diff --git a/src/st/st-theme-node-drawing.c b/src/st/st-theme-node-drawing.c index 70d963781..3250536e6 100644 --- a/src/st/st-theme-node-drawing.c +++ b/src/st/st-theme-node-drawing.c @@ -1269,53 +1269,6 @@ st_theme_node_prerender_background (StThemeNode *node, return texture; } -void -_st_theme_node_paint_state_free (StThemeNodePaintState *state) -{ - int corner_id; - - if (state->background_texture != COGL_INVALID_HANDLE) - cogl_handle_unref (state->background_texture); - if (state->background_material != COGL_INVALID_HANDLE) - cogl_handle_unref (state->background_material); - if (state->background_shadow_material != COGL_INVALID_HANDLE) - cogl_handle_unref (state->background_shadow_material); - if (state->border_slices_texture != COGL_INVALID_HANDLE) - cogl_handle_unref (state->border_slices_texture); - if (state->border_slices_material != COGL_INVALID_HANDLE) - cogl_handle_unref (state->border_slices_material); - if (state->prerendered_texture != COGL_INVALID_HANDLE) - cogl_handle_unref (state->prerendered_texture); - if (state->prerendered_material != COGL_INVALID_HANDLE) - cogl_handle_unref (state->prerendered_material); - if (state->box_shadow_material != COGL_INVALID_HANDLE) - cogl_handle_unref (state->box_shadow_material); - - for (corner_id = 0; corner_id < 4; corner_id++) - if (state->corner_material[corner_id] != COGL_INVALID_HANDLE) - cogl_handle_unref (state->corner_material[corner_id]); - - _st_theme_node_paint_state_init (state); -} - -void -_st_theme_node_paint_state_init (StThemeNodePaintState *state) -{ - int corner_id; - - state->background_texture = COGL_INVALID_HANDLE; - state->background_material = COGL_INVALID_HANDLE; - state->background_shadow_material = COGL_INVALID_HANDLE; - state->box_shadow_material = COGL_INVALID_HANDLE; - state->border_slices_texture = COGL_INVALID_HANDLE; - state->border_slices_material = COGL_INVALID_HANDLE; - state->prerendered_texture = COGL_INVALID_HANDLE; - state->prerendered_material = COGL_INVALID_HANDLE; - - for (corner_id = 0; corner_id < 4; corner_id++) - state->corner_material[corner_id] = COGL_INVALID_HANDLE; -} - static void st_theme_node_paint_borders (StThemeNode *node, StThemeNodePaintState *state, const ClutterActorBox *box, @@ -1345,7 +1298,7 @@ st_theme_node_render_resources (StThemeNode *node, * geometry change versus things that can be cached regardless, such as * a background image. */ - _st_theme_node_paint_state_free (state); + st_theme_node_paint_state_free (state); state->alloc_width = width; state->alloc_height = height; @@ -1939,12 +1892,12 @@ st_theme_node_paint_outline (StThemeNode *node, void st_theme_node_paint (StThemeNode *node, + StThemeNodePaintState *state, const ClutterActorBox *box, guint8 paint_opacity) { float width, height; ClutterActorBox allocation; - StThemeNodePaintState *state = &node->state; /* Some things take an ActorBox, some things just width/height */ width = box->x2 - box->x1; @@ -2064,7 +2017,54 @@ st_theme_node_paint (StThemeNode *node, } } -static void +void +st_theme_node_paint_state_free (StThemeNodePaintState *state) +{ + int corner_id; + + if (state->background_texture != COGL_INVALID_HANDLE) + cogl_handle_unref (state->background_texture); + if (state->background_material != COGL_INVALID_HANDLE) + cogl_handle_unref (state->background_material); + if (state->background_shadow_material != COGL_INVALID_HANDLE) + cogl_handle_unref (state->background_shadow_material); + if (state->border_slices_texture != COGL_INVALID_HANDLE) + cogl_handle_unref (state->border_slices_texture); + if (state->border_slices_material != COGL_INVALID_HANDLE) + cogl_handle_unref (state->border_slices_material); + if (state->prerendered_texture != COGL_INVALID_HANDLE) + cogl_handle_unref (state->prerendered_texture); + if (state->prerendered_material != COGL_INVALID_HANDLE) + cogl_handle_unref (state->prerendered_material); + if (state->box_shadow_material != COGL_INVALID_HANDLE) + cogl_handle_unref (state->box_shadow_material); + + for (corner_id = 0; corner_id < 4; corner_id++) + if (state->corner_material[corner_id] != COGL_INVALID_HANDLE) + cogl_handle_unref (state->corner_material[corner_id]); + + st_theme_node_paint_state_init (state); +} + +void +st_theme_node_paint_state_init (StThemeNodePaintState *state) +{ + int corner_id; + + state->background_texture = COGL_INVALID_HANDLE; + state->background_material = COGL_INVALID_HANDLE; + state->background_shadow_material = COGL_INVALID_HANDLE; + state->box_shadow_material = COGL_INVALID_HANDLE; + state->border_slices_texture = COGL_INVALID_HANDLE; + state->border_slices_material = COGL_INVALID_HANDLE; + state->prerendered_texture = COGL_INVALID_HANDLE; + state->prerendered_material = COGL_INVALID_HANDLE; + + for (corner_id = 0; corner_id < 4; corner_id++) + state->corner_material[corner_id] = COGL_INVALID_HANDLE; +} + +void st_theme_node_paint_state_copy (StThemeNodePaintState *state, StThemeNodePaintState *other) { @@ -2073,10 +2073,7 @@ st_theme_node_paint_state_copy (StThemeNodePaintState *state, if (state == other) return; - /* Check omitted for speed: */ - /* g_return_if_fail (st_theme_node_paint_equal (node, other)); */ - - _st_theme_node_paint_state_free (state); + st_theme_node_paint_state_free (state); state->alloc_width = other->alloc_width; state->alloc_height = other->alloc_height; @@ -2102,33 +2099,9 @@ st_theme_node_paint_state_copy (StThemeNodePaintState *state, state->corner_material[corner_id] = cogl_handle_ref (other->corner_material[corner_id]); } -/** - * 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) -{ - st_theme_node_paint_state_copy (&node->state, - &other->state); -} - -static void st_theme_node_paint_state_invalidate (StThemeNodePaintState *state) { state->alloc_width = 0; state->alloc_height = 0; } - -void -st_theme_node_invalidate_paint_state (StThemeNode *node) -{ - st_theme_node_paint_state_invalidate (&node->state); -} diff --git a/src/st/st-theme-node-private.h b/src/st/st-theme-node-private.h index e90835ee6..0da4edb66 100644 --- a/src/st/st-theme-node-private.h +++ b/src/st/st-theme-node-private.h @@ -29,23 +29,6 @@ G_BEGIN_DECLS -typedef struct _StThemeNodePaintState StThemeNodePaintState; - -struct _StThemeNodePaintState { - float alloc_width; - float alloc_height; - - CoglHandle background_texture; - CoglHandle background_material; - CoglHandle border_slices_texture; - CoglHandle border_slices_material; - CoglHandle background_shadow_material; - CoglHandle box_shadow_material; - CoglHandle prerendered_texture; - CoglHandle prerendered_material; - CoglHandle corner_material[4]; -}; - struct _StThemeNode { GObject parent; @@ -116,8 +99,6 @@ struct _StThemeNode { guint background_image_shadow_computed : 1; guint text_shadow_computed : 1; guint link_type : 2; - - StThemeNodePaintState state; }; struct _StThemeNodeClass { @@ -128,9 +109,6 @@ struct _StThemeNodeClass { void _st_theme_node_ensure_background (StThemeNode *node); void _st_theme_node_ensure_geometry (StThemeNode *node); -void _st_theme_node_paint_state_init (StThemeNodePaintState *state); -void _st_theme_node_paint_state_free (StThemeNodePaintState *state); - G_END_DECLS #endif /* __ST_THEME_NODE_PRIVATE_H__ */ diff --git a/src/st/st-theme-node-transition.c b/src/st/st-theme-node-transition.c index 9e565c8b1..c4b6ea15d 100644 --- a/src/st/st-theme-node-transition.c +++ b/src/st/st-theme-node-transition.c @@ -33,6 +33,9 @@ struct _StThemeNodeTransitionPrivate { StThemeNode *old_theme_node; StThemeNode *new_theme_node; + StThemeNodePaintState old_paint_state; + StThemeNodePaintState new_paint_state; + CoglHandle old_texture; CoglHandle new_texture; @@ -75,6 +78,7 @@ on_timeline_new_frame (ClutterTimeline *timeline, StThemeNodeTransition * st_theme_node_transition_new (StThemeNode *from_node, StThemeNode *to_node, + StThemeNodePaintState *old_paint_state, guint duration) { StThemeNodeTransition *transition; @@ -90,6 +94,9 @@ st_theme_node_transition_new (StThemeNode *from_node, transition->priv->old_theme_node = g_object_ref (from_node); transition->priv->new_theme_node = g_object_ref (to_node); + st_theme_node_paint_state_copy (&transition->priv->old_paint_state, + old_paint_state); + transition->priv->timeline = clutter_timeline_new (duration); transition->priv->timeline_completed_id = @@ -106,6 +113,12 @@ st_theme_node_transition_new (StThemeNode *from_node, return transition; } +StThemeNodePaintState * +st_theme_node_transition_get_new_paint_state (StThemeNodeTransition *transition) +{ + return &transition->priv->new_paint_state; +} + void st_theme_node_transition_update (StThemeNodeTransition *transition, StThemeNode *new_node) @@ -134,6 +147,12 @@ st_theme_node_transition_update (StThemeNodeTransition *transition, */ if (st_theme_node_equal (new_node, old_node)) { + { + StThemeNodePaintState tmp = priv->old_paint_state; + priv->old_paint_state = priv->new_paint_state; + priv->new_paint_state = tmp; + } + if (clutter_timeline_get_elapsed_time (priv->timeline) > 0) { if (direction == CLUTTER_TIMELINE_FORWARD) @@ -162,15 +181,10 @@ st_theme_node_transition_update (StThemeNodeTransition *transition, 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); + + st_theme_node_paint_state_invalidate (&priv->new_paint_state); } } } @@ -285,7 +299,7 @@ setup_framebuffers (StThemeNodeTransition *transition, cogl_ortho (priv->offscreen_box.x1, priv->offscreen_box.x2, priv->offscreen_box.y2, priv->offscreen_box.y1, 0.0, 1.0); - st_theme_node_paint (priv->old_theme_node, allocation, 255); + st_theme_node_paint (priv->old_theme_node, &priv->old_paint_state, allocation, 255); cogl_pop_framebuffer (); cogl_push_framebuffer (priv->new_offscreen); @@ -293,7 +307,7 @@ setup_framebuffers (StThemeNodeTransition *transition, cogl_ortho (priv->offscreen_box.x1, priv->offscreen_box.x2, priv->offscreen_box.y2, priv->offscreen_box.y1, 0.0, 1.0); - st_theme_node_paint (priv->new_theme_node, allocation, 255); + st_theme_node_paint (priv->new_theme_node, &priv->new_paint_state, allocation, 255); cogl_pop_framebuffer (); return TRUE; @@ -408,6 +422,9 @@ st_theme_node_transition_dispose (GObject *object) priv->timeline_completed_id = 0; priv->timeline_new_frame_id = 0; + st_theme_node_paint_state_free (&priv->old_paint_state); + st_theme_node_paint_state_free (&priv->new_paint_state); + G_OBJECT_CLASS (st_theme_node_transition_parent_class)->dispose (object); } @@ -425,6 +442,9 @@ st_theme_node_transition_init (StThemeNodeTransition *transition) transition->priv->old_offscreen = NULL; transition->priv->new_offscreen = NULL; + st_theme_node_paint_state_init (&transition->priv->old_paint_state); + st_theme_node_paint_state_init (&transition->priv->new_paint_state); + transition->priv->needs_setup = TRUE; } diff --git a/src/st/st-theme-node-transition.h b/src/st/st-theme-node-transition.h index d6fd9358a..e78389e45 100644 --- a/src/st/st-theme-node-transition.h +++ b/src/st/st-theme-node-transition.h @@ -56,6 +56,7 @@ GType st_theme_node_transition_get_type (void) G_GNUC_CONST; StThemeNodeTransition *st_theme_node_transition_new (StThemeNode *from_node, StThemeNode *to_node, + StThemeNodePaintState *old_paint_state, guint duration); void st_theme_node_transition_update (StThemeNodeTransition *transition, @@ -69,6 +70,8 @@ void st_theme_node_transition_get_paint_box (StThemeNodeTransition *transition, const ClutterActorBox *allocation, ClutterActorBox *paint_box); +StThemeNodePaintState * st_theme_node_transition_get_new_paint_state (StThemeNodeTransition *transition); + G_END_DECLS #endif diff --git a/src/st/st-theme-node.c b/src/st/st-theme-node.c index 91e8f0927..ff712dcee 100644 --- a/src/st/st-theme-node.c +++ b/src/st/st-theme-node.c @@ -49,7 +49,6 @@ static void st_theme_node_init (StThemeNode *node) { node->transition_duration = -1; - _st_theme_node_paint_state_init (&node->state); } static void @@ -152,8 +151,6 @@ st_theme_node_finalize (GObject *object) if (node->background_image) g_free (node->background_image); - _st_theme_node_paint_state_free (&node->state); - G_OBJECT_CLASS (st_theme_node_parent_class)->finalize (object); } diff --git a/src/st/st-theme-node.h b/src/st/st-theme-node.h index 4a5f58c46..9593bde6f 100644 --- a/src/st/st-theme-node.h +++ b/src/st/st-theme-node.h @@ -94,6 +94,23 @@ typedef enum { ST_GRADIENT_RADIAL } StGradientType; +typedef struct _StThemeNodePaintState StThemeNodePaintState; + +struct _StThemeNodePaintState { + float alloc_width; + float alloc_height; + + CoglHandle background_texture; + CoglHandle background_material; + CoglHandle border_slices_texture; + CoglHandle border_slices_material; + CoglHandle background_shadow_material; + CoglHandle box_shadow_material; + CoglHandle prerendered_texture; + CoglHandle prerendered_material; + CoglHandle corner_material[4]; +}; + GType st_theme_node_get_type (void) G_GNUC_CONST; StThemeNode *st_theme_node_new (StThemeContext *context, @@ -250,12 +267,15 @@ gboolean st_theme_node_paint_equal (StThemeNode *node, StThemeNode *other); void st_theme_node_paint (StThemeNode *node, + StThemeNodePaintState *state, const ClutterActorBox *box, guint8 paint_opacity); -void st_theme_node_copy_cached_paint_state (StThemeNode *node, - StThemeNode *other); -void st_theme_node_invalidate_paint_state (StThemeNode *node); +void st_theme_node_paint_state_init (StThemeNodePaintState *state); +void st_theme_node_paint_state_free (StThemeNodePaintState *state); +void st_theme_node_paint_state_copy (StThemeNodePaintState *state, + StThemeNodePaintState *other); +void st_theme_node_paint_state_invalidate (StThemeNodePaintState *node); G_END_DECLS diff --git a/src/st/st-widget.c b/src/st/st-widget.c index 7133e8561..737b3e875 100644 --- a/src/st/st-widget.c +++ b/src/st/st-widget.c @@ -79,6 +79,8 @@ struct _StWidgetPrivate * that we can remove the pseudo classes on them. */ StWidget *prev_last_child; StWidget *prev_first_child; + + StThemeNodePaintState paint_state; }; /** @@ -296,7 +298,7 @@ st_widget_texture_cache_changed (StTextureCache *cache, if (!changed) return; - st_theme_node_invalidate_paint_state (node); + st_theme_node_paint_state_invalidate (&actor->priv->paint_state); if (CLUTTER_ACTOR_IS_MAPPED (CLUTTER_ACTOR (actor))) clutter_actor_queue_redraw (CLUTTER_ACTOR (actor)); @@ -355,6 +357,8 @@ st_widget_finalize (GObject *gobject) g_free (priv->accessible_name); g_free (priv->inline_style); + st_theme_node_paint_state_free (&priv->paint_state); + G_OBJECT_CLASS (st_widget_parent_class)->finalize (gobject); } @@ -441,7 +445,10 @@ st_widget_paint_background (StWidget *widget) &allocation, opacity); else - st_theme_node_paint (theme_node, &allocation, opacity); + st_theme_node_paint (theme_node, + &widget->priv->paint_state, + &allocation, + opacity); } static void @@ -1517,12 +1524,17 @@ st_widget_init (StWidget *actor) g_signal_connect (actor, "notify::last-child", G_CALLBACK (st_widget_last_child_notify), NULL); g_signal_connect (st_texture_cache_get_default (), "texture-file-changed", G_CALLBACK (st_widget_texture_cache_changed), actor); + + st_theme_node_paint_state_init (&priv->paint_state); } static void on_transition_completed (StThemeNodeTransition *transition, StWidget *widget) { + st_theme_node_paint_state_copy (&widget->priv->paint_state, + st_theme_node_transition_get_new_paint_state (transition)); + st_widget_remove_transition (widget); } @@ -1549,9 +1561,6 @@ st_widget_recompute_style (StWidget *widget, 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); - g_object_get (gtk_settings_get_default (), "gtk-enable-animations", &animations_enabled, NULL); @@ -1574,6 +1583,7 @@ st_widget_recompute_style (StWidget *widget, widget->priv->transition_animation = st_theme_node_transition_new (old_theme_node, new_theme_node, + &widget->priv->paint_state, transition_duration); g_signal_connect (widget->priv->transition_animation, "completed", @@ -1589,6 +1599,9 @@ st_widget_recompute_style (StWidget *widget, st_widget_remove_transition (widget); } + if (!paint_equal) + st_theme_node_paint_state_invalidate (&widget->priv->paint_state); + g_signal_emit (widget, signals[STYLE_CHANGED], 0); widget->priv->is_style_dirty = FALSE; }