diff options
author | Benjamin Otte <otte@redhat.com> | 2016-12-21 05:43:14 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2016-12-22 04:17:27 +0100 |
commit | 524c25b727120421522b9c7652c526aee309c334 (patch) | |
tree | df3d8ca6089f77bb8b5a40b92e4237e866b89eae | |
parent | 8cc77194a3d330da60440ecd074cd3819f09bf15 (diff) | |
download | gtk+-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.c | 50 | ||||
-rw-r--r-- | gsk/gskrendernode.h | 6 | ||||
-rw-r--r-- | gsk/gskrendernodeimpl.c | 927 | ||||
-rw-r--r-- | gsk/gskrendernodeprivate.h | 6 |
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); |