[gtk+] themingengine: Add support for the border-radii



commit 91602cca6e85b0659781112cfe37618c9a60f032
Author: Benjamin Otte <otte redhat com>
Date:   Thu May 26 05:09:48 2011 +0200

    themingengine: Add support for the border-radii

 gtk/gtkthemingengine.c |  273 ++++++++++++++++++++++++++++++++++--------------
 1 files changed, 194 insertions(+), 79 deletions(-)
---
diff --git a/gtk/gtkthemingengine.c b/gtk/gtkthemingengine.c
index 47833a3..880534f 100644
--- a/gtk/gtkthemingengine.c
+++ b/gtk/gtkthemingengine.c
@@ -30,6 +30,7 @@
 #include "gtk9slice.h"
 #include "gtkpango.h"
 #include "gtkshadowprivate.h"
+#include "gtkcsstypesprivate.h"
 
 /**
  * SECTION:gtkthemingengine
@@ -1364,117 +1365,168 @@ color_shade (const GdkRGBA *color,
 }
 
 static void
-_cairo_round_rectangle_sides (cairo_t          *cr,
-                              gdouble           radius,
-                              gdouble           x,
-                              gdouble           y,
-                              gdouble           width,
-                              gdouble           height,
-                              guint             sides,
-                              GtkJunctionSides  junction)
+_cairo_ellipsis (cairo_t *cr,
+	         double xc, double yc,
+	         double xradius, double yradius,
+	         double angle1, double angle2)
 {
-  radius = CLAMP (radius, 0, MIN (width / 2, height / 2));
+  if (xradius <= 0.0 || yradius <= 0.0)
+    {
+      /* stolen from cairo sources */
+      cairo_line_to (cr, xc, yc); /* might become a move_to */
+      cairo_line_to (cr, xc, yc);
+      return;
+    }
 
+  cairo_save (cr);
+  cairo_translate (cr, xc, yc);
+  cairo_scale (cr, xradius, yradius);
+  cairo_arc (cr, 0, 0, 1.0, angle1, angle2);
+  cairo_restore (cr);
+}
+
+static void
+_cairo_round_rectangle_sides (cairo_t                  *cr,
+                              const GtkCssBorderRadius *border_radius,
+                              gdouble                   x,
+                              gdouble                   y,
+                              gdouble                   width,
+                              gdouble                   height,
+                              guint                     sides,
+                              GtkJunctionSides          junction)
+{
   if (sides & SIDE_RIGHT)
     {
-      if (radius == 0 ||
-          (junction & GTK_JUNCTION_CORNER_TOPRIGHT))
+      if (junction & GTK_JUNCTION_CORNER_TOPRIGHT)
         cairo_move_to (cr, x + width, y);
       else
         {
           cairo_new_sub_path (cr);
-          cairo_arc (cr, x + width - radius, y + radius, radius, - G_PI / 4, 0);
+          _cairo_ellipsis (cr, 
+                           x + width - border_radius->top_right.horizontal,
+                           y + border_radius->top_right.vertical,
+                           border_radius->top_right.horizontal,
+                           border_radius->top_right.vertical,
+                           - G_PI / 4, 0);
         }
 
-      if (radius == 0 ||
-          (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT))
+      if ((junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT))
         cairo_line_to (cr, x + width, y + height);
       else
-        cairo_arc (cr, x + width - radius, y + height - radius, radius, 0, G_PI / 4);
+        _cairo_ellipsis (cr,
+                         x + width - border_radius->bottom_right.horizontal,
+                         y + height - border_radius->bottom_right.vertical,
+                         border_radius->bottom_right.horizontal,
+                         border_radius->bottom_right.vertical,
+                         0, G_PI / 4);
     }
 
   if (sides & SIDE_BOTTOM)
     {
-      if (radius != 0 &&
-          ! (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT))
+      if (! (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT))
         {
           if ((sides & SIDE_RIGHT) == 0)
             cairo_new_sub_path (cr);
 
-          cairo_arc (cr, x + width - radius, y + height - radius, radius, G_PI / 4, G_PI / 2);
+          _cairo_ellipsis (cr,
+                           x + width - border_radius->bottom_right.horizontal,
+                           y + height - border_radius->bottom_right.vertical,
+                           border_radius->bottom_right.horizontal,
+                           border_radius->bottom_right.vertical,
+                           G_PI / 4, G_PI / 2);
         }
       else if ((sides & SIDE_RIGHT) == 0)
         cairo_move_to (cr, x + width, y + height);
 
-      if (radius == 0 ||
-          (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT))
+      if ((junction & GTK_JUNCTION_CORNER_BOTTOMLEFT))
         cairo_line_to (cr, x, y + height);
       else
-        cairo_arc (cr, x + radius, y + height - radius, radius, G_PI / 2, 3 * (G_PI / 4));
+        _cairo_ellipsis (cr,
+                         x + border_radius->bottom_left.horizontal,
+                         y + height - border_radius->bottom_left.vertical,
+                         border_radius->bottom_left.horizontal,
+                         border_radius->bottom_left.vertical,
+                         G_PI / 2, 3 * (G_PI / 4));
     }
   else
     cairo_move_to (cr, x, y + height);
 
   if (sides & SIDE_LEFT)
     {
-      if (radius != 0 &&
-          ! (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT))
+      if (! (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT))
         {
           if ((sides & SIDE_BOTTOM) == 0)
             cairo_new_sub_path (cr);
 
-          cairo_arc (cr, x + radius, y + height - radius, radius, 3 * (G_PI / 4), G_PI);
+          _cairo_ellipsis (cr,
+                           x + border_radius->bottom_left.horizontal,
+                           y + height - border_radius->bottom_left.vertical,
+                           border_radius->bottom_left.horizontal,
+                           border_radius->bottom_left.vertical,
+                           3 * (G_PI / 4), G_PI);
         }
       else if ((sides & SIDE_BOTTOM) == 0)
         cairo_move_to (cr, x, y + height);
 
-      if (radius == 0 ||
-          (junction & GTK_JUNCTION_CORNER_TOPLEFT))
+      if ((junction & GTK_JUNCTION_CORNER_TOPLEFT))
         cairo_line_to (cr, x, y);
       else
-        cairo_arc (cr, x + radius, y + radius, radius, G_PI, G_PI + G_PI / 4);
+        _cairo_ellipsis (cr,
+                         x + border_radius->top_left.horizontal,
+                         y + border_radius->top_left.vertical,
+                         border_radius->top_left.horizontal,
+                         border_radius->top_left.vertical,
+                         G_PI, G_PI + G_PI / 4);
     }
 
   if (sides & SIDE_TOP)
     {
-      if (radius != 0 &&
-          ! (junction & GTK_JUNCTION_CORNER_TOPLEFT))
+      if (! (junction & GTK_JUNCTION_CORNER_TOPLEFT))
         {
           if ((sides & SIDE_LEFT) == 0)
             cairo_new_sub_path (cr);
 
-          cairo_arc (cr, x + radius, y + radius, radius, 5 * (G_PI / 4), 3 * (G_PI / 2));
+          _cairo_ellipsis (cr,
+                           x + border_radius->top_left.horizontal,
+                           y + border_radius->top_left.vertical,
+                           border_radius->top_left.horizontal,
+                           border_radius->top_left.vertical,
+                           5 * (G_PI / 4), 3 * (G_PI / 2));
         }
       else if ((sides & SIDE_LEFT) == 0)
         cairo_move_to (cr, x, y);
 
-      if (radius == 0 ||
-          (junction & GTK_JUNCTION_CORNER_TOPRIGHT))
+      if ((junction & GTK_JUNCTION_CORNER_TOPRIGHT))
         cairo_line_to (cr, x + width, y);
       else
-        cairo_arc (cr, x + width - radius, y + radius, radius, 3 * (G_PI / 2), - G_PI / 4);
-    }
+        _cairo_ellipsis (cr,
+                         x + width - border_radius->top_right.horizontal,
+                         y + border_radius->top_right.vertical,
+                         border_radius->top_right.horizontal,
+                         border_radius->top_right.vertical,
+                         3 * (G_PI / 2), - G_PI / 4);
+  }
 }
 
 static void
-_cairo_uneven_frame (cairo_t          *cr,
-                     gdouble           radius,
-                     gdouble           x,
-                     gdouble           y,
-                     gdouble           width,
-                     gdouble           height,
-                     GtkBorder        *border,
-                     GtkJunctionSides  junction)
+_cairo_uneven_frame (cairo_t                  *cr,
+                     const GtkCssBorderRadius *border_radius,
+                     gdouble                   x,
+                     gdouble                   y,
+                     gdouble                   width,
+                     gdouble                   height,
+                     GtkBorder                *border,
+                     GtkJunctionSides          junction)
 {
   cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
   cairo_set_line_width (cr, 1);
 
-  _cairo_round_rectangle_sides (cr, (gdouble) radius,
+  _cairo_round_rectangle_sides (cr, border_radius,
                                 x, y,
                                 width, height,
                                 SIDE_ALL, junction);
 
-  _cairo_round_rectangle_sides (cr, (gdouble) radius,
+  _cairo_round_rectangle_sides (cr, border_radius,
                                 x + border->left,
                                 y + border->top,
                                 width - border->left - border->right,
@@ -1523,7 +1575,10 @@ render_background_internal (GtkThemingEngine *engine,
   gboolean running;
   gdouble progress, alpha = 1;
   GtkBorder border;
-  gint radius, border_width;
+  GtkCssBorderCornerRadius *top_left_radius, *top_right_radius;
+  GtkCssBorderCornerRadius *bottom_left_radius, *bottom_right_radius;
+  GtkCssBorderRadius border_radius = { { 0, },  };
+  gint border_width;
   GtkBorderStyle border_style;
   gdouble mat_w, mat_h;
   cairo_matrix_t identity;
@@ -1541,10 +1596,28 @@ render_background_internal (GtkThemingEngine *engine,
 
   gtk_theming_engine_get (engine, flags,
                           "background-image", &pattern,
-                          "border-radius", &radius,
+                          /* Can't use border-radius as it's an int for
+                           * backwards compat */
+                          "border-top-left-radius", &top_left_radius,
+                          "border-top-right-radius", &top_right_radius,
+                          "border-bottom-right-radius", &bottom_right_radius,
+                          "border-bottom-left-radius", &bottom_left_radius,
                           "border-style", &border_style,
                           NULL);
 
+  if (top_left_radius)
+    border_radius.top_left = *top_left_radius;
+  g_free (top_left_radius);
+  if (top_right_radius)
+    border_radius.top_right = *top_right_radius;
+  g_free (top_right_radius);
+  if (bottom_right_radius)
+    border_radius.bottom_right = *bottom_right_radius;
+  g_free (bottom_right_radius);
+  if (bottom_left_radius)
+    border_radius.bottom_left = *bottom_left_radius;
+  g_free (bottom_left_radius);
+
   border_width = MIN (MIN (border.top, border.bottom),
                       MIN (border.left, border.right));
 
@@ -1670,7 +1743,7 @@ render_background_internal (GtkThemingEngine *engine,
               /* Different pattern types, or different color
                * stop counts, alpha blend both patterns.
                */
-              _cairo_round_rectangle_sides (cr, (gdouble) radius,
+              _cairo_round_rectangle_sides (cr, &border_radius,
                                             0, 0, width, height,
                                             SIDE_ALL, junction);
 
@@ -1755,7 +1828,7 @@ render_background_internal (GtkThemingEngine *engine,
         cairo_pattern_destroy (other_pattern);
     }
 
-  _cairo_round_rectangle_sides (cr, (gdouble) radius,
+  _cairo_round_rectangle_sides (cr, &border_radius,
                                 0, 0, width, height,
                                 SIDE_ALL, junction);
   if (pattern)
@@ -1786,7 +1859,7 @@ render_background_internal (GtkThemingEngine *engine,
   else
     {
       cairo_save (cr);
-      _cairo_round_rectangle_sides (cr, (gdouble) radius,
+      _cairo_round_rectangle_sides (cr, &border_radius,
                                     0, 0, width, height,
                                     SIDE_ALL, junction);
       cairo_clip (cr);
@@ -1858,7 +1931,10 @@ render_frame_internal (GtkThemingEngine *engine,
   GdkRGBA lighter;
   GdkRGBA border_color;
   GtkBorderStyle border_style;
-  gint border_width, radius;
+  gint border_width;
+  GtkCssBorderCornerRadius *top_left_radius, *top_right_radius;
+  GtkCssBorderCornerRadius *bottom_left_radius, *bottom_right_radius;
+  GtkCssBorderRadius border_radius = { { 0, },  };
   gdouble progress, d1, d2, m;
   gboolean running;
   GtkBorder border;
@@ -1871,9 +1947,27 @@ render_frame_internal (GtkThemingEngine *engine,
 
   gtk_theming_engine_get (engine, state,
                           "border-style", &border_style,
-                          "border-radius", &radius,
+                          /* Can't use border-radius as it's an int for
+                           * backwards compat */
+                          "border-top-left-radius", &top_left_radius,
+                          "border-top-right-radius", &top_right_radius,
+                          "border-bottom-right-radius", &bottom_right_radius,
+                          "border-bottom-left-radius", &bottom_left_radius,
                           NULL);
 
+  if (top_left_radius)
+    border_radius.top_left = *top_left_radius;
+  g_free (top_left_radius);
+  if (top_right_radius)
+    border_radius.top_right = *top_right_radius;
+  g_free (top_right_radius);
+  if (bottom_right_radius)
+    border_radius.bottom_right = *bottom_right_radius;
+  g_free (bottom_right_radius);
+  if (bottom_left_radius)
+    border_radius.bottom_left = *bottom_left_radius;
+  g_free (bottom_left_radius);
+
   running = gtk_theming_engine_state_is_running (engine, GTK_STATE_PRELIGHT, &progress);
   border_width = MIN (MIN (border.top, border.bottom),
                       MIN (border.left, border.right));
@@ -1933,7 +2027,7 @@ render_frame_internal (GtkThemingEngine *engine,
               height -= 1;
             }
 
-          _cairo_round_rectangle_sides (cr, (gdouble) radius,
+          _cairo_round_rectangle_sides (cr, &border_radius,
                                         x, y, width, height,
                                         SIDE_ALL & ~(hidden_side),
                                         junction);
@@ -1942,7 +2036,7 @@ render_frame_internal (GtkThemingEngine *engine,
       else
         {
           cairo_save (cr);
-          _cairo_uneven_frame (cr, (gdouble) radius,
+          _cairo_uneven_frame (cr, &border_radius,
                                x, y, width, height,
                                &border, junction);
           cairo_fill (cr);
@@ -1953,11 +2047,7 @@ render_frame_internal (GtkThemingEngine *engine,
     case GTK_BORDER_STYLE_INSET:
     case GTK_BORDER_STYLE_OUTSET:
       cairo_set_line_width (cr, border_width);
-
-      if (radius == 0)
-        cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
-      else
-        cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+      cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
 
       if (border_width > 1)
         {
@@ -1982,7 +2072,7 @@ render_frame_internal (GtkThemingEngine *engine,
           else
             gdk_cairo_set_source_rgba (cr, &border_color);
 
-          _cairo_round_rectangle_sides (cr, (gdouble) radius,
+          _cairo_round_rectangle_sides (cr, &border_radius,
                                         x + d1, y + d1,
                                         width - d2, height - d2,
                                         (SIDE_BOTTOM | SIDE_RIGHT) & ~(hidden_side),
@@ -1994,7 +2084,7 @@ render_frame_internal (GtkThemingEngine *engine,
           else
             gdk_cairo_set_source_rgba (cr, &lighter);
 
-          _cairo_round_rectangle_sides (cr, (gdouble) radius,
+          _cairo_round_rectangle_sides (cr, &border_radius,
                                         x + d1, y + d1,
                                         width - d2, height - d2,
                                         (SIDE_TOP | SIDE_LEFT) & ~(hidden_side),
@@ -2011,7 +2101,7 @@ render_frame_internal (GtkThemingEngine *engine,
           else
             gdk_cairo_set_source_rgba (cr, &border_color);
 
-          _cairo_uneven_frame (cr, (gdouble) radius,
+          _cairo_uneven_frame (cr, &border_radius,
                                x, y, width, height,
                                &border, junction);
           cairo_fill (cr);
@@ -2019,9 +2109,15 @@ render_frame_internal (GtkThemingEngine *engine,
           /* Top/left */
           cairo_move_to (cr, x, y);
           cairo_line_to (cr, x + width, y);
-          cairo_line_to (cr, x + width - border.right - radius / 2, y + border.top + radius / 2);
-          cairo_line_to (cr, x + width - border.right - radius / 2, y + height - border.bottom - radius / 2);
-          cairo_line_to (cr, x + border.left + radius / 2, y + height - border.bottom - radius / 2);
+          cairo_line_to (cr, 
+                         x + width - border.right - border_radius.top_right.horizontal / 2,
+                         y + border.top + border_radius.top_right.vertical / 2);
+          cairo_line_to (cr, 
+                         x + width - border.right - border_radius.bottom_right.horizontal / 2,
+                         y + height - border.bottom - border_radius.bottom_right.vertical / 2);
+          cairo_line_to (cr, 
+                         x + border.left + border_radius.bottom_left.horizontal / 2,
+                         y + height - border.bottom - border_radius.bottom_left.vertical / 2);
           cairo_line_to (cr, x, y + height);
           cairo_close_path (cr);
 
@@ -2032,7 +2128,7 @@ render_frame_internal (GtkThemingEngine *engine,
           else
             gdk_cairo_set_source_rgba (cr, &lighter);
 
-          _cairo_uneven_frame (cr, (gdouble) radius,
+          _cairo_uneven_frame (cr, &border_radius,
                                x, y, width, height,
                                &border, junction);
           cairo_fill (cr);
@@ -2054,14 +2150,12 @@ render_frame_internal (GtkThemingEngine *engine,
 
           cairo_set_line_width (cr, 1);
 
-          if (radius == 0 ||
-              (junction & GTK_JUNCTION_CORNER_TOPRIGHT) != 0)
+          if ((junction & GTK_JUNCTION_CORNER_TOPRIGHT) != 0)
             _cairo_corner_triangle (cr,
                                     x + width - border_width, y,
                                     border_width);
 
-          if (radius == 0 ||
-              (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT) != 0)
+          if ((junction & GTK_JUNCTION_CORNER_BOTTOMLEFT) != 0)
             _cairo_corner_triangle (cr,
                                     x, y + height - border_width,
                                     border_width);
@@ -2493,7 +2587,10 @@ gtk_theming_engine_render_frame_gap (GtkThemingEngine *engine,
 {
   GtkJunctionSides junction;
   GtkStateFlags state;
-  gint border_width, radius;
+  gint border_width;
+  GtkCssBorderCornerRadius *top_left_radius, *top_right_radius;
+  GtkCssBorderCornerRadius *bottom_left_radius, *bottom_right_radius;
+  GtkCssBorderRadius border_radius = { { 0, },  };
   gdouble x0, y0, x1, y1, xc, yc, wc, hc;
   GtkBorder border;
 
@@ -2503,9 +2600,27 @@ gtk_theming_engine_render_frame_gap (GtkThemingEngine *engine,
 
   gtk_theming_engine_get_border (engine, state, &border);
   gtk_theming_engine_get (engine, state,
-                          "border-radius", &radius,
+                          /* Can't use border-radius as it's an int for
+                           * backwards compat */
+                          "border-top-left-radius", &top_left_radius,
+                          "border-top-right-radius", &top_right_radius,
+                          "border-bottom-right-radius", &bottom_right_radius,
+                          "border-bottom-left-radius", &bottom_left_radius,
                           NULL);
 
+  if (top_left_radius)
+    border_radius.top_left = *top_left_radius;
+  g_free (top_left_radius);
+  if (top_right_radius)
+    border_radius.top_right = *top_right_radius;
+  g_free (top_right_radius);
+  if (bottom_right_radius)
+    border_radius.bottom_right = *bottom_right_radius;
+  g_free (bottom_right_radius);
+  if (bottom_left_radius)
+    border_radius.bottom_left = *bottom_left_radius;
+  g_free (bottom_left_radius);
+
   border_width = MIN (MIN (border.top, border.bottom),
                       MIN (border.left, border.right));
 
@@ -2519,10 +2634,10 @@ gtk_theming_engine_render_frame_gap (GtkThemingEngine *engine,
       wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0);
       hc = border_width;
 
-      if (xy0_gap < radius)
+      if (xy0_gap < border_radius.top_left.horizontal)
         junction |= GTK_JUNCTION_CORNER_TOPLEFT;
 
-      if (xy1_gap > width - radius)
+      if (xy1_gap > width - border_radius.top_right.horizontal)
         junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
       break;
     case GTK_POS_BOTTOM:
@@ -2531,10 +2646,10 @@ gtk_theming_engine_render_frame_gap (GtkThemingEngine *engine,
       wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0);
       hc = border_width;
 
-      if (xy0_gap < radius)
+      if (xy0_gap < border_radius.bottom_left.horizontal)
         junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT;
 
-      if (xy1_gap > width - radius)
+      if (xy1_gap > width - border_radius.bottom_right.horizontal)
         junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT;
 
       break;
@@ -2544,10 +2659,10 @@ gtk_theming_engine_render_frame_gap (GtkThemingEngine *engine,
       wc = border_width;
       hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0);
 
-      if (xy0_gap < radius)
+      if (xy0_gap < border_radius.top_left.vertical)
         junction |= GTK_JUNCTION_CORNER_TOPLEFT;
 
-      if (xy1_gap > height - radius)
+      if (xy1_gap > height - border_radius.bottom_left.vertical)
         junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT;
 
       break;
@@ -2557,10 +2672,10 @@ gtk_theming_engine_render_frame_gap (GtkThemingEngine *engine,
       wc = border_width;
       hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0);
 
-      if (xy0_gap < radius)
+      if (xy0_gap < border_radius.top_right.vertical)
         junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
 
-      if (xy1_gap > height - radius)
+      if (xy1_gap > height - border_radius.bottom_right.vertical)
         junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT;
 
       break;



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