gsk: Add docs and error handling to serialization API

This commit is contained in:
Benjamin Otte 2016-12-23 08:03:36 +01:00
parent 4e866ec06b
commit 4bb0c70c11
7 changed files with 165 additions and 59 deletions

View File

@ -30,6 +30,7 @@ gsk_render_node_unref
GskRenderNodeType
gsk_render_node_get_node_type
gsk_render_node_draw
GskSerializationError
gsk_render_node_serialize
gsk_render_node_deserialize
gsk_render_node_write_to_file
@ -72,6 +73,10 @@ GskRenderNode
GskRenderNodeClass
gsk_render_node_get_type
GSK_TYPE_BLEND_MODE
<SUBSECTION Standard>
gsk_serialization_error_quark
GSK_SERIALIZATION_ERROR
GSK_TYPE_SERIALIZATION_ERROR
</SECTION>
<SECTION>

View File

@ -152,4 +152,21 @@ typedef enum {
GSK_CORNER_BOTTOM_LEFT
} GskCorner;
/**
* GskSerializationError:
* @GSK_SERIALIZATION_UNSUPPORTED_FORMAT: The format can not be
* identified
* @GSK_SERIALIZATION_UNSUPPORTED_VERSION: The version of the data
* is not understood
* @GSK_SERIALIZATION_INVALID_DATA: The given data may not exist in
* a proper serialization
*
* Errors that can happen during (de)serialization.
*/
typedef enum {
GSK_SERIALIZATION_UNSUPPORTED_FORMAT,
GSK_SERIALIZATION_UNSUPPORTED_VERSION,
GSK_SERIALIZATION_INVALID_DATA
} GskSerializationError;
#endif /* __GSK_TYPES_H__ */

View File

@ -65,6 +65,8 @@ G_DEFINE_BOXED_TYPE (GskRenderNode, gsk_render_node,
gsk_render_node_ref,
gsk_render_node_unref)
G_DEFINE_QUARK (gsk-serialization-error-quark, gsk_serialization_error)
static void
gsk_render_node_finalize (GskRenderNode *self)
{
@ -297,6 +299,22 @@ gsk_render_node_draw (GskRenderNode *node,
#define GSK_RENDER_NODE_SERIALIZATION_VERSION 0
#define GSK_RENDER_NODE_SERIALIZATION_ID "GskRenderNode"
/**
* gsk_render_node_serialize:
* @node: a #GskRenderNode
*
* Serializes the @node for later deserialization via
* gsk_render_node_deserialize(). No guarantees are made about the format
* used other than that the same version of GTK+ will be able to deserialize
* the result of a call to gsk_render_node_serialize() and
* gsk_render_node_deserialize() will correctly reject files it cannot open
* that were created with previous versions of GTK+.
*
* The intended use of this functions is testing, benchmarking and debugging.
* The format is not meant as a permanent storage format.
*
* Returns: a #GBytes representing the node.
**/
GBytes *
gsk_render_node_serialize (GskRenderNode *node)
{
@ -353,8 +371,20 @@ gsk_render_node_write_to_file (GskRenderNode *node,
return result;
}
/**
* gsk_render_node_deserialize:
* @bytes: the bytes containing the data
* @error: (allow-none): location to store error or %NULL
*
* Loads data previously created via gsk_render_node_serialize(). For a
* discussion of the supported format, see that function.
*
* Returns: (nullable) (transfer full): a new #GskRenderNode or %NULL on
* error.
**/
GskRenderNode *
gsk_render_node_deserialize (GBytes *bytes)
gsk_render_node_deserialize (GBytes *bytes,
GError **error)
{
char *id_string;
guint32 version, node_type;
@ -366,12 +396,20 @@ gsk_render_node_deserialize (GBytes *bytes)
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;
{
g_set_error (error, GSK_SERIALIZATION_ERROR, GSK_SERIALIZATION_UNSUPPORTED_FORMAT,
"Data not in GskRenderNode serialization format.");
goto out;
}
if (version != GSK_RENDER_NODE_SERIALIZATION_VERSION)
goto out;
{
g_set_error (error, GSK_SERIALIZATION_ERROR, GSK_SERIALIZATION_UNSUPPORTED_VERSION,
"Format version %u not supported.", version);
goto out;
}
node = gsk_render_node_deserialize_node (node_type, node_variant);
node = gsk_render_node_deserialize_node (node_type, node_variant, error);
out:
g_free (id_string);

View File

@ -32,6 +32,8 @@ G_BEGIN_DECLS
#define GSK_IS_RENDER_NODE(obj) ((obj) != NULL)
#define GSK_SERIALIZATION_ERROR (gsk_serialization_error_quark ())
typedef struct _GskRenderNode GskRenderNode;
typedef struct _GskColorStop GskColorStop;
typedef struct _GskShadow GskShadow;
@ -51,7 +53,10 @@ struct _GskShadow
};
GDK_AVAILABLE_IN_3_90
GType gsk_render_node_get_type (void) G_GNUC_CONST;
GType gsk_render_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_90
GQuark gsk_serialization_error_quark (void);
GDK_AVAILABLE_IN_3_90
GskRenderNode * gsk_render_node_ref (GskRenderNode *node);
@ -181,7 +186,8 @@ gboolean gsk_render_node_write_to_file (GskRenderNode *
const char *filename,
GError **error);
GDK_AVAILABLE_IN_3_90
GskRenderNode * gsk_render_node_deserialize (GBytes *bytes);
GskRenderNode * gsk_render_node_deserialize (GBytes *bytes,
GError **error);
G_END_DECLS

View File

@ -26,6 +26,22 @@
#include "gskroundedrectprivate.h"
#include "gsktextureprivate.h"
static gboolean
check_variant_type (GVariant *variant,
const char *type_string,
GError **error)
{
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (type_string)))
{
g_set_error (error, GSK_SERIALIZATION_ERROR, GSK_SERIALIZATION_INVALID_DATA,
"Wrong variant type, got '%s' but needed '%s",
g_variant_get_type_string (variant), type_string);
return FALSE;
}
return TRUE;
}
/*** GSK_COLOR_NODE ***/
typedef struct _GskColorNode GskColorNode;
@ -71,12 +87,13 @@ gsk_color_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_color_node_deserialize (GVariant *variant)
gsk_color_node_deserialize (GVariant *variant,
GError **error)
{
double x, y, w, h;
GdkRGBA color;
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_COLOR_NODE_VARIANT_TYPE)))
if (!check_variant_type (variant, GSK_COLOR_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, GSK_COLOR_NODE_VARIANT_TYPE,
@ -213,14 +230,15 @@ gsk_linear_gradient_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_linear_gradient_node_real_deserialize (GVariant *variant,
gboolean repeating)
gsk_linear_gradient_node_real_deserialize (GVariant *variant,
gboolean repeating,
GError **error)
{
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)))
if (!check_variant_type (variant, GSK_LINEAR_GRADIENT_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, GSK_LINEAR_GRADIENT_NODE_VARIANT_TYPE,
@ -250,15 +268,17 @@ gsk_linear_gradient_node_real_deserialize (GVariant *variant,
}
static GskRenderNode *
gsk_linear_gradient_node_deserialize (GVariant *variant)
gsk_linear_gradient_node_deserialize (GVariant *variant,
GError **error)
{
return gsk_linear_gradient_node_real_deserialize (variant, FALSE);
return gsk_linear_gradient_node_real_deserialize (variant, FALSE, error);
}
static GskRenderNode *
gsk_repeating_linear_gradient_node_deserialize (GVariant *variant)
gsk_repeating_linear_gradient_node_deserialize (GVariant *variant,
GError **error)
{
return gsk_linear_gradient_node_real_deserialize (variant, TRUE);
return gsk_linear_gradient_node_real_deserialize (variant, TRUE, error);
}
static const GskRenderNodeClass GSK_LINEAR_GRADIENT_NODE_CLASS = {
@ -473,12 +493,13 @@ gsk_border_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_border_node_deserialize (GVariant *variant)
gsk_border_node_deserialize (GVariant *variant,
GError **error)
{
double doutline[12], dwidths[4];
GdkRGBA colors[4];
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_BORDER_NODE_VARIANT_TYPE)))
if (!check_variant_type (variant, GSK_BORDER_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, GSK_BORDER_NODE_VARIANT_TYPE,
@ -650,7 +671,8 @@ gsk_texture_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_texture_node_deserialize (GVariant *variant)
gsk_texture_node_deserialize (GVariant *variant,
GError **error)
{
GskRenderNode *node;
GskTexture *texture;
@ -659,7 +681,7 @@ gsk_texture_node_deserialize (GVariant *variant)
GVariant *pixel_variant;
gsize n_pixels;
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_TEXTURE_NODE_VARIANT_TYPE)))
if (!check_variant_type (variant, GSK_TEXTURE_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, "(dddduu@au)",
@ -1152,12 +1174,13 @@ gsk_inset_shadow_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_inset_shadow_node_deserialize (GVariant *variant)
gsk_inset_shadow_node_deserialize (GVariant *variant,
GError **error)
{
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)))
if (!check_variant_type (variant, GSK_INSET_SHADOW_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, GSK_INSET_SHADOW_NODE_VARIANT_TYPE,
@ -1394,12 +1417,13 @@ gsk_outset_shadow_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_outset_shadow_node_deserialize (GVariant *variant)
gsk_outset_shadow_node_deserialize (GVariant *variant,
GError **error)
{
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)))
if (!check_variant_type (variant, GSK_OUTSET_SHADOW_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, GSK_INSET_SHADOW_NODE_VARIANT_TYPE,
@ -1554,7 +1578,8 @@ gsk_cairo_node_serialize (GskRenderNode *node)
const cairo_user_data_key_t gsk_surface_variant_key;
static GskRenderNode *
gsk_cairo_node_deserialize (GVariant *variant)
gsk_cairo_node_deserialize (GVariant *variant,
GError **error)
{
GskRenderNode *result;
cairo_surface_t *surface;
@ -1563,7 +1588,7 @@ gsk_cairo_node_deserialize (GVariant *variant)
GVariant *pixel_variant;
gsize n_pixels;
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_CAIRO_NODE_VARIANT_TYPE)))
if (!check_variant_type (variant, GSK_CAIRO_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, "(dddduu@au)",
@ -1821,7 +1846,8 @@ gsk_container_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_container_node_deserialize (GVariant *variant)
gsk_container_node_deserialize (GVariant *variant,
GError **error)
{
GskRenderNode *result;
GVariantIter iter;
@ -1829,7 +1855,7 @@ gsk_container_node_deserialize (GVariant *variant)
guint32 child_type;
GVariant *child_variant;
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_CONTAINER_NODE_VARIANT_TYPE)))
if (!check_variant_type (variant, GSK_CONTAINER_NODE_VARIANT_TYPE, error))
return NULL;
i = 0;
@ -1838,7 +1864,7 @@ gsk_container_node_deserialize (GVariant *variant)
while (g_variant_iter_loop (&iter, "(uv)", &child_type, &child_variant))
{
children[i] = gsk_render_node_deserialize_node (child_type, child_variant);
children[i] = gsk_render_node_deserialize_node (child_type, child_variant, error);
if (children[i] == NULL)
{
guint j;
@ -1996,7 +2022,8 @@ gsk_transform_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_transform_node_deserialize (GVariant *variant)
gsk_transform_node_deserialize (GVariant *variant,
GError **error)
{
graphene_matrix_t transform;
double mat[16];
@ -2004,7 +2031,7 @@ gsk_transform_node_deserialize (GVariant *variant)
GVariant *child_variant;
GskRenderNode *result, *child;
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_TRANSFORM_NODE_VARIANT_TYPE)))
if (!check_variant_type (variant, GSK_TRANSFORM_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, GSK_TRANSFORM_NODE_VARIANT_TYPE,
@ -2014,7 +2041,7 @@ gsk_transform_node_deserialize (GVariant *variant)
&mat[12], &mat[13], &mat[14], &mat[15],
&child_type, &child_variant);
child = gsk_render_node_deserialize_node (child_type, child_variant);
child = gsk_render_node_deserialize_node (child_type, child_variant, error);
g_variant_unref (child_variant);
if (child == NULL)
@ -2163,21 +2190,22 @@ gsk_opacity_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_opacity_node_deserialize (GVariant *variant)
gsk_opacity_node_deserialize (GVariant *variant,
GError **error)
{
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)))
if (!check_variant_type (variant, GSK_OPACITY_NODE_VARIANT_TYPE, error))
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);
child = gsk_render_node_deserialize_node (child_type, child_variant, error);
g_variant_unref (child_variant);
if (child == NULL)
@ -2311,21 +2339,22 @@ gsk_clip_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_clip_node_deserialize (GVariant *variant)
gsk_clip_node_deserialize (GVariant *variant,
GError **error)
{
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)))
if (!check_variant_type (variant, GSK_CLIP_NODE_VARIANT_TYPE, error))
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);
child = gsk_render_node_deserialize_node (child_type, child_variant, error);
g_variant_unref (child_variant);
if (child == NULL)
@ -2462,14 +2491,15 @@ gsk_rounded_clip_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_rounded_clip_node_deserialize (GVariant *variant)
gsk_rounded_clip_node_deserialize (GVariant *variant,
GError **error)
{
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)))
if (!check_variant_type (variant, GSK_ROUNDED_CLIP_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, GSK_ROUNDED_CLIP_NODE_VARIANT_TYPE,
@ -2478,7 +2508,7 @@ gsk_rounded_clip_node_deserialize (GVariant *variant)
&doutline[8], &doutline[9], &doutline[10], &doutline[11],
&child_type, &child_variant);
child = gsk_render_node_deserialize_node (child_type, child_variant);
child = gsk_render_node_deserialize_node (child_type, child_variant, error);
g_variant_unref (child_variant);
if (child == NULL)
@ -2678,7 +2708,8 @@ gsk_shadow_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_shadow_node_deserialize (GVariant *variant)
gsk_shadow_node_deserialize (GVariant *variant,
GError **error)
{
gsize n_shadows;
guint32 child_type;
@ -2687,13 +2718,13 @@ gsk_shadow_node_deserialize (GVariant *variant)
GVariantIter *iter;
gsize i;
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE (GSK_SHADOW_NODE_VARIANT_TYPE)))
if (!check_variant_type (variant, GSK_SHADOW_NODE_VARIANT_TYPE, error))
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);
child = gsk_render_node_deserialize_node (child_type, child_variant, error);
g_variant_unref (child_variant);
if (child == NULL)
@ -2901,13 +2932,14 @@ gsk_blend_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_blend_node_deserialize (GVariant *variant)
gsk_blend_node_deserialize (GVariant *variant,
GError **error)
{
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)))
if (!check_variant_type (variant, GSK_BLEND_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, GSK_BLEND_NODE_VARIANT_TYPE,
@ -2915,7 +2947,7 @@ gsk_blend_node_deserialize (GVariant *variant)
&top_child_type, &top_child_variant,
&blend_mode);
bottom_child = gsk_render_node_deserialize_node (bottom_child_type, bottom_child_variant);
bottom_child = gsk_render_node_deserialize_node (bottom_child_type, bottom_child_variant, error);
g_variant_unref (bottom_child_variant);
if (bottom_child == NULL)
{
@ -2923,7 +2955,7 @@ gsk_blend_node_deserialize (GVariant *variant)
return NULL;
}
top_child = gsk_render_node_deserialize_node (top_child_type, top_child_variant);
top_child = gsk_render_node_deserialize_node (top_child_type, top_child_variant, error);
g_variant_unref (top_child_variant);
if (top_child == NULL)
{
@ -3071,14 +3103,15 @@ gsk_cross_fade_node_serialize (GskRenderNode *node)
}
static GskRenderNode *
gsk_cross_fade_node_deserialize (GVariant *variant)
gsk_cross_fade_node_deserialize (GVariant *variant,
GError **error)
{
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)))
if (!check_variant_type (variant, GSK_CROSS_FADE_NODE_VARIANT_TYPE, error))
return NULL;
g_variant_get (variant, GSK_CROSS_FADE_NODE_VARIANT_TYPE,
@ -3086,7 +3119,7 @@ gsk_cross_fade_node_deserialize (GVariant *variant)
&end_child_type, &end_child_variant,
&progress);
start_child = gsk_render_node_deserialize_node (start_child_type, start_child_variant);
start_child = gsk_render_node_deserialize_node (start_child_type, start_child_variant, error);
g_variant_unref (start_child_variant);
if (start_child == NULL)
{
@ -3094,7 +3127,7 @@ gsk_cross_fade_node_deserialize (GVariant *variant)
return NULL;
}
end_child = gsk_render_node_deserialize_node (end_child_type, end_child_variant);
end_child = gsk_render_node_deserialize_node (end_child_type, end_child_variant, error);
g_variant_unref (end_child_variant);
if (end_child == NULL)
{
@ -3204,8 +3237,9 @@ static const GskRenderNodeClass *klasses[] = {
};
GskRenderNode *
gsk_render_node_deserialize_node (GskRenderNodeType type,
GVariant *variant)
gsk_render_node_deserialize_node (GskRenderNodeType type,
GVariant *variant,
GError **error)
{
const GskRenderNodeClass *klass;
GskRenderNode *result;
@ -3216,9 +3250,13 @@ gsk_render_node_deserialize_node (GskRenderNodeType type,
klass = NULL;
if (klass == NULL)
return NULL;
{
g_set_error (error, GSK_SERIALIZATION_ERROR, GSK_SERIALIZATION_INVALID_DATA,
"Type %u is not a valid node type", type);
return NULL;
}
result = klass->deserialize (variant);
result = klass->deserialize (variant, error);
return result;
}

View File

@ -35,13 +35,14 @@ struct _GskRenderNodeClass
void (* draw) (GskRenderNode *node,
cairo_t *cr);
GVariant * (* serialize) (GskRenderNode *node);
GskRenderNode * (* deserialize) (GVariant *variant);
GskRenderNode * (* deserialize) (GVariant *variant,
GError **error);
};
GskRenderNode *gsk_render_node_new (const GskRenderNodeClass *node_class, gsize extra_size);
GVariant * gsk_render_node_serialize_node (GskRenderNode *node);
GskRenderNode * gsk_render_node_deserialize_node (GskRenderNodeType type, GVariant *variant);
GskRenderNode * gsk_render_node_deserialize_node (GskRenderNodeType type, GVariant *variant, GError **error);
double gsk_opacity_node_get_opacity (GskRenderNode *node);

View File

@ -51,7 +51,7 @@ main(int argc, char **argv)
}
start = g_get_monotonic_time ();
node = gsk_render_node_deserialize (bytes);
node = gsk_render_node_deserialize (bytes, &error);
end = g_get_monotonic_time ();
if (benchmark)
{
@ -63,7 +63,8 @@ main(int argc, char **argv)
if (node == NULL)
{
g_printerr ("Invalid node file.\n");
g_printerr ("Invalid node file: %s\n", error->message);
g_clear_error (&error);
return 1;
}