csskeyframes: Support variables
This commit is contained in:
@@ -142,3 +142,9 @@ gtk_css_variable_value_set_section (GtkCssVariableValue *self,
|
||||
{
|
||||
self->section = gtk_css_section_ref (section);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_css_variable_value_taint (GtkCssVariableValue *self)
|
||||
{
|
||||
self->is_animation_tainted = TRUE;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ struct _GtkCssVariableValue
|
||||
|
||||
GtkCssSection *section;
|
||||
gboolean is_invalid;
|
||||
gboolean is_animation_tainted;
|
||||
};
|
||||
|
||||
GtkCssVariableValue *gtk_css_variable_value_new (GBytes *bytes,
|
||||
@@ -70,5 +71,6 @@ GtkCssVariableValue *gtk_css_variable_value_transition (GtkCssVariableValue
|
||||
double progress);
|
||||
void gtk_css_variable_value_set_section (GtkCssVariableValue *self,
|
||||
GtkCssSection *section);
|
||||
void gtk_css_variable_value_taint (GtkCssVariableValue *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -33,13 +33,59 @@
|
||||
#include "gtkcssstringvalueprivate.h"
|
||||
#include "gtkcssstylepropertyprivate.h"
|
||||
#include "gtkcsstransitionprivate.h"
|
||||
#include "gtkcssvaluesprivate.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkstyleanimationprivate.h"
|
||||
#include "gtkstylepropertyprivate.h"
|
||||
#include "gtkstyleproviderprivate.h"
|
||||
#include "gtkcsscustompropertypoolprivate.h"
|
||||
|
||||
G_DEFINE_TYPE (GtkCssAnimatedStyle, gtk_css_animated_style, GTK_TYPE_CSS_STYLE)
|
||||
|
||||
#define DEFINE_VALUES(ENUM, TYPE, NAME) \
|
||||
static inline void \
|
||||
gtk_css_ ## NAME ## _values_recompute (GtkCssAnimatedStyle *animated) \
|
||||
{ \
|
||||
GtkCssStyle *style = (GtkCssStyle *)animated; \
|
||||
GtkCssValue **values = (GtkCssValue **)((guint8*)(animated->style->NAME) + sizeof (GtkCssValues)); \
|
||||
int i; \
|
||||
\
|
||||
for (i = 0; i < G_N_ELEMENTS (NAME ## _props); i++) \
|
||||
{ \
|
||||
guint id = NAME ## _props[i]; \
|
||||
GtkCssValue *original, *computed; \
|
||||
\
|
||||
if (values[i] == NULL) \
|
||||
continue; \
|
||||
\
|
||||
original = gtk_css_style_get_original_value (style, id); \
|
||||
if (original == NULL) \
|
||||
continue; \
|
||||
\
|
||||
computed = _gtk_css_value_compute (original, \
|
||||
id, \
|
||||
animated->provider, \
|
||||
style, \
|
||||
animated->parent_style, \
|
||||
NULL); \
|
||||
if (computed == NULL) \
|
||||
continue; \
|
||||
\
|
||||
gtk_css_animated_style_set_animated_value (animated, id, computed); \
|
||||
} \
|
||||
}
|
||||
|
||||
DEFINE_VALUES (CORE, Core, core)
|
||||
DEFINE_VALUES (BACKGROUND, Background, background)
|
||||
DEFINE_VALUES (BORDER, Border, border)
|
||||
DEFINE_VALUES (ICON, Icon, icon)
|
||||
DEFINE_VALUES (OUTLINE, Outline, outline)
|
||||
DEFINE_VALUES (FONT, Font, font)
|
||||
DEFINE_VALUES (FONT_VARIANT, FontVariant, font_variant)
|
||||
DEFINE_VALUES (ANIMATION, Animation, animation)
|
||||
DEFINE_VALUES (TRANSITION, Transition, transition)
|
||||
DEFINE_VALUES (SIZE, Size, size)
|
||||
DEFINE_VALUES (OTHER, Other, other)
|
||||
|
||||
static GtkCssSection *
|
||||
gtk_css_animated_style_get_section (GtkCssStyle *style,
|
||||
@@ -74,6 +120,15 @@ gtk_css_animated_style_get_static_style (GtkCssStyle *style)
|
||||
return (GtkCssStaticStyle *)animated->style;
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
gtk_css_animated_style_get_original_value (GtkCssStyle *style,
|
||||
guint id)
|
||||
{
|
||||
GtkCssAnimatedStyle *animated = GTK_CSS_ANIMATED_STYLE (style);
|
||||
|
||||
return gtk_css_style_get_original_value (animated->style, id);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_animated_style_dispose (GObject *object)
|
||||
{
|
||||
@@ -115,6 +170,7 @@ gtk_css_animated_style_class_init (GtkCssAnimatedStyleClass *klass)
|
||||
style_class->get_section = gtk_css_animated_style_get_section;
|
||||
style_class->is_static = gtk_css_animated_style_is_static;
|
||||
style_class->get_static_style = gtk_css_animated_style_get_static_style;
|
||||
style_class->get_original_value = gtk_css_animated_style_get_original_value;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -549,6 +605,51 @@ gtk_css_animated_style_get_intrinsic_value (GtkCssAnimatedStyle *style,
|
||||
return gtk_css_style_get_value (style->style, id);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_css_animated_style_set_animated_custom_value (GtkCssAnimatedStyle *animated,
|
||||
int id,
|
||||
GtkCssVariableValue *value)
|
||||
{
|
||||
GtkCssStyle *style = (GtkCssStyle *)animated;
|
||||
|
||||
gtk_internal_return_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style));
|
||||
gtk_internal_return_if_fail (value != NULL);
|
||||
|
||||
if (style->variables == NULL)
|
||||
{
|
||||
style->variables = gtk_css_variable_set_new ();
|
||||
if (animated->parent_style)
|
||||
gtk_css_variable_set_set_parent (style->variables,
|
||||
animated->parent_style->variables);
|
||||
}
|
||||
else if (style->variables == animated->style->variables)
|
||||
{
|
||||
gtk_css_variable_set_unref (style->variables);
|
||||
style->variables = gtk_css_variable_set_copy (animated->style->variables);
|
||||
}
|
||||
|
||||
gtk_css_variable_set_add (style->variables, id, value);
|
||||
|
||||
gtk_css_core_values_recompute (animated);
|
||||
gtk_css_background_values_recompute (animated);
|
||||
gtk_css_border_values_recompute (animated);
|
||||
gtk_css_icon_values_recompute (animated);
|
||||
gtk_css_outline_values_recompute (animated);
|
||||
gtk_css_font_values_recompute (animated);
|
||||
gtk_css_font_variant_values_recompute (animated);
|
||||
gtk_css_animation_values_recompute (animated);
|
||||
gtk_css_transition_values_recompute (animated);
|
||||
gtk_css_size_values_recompute (animated);
|
||||
gtk_css_other_values_recompute (animated);
|
||||
}
|
||||
|
||||
GtkCssVariableValue *
|
||||
gtk_css_animated_style_get_intrinsic_custom_value (GtkCssAnimatedStyle *style,
|
||||
int id)
|
||||
{
|
||||
return gtk_css_style_get_custom_property (style->style, id);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
gtk_css_animated_style_create_dynamic (GPtrArray *animations,
|
||||
GtkCssStyle *style,
|
||||
@@ -920,6 +1021,8 @@ gtk_css_animated_style_new (GtkCssStyle *base_style,
|
||||
style->transition = (GtkCssTransitionValues *)gtk_css_values_ref ((GtkCssValues *)base_style->transition);
|
||||
style->size = (GtkCssSizeValues *)gtk_css_values_ref ((GtkCssValues *)base_style->size);
|
||||
style->other = (GtkCssOtherValues *)gtk_css_values_ref ((GtkCssValues *)base_style->other);
|
||||
if (base_style->variables)
|
||||
style->variables = gtk_css_variable_set_ref (base_style->variables);
|
||||
|
||||
gtk_css_animated_style_apply_animations (result);
|
||||
|
||||
@@ -991,6 +1094,8 @@ gtk_css_animated_style_new_advance (GtkCssAnimatedStyle *source,
|
||||
style->transition = (GtkCssTransitionValues *)gtk_css_values_ref ((GtkCssValues *)base_style->transition);
|
||||
style->size = (GtkCssSizeValues *)gtk_css_values_ref ((GtkCssValues *)base_style->size);
|
||||
style->other = (GtkCssOtherValues *)gtk_css_values_ref ((GtkCssValues *)base_style->other);
|
||||
if (base_style->variables)
|
||||
style->variables = gtk_css_variable_set_ref (base_style->variables);
|
||||
|
||||
gtk_css_animated_style_apply_animations (result);
|
||||
|
||||
|
||||
@@ -67,10 +67,15 @@ GtkCssStyle * gtk_css_animated_style_new_advance (GtkCssAnimatedS
|
||||
void gtk_css_animated_style_set_animated_value(GtkCssAnimatedStyle *style,
|
||||
guint id,
|
||||
GtkCssValue *value);
|
||||
|
||||
GtkCssValue * gtk_css_animated_style_get_intrinsic_value (GtkCssAnimatedStyle *style,
|
||||
guint id);
|
||||
|
||||
void gtk_css_animated_style_set_animated_custom_value (GtkCssAnimatedStyle *animated,
|
||||
int id,
|
||||
GtkCssVariableValue *value);
|
||||
GtkCssVariableValue * gtk_css_animated_style_get_intrinsic_custom_value (GtkCssAnimatedStyle *style,
|
||||
int id);
|
||||
|
||||
GtkCssStyle * gtk_css_animated_style_get_base_style (GtkCssAnimatedStyle *style);
|
||||
GtkCssStyle * gtk_css_animated_style_get_parent_style (GtkCssAnimatedStyle *style);
|
||||
GtkStyleProvider * gtk_css_animated_style_get_provider (GtkCssAnimatedStyle *style);
|
||||
|
||||
@@ -110,6 +110,26 @@ gtk_css_animation_apply_values (GtkStyleAnimation *style_animation,
|
||||
base_style,
|
||||
parent_style);
|
||||
|
||||
for (i = 0; i < _gtk_css_keyframes_get_n_variables (resolved_keyframes); i++)
|
||||
{
|
||||
GtkCssVariableValue *value;
|
||||
int variable_id;
|
||||
|
||||
variable_id = _gtk_css_keyframes_get_variable_id (resolved_keyframes, i);
|
||||
|
||||
value = _gtk_css_keyframes_get_variable (resolved_keyframes,
|
||||
i,
|
||||
progress,
|
||||
gtk_css_animated_style_get_intrinsic_custom_value (style, variable_id));
|
||||
|
||||
if (!value)
|
||||
continue;
|
||||
|
||||
gtk_css_animated_style_set_animated_custom_value (style, variable_id, value);
|
||||
|
||||
gtk_css_variable_value_unref (value);
|
||||
}
|
||||
|
||||
for (i = 0; i < _gtk_css_keyframes_get_n_properties (resolved_keyframes); i++)
|
||||
{
|
||||
GtkCssValue *value;
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "gtkcssstyleprivate.h"
|
||||
#include "gtkcssarrayvalueprivate.h"
|
||||
#include "gtkcsscustompropertypoolprivate.h"
|
||||
#include "gtkcssreferencevalueprivate.h"
|
||||
#include "gtkcssshorthandpropertyprivate.h"
|
||||
#include "gtkcssstylepropertyprivate.h"
|
||||
#include "gtkstylepropertyprivate.h"
|
||||
@@ -31,12 +33,15 @@
|
||||
#include <string.h>
|
||||
|
||||
struct _GtkCssKeyframes {
|
||||
int ref_count; /* ref count */
|
||||
int n_keyframes; /* number of keyframes (at least 2 for 0% and 100% */
|
||||
double *keyframe_progress; /* ordered array of n_keyframes of [0..1] */
|
||||
int n_properties; /* number of properties used by keyframes */
|
||||
guint *property_ids; /* ordered array of n_properties property ids */
|
||||
GtkCssValue **values; /* 2D array: n_keyframes * n_properties of (value or NULL) for all the keyframes */
|
||||
int ref_count; /* ref count */
|
||||
int n_keyframes; /* number of keyframes (at least 2 for 0% and 100% */
|
||||
double *keyframe_progress; /* ordered array of n_keyframes of [0..1] */
|
||||
int n_properties; /* number of properties used by keyframes */
|
||||
guint *property_ids; /* ordered array of n_properties property ids */
|
||||
GtkCssValue **values; /* 2D array: n_keyframes * n_properties of (value or NULL) for all the keyframes */
|
||||
GtkCssVariableSet **variables; /* array of variable sets for each keyframe */
|
||||
int *variable_ids; /* ordered array of variable ids */
|
||||
int n_variables; /* number of variable used by keyframes */
|
||||
};
|
||||
|
||||
#define KEYFRAMES_VALUE(keyframes, k, p) ((keyframes)->values[(k) * (keyframes)->n_properties + (p)])
|
||||
@@ -72,8 +77,13 @@ _gtk_css_keyframes_unref (GtkCssKeyframes *keyframes)
|
||||
_gtk_css_value_unref (KEYFRAMES_VALUE (keyframes, k, p));
|
||||
KEYFRAMES_VALUE (keyframes, k, p) = NULL;
|
||||
}
|
||||
|
||||
if (keyframes->variables && keyframes->variables[k])
|
||||
gtk_css_variable_set_unref (keyframes->variables[k]);
|
||||
}
|
||||
g_free (keyframes->values);
|
||||
g_free (keyframes->variables);
|
||||
g_free (keyframes->variable_ids);
|
||||
|
||||
g_free (keyframes);
|
||||
}
|
||||
@@ -120,6 +130,9 @@ gtk_css_keyframes_add_keyframe (GtkCssKeyframes *keyframes,
|
||||
memset (&KEYFRAMES_VALUE (keyframes, k, 0), 0, size);
|
||||
}
|
||||
|
||||
if (keyframes->variables)
|
||||
keyframes->variables = g_realloc (keyframes->variables, sizeof (GtkCssVariableSet *) * keyframes->n_keyframes);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
@@ -173,6 +186,26 @@ gtk_css_keyframes_lookup_property (GtkCssKeyframes *keyframes,
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_keyframes_register_variable (GtkCssKeyframes *keyframes,
|
||||
int variable_id)
|
||||
{
|
||||
guint p;
|
||||
|
||||
for (p = 0; p < keyframes->n_variables; p++)
|
||||
{
|
||||
if (keyframes->variable_ids[p] == variable_id)
|
||||
return;
|
||||
else if (keyframes->variable_ids[p] > variable_id)
|
||||
break;
|
||||
}
|
||||
|
||||
keyframes->n_variables++;
|
||||
keyframes->variable_ids = g_realloc (keyframes->variable_ids, sizeof (int) * keyframes->n_variables);
|
||||
memmove (keyframes->variable_ids + p + 1, keyframes->variable_ids + p, sizeof (int) * (keyframes->n_variables - p - 1));
|
||||
keyframes->variable_ids[p] = variable_id;
|
||||
}
|
||||
|
||||
static GtkCssKeyframes *
|
||||
gtk_css_keyframes_alloc (void)
|
||||
{
|
||||
@@ -235,6 +268,47 @@ gtk_css_keyframes_parse_declaration (GtkCssKeyframes *keyframes,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* This is a custom property */
|
||||
if (name[0] == '-' && name[1] == '-')
|
||||
{
|
||||
GtkCssVariableValue *var_value;
|
||||
GtkCssCustomPropertyPool *pool;
|
||||
int id;
|
||||
|
||||
if (!gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COLON))
|
||||
{
|
||||
gtk_css_parser_error_syntax (parser, "Expected a ':'");
|
||||
g_free (name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
var_value = gtk_css_parser_parse_value_into_token_stream (parser);
|
||||
if (var_value == NULL)
|
||||
{
|
||||
g_free (name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!keyframes->variables)
|
||||
keyframes->variables = g_new0 (GtkCssVariableSet *, keyframes->n_keyframes);
|
||||
|
||||
if (!keyframes->variables[k])
|
||||
keyframes->variables[k] = gtk_css_variable_set_new ();
|
||||
|
||||
pool = gtk_css_custom_property_pool_get ();
|
||||
id = gtk_css_custom_property_pool_add (pool, name);
|
||||
gtk_css_keyframes_register_variable (keyframes, id);
|
||||
|
||||
gtk_css_variable_value_taint (var_value);
|
||||
|
||||
gtk_css_variable_set_add (keyframes->variables[k], id, var_value);
|
||||
|
||||
gtk_css_custom_property_pool_unref (pool, id);
|
||||
|
||||
g_free (name);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
property = _gtk_style_property_lookup (name);
|
||||
if (property == NULL)
|
||||
{
|
||||
@@ -251,9 +325,53 @@ gtk_css_keyframes_parse_declaration (GtkCssKeyframes *keyframes,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
value = _gtk_style_property_parse_value (property, parser);
|
||||
if (value == NULL)
|
||||
return FALSE;
|
||||
if (gtk_css_parser_has_references (parser))
|
||||
{
|
||||
GtkCssVariableValue *var_value;
|
||||
|
||||
var_value = gtk_css_parser_parse_value_into_token_stream (parser);
|
||||
if (var_value == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (GTK_IS_CSS_SHORTHAND_PROPERTY (property))
|
||||
{
|
||||
GtkCssShorthandProperty *shorthand = GTK_CSS_SHORTHAND_PROPERTY (property);
|
||||
guint i, n;
|
||||
GtkCssValue **values;
|
||||
|
||||
n = _gtk_css_shorthand_property_get_n_subproperties (shorthand);
|
||||
|
||||
values = g_new (GtkCssValue *, n);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GtkCssValue *child =
|
||||
_gtk_css_reference_value_new (property,
|
||||
var_value,
|
||||
gtk_css_parser_get_file (parser));
|
||||
_gtk_css_reference_value_set_subproperty (child, i);
|
||||
|
||||
values[i] = _gtk_css_array_value_get_nth (child, i);
|
||||
}
|
||||
|
||||
value = _gtk_css_array_value_new_from_array (values, n);
|
||||
g_free (values);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = _gtk_css_reference_value_new (property,
|
||||
var_value,
|
||||
gtk_css_parser_get_file (parser));
|
||||
}
|
||||
|
||||
gtk_css_variable_value_unref (var_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = _gtk_style_property_parse_value (property, parser);
|
||||
if (value == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
|
||||
{
|
||||
@@ -314,6 +432,9 @@ gtk_css_keyframes_parse_block (GtkCssKeyframes *keyframes,
|
||||
gtk_css_parser_end_block (parser);
|
||||
}
|
||||
|
||||
if (keyframes->variables && keyframes->variables[k])
|
||||
gtk_css_variable_set_resolve_cycles (keyframes->variables[k]);
|
||||
|
||||
gtk_css_parser_end_block (parser);
|
||||
|
||||
return TRUE;
|
||||
@@ -378,12 +499,27 @@ compare_property_by_name (gconstpointer a,
|
||||
_gtk_css_style_property_lookup_by_id (keyframes->property_ids[*(const guint *) b]))));
|
||||
}
|
||||
|
||||
static int
|
||||
compare_custom_property_ids (gconstpointer a, gconstpointer b, gpointer user_data)
|
||||
{
|
||||
GtkCssCustomPropertyPool *pool = user_data;
|
||||
int id1 = GPOINTER_TO_INT (*((const int *) a));
|
||||
int id2 = GPOINTER_TO_INT (*((const int *) b));
|
||||
const char *name1, *name2;
|
||||
|
||||
name1 = gtk_css_custom_property_pool_get_name (pool, id1);
|
||||
name2 = gtk_css_custom_property_pool_get_name (pool, id2);
|
||||
|
||||
return strcmp (name1, name2);
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_css_keyframes_print (GtkCssKeyframes *keyframes,
|
||||
GString *string)
|
||||
{
|
||||
GtkCssCustomPropertyPool *pool = gtk_css_custom_property_pool_get ();
|
||||
guint k, p;
|
||||
guint *sorted;
|
||||
guint *sorted, *sorted_variable_ids = NULL;
|
||||
|
||||
g_return_if_fail (keyframes != NULL);
|
||||
g_return_if_fail (string != NULL);
|
||||
@@ -393,6 +529,18 @@ _gtk_css_keyframes_print (GtkCssKeyframes *keyframes,
|
||||
sorted[p] = p;
|
||||
g_qsort_with_data (sorted, keyframes->n_properties, sizeof (guint), compare_property_by_name, keyframes);
|
||||
|
||||
if (keyframes->variable_ids)
|
||||
{
|
||||
sorted_variable_ids = g_memdup2 (keyframes->variable_ids,
|
||||
sizeof (int) * keyframes->n_variables);
|
||||
|
||||
g_qsort_with_data (sorted_variable_ids,
|
||||
keyframes->n_variables,
|
||||
sizeof (int),
|
||||
compare_custom_property_ids,
|
||||
pool);
|
||||
}
|
||||
|
||||
for (k = 0; k < keyframes->n_keyframes; k++)
|
||||
{
|
||||
/* useful for 0% and 100% which might be empty */
|
||||
@@ -422,11 +570,43 @@ _gtk_css_keyframes_print (GtkCssKeyframes *keyframes,
|
||||
g_string_append (string, ";\n");
|
||||
}
|
||||
|
||||
if (keyframes->variables && keyframes->variables[k])
|
||||
{
|
||||
for (p = 0; p < keyframes->n_variables; p++)
|
||||
{
|
||||
int variable_id = sorted_variable_ids[p];
|
||||
GtkCssVariableValue *value =
|
||||
gtk_css_variable_set_lookup (keyframes->variables[k], variable_id, NULL);
|
||||
const char *name;
|
||||
|
||||
if (value == NULL)
|
||||
continue;
|
||||
|
||||
if (!opened)
|
||||
{
|
||||
if (keyframes->keyframe_progress[k] == 0.0)
|
||||
g_string_append (string, " from {\n");
|
||||
else if (keyframes->keyframe_progress[k] == 1.0)
|
||||
g_string_append (string, " to {\n");
|
||||
else
|
||||
g_string_append_printf (string, " %g%% {\n", keyframes->keyframe_progress[k] * 100);
|
||||
opened = TRUE;
|
||||
}
|
||||
|
||||
name = gtk_css_custom_property_pool_get_name (pool, variable_id);
|
||||
|
||||
g_string_append_printf (string, " %s: ", name);
|
||||
gtk_css_variable_value_print (value, string);
|
||||
g_string_append (string, ";\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (opened)
|
||||
g_string_append (string, " }\n");
|
||||
}
|
||||
|
||||
g_free (sorted);
|
||||
g_free (sorted_variable_ids);
|
||||
}
|
||||
|
||||
GtkCssKeyframes *
|
||||
@@ -462,10 +642,26 @@ _gtk_css_keyframes_compute (GtkCssKeyframes *keyframes,
|
||||
provider,
|
||||
style,
|
||||
parent_style,
|
||||
NULL);
|
||||
keyframes->variables ? keyframes->variables[k] : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (keyframes->variables)
|
||||
{
|
||||
resolved->variables = g_new0 (GtkCssVariableSet *, resolved->n_keyframes);
|
||||
|
||||
for (k = 0; k < resolved->n_keyframes; k++)
|
||||
{
|
||||
if (keyframes->variables[k])
|
||||
resolved->variables[k] = gtk_css_variable_set_ref (keyframes->variables[k]);
|
||||
}
|
||||
}
|
||||
else
|
||||
resolved->variables = NULL;
|
||||
|
||||
resolved->variable_ids = g_memdup2 (keyframes->variable_ids, keyframes->n_variables * sizeof (int));
|
||||
resolved->n_variables = keyframes->n_variables;
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
@@ -541,3 +737,83 @@ _gtk_css_keyframes_get_value (GtkCssKeyframes *keyframes,
|
||||
return result;
|
||||
}
|
||||
|
||||
guint
|
||||
_gtk_css_keyframes_get_n_variables (GtkCssKeyframes *keyframes)
|
||||
{
|
||||
g_return_val_if_fail (keyframes != NULL, 0);
|
||||
|
||||
return keyframes->n_variables;
|
||||
}
|
||||
|
||||
int
|
||||
_gtk_css_keyframes_get_variable_id (GtkCssKeyframes *keyframes,
|
||||
guint id)
|
||||
{
|
||||
g_return_val_if_fail (keyframes != NULL, 0);
|
||||
g_return_val_if_fail (id < keyframes->n_variables, 0);
|
||||
|
||||
return keyframes->variable_ids[id];
|
||||
}
|
||||
|
||||
GtkCssVariableValue *
|
||||
_gtk_css_keyframes_get_variable (GtkCssKeyframes *keyframes,
|
||||
guint id,
|
||||
double progress,
|
||||
GtkCssVariableValue *default_value)
|
||||
{
|
||||
GtkCssVariableValue *start_value, *end_value, *result;
|
||||
double start_progress, end_progress;
|
||||
int variable_id;
|
||||
guint k;
|
||||
|
||||
g_return_val_if_fail (keyframes != NULL, 0);
|
||||
g_return_val_if_fail (id < keyframes->n_variables, 0);
|
||||
|
||||
start_value = default_value;
|
||||
start_progress = 0.0;
|
||||
end_value = default_value;
|
||||
end_progress = 1.0;
|
||||
|
||||
variable_id = keyframes->variable_ids[id];
|
||||
|
||||
for (k = 0; k < keyframes->n_keyframes; k++)
|
||||
{
|
||||
GtkCssVariableValue *value;
|
||||
|
||||
if (keyframes->variables[k] == NULL)
|
||||
continue;
|
||||
|
||||
value = gtk_css_variable_set_lookup (keyframes->variables[k], variable_id, NULL);
|
||||
|
||||
if (value == NULL)
|
||||
continue;
|
||||
|
||||
if (keyframes->keyframe_progress[k] == progress)
|
||||
{
|
||||
return gtk_css_variable_value_ref (value);
|
||||
}
|
||||
else if (keyframes->keyframe_progress[k] < progress)
|
||||
{
|
||||
start_value = value;
|
||||
start_progress = keyframes->keyframe_progress[k];
|
||||
}
|
||||
else
|
||||
{
|
||||
end_value = value;
|
||||
end_progress = keyframes->keyframe_progress[k];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
progress = (progress - start_progress) / (end_progress - start_progress);
|
||||
|
||||
result = gtk_css_variable_value_transition (start_value,
|
||||
end_value,
|
||||
progress);
|
||||
|
||||
/* XXX: Dear spec, what's the correct thing to do here? */
|
||||
if (result == NULL)
|
||||
return start_value ? gtk_css_variable_value_ref (start_value) : NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -50,5 +50,13 @@ GtkCssValue * _gtk_css_keyframes_get_value (GtkCssKeyframes
|
||||
double progress,
|
||||
GtkCssValue *default_value);
|
||||
|
||||
guint _gtk_css_keyframes_get_n_variables (GtkCssKeyframes *keyframes);
|
||||
int _gtk_css_keyframes_get_variable_id (GtkCssKeyframes *keyframes,
|
||||
guint id);
|
||||
GtkCssVariableValue *_gtk_css_keyframes_get_variable (GtkCssKeyframes *keyframes,
|
||||
guint id,
|
||||
double progress,
|
||||
GtkCssVariableValue *default_value);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
|
||||
#define MAX_TOKEN_LENGTH 65536
|
||||
|
||||
typedef enum {
|
||||
RESOLVE_SUCCESS,
|
||||
RESOLVE_INVALID,
|
||||
RESOLVE_ANIMATION_TAINTED,
|
||||
} ResolveResult;
|
||||
|
||||
struct _GtkCssValue {
|
||||
GTK_CSS_VALUE_BASE
|
||||
|
||||
@@ -48,8 +54,9 @@ gtk_css_value_reference_free (GtkCssValue *value)
|
||||
g_object_unref (value->file);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static ResolveResult
|
||||
resolve_references_do (GtkCssVariableValue *value,
|
||||
guint property_id,
|
||||
GtkCssVariableSet *style_variables,
|
||||
GtkCssVariableSet *keyframes_variables,
|
||||
gboolean root,
|
||||
@@ -61,9 +68,30 @@ resolve_references_do (GtkCssVariableValue *value,
|
||||
gsize i;
|
||||
gsize length = value->length;
|
||||
gsize n_refs = 0;
|
||||
ResolveResult ret = RESOLVE_SUCCESS;
|
||||
|
||||
if (value->is_animation_tainted)
|
||||
{
|
||||
GtkCssStyleProperty *prop = _gtk_css_style_property_lookup_by_id (property_id);
|
||||
|
||||
if (!_gtk_css_style_property_is_animated (prop))
|
||||
{
|
||||
/* Animation-tainted variables make other variables that reference
|
||||
* them animation-tainted too, so unlike regular invalid variables it
|
||||
* propagates to the root. For example, if --test is animation-tainted,
|
||||
* --test2: var(--test, fallback1); prop: var(--test2, fallback2); will\
|
||||
* resolve to fallback2 and _not_ to fallback1. So we'll propagate it
|
||||
* up until the root, and treat it same as invalid there instead. */
|
||||
ret = RESOLVE_ANIMATION_TAINTED;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (value->is_invalid)
|
||||
goto error;
|
||||
{
|
||||
ret = RESOLVE_INVALID;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!root)
|
||||
{
|
||||
@@ -78,6 +106,7 @@ resolve_references_do (GtkCssVariableValue *value,
|
||||
GtkCssVariableValue *var_value = NULL;
|
||||
gsize var_length, var_refs;
|
||||
GtkCssVariableSet *source = style_variables;
|
||||
ResolveResult result = RESOLVE_INVALID;
|
||||
|
||||
if (keyframes_variables)
|
||||
var_value = gtk_css_variable_set_lookup (keyframes_variables, id, NULL);
|
||||
@@ -85,21 +114,48 @@ resolve_references_do (GtkCssVariableValue *value,
|
||||
if (!var_value && style_variables)
|
||||
var_value = gtk_css_variable_set_lookup (style_variables, id, &source);
|
||||
|
||||
if (!var_value || !resolve_references_do (var_value, source, keyframes_variables,
|
||||
FALSE, refs, &var_length, &var_refs))
|
||||
if (var_value)
|
||||
{
|
||||
var_value = ref->fallback;
|
||||
result = resolve_references_do (var_value, property_id, source,
|
||||
keyframes_variables, FALSE,
|
||||
refs, &var_length, &var_refs);
|
||||
|
||||
if (!var_value || !resolve_references_do (var_value, style_variables, keyframes_variables,
|
||||
FALSE, refs, &var_length, &var_refs))
|
||||
goto error;
|
||||
if (root && result == RESOLVE_ANIMATION_TAINTED)
|
||||
result = RESOLVE_INVALID;
|
||||
}
|
||||
|
||||
if (result == RESOLVE_INVALID)
|
||||
{
|
||||
if (ref->fallback)
|
||||
{
|
||||
result = resolve_references_do (ref->fallback, property_id,
|
||||
style_variables, keyframes_variables,
|
||||
FALSE, refs, &var_length, &var_refs);
|
||||
|
||||
if (root && result == RESOLVE_ANIMATION_TAINTED)
|
||||
result = RESOLVE_INVALID;
|
||||
}
|
||||
|
||||
if (result != RESOLVE_SUCCESS)
|
||||
{
|
||||
ret = result;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (result == RESOLVE_ANIMATION_TAINTED)
|
||||
{
|
||||
ret = RESOLVE_ANIMATION_TAINTED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
length += var_length - ref->length;
|
||||
n_refs += var_refs;
|
||||
|
||||
if (length > MAX_TOKEN_LENGTH)
|
||||
goto error;
|
||||
{
|
||||
ret = RESOLVE_INVALID;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (out_length)
|
||||
@@ -108,7 +164,7 @@ resolve_references_do (GtkCssVariableValue *value,
|
||||
if (out_n_refs)
|
||||
*out_n_refs = n_refs;
|
||||
|
||||
return TRUE;
|
||||
return ret;
|
||||
|
||||
error:
|
||||
/* Remove the references we added as if nothing happened */
|
||||
@@ -120,11 +176,12 @@ error:
|
||||
if (out_n_refs)
|
||||
*out_n_refs = 0;
|
||||
|
||||
return FALSE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GtkCssVariableValue **
|
||||
resolve_references (GtkCssVariableValue *input,
|
||||
guint property_id,
|
||||
GtkCssStyle *style,
|
||||
GtkCssVariableSet *keyframes_variables,
|
||||
gsize *n_refs)
|
||||
@@ -132,8 +189,12 @@ resolve_references (GtkCssVariableValue *input,
|
||||
GPtrArray *refs = g_ptr_array_new ();
|
||||
GtkCssVariableValue **out_refs;
|
||||
|
||||
if (!resolve_references_do (input, style->variables, keyframes_variables, TRUE, refs, NULL, NULL))
|
||||
return NULL;
|
||||
if (resolve_references_do (input, property_id, style->variables,
|
||||
keyframes_variables, TRUE, refs,
|
||||
NULL, NULL) != RESOLVE_SUCCESS)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out_refs = (GtkCssVariableValue **) g_ptr_array_steal (refs, n_refs);
|
||||
|
||||
@@ -173,7 +234,7 @@ gtk_css_value_reference_compute (GtkCssValue *value,
|
||||
GtkCssVariableValue **refs;
|
||||
gsize n_refs = 0;
|
||||
|
||||
refs = resolve_references (value->value, style, variables, &n_refs);
|
||||
refs = resolve_references (value->value, property_id, style, variables, &n_refs);
|
||||
|
||||
if (refs != NULL)
|
||||
{
|
||||
|
||||
@@ -199,6 +199,12 @@ gtk_css_static_style_dispose (GObject *object)
|
||||
style->sections = NULL;
|
||||
}
|
||||
|
||||
if (style->original_values)
|
||||
{
|
||||
g_ptr_array_unref (style->original_values);
|
||||
style->original_values = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gtk_css_static_style_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
@@ -208,6 +214,19 @@ gtk_css_static_style_get_static_style (GtkCssStyle *style)
|
||||
return (GtkCssStaticStyle *)style;
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
gtk_css_static_style_get_original_value (GtkCssStyle *style,
|
||||
guint id)
|
||||
{
|
||||
GtkCssStaticStyle *sstyle = GTK_CSS_STATIC_STYLE (style);
|
||||
|
||||
if (sstyle->original_values == NULL ||
|
||||
id >= sstyle->original_values->len)
|
||||
return NULL;
|
||||
|
||||
return g_ptr_array_index (sstyle->original_values, id);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_static_style_class_init (GtkCssStaticStyleClass *klass)
|
||||
{
|
||||
@@ -218,6 +237,7 @@ gtk_css_static_style_class_init (GtkCssStaticStyleClass *klass)
|
||||
|
||||
style_class->get_section = gtk_css_static_style_get_section;
|
||||
style_class->get_static_style = gtk_css_static_style_get_static_style;
|
||||
style_class->get_original_value = gtk_css_static_style_get_original_value;
|
||||
|
||||
gtk_css_core_values_init ();
|
||||
gtk_css_background_values_init ();
|
||||
@@ -246,6 +266,13 @@ maybe_unref_section (gpointer section)
|
||||
gtk_css_section_unref (section);
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_unref_value (gpointer value)
|
||||
{
|
||||
if (value)
|
||||
_gtk_css_value_unref (value);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_css_take_value (GtkCssValue **variable,
|
||||
GtkCssValue *value)
|
||||
@@ -259,6 +286,7 @@ static void
|
||||
gtk_css_static_style_set_value (GtkCssStaticStyle *sstyle,
|
||||
guint id,
|
||||
GtkCssValue *value,
|
||||
GtkCssValue *original_value,
|
||||
GtkCssSection *section)
|
||||
{
|
||||
GtkCssStyle *style = (GtkCssStyle *)sstyle;
|
||||
@@ -561,6 +589,22 @@ gtk_css_static_style_set_value (GtkCssStaticStyle *sstyle,
|
||||
g_ptr_array_set_size (sstyle->sections, id + 1);
|
||||
g_ptr_array_index (sstyle->sections, id) = gtk_css_section_ref (section);
|
||||
}
|
||||
|
||||
if (sstyle->original_values && sstyle->original_values->len > id &&
|
||||
g_ptr_array_index (sstyle->original_values, id))
|
||||
{
|
||||
_gtk_css_value_unref (g_ptr_array_index (sstyle->original_values, id));
|
||||
g_ptr_array_index (sstyle->original_values, id) = NULL;
|
||||
}
|
||||
|
||||
if (original_value)
|
||||
{
|
||||
if (sstyle->original_values == NULL)
|
||||
sstyle->original_values = g_ptr_array_new_with_free_func (maybe_unref_value);
|
||||
if (sstyle->original_values->len <= id)
|
||||
g_ptr_array_set_size (sstyle->original_values, id + 1);
|
||||
g_ptr_array_index (sstyle->original_values, id) = _gtk_css_value_ref (original_value);
|
||||
}
|
||||
}
|
||||
|
||||
static GtkCssStyle *default_style;
|
||||
@@ -950,7 +994,7 @@ gtk_css_static_style_compute_value (GtkCssStaticStyle *style,
|
||||
GtkCssValue *specified,
|
||||
GtkCssSection *section)
|
||||
{
|
||||
GtkCssValue *value;
|
||||
GtkCssValue *value, *original_value;
|
||||
GtkBorderStyle border_style;
|
||||
|
||||
gtk_internal_return_if_fail (id < GTK_CSS_PROPERTY_N_PROPERTIES);
|
||||
@@ -971,7 +1015,7 @@ gtk_css_static_style_compute_value (GtkCssStaticStyle *style,
|
||||
border_style = _gtk_css_border_style_value_get (gtk_css_style_get_value ((GtkCssStyle *)style, id - 1));
|
||||
if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
|
||||
{
|
||||
gtk_css_static_style_set_value (style, id, gtk_css_dimension_value_new (0, GTK_CSS_NUMBER), section);
|
||||
gtk_css_static_style_set_value (style, id, gtk_css_dimension_value_new (0, GTK_CSS_NUMBER), NULL, section);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -989,18 +1033,33 @@ gtk_css_static_style_compute_value (GtkCssStaticStyle *style,
|
||||
if (specified)
|
||||
{
|
||||
value = _gtk_css_value_compute (specified, id, provider, (GtkCssStyle *)style, parent_style, NULL);
|
||||
|
||||
if (gtk_css_value_contains_variables (specified))
|
||||
original_value = specified;
|
||||
else
|
||||
original_value = NULL;
|
||||
}
|
||||
else if (parent_style && _gtk_css_style_property_is_inherit (_gtk_css_style_property_lookup_by_id (id)))
|
||||
{
|
||||
GtkCssValue *parent_original_value;
|
||||
|
||||
/* Just take the style from the parent */
|
||||
value = _gtk_css_value_ref (gtk_css_style_get_value (parent_style, id));
|
||||
|
||||
parent_original_value = gtk_css_style_get_original_value (parent_style, id);
|
||||
|
||||
if (parent_original_value)
|
||||
original_value = parent_original_value;
|
||||
else
|
||||
original_value = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = _gtk_css_initial_value_new_compute (id, provider, (GtkCssStyle *)style, parent_style);
|
||||
original_value = NULL;
|
||||
}
|
||||
|
||||
gtk_css_static_style_set_value (style, id, value, section);
|
||||
gtk_css_static_style_set_value (style, id, value, original_value, section);
|
||||
}
|
||||
|
||||
GtkCssChange
|
||||
|
||||
@@ -40,6 +40,7 @@ struct _GtkCssStaticStyle
|
||||
GtkCssStyle parent;
|
||||
|
||||
GPtrArray *sections; /* sections the values are defined in */
|
||||
GPtrArray *original_values;
|
||||
|
||||
GtkCssChange change; /* change as returned by value lookup */
|
||||
};
|
||||
|
||||
@@ -316,6 +316,15 @@ gtk_css_style_get_static_style (GtkCssStyle *style)
|
||||
return GTK_CSS_STYLE_GET_CLASS (style)->get_static_style (style);
|
||||
}
|
||||
|
||||
GtkCssValue *
|
||||
gtk_css_style_get_original_value (GtkCssStyle *style,
|
||||
guint id)
|
||||
{
|
||||
gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (style), NULL);
|
||||
|
||||
return GTK_CSS_STYLE_GET_CLASS (style)->get_original_value (style, id);
|
||||
}
|
||||
|
||||
/*
|
||||
* gtk_css_style_print:
|
||||
* @style: a `GtkCssStyle`
|
||||
|
||||
@@ -252,6 +252,9 @@ struct _GtkCssStyleClass
|
||||
gboolean (* is_static) (GtkCssStyle *style);
|
||||
|
||||
GtkCssStaticStyle * (* get_static_style) (GtkCssStyle *style);
|
||||
|
||||
GtkCssValue * (* get_original_value) (GtkCssStyle *style,
|
||||
guint id);
|
||||
};
|
||||
|
||||
GType gtk_css_style_get_type (void) G_GNUC_CONST;
|
||||
@@ -263,6 +266,9 @@ GtkCssSection * gtk_css_style_get_section (GtkCssStyle
|
||||
gboolean gtk_css_style_is_static (GtkCssStyle *style) G_GNUC_PURE;
|
||||
GtkCssStaticStyle * gtk_css_style_get_static_style (GtkCssStyle *style);
|
||||
|
||||
GtkCssValue * gtk_css_style_get_original_value (GtkCssStyle *style,
|
||||
guint id) G_GNUC_PURE;
|
||||
|
||||
char * gtk_css_style_to_string (GtkCssStyle *style);
|
||||
gboolean gtk_css_style_print (GtkCssStyle *style,
|
||||
GString *string,
|
||||
|
||||
Reference in New Issue
Block a user