snapshot: Change how gtk_snapshot_push/pop works

Instead of appending a container node and adding the nodes to it as they
come in, we now collect the nodes until gtk_snapshot_pop() is called and
then hand them out in a container node.

The caller of gtk_snapshot_push() is then responsible for doing whatever
he wants with the created node.

Another addigion is the keep_coordinates flag to gtk_snapshot_push()
which allows callers to keep the current offset and clip region or
discard it. Discarding is useful when doing transforms, keeping it is
useful when inserting effect nodes (like the ones I'm about to add).
This commit is contained in:
Benjamin Otte 2016-12-13 02:33:15 +01:00
parent ca80e9decf
commit 02131d590e
7 changed files with 112 additions and 109 deletions

View File

@ -38,7 +38,6 @@ gsk_texture_node_new
gsk_cairo_node_new
gsk_cairo_node_get_draw_context
gsk_container_node_new
gsk_container_node_append_child
gsk_container_node_get_n_children
gsk_container_node_get_child
gsk_transform_node_new

View File

@ -55,15 +55,13 @@ cairo_t * gsk_cairo_node_get_draw_context (GskRenderNode
GskRenderer *renderer);
GDK_AVAILABLE_IN_3_90
GskRenderNode * gsk_container_node_new (void);
GskRenderNode * gsk_container_node_new (GskRenderNode **children,
guint n_children);
GDK_AVAILABLE_IN_3_90
GskRenderNode * gsk_container_node_append_child (GskRenderNode *node,
GskRenderNode *child);
guint gsk_container_node_get_n_children (GskRenderNode *node);
GDK_AVAILABLE_IN_3_90
guint gsk_container_node_get_n_children (GskRenderNode *node);
GDK_AVAILABLE_IN_3_90
GskRenderNode * gsk_container_node_get_child (GskRenderNode *node,
guint idx);
GskRenderNode * gsk_container_node_get_child (GskRenderNode *node,
guint idx);
GDK_AVAILABLE_IN_3_90
GskRenderNode * gsk_transform_node_new (GskRenderNode *child,

View File

@ -285,15 +285,20 @@ struct _GskContainerNode
{
GskRenderNode render_node;
GPtrArray *children;
GskRenderNode **children;
guint n_children;
};
static void
gsk_container_node_finalize (GskRenderNode *node)
{
GskContainerNode *container = (GskContainerNode *) node;
guint i;
g_ptr_array_unref (container->children);
for (i = 0; i < container->n_children; i++)
gsk_render_node_unref (container->children[i]);
g_free (container->children);
}
static void
@ -302,9 +307,9 @@ gsk_container_node_make_immutable (GskRenderNode *node)
GskContainerNode *container = (GskContainerNode *) node;
guint i;
for (i = 1; i < container->children->len; i++)
for (i = 1; i < container->n_children; i++)
{
gsk_render_node_make_immutable (g_ptr_array_index (container->children, i));
gsk_render_node_make_immutable (container->children[i]);
}
}
@ -343,55 +348,34 @@ static const GskRenderNodeClass GSK_CONTAINER_NODE_CLASS = {
/**
* gsk_container_node_new:
* @children: (array length=n_children) (transfer none): The children of the node
* @n_children: Number of children in the @children array
*
* Creates a new #GskRenderNode instance for holding multiple different
* render nodes. You can use gsk_container_node_append_child() to add
* nodes to the container.
* Creates a new #GskRenderNode instance for holding the given @children.
* The new node will acquire a reference to each of the children.
*
* Returns: (transfer full): the new #GskRenderNode
*
* Since: 3.90
*/
GskRenderNode *
gsk_container_node_new (void)
gsk_container_node_new (GskRenderNode **children,
guint n_children)
{
GskContainerNode *container;
guint i;
container = (GskContainerNode *) gsk_render_node_new (&GSK_CONTAINER_NODE_CLASS);
container->children = g_ptr_array_new_with_free_func ((GDestroyNotify) gsk_render_node_unref);
container->children = g_memdup (children, sizeof (GskRenderNode *) * n_children);
container->n_children = n_children;
for (i = 0; i < container->n_children; i++)
gsk_render_node_ref (container->children[i]);
return &container->render_node;
}
/**
* gsk_container_node_append_child:
* @node: a container node
* @child: a #GskRenderNode
*
* Appends @child to the list of children of @node.
*
* This function acquires a reference on @child.
*
* Returns: (transfer none): the #GskRenderNode
*
* Since: 3.90
*/
GskRenderNode *
gsk_container_node_append_child (GskRenderNode *node,
GskRenderNode *child)
{
GskContainerNode *container = (GskContainerNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_CONTAINER_NODE), NULL);
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), node);
g_return_val_if_fail (node->is_mutable, node);
g_ptr_array_add (container->children, gsk_render_node_ref (child));
return node;
}
/**
* gsk_container_node_get_n_children:
* @node: a container #GskRenderNode
@ -409,7 +393,7 @@ gsk_container_node_get_n_children (GskRenderNode *node)
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_CONTAINER_NODE), 0);
return container->children->len;
return container->n_children;
}
GskRenderNode *
@ -419,9 +403,9 @@ gsk_container_node_get_child (GskRenderNode *node,
GskContainerNode *container = (GskContainerNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_CONTAINER_NODE), NULL);
g_return_val_if_fail (idx < container->children->len, 0);
g_return_val_if_fail (idx < container->n_children, 0);
return g_ptr_array_index (container->children, idx);
return container->children[idx];
}
/*** GSK_TRANSFORM_NODE ***/

View File

@ -126,7 +126,7 @@ gtk_css_style_snapshot_icon (GtkCssStyle *style,
else
{
graphene_matrix_t m1, m2, m3;
GskRenderNode *transform_node, *container_node;
GskRenderNode *transform_node, *icon_node;
double offset_x, offset_y;
gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y);
@ -136,15 +136,16 @@ gtk_css_style_snapshot_icon (GtkCssStyle *style,
graphene_matrix_init_translate (&m2, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0));
graphene_matrix_multiply (&m2, &m3, &m1);
container_node = gsk_container_node_new ();
gsk_render_node_set_name (container_node, "CSS Icon Transform Container");
transform_node = gsk_transform_node_new (container_node, &m1);
gtk_snapshot_push (snapshot, FALSE, "CSS Icon Transform Container");
gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
icon_node = gtk_snapshot_pop (snapshot);
transform_node = gsk_transform_node_new (icon_node, &m1);
gsk_render_node_set_name (transform_node, "CSS Icon Transform");
gtk_snapshot_append_node (snapshot, transform_node);
gtk_snapshot_push_node (snapshot, container_node);
gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
gtk_snapshot_pop (snapshot);
gsk_render_node_unref (transform_node);
gsk_render_node_unref (icon_node);
}
}

View File

@ -50,15 +50,21 @@
static GtkSnapshotState *
gtk_snapshot_state_new (GtkSnapshotState *parent,
char *name,
cairo_region_t *clip,
GskRenderNode *node)
double translate_x,
double translate_y)
{
GtkSnapshotState *state;
state = g_slice_new0 (GtkSnapshotState);
state->node = node;
state->nodes = g_ptr_array_new_with_free_func ((GDestroyNotify) gsk_render_node_unref);
state->parent = parent;
state->name = name;
state->translate_x = translate_x;
state->translate_y = translate_y;
if (clip)
state->clip_region = cairo_region_reference (clip);
@ -68,9 +74,13 @@ gtk_snapshot_state_new (GtkSnapshotState *parent,
static void
gtk_snapshot_state_free (GtkSnapshotState *state)
{
g_ptr_array_unref (state->nodes);
if (state->clip_region)
cairo_region_destroy (state->clip_region);
g_free (state->name);
g_slice_free (GtkSnapshotState, state);
}
@ -81,66 +91,49 @@ gtk_snapshot_init (GtkSnapshot *snapshot,
const char *name,
...)
{
cairo_rectangle_int_t extents;
cairo_region_get_extents (clip, &extents);
char *str;
snapshot->state = NULL;
snapshot->renderer = renderer;
snapshot->root = gsk_container_node_new ();
if (name)
{
va_list args;
char *str;
va_start (args, name);
str = g_strdup_vprintf (name, args);
va_end (args);
gsk_render_node_set_name (snapshot->root, str);
g_free (str);
}
else
str = NULL;
snapshot->state = gtk_snapshot_state_new (NULL, (cairo_region_t *) clip, snapshot->root);
snapshot->state = gtk_snapshot_state_new (NULL,
str,
(cairo_region_t *) clip,
0, 0);
}
GskRenderNode *
gtk_snapshot_finish (GtkSnapshot *snapshot)
{
gtk_snapshot_pop (snapshot);
GskRenderNode *result;
result = gtk_snapshot_pop (snapshot);
if (snapshot->state != NULL)
{
g_warning ("Too many gtk_snapshot_push() calls.");
}
return snapshot->root;
}
/**
* gtk_snapshot_push_node:
* @snapshot: a #GtkSnapshot
* @node: the render node to push
*
* Makes @node the new current render node. You are responsible for adding
* @node to the snapshot.
*
* Since: 3.90
*/
void
gtk_snapshot_push_node (GtkSnapshot *snapshot,
GskRenderNode *node)
{
g_return_if_fail (gsk_render_node_get_node_type (node) == GSK_CONTAINER_NODE);
snapshot->state = gtk_snapshot_state_new (snapshot->state, snapshot->state->clip_region, node);
return result;
}
/**
* gtk_snapshot_push:
* @snapshot: a #GtkSnapshot
* @keep_coordinates: If %TRUE, the current offset and clip will be kept.
* Otherwise, the clip will be unset and the offset will be reset to
* (0, 0).
* @bounds: the bounds for the new node
* @name: (transfer none): a printf() style format string for the name for the new node
* @...: arguments to insert into the format string
@ -152,30 +145,38 @@ gtk_snapshot_push_node (GtkSnapshot *snapshot,
*/
void
gtk_snapshot_push (GtkSnapshot *snapshot,
gboolean keep_coordinates,
const char *name,
...)
{
GskRenderNode *node;
node = gsk_container_node_new ();
char *str;
if (name)
{
va_list args;
char *str;
va_start (args, name);
str = g_strdup_vprintf (name, args);
va_end (args);
gsk_render_node_set_name (node, str);
g_free (str);
}
else
str = NULL;
gtk_snapshot_append_node (snapshot, node);
gtk_snapshot_push_node (snapshot, node);
gsk_render_node_unref (node);
if (keep_coordinates)
{
snapshot->state = gtk_snapshot_state_new (snapshot->state,
str,
snapshot->state->clip_region,
snapshot->state->translate_x,
snapshot->state->translate_y);
}
else
{
snapshot->state = gtk_snapshot_state_new (snapshot->state,
str,
NULL,
0, 0);
}
}
/**
@ -185,23 +186,45 @@ gtk_snapshot_push (GtkSnapshot *snapshot,
* Removes the top element from the stack of render nodes,
* making the node underneath the current node again.
*
* Returns: (transfer full) (allow none): A #GskRenderNode for
* the contents that were rendered to @snapshot since
* the corresponding gtk_snapshot_push() call
*
* Since: 3.90
*/
void
GskRenderNode *
gtk_snapshot_pop (GtkSnapshot *snapshot)
{
GtkSnapshotState *state;
GskRenderNode *node;
if (snapshot->state == NULL)
{
g_warning ("Too many gtk_snapshot_pop() calls.");
return;
return NULL;
}
state = snapshot->state;
snapshot->state = state->parent;
if (state->nodes->len == 0)
{
node = NULL;
}
else if (state->nodes->len == 1)
{
node = gsk_render_node_ref (g_ptr_array_index (state->nodes, 0));
}
else
{
node = gsk_container_node_new ((GskRenderNode **) state->nodes->pdata,
state->nodes->len);
gsk_render_node_set_name (node, state->name);
}
gtk_snapshot_state_free (state);
return node;
}
/**
@ -288,7 +311,7 @@ gtk_snapshot_append_node (GtkSnapshot *snapshot,
if (snapshot->state)
{
gsk_container_node_append_child (snapshot->state->node, node);
g_ptr_array_add (snapshot->state->nodes, gsk_render_node_ref (node));
}
else
{

View File

@ -41,13 +41,11 @@ GskRenderer * gtk_snapshot_get_renderer (const GtkSnapshot
GDK_AVAILABLE_IN_3_90
void gtk_snapshot_push (GtkSnapshot *snapshot,
gboolean keep_coordinates,
const char *name,
...) G_GNUC_PRINTF(2, 3);
...) G_GNUC_PRINTF (3, 4);
GDK_AVAILABLE_IN_3_90
void gtk_snapshot_push_node (GtkSnapshot *snapshot,
GskRenderNode *node);
GDK_AVAILABLE_IN_3_90
void gtk_snapshot_pop (GtkSnapshot *snapshot);
GskRenderNode * gtk_snapshot_pop (GtkSnapshot *snapshot) G_GNUC_WARN_UNUSED_RESULT;
GDK_AVAILABLE_IN_3_90
void gtk_snapshot_translate_2d (GtkSnapshot *snapshot,

View File

@ -27,7 +27,8 @@ typedef struct _GtkSnapshotState GtkSnapshotState;
struct _GtkSnapshotState {
GtkSnapshotState *parent;
GskRenderNode *node;
char *name;
GPtrArray *nodes;
cairo_region_t *clip_region;
double translate_x;
@ -37,7 +38,6 @@ struct _GtkSnapshotState {
struct _GtkSnapshot {
GtkSnapshotState *state;
GskRenderNode *root;
GskRenderer *renderer;
};