Commit 6962b49a authored by Benjamin Otte's avatar Benjamin Otte

css: Introduce GtkCssComputedValues

To be used for storing computed values. Is the replacement for
GtkStyleProperties, which is now legacy code.
parent 694a9114
......@@ -411,6 +411,7 @@ gtk_private_h_sources = \
gtkbuttonprivate.h \
gtkcellareaboxcontextprivate.h \
gtkcontainerprivate.h \
gtkcsscomputedvaluesprivate.h \
gtkcsscustompropertyprivate.h \
gtkcssimagegradientprivate.h \
gtkcssimageprivate.h \
......@@ -592,6 +593,7 @@ gtk_base_c_sources = \
gtkcombobox.c \
gtkcomboboxtext.c \
gtkcontainer.c \
gtkcsscomputedvalues.c \
gtkcsscustomproperty.c \
gtkcssimage.c \
gtkcssimagegradient.c \
......
/*
* Copyright © 2012 Red Hat Inc.
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkcsscomputedvaluesprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkcsstypesprivate.h"
#include "gtkprivatetypebuiltins.h"
G_DEFINE_TYPE (GtkCssComputedValues, _gtk_css_computed_values, G_TYPE_OBJECT)
static void
gtk_css_computed_values_dispose (GObject *object)
{
GtkCssComputedValues *values = GTK_CSS_COMPUTED_VALUES (object);
if (values->values)
{
g_value_array_free (values->values);
values->values = NULL;
}
if (values->sections)
{
g_ptr_array_unref (values->sections);
values->sections = NULL;
}
G_OBJECT_CLASS (_gtk_css_computed_values_parent_class)->dispose (object);
}
static void
_gtk_css_computed_values_class_init (GtkCssComputedValuesClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_css_computed_values_dispose;
}
static void
_gtk_css_computed_values_init (GtkCssComputedValues *computed_values)
{
}
GtkCssComputedValues *
_gtk_css_computed_values_new (void)
{
return g_object_new (GTK_TYPE_CSS_COMPUTED_VALUES, NULL);
}
static void
maybe_unref_section (gpointer section)
{
if (section)
gtk_css_section_unref (section);
}
void
_gtk_css_computed_values_compute_value (GtkCssComputedValues *values,
GtkStyleContext *context,
guint id,
const GValue *specified,
GtkCssSection *section)
{
GtkCssStyleProperty *prop;
GtkStyleContext *parent;
g_return_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values));
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (specified == NULL || G_IS_VALUE (specified));
prop = _gtk_css_style_property_lookup_by_id (id);
parent = gtk_style_context_get_parent (context);
if (values->values == NULL)
values->values = g_value_array_new (id + 1);
while (values->values->n_values <= id)
g_value_array_append (values->values, NULL);
/* http://www.w3.org/TR/css3-cascade/#cascade
* Then, for every element, the value for each property can be found
* by following this pseudo-algorithm:
* 1) Identify all declarations that apply to the element
*/
if (specified != NULL)
{
if (G_VALUE_HOLDS (specified, GTK_TYPE_CSS_SPECIAL_VALUE))
{
switch (g_value_get_enum (specified))
{
case GTK_CSS_INHERIT:
/* 3) if the value of the winning declaration is ‘inherit’,
* the inherited value (see below) becomes the specified value.
*/
specified = NULL;
break;
case GTK_CSS_INITIAL:
/* if the value of the winning declaration is ‘initial’,
* the initial value (see below) becomes the specified value.
*/
specified = _gtk_css_style_property_get_initial_value (prop);
break;
default:
/* This is part of (2) above */
break;
}
}
/* 2) If the cascading process (described below) yields a winning
* declaration and the value of the winning declaration is not
* ‘initial’ or ‘inherit’, the value of the winning declaration
* becomes the specified value.
*/
}
else
{
if (_gtk_css_style_property_is_inherit (prop))
{
/* 4) if the property is inherited, the inherited value becomes
* the specified value.
*/
specified = NULL;
}
else
{
/* 5) Otherwise, the initial value becomes the specified value.
*/
specified = _gtk_css_style_property_get_initial_value (prop);
}
}
if (specified == NULL && parent == NULL)
{
/* If the ‘inherit’ value is set on the root element, the property is
* assigned its initial value. */
specified = _gtk_css_style_property_get_initial_value (prop);
}
if (specified)
{
_gtk_css_style_property_compute_value (prop,
g_value_array_get_nth (values->values, id),
context,
specified);
}
else
{
const GValue *parent_value;
GValue *value = g_value_array_get_nth (values->values, id);
/* Set NULL here and do the inheritance upon lookup? */
parent_value = _gtk_style_context_peek_property (parent,
_gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop)));
g_value_init (value, G_VALUE_TYPE (parent_value));
g_value_copy (parent_value, value);
}
if (section)
{
if (values->sections == NULL)
values->sections = g_ptr_array_new_with_free_func (maybe_unref_section);
if (values->sections->len <= id)
g_ptr_array_set_size (values->sections, id + 1);
g_ptr_array_index (values->sections, id) = gtk_css_section_ref (section);
}
}
const GValue *
_gtk_css_computed_values_get_value (GtkCssComputedValues *values,
guint id)
{
const GValue *v;
g_return_val_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values), NULL);
if (values->values == NULL ||
id >= values->values->n_values)
return NULL;
v = g_value_array_get_nth (values->values, id);
if (!G_IS_VALUE (v))
return NULL;
return v;
}
const GValue *
_gtk_css_computed_values_get_value_by_name (GtkCssComputedValues *values,
const char *name)
{
GtkStyleProperty *prop;
g_return_val_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values), NULL);
g_return_val_if_fail (name != NULL, NULL);
prop = _gtk_style_property_lookup (name);
g_assert (GTK_IS_CSS_STYLE_PROPERTY (prop));
return _gtk_css_computed_values_get_value (values, _gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop)));
}
GtkCssSection *
_gtk_css_computed_values_get_section (GtkCssComputedValues *values,
guint id)
{
g_return_val_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values), NULL);
if (values->sections == NULL ||
id >= values->sections->len)
return NULL;
return g_ptr_array_index (values->sections, id);
}
/*
* Copyright © 2012 Red Hat Inc.
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_CSS_COMPUTED_VALUES_PRIVATE_H__
#define __GTK_CSS_COMPUTED_VALUES_PRIVATE_H__
#include <glib-object.h>
#include "gtk/gtkcsssection.h"
#include "gtk/gtkstylecontext.h"
G_BEGIN_DECLS
#define GTK_TYPE_CSS_COMPUTED_VALUES (_gtk_css_computed_values_get_type ())
#define GTK_CSS_COMPUTED_VALUES(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_COMPUTED_VALUES, GtkCssComputedValues))
#define GTK_CSS_COMPUTED_VALUES_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_COMPUTED_VALUES, GtkCssComputedValuesClass))
#define GTK_IS_CSS_COMPUTED_VALUES(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_COMPUTED_VALUES))
#define GTK_IS_CSS_COMPUTED_VALUES_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_COMPUTED_VALUES))
#define GTK_CSS_COMPUTED_VALUES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_COMPUTED_VALUES, GtkCssComputedValuesClass))
typedef struct _GtkCssComputedValues GtkCssComputedValues;
typedef struct _GtkCssComputedValuesClass GtkCssComputedValuesClass;
struct _GtkCssComputedValues
{
GObject parent;
GValueArray *values;
GPtrArray *sections;
};
struct _GtkCssComputedValuesClass
{
GObjectClass parent_class;
};
GType _gtk_css_computed_values_get_type (void) G_GNUC_CONST;
GtkCssComputedValues * _gtk_css_computed_values_new (void);
void _gtk_css_computed_values_compute_value (GtkCssComputedValues *values,
GtkStyleContext *context,
guint id,
const GValue *specified,
GtkCssSection *section);
void _gtk_css_computed_values_set_value (GtkCssComputedValues *values,
guint id,
const GValue *value,
GtkCssSection *section);
const GValue * _gtk_css_computed_values_get_value (GtkCssComputedValues *values,
guint id);
const GValue * _gtk_css_computed_values_get_value_by_name (GtkCssComputedValues *values,
const char *name);
GtkCssSection * _gtk_css_computed_values_get_section (GtkCssComputedValues *values,
guint id);
G_END_DECLS
#endif /* __GTK_CSS_COMPUTED_VALUES_PRIVATE_H__ */
......@@ -107,7 +107,7 @@ _gtk_css_lookup_set (GtkCssLookup *lookup,
* _gtk_css_lookup_resolve:
* @lookup: the lookup
* @context: the context the values are resolved for
* @props: a new #GtkStyleProperties to be filled with the new properties
* @values: a new #GtkCssComputedValues to be filled with the new properties
*
* Resolves the current lookup into a styleproperties object. This is done
* by converting from the "winning declaration" to the "computed value".
......@@ -116,106 +116,24 @@ _gtk_css_lookup_set (GtkCssLookup *lookup,
* an issue, go fix it.
**/
void
_gtk_css_lookup_resolve (GtkCssLookup *lookup,
GtkStyleContext *context,
GtkStyleProperties *props)
_gtk_css_lookup_resolve (GtkCssLookup *lookup,
GtkStyleContext *context,
GtkCssComputedValues *values)
{
GtkStyleContext *parent;
guint i, n;
g_return_if_fail (lookup != NULL);
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (GTK_IS_STYLE_PROPERTIES (props));
g_return_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values));
parent = gtk_style_context_get_parent (context);
n = _gtk_css_style_property_get_n_properties ();
for (i = 0; i < n; i++)
{
GtkCssStyleProperty *prop = _gtk_css_style_property_lookup_by_id (i);
const GValue *result;
GValue value = { 0, };
/* http://www.w3.org/TR/css3-cascade/#cascade
* Then, for every element, the value for each property can be found
* by following this pseudo-algorithm:
* 1) Identify all declarations that apply to the element
*/
if (lookup->values[i].value != NULL)
{
/* 2) If the cascading process (described below) yields a winning
* declaration and the value of the winning declaration is not
* ‘initial’ or ‘inherit’, the value of the winning declaration
* becomes the specified value.
*/
if (!G_VALUE_HOLDS (lookup->values[i].value, GTK_TYPE_CSS_SPECIAL_VALUE))
{
result = lookup->values[i].value;
}
else
{
switch (g_value_get_enum (lookup->values[i].value))
{
case GTK_CSS_INHERIT:
/* 3) if the value of the winning declaration is ‘inherit’,
* the inherited value (see below) becomes the specified value.
*/
result = NULL;
break;
case GTK_CSS_INITIAL:
/* if the value of the winning declaration is ‘initial’,
* the initial value (see below) becomes the specified value.
*/
result = _gtk_css_style_property_get_initial_value (prop);
break;
default:
/* This is part of (2) above */
result = lookup->values[i].value;
break;
}
}
}
else
{
if (_gtk_css_style_property_is_inherit (prop))
{
/* 4) if the property is inherited, the inherited value becomes
* the specified value.
*/
result = NULL;
}
else
{
/* 5) Otherwise, the initial value becomes the specified value.
*/
result = _gtk_css_style_property_get_initial_value (prop);
}
}
if (result == NULL && parent == NULL)
{
/* If the ‘inherit’ value is set on the root element, the property is
* assigned its initial value. */
result = _gtk_css_style_property_get_initial_value (prop);
}
if (result)
{
_gtk_css_style_property_compute_value (prop, &value, context, result);
}
else
{
/* Set NULL here and do the inheritance upon lookup? */
result = _gtk_style_context_peek_property (parent,
_gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop)));
g_value_init (&value, G_VALUE_TYPE (result));
g_value_copy (result, &value);
}
_gtk_style_properties_set_property_by_property (props,
prop,
0,
&value);
g_value_unset (&value);
_gtk_css_computed_values_compute_value (values,
context,
i,
lookup->values[i].value,
lookup->values[i].section);
}
}
......@@ -22,9 +22,9 @@
#include <glib-object.h>
#include "gtk/gtkbitmaskprivate.h"
#include "gtk/gtkcsscomputedvaluesprivate.h"
#include "gtk/gtkcsssection.h"
#include "gtk/gtkstylecontext.h"
#include "gtk/gtkstyleproperties.h"
G_BEGIN_DECLS
......@@ -43,7 +43,7 @@ void _gtk_css_lookup_set (GtkCssLookup
const GValue *value);
void _gtk_css_lookup_resolve (GtkCssLookup *lookup,
GtkStyleContext *context,
GtkStyleProperties *props);
GtkCssComputedValues *values);
G_END_DECLS
......
......@@ -337,7 +337,7 @@ struct GtkStyleInfo
struct StyleData
{
GtkStyleProperties *store;
GtkCssComputedValues *store;
GSList *icon_factories;
GArray *property_cache;
};
......@@ -987,7 +987,7 @@ build_properties (GtkStyleContext *context,
}
}
style_data->store = gtk_style_properties_new ();
style_data->store = _gtk_css_computed_values_new ();
_gtk_css_lookup_resolve (lookup, context, style_data->store);
_gtk_css_lookup_free (lookup);
}
......@@ -1073,6 +1073,7 @@ style_data_lookup (GtkStyleContext *context,
GtkStyleContextPrivate *priv;
StyleData *data;
gboolean state_mismatch;
const GValue *v;
priv = context->priv;
state_mismatch = ((GtkStyleInfo *) priv->info_stack->data)->state_flags != state;
......@@ -1114,11 +1115,10 @@ style_data_lookup (GtkStyleContext *context,
if (priv->theming_engine)
g_object_unref (priv->theming_engine);
gtk_style_properties_get (priv->current_data->store, 0,
"engine", &priv->theming_engine,
NULL);
if (!priv->theming_engine)
v = _gtk_css_computed_values_get_value_by_name (priv->current_data->store, "engine");
if (v)
priv->theming_engine = g_value_dup_object (v);
else
priv->theming_engine = g_object_ref (gtk_theming_engine_load (NULL));
if (G_UNLIKELY (state_mismatch))
......@@ -1399,6 +1399,13 @@ gtk_style_context_remove_provider_for_screen (GdkScreen *screen,
}
}
static const GValue *
gtk_style_context_query_func (guint id,
gpointer values)
{
return _gtk_css_computed_values_get_value (values, id);
}
/**
* gtk_style_context_get_property:
* @context: a #GtkStyleContext
......@@ -1420,6 +1427,7 @@ gtk_style_context_get_property (GtkStyleContext *context,
GValue *value)
{
GtkStyleContextPrivate *priv;
GtkStyleProperty *prop;
StyleData *data;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
......@@ -1427,11 +1435,22 @@ gtk_style_context_get_property (GtkStyleContext *context,
g_return_if_fail (value != NULL);
priv = context->priv;
g_return_if_fail (priv->widget_path != NULL);
prop = _gtk_style_property_lookup (property);
if (prop == NULL)
{
g_warning ("Style property \"%s\" is not registered", property);
return;
}
if (_gtk_style_property_get_value_type (prop) == G_TYPE_NONE)
{
g_warning ("Style property \"%s\" is not gettable", property);
return;
}
data = style_data_lookup (context, state);
gtk_style_properties_get_property (data->store, property, 0, value);
_gtk_style_property_query (prop, value, gtk_style_context_query_func, data->store);
}
/**
......@@ -1449,16 +1468,34 @@ gtk_style_context_get_valist (GtkStyleContext *context,
GtkStateFlags state,
va_list args)
{
GtkStyleContextPrivate *priv;
StyleData *data;
const gchar *property_name;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
priv = context->priv;
g_return_if_fail (priv->widget_path != NULL);
property_name = va_arg (args, const gchar *);
data = style_data_lookup (context, state);
gtk_style_properties_get_valist (data->store, 0, args);
while (property_name)
{
gchar *error = NULL;
GValue value = G_VALUE_INIT;
gtk_style_context_get_property (context,
property_name,
state,
&value);
G_VALUE_LCOPY (&value, args, 0, &error);
g_value_unset (&value);
if (error)
{
g_warning ("Could not get style property \"%s\": %s", property_name, error);
g_free (error);
break;
}
property_name = va_arg (args, const gchar *);
}
}
/**
......@@ -2288,21 +2325,9 @@ const GValue *
_gtk_style_context_peek_property (GtkStyleContext *context,
const char *property_name)
{
GtkStyleProperty *property;
StyleData *data;
property = _gtk_style_property_lookup (property_name);
if (!GTK_IS_CSS_STYLE_PROPERTY (property))
{
g_warning ("Style property \"%s\" does not exist", property_name);
return NULL;
}
data = style_data_lookup (context, gtk_style_context_get_state (context));
StyleData *data = style_data_lookup (context, gtk_style_context_get_state (context));
return _gtk_style_properties_peek_property (data->store,
GTK_CSS_STYLE_PROPERTY (property),
0);
return _gtk_css_computed_values_get_value_by_name (data->store, property_name);
}
const GValue *
......@@ -2946,6 +2971,7 @@ gtk_style_context_notify_state_change (GtkStyleContext *context,
GtkAnimationDescription *desc;
AnimationInfo *info;
GtkStateFlags flags;
const GValue *v;
StyleData *data;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
......@@ -2987,10 +3013,10 @@ gtk_style_context_notify_state_change (GtkStyleContext *context,
* state, it will fallback to the normal state as well if necessary.
*/
data = style_data_lookup (context, flags);
gtk_style_properties_get (data->store, 0,
"transition", &desc,
NULL);
v = _gtk_css_computed_values_get_value_by_name (data->store, "transition");
if (!v)
return;
desc = g_value_get_boxed (v);
if (!desc)
return;
......@@ -3630,7 +3656,6 @@ gtk_style_context_get_font (GtkStyleContext *context,
{
GtkStyleContextPrivate *priv;
StyleData *data;
GHashTable *font_cache;
PangoFontDescription *description;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
......@@ -3642,27 +3667,15 @@ gtk_style_context_get_font (GtkStyleContext *context,
/* Yuck, fonts are created on-demand but we don't return a ref.
* Do bad things to achieve this requirement */
font_cache = g_object_get_data (G_OBJECT (data->store), "font-cache-for-get_font");
if (font_cache)
{
description = g_hash_table_lookup (font_cache, GUINT_TO_POINTER (state));
}
else
description = g_object_get_data (G_OBJECT (data->store), "font-cache-for-get_font");
if (description == NULL)
{
font_cache = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) pango_font_description_free);
gtk_style_context_get (context, state, "font", &description, NULL);
g_object_set_data_full (G_OBJECT (data->store),
"font-cache-for-get_font",
font_cache,
(GDestroyNotify) g_hash_table_unref);
description = NULL;
description,
(GDestroyNotify) pango_font_description_free);
}
if (description == NULL)
{
gtk_style_properties_get (data->store, 0, "font", &description, NULL);
g_hash_table_insert (font_cache, GUINT_TO_POINTER (state), description);
}
return description;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment