summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2016-12-21 05:43:14 +0100
committerBenjamin Otte <otte@redhat.com>2016-12-22 04:17:27 +0100
commit524c25b727120421522b9c7652c526aee309c334 (patch)
treedf3d8ca6089f77bb8b5a40b92e4237e866b89eae
parent8cc77194a3d330da60440ecd074cd3819f09bf15 (diff)
downloadgtk+-524c25b727120421522b9c7652c526aee309c334.tar.gz
gsk: Add gsk_render_node_serialize/deserialize()
This does a conversion to/from GBytes and is intended for writing tests. It's really crude but it works. And that probably means Alex will (ab)use it for broadway.
-rw-r--r--gsk/gskrendernode.c50
-rw-r--r--gsk/gskrendernode.h6
-rw-r--r--gsk/gskrendernodeimpl.c927
-rw-r--r--gsk/gskrendernodeprivate.h6
4 files changed, 989 insertions, 0 deletions
diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c
index d1fdb4f2ae..fd410f67a5 100644
--- a/gsk/gskrendernode.c
+++ b/gsk/gskrendernode.c
@@ -285,4 +285,54 @@ gsk_render_node_draw (GskRenderNode *node,
cairo_restore (cr);
}
+#define GSK_RENDER_NODE_SERIALIZATION_VERSION 0
+#define GSK_RENDER_NODE_SERIALIZATION_ID "GskRenderNode"
+
+GBytes *
+gsk_render_node_serialize (GskRenderNode *node)
+{
+ GVariant *node_variant, *variant;
+ GBytes *result;
+
+ node_variant = gsk_render_node_serialize_node (node);
+
+ variant = g_variant_new ("(suuv)",
+ GSK_RENDER_NODE_SERIALIZATION_ID,
+ (guint32) GSK_RENDER_NODE_SERIALIZATION_VERSION,
+ (guint32) gsk_render_node_get_node_type (node),
+ node_variant);
+
+ result = g_variant_get_data_as_bytes (variant);
+ g_variant_unref (variant);
+
+ return result;
+}
+
+GskRenderNode *
+gsk_render_node_deserialize (GBytes *bytes)
+{
+ char *id_string;
+ guint32 version, node_type;
+ GVariant *variant, *node_variant;
+ GskRenderNode *node = NULL;
+
+ variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("(suuv)"), bytes, FALSE);
+
+ g_variant_get (variant, "(suuv)", &id_string, &version, &node_type, &node_variant);
+
+ if (!g_str_equal (id_string, GSK_RENDER_NODE_SERIALIZATION_ID))
+ goto out;
+
+ if (version != GSK_RENDER_NODE_SERIALIZATION_VERSION)
+ goto out;
+
+ node = gsk_render_node_deserialize_node (node_type, node_variant);
+
+out:
+ g_free (id_string);
+ g_variant_unref (node_variant);
+ g_variant_unref (variant);
+
+ return node;
+}
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 39c134a963..0cbbfd5ad5 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -170,6 +170,12 @@ const char * gsk_render_node_get_name (GskRenderNode *
GDK_AVAILABLE_IN_3_90
void gsk_render_node_draw (GskRenderNode *node,
cairo_t *cr);
+
+GDK_AVAILABLE_IN_3_90
+GBytes * gsk_render_node_serialize (GskRenderNode *node);
+GDK_AVAILABLE_IN_3_90
+GskRenderNode * gsk_render_node_deserialize (GBytes *bytes);
+
G_END_DECLS
#endif /* __GSK_RENDER_NODE_H__ */
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 26ef037339..a70d1b25f8 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -54,12 +54,44 @@ gsk_color_node_draw (GskRenderNode *node,
cairo_fill (cr);
}
+#define GSK_COLOR_NODE_VARIANT_TYPE "(dddddddd)"
+
+static GVariant *
+gsk_color_node_serialize (GskRenderNode *node)
+{
+ GskColorNode *self = (GskColorNode *) node;
+
+ return g_variant_new (GSK_COLOR_NODE_VARIANT_TYPE,
+ self->color.red, self->color.green,
+ self->color.blue, self->color.alpha,
+ (double) node->bounds.origin.x, (double) node->bounds.origin.y,
+ (double) node->bounds.size.width, (double) node->bounds.size.height);
+}
+
+static GskRenderNode *
+gsk_color_node_deserialize (GVariant *variant)
+{
+ double x, y, w, h;
+ GdkRGBA color;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_COLOR_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_COLOR_NODE_VARIANT_TYPE,
+ &color.red, &color.green, &color.blue, &color.alpha,
+ &x, &y, &w, &h);
+
+ return gsk_color_node_new (&color, &GRAPHENE_RECT_INIT (x, y, w, h));
+}
+
static const GskRenderNodeClass GSK_COLOR_NODE_CLASS = {
GSK_COLOR_NODE,
sizeof (GskColorNode),
"GskColorNode",
gsk_color_node_finalize,
gsk_color_node_draw,
+ gsk_color_node_serialize,
+ gsk_color_node_deserialize,
};
const GdkRGBA *
@@ -152,12 +184,89 @@ gsk_linear_gradient_node_draw (GskRenderNode *node,
cairo_fill (cr);
}
+#define GSK_LINEAR_GRADIENT_NODE_VARIANT_TYPE "(dddddddda(ddddd))"
+
+static GVariant *
+gsk_linear_gradient_node_serialize (GskRenderNode *node)
+{
+ GskLinearGradientNode *self = (GskLinearGradientNode *) node;
+ GVariantBuilder builder;
+ guint i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ddddd)"));
+ for (i = 0; i < self->n_stops; i++)
+ {
+ g_variant_builder_add (&builder, "(ddddd)",
+ (double) self->stops[i].offset,
+ self->stops[i].color.red, self->stops[i].color.green,
+ self->stops[i].color.blue, self->stops[i].color.alpha);
+ }
+
+ return g_variant_new (GSK_LINEAR_GRADIENT_NODE_VARIANT_TYPE,
+ (double) node->bounds.origin.x, (double) node->bounds.origin.y,
+ (double) node->bounds.size.width, (double) node->bounds.size.height,
+ (double) self->start.x, (double) self->start.y,
+ (double) self->end.x, (double) self->end.y,
+ &builder);
+}
+
+static GskRenderNode *
+gsk_linear_gradient_node_real_deserialize (GVariant *variant,
+ gboolean repeating)
+{
+ GVariantIter *iter;
+ double x, y, w, h, start_x, start_y, end_x, end_y;
+ gsize i, n_stops;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_LINEAR_GRADIENT_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_LINEAR_GRADIENT_NODE_VARIANT_TYPE,
+ &x, &y, &w, &h,
+ &start_x, &start_y, &end_x, &end_y,
+ &iter);
+
+ n_stops = g_variant_iter_n_children (iter);
+ GskColorStop stops[n_stops];
+ for (i = 0; i < n_stops; i++)
+ {
+ double offset;
+ g_variant_iter_next (iter, "(ddddd)",
+ &offset,
+ &stops[i].color.red, &stops[i].color.green,
+ &stops[i].color.blue, &stops[i].color.alpha);
+ stops[i].offset = offset;
+ }
+ g_variant_iter_free (iter);
+
+ return (repeating ? gsk_repeating_linear_gradient_node_new : gsk_linear_gradient_node_new)
+ (&GRAPHENE_RECT_INIT (x, y, w, h),
+ &GRAPHENE_POINT_INIT (start_x, start_y),
+ &GRAPHENE_POINT_INIT (end_x, end_y),
+ stops,
+ n_stops);
+}
+
+static GskRenderNode *
+gsk_linear_gradient_node_deserialize (GVariant *variant)
+{
+ return gsk_linear_gradient_node_real_deserialize (variant, FALSE);
+}
+
+static GskRenderNode *
+gsk_repeating_linear_gradient_node_deserialize (GVariant *variant)
+{
+ return gsk_linear_gradient_node_real_deserialize (variant, TRUE);
+}
+
static const GskRenderNodeClass GSK_LINEAR_GRADIENT_NODE_CLASS = {
GSK_LINEAR_GRADIENT_NODE,
sizeof (GskLinearGradientNode),
"GskLinearGradientNode",
gsk_linear_gradient_node_finalize,
gsk_linear_gradient_node_draw,
+ gsk_linear_gradient_node_serialize,
+ gsk_linear_gradient_node_deserialize,
};
static const GskRenderNodeClass GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS = {
@@ -166,6 +275,8 @@ static const GskRenderNodeClass GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS = {
"GskLinearGradientNode",
gsk_linear_gradient_node_finalize,
gsk_linear_gradient_node_draw,
+ gsk_linear_gradient_node_serialize,
+ gsk_repeating_linear_gradient_node_deserialize,
};
/**
@@ -333,12 +444,72 @@ gsk_border_node_draw (GskRenderNode *node,
cairo_restore (cr);
}
+#define GSK_BORDER_NODE_VARIANT_TYPE "(dddddddddddddddddddddddddddddddd)"
+
+static GVariant *
+gsk_border_node_serialize (GskRenderNode *node)
+{
+ GskBorderNode *self = (GskBorderNode *) node;
+
+ return g_variant_new (GSK_BORDER_NODE_VARIANT_TYPE,
+ (double) self->outline.bounds.origin.x, (double) self->outline.bounds.origin.y,
+ (double) self->outline.bounds.size.width, (double) self->outline.bounds.size.height,
+ (double) self->outline.corner[0].width, (double) self->outline.corner[0].height,
+ (double) self->outline.corner[1].width, (double) self->outline.corner[1].height,
+ (double) self->outline.corner[2].width, (double) self->outline.corner[2].height,
+ (double) self->outline.corner[3].width, (double) self->outline.corner[3].height,
+ (double) self->border_width[0], (double) self->border_width[1],
+ (double) self->border_width[2], (double) self->border_width[3],
+ self->border_color[0].red, self->border_color[0].green,
+ self->border_color[0].blue, self->border_color[0].alpha,
+ self->border_color[1].red, self->border_color[1].green,
+ self->border_color[1].blue, self->border_color[1].alpha,
+ self->border_color[2].red, self->border_color[2].green,
+ self->border_color[2].blue, self->border_color[2].alpha,
+ self->border_color[3].red, self->border_color[3].green,
+ self->border_color[3].blue, self->border_color[3].alpha);
+}
+
+static GskRenderNode *
+gsk_border_node_deserialize (GVariant *variant)
+{
+ double doutline[12], dwidths[4];
+ GdkRGBA colors[4];
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_BORDER_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_BORDER_NODE_VARIANT_TYPE,
+ &doutline[0], &doutline[1], &doutline[2], &doutline[3],
+ &doutline[4], &doutline[5], &doutline[6], &doutline[7],
+ &doutline[8], &doutline[9], &doutline[10], &doutline[11],
+ &dwidths[0], &dwidths[1], &dwidths[2], &dwidths[3],
+ &colors[0].red, &colors[0].green, &colors[0].blue, &colors[0].alpha,
+ &colors[1].red, &colors[1].green, &colors[1].blue, &colors[1].alpha,
+ &colors[2].red, &colors[2].green, &colors[2].blue, &colors[2].alpha,
+ &colors[3].red, &colors[3].green, &colors[3].blue, &colors[3].alpha);
+
+ return gsk_border_node_new (&(GskRoundedRect) {
+ .bounds = GRAPHENE_RECT_INIT(doutline[0], doutline[1], doutline[2], doutline[3]),
+ .corner = {
+ GRAPHENE_SIZE_INIT (doutline[4], doutline[5]),
+ GRAPHENE_SIZE_INIT (doutline[6], doutline[7]),
+ GRAPHENE_SIZE_INIT (doutline[8], doutline[9]),
+ GRAPHENE_SIZE_INIT (doutline[10], doutline[11])
+ }
+ },
+ (float[4]) { dwidths[0], dwidths[1], dwidths[2], dwidths[3] },
+ colors);
+}
+
static const GskRenderNodeClass GSK_BORDER_NODE_CLASS = {
GSK_BORDER_NODE,
sizeof (GskBorderNode),
"GskBorderNode",
gsk_border_node_finalize,
gsk_border_node_draw,
+ gsk_border_node_serialize,
+ gsk_border_node_deserialize
};
const GskRoundedRect *
@@ -447,12 +618,72 @@ gsk_texture_node_draw (GskRenderNode *node,
cairo_surface_destroy (surface);
}
+#define GSK_TEXTURE_NODE_VARIANT_TYPE "(dddduuau)"
+
+static GVariant *
+gsk_texture_node_serialize (GskRenderNode *node)
+{
+ GskTextureNode *self = (GskTextureNode *) node;
+ cairo_surface_t *surface;
+ GVariant *result;
+
+ surface = gsk_texture_download (self->texture);
+
+ g_assert (cairo_image_surface_get_width (surface) * 4 == cairo_image_surface_get_stride (surface));
+
+ result = g_variant_new ("(dddduu@au)",
+ (double) node->bounds.origin.x, (double) node->bounds.origin.y,
+ (double) node->bounds.size.width, (double) node->bounds.size.height,
+ (guint32) gsk_texture_get_width (self->texture),
+ (guint32) gsk_texture_get_height (self->texture),
+ g_variant_new_fixed_array (G_VARIANT_TYPE ("u"),
+ cairo_image_surface_get_data (surface),
+ gsk_texture_get_width (self->texture)
+ * gsk_texture_get_height (self->texture),
+ sizeof (guint32)));
+
+ cairo_surface_destroy (surface);
+
+ return result;
+}
+
+static GskRenderNode *
+gsk_texture_node_deserialize (GVariant *variant)
+{
+ GskRenderNode *node;
+ GskTexture *texture;
+ double bounds[4];
+ guint32 width, height;
+ GVariant *pixel_variant;
+ gsize n_pixels;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_TEXTURE_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, "(dddduu@au)",
+ &bounds[0], &bounds[1], &bounds[2], &bounds[3],
+ &width, &height, &pixel_variant);
+
+ /* XXX: Make this work without copying the data */
+ texture = gsk_texture_new_for_data (g_variant_get_fixed_array (pixel_variant, &n_pixels, sizeof (guint32)),
+ width, height, width * 4);
+ g_variant_unref (pixel_variant);
+
+ node = gsk_texture_node_new (texture, &GRAPHENE_RECT_INIT(bounds[0], bounds[1], bounds[2], bounds[3]));
+
+ gsk_texture_unref (texture);
+
+ return node;
+}
+
static const GskRenderNodeClass GSK_TEXTURE_NODE_CLASS = {
GSK_TEXTURE_NODE,
sizeof (GskTextureNode),
"GskTextureNode",
gsk_texture_node_finalize,
gsk_texture_node_draw,
+ gsk_texture_node_serialize,
+ gsk_texture_node_deserialize
};
GskTexture *
@@ -898,12 +1129,62 @@ gsk_inset_shadow_node_draw (GskRenderNode *node,
cairo_restore (cr);
}
+#define GSK_INSET_SHADOW_NODE_VARIANT_TYPE "(dddddddddddddddddddd)"
+
+static GVariant *
+gsk_inset_shadow_node_serialize (GskRenderNode *node)
+{
+ GskInsetShadowNode *self = (GskInsetShadowNode *) node;
+
+ return g_variant_new (GSK_INSET_SHADOW_NODE_VARIANT_TYPE,
+ (double) self->outline.bounds.origin.x, (double) self->outline.bounds.origin.y,
+ (double) self->outline.bounds.size.width, (double) self->outline.bounds.size.height,
+ (double) self->outline.corner[0].width, (double) self->outline.corner[0].height,
+ (double) self->outline.corner[1].width, (double) self->outline.corner[1].height,
+ (double) self->outline.corner[2].width, (double) self->outline.corner[2].height,
+ (double) self->outline.corner[3].width, (double) self->outline.corner[3].height,
+ self->color.red, self->color.green,
+ self->color.blue, self->color.alpha,
+ (double) self->dx, (double) self->dy,
+ (double) self->spread, (double) self->blur_radius);
+}
+
+static GskRenderNode *
+gsk_inset_shadow_node_deserialize (GVariant *variant)
+{
+ double doutline[12], dx, dy, spread, radius;
+ GdkRGBA color;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_INSET_SHADOW_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_INSET_SHADOW_NODE_VARIANT_TYPE,
+ &doutline[0], &doutline[1], &doutline[2], &doutline[3],
+ &doutline[4], &doutline[5], &doutline[6], &doutline[7],
+ &doutline[8], &doutline[9], &doutline[10], &doutline[11],
+ &color.red, &color.green, &color.blue, &color.alpha,
+ &dx, &dy, &spread, &radius);
+
+ return gsk_inset_shadow_node_new (&(GskRoundedRect) {
+ .bounds = GRAPHENE_RECT_INIT(doutline[0], doutline[1], doutline[2], doutline[3]),
+ .corner = {
+ GRAPHENE_SIZE_INIT (doutline[4], doutline[5]),
+ GRAPHENE_SIZE_INIT (doutline[6], doutline[7]),
+ GRAPHENE_SIZE_INIT (doutline[8], doutline[9]),
+ GRAPHENE_SIZE_INIT (doutline[10], doutline[11])
+ }
+ },
+ &color, dx, dy, spread, radius);
+}
+
static const GskRenderNodeClass GSK_INSET_SHADOW_NODE_CLASS = {
GSK_INSET_SHADOW_NODE,
sizeof (GskInsetShadowNode),
"GskInsetShadowNode",
gsk_inset_shadow_node_finalize,
gsk_inset_shadow_node_draw,
+ gsk_inset_shadow_node_serialize,
+ gsk_inset_shadow_node_deserialize
};
/**
@@ -1090,12 +1371,62 @@ gsk_outset_shadow_node_draw (GskRenderNode *node,
cairo_restore (cr);
}
+#define GSK_OUTSET_SHADOW_NODE_VARIANT_TYPE "(dddddddddddddddddddd)"
+
+static GVariant *
+gsk_outset_shadow_node_serialize (GskRenderNode *node)
+{
+ GskOutsetShadowNode *self = (GskOutsetShadowNode *) node;
+
+ return g_variant_new (GSK_OUTSET_SHADOW_NODE_VARIANT_TYPE,
+ (double) self->outline.bounds.origin.x, (double) self->outline.bounds.origin.y,
+ (double) self->outline.bounds.size.width, (double) self->outline.bounds.size.height,
+ (double) self->outline.corner[0].width, (double) self->outline.corner[0].height,
+ (double) self->outline.corner[1].width, (double) self->outline.corner[1].height,
+ (double) self->outline.corner[2].width, (double) self->outline.corner[2].height,
+ (double) self->outline.corner[3].width, (double) self->outline.corner[3].height,
+ self->color.red, self->color.green,
+ self->color.blue, self->color.alpha,
+ (double) self->dx, (double) self->dy,
+ (double) self->spread, (double) self->blur_radius);
+}
+
+static GskRenderNode *
+gsk_outset_shadow_node_deserialize (GVariant *variant)
+{
+ double doutline[12], dx, dy, spread, radius;
+ GdkRGBA color;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_OUTSET_SHADOW_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_INSET_SHADOW_NODE_VARIANT_TYPE,
+ &doutline[0], &doutline[1], &doutline[2], &doutline[3],
+ &doutline[4], &doutline[5], &doutline[6], &doutline[7],
+ &doutline[8], &doutline[9], &doutline[10], &doutline[11],
+ &color.red, &color.green, &color.blue, &color.alpha,
+ &dx, &dy, &spread, &radius);
+
+ return gsk_outset_shadow_node_new (&(GskRoundedRect) {
+ .bounds = GRAPHENE_RECT_INIT(doutline[0], doutline[1], doutline[2], doutline[3]),
+ .corner = {
+ GRAPHENE_SIZE_INIT (doutline[4], doutline[5]),
+ GRAPHENE_SIZE_INIT (doutline[6], doutline[7]),
+ GRAPHENE_SIZE_INIT (doutline[8], doutline[9]),
+ GRAPHENE_SIZE_INIT (doutline[10], doutline[11])
+ }
+ },
+ &color, dx, dy, spread, radius);
+}
+
static const GskRenderNodeClass GSK_OUTSET_SHADOW_NODE_CLASS = {
GSK_OUTSET_SHADOW_NODE,
sizeof (GskOutsetShadowNode),
"GskOutsetShadowNode",
gsk_outset_shadow_node_finalize,
gsk_outset_shadow_node_draw,
+ gsk_outset_shadow_node_serialize,
+ gsk_outset_shadow_node_deserialize
};
/**
@@ -1182,12 +1513,92 @@ gsk_cairo_node_draw (GskRenderNode *node,
cairo_paint (cr);
}
+#define GSK_CAIRO_NODE_VARIANT_TYPE "(dddduuau)"
+
+static GVariant *
+gsk_cairo_node_serialize (GskRenderNode *node)
+{
+ GskCairoNode *self = (GskCairoNode *) node;
+
+ if (self->surface == NULL)
+ {
+ return g_variant_new ("(dddduu@au)",
+ (double) node->bounds.origin.x, (double) node->bounds.origin.y,
+ (double) node->bounds.size.width, (double) node->bounds.size.height,
+ (guint32) 0, (guint32) 0,
+ g_variant_new_array (G_VARIANT_TYPE ("u"), NULL, 0));
+ }
+ else if (cairo_image_surface_get_width (self->surface) * 4 == cairo_image_surface_get_stride (self->surface))
+ {
+ return g_variant_new ("(dddduu@au)",
+ (double) node->bounds.origin.x, (double) node->bounds.origin.y,
+ (double) node->bounds.size.width, (double) node->bounds.size.height,
+ (guint32) cairo_image_surface_get_width (self->surface),
+ (guint32) cairo_image_surface_get_height (self->surface),
+ g_variant_new_fixed_array (G_VARIANT_TYPE ("u"),
+ cairo_image_surface_get_data (self->surface),
+ cairo_image_surface_get_width (self->surface)
+ * cairo_image_surface_get_height (self->surface),
+ sizeof (guint32)));
+ }
+ else
+ {
+ /* FIXME: implement! */
+ g_assert_not_reached ();
+ return NULL;
+ }
+}
+
+const cairo_user_data_key_t gsk_surface_variant_key;
+
+static GskRenderNode *
+gsk_cairo_node_deserialize (GVariant *variant)
+{
+ GskRenderNode *result;
+ cairo_surface_t *surface;
+ double x, y, width, height;
+ guint32 surface_width, surface_height;
+ GVariant *pixel_variant;
+ gsize n_pixels;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_CAIRO_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, "(dddduu@au)",
+ &x, &y, &width, &height,
+ &surface_width, &surface_height,
+ &pixel_variant);
+
+ if (surface_width == 0 || surface_height == 0)
+ {
+ g_variant_unref (pixel_variant);
+ return gsk_cairo_node_new (&GRAPHENE_RECT_INIT (x, y, width, height));
+ }
+
+ /* XXX: Make this work without copying the data */
+ surface = cairo_image_surface_create_for_data ((guchar *) g_variant_get_fixed_array (pixel_variant, &n_pixels, sizeof (guint32)),
+ CAIRO_FORMAT_ARGB32,
+ surface_width, surface_height, surface_width * 4);
+ cairo_surface_set_user_data (surface,
+ &gsk_surface_variant_key,
+ pixel_variant,
+ (cairo_destroy_func_t) g_variant_unref);
+
+ result = gsk_cairo_node_new_for_surface (&GRAPHENE_RECT_INIT (x, y, width, height), surface);
+
+ cairo_surface_destroy (surface);
+
+ return result;
+}
+
static const GskRenderNodeClass GSK_CAIRO_NODE_CLASS = {
GSK_CAIRO_NODE,
sizeof (GskCairoNode),
"GskCairoNode",
gsk_cairo_node_finalize,
gsk_cairo_node_draw,
+ gsk_cairo_node_serialize,
+ gsk_cairo_node_deserialize
};
/*< private >
@@ -1208,6 +1619,22 @@ gsk_cairo_node_get_surface (GskRenderNode *node)
return self->surface;
}
+GskRenderNode *
+gsk_cairo_node_new_for_surface (const graphene_rect_t *bounds,
+ cairo_surface_t *surface)
+{
+ GskCairoNode *self;
+
+ g_return_val_if_fail (bounds != NULL, NULL);
+
+ self = (GskCairoNode *) gsk_render_node_new (&GSK_CAIRO_NODE_CLASS, 0);
+
+ graphene_rect_init_from_rect (&self->render_node.bounds, bounds);
+ self->surface = cairo_surface_reference (surface);
+
+ return &self->render_node;
+}
+
/**
* gsk_cairo_node_new:
* @bounds: the rectangle to render the to
@@ -1370,12 +1797,73 @@ gsk_container_node_get_bounds (GskContainerNode *container,
graphene_rect_union (bounds, &container->children[i]->bounds, bounds);
}
+#define GSK_CONTAINER_NODE_VARIANT_TYPE "a(uv)"
+
+static GVariant *
+gsk_container_node_serialize (GskRenderNode *node)
+{
+ GskContainerNode *self = (GskContainerNode *) node;
+ GVariantBuilder builder;
+ guint i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE (GSK_CONTAINER_NODE_VARIANT_TYPE));
+
+ for (i = 0; i < self->n_children; i++)
+ {
+ g_variant_builder_add (&builder, "(uv)",
+ (guint32) gsk_render_node_get_node_type (self->children[i]),
+ gsk_render_node_serialize_node (self->children[i]));
+ }
+
+ return g_variant_builder_end (&builder);
+}
+
+static GskRenderNode *
+gsk_container_node_deserialize (GVariant *variant)
+{
+ GskRenderNode *result;
+ GVariantIter iter;
+ gsize i, n_children;
+ guint32 child_type;
+ GVariant *child_variant;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_CONTAINER_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ i = 0;
+ n_children = g_variant_iter_init (&iter, variant);
+ GskRenderNode *children[n_children];
+
+ while (g_variant_iter_loop (&iter, "(uv)", &child_type, &child_variant))
+ {
+ children[i] = gsk_render_node_deserialize_node (child_type, child_variant);
+ if (children[i] == NULL)
+ {
+ guint j;
+ for (j = 0; j < i; j++)
+ gsk_render_node_unref (children[j]);
+ g_variant_unref (child_variant);
+ return NULL;
+ }
+ i++;
+ }
+
+ result = gsk_container_node_new (children, n_children);
+
+ for (i = 0; i < n_children; i++)
+ gsk_render_node_unref (children[i]);
+
+ return result;
+}
+
static const GskRenderNodeClass GSK_CONTAINER_NODE_CLASS = {
GSK_CONTAINER_NODE,
sizeof (GskContainerNode),
"GskContainerNode",
gsk_container_node_finalize,
gsk_container_node_draw,
+ gsk_container_node_serialize,
+ gsk_container_node_deserialize
};
/**
@@ -1486,12 +1974,73 @@ gsk_transform_node_draw (GskRenderNode *node,
}
}
+#define GSK_TRANSFORM_NODE_VARIANT_TYPE "(dddddddddddddddduv)"
+
+static GVariant *
+gsk_transform_node_serialize (GskRenderNode *node)
+{
+ GskTransformNode *self = (GskTransformNode *) node;
+ float mat[16];
+
+ graphene_matrix_to_float (&self->transform, mat);
+
+ return g_variant_new (GSK_TRANSFORM_NODE_VARIANT_TYPE,
+ (double) mat[0], (double) mat[1], (double) mat[2], (double) mat[3],
+ (double) mat[4], (double) mat[5], (double) mat[6], (double) mat[7],
+ (double) mat[8], (double) mat[9], (double) mat[10], (double) mat[11],
+ (double) mat[12], (double) mat[13], (double) mat[14], (double) mat[15],
+ (guint32) gsk_render_node_get_node_type (self->child),
+ gsk_render_node_serialize_node (self->child));
+}
+
+static GskRenderNode *
+gsk_transform_node_deserialize (GVariant *variant)
+{
+ graphene_matrix_t transform;
+ double mat[16];
+ guint32 child_type;
+ GVariant *child_variant;
+ GskRenderNode *result, *child;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_TRANSFORM_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_TRANSFORM_NODE_VARIANT_TYPE,
+ &mat[0], &mat[1], &mat[2], &mat[3],
+ &mat[4], &mat[5], &mat[6], &mat[7],
+ &mat[8], &mat[9], &mat[10], &mat[11],
+ &mat[12], &mat[13], &mat[14], &mat[15],
+ &child_type, &child_variant);
+
+ child = gsk_render_node_deserialize_node (child_type, child_variant);
+ g_variant_unref (child_variant);
+
+ if (child == NULL)
+ return NULL;
+
+ graphene_matrix_init_from_float (&transform,
+ (float[16]) {
+ mat[0], mat[1], mat[2], mat[3],
+ mat[4], mat[5], mat[6], mat[7],
+ mat[8], mat[9], mat[10], mat[11],
+ mat[12], mat[13], mat[14], mat[15]
+ });
+
+ result = gsk_transform_node_new (child, &transform);
+
+ gsk_render_node_unref (child);
+
+ return result;
+}
+
static const GskRenderNodeClass GSK_TRANSFORM_NODE_CLASS = {
GSK_TRANSFORM_NODE,
sizeof (GskTransformNode),
"GskTransformNode",
gsk_transform_node_finalize,
gsk_transform_node_draw,
+ gsk_transform_node_serialize,
+ gsk_transform_node_deserialize
};
/**
@@ -1598,12 +2147,55 @@ gsk_opacity_node_draw (GskRenderNode *node,
cairo_restore (cr);
}
+#define GSK_OPACITY_NODE_VARIANT_TYPE "(duv)"
+
+static GVariant *
+gsk_opacity_node_serialize (GskRenderNode *node)
+{
+ GskOpacityNode *self = (GskOpacityNode *) node;
+
+ return g_variant_new (GSK_OPACITY_NODE_VARIANT_TYPE,
+ (double) self->opacity,
+ (guint32) gsk_render_node_get_node_type (self->child),
+ gsk_render_node_serialize_node (self->child));
+}
+
+static GskRenderNode *
+gsk_opacity_node_deserialize (GVariant *variant)
+{
+ double opacity;
+ guint32 child_type;
+ GVariant *child_variant;
+ GskRenderNode *result, *child;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_OPACITY_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_OPACITY_NODE_VARIANT_TYPE,
+ &opacity,
+ &child_type, &child_variant);
+
+ child = gsk_render_node_deserialize_node (child_type, child_variant);
+ g_variant_unref (child_variant);
+
+ if (child == NULL)
+ return NULL;
+
+ result = gsk_opacity_node_new (child, opacity);
+
+ gsk_render_node_unref (child);
+
+ return result;
+}
+
static const GskRenderNodeClass GSK_OPACITY_NODE_CLASS = {
GSK_OPACITY_NODE,
sizeof (GskOpacityNode),
"GskOpacityNode",
gsk_opacity_node_finalize,
gsk_opacity_node_draw,
+ gsk_opacity_node_serialize,
+ gsk_opacity_node_deserialize
};
/**
@@ -1702,12 +2294,56 @@ gsk_clip_node_draw (GskRenderNode *node,
cairo_restore (cr);
}
+#define GSK_CLIP_NODE_VARIANT_TYPE "(dddduv)"
+
+static GVariant *
+gsk_clip_node_serialize (GskRenderNode *node)
+{
+ GskClipNode *self = (GskClipNode *) node;
+
+ return g_variant_new (GSK_CLIP_NODE_VARIANT_TYPE,
+ (double) node->bounds.origin.x, (double) node->bounds.origin.y,
+ (double) node->bounds.size.width, (double) node->bounds.size.height,
+ (guint32) gsk_render_node_get_node_type (self->child),
+ gsk_render_node_serialize_node (self->child));
+}
+
+static GskRenderNode *
+gsk_clip_node_deserialize (GVariant *variant)
+{
+ double x, y, width, height;
+ guint32 child_type;
+ GVariant *child_variant;
+ GskRenderNode *result, *child;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_CLIP_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_CLIP_NODE_VARIANT_TYPE,
+ &x, &y, &width, &height,
+ &child_type, &child_variant);
+
+ child = gsk_render_node_deserialize_node (child_type, child_variant);
+ g_variant_unref (child_variant);
+
+ if (child == NULL)
+ return NULL;
+
+ result = gsk_clip_node_new (child, &GRAPHENE_RECT_INIT(x, y, width, height));
+
+ gsk_render_node_unref (child);
+
+ return result;
+}
+
static const GskRenderNodeClass GSK_CLIP_NODE_CLASS = {
GSK_CLIP_NODE,
sizeof (GskClipNode),
"GskClipNode",
gsk_clip_node_finalize,
gsk_clip_node_draw,
+ gsk_clip_node_serialize,
+ gsk_clip_node_deserialize
};
/**
@@ -1805,12 +2441,71 @@ gsk_rounded_clip_node_draw (GskRenderNode *node,
cairo_restore (cr);
}
+#define GSK_ROUNDED_CLIP_NODE_VARIANT_TYPE "(dddddddddddduv)"
+
+static GVariant *
+gsk_rounded_clip_node_serialize (GskRenderNode *node)
+{
+ GskRoundedClipNode *self = (GskRoundedClipNode *) node;
+
+ return g_variant_new (GSK_ROUNDED_CLIP_NODE_VARIANT_TYPE,
+ (double) self->clip.bounds.origin.x, (double) self->clip.bounds.origin.y,
+ (double) self->clip.bounds.size.width, (double) self->clip.bounds.size.height,
+ (double) self->clip.corner[0].width, (double) self->clip.corner[0].height,
+ (double) self->clip.corner[1].width, (double) self->clip.corner[1].height,
+ (double) self->clip.corner[2].width, (double) self->clip.corner[2].height,
+ (double) self->clip.corner[3].width, (double) self->clip.corner[3].height,
+ (guint32) gsk_render_node_get_node_type (self->child),
+ gsk_render_node_serialize_node (self->child));
+}
+
+static GskRenderNode *
+gsk_rounded_clip_node_deserialize (GVariant *variant)
+{
+ double doutline[12];
+ guint32 child_type;
+ GVariant *child_variant;
+ GskRenderNode *child, *result;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_ROUNDED_CLIP_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_ROUNDED_CLIP_NODE_VARIANT_TYPE,
+ &doutline[0], &doutline[1], &doutline[2], &doutline[3],
+ &doutline[4], &doutline[5], &doutline[6], &doutline[7],
+ &doutline[8], &doutline[9], &doutline[10], &doutline[11],
+ &child_type, &child_variant);
+
+ child = gsk_render_node_deserialize_node (child_type, child_variant);
+ g_variant_unref (child_variant);
+
+ if (child == NULL)
+ return NULL;
+
+ result = gsk_rounded_clip_node_new (child,
+ &(GskRoundedRect) {
+ .bounds = GRAPHENE_RECT_INIT(doutline[0], doutline[1], doutline[2], doutline[3]),
+ .corner = {
+ GRAPHENE_SIZE_INIT (doutline[4], doutline[5]),
+ GRAPHENE_SIZE_INIT (doutline[6], doutline[7]),
+ GRAPHENE_SIZE_INIT (doutline[8], doutline[9]),
+ GRAPHENE_SIZE_INIT (doutline[10], doutline[11])
+ }
+ });
+
+ gsk_render_node_unref (child);
+
+ return result;
+}
+
static const GskRenderNodeClass GSK_ROUNDED_CLIP_NODE_CLASS = {
GSK_ROUNDED_CLIP_NODE,
sizeof (GskRoundedClipNode),
"GskRoundedClipNode",
gsk_rounded_clip_node_finalize,
gsk_rounded_clip_node_draw,
+ gsk_rounded_clip_node_serialize,
+ gsk_rounded_clip_node_deserialize
};
/**
@@ -1955,12 +2650,86 @@ gsk_shadow_node_get_bounds (GskShadowNode *self,
bounds->size.height += top + bottom;
}
+#define GSK_SHADOW_NODE_VARIANT_TYPE "(uva(ddddddd))"
+
+static GVariant *
+gsk_shadow_node_serialize (GskRenderNode *node)
+{
+ GskShadowNode *self = (GskShadowNode *) node;
+ GVariantBuilder builder;
+ gsize i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ddddddd)"));
+ for (i = 0; i < self->n_shadows; i++)
+ {
+ g_variant_builder_add (&builder, "(ddddddd)",
+ self->shadows[i].color.red, self->shadows[i].color.green,
+ self->shadows[i].color.blue, self->shadows[i].color.alpha,
+ self->shadows[i].dx, self->shadows[i].dy,
+ self->shadows[i].radius);
+ }
+
+ return g_variant_new (GSK_SHADOW_NODE_VARIANT_TYPE,
+ (guint32) gsk_render_node_get_node_type (self->child),
+ gsk_render_node_serialize_node (self->child),
+ &builder);
+}
+
+static GskRenderNode *
+gsk_shadow_node_deserialize (GVariant *variant)
+{
+ gsize n_shadows;
+ guint32 child_type;
+ GVariant *child_variant;
+ GskRenderNode *result, *child;
+ GVariantIter *iter;
+ gsize i;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_SHADOW_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_SHADOW_NODE_VARIANT_TYPE,
+ &child_type, &child_variant, &iter);
+
+ child = gsk_render_node_deserialize_node (child_type, child_variant);
+ g_variant_unref (child_variant);
+
+ if (child == NULL)
+ {
+ g_variant_iter_free (iter);
+ return NULL;
+ }
+
+ n_shadows = g_variant_iter_n_children (iter);
+ GskShadow shadows[n_shadows];
+ for (i = 0; i < n_shadows; i++)
+ {
+ double dx, dy, radius;
+ g_variant_iter_next (iter, "(ddddddd)",
+ &shadows[i].color.red, &shadows[i].color.green,
+ &shadows[i].color.blue, &shadows[i].color.alpha,
+ &dx, &dy, &radius);
+ shadows[i].dx = dx;
+ shadows[i].dy = dy;
+ shadows[i].radius = radius;
+ }
+ g_variant_iter_free (iter);
+
+ result = gsk_shadow_node_new (child, shadows, n_shadows);
+
+ gsk_render_node_unref (child);
+
+ return result;
+}
+
static const GskRenderNodeClass GSK_SHADOW_NODE_CLASS = {
GSK_SHADOW_NODE,
sizeof (GskShadowNode),
"GskShadowNode",
gsk_shadow_node_finalize,
gsk_shadow_node_draw,
+ gsk_shadow_node_serialize,
+ gsk_shadow_node_deserialize
};
/**
@@ -2114,12 +2883,68 @@ gsk_blend_node_draw (GskRenderNode *node,
cairo_paint (cr);
}
+#define GSK_BLEND_NODE_VARIANT_TYPE "(uvuvu)"
+
+static GVariant *
+gsk_blend_node_serialize (GskRenderNode *node)
+{
+ GskBlendNode *self = (GskBlendNode *) node;
+
+ return g_variant_new (GSK_BLEND_NODE_VARIANT_TYPE,
+ (guint32) gsk_render_node_get_node_type (self->bottom),
+ gsk_render_node_serialize_node (self->bottom),
+ (guint32) gsk_render_node_get_node_type (self->top),
+ gsk_render_node_serialize_node (self->top),
+ (guint32) self->blend_mode);
+}
+
+static GskRenderNode *
+gsk_blend_node_deserialize (GVariant *variant)
+{
+ guint32 bottom_child_type, top_child_type, blend_mode;
+ GVariant *bottom_child_variant, *top_child_variant;
+ GskRenderNode *bottom_child, *top_child, *result;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_BLEND_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_BLEND_NODE_VARIANT_TYPE,
+ &bottom_child_type, &bottom_child_variant,
+ &top_child_type, &top_child_variant,
+ &blend_mode);
+
+ bottom_child = gsk_render_node_deserialize_node (bottom_child_type, bottom_child_variant);
+ g_variant_unref (bottom_child_variant);
+ if (bottom_child == NULL)
+ {
+ g_variant_unref (top_child_variant);
+ return NULL;
+ }
+
+ top_child = gsk_render_node_deserialize_node (top_child_type, top_child_variant);
+ g_variant_unref (top_child_variant);
+ if (top_child == NULL)
+ {
+ gsk_render_node_unref (bottom_child);
+ return NULL;
+ }
+
+ result = gsk_blend_node_new (bottom_child, top_child, blend_mode);
+
+ gsk_render_node_unref (top_child);
+ gsk_render_node_unref (bottom_child);
+
+ return result;
+}
+
static const GskRenderNodeClass GSK_BLEND_NODE_CLASS = {
GSK_BLEND_NODE,
sizeof (GskBlendNode),
"GskBlendNode",
gsk_blend_node_finalize,
gsk_blend_node_draw,
+ gsk_blend_node_serialize,
+ gsk_blend_node_deserialize
};
/**
@@ -2228,12 +3053,69 @@ gsk_cross_fade_node_draw (GskRenderNode *node,
cairo_paint (cr);
}
+#define GSK_CROSS_FADE_NODE_VARIANT_TYPE "(uvuvd)"
+
+static GVariant *
+gsk_cross_fade_node_serialize (GskRenderNode *node)
+{
+ GskCrossFadeNode *self = (GskCrossFadeNode *) node;
+
+ return g_variant_new (GSK_CROSS_FADE_NODE_VARIANT_TYPE,
+ (guint32) gsk_render_node_get_node_type (self->start),
+ gsk_render_node_serialize_node (self->start),
+ (guint32) gsk_render_node_get_node_type (self->end),
+ gsk_render_node_serialize_node (self->end),
+ (double) self->progress);
+}
+
+static GskRenderNode *
+gsk_cross_fade_node_deserialize (GVariant *variant)
+{
+ guint32 start_child_type, end_child_type;
+ GVariant *start_child_variant, *end_child_variant;
+ GskRenderNode *start_child, *end_child, *result;
+ double progress;
+
+ if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_CROSS_FADE_NODE_VARIANT_TYPE)))
+ return NULL;
+
+ g_variant_get (variant, GSK_CROSS_FADE_NODE_VARIANT_TYPE,
+ &start_child_type, &start_child_variant,
+ &end_child_type, &end_child_variant,
+ &progress);
+
+ start_child = gsk_render_node_deserialize_node (start_child_type, start_child_variant);
+ g_variant_unref (start_child_variant);
+ if (start_child == NULL)
+ {
+ g_variant_unref (end_child_variant);
+ return NULL;
+ }
+
+ end_child = gsk_render_node_deserialize_node (end_child_type, end_child_variant);
+ g_variant_unref (end_child_variant);
+ if (end_child == NULL)
+ {
+ gsk_render_node_unref (start_child);
+ return NULL;
+ }
+
+ result = gsk_cross_fade_node_new (start_child, end_child, progress);
+
+ gsk_render_node_unref (end_child);
+ gsk_render_node_unref (start_child);
+
+ return result;
+}
+
static const GskRenderNodeClass GSK_CROSS_FADE_NODE_CLASS = {
GSK_CROSS_FADE_NODE,
sizeof (GskCrossFadeNode),
"GskCrossFadeNode",
gsk_cross_fade_node_finalize,
gsk_cross_fade_node_draw,
+ gsk_cross_fade_node_serialize,
+ gsk_cross_fade_node_deserialize
};
/**
@@ -2300,3 +3182,48 @@ gsk_cross_fade_node_get_progress (GskRenderNode *node)
return self->progress;
}
+static const GskRenderNodeClass *klasses[] = {
+ [GSK_CONTAINER_NODE] = &GSK_CONTAINER_NODE_CLASS,
+ [GSK_CAIRO_NODE] = &GSK_CAIRO_NODE_CLASS,
+ [GSK_COLOR_NODE] = &GSK_COLOR_NODE_CLASS,
+ [GSK_LINEAR_GRADIENT_NODE] = &GSK_LINEAR_GRADIENT_NODE_CLASS,
+ [GSK_REPEATING_LINEAR_GRADIENT_NODE] = &GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS,
+ [GSK_BORDER_NODE] = &GSK_BORDER_NODE_CLASS,
+ [GSK_TEXTURE_NODE] = &GSK_TEXTURE_NODE_CLASS,
+ [GSK_INSET_SHADOW_NODE] = &GSK_INSET_SHADOW_NODE_CLASS,
+ [GSK_OUTSET_SHADOW_NODE] = &GSK_OUTSET_SHADOW_NODE_CLASS,
+ [GSK_TRANSFORM_NODE] = &GSK_TRANSFORM_NODE_CLASS,
+ [GSK_OPACITY_NODE] = &GSK_OPACITY_NODE_CLASS,
+ [GSK_CLIP_NODE] = &GSK_CLIP_NODE_CLASS,
+ [GSK_ROUNDED_CLIP_NODE] = &GSK_ROUNDED_CLIP_NODE_CLASS,
+ [GSK_SHADOW_NODE] = &GSK_SHADOW_NODE_CLASS,
+ [GSK_BLEND_NODE] = &GSK_BLEND_NODE_CLASS,
+ [GSK_CROSS_FADE_NODE] = &GSK_CROSS_FADE_NODE_CLASS
+};
+
+GskRenderNode *
+gsk_render_node_deserialize_node (GskRenderNodeType type,
+ GVariant *variant)
+{
+ const GskRenderNodeClass *klass;
+ GskRenderNode *result;
+
+ if (type < G_N_ELEMENTS (klasses))
+ klass = klasses[type];
+ else
+ klass = NULL;
+
+ if (klass == NULL)
+ return NULL;
+
+ result = klass->deserialize (variant);
+
+ return result;
+}
+
+GVariant *
+gsk_render_node_serialize_node (GskRenderNode *node)
+{
+ return node->node_class->serialize (node);
+}
+
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 8eacb7a1aa..32133149e7 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -34,18 +34,24 @@ struct _GskRenderNodeClass
void (* finalize) (GskRenderNode *node);
void (* draw) (GskRenderNode *node,
cairo_t *cr);
+ GVariant * (* serialize) (GskRenderNode *node);
+ GskRenderNode * (* deserialize) (GVariant *variant);
};
GskRenderNode *gsk_render_node_new (const GskRenderNodeClass *node_class, gsize extra_size);
void gsk_render_node_get_bounds (GskRenderNode *node,
graphene_rect_t *frame);
+GVariant * gsk_render_node_serialize_node (GskRenderNode *node);
+GskRenderNode * gsk_render_node_deserialize_node (GskRenderNodeType type, GVariant *variant);
+
double gsk_opacity_node_get_opacity (GskRenderNode *node);
const GskRoundedRect * gsk_border_node_peek_outline (GskRenderNode *node);
float gsk_border_node_get_width (GskRenderNode *node, guint i);
const GdkRGBA * gsk_border_node_peek_color (GskRenderNode *node, guint i);
+GskRenderNode *gsk_cairo_node_new_for_surface (const graphene_rect_t *bounds, cairo_surface_t *surface);
cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node);
GskTexture *gsk_texture_node_get_texture (GskRenderNode *node);