* 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "gtkcsstypesprivate.h"
#include "gtkprivatetypebuiltins.h"
#include "gtkstylepropertiesprivate.h"
+#include "gtksymboliccolorprivate.h"
#include "gtktypebuiltins.h"
/* this is in case round() is not provided by the compiler,
}
static gboolean
-parse_border_width (GtkCssShorthandProperty *shorthand,
+parse_four_numbers (GtkCssShorthandProperty *shorthand,
GValue *values,
GtkCssParser *parser,
- GFile *base)
+ GtkCssNumberParseFlags flags)
{
- GValue temp = G_VALUE_INIT;
- GtkBorder *border;
+ GtkCssNumber numbers[4];
+ guint i;
- g_value_init (&temp, GTK_TYPE_BORDER);
- if (!_gtk_css_style_parse_value (&temp, parser, base))
+ for (i = 0; i < 4; i++)
{
- g_value_unset (&temp);
- return FALSE;
+ if (!_gtk_css_parser_has_number (parser))
+ break;
+
+ if (!_gtk_css_parser_read_number (parser,
+ &numbers[i],
+ flags))
+ return FALSE;
}
- border = g_value_get_boxed (&temp);
+ if (i == 0)
+ {
+ _gtk_css_parser_error (parser, "Expected a length");
+ return FALSE;
+ }
- g_value_init (&values[0], G_TYPE_INT);
- g_value_init (&values[1], G_TYPE_INT);
- g_value_init (&values[2], G_TYPE_INT);
- g_value_init (&values[3], G_TYPE_INT);
- g_value_set_int (&values[0], border->top);
- g_value_set_int (&values[1], border->right);
- g_value_set_int (&values[2], border->bottom);
- g_value_set_int (&values[3], border->left);
+ for (; i < 4; i++)
+ {
+ numbers[i] = numbers[(i - 1) >> 1];
+ }
- g_value_unset (&temp);
+ for (i = 0; i < 4; i++)
+ {
+ g_value_init (&values[i], GTK_TYPE_CSS_NUMBER);
+ g_value_set_boxed (&values[i], &numbers[i]);
+ }
return TRUE;
}
+static gboolean
+parse_margin (GtkCssShorthandProperty *shorthand,
+ GValue *values,
+ GtkCssParser *parser,
+ GFile *base)
+{
+ return parse_four_numbers (shorthand,
+ values,
+ parser,
+ GTK_CSS_NUMBER_AS_PIXELS
+ | GTK_CSS_PARSE_LENGTH);
+}
+
+static gboolean
+parse_padding (GtkCssShorthandProperty *shorthand,
+ GValue *values,
+ GtkCssParser *parser,
+ GFile *base)
+{
+ return parse_four_numbers (shorthand,
+ values,
+ parser,
+ GTK_CSS_POSITIVE_ONLY
+ | GTK_CSS_NUMBER_AS_PIXELS
+ | GTK_CSS_PARSE_LENGTH);
+}
+
+static gboolean
+parse_border_width (GtkCssShorthandProperty *shorthand,
+ GValue *values,
+ GtkCssParser *parser,
+ GFile *base)
+{
+ return parse_four_numbers (shorthand,
+ values,
+ parser,
+ GTK_CSS_POSITIVE_ONLY
+ | GTK_CSS_NUMBER_AS_PIXELS
+ | GTK_CSS_PARSE_LENGTH);
+}
+
static gboolean
parse_border_radius (GtkCssShorthandProperty *shorthand,
GValue *values,
for (i = 0; i < G_N_ELEMENTS (borders); i++)
{
- if (!_gtk_css_parser_try_double (parser, &borders[i].horizontal))
+ if (!_gtk_css_parser_has_number (parser))
break;
- if (borders[i].horizontal < 0)
- {
- _gtk_css_parser_error (parser, "Border radius values cannot be negative");
- return FALSE;
- }
+ if (!_gtk_css_parser_read_number (parser,
+ &borders[i].horizontal,
+ GTK_CSS_POSITIVE_ONLY
+ | GTK_CSS_PARSE_PERCENT
+ | GTK_CSS_NUMBER_AS_PIXELS
+ | GTK_CSS_PARSE_LENGTH))
+ return FALSE;
}
if (i == 0)
{
for (i = 0; i < G_N_ELEMENTS (borders); i++)
{
- if (!_gtk_css_parser_try_double (parser, &borders[i].vertical))
+ if (!_gtk_css_parser_has_number (parser))
break;
- if (borders[i].vertical < 0)
- {
- _gtk_css_parser_error (parser, "Border radius values cannot be negative");
- return FALSE;
- }
+ if (!_gtk_css_parser_read_number (parser,
+ &borders[i].vertical,
+ GTK_CSS_POSITIVE_ONLY
+ | GTK_CSS_PARSE_PERCENT
+ | GTK_CSS_NUMBER_AS_PIXELS
+ | GTK_CSS_PARSE_LENGTH))
+ return FALSE;
}
if (i == 0)
for (i = 0; i < 4; i++)
{
- symbolic = _gtk_css_parser_read_symbolic_color (parser);
- if (symbolic == NULL)
- return FALSE;
+ if (_gtk_css_parser_try (parser, "currentcolor", TRUE))
+ {
+ symbolic = gtk_symbolic_color_ref (_gtk_symbolic_color_get_current_color ());
+ }
+ else
+ {
+ symbolic = _gtk_css_parser_read_symbolic_color (parser);
+ if (symbolic == NULL)
+ return FALSE;
+ }
g_value_init (&values[i], GTK_TYPE_SYMBOLIC_COLOR);
g_value_set_boxed (&values[i], symbolic);
for (i++; i < 4; i++)
{
- g_value_init (&values[i], GTK_TYPE_SYMBOLIC_COLOR);
+ g_value_init (&values[i], G_VALUE_TYPE (&values[(i - 1) >> 1]));
g_value_copy (&values[(i - 1) >> 1], &values[i]);
}
GtkCssParser *parser,
GFile *base)
{
- int width;
int style;
do
{
if (!G_IS_VALUE (&values[0]) &&
- _gtk_css_parser_try_length (parser, &width))
+ _gtk_css_parser_has_number (parser))
{
- g_value_init (&values[0], G_TYPE_INT);
- g_value_set_int (&values[0], width);
+ GtkCssNumber number;
+ if (!_gtk_css_parser_read_number (parser,
+ &number,
+ GTK_CSS_POSITIVE_ONLY
+ | GTK_CSS_NUMBER_AS_PIXELS
+ | GTK_CSS_PARSE_LENGTH))
+ return FALSE;
+
+ g_value_init (&values[0], GTK_TYPE_CSS_NUMBER);
+ g_value_set_boxed (&values[0], &number);
}
else if (!G_IS_VALUE (&values[1]) &&
_gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
GtkCssParser *parser,
GFile *base)
{
- int width;
int style;
do
{
if (!G_IS_VALUE (&values[0]) &&
- _gtk_css_parser_try_length (parser, &width))
+ _gtk_css_parser_has_number (parser))
{
- g_value_init (&values[0], G_TYPE_INT);
- g_value_init (&values[1], G_TYPE_INT);
- g_value_init (&values[2], G_TYPE_INT);
- g_value_init (&values[3], G_TYPE_INT);
- g_value_set_int (&values[0], width);
- g_value_set_int (&values[1], width);
- g_value_set_int (&values[2], width);
- g_value_set_int (&values[3], width);
+ GtkCssNumber number;
+ if (!_gtk_css_parser_read_number (parser,
+ &number,
+ GTK_CSS_POSITIVE_ONLY
+ | GTK_CSS_NUMBER_AS_PIXELS
+ | GTK_CSS_PARSE_LENGTH))
+ return FALSE;
+
+ g_value_init (&values[0], GTK_TYPE_CSS_NUMBER);
+ g_value_init (&values[1], GTK_TYPE_CSS_NUMBER);
+ g_value_init (&values[2], GTK_TYPE_CSS_NUMBER);
+ g_value_init (&values[3], GTK_TYPE_CSS_NUMBER);
+ g_value_set_boxed (&values[0], &number);
+ g_value_set_boxed (&values[1], &number);
+ g_value_set_boxed (&values[2], &number);
+ g_value_set_boxed (&values[3], &number);
}
else if (!G_IS_VALUE (&values[4]) &&
_gtk_css_parser_try_enum (parser, GTK_TYPE_BORDER_STYLE, &style))
/*** PACKING ***/
-static GParameter *
-unpack_border (const GValue *value,
- guint *n_params,
- const char *top,
- const char *left,
- const char *bottom,
- const char *right)
+static void
+unpack_border (GtkCssShorthandProperty *shorthand,
+ GtkStyleProperties *props,
+ GtkStateFlags state,
+ const GValue *value)
{
- GParameter *parameter = g_new0 (GParameter, 4);
+ GValue v = G_VALUE_INIT;
GtkBorder *border = g_value_get_boxed (value);
- parameter[0].name = top;
- g_value_init (¶meter[0].value, G_TYPE_INT);
- g_value_set_int (¶meter[0].value, border->top);
- parameter[1].name = left;
- g_value_init (¶meter[1].value, G_TYPE_INT);
- g_value_set_int (¶meter[1].value, border->left);
- parameter[2].name = bottom;
- g_value_init (¶meter[2].value, G_TYPE_INT);
- g_value_set_int (¶meter[2].value, border->bottom);
- parameter[3].name = right;
- g_value_init (¶meter[3].value, G_TYPE_INT);
- g_value_set_int (¶meter[3].value, border->right);
-
- *n_params = 4;
- return parameter;
+ g_value_init (&v, G_TYPE_INT);
+
+ g_value_set_int (&v, border->top);
+ _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 0)), props, state, &v);
+ g_value_set_int (&v, border->right);
+ _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 1)), props, state, &v);
+ g_value_set_int (&v, border->bottom);
+ _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 2)), props, state, &v);
+ g_value_set_int (&v, border->left);
+ _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, 3)), props, state, &v);
+
+ g_value_unset (&v);
}
static void
pack_border (GtkCssShorthandProperty *shorthand,
GValue *value,
- GtkStyleProperties *props,
- GtkStateFlags state)
+ GtkStyleQueryFunc query_func,
+ gpointer query_data)
{
GtkCssStyleProperty *prop;
GtkBorder border;
const GValue *v;
prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
- v = _gtk_style_properties_peek_property (props, prop, state);
+ v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
if (v)
border.top = g_value_get_int (v);
prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 1);
- v = _gtk_style_properties_peek_property (props, prop, state);
+ v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
if (v)
border.right = g_value_get_int (v);
prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 2);
- v = _gtk_style_properties_peek_property (props, prop, state);
+ v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
if (v)
border.bottom = g_value_get_int (v);
prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 3);
- v = _gtk_style_properties_peek_property (props, prop, state);
+ v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
if (v)
border.left = g_value_get_int (v);
g_value_set_boxed (value, &border);
}
-static GParameter *
-unpack_border_width (GtkCssShorthandProperty *shorthand,
- const GValue *value,
- guint *n_params)
-{
- return unpack_border (value, n_params,
- "border-top-width", "border-left-width",
- "border-bottom-width", "border-right-width");
-}
-
-static GParameter *
-unpack_padding (GtkCssShorthandProperty *shorthand,
- const GValue *value,
- guint *n_params)
-{
- return unpack_border (value, n_params,
- "padding-top", "padding-left",
- "padding-bottom", "padding-right");
-}
-
-static GParameter *
-unpack_margin (GtkCssShorthandProperty *shorthand,
- const GValue *value,
- guint *n_params)
-{
- return unpack_border (value, n_params,
- "margin-top", "margin-left",
- "margin-bottom", "margin-right");
-}
-
-static GParameter *
+static void
unpack_border_radius (GtkCssShorthandProperty *shorthand,
- const GValue *value,
- guint *n_params)
+ GtkStyleProperties *props,
+ GtkStateFlags state,
+ const GValue *value)
{
- GParameter *parameter = g_new0 (GParameter, 4);
GtkCssBorderCornerRadius border;
+ GValue v = G_VALUE_INIT;
+ guint i;
- border.horizontal = border.vertical = g_value_get_int (value);
-
- parameter[0].name = "border-top-left-radius";
- g_value_init (¶meter[0].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
- g_value_set_boxed (¶meter[0].value, &border);
- parameter[1].name = "border-top-right-radius";
- g_value_init (¶meter[1].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
- g_value_set_boxed (¶meter[1].value, &border);
- parameter[2].name = "border-bottom-right-radius";
- g_value_init (¶meter[2].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
- g_value_set_boxed (¶meter[2].value, &border);
- parameter[3].name = "border-bottom-left-radius";
- g_value_init (¶meter[3].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
- g_value_set_boxed (¶meter[3].value, &border);
-
- *n_params = 4;
- return parameter;
+ _gtk_css_number_init (&border.horizontal, g_value_get_int (value), GTK_CSS_PX);
+ border.vertical = border.horizontal;
+ g_value_init (&v, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
+ g_value_set_boxed (&v, &border);
+
+ for (i = 0; i < 4; i++)
+ _gtk_style_property_assign (GTK_STYLE_PROPERTY (_gtk_css_shorthand_property_get_subproperty (shorthand, i)), props, state, &v);
+
+ g_value_unset (&v);
}
static void
pack_border_radius (GtkCssShorthandProperty *shorthand,
GValue *value,
- GtkStyleProperties *props,
- GtkStateFlags state)
+ GtkStyleQueryFunc query_func,
+ gpointer query_data)
{
GtkCssBorderCornerRadius *top_left;
+ GtkCssStyleProperty *prop;
+ const GValue *v;
- /* NB: We are an int property, so we have to resolve to an int here.
- * So we just resolve to an int. We pick one and stick to it.
- * Lesson learned: Don't query border-radius shorthand, query the
- * real properties instead. */
- gtk_style_properties_get (props,
- state,
- "border-top-left-radius", &top_left,
- NULL);
-
- if (top_left)
- g_value_set_int (value, top_left->horizontal);
-
- g_free (top_left);
+ prop = GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("border-top-left-radius"));
+ v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
+ if (v)
+ {
+ top_left = g_value_get_boxed (v);
+ if (top_left)
+ g_value_set_int (value, top_left->horizontal.value);
+ }
}
-static GParameter *
+static void
unpack_font_description (GtkCssShorthandProperty *shorthand,
- const GValue *value,
- guint *n_params)
+ GtkStyleProperties *props,
+ GtkStateFlags state,
+ const GValue *value)
{
- GParameter *parameter = g_new0 (GParameter, 5);
+ GtkStyleProperty *prop;
PangoFontDescription *description;
PangoFontMask mask;
- guint n;
+ GValue v = G_VALUE_INIT;
/* For backwards compat, we only unpack values that are indeed set.
* For strict CSS conformance we need to unpack all of them.
*/
description = g_value_get_boxed (value);
- n = 0;
if (description)
mask = pango_font_description_get_set_fields (description);
g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description)));
g_ptr_array_add (strv, NULL);
- parameter[n].name = "font-family";
- g_value_init (¶meter[n].value, G_TYPE_STRV);
- g_value_take_boxed (¶meter[n].value,
- g_ptr_array_free (strv, FALSE));
- n++;
+ g_value_init (&v, G_TYPE_STRV);
+ g_value_take_boxed (&v, g_ptr_array_free (strv, FALSE));
+
+ prop = _gtk_style_property_lookup ("font-family");
+ _gtk_style_property_assign (prop, props, state, &v);
+ g_value_unset (&v);
}
if (mask & PANGO_FONT_MASK_STYLE)
{
- parameter[n].name = "font-style";
- g_value_init (¶meter[n].value, PANGO_TYPE_STYLE);
- g_value_set_enum (¶meter[n].value,
- pango_font_description_get_style (description));
- n++;
+ g_value_init (&v, PANGO_TYPE_STYLE);
+ g_value_set_enum (&v, pango_font_description_get_style (description));
+
+ prop = _gtk_style_property_lookup ("font-style");
+ _gtk_style_property_assign (prop, props, state, &v);
+ g_value_unset (&v);
}
if (mask & PANGO_FONT_MASK_VARIANT)
{
- parameter[n].name = "font-variant";
- g_value_init (¶meter[n].value, PANGO_TYPE_VARIANT);
- g_value_set_enum (¶meter[n].value,
- pango_font_description_get_variant (description));
- n++;
+ g_value_init (&v, PANGO_TYPE_VARIANT);
+ g_value_set_enum (&v, pango_font_description_get_variant (description));
+
+ prop = _gtk_style_property_lookup ("font-variant");
+ _gtk_style_property_assign (prop, props, state, &v);
+ g_value_unset (&v);
}
if (mask & PANGO_FONT_MASK_WEIGHT)
{
- parameter[n].name = "font-weight";
- g_value_init (¶meter[n].value, PANGO_TYPE_WEIGHT);
- g_value_set_enum (¶meter[n].value,
- pango_font_description_get_weight (description));
- n++;
+ g_value_init (&v, PANGO_TYPE_WEIGHT);
+ g_value_set_enum (&v, pango_font_description_get_weight (description));
+
+ prop = _gtk_style_property_lookup ("font-weight");
+ _gtk_style_property_assign (prop, props, state, &v);
+ g_value_unset (&v);
}
if (mask & PANGO_FONT_MASK_SIZE)
{
- parameter[n].name = "font-size";
- g_value_init (¶meter[n].value, G_TYPE_DOUBLE);
- g_value_set_double (¶meter[n].value,
- (double) pango_font_description_get_size (description) / PANGO_SCALE);
- n++;
- }
-
- *n_params = n;
+ g_value_init (&v, G_TYPE_DOUBLE);
+ g_value_set_double (&v, (double) pango_font_description_get_size (description) / PANGO_SCALE);
- return parameter;
+ prop = _gtk_style_property_lookup ("font-size");
+ _gtk_style_property_assign (prop, props, state, &v);
+ g_value_unset (&v);
+ }
}
static void
pack_font_description (GtkCssShorthandProperty *shorthand,
GValue *value,
- GtkStyleProperties *props,
- GtkStateFlags state)
+ GtkStyleQueryFunc query_func,
+ gpointer query_data)
{
PangoFontDescription *description;
- char **families;
- PangoStyle style;
- PangoVariant variant;
- PangoWeight weight;
- double size;
-
- gtk_style_properties_get (props,
- state,
- "font-family", &families,
- "font-style", &style,
- "font-variant", &variant,
- "font-weight", &weight,
- "font-size", &size,
- NULL);
+ const GValue *v;
description = pango_font_description_new ();
- /* xxx: Can we set all the families here somehow? */
- if (families)
- pango_font_description_set_family (description, families[0]);
- pango_font_description_set_size (description, round (size * PANGO_SCALE));
- pango_font_description_set_style (description, style);
- pango_font_description_set_variant (description, variant);
- pango_font_description_set_weight (description, weight);
- g_strfreev (families);
+ v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-family"))), query_data);
+ if (v)
+ {
+ const char **families = g_value_get_boxed (v);
+ /* xxx: Can we set all the families here somehow? */
+ if (families)
+ pango_font_description_set_family (description, families[0]);
+ }
+
+ v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-size"))), query_data);
+ if (v)
+ pango_font_description_set_size (description, round (g_value_get_double (v) * PANGO_SCALE));
+
+ v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-style"))), query_data);
+ if (v)
+ pango_font_description_set_style (description, g_value_get_enum (v));
+
+ v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-variant"))), query_data);
+ if (v)
+ pango_font_description_set_variant (description, g_value_get_enum (v));
+
+ v = (* query_func) (_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (_gtk_style_property_lookup ("font-weight"))), query_data);
+ if (v)
+ pango_font_description_set_weight (description, g_value_get_enum (v));
g_value_take_boxed (value, description);
}
-static GParameter *
+static void
unpack_to_everything (GtkCssShorthandProperty *shorthand,
- const GValue *value,
- guint *n_params)
+ GtkStyleProperties *props,
+ GtkStateFlags state,
+ const GValue *value)
{
GtkCssStyleProperty *prop;
- GParameter *parameter;
guint i, n;
- GType type;
n = _gtk_css_shorthand_property_get_n_subproperties (shorthand);
- parameter = g_new0 (GParameter, n);
- type = G_VALUE_TYPE (value);
for (i = 0; i < n; i++)
{
prop = _gtk_css_shorthand_property_get_subproperty (shorthand, i);
- parameter[i].name = _gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop));
- g_value_init (¶meter[i].value, type);
- g_value_copy (value, ¶meter[i].value);
+ _gtk_style_property_assign (GTK_STYLE_PROPERTY (prop), props, state, value);
}
-
- *n_params = n;
- return parameter;
}
static void
pack_first_element (GtkCssShorthandProperty *shorthand,
GValue *value,
- GtkStyleProperties *props,
- GtkStateFlags state)
+ GtkStyleQueryFunc query_func,
+ gpointer query_data)
{
GtkCssStyleProperty *prop;
const GValue *v;
for (i = 0; i < _gtk_css_shorthand_property_get_n_subproperties (shorthand); i++)
{
prop = _gtk_css_shorthand_property_get_subproperty (shorthand, 0);
- v = _gtk_style_properties_peek_property (props, prop, state);
+ v = (* query_func) (_gtk_css_style_property_get_id (prop), query_data);
if (v)
{
g_value_copy (v, value);
_gtk_css_shorthand_property_register ("margin",
GTK_TYPE_BORDER,
margin_subproperties,
- parse_border_width,
- unpack_margin,
+ parse_margin,
+ unpack_border,
pack_border);
_gtk_css_shorthand_property_register ("padding",
GTK_TYPE_BORDER,
padding_subproperties,
- parse_border_width,
- unpack_padding,
+ parse_padding,
+ unpack_border,
pack_border);
_gtk_css_shorthand_property_register ("border-width",
GTK_TYPE_BORDER,
border_width_subproperties,
parse_border_width,
- unpack_border_width,
+ unpack_border,
pack_border);
_gtk_css_shorthand_property_register ("border-radius",
G_TYPE_INT,