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
This commit is contained in:
parent
b9f9dd948a
commit
5e7c25e136
@ -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);
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -77,6 +77,37 @@ st_shadow_free (StShadow *shadow)
|
||||
g_slice_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
|
||||
@ -105,7 +136,6 @@ st_shadow_get_box (StShadow *shadow,
|
||||
+ shadow->blur + shadow->spread;
|
||||
}
|
||||
|
||||
|
||||
GType
|
||||
st_shadow_get_type (void)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user