From cd6dc954f2bd173903d805fe3c4810ae25e82490 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 12 Feb 2016 06:56:14 +0100 Subject: [PATCH] css: Add initial support for calc() So far, calc() only supports literals, ie it's completely useless. --- gtk/Makefile.am | 2 + gtk/gtkcsscalcvalue.c | 152 +++++++++++++++++++++++ gtk/gtkcsscalcvalueprivate.h | 30 +++++ gtk/gtkcssnumbervalue.c | 7 +- testsuite/css/parser/Makefile.am | 2 + testsuite/css/parser/calc-simple.css | 31 +++++ testsuite/css/parser/calc-simple.ref.css | 41 ++++++ 7 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 gtk/gtkcsscalcvalue.c create mode 100644 gtk/gtkcsscalcvalueprivate.h create mode 100644 testsuite/css/parser/calc-simple.css create mode 100644 testsuite/css/parser/calc-simple.ref.css diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 5c2875cf7c..7bf26a62ef 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -387,6 +387,7 @@ gtk_private_h_sources = \ gtkcssarrayvalueprivate.h \ gtkcssbgsizevalueprivate.h \ gtkcssbordervalueprivate.h \ + gtkcsscalcvalueprivate.h \ gtkcsscolorvalueprivate.h \ gtkcsscornervalueprivate.h \ gtkcsscustomgadgetprivate.h \ @@ -652,6 +653,7 @@ gtk_base_c_sources = \ gtkcssarrayvalue.c \ gtkcssbgsizevalue.c \ gtkcssbordervalue.c \ + gtkcsscalcvalue.c \ gtkcsscolorvalue.c \ gtkcsscornervalue.c \ gtkcsscustomgadget.c \ diff --git a/gtk/gtkcsscalcvalue.c b/gtk/gtkcsscalcvalue.c new file mode 100644 index 0000000000..51839c0514 --- /dev/null +++ b/gtk/gtkcsscalcvalue.c @@ -0,0 +1,152 @@ +/* GTK - The GIMP Toolkit + * Copyright © 2016 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gtkcsscalcvalueprivate.h" + +#include "gtkcssenumvalueprivate.h" +#include "gtkcssinitialvalueprivate.h" +#include "gtkstylepropertyprivate.h" + +#include "fallback-c89.c" + +struct _GtkCssValue { + GTK_CSS_VALUE_BASE + GtkCssValue *term; +}; + +static void +gtk_css_value_calc_free (GtkCssValue *value) +{ + _gtk_css_value_unref (value->term); + g_slice_free (GtkCssValue, value); +} + +static GtkCssValue *gtk_css_calc_value_new (GtkCssValue *term); + +static GtkCssValue * +gtk_css_value_calc_compute (GtkCssValue *calc, + guint property_id, + GtkStyleProviderPrivate *provider, + GtkCssStyle *style, + GtkCssStyle *parent_style) +{ + GtkCssValue *computed_term; + + computed_term = _gtk_css_value_compute (calc->term, property_id, provider, style, parent_style); + if (computed_term == calc->term) + return _gtk_css_value_ref (calc); + + return gtk_css_calc_value_new (computed_term); +} + + +static gboolean +gtk_css_value_calc_equal (const GtkCssValue *calc1, + const GtkCssValue *calc2) +{ + return _gtk_css_value_equal (calc1->term, calc2->term); +} + +static GtkCssValue * +gtk_css_value_calc_transition (GtkCssValue *start, + GtkCssValue *end, + guint property_id, + double progress) +{ + return NULL; +} + +static void +gtk_css_value_calc_print (const GtkCssValue *calc, + GString *string) +{ + g_string_append (string, "calc("); + _gtk_css_value_print (calc->term, string); + g_string_append (string, ")"); +} + +double +gtk_css_value_calc_get (const GtkCssValue *value, + double one_hundred_percent) +{ + return _gtk_css_number_value_get (value->term, one_hundred_percent); +} + +GtkCssDimension +gtk_css_value_calc_get_dimension (const GtkCssValue *value) +{ + return gtk_css_number_value_get_dimension (value->term); +} + +gboolean +gtk_css_value_calc_has_percent (const GtkCssValue *value) +{ + return gtk_css_number_value_has_percent (value->term); +} + +static const GtkCssNumberValueClass GTK_CSS_VALUE_CALC = { + { + gtk_css_value_calc_free, + gtk_css_value_calc_compute, + gtk_css_value_calc_equal, + gtk_css_value_calc_transition, + gtk_css_value_calc_print + }, + gtk_css_value_calc_get, + gtk_css_value_calc_get_dimension, + gtk_css_value_calc_has_percent, +}; + +static GtkCssValue * +gtk_css_calc_value_new (GtkCssValue *term) +{ + GtkCssValue *result; + + result = _gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_CALC.value_class); + result->term = term; + + return result; +} + +GtkCssValue * +gtk_css_calc_value_parse (GtkCssParser *parser, + GtkCssNumberParseFlags flags) +{ + GtkCssValue *term; + + if (!_gtk_css_parser_try (parser, "calc(", TRUE)) + { + _gtk_css_parser_error (parser, "Expected 'calc('"); + return NULL; + } + + term = _gtk_css_number_value_parse (parser, flags); + if (term == NULL) + return NULL; + + if (!_gtk_css_parser_try (parser, ")", TRUE)) + { + _gtk_css_value_unref (term); + _gtk_css_parser_error (parser, "Expected ')' for calc() statement"); + return NULL; + } + + return gtk_css_calc_value_new (term); +} + diff --git a/gtk/gtkcsscalcvalueprivate.h b/gtk/gtkcsscalcvalueprivate.h new file mode 100644 index 0000000000..247d4c8a2a --- /dev/null +++ b/gtk/gtkcsscalcvalueprivate.h @@ -0,0 +1,30 @@ +/* + * Copyright © 2016 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef __GTK_CSS_CALC_VALUE_PRIVATE_H__ +#define __GTK_CSS_CALC_VALUE_PRIVATE_H__ + +#include "gtkcssnumbervalueprivate.h" + +G_BEGIN_DECLS + +GtkCssValue * gtk_css_calc_value_parse (GtkCssParser *parser, + GtkCssNumberParseFlags flags); + +G_END_DECLS + +#endif /* __GTK_CSS_CALC_VALUE_PRIVATE_H__ */ diff --git a/gtk/gtkcssnumbervalue.c b/gtk/gtkcssnumbervalue.c index 05643d7364..12508db130 100644 --- a/gtk/gtkcssnumbervalue.c +++ b/gtk/gtkcssnumbervalue.c @@ -19,6 +19,7 @@ #include "gtkcssnumbervalueprivate.h" +#include "gtkcsscalcvalueprivate.h" #include "gtkcssdimensionvalueprivate.h" struct _GtkCssValue { @@ -51,13 +52,17 @@ _gtk_css_number_value_new (double value, gboolean gtk_css_number_value_can_parse (GtkCssParser *parser) { - return _gtk_css_parser_has_number (parser); + return _gtk_css_parser_has_number (parser) + || _gtk_css_parser_has_prefix (parser, "calc"); } GtkCssValue * _gtk_css_number_value_parse (GtkCssParser *parser, GtkCssNumberParseFlags flags) { + if (_gtk_css_parser_has_prefix (parser, "calc")) + return gtk_css_calc_value_parse (parser, flags); + return gtk_css_dimension_value_parse (parser, flags); } diff --git a/testsuite/css/parser/Makefile.am b/testsuite/css/parser/Makefile.am index a90b869798..28fa71fcf3 100644 --- a/testsuite/css/parser/Makefile.am +++ b/testsuite/css/parser/Makefile.am @@ -226,6 +226,8 @@ test_data = \ border-width.ref.css \ box-shadow.css \ box-shadow.ref.css \ + calc-simple.css \ + calc-simple.ref.css \ close-at-end-of-file.css \ close-at-end-of-file.errors \ close-at-end-of-file.ref.css \ diff --git a/testsuite/css/parser/calc-simple.css b/testsuite/css/parser/calc-simple.css new file mode 100644 index 0000000000..ca5327d47e --- /dev/null +++ b/testsuite/css/parser/calc-simple.css @@ -0,0 +1,31 @@ +a { + margin: calc(1px) calc(0px) calc(-3px); +} + +b { + background-position: calc(50%) calc(0%); +} + +c { + background-image: linear-gradient(calc(45deg), red calc(0%), green calc(100%)); +} + +d { + border-radius: calc(1px) calc(2px) / calc(1em) calc(2em) calc(3em); +} + +e { + border-top-left-radius: calc(50%); +} + +f { + border-image-source: radial-gradient(circle calc(20px) at calc(50%) calc(25%), red calc(0%), blue calc(100%)); +} + +g { + border-left: calc(1px); +} + +h { + border-right: red calc(2px); +} diff --git a/testsuite/css/parser/calc-simple.ref.css b/testsuite/css/parser/calc-simple.ref.css new file mode 100644 index 0000000000..2c4c66fee9 --- /dev/null +++ b/testsuite/css/parser/calc-simple.ref.css @@ -0,0 +1,41 @@ +a { + margin-bottom: -3px; + margin-left: 0; + margin-right: 0; + margin-top: 1px; +} + +b { + background-position: top; +} + +c { + background-image: linear-gradient(45deg, rgb(255,0,0) 0, rgb(0,128,0) 100%); +} + +d { + border-bottom-left-radius: 2px 2em; + border-bottom-right-radius: 1px 3em; + border-top-left-radius: 1px 1em; + border-top-right-radius: 2px 2em; +} + +e { + border-top-left-radius: 50%; +} + +f { + border-image-source: radial-gradient(circle 20px at center 25%, rgb(255,0,0) 0, rgb(0,0,255) 100%); +} + +g { + border-left-color: initial; + border-left-style: initial; + border-left-width: 1px; +} + +h { + border-right-color: rgb(255,0,0); + border-right-style: initial; + border-right-width: 2px; +}