[gtk+] cssstyle: Split into GtkCssStyle and GtkCssAnimatedStyle



commit 4168e0385efd9231731ed35b96ce58bafc3eb03f
Author: Benjamin Otte <otte redhat com>
Date:   Thu Oct 23 04:10:03 2014 +0200

    cssstyle: Split into GtkCssStyle and GtkCssAnimatedStyle
    
    GtkCssStyle is the base class to be used for all types of styles that do
    exist.
    
    GtkCssAnimatedStyle is the only implementation so far, that is exactly a
    copy/paste of the old GtkCssStyle code.

 gtk/Makefile.am                  |    2 +
 gtk/gtkcssanimatedstyle.c        |  599 ++++++++++++++++++++++++++++++++++++++
 gtk/gtkcssanimatedstyleprivate.h |   90 ++++++
 gtk/gtkcssanimation.c            |    6 +-
 gtk/gtkcsslookup.c               |   22 +-
 gtk/gtkcsslookupprivate.h        |    6 +-
 gtk/gtkcssstyle.c                |  538 +---------------------------------
 gtk/gtkcssstyleprivate.h         |   53 +---
 gtk/gtkcsstransition.c           |   10 +-
 gtk/gtkstyleanimation.c          |    8 +-
 gtk/gtkstyleanimationprivate.h   |    7 +-
 gtk/gtkstylecontext.c            |   28 +-
 12 files changed, 767 insertions(+), 602 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index d2ffbd8..0573e3e 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -368,6 +368,7 @@ gtk_private_h_sources =             \
        gtkcomboboxprivate.h    \
        gtkcontainerprivate.h   \
        gtkcssanimationprivate.h        \
+       gtkcssanimatedstyleprivate.h    \
        gtkcssarrayvalueprivate.h       \
        gtkcssbgsizevalueprivate.h      \
        gtkcssbordervalueprivate.h      \
@@ -592,6 +593,7 @@ gtk_base_c_sources =                \
        gtkcomboboxtext.c       \
        gtkcontainer.c          \
        gtkcssanimation.c       \
+       gtkcssanimatedstyle.c   \
        gtkcssarrayvalue.c      \
        gtkcssbgsizevalue.c     \
        gtkcssbordervalue.c     \
diff --git a/gtk/gtkcssanimatedstyle.c b/gtk/gtkcssanimatedstyle.c
new file mode 100644
index 0000000..4ced8d1
--- /dev/null
+++ b/gtk/gtkcssanimatedstyle.c
@@ -0,0 +1,599 @@
+/*
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkcssanimatedstyleprivate.h"
+
+#include "gtkcssanimationprivate.h"
+#include "gtkcssarrayvalueprivate.h"
+#include "gtkcssenumvalueprivate.h"
+#include "gtkcssinheritvalueprivate.h"
+#include "gtkcssinitialvalueprivate.h"
+#include "gtkcssnumbervalueprivate.h"
+#include "gtkcsssectionprivate.h"
+#include "gtkcssshorthandpropertyprivate.h"
+#include "gtkcssstringvalueprivate.h"
+#include "gtkcssstylepropertyprivate.h"
+#include "gtkcsstransitionprivate.h"
+#include "gtkprivate.h"
+#include "gtkstyleanimationprivate.h"
+#include "gtkstylepropertyprivate.h"
+#include "gtkstyleproviderprivate.h"
+
+G_DEFINE_TYPE (GtkCssAnimatedStyle, gtk_css_animated_style, GTK_TYPE_CSS_STYLE)
+
+static GtkCssValue *
+gtk_css_animated_style_get_value (GtkCssStyle *style,
+                                  guint        id)
+{
+  GtkCssAnimatedStyle *animated = GTK_CSS_ANIMATED_STYLE (style);
+
+  if (animated->animated_values &&
+      id < animated->animated_values->len &&
+      g_ptr_array_index (animated->animated_values, id))
+    return g_ptr_array_index (animated->animated_values, id);
+
+  return gtk_css_animated_style_get_intrinsic_value (animated, id);
+}
+
+static GtkCssSection *
+gtk_css_animated_style_get_section (GtkCssStyle *style,
+                                    guint        id)
+{
+  GtkCssAnimatedStyle *animated = GTK_CSS_ANIMATED_STYLE (style);
+
+  if (animated->sections == NULL ||
+      id >= animated->sections->len)
+    return NULL;
+
+  return g_ptr_array_index (animated->sections, id);
+}
+
+static GtkBitmask *
+gtk_css_animated_style_compute_dependencies (GtkCssStyle      *style,
+                                             const GtkBitmask *parent_changes)
+{
+  GtkCssAnimatedStyle *animated = GTK_CSS_ANIMATED_STYLE (style);
+  GtkBitmask *changes;
+
+  changes = _gtk_bitmask_copy (parent_changes);
+  changes = _gtk_bitmask_intersect (changes, animated->depends_on_parent);
+  if (_gtk_bitmask_get (changes, GTK_CSS_PROPERTY_COLOR))
+    changes = _gtk_bitmask_union (changes, animated->depends_on_color);
+  if (_gtk_bitmask_get (changes, GTK_CSS_PROPERTY_FONT_SIZE))
+    changes = _gtk_bitmask_union (changes, animated->depends_on_font_size);
+
+  return changes;
+}
+
+static void
+gtk_css_animated_style_dispose (GObject *object)
+{
+  GtkCssAnimatedStyle *style = GTK_CSS_ANIMATED_STYLE (object);
+
+  if (style->values)
+    {
+      g_ptr_array_unref (style->values);
+      style->values = NULL;
+    }
+  if (style->sections)
+    {
+      g_ptr_array_unref (style->sections);
+      style->sections = NULL;
+    }
+  if (style->animated_values)
+    {
+      g_ptr_array_unref (style->animated_values);
+      style->animated_values = NULL;
+    }
+
+  g_slist_free_full (style->animations, g_object_unref);
+  style->animations = NULL;
+
+  G_OBJECT_CLASS (gtk_css_animated_style_parent_class)->dispose (object);
+}
+
+static void
+gtk_css_animated_style_finalize (GObject *object)
+{
+  GtkCssAnimatedStyle *style = GTK_CSS_ANIMATED_STYLE (object);
+
+  _gtk_bitmask_free (style->depends_on_parent);
+  _gtk_bitmask_free (style->equals_parent);
+  _gtk_bitmask_free (style->depends_on_color);
+  _gtk_bitmask_free (style->depends_on_font_size);
+
+  G_OBJECT_CLASS (gtk_css_animated_style_parent_class)->finalize (object);
+}
+
+static void
+gtk_css_animated_style_class_init (GtkCssAnimatedStyleClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkCssStyleClass *style_class = GTK_CSS_STYLE_CLASS (klass);
+
+  object_class->dispose = gtk_css_animated_style_dispose;
+  object_class->finalize = gtk_css_animated_style_finalize;
+
+  style_class->get_value = gtk_css_animated_style_get_value;
+  style_class->get_section = gtk_css_animated_style_get_section;
+  style_class->compute_dependencies = gtk_css_animated_style_compute_dependencies;
+}
+
+static void
+gtk_css_animated_style_init (GtkCssAnimatedStyle *style)
+{
+  style->depends_on_parent = _gtk_bitmask_new ();
+  style->equals_parent = _gtk_bitmask_new ();
+  style->depends_on_color = _gtk_bitmask_new ();
+  style->depends_on_font_size = _gtk_bitmask_new ();
+}
+
+GtkCssStyle *
+gtk_css_animated_style_new (void)
+{
+  return g_object_new (GTK_TYPE_CSS_ANIMATED_STYLE, NULL);
+}
+
+static void
+maybe_unref_section (gpointer section)
+{
+  if (section)
+    gtk_css_section_unref (section);
+}
+
+void
+gtk_css_animated_style_compute_value (GtkCssAnimatedStyle     *style,
+                                      GtkStyleProviderPrivate *provider,
+                                      int                      scale,
+                                      GtkCssStyle             *parent_style,
+                                      guint                    id,
+                                      GtkCssValue             *specified,
+                                      GtkCssSection           *section)
+{
+  GtkCssDependencies dependencies;
+  GtkCssValue *value;
+
+  gtk_internal_return_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style));
+  gtk_internal_return_if_fail (GTK_IS_STYLE_PROVIDER_PRIVATE (provider));
+  gtk_internal_return_if_fail (parent_style == NULL || GTK_IS_CSS_STYLE (parent_style));
+
+  /* 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)
+    {
+      GtkCssStyleProperty *prop = _gtk_css_style_property_lookup_by_id (id);
+
+      if (_gtk_css_style_property_is_inherit (prop))
+        specified = _gtk_css_inherit_value_new ();
+      else
+        specified = _gtk_css_initial_value_new ();
+    }
+  else
+    _gtk_css_value_ref (specified);
+
+  value = _gtk_css_value_compute (specified, id, provider, scale, GTK_CSS_STYLE (style), parent_style, 
&dependencies);
+
+  if (style->values == NULL)
+    style->values = g_ptr_array_new_full (_gtk_css_style_property_get_n_properties (),
+                                          (GDestroyNotify)_gtk_css_value_unref);
+  if (id >= style->values->len)
+   g_ptr_array_set_size (style->values, id + 1);
+
+  if (g_ptr_array_index (style->values, id))
+    _gtk_css_value_unref (g_ptr_array_index (style->values, id));
+  g_ptr_array_index (style->values, id) = _gtk_css_value_ref (value);
+
+  if (dependencies & (GTK_CSS_DEPENDS_ON_PARENT | GTK_CSS_EQUALS_PARENT))
+    style->depends_on_parent = _gtk_bitmask_set (style->depends_on_parent, id, TRUE);
+  if (dependencies & (GTK_CSS_EQUALS_PARENT))
+    style->equals_parent = _gtk_bitmask_set (style->equals_parent, id, TRUE);
+  if (dependencies & (GTK_CSS_DEPENDS_ON_COLOR))
+    style->depends_on_color = _gtk_bitmask_set (style->depends_on_color, id, TRUE);
+  if (dependencies & (GTK_CSS_DEPENDS_ON_FONT_SIZE))
+    style->depends_on_font_size = _gtk_bitmask_set (style->depends_on_font_size, id, TRUE);
+
+  if (style->sections && style->sections->len > id && g_ptr_array_index (style->sections, id))
+    {
+      gtk_css_section_unref (g_ptr_array_index (style->sections, id));
+      g_ptr_array_index (style->sections, id) = NULL;
+    }
+
+  if (section)
+    {
+      if (style->sections == NULL)
+        style->sections = g_ptr_array_new_with_free_func (maybe_unref_section);
+      if (style->sections->len <= id)
+        g_ptr_array_set_size (style->sections, id + 1);
+
+      g_ptr_array_index (style->sections, id) = gtk_css_section_ref (section);
+    }
+
+  _gtk_css_value_unref (value);
+  _gtk_css_value_unref (specified);
+}
+
+void
+gtk_css_animated_style_set_animated_value (GtkCssAnimatedStyle *style,
+                                           guint                id,
+                                           GtkCssValue         *value)
+{
+  gtk_internal_return_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style));
+  gtk_internal_return_if_fail (value != NULL);
+
+  if (style->animated_values == NULL)
+    style->animated_values = g_ptr_array_new_with_free_func ((GDestroyNotify)_gtk_css_value_unref);
+  if (id >= style->animated_values->len)
+   g_ptr_array_set_size (style->animated_values, id + 1);
+
+  if (g_ptr_array_index (style->animated_values, id))
+    _gtk_css_value_unref (g_ptr_array_index (style->animated_values, id));
+  g_ptr_array_index (style->animated_values, id) = _gtk_css_value_ref (value);
+
+}
+
+GtkCssValue *
+gtk_css_animated_style_get_intrinsic_value (GtkCssAnimatedStyle *style,
+                                            guint                id)
+{
+  gtk_internal_return_val_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style), NULL);
+
+  if (style->values == NULL ||
+      id >= style->values->len)
+    return NULL;
+
+  return g_ptr_array_index (style->values, id);
+}
+
+/* TRANSITIONS */
+
+typedef struct _TransitionInfo TransitionInfo;
+struct _TransitionInfo {
+  guint index;                  /* index into value arrays */
+  gboolean pending;             /* TRUE if we still need to handle it */
+};
+
+static void
+transition_info_add (TransitionInfo    infos[GTK_CSS_PROPERTY_N_PROPERTIES],
+                     GtkStyleProperty *property,
+                     guint             index)
+{
+  if (property == NULL)
+    {
+      guint i;
+
+      for (i = 0; i < _gtk_css_style_property_get_n_properties (); i++)
+        {
+          GtkCssStyleProperty *prop = _gtk_css_style_property_lookup_by_id (i);
+
+          transition_info_add (infos, GTK_STYLE_PROPERTY (prop), index);
+        }
+    }
+  else if (GTK_IS_CSS_SHORTHAND_PROPERTY (property))
+    {
+      GtkCssShorthandProperty *shorthand = GTK_CSS_SHORTHAND_PROPERTY (property);
+      guint i;
+
+      for (i = 0; i < _gtk_css_shorthand_property_get_n_subproperties (shorthand); i++)
+        {
+          GtkCssStyleProperty *prop = _gtk_css_shorthand_property_get_subproperty (shorthand, i);
+
+          transition_info_add (infos, GTK_STYLE_PROPERTY (prop), index);
+        }
+    }
+  else if (GTK_IS_CSS_STYLE_PROPERTY (property))
+    {
+      guint id;
+      
+      if (!_gtk_css_style_property_is_animated (GTK_CSS_STYLE_PROPERTY (property)))
+        return;
+
+      id = _gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (property));
+      g_assert (id < GTK_CSS_PROPERTY_N_PROPERTIES);
+      infos[id].index = index;
+      infos[id].pending = TRUE;
+    }
+  else
+    {
+      g_assert_not_reached ();
+    }
+}
+
+static void
+transition_infos_set (TransitionInfo  infos[GTK_CSS_PROPERTY_N_PROPERTIES],
+                      GtkCssValue    *transitions)
+{
+  guint i;
+
+  for (i = 0; i < _gtk_css_array_value_get_n_values (transitions); i++)
+    {
+      GtkStyleProperty *property;
+      GtkCssValue *prop_value;
+
+      prop_value = _gtk_css_array_value_get_nth (transitions, i);
+      if (g_ascii_strcasecmp (_gtk_css_ident_value_get (prop_value), "all") == 0)
+        property = NULL;
+      else
+        {
+          property = _gtk_style_property_lookup (_gtk_css_ident_value_get (prop_value));
+          if (property == NULL)
+            continue;
+        }
+      
+      transition_info_add (infos, property, i);
+    }
+}
+
+static GtkStyleAnimation *
+gtk_css_animated_style_find_transition (GtkCssAnimatedStyle *style,
+                                        guint                property_id)
+{
+  GSList *list;
+
+  for (list = style->animations; list; list = list->next)
+    {
+      if (!GTK_IS_CSS_TRANSITION (list->data))
+        continue;
+
+      if (_gtk_css_transition_get_property (list->data) == property_id)
+        return list->data;
+    }
+
+  return NULL;
+}
+
+static void
+gtk_css_animated_style_create_css_transitions (GtkCssAnimatedStyle *style,
+                                               gint64               timestamp,
+                                               GtkCssAnimatedStyle *source)
+{
+  TransitionInfo transitions[GTK_CSS_PROPERTY_N_PROPERTIES] = { { 0, } };
+  GtkCssValue *durations, *delays, *timing_functions;
+  guint i;
+
+  transition_infos_set (transitions, gtk_css_style_get_value (GTK_CSS_STYLE (style), 
GTK_CSS_PROPERTY_TRANSITION_PROPERTY));
+
+  durations = gtk_css_style_get_value (GTK_CSS_STYLE (style), GTK_CSS_PROPERTY_TRANSITION_DURATION);
+  delays = gtk_css_style_get_value (GTK_CSS_STYLE (style), GTK_CSS_PROPERTY_TRANSITION_DELAY);
+  timing_functions = gtk_css_style_get_value (GTK_CSS_STYLE (style), 
GTK_CSS_PROPERTY_TRANSITION_TIMING_FUNCTION);
+
+  for (i = 0; i < GTK_CSS_PROPERTY_N_PROPERTIES; i++)
+    {
+      GtkStyleAnimation *animation;
+      GtkCssValue *start, *end;
+      double duration, delay;
+
+      if (!transitions[i].pending)
+        continue;
+
+      duration = _gtk_css_number_value_get (_gtk_css_array_value_get_nth (durations, transitions[i].index), 
100);
+      delay = _gtk_css_number_value_get (_gtk_css_array_value_get_nth (delays, transitions[i].index), 100);
+      if (duration + delay == 0.0)
+        continue;
+
+      start = gtk_css_animated_style_get_intrinsic_value (source, i);
+      end = gtk_css_animated_style_get_intrinsic_value (style, i);
+      if (_gtk_css_value_equal (start, end))
+        {
+          animation = gtk_css_animated_style_find_transition (GTK_CSS_ANIMATED_STYLE (source), i);
+          if (animation)
+            style->animations = g_slist_prepend (style->animations, g_object_ref (animation));
+        }
+      else
+        {
+          animation = _gtk_css_transition_new (i,
+                                               gtk_css_style_get_value (GTK_CSS_STYLE (source), i),
+                                               _gtk_css_array_value_get_nth (timing_functions, i),
+                                               timestamp + delay * G_USEC_PER_SEC,
+                                               timestamp + (delay + duration) * G_USEC_PER_SEC);
+          style->animations = g_slist_prepend (style->animations, animation);
+        }
+    }
+}
+
+static GtkStyleAnimation *
+gtk_css_animated_style_find_animation (GtkCssAnimatedStyle *style,
+                                       const char          *name)
+{
+  GSList *list;
+
+  for (list = style->animations; list; list = list->next)
+    {
+      if (!GTK_IS_CSS_ANIMATION (list->data))
+        continue;
+
+      if (g_str_equal (_gtk_css_animation_get_name (list->data), name))
+        return list->data;
+    }
+
+  return NULL;
+}
+
+static void
+gtk_css_animated_style_create_css_animations (GtkCssAnimatedStyle     *style,
+                                              GtkCssAnimatedStyle     *parent_style,
+                                              gint64                   timestamp,
+                                              GtkStyleProviderPrivate *provider,
+                                              int                      scale,
+                                              GtkCssAnimatedStyle     *source)
+{
+  GtkCssValue *durations, *delays, *timing_functions, *animations;
+  GtkCssValue *iteration_counts, *directions, *play_states, *fill_modes;
+  guint i;
+
+  animations = gtk_css_style_get_value (GTK_CSS_STYLE (style), GTK_CSS_PROPERTY_ANIMATION_NAME);
+  durations = gtk_css_style_get_value (GTK_CSS_STYLE (style), GTK_CSS_PROPERTY_ANIMATION_DURATION);
+  delays = gtk_css_style_get_value (GTK_CSS_STYLE (style), GTK_CSS_PROPERTY_ANIMATION_DELAY);
+  timing_functions = gtk_css_style_get_value (GTK_CSS_STYLE (style), 
GTK_CSS_PROPERTY_ANIMATION_TIMING_FUNCTION);
+  iteration_counts = gtk_css_style_get_value (GTK_CSS_STYLE (style), 
GTK_CSS_PROPERTY_ANIMATION_ITERATION_COUNT);
+  directions = gtk_css_style_get_value (GTK_CSS_STYLE (style), GTK_CSS_PROPERTY_ANIMATION_DIRECTION);
+  play_states = gtk_css_style_get_value (GTK_CSS_STYLE (style), GTK_CSS_PROPERTY_ANIMATION_PLAY_STATE);
+  fill_modes = gtk_css_style_get_value (GTK_CSS_STYLE (style), GTK_CSS_PROPERTY_ANIMATION_FILL_MODE);
+
+  for (i = 0; i < _gtk_css_array_value_get_n_values (animations); i++)
+    {
+      GtkStyleAnimation *animation;
+      GtkCssKeyframes *keyframes;
+      const char *name;
+      
+      name = _gtk_css_ident_value_get (_gtk_css_array_value_get_nth (animations, i));
+      if (g_ascii_strcasecmp (name, "none") == 0)
+        continue;
+
+      animation = gtk_css_animated_style_find_animation (style, name);
+      if (animation)
+        continue;
+
+      if (source)
+        animation = gtk_css_animated_style_find_animation (source, name);
+
+      if (animation)
+        {
+          animation = _gtk_css_animation_copy (GTK_CSS_ANIMATION (animation),
+                                               timestamp,
+                                               _gtk_css_play_state_value_get (_gtk_css_array_value_get_nth 
(play_states, i)));
+        }
+      else
+        {
+          keyframes = _gtk_style_provider_private_get_keyframes (provider, name);
+          if (keyframes == NULL)
+            continue;
+
+          keyframes = _gtk_css_keyframes_compute (keyframes, provider, scale, GTK_CSS_STYLE (style), 
GTK_CSS_STYLE (parent_style));
+
+          animation = _gtk_css_animation_new (name,
+                                              keyframes,
+                                              timestamp,
+                                              _gtk_css_number_value_get (_gtk_css_array_value_get_nth 
(delays, i), 100) * G_USEC_PER_SEC,
+                                              _gtk_css_number_value_get (_gtk_css_array_value_get_nth 
(durations, i), 100) * G_USEC_PER_SEC,
+                                              _gtk_css_array_value_get_nth (timing_functions, i),
+                                              _gtk_css_direction_value_get (_gtk_css_array_value_get_nth 
(directions, i)),
+                                              _gtk_css_play_state_value_get (_gtk_css_array_value_get_nth 
(play_states, i)),
+                                              _gtk_css_fill_mode_value_get (_gtk_css_array_value_get_nth 
(fill_modes, i)),
+                                              _gtk_css_number_value_get (_gtk_css_array_value_get_nth 
(iteration_counts, i), 100));
+          _gtk_css_keyframes_unref (keyframes);
+        }
+      style->animations = g_slist_prepend (style->animations, animation);
+    }
+}
+
+/* PUBLIC API */
+
+void
+gtk_css_animated_style_create_animations (GtkCssAnimatedStyle     *style,
+                                          GtkCssAnimatedStyle     *parent_style,
+                                          gint64                   timestamp,
+                                          GtkStyleProviderPrivate *provider,
+                                          int                      scale,
+                                          GtkCssAnimatedStyle     *source)
+{
+  if (source != NULL)
+    gtk_css_animated_style_create_css_transitions (style, timestamp, source);
+  gtk_css_animated_style_create_css_animations (style, parent_style, timestamp, provider, scale, source);
+}
+
+GtkBitmask *
+gtk_css_animated_style_advance (GtkCssAnimatedStyle *style,
+                                gint64               timestamp)
+{
+  GtkBitmask *changed;
+  GPtrArray *old_computed_values;
+  GSList *list;
+  guint i;
+
+  gtk_internal_return_val_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style), NULL);
+  gtk_internal_return_val_if_fail (timestamp >= style->current_time, NULL);
+
+  style->current_time = timestamp;
+  old_computed_values = style->animated_values;
+  style->animated_values = NULL;
+
+  list = style->animations;
+  while (list)
+    {
+      GtkStyleAnimation *animation = list->data;
+      
+      list = list->next;
+
+      _gtk_style_animation_set_values (animation,
+                                       timestamp,
+                                       GTK_CSS_ANIMATED_STYLE (style));
+      
+      if (_gtk_style_animation_is_finished (animation, timestamp))
+        {
+          style->animations = g_slist_remove (style->animations, animation);
+          g_object_unref (animation);
+        }
+    }
+
+  /* figure out changes */
+  changed = _gtk_bitmask_new ();
+
+  for (i = 0; i < GTK_CSS_PROPERTY_N_PROPERTIES; i++)
+    {
+      GtkCssValue *old_animated, *new_animated;
+
+      old_animated = old_computed_values && i < old_computed_values->len ? g_ptr_array_index 
(old_computed_values, i) : NULL;
+      new_animated = style->animated_values && i < style->animated_values->len ? g_ptr_array_index 
(style->animated_values, i) : NULL;
+
+      if (!_gtk_css_value_equal0 (old_animated, new_animated))
+        changed = _gtk_bitmask_set (changed, i, TRUE);
+    }
+
+  if (old_computed_values)
+    g_ptr_array_unref (old_computed_values);
+
+  return changed;
+}
+
+gboolean
+gtk_css_animated_style_is_static (GtkCssAnimatedStyle *style)
+{
+  GSList *list;
+
+  gtk_internal_return_val_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style), TRUE);
+
+  for (list = style->animations; list; list = list->next)
+    {
+      if (!_gtk_style_animation_is_static (list->data, style->current_time))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+void
+gtk_css_animated_style_cancel_animations (GtkCssAnimatedStyle *style)
+{
+  gtk_internal_return_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style));
+
+  if (style->animated_values)
+    {
+      g_ptr_array_unref (style->animated_values);
+      style->animated_values = NULL;
+    }
+
+  g_slist_free_full (style->animations, g_object_unref);
+  style->animations = NULL;
+}
+
diff --git a/gtk/gtkcssanimatedstyleprivate.h b/gtk/gtkcssanimatedstyleprivate.h
new file mode 100644
index 0000000..07b094b
--- /dev/null
+++ b/gtk/gtkcssanimatedstyleprivate.h
@@ -0,0 +1,90 @@
+/*
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_CSS_ANIMATED_STYLE_PRIVATE_H__
+#define __GTK_CSS_ANIMATED_STYLE_PRIVATE_H__
+
+#include "gtk/gtkcssstyleprivate.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_CSS_ANIMATED_STYLE           (gtk_css_animated_style_get_type ())
+#define GTK_CSS_ANIMATED_STYLE(obj)           (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_ANIMATED_STYLE, 
GtkCssAnimatedStyle))
+#define GTK_CSS_ANIMATED_STYLE_CLASS(cls)     (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_ANIMATED_STYLE, 
GtkCssAnimatedStyleClass))
+#define GTK_IS_CSS_ANIMATED_STYLE(obj)        (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_ANIMATED_STYLE))
+#define GTK_IS_CSS_ANIMATED_STYLE_CLASS(obj)  (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_ANIMATED_STYLE))
+#define GTK_CSS_ANIMATED_STYLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GTK_TYPE_CSS_ANIMATED_STYLE, GtkCssAnimatedStyleClass))
+
+typedef struct _GtkCssAnimatedStyle           GtkCssAnimatedStyle;
+typedef struct _GtkCssAnimatedStyleClass      GtkCssAnimatedStyleClass;
+
+struct _GtkCssAnimatedStyle
+{
+  GtkCssStyle parent;
+
+  GPtrArray             *values;               /* the unanimated (aka intrinsic) values */
+  GPtrArray             *sections;             /* sections the values are defined in */
+
+  GPtrArray             *animated_values;      /* NULL or array of animated values/NULL if not animated */
+  gint64                 current_time;         /* the current time in our world */
+  GSList                *animations;           /* the running animations, least important one first */
+
+  GtkBitmask            *depends_on_parent;    /* for intrinsic values */
+  GtkBitmask            *equals_parent;        /* dito */
+  GtkBitmask            *depends_on_color;     /* dito */
+  GtkBitmask            *depends_on_font_size; /* dito */
+};
+
+struct _GtkCssAnimatedStyleClass
+{
+  GtkCssStyleClass parent_class;
+};
+
+GType                   gtk_css_animated_style_get_type         (void) G_GNUC_CONST;
+
+GtkCssStyle *           gtk_css_animated_style_new              (void);
+
+void                    gtk_css_animated_style_compute_value    (GtkCssAnimatedStyle    *style,
+                                                                 GtkStyleProviderPrivate*provider,
+                                                                int                     scale,
+                                                                 GtkCssStyle            *parent_style,
+                                                                 guint                   id,
+                                                                 GtkCssValue            *specified,
+                                                                 GtkCssSection          *section);
+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_create_animations(GtkCssAnimatedStyle    *style,
+                                                                 GtkCssAnimatedStyle    *parent_style,
+                                                                 gint64                  timestamp,
+                                                                 GtkStyleProviderPrivate*provider,
+                                                                int                     scale,
+                                                                 GtkCssAnimatedStyle    *source);
+GtkBitmask *            gtk_css_animated_style_advance          (GtkCssAnimatedStyle    *style,
+                                                                 gint64                  timestamp);
+void                    gtk_css_animated_style_cancel_animations(GtkCssAnimatedStyle    *style);
+gboolean                gtk_css_animated_style_is_static        (GtkCssAnimatedStyle    *style);
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_ANIMATED_STYLE_PRIVATE_H__ */
diff --git a/gtk/gtkcssanimation.c b/gtk/gtkcssanimation.c
index 8ffb537..601e406 100644
--- a/gtk/gtkcssanimation.c
+++ b/gtk/gtkcssanimation.c
@@ -104,7 +104,7 @@ gtk_css_animation_get_progress_from_iteration (GtkCssAnimation *animation,
 static void
 gtk_css_animation_set_values (GtkStyleAnimation    *style_animation,
                               gint64                for_time_us,
-                              GtkCssStyle *values)
+                              GtkCssAnimatedStyle  *style)
 {
   GtkCssAnimation *animation = GTK_CSS_ANIMATION (style_animation);
   double iteration, progress;
@@ -128,8 +128,8 @@ gtk_css_animation_set_values (GtkStyleAnimation    *style_animation,
       value = _gtk_css_keyframes_get_value (animation->keyframes,
                                             i,
                                             progress,
-                                            gtk_css_style_get_intrinsic_value (values, property_id));
-      gtk_css_style_set_animated_value (values, property_id, value);
+                                            gtk_css_animated_style_get_intrinsic_value (style, property_id));
+      gtk_css_animated_style_set_animated_value (style, property_id, value);
       _gtk_css_value_unref (value);
     }
 }
diff --git a/gtk/gtkcsslookup.c b/gtk/gtkcsslookup.c
index ed58601..0e2a952 100644
--- a/gtk/gtkcsslookup.c
+++ b/gtk/gtkcsslookup.c
@@ -106,15 +106,15 @@ void
 _gtk_css_lookup_resolve (GtkCssLookup            *lookup,
                          GtkStyleProviderPrivate *provider,
                         int                      scale,
-                         GtkCssStyle             *values,
-                         GtkCssStyle             *parent_values)
+                         GtkCssAnimatedStyle     *style,
+                         GtkCssStyle             *parent_style)
 {
   guint i, n;
 
   g_return_if_fail (lookup != NULL);
   g_return_if_fail (GTK_IS_STYLE_PROVIDER_PRIVATE (provider));
-  g_return_if_fail (GTK_IS_CSS_STYLE (values));
-  g_return_if_fail (parent_values == NULL || GTK_IS_CSS_STYLE (parent_values));
+  g_return_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style));
+  g_return_if_fail (parent_style == NULL || GTK_IS_CSS_ANIMATED_STYLE (parent_style));
 
   n = _gtk_css_style_property_get_n_properties ();
 
@@ -122,13 +122,13 @@ _gtk_css_lookup_resolve (GtkCssLookup            *lookup,
     {
       if (lookup->values[i].value ||
           _gtk_bitmask_get (lookup->missing, i))
-        gtk_css_style_compute_value (values,
-                                     provider,
-                                     scale,
-                                     parent_values,
-                                     i,
-                                     lookup->values[i].value,
-                                     lookup->values[i].section);
+        gtk_css_animated_style_compute_value (style,
+                                              provider,
+                                              scale,
+                                              parent_style,
+                                              i,
+                                              lookup->values[i].value,
+                                              lookup->values[i].section);
       /* else not a relevant property */
     }
 }
diff --git a/gtk/gtkcsslookupprivate.h b/gtk/gtkcsslookupprivate.h
index 897fe9e..2b53e4a 100644
--- a/gtk/gtkcsslookupprivate.h
+++ b/gtk/gtkcsslookupprivate.h
@@ -20,7 +20,7 @@
 
 #include <glib-object.h>
 #include "gtk/gtkbitmaskprivate.h"
-#include "gtk/gtkcssstyleprivate.h"
+#include "gtk/gtkcssanimatedstyleprivate.h"
 #include "gtk/gtkcsssection.h"
 
 
@@ -51,8 +51,8 @@ void                    _gtk_css_lookup_set                     (GtkCssLookup
 void                    _gtk_css_lookup_resolve                 (GtkCssLookup               *lookup,
                                                                  GtkStyleProviderPrivate    *provider,
                                                                 int                         scale,
-                                                                 GtkCssStyle       *values,
-                                                                 GtkCssStyle       *parent_values);
+                                                                 GtkCssAnimatedStyle        *style,
+                                                                 GtkCssStyle                *parent_style);
 
 static inline const GtkBitmask *
 _gtk_css_lookup_get_missing (const GtkCssLookup *lookup)
diff --git a/gtk/gtkcssstyle.c b/gtk/gtkcssstyle.c
index 21c89a1..f24557c 100644
--- a/gtk/gtkcssstyle.c
+++ b/gtk/gtkcssstyle.c
@@ -37,170 +37,32 @@
 #include "gtkstylepropertyprivate.h"
 #include "gtkstyleproviderprivate.h"
 
-G_DEFINE_TYPE (GtkCssStyle, gtk_css_style, G_TYPE_OBJECT)
+G_DEFINE_ABSTRACT_TYPE (GtkCssStyle, gtk_css_style, G_TYPE_OBJECT)
 
-static void
-gtk_css_style_dispose (GObject *object)
+static GtkCssSection *
+gtk_css_style_real_get_section (GtkCssStyle *style,
+                                guint        id)
 {
-  GtkCssStyle *style = GTK_CSS_STYLE (object);
-
-  if (style->values)
-    {
-      g_ptr_array_unref (style->values);
-      style->values = NULL;
-    }
-  if (style->sections)
-    {
-      g_ptr_array_unref (style->sections);
-      style->sections = NULL;
-    }
-  if (style->animated_values)
-    {
-      g_ptr_array_unref (style->animated_values);
-      style->animated_values = NULL;
-    }
-
-  g_slist_free_full (style->animations, g_object_unref);
-  style->animations = NULL;
-
-  G_OBJECT_CLASS (gtk_css_style_parent_class)->dispose (object);
+  return NULL;
 }
 
-static void
-gtk_css_style_finalize (GObject *object)
+static GtkBitmask *
+gtk_css_style_real_compute_dependencies (GtkCssStyle      *style,
+                                         const GtkBitmask *parent_changes)
 {
-  GtkCssStyle *style = GTK_CSS_STYLE (object);
-
-  _gtk_bitmask_free (style->depends_on_parent);
-  _gtk_bitmask_free (style->equals_parent);
-  _gtk_bitmask_free (style->depends_on_color);
-  _gtk_bitmask_free (style->depends_on_font_size);
-
-  G_OBJECT_CLASS (gtk_css_style_parent_class)->finalize (object);
+  return _gtk_bitmask_copy (parent_changes);
 }
 
 static void
 gtk_css_style_class_init (GtkCssStyleClass *klass)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  object_class->dispose = gtk_css_style_dispose;
-  object_class->finalize = gtk_css_style_finalize;
+  klass->get_section = gtk_css_style_real_get_section;
+  klass->compute_dependencies = gtk_css_style_real_compute_dependencies;
 }
 
 static void
 gtk_css_style_init (GtkCssStyle *style)
 {
-  style->depends_on_parent = _gtk_bitmask_new ();
-  style->equals_parent = _gtk_bitmask_new ();
-  style->depends_on_color = _gtk_bitmask_new ();
-  style->depends_on_font_size = _gtk_bitmask_new ();
-}
-
-GtkCssStyle *
-gtk_css_style_new (void)
-{
-  return g_object_new (GTK_TYPE_CSS_STYLE, NULL);
-}
-
-static void
-maybe_unref_section (gpointer section)
-{
-  if (section)
-    gtk_css_section_unref (section);
-}
-
-void
-gtk_css_style_compute_value (GtkCssStyle             *style,
-                             GtkStyleProviderPrivate *provider,
-                            int                      scale,
-                             GtkCssStyle             *parent_style,
-                             guint                    id,
-                             GtkCssValue             *specified,
-                             GtkCssSection           *section)
-{
-  GtkCssDependencies dependencies;
-  GtkCssValue *value;
-
-  gtk_internal_return_if_fail (GTK_IS_CSS_STYLE (style));
-  gtk_internal_return_if_fail (GTK_IS_STYLE_PROVIDER_PRIVATE (provider));
-  gtk_internal_return_if_fail (parent_style == NULL || GTK_IS_CSS_STYLE (parent_style));
-
-  /* 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)
-    {
-      GtkCssStyleProperty *prop = _gtk_css_style_property_lookup_by_id (id);
-
-      if (_gtk_css_style_property_is_inherit (prop))
-        specified = _gtk_css_inherit_value_new ();
-      else
-        specified = _gtk_css_initial_value_new ();
-    }
-  else
-    _gtk_css_value_ref (specified);
-
-  value = _gtk_css_value_compute (specified, id, provider, scale, style, parent_style, &dependencies);
-
-  if (style->values == NULL)
-    style->values = g_ptr_array_new_full (_gtk_css_style_property_get_n_properties (),
-                                          (GDestroyNotify)_gtk_css_value_unref);
-  if (id >= style->values->len)
-   g_ptr_array_set_size (style->values, id + 1);
-
-  if (g_ptr_array_index (style->values, id))
-    _gtk_css_value_unref (g_ptr_array_index (style->values, id));
-  g_ptr_array_index (style->values, id) = _gtk_css_value_ref (value);
-
-  if (dependencies & (GTK_CSS_DEPENDS_ON_PARENT | GTK_CSS_EQUALS_PARENT))
-    style->depends_on_parent = _gtk_bitmask_set (style->depends_on_parent, id, TRUE);
-  if (dependencies & (GTK_CSS_EQUALS_PARENT))
-    style->equals_parent = _gtk_bitmask_set (style->equals_parent, id, TRUE);
-  if (dependencies & (GTK_CSS_DEPENDS_ON_COLOR))
-    style->depends_on_color = _gtk_bitmask_set (style->depends_on_color, id, TRUE);
-  if (dependencies & (GTK_CSS_DEPENDS_ON_FONT_SIZE))
-    style->depends_on_font_size = _gtk_bitmask_set (style->depends_on_font_size, id, TRUE);
-
-  if (style->sections && style->sections->len > id && g_ptr_array_index (style->sections, id))
-    {
-      gtk_css_section_unref (g_ptr_array_index (style->sections, id));
-      g_ptr_array_index (style->sections, id) = NULL;
-    }
-
-  if (section)
-    {
-      if (style->sections == NULL)
-        style->sections = g_ptr_array_new_with_free_func (maybe_unref_section);
-      if (style->sections->len <= id)
-        g_ptr_array_set_size (style->sections, id + 1);
-
-      g_ptr_array_index (style->sections, id) = gtk_css_section_ref (section);
-    }
-
-  _gtk_css_value_unref (value);
-  _gtk_css_value_unref (specified);
-}
-
-void
-gtk_css_style_set_animated_value (GtkCssStyle *style,
-                                  guint        id,
-                                  GtkCssValue *value)
-{
-  gtk_internal_return_if_fail (GTK_IS_CSS_STYLE (style));
-  gtk_internal_return_if_fail (value != NULL);
-
-  if (style->animated_values == NULL)
-    style->animated_values = g_ptr_array_new_with_free_func ((GDestroyNotify)_gtk_css_value_unref);
-  if (id >= style->animated_values->len)
-   g_ptr_array_set_size (style->animated_values, id + 1);
-
-  if (g_ptr_array_index (style->animated_values, id))
-    _gtk_css_value_unref (g_ptr_array_index (style->animated_values, id));
-  g_ptr_array_index (style->animated_values, id) = _gtk_css_value_ref (value);
-
 }
 
 GtkCssValue *
@@ -209,25 +71,7 @@ gtk_css_style_get_value (GtkCssStyle *style,
 {
   gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (style), NULL);
 
-  if (style->animated_values &&
-      id < style->animated_values->len &&
-      g_ptr_array_index (style->animated_values, id))
-    return g_ptr_array_index (style->animated_values, id);
-
-  return gtk_css_style_get_intrinsic_value (style, id);
-}
-
-GtkCssValue *
-gtk_css_style_get_intrinsic_value (GtkCssStyle *style,
-                                   guint        id)
-{
-  gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (style), NULL);
-
-  if (style->values == NULL ||
-      id >= style->values->len)
-    return NULL;
-
-  return g_ptr_array_index (style->values, id);
+  return GTK_CSS_STYLE_GET_CLASS (style)->get_value (style, id);
 }
 
 GtkCssSection *
@@ -236,11 +80,7 @@ gtk_css_style_get_section (GtkCssStyle *style,
 {
   gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (style), NULL);
 
-  if (style->sections == NULL ||
-      id >= style->sections->len)
-    return NULL;
-
-  return g_ptr_array_index (style->sections, id);
+  return GTK_CSS_STYLE_GET_CLASS (style)->get_section (style, id);
 }
 
 GtkBitmask *
@@ -250,369 +90,25 @@ gtk_css_style_get_difference (GtkCssStyle *style,
   GtkBitmask *result;
   guint i, len;
 
-  len = MIN (style->values->len, other->values->len);
   result = _gtk_bitmask_new ();
-  if (style->values->len != other->values->len)
-    result = _gtk_bitmask_invert_range (result, len, MAX (style->values->len, other->values->len));
-  
+  len = _gtk_css_style_property_get_n_properties ();
   for (i = 0; i < len; i++)
     {
-      if (!_gtk_css_value_equal (g_ptr_array_index (style->values, i),
-                                 g_ptr_array_index (other->values, i)))
+      if (!_gtk_css_value_equal (gtk_css_style_get_value (style, i),
+                                 gtk_css_style_get_value (other, i)))
         result = _gtk_bitmask_set (result, i, TRUE);
     }
 
   return result;
 }
 
-/* TRANSITIONS */
-
-typedef struct _TransitionInfo TransitionInfo;
-struct _TransitionInfo {
-  guint index;                  /* index into value arrays */
-  gboolean pending;             /* TRUE if we still need to handle it */
-};
-
-static void
-transition_info_add (TransitionInfo    infos[GTK_CSS_PROPERTY_N_PROPERTIES],
-                     GtkStyleProperty *property,
-                     guint             index)
-{
-  if (property == NULL)
-    {
-      guint i;
-
-      for (i = 0; i < _gtk_css_style_property_get_n_properties (); i++)
-        {
-          GtkCssStyleProperty *prop = _gtk_css_style_property_lookup_by_id (i);
-
-          transition_info_add (infos, GTK_STYLE_PROPERTY (prop), index);
-        }
-    }
-  else if (GTK_IS_CSS_SHORTHAND_PROPERTY (property))
-    {
-      GtkCssShorthandProperty *shorthand = GTK_CSS_SHORTHAND_PROPERTY (property);
-      guint i;
-
-      for (i = 0; i < _gtk_css_shorthand_property_get_n_subproperties (shorthand); i++)
-        {
-          GtkCssStyleProperty *prop = _gtk_css_shorthand_property_get_subproperty (shorthand, i);
-
-          transition_info_add (infos, GTK_STYLE_PROPERTY (prop), index);
-        }
-    }
-  else if (GTK_IS_CSS_STYLE_PROPERTY (property))
-    {
-      guint id;
-      
-      if (!_gtk_css_style_property_is_animated (GTK_CSS_STYLE_PROPERTY (property)))
-        return;
-
-      id = _gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (property));
-      g_assert (id < GTK_CSS_PROPERTY_N_PROPERTIES);
-      infos[id].index = index;
-      infos[id].pending = TRUE;
-    }
-  else
-    {
-      g_assert_not_reached ();
-    }
-}
-
-static void
-transition_infos_set (TransitionInfo  infos[GTK_CSS_PROPERTY_N_PROPERTIES],
-                      GtkCssValue    *transitions)
-{
-  guint i;
-
-  for (i = 0; i < _gtk_css_array_value_get_n_values (transitions); i++)
-    {
-      GtkStyleProperty *property;
-      GtkCssValue *prop_value;
-
-      prop_value = _gtk_css_array_value_get_nth (transitions, i);
-      if (g_ascii_strcasecmp (_gtk_css_ident_value_get (prop_value), "all") == 0)
-        property = NULL;
-      else
-        {
-          property = _gtk_style_property_lookup (_gtk_css_ident_value_get (prop_value));
-          if (property == NULL)
-            continue;
-        }
-      
-      transition_info_add (infos, property, i);
-    }
-}
-
-static GtkStyleAnimation *
-gtk_css_style_find_transition (GtkCssStyle *style,
-                               guint        property_id)
-{
-  GSList *list;
-
-  for (list = style->animations; list; list = list->next)
-    {
-      if (!GTK_IS_CSS_TRANSITION (list->data))
-        continue;
-
-      if (_gtk_css_transition_get_property (list->data) == property_id)
-        return list->data;
-    }
-
-  return NULL;
-}
-
-static void
-gtk_css_style_create_css_transitions (GtkCssStyle *style,
-                                      gint64       timestamp,
-                                      GtkCssStyle *source)
-{
-  TransitionInfo transitions[GTK_CSS_PROPERTY_N_PROPERTIES] = { { 0, } };
-  GtkCssValue *durations, *delays, *timing_functions;
-  guint i;
-
-  transition_infos_set (transitions, gtk_css_style_get_value (style, GTK_CSS_PROPERTY_TRANSITION_PROPERTY));
-
-  durations = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_TRANSITION_DURATION);
-  delays = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_TRANSITION_DELAY);
-  timing_functions = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_TRANSITION_TIMING_FUNCTION);
-
-  for (i = 0; i < GTK_CSS_PROPERTY_N_PROPERTIES; i++)
-    {
-      GtkStyleAnimation *animation;
-      GtkCssValue *start, *end;
-      double duration, delay;
-
-      if (!transitions[i].pending)
-        continue;
-
-      duration = _gtk_css_number_value_get (_gtk_css_array_value_get_nth (durations, transitions[i].index), 
100);
-      delay = _gtk_css_number_value_get (_gtk_css_array_value_get_nth (delays, transitions[i].index), 100);
-      if (duration + delay == 0.0)
-        continue;
-
-      start = gtk_css_style_get_intrinsic_value (source, i);
-      end = gtk_css_style_get_intrinsic_value (style, i);
-      if (_gtk_css_value_equal (start, end))
-        {
-          animation = gtk_css_style_find_transition (GTK_CSS_STYLE (source), i);
-          if (animation)
-            style->animations = g_slist_prepend (style->animations, g_object_ref (animation));
-        }
-      else
-        {
-          animation = _gtk_css_transition_new (i,
-                                               gtk_css_style_get_value (source, i),
-                                               _gtk_css_array_value_get_nth (timing_functions, i),
-                                               timestamp + delay * G_USEC_PER_SEC,
-                                               timestamp + (delay + duration) * G_USEC_PER_SEC);
-          style->animations = g_slist_prepend (style->animations, animation);
-        }
-    }
-}
-
-static GtkStyleAnimation *
-gtk_css_style_find_animation (GtkCssStyle *style,
-                              const char  *name)
-{
-  GSList *list;
-
-  for (list = style->animations; list; list = list->next)
-    {
-      if (!GTK_IS_CSS_ANIMATION (list->data))
-        continue;
-
-      if (g_str_equal (_gtk_css_animation_get_name (list->data), name))
-        return list->data;
-    }
-
-  return NULL;
-}
-
-static void
-gtk_css_style_create_css_animations (GtkCssStyle             *style,
-                                     GtkCssStyle             *parent_style,
-                                     gint64                   timestamp,
-                                     GtkStyleProviderPrivate *provider,
-                                    int                      scale,
-                                     GtkCssStyle             *source)
-{
-  GtkCssValue *durations, *delays, *timing_functions, *animations;
-  GtkCssValue *iteration_counts, *directions, *play_states, *fill_modes;
-  guint i;
-
-  animations = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ANIMATION_NAME);
-  durations = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ANIMATION_DURATION);
-  delays = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ANIMATION_DELAY);
-  timing_functions = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ANIMATION_TIMING_FUNCTION);
-  iteration_counts = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ANIMATION_ITERATION_COUNT);
-  directions = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ANIMATION_DIRECTION);
-  play_states = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ANIMATION_PLAY_STATE);
-  fill_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ANIMATION_FILL_MODE);
-
-  for (i = 0; i < _gtk_css_array_value_get_n_values (animations); i++)
-    {
-      GtkStyleAnimation *animation;
-      GtkCssKeyframes *keyframes;
-      const char *name;
-      
-      name = _gtk_css_ident_value_get (_gtk_css_array_value_get_nth (animations, i));
-      if (g_ascii_strcasecmp (name, "none") == 0)
-        continue;
-
-      animation = gtk_css_style_find_animation (style, name);
-      if (animation)
-        continue;
-
-      if (source)
-        animation = gtk_css_style_find_animation (source, name);
-
-      if (animation)
-        {
-          animation = _gtk_css_animation_copy (GTK_CSS_ANIMATION (animation),
-                                               timestamp,
-                                               _gtk_css_play_state_value_get (_gtk_css_array_value_get_nth 
(play_states, i)));
-        }
-      else
-        {
-          keyframes = _gtk_style_provider_private_get_keyframes (provider, name);
-          if (keyframes == NULL)
-            continue;
-
-          keyframes = _gtk_css_keyframes_compute (keyframes, provider, scale, style, parent_style);
-
-          animation = _gtk_css_animation_new (name,
-                                              keyframes,
-                                              timestamp,
-                                              _gtk_css_number_value_get (_gtk_css_array_value_get_nth 
(delays, i), 100) * G_USEC_PER_SEC,
-                                              _gtk_css_number_value_get (_gtk_css_array_value_get_nth 
(durations, i), 100) * G_USEC_PER_SEC,
-                                              _gtk_css_array_value_get_nth (timing_functions, i),
-                                              _gtk_css_direction_value_get (_gtk_css_array_value_get_nth 
(directions, i)),
-                                              _gtk_css_play_state_value_get (_gtk_css_array_value_get_nth 
(play_states, i)),
-                                              _gtk_css_fill_mode_value_get (_gtk_css_array_value_get_nth 
(fill_modes, i)),
-                                              _gtk_css_number_value_get (_gtk_css_array_value_get_nth 
(iteration_counts, i), 100));
-          _gtk_css_keyframes_unref (keyframes);
-        }
-      style->animations = g_slist_prepend (style->animations, animation);
-    }
-}
-
-/* PUBLIC API */
-
-void
-gtk_css_style_create_animations (GtkCssStyle             *style,
-                                 GtkCssStyle             *parent_style,
-                                 gint64                   timestamp,
-                                 GtkStyleProviderPrivate *provider,
-                                 int                      scale,
-                                 GtkCssStyle             *source)
-{
-  if (source != NULL)
-    gtk_css_style_create_css_transitions (style, timestamp, source);
-  gtk_css_style_create_css_animations (style, parent_style, timestamp, provider, scale, source);
-}
-
-GtkBitmask *
-gtk_css_style_advance (GtkCssStyle *style,
-                       gint64       timestamp)
-{
-  GtkBitmask *changed;
-  GPtrArray *old_computed_values;
-  GSList *list;
-  guint i;
-
-  gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (style), NULL);
-  gtk_internal_return_val_if_fail (timestamp >= style->current_time, NULL);
-
-  style->current_time = timestamp;
-  old_computed_values = style->animated_values;
-  style->animated_values = NULL;
-
-  list = style->animations;
-  while (list)
-    {
-      GtkStyleAnimation *animation = list->data;
-      
-      list = list->next;
-
-      _gtk_style_animation_set_values (animation,
-                                       timestamp,
-                                       GTK_CSS_STYLE (style));
-      
-      if (_gtk_style_animation_is_finished (animation, timestamp))
-        {
-          style->animations = g_slist_remove (style->animations, animation);
-          g_object_unref (animation);
-        }
-    }
-
-  /* figure out changes */
-  changed = _gtk_bitmask_new ();
-
-  for (i = 0; i < GTK_CSS_PROPERTY_N_PROPERTIES; i++)
-    {
-      GtkCssValue *old_animated, *new_animated;
-
-      old_animated = old_computed_values && i < old_computed_values->len ? g_ptr_array_index 
(old_computed_values, i) : NULL;
-      new_animated = style->animated_values && i < style->animated_values->len ? g_ptr_array_index 
(style->animated_values, i) : NULL;
-
-      if (!_gtk_css_value_equal0 (old_animated, new_animated))
-        changed = _gtk_bitmask_set (changed, i, TRUE);
-    }
-
-  if (old_computed_values)
-    g_ptr_array_unref (old_computed_values);
-
-  return changed;
-}
-
-gboolean
-gtk_css_style_is_static (GtkCssStyle *style)
-{
-  GSList *list;
-
-  gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (style), TRUE);
-
-  for (list = style->animations; list; list = list->next)
-    {
-      if (!_gtk_style_animation_is_static (list->data, style->current_time))
-        return FALSE;
-    }
-
-  return TRUE;
-}
-
-void
-gtk_css_style_cancel_animations (GtkCssStyle *style)
-{
-  gtk_internal_return_if_fail (GTK_IS_CSS_STYLE (style));
-
-  if (style->animated_values)
-    {
-      g_ptr_array_unref (style->animated_values);
-      style->animated_values = NULL;
-    }
-
-  g_slist_free_full (style->animations, g_object_unref);
-  style->animations = NULL;
-}
-
 GtkBitmask *
 gtk_css_style_compute_dependencies (GtkCssStyle      *style,
                                     const GtkBitmask *parent_changes)
 {
-  GtkBitmask *changes;
-
   gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (style), _gtk_bitmask_new ());
 
-  changes = _gtk_bitmask_copy (parent_changes);
-  changes = _gtk_bitmask_intersect (changes, style->depends_on_parent);
-  if (_gtk_bitmask_get (changes, GTK_CSS_PROPERTY_COLOR))
-    changes = _gtk_bitmask_union (changes, style->depends_on_color);
-  if (_gtk_bitmask_get (changes, GTK_CSS_PROPERTY_FONT_SIZE))
-    changes = _gtk_bitmask_union (changes, style->depends_on_font_size);
-
-  return changes;
+  return GTK_CSS_STYLE_GET_CLASS (style)->compute_dependencies (style, parent_changes);
 }
 
 void
diff --git a/gtk/gtkcssstyleprivate.h b/gtk/gtkcssstyleprivate.h
index f566426..d61b4c3 100644
--- a/gtk/gtkcssstyleprivate.h
+++ b/gtk/gtkcssstyleprivate.h
@@ -41,62 +41,39 @@ typedef struct _GtkCssStyleClass      GtkCssStyleClass;
 struct _GtkCssStyle
 {
   GObject parent;
-
-  GPtrArray             *values;               /* the unanimated (aka intrinsic) values */
-  GPtrArray             *sections;             /* sections the values are defined in */
-
-  GPtrArray             *animated_values;      /* NULL or array of animated values/NULL if not animated */
-  gint64                 current_time;         /* the current time in our world */
-  GSList                *animations;           /* the running animations, least important one first */
-
-  GtkBitmask            *depends_on_parent;    /* for intrinsic values */
-  GtkBitmask            *equals_parent;        /* dito */
-  GtkBitmask            *depends_on_color;     /* dito */
-  GtkBitmask            *depends_on_font_size; /* dito */
 };
 
 struct _GtkCssStyleClass
 {
   GObjectClass parent_class;
+
+  /* Get the value for the given property id. This needs to be FAST. */
+  GtkCssValue *         (* get_value)                           (GtkCssStyle            *style,
+                                                                 guint                   id);
+  /* Get the section the value at the given id was declared at or NULL if unavailable.
+   * Optional: default impl will just return NULL */
+  GtkCssSection *       (* get_section)                         (GtkCssStyle            *style,
+                                                                 guint                   id);
+  /* Compute the bitmask of potentially changed properties if the parent has changed
+   * the passed in ones.
+   * This is for example needed when changes in the "color" property will affect
+   * all properties using "currentColor" as a color.
+   * Optional: The default impl just returns the parent changes unchanged */
+  GtkBitmask *          (* compute_dependencies)                (GtkCssStyle            *style,
+                                                                 const GtkBitmask       *parent_changes);
 };
 
 GType                   gtk_css_style_get_type                  (void) G_GNUC_CONST;
 
-GtkCssStyle *           gtk_css_style_new                       (void);
-
-void                    gtk_css_style_compute_value             (GtkCssStyle            *style,
-                                                                 GtkStyleProviderPrivate*provider,
-                                                                int                     scale,
-                                                                 GtkCssStyle            *parent_style,
-                                                                 guint                   id,
-                                                                 GtkCssValue            *specified,
-                                                                 GtkCssSection          *section);
-void                    gtk_css_style_set_animated_value        (GtkCssStyle            *style,
-                                                                 guint                   id,
-                                                                 GtkCssValue            *value);
-                                                                        
 GtkCssValue *           gtk_css_style_get_value                 (GtkCssStyle            *style,
                                                                  guint                   id);
 GtkCssSection *         gtk_css_style_get_section               (GtkCssStyle            *style,
                                                                  guint                   id);
-GtkCssValue *           gtk_css_style_get_intrinsic_value       (GtkCssStyle            *style,
-                                                                 guint                   id);
 GtkBitmask *            gtk_css_style_get_difference            (GtkCssStyle            *style,
                                                                  GtkCssStyle            *other);
 GtkBitmask *            gtk_css_style_compute_dependencies      (GtkCssStyle            *style,
                                                                  const GtkBitmask       *parent_changes);
 
-void                    gtk_css_style_create_animations         (GtkCssStyle            *style,
-                                                                 GtkCssStyle            *parent_style,
-                                                                 gint64                  timestamp,
-                                                                 GtkStyleProviderPrivate*provider,
-                                                                int                     scale,
-                                                                 GtkCssStyle            *source);
-GtkBitmask *            gtk_css_style_advance                   (GtkCssStyle            *style,
-                                                                 gint64                  timestamp);
-void                    gtk_css_style_cancel_animations         (GtkCssStyle            *style);
-gboolean                gtk_css_style_is_static                 (GtkCssStyle            *style);
-
 char *                  gtk_css_style_to_string                 (GtkCssStyle            *style);
 void                    gtk_css_style_print                     (GtkCssStyle            *style,
                                                                  GString                *string);
diff --git a/gtk/gtkcsstransition.c b/gtk/gtkcsstransition.c
index 0d0f581..747bac1 100644
--- a/gtk/gtkcsstransition.c
+++ b/gtk/gtkcsstransition.c
@@ -26,15 +26,15 @@
 G_DEFINE_TYPE (GtkCssTransition, _gtk_css_transition, GTK_TYPE_STYLE_ANIMATION)
 
 static void
-gtk_css_transition_set_values (GtkStyleAnimation *animation,
-                               gint64             for_time_us,
-                               GtkCssStyle       *style)
+gtk_css_transition_set_values (GtkStyleAnimation   *animation,
+                               gint64               for_time_us,
+                               GtkCssAnimatedStyle *style)
 {
   GtkCssTransition *transition = GTK_CSS_TRANSITION (animation);
   GtkCssValue *value, *end;
   double progress;
 
-  end = gtk_css_style_get_intrinsic_value (style, transition->property);
+  end = gtk_css_animated_style_get_intrinsic_value (style, transition->property);
 
   if (transition->start_time >= for_time_us)
     value = _gtk_css_value_ref (transition->start);
@@ -55,7 +55,7 @@ gtk_css_transition_set_values (GtkStyleAnimation *animation,
 
   if (value)
     {
-      gtk_css_style_set_animated_value (style, transition->property, value);
+      gtk_css_animated_style_set_animated_value (style, transition->property, value);
       _gtk_css_value_unref (value);
     }
 }
diff --git a/gtk/gtkstyleanimation.c b/gtk/gtkstyleanimation.c
index 7bca5b7..3c1a887 100644
--- a/gtk/gtkstyleanimation.c
+++ b/gtk/gtkstyleanimation.c
@@ -26,7 +26,7 @@ G_DEFINE_ABSTRACT_TYPE (GtkStyleAnimation, _gtk_style_animation, G_TYPE_OBJECT)
 static void
 gtk_style_animation_real_set_values (GtkStyleAnimation    *animation,
                                      gint64                for_time_us,
-                                     GtkCssStyle *values)
+                                     GtkCssAnimatedStyle  *style)
 {
 }
 
@@ -60,16 +60,16 @@ _gtk_style_animation_init (GtkStyleAnimation *animation)
 void
 _gtk_style_animation_set_values (GtkStyleAnimation    *animation,
                                  gint64                for_time_us,
-                                 GtkCssStyle *values)
+                                 GtkCssAnimatedStyle  *style)
 {
   GtkStyleAnimationClass *klass;
 
   g_return_if_fail (GTK_IS_STYLE_ANIMATION (animation));
-  g_return_if_fail (GTK_IS_CSS_STYLE (values));
+  g_return_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style));
 
   klass = GTK_STYLE_ANIMATION_GET_CLASS (animation);
 
-  return klass->set_values (animation, for_time_us, values);
+  klass->set_values (animation, for_time_us, style);
 }
 
 gboolean
diff --git a/gtk/gtkstyleanimationprivate.h b/gtk/gtkstyleanimationprivate.h
index fbeb9d7..6981004 100644
--- a/gtk/gtkstyleanimationprivate.h
+++ b/gtk/gtkstyleanimationprivate.h
@@ -20,8 +20,7 @@
 #ifndef __GTK_STYLE_ANIMATION_PRIVATE_H__
 #define __GTK_STYLE_ANIMATION_PRIVATE_H__
 
-#include <glib-object.h>
-#include "gtkcssstyleprivate.h"
+#include "gtkcssanimatedstyleprivate.h"
 
 G_BEGIN_DECLS
 
@@ -50,14 +49,14 @@ struct _GtkStyleAnimationClass
                                                          gint64                  at_time_us);
   void          (* set_values)                          (GtkStyleAnimation      *animation,
                                                          gint64                  for_time_us,
-                                                         GtkCssStyle   *values);
+                                                         GtkCssAnimatedStyle    *style);
 };
 
 GType           _gtk_style_animation_get_type           (void) G_GNUC_CONST;
 
 void            _gtk_style_animation_set_values         (GtkStyleAnimation      *animation,
                                                          gint64                  for_time_us,
-                                                         GtkCssStyle   *values);
+                                                         GtkCssAnimatedStyle    *style);
 gboolean        _gtk_style_animation_is_finished        (GtkStyleAnimation      *animation,
                                                          gint64                  at_time_us);
 gboolean        _gtk_style_animation_is_static          (GtkStyleAnimation      *animation,
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index cdd66f0..479bf14 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -503,7 +503,7 @@ gtk_style_context_should_animate (GtkStyleContext *context)
     return FALSE;
 
   values = style_values_lookup (context);
-  if (gtk_css_style_is_static (values))
+  if (gtk_css_animated_style_is_static (GTK_CSS_ANIMATED_STYLE (values)))
     return FALSE;
 
   g_object_get (gtk_widget_get_settings (context->priv->widget),
@@ -704,7 +704,7 @@ build_properties (GtkStyleContext             *context,
   _gtk_css_lookup_resolve (lookup, 
                            GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
                           priv->scale,
-                           values,
+                           GTK_CSS_ANIMATED_STYLE (values),
                            priv->parent ? style_values_lookup (priv->parent) : NULL);
 
   _gtk_css_lookup_free (lookup);
@@ -734,7 +734,7 @@ style_values_lookup (GtkStyleContext *context)
       return values;
     }
 
-  values = gtk_css_style_new ();
+  values = gtk_css_animated_style_new ();
 
   style_info_set_values (info, values);
   if (gtk_style_context_is_saved (context))
@@ -772,7 +772,7 @@ style_values_lookup_for_state (GtkStyleContext *context,
 
   decl = gtk_css_node_declaration_ref (context->priv->info->decl);
   gtk_css_node_declaration_set_state (&decl, state);
-  values = gtk_css_style_new ();
+  values = gtk_css_animated_style_new ();
   build_properties (context, values, decl, NULL, NULL);
   gtk_css_node_declaration_unref (decl);
 
@@ -2696,9 +2696,9 @@ gtk_style_context_update_animations (GtkStyleContext *context,
   
   values = style_values_lookup (context);
 
-  differences = gtk_css_style_advance (values, timestamp);
+  differences = gtk_css_animated_style_advance (GTK_CSS_ANIMATED_STYLE (values), timestamp);
 
-  if (gtk_css_style_is_static (values))
+  if (gtk_css_animated_style_is_static (GTK_CSS_ANIMATED_STYLE (values)))
     _gtk_style_context_update_animating (context);
 
   return differences;
@@ -2805,13 +2805,15 @@ _gtk_style_context_validate (GtkStyleContext  *context,
       values = style_values_lookup (context);
 
       if (values != current)
-        gtk_css_style_create_animations (values,
-                                         priv->parent ? style_values_lookup (priv->parent) : NULL,
-                                         timestamp,
-                                         GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
-                                         priv->scale,
-                                         gtk_style_context_should_create_transitions (context) ? current : 
NULL);
-      if (gtk_css_style_is_static (values))
+        gtk_css_animated_style_create_animations (GTK_CSS_ANIMATED_STYLE (values),
+                                                  priv->parent ? GTK_CSS_ANIMATED_STYLE (style_values_lookup 
(priv->parent)) : NULL,
+                                                  timestamp,
+                                                  GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
+                                                  priv->scale,
+                                                  gtk_style_context_should_create_transitions (context) 
+                                                    ? GTK_CSS_ANIMATED_STYLE (current)
+                                                    : NULL);
+      if (gtk_css_animated_style_is_static (GTK_CSS_ANIMATED_STYLE (values)))
         change &= ~GTK_CSS_CHANGE_ANIMATE;
       else
         change |= GTK_CSS_CHANGE_ANIMATE;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]