From 4ddc1118bb745a489f3b37c4d2475131ba4c36ae Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Mon, 5 Oct 2009 10:10:23 -0400 Subject: [PATCH] Work around libcroco < 0.6.2 parsing bug for 'rgba' To work around a problem where libcroco < 0.6.2 can't handle functions starting with 'r' or 'u', preconvert 'rgba' to 'RGBA' when parsing stylesheets and then check for rgba() case-insensitively. (libcroco is uniformly case-sensitive, though the CSS spec requires that ASCII should be handled case-insensitively.) https://bugzilla.gnome.org/show_bug.cgi?id=597054 --- src/st/st-theme-node.c | 15 +++++-- src/st/st-theme-private.h | 2 + src/st/st-theme.c | 94 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 4 deletions(-) diff --git a/src/st/st-theme-node.c b/src/st/st-theme-node.c index 0b48e47e3..d0e913555 100644 --- a/src/st/st-theme-node.c +++ b/src/st/st-theme-node.c @@ -258,9 +258,7 @@ ensure_properties (StThemeNode *node) if (!properties) properties = g_ptr_array_new (); - node->inline_properties = cr_declaration_parse_list_from_buf ((const guchar *)node->inline_style, - CR_UTF_8); - + node->inline_properties = _st_theme_parse_declaration_list (node->inline_style); for (cur_decl = node->inline_properties; cur_decl; cur_decl = cur_decl->next) g_ptr_array_add (properties, cur_decl); } @@ -408,12 +406,21 @@ get_color_from_term (StThemeNode *node, /* rgba () colors - a CSS3 addition, are not supported by libcroco, * but they are parsed as a "function", so we can emulate the * functionality. + * + * libcroco < 0.6.2 has a bug where functions starting with 'r' are + * misparsed. We workaround this by pre-converting 'rgba' to 'RGBA' + * before parsing the stylesheet. Since libcroco isn't + * case-insensitive (a bug), it's fine with functions starting with + * 'R'. (In theory, we should be doing a case-insensitive compare + * everywhere, not just here, but that doesn't make much sense when + * the built-in parsing of libcroco is case-sensitive and things + * like 10PX don't work.) */ else if (term->type == TERM_FUNCTION && term->content.str && term->content.str->stryng && term->content.str->stryng->str && - strcmp (term->content.str->stryng->str, "rgba") == 0) + g_ascii_strcasecmp (term->content.str->stryng->str, "rgba") == 0) { return get_color_from_rgba_term (term, color); } diff --git a/src/st/st-theme-private.h b/src/st/st-theme-private.h index a307b0824..92e87e833 100644 --- a/src/st/st-theme-private.h +++ b/src/st/st-theme-private.h @@ -15,6 +15,8 @@ char *_st_theme_resolve_url (StTheme *theme, CRStyleSheet *base_stylesheet, const char *url); +CRDeclaration *_st_theme_parse_declaration_list (const char *str); + G_END_DECLS #endif /* __ST_THEME_PRIVATE_H__ */ diff --git a/src/st/st-theme.c b/src/st/st-theme.c index 420f1fa48..944783210 100644 --- a/src/st/st-theme.c +++ b/src/st/st-theme.c @@ -156,6 +156,92 @@ st_theme_class_init (StThemeClass *klass) } +/* This is a workaround for a bug in libcroco < 0.6.2 where + * function starting with 'r' (and 'u') are misparsed. We work + * around this by exploiting the fact that libcroco is incomformant + * with the CSS-spec and case sensitive and pre-convert all + * occurrences of rgba to RGBA. Then we make our own parsing + * code check for RGBA as well. + */ +#if LIBCROCO_VERSION_NUMBER < 602 +static gboolean +is_identifier_character (char c) +{ + /* Actual CSS rules allow for unicode > 0x00a1 and escaped + * characters, but we'll assume we won't do that in our stylesheets + * or at least not next to the string 'rgba'. + */ + return g_ascii_isalnum(c) || c == '-' || c == '_'; +} + +static void +convert_rgba_RGBA (char *buf) +{ + char *p; + + p = strstr (buf, "rgba"); + while (p) + { + /* Check if this looks like a complete token; this is to + * avoiding mangling, say, a selector '.rgba-entry' */ + if (!((p > buf && is_identifier_character (*(p - 1))) || + (is_identifier_character (*(p + 4))))) + memcpy(p, "RGBA", 4); + p += 4; + p = strstr (p, "rgba"); + } +} + +static CRStyleSheet * +parse_stylesheet (const char *filename) +{ + enum CRStatus status; + char *contents; + gsize length; + GError *error = NULL; + CRStyleSheet *stylesheet = NULL; + + if (filename == NULL) + return NULL; + + if (!g_file_get_contents (filename, &contents ,&length, &error)) + { + g_warning("Couldn't read stylesheet: %s", error->message); + g_error_free (error); + + return NULL; + } + + convert_rgba_RGBA (contents); + + status = cr_om_parser_simply_parse_buf ((const guchar *) contents, + length, + CR_UTF_8, + &stylesheet); + + if (status != CR_OK) + g_warning ("Error parsing stylesheet '%s'", filename); + + g_free (contents); + + return stylesheet; +} + +CRDeclaration * +_st_theme_parse_declaration_list (const char *str) +{ + char *copy = g_strdup (str); + CRDeclaration *result; + + convert_rgba_RGBA (copy); + + result = cr_declaration_parse_list_from_buf ((const guchar *)copy, + CR_UTF_8); + g_free (copy); + + return result; +} +#else /* LIBCROCO_VERSION_NUMBER >= 602 */ static CRStyleSheet * parse_stylesheet (const char *filename) { @@ -178,6 +264,14 @@ parse_stylesheet (const char *filename) return stylesheet; } +CRDeclaration * +_st_theme_parse_declaration_list (const char *str) +{ + return cr_declaration_parse_list_from_buf ((const guchar *)str, + CR_UTF_8); +} +#endif /* LIBCROCO_VERSION_NUMBER < 602 */ + static void insert_stylesheet (StTheme *theme, const char *filename,