diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-01-26 17:40:34 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-01-26 17:53:14 -0500 |
commit | 1258fcaaf4d1148efb1b3f7a7dffba1b27f61c1c (patch) | |
tree | cd89365dc3431db002dc676a40b8c03df23a7493 | |
parent | b6e7acfb9008979ef9b14f4e7a74f01701148b78 (diff) | |
download | gtk+-1258fcaaf4d1148efb1b3f7a7dffba1b27f61c1c.tar.gz |
css: Fix text-decoration-line support
This property needs to be treated as flags, not as
enum, since it should be possible to specify more
than one value, e.g.
text-decoration-line: underline overline;
Tests included.
Fixes: #3621
-rw-r--r-- | gtk/gtkcssenumvalue.c | 145 | ||||
-rw-r--r-- | gtk/gtkcssenumvalueprivate.h | 9 | ||||
-rw-r--r-- | gtk/gtkcssshorthandpropertyimpl.c | 30 | ||||
-rw-r--r-- | gtk/gtkcssstyle.c | 17 | ||||
-rw-r--r-- | gtk/gtkcssstylepropertyimpl.c | 37 | ||||
-rw-r--r-- | gtk/gtkcsstypesprivate.h | 8 | ||||
-rw-r--r-- | testsuite/css/parser/meson.build | 2 | ||||
-rw-r--r-- | testsuite/css/parser/text-decoration-line.css | 8 | ||||
-rw-r--r-- | testsuite/css/parser/text-decoration-line.ref.css | 8 | ||||
-rw-r--r-- | testsuite/css/parser/text-decoration.css | 23 | ||||
-rw-r--r-- | testsuite/css/parser/text-decoration.ref.css | 35 |
11 files changed, 236 insertions, 86 deletions
diff --git a/gtk/gtkcssenumvalue.c b/gtk/gtkcssenumvalue.c index 6a9b4bfec7..d28daf5ac2 100644 --- a/gtk/gtkcssenumvalue.c +++ b/gtk/gtkcssenumvalue.c @@ -545,58 +545,6 @@ _gtk_css_font_stretch_value_get (const GtkCssValue *value) return value->value; } -/* GtkTextDecorationLine */ - -static const GtkCssValueClass GTK_CSS_VALUE_TEXT_DECORATION_LINE = { - "GtkCssTextDecorationLineValue", - gtk_css_value_enum_free, - gtk_css_value_enum_compute, - gtk_css_value_enum_equal, - gtk_css_value_enum_transition, - NULL, - NULL, - gtk_css_value_enum_print -}; - -static GtkCssValue text_decoration_line_values[] = { - { >K_CSS_VALUE_TEXT_DECORATION_LINE, 1, TRUE, GTK_CSS_TEXT_DECORATION_LINE_NONE, "none" }, - { >K_CSS_VALUE_TEXT_DECORATION_LINE, 1, TRUE, GTK_CSS_TEXT_DECORATION_LINE_UNDERLINE, "underline" }, - { >K_CSS_VALUE_TEXT_DECORATION_LINE, 1, TRUE, GTK_CSS_TEXT_DECORATION_LINE_OVERLINE, "overline" }, - { >K_CSS_VALUE_TEXT_DECORATION_LINE, 1, TRUE, GTK_CSS_TEXT_DECORATION_LINE_LINE_THROUGH, "line-through" }, -}; - -GtkCssValue * -_gtk_css_text_decoration_line_value_new (GtkTextDecorationLine line) -{ - g_return_val_if_fail (line < G_N_ELEMENTS (text_decoration_line_values), NULL); - - return _gtk_css_value_ref (&text_decoration_line_values[line]); -} - -GtkCssValue * -_gtk_css_text_decoration_line_value_try_parse (GtkCssParser *parser) -{ - guint i; - - g_return_val_if_fail (parser != NULL, NULL); - - for (i = 0; i < G_N_ELEMENTS (text_decoration_line_values); i++) - { - if (gtk_css_parser_try_ident (parser, text_decoration_line_values[i].name)) - return _gtk_css_value_ref (&text_decoration_line_values[i]); - } - - return NULL; -} - -GtkTextDecorationLine -_gtk_css_text_decoration_line_value_get (const GtkCssValue *value) -{ - g_return_val_if_fail (value->class == >K_CSS_VALUE_TEXT_DECORATION_LINE, GTK_CSS_TEXT_DECORATION_LINE_NONE); - - return value->value; -} - /* GtkTextDecorationStyle */ static const GtkCssValueClass GTK_CSS_VALUE_TEXT_DECORATION_STYLE = { @@ -1204,6 +1152,99 @@ gtk_css_value_flags_print (const FlagsValue *values, } } +/* GtkTextDecorationLine */ + +static FlagsValue text_decoration_line_values[] = { + { GTK_CSS_TEXT_DECORATION_LINE_NONE, "none" }, + { GTK_CSS_TEXT_DECORATION_LINE_UNDERLINE, "underline" }, + { GTK_CSS_TEXT_DECORATION_LINE_OVERLINE, "overline" }, + { GTK_CSS_TEXT_DECORATION_LINE_LINE_THROUGH, "line-through" }, +}; + +static void +gtk_css_text_decoration_line_value_print (const GtkCssValue *value, + GString *string) +{ + gtk_css_value_flags_print (text_decoration_line_values, + G_N_ELEMENTS (text_decoration_line_values), + value, string); +} + +static const GtkCssValueClass GTK_CSS_VALUE_TEXT_DECORATION_LINE = { + "GtkCssTextDecorationLine", + gtk_css_value_enum_free, + gtk_css_value_enum_compute, + gtk_css_value_flags_equal, + gtk_css_value_enum_transition, + NULL, + NULL, + gtk_css_text_decoration_line_value_print +}; + +static gboolean +text_decoration_line_is_valid (GtkTextDecorationLine line) +{ + if ((line & GTK_CSS_TEXT_DECORATION_LINE_NONE) && + (line != GTK_CSS_TEXT_DECORATION_LINE_NONE)) + return FALSE; + + return TRUE; +} + +GtkCssValue * +_gtk_css_text_decoration_line_value_new (GtkTextDecorationLine line) +{ + GtkCssValue *value; + + if (!text_decoration_line_is_valid (line)) + return NULL; + + value = _gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_TEXT_DECORATION_LINE); + value->value = line; + value->name = NULL; + value->is_computed = TRUE; + + return value; +} + +GtkTextDecorationLine +_gtk_css_text_decoration_line_try_parse_one (GtkCssParser *parser, + GtkTextDecorationLine base) +{ + guint i; + GtkTextDecorationLine value = 0; + + g_return_val_if_fail (parser != NULL, 0); + + for (i = 0; i < G_N_ELEMENTS (text_decoration_line_values); i++) + { + if (gtk_css_parser_try_ident (parser, text_decoration_line_values[i].name)) + { + value = text_decoration_line_values[i].value; + break; + } + } + + if (value == 0) + return base; /* not parsing this value */ + + if ((base | value) == base) + return 0; /* repeated value */ + + if (!text_decoration_line_is_valid (base | value)) + return 0; /* bad combination */ + + return base | value; +} + +GtkTextDecorationLine +_gtk_css_text_decoration_line_value_get (const GtkCssValue *value) +{ + g_return_val_if_fail (value->class == >K_CSS_VALUE_TEXT_DECORATION_LINE, GTK_CSS_TEXT_DECORATION_LINE_NONE); + + return value->value; +} + /* GtkCssFontVariantLigature */ static FlagsValue font_variant_ligature_values[] = { diff --git a/gtk/gtkcssenumvalueprivate.h b/gtk/gtkcssenumvalueprivate.h index 7ac181b7a9..a102a8650b 100644 --- a/gtk/gtkcssenumvalueprivate.h +++ b/gtk/gtkcssenumvalueprivate.h @@ -54,11 +54,12 @@ GtkCssValue * _gtk_css_font_stretch_value_new (PangoStretch stretc GtkCssValue * _gtk_css_font_stretch_value_try_parse (GtkCssParser *parser); PangoStretch _gtk_css_font_stretch_value_get (const GtkCssValue *value); -GtkCssValue * _gtk_css_text_decoration_line_value_new (GtkTextDecorationLine line); -GtkCssValue * _gtk_css_text_decoration_line_value_try_parse (GtkCssParser *parser); -GtkTextDecorationLine _gtk_css_text_decoration_line_value_get (const GtkCssValue *value); +GtkCssValue * _gtk_css_text_decoration_line_value_new (GtkTextDecorationLine line); +GtkTextDecorationLine _gtk_css_text_decoration_line_try_parse_one (GtkCssParser *parser, + GtkTextDecorationLine base); +GtkTextDecorationLine _gtk_css_text_decoration_line_value_get (const GtkCssValue *value); -GtkCssValue * _gtk_css_text_decoration_style_value_new (GtkTextDecorationStyle style); +GtkCssValue * _gtk_css_text_decoration_style_value_new (GtkTextDecorationStyle style); GtkCssValue * _gtk_css_text_decoration_style_value_try_parse (GtkCssParser *parser); GtkTextDecorationStyle _gtk_css_text_decoration_style_value_get (const GtkCssValue *value); diff --git a/gtk/gtkcssshorthandpropertyimpl.c b/gtk/gtkcssshorthandpropertyimpl.c index 4a9b97fd07..5908904d25 100644 --- a/gtk/gtkcssshorthandpropertyimpl.c +++ b/gtk/gtkcssshorthandpropertyimpl.c @@ -865,16 +865,26 @@ parse_text_decoration (GtkCssShorthandProperty *shorthand, GtkCssValue **values, GtkCssParser *parser) { + GtkTextDecorationLine line = 0; + do { - if (values[0] == NULL && - (values[0] = _gtk_css_text_decoration_line_value_try_parse (parser))) + GtkTextDecorationLine parsed_line; + + parsed_line = _gtk_css_text_decoration_line_try_parse_one (parser, line); + + if (parsed_line == 0 && line != 0) { - if (values[0] == NULL) - return FALSE; + gtk_css_parser_error_value (parser, "Invalid combination of text-decoration-line values"); + return FALSE; + } + + if (parsed_line != line) + { + line = parsed_line; } else if (values[1] == NULL && - (values[1] = _gtk_css_text_decoration_style_value_try_parse (parser))) + (values[1] = _gtk_css_text_decoration_style_value_try_parse (parser))) { if (values[1] == NULL) return FALSE; @@ -895,6 +905,16 @@ parse_text_decoration (GtkCssShorthandProperty *shorthand, } while (!value_is_done_parsing (parser)); + if (line != 0) + { + values[0] = _gtk_css_text_decoration_line_value_new (line); + if (values[0] == NULL) + { + gtk_css_parser_error_value (parser, "Invalid combination of text-decoration-line values"); + return FALSE; + } + } + return TRUE; } diff --git a/gtk/gtkcssstyle.c b/gtk/gtkcssstyle.c index ee6f9c44c5..91830266a5 100644 --- a/gtk/gtkcssstyle.c +++ b/gtk/gtkcssstyle.c @@ -451,32 +451,29 @@ gtk_css_style_get_pango_attributes (GtkCssStyle *style) ? style->font_variant->text_decoration_color : style->core->color); - switch (decoration_line) + if (decoration_line & GTK_CSS_TEXT_DECORATION_LINE_UNDERLINE) { - case GTK_CSS_TEXT_DECORATION_LINE_UNDERLINE: attrs = add_pango_attr (attrs, pango_attr_underline_new (get_pango_underline_from_style (decoration_style))); if (!gdk_rgba_equal (color, decoration_color)) attrs = add_pango_attr (attrs, pango_attr_underline_color_new (decoration_color->red * 65535. + 0.5, decoration_color->green * 65535. + 0.5, decoration_color->blue * 65535. + 0.5)); - break; - case GTK_CSS_TEXT_DECORATION_LINE_OVERLINE: + } + if (decoration_line & GTK_CSS_TEXT_DECORATION_LINE_OVERLINE) + { attrs = add_pango_attr (attrs, pango_attr_overline_new (get_pango_overline_from_style (decoration_style))); if (!gdk_rgba_equal (color, decoration_color)) attrs = add_pango_attr (attrs, pango_attr_overline_color_new (decoration_color->red * 65535. + 0.5, decoration_color->green * 65535. + 0.5, decoration_color->blue * 65535. + 0.5)); - break; - case GTK_CSS_TEXT_DECORATION_LINE_LINE_THROUGH: + } + if (decoration_line & GTK_CSS_TEXT_DECORATION_LINE_LINE_THROUGH) + { attrs = add_pango_attr (attrs, pango_attr_strikethrough_new (TRUE)); if (!gdk_rgba_equal (color, decoration_color)) attrs = add_pango_attr (attrs, pango_attr_strikethrough_color_new (decoration_color->red * 65535. + 0.5, decoration_color->green * 65535. + 0.5, decoration_color->blue * 65535. + 0.5)); - break; - case GTK_CSS_TEXT_DECORATION_LINE_NONE: - default: - break; } /* letter-spacing */ diff --git a/gtk/gtkcssstylepropertyimpl.c b/gtk/gtkcssstylepropertyimpl.c index 3eb4ac7c5c..8e5d4bf796 100644 --- a/gtk/gtkcssstylepropertyimpl.c +++ b/gtk/gtkcssstylepropertyimpl.c @@ -317,14 +317,38 @@ parse_letter_spacing (GtkCssStyleProperty *property, return _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_LENGTH); } +static gboolean +value_is_done_parsing (GtkCssParser *parser) +{ + return gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF) || + gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_COMMA) || + gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SEMICOLON) || + gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_CLOSE_CURLY); +} + static GtkCssValue * parse_text_decoration_line (GtkCssStyleProperty *property, GtkCssParser *parser) { - GtkCssValue *value = _gtk_css_text_decoration_line_value_try_parse (parser); + GtkCssValue *value = NULL; + GtkTextDecorationLine line; + + line = 0; + do { + GtkTextDecorationLine parsed; + + parsed = _gtk_css_text_decoration_line_try_parse_one (parser, line); + if (parsed == 0 || parsed == line) + { + gtk_css_parser_error_syntax (parser, "Not a valid value"); + return NULL; + } + line = parsed; + } while (!value_is_done_parsing (parser)); + value = _gtk_css_text_decoration_line_value_new (line); if (value == NULL) - gtk_css_parser_error_syntax (parser, "unknown text decoration line value"); + gtk_css_parser_error_syntax (parser, "Invalid combination of values"); return value; } @@ -353,15 +377,6 @@ parse_font_kerning (GtkCssStyleProperty *property, return value; } -static gboolean -value_is_done_parsing (GtkCssParser *parser) -{ - return gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF) || - gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_COMMA) || - gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SEMICOLON) || - gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_CLOSE_CURLY); -} - static GtkCssValue * parse_font_variant_ligatures (GtkCssStyleProperty *property, GtkCssParser *parser) diff --git a/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h index efb54a5561..35ae56a41c 100644 --- a/gtk/gtkcsstypesprivate.h +++ b/gtk/gtkcsstypesprivate.h @@ -325,10 +325,10 @@ typedef enum /*< skip >*/ { } GtkCssFontSize; typedef enum /*< skip >*/ { - GTK_CSS_TEXT_DECORATION_LINE_NONE, - GTK_CSS_TEXT_DECORATION_LINE_UNDERLINE, - GTK_CSS_TEXT_DECORATION_LINE_OVERLINE, - GTK_CSS_TEXT_DECORATION_LINE_LINE_THROUGH + GTK_CSS_TEXT_DECORATION_LINE_NONE = 1 << 0, + GTK_CSS_TEXT_DECORATION_LINE_UNDERLINE = 1 << 1, + GTK_CSS_TEXT_DECORATION_LINE_OVERLINE = 1 << 2, + GTK_CSS_TEXT_DECORATION_LINE_LINE_THROUGH = 1 << 3 } GtkTextDecorationLine; typedef enum /*< skip >*/ { diff --git a/testsuite/css/parser/meson.build b/testsuite/css/parser/meson.build index f70753c2b5..b398251450 100644 --- a/testsuite/css/parser/meson.build +++ b/testsuite/css/parser/meson.build @@ -423,6 +423,8 @@ test_data = [ 'string-values.css', 'string-values.ref.css', 'test.png', + 'text-decoration.css', + 'text-decoration.ref.css', 'text-decoration-color.css', 'text-decoration-color.ref.css', 'text-decoration-line.css', diff --git a/testsuite/css/parser/text-decoration-line.css b/testsuite/css/parser/text-decoration-line.css index 16311eb23c..1725688a8c 100644 --- a/testsuite/css/parser/text-decoration-line.css +++ b/testsuite/css/parser/text-decoration-line.css @@ -21,3 +21,11 @@ e { f { text-decoration-line: line-through; } + +g { + text-decoration-line: overline; +} + +h { + text-decoration-line: underline overline; +} diff --git a/testsuite/css/parser/text-decoration-line.ref.css b/testsuite/css/parser/text-decoration-line.ref.css index 16311eb23c..1725688a8c 100644 --- a/testsuite/css/parser/text-decoration-line.ref.css +++ b/testsuite/css/parser/text-decoration-line.ref.css @@ -21,3 +21,11 @@ e { f { text-decoration-line: line-through; } + +g { + text-decoration-line: overline; +} + +h { + text-decoration-line: underline overline; +} diff --git a/testsuite/css/parser/text-decoration.css b/testsuite/css/parser/text-decoration.css new file mode 100644 index 0000000000..3496b0713a --- /dev/null +++ b/testsuite/css/parser/text-decoration.css @@ -0,0 +1,23 @@ +a { + text-decoration: underline; +} + +b { + text-decoration: wavy; +} + +c { + text-decoration: red; +} + +d { + text-decoration: red wavy; +} + +e { + text-decoration: none; +} + +f { + text-decoration: red underline wavy overline; +} diff --git a/testsuite/css/parser/text-decoration.ref.css b/testsuite/css/parser/text-decoration.ref.css new file mode 100644 index 0000000000..7369332ce3 --- /dev/null +++ b/testsuite/css/parser/text-decoration.ref.css @@ -0,0 +1,35 @@ +a { + text-decoration-color: initial; + text-decoration-line: underline; + text-decoration-style: initial; +} + +b { + text-decoration-color: initial; + text-decoration-line: initial; + text-decoration-style: wavy; +} + +c { + text-decoration-color: rgb(255,0,0); + text-decoration-line: initial; + text-decoration-style: initial; +} + +d { + text-decoration-color: rgb(255,0,0); + text-decoration-line: initial; + text-decoration-style: wavy; +} + +e { + text-decoration-color: initial; + text-decoration-line: none; + text-decoration-style: initial; +} + +f { + text-decoration-color: rgb(255,0,0); + text-decoration-line: underline overline; + text-decoration-style: wavy; +} |