[gnome-shell] Notice style transitions that don't change how StThemeNode paints
- From: Owen Taylor <otaylor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] Notice style transitions that don't change how StThemeNode paints
- Date: Mon, 30 Aug 2010 17:41:36 +0000 (UTC)
commit 5e7c25e136f28c2263770f86e1942b0baea080fd
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Thu Aug 26 14:10:46 2010 -0400
Notice style transitions that don't change how StThemeNode paints
Add st_theme_node_paint_equal() and use that to do two things:
1) Avoid animating transitions where nothing changes.
2) Copy cached painting state from the old theme node to the new
theme node.
https://bugzilla.gnome.org/show_bug.cgi?id=627083
src/st/st-border-image.c | 25 +++++++++++
src/st/st-border-image.h | 3 +
src/st/st-shadow.c | 32 +++++++++++++-
src/st/st-shadow.h | 3 +
src/st/st-theme-node-drawing.c | 37 ++++++++++++++++
src/st/st-theme-node-transition.c | 9 +++-
src/st/st-theme-node.c | 86 +++++++++++++++++++++++++++++++++++++
src/st/st-theme-node.h | 4 ++
src/st/st-widget.c | 14 ++++++-
9 files changed, 210 insertions(+), 3 deletions(-)
---
diff --git a/src/st/st-border-image.c b/src/st/st-border-image.c
index 373b4ab..4e27d6e 100644
--- a/src/st/st-border-image.c
+++ b/src/st/st-border-image.c
@@ -2,6 +2,8 @@
#include <config.h>
+#include <string.h>
+
#include "st-border-image.h"
struct _StBorderImage {
@@ -90,3 +92,26 @@ st_border_image_get_borders (StBorderImage *image,
if (border_left)
*border_left = image->border_left;
}
+
+/**
+ * st_border_image_equal:
+ * @border_image: a #StBorder_Image
+ * @other: a different #StBorder_Image
+ *
+ * Check if two border_image objects are identical.
+ *
+ * Return value: %TRUE if the two border image objects are identical
+ */
+gboolean
+st_border_image_equal (StBorderImage *image,
+ StBorderImage *other)
+{
+ g_return_val_if_fail (ST_IS_BORDER_IMAGE (image), FALSE);
+ g_return_val_if_fail (ST_IS_BORDER_IMAGE (other), FALSE);
+
+ return (image->border_top == other->border_top &&
+ image->border_right == other->border_right &&
+ image->border_bottom == other->border_bottom &&
+ image->border_left == other->border_left &&
+ strcmp (image->filename, other->filename) == 0);
+}
diff --git a/src/st/st-border-image.h b/src/st/st-border-image.h
index 3f96473..c1bb7e4 100644
--- a/src/st/st-border-image.h
+++ b/src/st/st-border-image.h
@@ -33,6 +33,9 @@ void st_border_image_get_borders (StBorderImage *image,
int *border_bottom,
int *border_left);
+gboolean st_border_image_equal (StBorderImage *image,
+ StBorderImage *other);
+
G_END_DECLS
#endif /* __ST_BORDER_IMAGE_H__ */
diff --git a/src/st/st-shadow.c b/src/st/st-shadow.c
index 49fd5b2..f353e65 100644
--- a/src/st/st-shadow.c
+++ b/src/st/st-shadow.c
@@ -78,6 +78,37 @@ st_shadow_free (StShadow *shadow)
}
/**
+ * st_shadow_equal:
+ * @shadow: a #StShadow
+ * @other: a different #StShadow
+ *
+ * Check if two shadow objects are identical. Note that two shadows may
+ * compare non-identically if they differ only by floating point rounding
+ * errors.
+ *
+ * Return value: %TRUE if the two shadows are identical
+ */
+gboolean
+st_shadow_equal (StShadow *shadow,
+ StShadow *other)
+{
+ g_return_val_if_fail (shadow != NULL, FALSE);
+ g_return_val_if_fail (other != NULL, FALSE);
+
+ /* We use strict equality to compare double quantities; this means
+ * that, for example, a shadow offset of 0.25in does not necessarily
+ * compare equal to a shadow offset of 18pt in this test. Assume
+ * that a few false negatives are mostly harmless.
+ */
+
+ return (clutter_color_equal (&shadow->color, &other->color) &&
+ shadow->xoffset == other->xoffset &&
+ shadow->yoffset == other->yoffset &&
+ shadow->blur == other->blur &&
+ shadow->spread == other->spread);
+}
+
+/**
* st_shadow_get_box:
* @shadow: a #StShadow
* @actor_box: the box allocated to a #ClutterAlctor
@@ -105,7 +136,6 @@ st_shadow_get_box (StShadow *shadow,
+ shadow->blur + shadow->spread;
}
-
GType
st_shadow_get_type (void)
{
diff --git a/src/st/st-shadow.h b/src/st/st-shadow.h
index 97cecf8..53b1494 100644
--- a/src/st/st-shadow.h
+++ b/src/st/st-shadow.h
@@ -41,6 +41,9 @@ StShadow *st_shadow_new (ClutterColor *color,
StShadow *st_shadow_copy (const StShadow *shadow);
void st_shadow_free (StShadow *shadow);
+gboolean st_shadow_equal (StShadow *shadow,
+ StShadow *other);
+
void st_shadow_get_box (StShadow *shadow,
const ClutterActorBox *actor_box,
ClutterActorBox *shadow_box);
diff --git a/src/st/st-theme-node-drawing.c b/src/st/st-theme-node-drawing.c
index 5bd41c7..0e23caa 100644
--- a/src/st/st-theme-node-drawing.c
+++ b/src/st/st-theme-node-drawing.c
@@ -1198,3 +1198,40 @@ st_theme_node_paint (StThemeNode *node,
paint_texture_with_opacity (node->background_texture, &background_box, paint_opacity);
}
}
+
+/**
+ * st_theme_node_copy_cached_paint_state:
+ * @node: a #StThemeNode
+ * @other: a different #StThemeNode
+ *
+ * Copy cached painting state from @other to @node. This function can be used to
+ * optimize redrawing cached background images when the style on an element changess
+ * in a way that doesn't affect background drawing. This function must only be called
+ * if st_theme_node_paint_equal (node, other) returns %TRUE.
+ */
+void
+st_theme_node_copy_cached_paint_state (StThemeNode *node,
+ StThemeNode *other)
+{
+ g_return_if_fail (ST_IS_THEME_NODE (node));
+ g_return_if_fail (ST_IS_THEME_NODE (other));
+
+ /* Check omitted for speed: */
+ /* g_return_if_fail (st_theme_node_paint_equal (node, other)); */
+
+ _st_theme_node_free_drawing_state (node);
+
+ node->alloc_width = other->alloc_width;
+ node->alloc_height = other->alloc_height;
+
+ if (other->background_shadow_material)
+ node->background_shadow_material = cogl_handle_ref (other->background_shadow_material);
+ if (other->border_shadow_material)
+ node->border_shadow_material = cogl_handle_ref (other->border_shadow_material);
+ if (other->background_texture)
+ node->background_texture = cogl_handle_ref (other->background_texture);
+ if (other->border_texture)
+ node->border_texture = cogl_handle_ref (other->border_texture);
+ if (other->corner_texture)
+ node->corner_texture = cogl_handle_ref (other->corner_texture);
+}
diff --git a/src/st/st-theme-node-transition.c b/src/st/st-theme-node-transition.c
index 9dbb45c..884f806 100644
--- a/src/st/st-theme-node-transition.c
+++ b/src/st/st-theme-node-transition.c
@@ -165,9 +165,16 @@ st_theme_node_transition_update (StThemeNodeTransition *transition,
guint new_duration = st_theme_node_get_transition_duration (new_node);
clutter_timeline_set_duration (priv->timeline, new_duration);
+
+ /* If the change doesn't affect painting, we don't need to redraw,
+ * but we still need to replace the node so that we properly share
+ * caching with the painting that happens after the transition finishes.
+ */
+ if (!st_theme_node_paint_equal (priv->new_theme_node, new_node))
+ priv->needs_setup = TRUE;
+
g_object_unref (priv->new_theme_node);
priv->new_theme_node = g_object_ref (new_node);
- priv->needs_setup = TRUE;
}
}
}
diff --git a/src/st/st-theme-node.c b/src/st/st-theme-node.c
index a9d33af..90b156a 100644
--- a/src/st/st-theme-node.c
+++ b/src/st/st-theme-node.c
@@ -2760,6 +2760,9 @@ st_theme_node_geometry_equal (StThemeNode *node,
{
StSide side;
+ g_return_val_if_fail (ST_IS_THEME_NODE (node), FALSE);
+ g_return_val_if_fail (ST_IS_THEME_NODE (other), FALSE);
+
_st_theme_node_ensure_geometry (node);
_st_theme_node_ensure_geometry (other);
@@ -2780,3 +2783,86 @@ st_theme_node_geometry_equal (StThemeNode *node,
return TRUE;
}
+
+/**
+ * st_theme_node_paint_equal:
+ * @node: a #StThemeNode
+ * @other: a different #StThemeNode
+ *
+ * Check if st_theme_node_paint() will paint identically for @node as it does
+ * for @other. Note that in some cases this function may return %TRUE even
+ * if there is no visible difference in the painting.
+ *
+ * Return value: %TRUE if the two theme nodes paint identically. %FALSE if the
+ * two nodes potentially paint differently.
+ */
+gboolean
+st_theme_node_paint_equal (StThemeNode *node,
+ StThemeNode *other)
+{
+ StBorderImage *border_image, *other_border_image;
+ StShadow *shadow, *other_shadow;
+ int i;
+
+ g_return_val_if_fail (ST_IS_THEME_NODE (node), FALSE);
+ g_return_val_if_fail (ST_IS_THEME_NODE (other), FALSE);
+
+ _st_theme_node_ensure_background (node);
+ _st_theme_node_ensure_background (other);
+
+ if (!clutter_color_equal (&node->background_color, &other->background_color))
+ return FALSE;
+
+ if (node->background_gradient_type != other->background_gradient_type)
+ return FALSE;
+
+ if (node->background_gradient_type != ST_GRADIENT_NONE &&
+ !clutter_color_equal (&node->background_gradient_end, &other->background_gradient_end))
+ return FALSE;
+
+ if (g_strcmp0 (node->background_image, other->background_image) != 0)
+ return FALSE;
+
+ _st_theme_node_ensure_geometry (node);
+ _st_theme_node_ensure_geometry (other);
+
+ for (i = 0; i < 4; i++)
+ {
+ if (node->border_width[i] != other->border_width[i])
+ return FALSE;
+
+ if (node->border_width[i] > 0 &&
+ !clutter_color_equal (&node->border_color[i], &other->border_color[i]))
+ return FALSE;
+
+ if (node->border_radius[i] != other->border_radius[i])
+ return FALSE;
+ }
+
+ if (node->outline_width != other->outline_width)
+ return FALSE;
+
+ if (node->outline_width > 0 &&
+ !clutter_color_equal (&node->outline_color, &other->outline_color))
+ return FALSE;
+
+ border_image = st_theme_node_get_border_image (node);
+ other_border_image = st_theme_node_get_border_image (other);
+
+ if ((border_image == NULL) != (other_border_image == NULL))
+ return FALSE;
+
+ if (border_image != NULL && !st_border_image_equal (border_image, other_border_image))
+ return FALSE;
+
+ shadow = st_theme_node_get_shadow (node);
+ other_shadow = st_theme_node_get_shadow (other);
+
+ if ((shadow == NULL) != (other_shadow == NULL))
+ return FALSE;
+
+ if (shadow != NULL && !st_shadow_equal (shadow, other_shadow))
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/src/st/st-theme-node.h b/src/st/st-theme-node.h
index 97f8e83..19796c6 100644
--- a/src/st/st-theme-node.h
+++ b/src/st/st-theme-node.h
@@ -191,11 +191,15 @@ void st_theme_node_get_paint_box (StThemeNode *node,
gboolean st_theme_node_geometry_equal (StThemeNode *node,
StThemeNode *other);
+gboolean st_theme_node_paint_equal (StThemeNode *node,
+ StThemeNode *other);
void st_theme_node_paint (StThemeNode *node,
const ClutterActorBox *box,
guint8 paint_opacity);
+void st_theme_node_copy_cached_paint_state (StThemeNode *node,
+ StThemeNode *other);
G_END_DECLS
diff --git a/src/st/st-widget.c b/src/st/st-widget.c
index d4850a7..f56331d 100644
--- a/src/st/st-widget.c
+++ b/src/st/st-widget.c
@@ -1222,6 +1222,7 @@ st_widget_recompute_style (StWidget *widget,
{
StThemeNode *new_theme_node = st_widget_get_theme_node (widget);
int transition_duration;
+ gboolean paint_equal;
if (!old_theme_node ||
!st_theme_node_geometry_equal (old_theme_node, new_theme_node))
@@ -1229,6 +1230,11 @@ st_widget_recompute_style (StWidget *widget,
transition_duration = st_theme_node_get_transition_duration (new_theme_node);
+ paint_equal = old_theme_node && st_theme_node_paint_equal (old_theme_node, new_theme_node);
+
+ if (paint_equal)
+ st_theme_node_copy_cached_paint_state (new_theme_node, old_theme_node);
+
if (transition_duration > 0)
{
if (widget->priv->transition_animation != NULL)
@@ -1236,8 +1242,14 @@ st_widget_recompute_style (StWidget *widget,
st_theme_node_transition_update (widget->priv->transition_animation,
new_theme_node);
}
- else if (old_theme_node)
+ else if (old_theme_node && !paint_equal)
{
+ /* Since our transitions are only of the painting done by StThemeNode, we
+ * only want to start a transition when what is painted changes; if
+ * other visual aspects like the foreground color of a label change,
+ * we can't animate that anyways.
+ */
+
widget->priv->transition_animation =
st_theme_node_transition_new (old_theme_node,
new_theme_node,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]