gsk: Add support for rounded clip rectangles

Also add support to GtkSnapshot, so people can push rounded clips.
This commit is contained in:
Benjamin Otte 2016-12-13 21:59:28 +01:00
parent f96f16899d
commit 23e35706b4
8 changed files with 213 additions and 0 deletions

View File

@ -47,6 +47,8 @@ gsk_opacity_node_new
gsk_opacity_node_get_child
gsk_clip_node_new
gsk_clip_node_get_child
gsk_rounded_clip_node_new
gsk_rounded_clip_node_get_child
<SUBSECTION Standard>
GSK_IS_RENDER_NODE
GSK_RENDER_NODE

View File

@ -4457,6 +4457,7 @@ gtk_snapshot_push
gtk_snapshot_push_node
gtk_snapshot_push_transform
gtk_snapshot_push_clip
gtk_snapshot_push_rounded_clip
gtk_snapshot_pop
gtk_snapshot_pop_and_append
gtk_snapshot_set_transform

View File

@ -23,6 +23,7 @@
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gskroundedrect.h>
#include <gsk/gsktypes.h>
G_BEGIN_DECLS
@ -85,6 +86,12 @@ GskRenderNode * gsk_clip_node_new (GskRenderNode
GDK_AVAILABLE_IN_3_90
GskRenderNode * gsk_clip_node_get_child (GskRenderNode *node);
GDK_AVAILABLE_IN_3_90
GskRenderNode * gsk_rounded_clip_node_new (GskRenderNode *child,
const GskRoundedRect *clip);
GDK_AVAILABLE_IN_3_90
GskRenderNode * gsk_rounded_clip_node_get_child (GskRenderNode *node);
GDK_AVAILABLE_IN_3_90
void gsk_render_node_set_blend_mode (GskRenderNode *node,
GskBlendMode blend_mode);

View File

@ -20,6 +20,7 @@
#include "gskdebugprivate.h"
#include "gskrendererprivate.h"
#include "gskroundedrectprivate.h"
#include "gsktextureprivate.h"
/*** GSK_COLOR_NODE ***/
@ -944,3 +945,126 @@ gsk_clip_node_peek_clip (GskRenderNode *node)
return &self->clip;
}
/*** GSK_ROUNDED_CLIP_NODE ***/
typedef struct _GskRoundedClipNode GskRoundedClipNode;
struct _GskRoundedClipNode
{
GskRenderNode render_node;
GskRenderNode *child;
GskRoundedRect clip;
};
static void
gsk_rounded_clip_node_finalize (GskRenderNode *node)
{
GskRoundedClipNode *self = (GskRoundedClipNode *) node;
gsk_render_node_unref (self->child);
}
static void
gsk_rounded_clip_node_make_immutable (GskRenderNode *node)
{
GskRoundedClipNode *self = (GskRoundedClipNode *) node;
gsk_render_node_make_immutable (self->child);
}
static void
gsk_rounded_clip_node_draw (GskRenderNode *node,
cairo_t *cr)
{
GskRoundedClipNode *self = (GskRoundedClipNode *) node;
cairo_save (cr);
gsk_rounded_rect_path (&self->clip, cr);
cairo_clip (cr);
gsk_render_node_draw (self->child, cr);
cairo_restore (cr);
}
static void
gsk_rounded_clip_node_get_bounds (GskRenderNode *node,
graphene_rect_t *bounds)
{
GskRoundedClipNode *self = (GskRoundedClipNode *) node;
graphene_rect_t child_bounds;
gsk_render_node_get_bounds (self->child, &child_bounds);
graphene_rect_intersection (&self->clip.bounds, &child_bounds, bounds);
}
static const GskRenderNodeClass GSK_ROUNDED_CLIP_NODE_CLASS = {
GSK_ROUNDED_CLIP_NODE,
sizeof (GskRoundedClipNode),
"GskRoundedClipNode",
gsk_rounded_clip_node_finalize,
gsk_rounded_clip_node_make_immutable,
gsk_rounded_clip_node_draw,
gsk_rounded_clip_node_get_bounds
};
/**
* gsk_rounded_clip_node_new:
* @child: The node to draw
* @clip: The clip to apply
*
* Creates a #GskRenderNode that will clip the @child to the area
* given by @clip.
*
* Returns: A new #GskRenderNode
*
* Since: 3.90
*/
GskRenderNode *
gsk_rounded_clip_node_new (GskRenderNode *child,
const GskRoundedRect *clip)
{
GskRoundedClipNode *self;
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
g_return_val_if_fail (clip != NULL, NULL);
self = (GskRoundedClipNode *) gsk_render_node_new (&GSK_ROUNDED_CLIP_NODE_CLASS);
self->child = gsk_render_node_ref (child);
gsk_rounded_rect_init_copy (&self->clip, clip);
return &self->render_node;
}
/**
* gsk_rounded_clip_node_get_child:
* @node: a clip @GskRenderNode
*
* Gets the child node that is getting clipped by the given @node.
*
* Returns: (transfer none): The child that is getting clipped
**/
GskRenderNode *
gsk_rounded_clip_node_get_child (GskRenderNode *node)
{
GskRoundedClipNode *self = (GskRoundedClipNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_ROUNDED_CLIP_NODE), NULL);
return self->child;
}
const GskRoundedRect *
gsk_rounded_clip_node_peek_clip (GskRenderNode *node)
{
GskRoundedClipNode *self = (GskRoundedClipNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_ROUNDED_CLIP_NODE), NULL);
return &self->clip;
}

View File

@ -62,6 +62,8 @@ const GdkRGBA *gsk_color_node_peek_color (GskRenderNode *node);
const graphene_rect_t * gsk_clip_node_peek_clip (GskRenderNode *node);
const GskRoundedRect * gsk_rounded_clip_node_peek_clip (GskRenderNode *node);
void gsk_transform_node_get_transform (GskRenderNode *node, graphene_matrix_t *transform);
GskBlendMode gsk_render_node_get_blend_mode (GskRenderNode *node);

View File

@ -352,6 +352,74 @@ gtk_snapshot_push_clip (GtkSnapshot *snapshot,
cairo_region_destroy (clip);
}
static GskRenderNode *
gtk_snapshot_collect_rounded_clip (GskRenderNode **nodes,
guint n_nodes,
const char *name,
gpointer bounds)
{
GskRenderNode *node, *clip_node;
node = gtk_snapshot_collect_default (nodes, n_nodes, name, NULL);
if (node == NULL)
return NULL;
clip_node = gsk_rounded_clip_node_new (node, bounds);
gsk_render_node_set_name (clip_node, name);
gsk_render_node_unref (node);
g_slice_free (GskRoundedRect, bounds);
return clip_node;
}
void
gtk_snapshot_push_rounded_clip (GtkSnapshot *snapshot,
const GskRoundedRect *bounds,
const char *name,
...)
{
GskRoundedRect *real_bounds;
cairo_region_t *clip;
cairo_rectangle_int_t rect;
char *str;
real_bounds = g_slice_new (GskRoundedRect);
gsk_rounded_rect_init_copy (real_bounds, bounds);
gsk_rounded_rect_offset (real_bounds, snapshot->state->translate_x, snapshot->state->translate_y);
if (name)
{
va_list args;
va_start (args, name);
str = g_strdup_vprintf (name, args);
va_end (args);
}
else
str = NULL;
rectangle_init_from_graphene (&rect, &real_bounds->bounds);
if (snapshot->state->clip_region)
{
clip = cairo_region_copy (snapshot->state->clip_region);
cairo_region_intersect_rectangle (clip, &rect);
}
else
{
clip = cairo_region_create_rectangle (&rect);
}
snapshot->state = gtk_snapshot_state_new (snapshot->state,
str,
clip,
snapshot->state->translate_x,
snapshot->state->translate_y,
gtk_snapshot_collect_rounded_clip,
real_bounds);
cairo_region_destroy (clip);
}
/**
* gtk_snapshot_pop:
* @snapshot: a #GtkSnapshot

View File

@ -52,6 +52,11 @@ void gtk_snapshot_push_clip (GtkSnapshot
const char *name,
...) G_GNUC_PRINTF (3, 4);
GDK_AVAILABLE_IN_3_90
void gtk_snapshot_push_rounded_clip (GtkSnapshot *snapshot,
const GskRoundedRect *bounds,
const char *name,
...) G_GNUC_PRINTF (3, 4);
GDK_AVAILABLE_IN_3_90
GskRenderNode * gtk_snapshot_pop (GtkSnapshot *snapshot) G_GNUC_WARN_UNUSED_RESULT;
GDK_AVAILABLE_IN_3_90
void gtk_snapshot_pop_and_append (GtkSnapshot *snapshot);

View File

@ -538,6 +538,10 @@ append_node (GtkTreeModelRenderNode *nodemodel,
append_node (nodemodel, gsk_clip_node_get_child (node), priv->nodes->len - 1);
break;
case GSK_ROUNDED_CLIP_NODE:
append_node (nodemodel, gsk_rounded_clip_node_get_child (node), priv->nodes->len - 1);
break;
case GSK_CONTAINER_NODE:
{
gint elt_index;