[gnome-shell] st-theme-node: Improve borders with gradient backgrounds



commit cb2babb1a010fe72c812045d9466ffbf1350c1d4
Author: Florian Müllner <fmuellner gnome org>
Date:   Thu Dec 9 10:35:40 2010 +0100

    st-theme-node: Improve borders with gradient backgrounds
    
    For gradient backgrounds, borders were implemented by filling the
    background shape with the border color first, and then scaling down
    the path to draw the background.
    
    The result is not correct[0], which is especially visible if the border
    width is greater than the border radius - so instead of scaling down
    the original path, use a separate path for the background.
    
    The result is consistent with the borders we draw for non-gradient
    backgrounds, and much closer to the correct standard behavior.
    
    [0] http://www.w3.org/TR/css3-background/#the-border-radius
    
    https://bugzilla.gnome.org/show_bug.cgi?id=607500

 src/st/st-theme-node-drawing.c |  112 +++++++++++++++++++++++++---------------
 1 files changed, 71 insertions(+), 41 deletions(-)
---
diff --git a/src/st/st-theme-node-drawing.c b/src/st/st-theme-node-drawing.c
index 847c7bb..4a17ac2 100644
--- a/src/st/st-theme-node-drawing.c
+++ b/src/st/st-theme-node-drawing.c
@@ -378,7 +378,6 @@ st_theme_node_render_gradient (StThemeNode *node)
   cairo_t *cr;
   cairo_surface_t *surface;
   cairo_pattern_t *pattern;
-  gboolean round_border = FALSE;
   ClutterColor border_color;
   int border_width;
   guint rowstride;
@@ -397,11 +396,7 @@ st_theme_node_render_gradient (StThemeNode *node)
   get_arbitrary_border (node, &border_width, &border_color);
 
   for (i = 0; i < 4; i++)
-    {
-      radius[i] = st_theme_node_get_border_radius (node, i);
-      if (radius[i] > 0)
-        round_border = TRUE;
-    }
+    radius[i] = st_theme_node_get_border_radius (node, i);
 
   if (node->background_gradient_type == ST_GRADIENT_VERTICAL)
     pattern = cairo_pattern_create_linear (0, 0, 0, node->alloc_height);
@@ -427,57 +422,92 @@ st_theme_node_render_gradient (StThemeNode *node)
                                      node->background_gradient_end.blue / 255.,
                                      node->background_gradient_end.alpha / 255.);
 
-  if (round_border)
+  /* Create a path for the background's outline first */
+  if (radius[ST_CORNER_TOPLEFT] > 0)
+    cairo_arc (cr,
+               radius[ST_CORNER_TOPLEFT],
+               radius[ST_CORNER_TOPLEFT],
+               radius[ST_CORNER_TOPLEFT], M_PI, 3 * M_PI / 2);
+  else
+    cairo_move_to (cr, 0, 0);
+  cairo_line_to (cr, node->alloc_width - radius[ST_CORNER_TOPRIGHT], 0);
+  if (radius[ST_CORNER_TOPRIGHT] > 0)
+    cairo_arc (cr,
+               node->alloc_width - radius[ST_CORNER_TOPRIGHT],
+               radius[ST_CORNER_TOPRIGHT],
+               radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI);
+  cairo_line_to (cr, node->alloc_width, node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT]);
+  if (radius[ST_CORNER_BOTTOMRIGHT])
+    cairo_arc (cr,
+               node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT],
+               node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT],
+               radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2);
+  cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], node->alloc_height);
+  if (radius[ST_CORNER_BOTTOMLEFT])
+    cairo_arc (cr,
+               radius[ST_CORNER_BOTTOMLEFT],
+               node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
+               radius[ST_CORNER_BOTTOMLEFT], M_PI / 2, M_PI);
+  cairo_close_path (cr);
+
+
+  /* If we have a border, we fill the outline with the border
+   * color and create the inline shape for the background gradient;
+   * otherwise the outline shape is filled with the background
+   * gradient directly
+   */
+  if (border_width > 0)
     {
-      if (radius[ST_CORNER_TOPLEFT] > 0)
+      cairo_set_source_rgba (cr,
+                             border_color.red / 255.,
+                             border_color.green / 255.,
+                             border_color.blue / 255.,
+                             border_color.alpha / 255.);
+      cairo_fill (cr);
+
+      if (radius[ST_CORNER_TOPLEFT] > border_width)
         cairo_arc (cr,
                    radius[ST_CORNER_TOPLEFT],
                    radius[ST_CORNER_TOPLEFT],
-                   radius[ST_CORNER_TOPLEFT], M_PI, 3 * M_PI / 2);
+                   radius[ST_CORNER_TOPLEFT] - border_width,
+                   M_PI, 3 * M_PI / 2);
       else
-        cairo_move_to (cr, 0, 0);
-      cairo_line_to (cr, node->alloc_width - radius[ST_CORNER_TOPRIGHT], 0);
-      if (radius[ST_CORNER_TOPRIGHT] > 0)
+        cairo_move_to (cr, border_width, border_width);
+
+      cairo_line_to (cr,
+                     node->alloc_width - MAX(radius[ST_CORNER_TOPRIGHT], border_width),
+                     border_width);
+
+      if (radius[ST_CORNER_TOPRIGHT] > border_width)
         cairo_arc (cr,
                    node->alloc_width - radius[ST_CORNER_TOPRIGHT],
                    radius[ST_CORNER_TOPRIGHT],
-                   radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI);
-      cairo_line_to (cr, node->alloc_width, node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT]);
-      if (radius[ST_CORNER_BOTTOMRIGHT])
+                   radius[ST_CORNER_TOPRIGHT] - border_width,
+                   3 * M_PI / 2, 2 * M_PI);
+
+      cairo_line_to (cr,
+                     node->alloc_width - border_width,
+                     node->alloc_height - MAX(radius[ST_CORNER_BOTTOMRIGHT], border_width));
+
+      if (radius[ST_CORNER_BOTTOMRIGHT] > border_width)
         cairo_arc (cr,
                    node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT],
                    node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT],
-                   radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2);
-      cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], node->alloc_height);
-      if (radius[ST_CORNER_BOTTOMLEFT])
+                   radius[ST_CORNER_BOTTOMRIGHT] - border_width,
+                   0, M_PI / 2);
+
+      cairo_line_to (cr,
+                     MAX(radius[ST_CORNER_BOTTOMLEFT], border_width),
+                     node->alloc_height - border_width);
+
+      if (radius[ST_CORNER_BOTTOMLEFT] > border_width)
         cairo_arc (cr,
                    radius[ST_CORNER_BOTTOMLEFT],
                    node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
-                   radius[ST_CORNER_BOTTOMLEFT], M_PI / 2, M_PI);
+                   radius[ST_CORNER_BOTTOMLEFT] - border_width,
+                   M_PI / 2, M_PI);
       cairo_close_path (cr);
     }
-  else
-    cairo_rectangle (cr, 0, 0, node->alloc_width, node->alloc_height);
-
-  if (border_width > 0)
-    {
-      cairo_path_t *path;
-
-      path = cairo_copy_path (cr);
-      cairo_set_source_rgba (cr,
-                             border_color.red / 255.,
-                             border_color.green / 255.,
-                             border_color.blue / 255.,
-                             border_color.alpha / 255.);
-      cairo_fill (cr);
-
-      cairo_translate (cr, border_width, border_width);
-      cairo_scale (cr,
-                   (gdouble)(node->alloc_width - 2 * border_width) / node->alloc_width,
-                   (gdouble)(node->alloc_height - 2 * border_width) / node->alloc_height);
-      cairo_append_path (cr, path);
-      cairo_path_destroy (path);
-    }
 
   cairo_set_source (cr, pattern);
   cairo_fill (cr);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]