From 8c72623da38539f65a20a9b7fdef268d53913b92 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Sun, 20 Sep 2009 09:08:08 -0400 Subject: [PATCH] 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 f602da8dd..9645acbc7 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; @@ -759,6 +760,88 @@ st_theme_node_get_length (StThemeNode *node, return FALSE; } +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 981ccaa3f..6756a2b33 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 30bc4bdce..f39471aef 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 ""; +} + +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, @@ -222,6 +258,40 @@ test_padding (void) st_theme_node_get_padding (group2, ST_SIDE_LEFT)); } +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) { @@ -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 be512d5cd..b2fad3699 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 {