[gnome-shell] StThemeNode: Add border-radius support



commit 8c72623da38539f65a20a9b7fdef268d53913b92
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Sun Sep 20 09:08:08 2009 -0400

    StThemeNode: Add border-radius support
    
    Add support for parsing and caching the border-radius property.
    Different radii for the 4 corners are supported; elliptical corners
    are not supported.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=595993

 src/st/st-theme-node.c |  107 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/st/st-theme-node.h |   30 +++++++++----
 src/st/test-theme.c    |   71 ++++++++++++++++++++++++++++++++
 src/st/test-theme.css  |    4 ++
 4 files changed, 199 insertions(+), 13 deletions(-)
---
diff --git a/src/st/st-theme-node.c b/src/st/st-theme-node.c
index f602da8..9645acb 100644
--- a/src/st/st-theme-node.c
+++ b/src/st/st-theme-node.c
@@ -24,6 +24,7 @@ struct _StThemeNode {
   ClutterColor foreground_color;
   ClutterColor border_color[4];
   double border_width[4];
+  double border_radius[4];
   guint padding[4];
 
   char *background_image;
@@ -760,6 +761,88 @@ st_theme_node_get_length (StThemeNode *node,
 }
 
 static void
+do_border_radius_term (StThemeNode *node,
+                       CRTerm      *term,
+                       gboolean     topleft,
+                       gboolean     topright,
+                       gboolean     bottomright,
+                       gboolean     bottomleft)
+{
+  gdouble value;
+
+  if (get_length_from_term (node, term, FALSE, &value) != VALUE_FOUND)
+    return;
+
+  if (topleft)
+    node->border_radius[ST_CORNER_TOPLEFT] = value;
+  if (topright)
+    node->border_radius[ST_CORNER_TOPRIGHT] = value;
+  if (bottomright)
+    node->border_radius[ST_CORNER_BOTTOMRIGHT] = value;
+  if (bottomleft)
+    node->border_radius[ST_CORNER_BOTTOMLEFT] = value;
+}
+
+static void
+do_border_radius (StThemeNode   *node,
+                  CRDeclaration *decl)
+{
+  const char *property_name = decl->property->stryng->str + 13; /* Skip 'border-radius' */
+
+  if (strcmp (property_name, "") == 0)
+    {
+      /* Slight deviation ... if we don't understand some of the terms and understand others,
+       * then we set the ones we understand and ignore the others instead of ignoring the
+       * whole thing
+       */
+      if (decl->value == NULL) /* 0 values */
+        return;
+      else if (decl->value->next == NULL) /* 1 value */
+        {
+          do_border_radius_term (node, decl->value,       TRUE, TRUE, TRUE, TRUE); /* all corners */
+          return;
+        }
+      else if (decl->value->next->next == NULL) /* 2 values */
+        {
+          do_border_radius_term (node, decl->value,       TRUE,  FALSE,  TRUE,  FALSE);  /* topleft/bottomright */
+          do_border_radius_term (node, decl->value->next, FALSE,  TRUE,   FALSE, TRUE);  /* topright/bottomleft */
+        }
+      else if (decl->value->next->next->next == NULL) /* 3 values */
+        {
+          do_border_radius_term (node, decl->value,             TRUE,  FALSE, FALSE, FALSE); /* topleft */
+          do_border_radius_term (node, decl->value->next,       FALSE, TRUE,  FALSE, TRUE);  /* topright/bottomleft */
+          do_border_radius_term (node, decl->value->next->next, FALSE, FALSE, TRUE,  FALSE);  /* bottomright */
+        }
+      else if (decl->value->next->next->next->next == NULL) /* 4 values */
+        {
+          do_border_radius_term (node, decl->value,                   TRUE,  FALSE, FALSE, FALSE); /* topleft */
+          do_border_radius_term (node, decl->value->next,             FALSE, TRUE,  FALSE, FALSE); /* topright */
+          do_border_radius_term (node, decl->value->next->next,       FALSE, FALSE, TRUE,  FALSE); /* bottomright */
+          do_border_radius_term (node, decl->value->next->next->next, FALSE, FALSE, FALSE, TRUE);  /* bottomleft */
+        }
+      else
+        {
+          g_warning ("Too many values for border-radius property");
+          return;
+        }
+    }
+  else
+    {
+      if (decl->value == NULL || decl->value->next != NULL)
+        return;
+
+      if (strcmp (property_name, "-topleft") == 0)
+        do_border_radius_term (node, decl->value, TRUE,  FALSE, FALSE, FALSE);
+      else if (strcmp (property_name, "-topright") == 0)
+        do_border_radius_term (node, decl->value, FALSE, TRUE,  FALSE, FALSE);
+      else if (strcmp (property_name, "-bottomright") == 0)
+        do_border_radius_term (node, decl->value, FALSE, FALSE, TRUE,  FALSE);
+      else if (strcmp (property_name, "-bottomleft") == 0)
+        do_border_radius_term (node, decl->value, FALSE, FALSE, FALSE, TRUE);
+    }
+}
+
+static void
 do_border_property (StThemeNode   *node,
                     CRDeclaration *decl)
 {
@@ -771,6 +854,12 @@ do_border_property (StThemeNode   *node,
   gboolean width_set = FALSE;
   int j;
 
+  if (g_str_has_prefix (property_name, "-radius"))
+    {
+      do_border_radius (node, decl);
+      return;
+    }
+
   if (g_str_has_prefix (property_name, "-left"))
     {
       side = ST_SIDE_LEFT;
@@ -1004,13 +1093,25 @@ st_theme_node_get_border_width (StThemeNode *node,
                                 StSide       side)
 {
   g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
-  g_return_val_if_fail (side >= ST_SIDE_LEFT && side <= ST_SIDE_BOTTOM, 0.);
+  g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
 
   ensure_borders (node);
 
   return node->border_width[side];
 }
 
+double
+st_theme_node_get_border_radius (StThemeNode *node,
+                                 StCorner     corner)
+{
+  g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
+  g_return_val_if_fail (corner >= ST_CORNER_TOPLEFT && corner <= ST_CORNER_BOTTOMLEFT, 0.);
+
+  ensure_borders (node);
+
+  return node->border_radius[corner];
+}
+
 static GetFromTermResult
 get_background_color_from_term (StThemeNode  *node,
                                 CRTerm       *term,
@@ -1202,7 +1303,7 @@ st_theme_node_get_border_color (StThemeNode  *node,
                                 ClutterColor *color)
 {
   g_return_if_fail (ST_IS_THEME_NODE (node));
-  g_return_if_fail (side >= ST_SIDE_LEFT && side <= ST_SIDE_BOTTOM);
+  g_return_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT);
 
   ensure_borders (node);
 
@@ -1214,7 +1315,7 @@ st_theme_node_get_padding (StThemeNode *node,
                            StSide       side)
 {
   g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
-  g_return_val_if_fail (side >= ST_SIDE_LEFT && side <= ST_SIDE_BOTTOM, 0.);
+  g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
 
   ensure_borders (node);
 
diff --git a/src/st/st-theme-node.h b/src/st/st-theme-node.h
index 981ccaa..6756a2b 100644
--- a/src/st/st-theme-node.h
+++ b/src/st/st-theme-node.h
@@ -36,12 +36,19 @@ typedef struct _StThemeNodeClass StThemeNodeClass;
 #define ST_THEME_NODE_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj),     ST_TYPE_THEME_NODE, StThemeNodeClass))
 
 typedef enum {
-    ST_SIDE_LEFT,
-    ST_SIDE_RIGHT,
     ST_SIDE_TOP,
-    ST_SIDE_BOTTOM
+    ST_SIDE_RIGHT,
+    ST_SIDE_BOTTOM,
+    ST_SIDE_LEFT
 } StSide;
 
+typedef enum {
+    ST_CORNER_TOPLEFT,
+    ST_CORNER_TOPRIGHT,
+    ST_CORNER_BOTTOMRIGHT,
+    ST_CORNER_BOTTOMLEFT
+} StCorner;
+
 /* These are the CSS values; that doesn't mean we have to implement blink... */
 typedef enum {
     ST_TEXT_DECORATION_UNDERLINE    = 1 << 0,
@@ -99,13 +106,16 @@ void st_theme_node_get_foreground_color (StThemeNode  *node,
 
 const char *st_theme_node_get_background_image (StThemeNode *node);
 
-double st_theme_node_get_border_width (StThemeNode  *node,
-                                       StSide        side);
-void   st_theme_node_get_border_color (StThemeNode  *node,
-                                       StSide        side,
-                                       ClutterColor *color);
-double st_theme_node_get_padding      (StThemeNode  *node,
-                                       StSide        side);
+double st_theme_node_get_border_width  (StThemeNode  *node,
+                                        StSide        side);
+double st_theme_node_get_border_radius (StThemeNode  *node,
+                                        StCorner      corner);
+void   st_theme_node_get_border_color  (StThemeNode  *node,
+                                        StSide        side,
+                                        ClutterColor *color);
+
+double st_theme_node_get_padding       (StThemeNode  *node,
+                                        StSide        side);
 
 StTextDecoration st_theme_node_get_text_decoration (StThemeNode *node);
 
diff --git a/src/st/test-theme.c b/src/st/test-theme.c
index 30bc4bd..f39471a 100644
--- a/src/st/test-theme.c
+++ b/src/st/test-theme.c
@@ -112,6 +112,42 @@ assert_background_color (StThemeNode *node,
     }
 }
 
+static const char *
+side_to_string (StSide side)
+{
+  switch (side)
+    {
+    case ST_SIDE_TOP:
+      return "top";
+    case ST_SIDE_RIGHT:
+      return "right";
+    case ST_SIDE_BOTTOM:
+      return "bottom";
+    case ST_SIDE_LEFT:
+      return "left";
+    }
+
+  return "<unknown>";
+}
+
+static void
+assert_border_color (StThemeNode *node,
+                     const char  *node_description,
+                     StSide       side,
+                     guint32      expected)
+{
+  ClutterColor color;
+  st_theme_node_get_border_color (node, side, &color);
+  guint32 value = clutter_color_to_pixel (&color);
+
+  if (expected != value)
+    {
+      g_print ("%s: %s.border-%s-color: expected: #%08x, got: #%08x\n",
+	       test, node_description, side_to_string (side), expected, value);
+      fail = TRUE;
+    }
+}
+
 static void
 assert_background_image (StThemeNode *node,
 			 const char  *node_description,
@@ -223,6 +259,40 @@ test_padding (void)
 }
 
 static void
+test_border (void)
+{
+  test = "border";
+
+  /* group2 is defined as having a thin black border along the top three
+   * sides with rounded joins, then a square-joined green border at the
+   * botttom
+   */
+
+  assert_length ("group2", "border-top-width", 2.,
+		 st_theme_node_get_border_width (group2, ST_SIDE_TOP));
+  assert_length ("group2", "border-right-width", 2.,
+		 st_theme_node_get_border_width (group2, ST_SIDE_RIGHT));
+  assert_length ("group2", "border-bottom-width", 5.,
+		 st_theme_node_get_border_width (group2, ST_SIDE_BOTTOM));
+  assert_length ("group2", "border-left-width", 2.,
+		 st_theme_node_get_border_width (group2, ST_SIDE_LEFT));
+
+  assert_border_color (group2, "group2", ST_SIDE_TOP,    0x000000ff);
+  assert_border_color (group2, "group2", ST_SIDE_RIGHT,  0x000000ff);
+  assert_border_color (group2, "group2", ST_SIDE_BOTTOM, 0x0000ffff);
+  assert_border_color (group2, "group2", ST_SIDE_LEFT,   0x000000ff);
+
+  assert_length ("group2", "border-radius-topleft", 10.,
+		 st_theme_node_get_border_radius (group2, ST_CORNER_TOPLEFT));
+  assert_length ("group2", "border-radius-topright", 10.,
+		 st_theme_node_get_border_radius (group2, ST_CORNER_TOPRIGHT));
+  assert_length ("group2", "border-radius-bottomright", 0.,
+		 st_theme_node_get_border_radius (group2, ST_CORNER_BOTTOMRIGHT));
+  assert_length ("group2", "border-radius-bottomleft", 0.,
+		 st_theme_node_get_border_radius (group2, ST_CORNER_BOTTOMLEFT));
+}
+
+static void
 test_background (void)
 {
   test = "background";
@@ -312,6 +382,7 @@ main (int argc, char **argv)
   test_type_inheritance ();
   test_adjacent_selector ();
   test_padding ();
+  test_border ();
   test_background ();
   test_font ();
   test_pseudo_class ();
diff --git a/src/st/test-theme.css b/src/st/test-theme.css
index be512d5..b2fad36 100644
--- a/src/st/test-theme.css
+++ b/src/st/test-theme.css
@@ -58,6 +58,10 @@ stage > #text2 {
 #group2 {
     background-image: url('other-background.png');
     padding: 1px 2px 3px 4px;
+
+    border: 2px solid #000000;
+    border-bottom: 5px solid #0000ff;
+    border-radius: 10px 10px 0px 0px;
 }
 
 ClutterText:hover {



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