From 49ba54820c8191b26e9f938f4761a12795ef59b1 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Sun, 20 Sep 2009 09:08:08 -0400 Subject: [PATCH] ShellThemeNode: 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. --- src/toolkit/shell-theme-node.c | 115 ++++++++++++++++++++++++++++++++- src/toolkit/shell-theme-node.h | 20 ++++-- src/toolkit/test-theme.c | 71 ++++++++++++++++++++ src/toolkit/test-theme.css | 4 ++ 4 files changed, 202 insertions(+), 8 deletions(-) diff --git a/src/toolkit/shell-theme-node.c b/src/toolkit/shell-theme-node.c index abea89981..0e919fcd3 100644 --- a/src/toolkit/shell-theme-node.c +++ b/src/toolkit/shell-theme-node.c @@ -34,6 +34,7 @@ struct _ShellThemeNode { ClutterColor foreground_color; ClutterColor border_color[4]; double border_width[4]; + double border_radius[4]; guint padding[4]; char *background_image; @@ -696,6 +697,96 @@ shell_theme_node_get_length (ShellThemeNode *node, return FALSE; } +static void +do_border_radius_term (ShellThemeNode *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[SHELL_CORNER_TOPLEFT] = value; + if (topright) + node->border_radius[SHELL_CORNER_TOPRIGHT] = value; + if (bottomright) + node->border_radius[SHELL_CORNER_BOTTOMRIGHT] = value; + if (bottomleft) + node->border_radius[SHELL_CORNER_BOTTOMLEFT] = value; +} + +static void +do_border_radius (ShellThemeNode *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 (ShellThemeNode *node, CRDeclaration *decl) @@ -708,6 +799,12 @@ do_border_property (ShellThemeNode *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 = SHELL_SIDE_LEFT; @@ -955,13 +1052,25 @@ shell_theme_node_get_border_width (ShellThemeNode *node, ShellSide side) { g_return_val_if_fail (SHELL_IS_THEME_NODE (node), 0.); - g_return_val_if_fail (side >= SHELL_SIDE_LEFT && side <= SHELL_SIDE_BOTTOM, 0.); + g_return_val_if_fail (side >= SHELL_SIDE_TOP && side <= SHELL_SIDE_LEFT, 0.); ensure_borders (node); return node->border_width[side]; } +double +shell_theme_node_get_border_radius (ShellThemeNode *node, + ShellCorner corner) +{ + g_return_val_if_fail (SHELL_IS_THEME_NODE (node), 0.); + g_return_val_if_fail (corner >= SHELL_CORNER_TOPLEFT && corner <= SHELL_CORNER_BOTTOMLEFT, 0.); + + ensure_borders (node); + + return node->border_radius[corner]; +} + static GetFromTermResult get_background_color_from_term (ShellThemeNode *node, CRTerm *term, @@ -1150,7 +1259,7 @@ shell_theme_node_get_border_color (ShellThemeNode *node, ClutterColor *color) { g_return_if_fail (SHELL_IS_THEME_NODE (node)); - g_return_if_fail (side >= SHELL_SIDE_LEFT && side <= SHELL_SIDE_BOTTOM); + g_return_if_fail (side >= SHELL_SIDE_TOP && side <= SHELL_SIDE_LEFT); ensure_borders (node); @@ -1162,7 +1271,7 @@ shell_theme_node_get_padding (ShellThemeNode *node, ShellSide side) { g_return_val_if_fail (SHELL_IS_THEME_NODE (node), 0.); - g_return_val_if_fail (side >= SHELL_SIDE_LEFT && side <= SHELL_SIDE_BOTTOM, 0.); + g_return_val_if_fail (side >= SHELL_SIDE_TOP && side <= SHELL_SIDE_LEFT, 0.); ensure_borders (node); diff --git a/src/toolkit/shell-theme-node.h b/src/toolkit/shell-theme-node.h index 489295e68..a05d68af5 100644 --- a/src/toolkit/shell-theme-node.h +++ b/src/toolkit/shell-theme-node.h @@ -21,12 +21,19 @@ typedef struct _ShellThemeNodeClass ShellThemeNodeClass; #define SHELL_THEME_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_THEME_NODE, ShellThemeNodeClass)) typedef enum { - SHELL_SIDE_LEFT, - SHELL_SIDE_RIGHT, SHELL_SIDE_TOP, - SHELL_SIDE_BOTTOM + SHELL_SIDE_RIGHT, + SHELL_SIDE_BOTTOM, + SHELL_SIDE_LEFT } ShellSide; +typedef enum { + SHELL_CORNER_TOPLEFT, + SHELL_CORNER_TOPRIGHT, + SHELL_CORNER_BOTTOMRIGHT, + SHELL_CORNER_BOTTOMLEFT +} ShellCorner; + /* These are the CSS values; that doesn't mean we have to implement blink... */ typedef enum { SHELL_TEXT_DECORATION_UNDERLINE = 1 << 0, @@ -89,11 +96,14 @@ void shell_theme_node_get_foreground_color (ShellThemeNode *node, const char *shell_theme_node_get_background_image (ShellThemeNode *node); -double shell_theme_node_get_border_width (ShellThemeNode *node, +double shell_theme_node_get_border_width (ShellThemeNode *node, ShellSide side); -void shell_theme_node_get_border_color (ShellThemeNode *node, +double shell_theme_node_get_border_radius (ShellThemeNode *node, + ShellCorner corner); +void shell_theme_node_get_border_color (ShellThemeNode *node, ShellSide side, ClutterColor *color); + double shell_theme_node_get_padding (ShellThemeNode *node, ShellSide side); diff --git a/src/toolkit/test-theme.c b/src/toolkit/test-theme.c index e4b1aebf2..0518eca51 100644 --- a/src/toolkit/test-theme.c +++ b/src/toolkit/test-theme.c @@ -112,6 +112,42 @@ assert_background_color (ShellThemeNode *node, } } +static const char * +side_to_string (ShellSide side) +{ + switch (side) + { + case SHELL_SIDE_TOP: + return "top"; + case SHELL_SIDE_RIGHT: + return "right"; + case SHELL_SIDE_BOTTOM: + return "bottom"; + case SHELL_SIDE_LEFT: + return "left"; + } + + return ""; +} + +static void +assert_border_color (ShellThemeNode *node, + const char *node_description, + ShellSide side, + guint32 expected) +{ + ClutterColor color; + shell_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 (ShellThemeNode *node, const char *node_description, @@ -222,6 +258,40 @@ test_padding (void) shell_theme_node_get_padding (group2, SHELL_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., + shell_theme_node_get_border_width (group2, SHELL_SIDE_TOP)); + assert_length ("group2", "border-right-width", 2., + shell_theme_node_get_border_width (group2, SHELL_SIDE_RIGHT)); + assert_length ("group2", "border-bottom-width", 5., + shell_theme_node_get_border_width (group2, SHELL_SIDE_BOTTOM)); + assert_length ("group2", "border-left-width", 2., + shell_theme_node_get_border_width (group2, SHELL_SIDE_LEFT)); + + assert_border_color (group2, "group2", SHELL_SIDE_TOP, 0x000000ff); + assert_border_color (group2, "group2", SHELL_SIDE_RIGHT, 0x000000ff); + assert_border_color (group2, "group2", SHELL_SIDE_BOTTOM, 0x0000ffff); + assert_border_color (group2, "group2", SHELL_SIDE_LEFT, 0x000000ff); + + assert_length ("group2", "border-radius-topleft", 10., + shell_theme_node_get_border_radius (group2, SHELL_CORNER_TOPLEFT)); + assert_length ("group2", "border-radius-topright", 10., + shell_theme_node_get_border_radius (group2, SHELL_CORNER_TOPRIGHT)); + assert_length ("group2", "border-radius-bottomright", 0., + shell_theme_node_get_border_radius (group2, SHELL_CORNER_BOTTOMRIGHT)); + assert_length ("group2", "border-radius-bottomleft", 0., + shell_theme_node_get_border_radius (group2, SHELL_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/toolkit/test-theme.css b/src/toolkit/test-theme.css index be512d5cd..b2fad3699 100644 --- a/src/toolkit/test-theme.css +++ b/src/toolkit/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 {