[gtk/wip/ottie/print: 1/2] ottie: Add printing




commit c6e54728a8d80f2d4e7bedd58f54d522d49bfc35
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Dec 27 18:44:26 2020 -0500

    ottie: Add printing
    
    Add and implement ottie_object_print and ottie_creation_to_bytes.

 ottie/meson.build                |   1 +
 ottie/ottiecolorvalue.c          |  17 +++++
 ottie/ottiecolorvalueprivate.h   |   4 +
 ottie/ottiecomposition.c         |  10 +++
 ottie/ottiecompositionprivate.h  |   4 +
 ottie/ottiecreation.c            |  51 +++++++++++++
 ottie/ottiecreation.h            |   3 +
 ottie/ottiedoublevalue.c         |  17 +++++
 ottie/ottiedoublevalueprivate.h  |   5 ++
 ottie/ottieellipseshape.c        |  16 ++++
 ottie/ottiefillshape.c           |  17 +++++
 ottie/ottiegroupshape.c          |  34 +++++++++
 ottie/ottiegroupshapeprivate.h   |   4 +
 ottie/ottiekeyframesimpl.c       |  58 +++++++++++++++
 ottie/ottielayer.c               |  31 +++++++-
 ottie/ottielayerprivate.h        |   3 +
 ottie/ottieobject.c              |  23 ++++++
 ottie/ottieobjectprivate.h       |   8 ++
 ottie/ottieparser.c              |   2 +-
 ottie/ottiepathshape.c           |  16 ++++
 ottie/ottiepathvalue.c           |  66 +++++++++++++++++
 ottie/ottiepathvalueprivate.h    |   5 ++
 ottie/ottiepoint3dvalue.c        |  17 +++++
 ottie/ottiepoint3dvalueprivate.h |   6 ++
 ottie/ottiepointvalue.c          |  17 +++++
 ottie/ottiepointvalueprivate.h   |   5 ++
 ottie/ottieprinter.c             | 155 +++++++++++++++++++++++++++++++++++++++
 ottie/ottieprinterprivate.h      |  72 ++++++++++++++++++
 ottie/ottierectshape.c           |  17 +++++
 ottie/ottieshape.c               |  15 ++++
 ottie/ottieshapelayer.c          |  14 ++++
 ottie/ottiestrokeshape.c         |  20 +++++
 ottie/ottietransform.c           |  21 +++++-
 ottie/ottietrimshape.c           |  17 +++++
 34 files changed, 768 insertions(+), 3 deletions(-)
---
diff --git a/ottie/meson.build b/ottie/meson.build
index 6dc8d1d6fa..9c91630b4c 100644
--- a/ottie/meson.build
+++ b/ottie/meson.build
@@ -28,6 +28,7 @@ ottie_private_sources = files([
   'ottiestrokeshape.c',
   'ottietransform.c',
   'ottietrimshape.c',
+  'ottieprinter.c',
 ])
 
 ottie_public_headers = files([
diff --git a/ottie/ottiecolorvalue.c b/ottie/ottiecolorvalue.c
index 7b81afd1ee..72cfa4c808 100644
--- a/ottie/ottiecolorvalue.c
+++ b/ottie/ottiecolorvalue.c
@@ -22,6 +22,7 @@
 #include "ottiecolorvalueprivate.h"
 
 #include "ottieparserprivate.h"
+#include "ottieprinterprivate.h"
 
 #include <glib/gi18n-lib.h>
 
@@ -69,6 +70,7 @@ ottie_color_value_interpolate (const GdkRGBA *start,
 #define OTTIE_KEYFRAMES_DIMENSIONS 4
 #define OTTIE_KEYFRAMES_PARSE_FUNC ottie_color_value_parse_one
 #define OTTIE_KEYFRAMES_INTERPOLATE_FUNC ottie_color_value_interpolate
+#define OTTIE_KEYFRAMES_PRINT_FUNC ottie_printer_add_color
 #include "ottiekeyframesimpl.c"
 
 void
@@ -147,3 +149,18 @@ ottie_color_value_parse (JsonReader *reader,
   return TRUE;
 }
 
+void
+ottie_color_value_print (OttieColorValue *self,
+                         const char      *name,
+                         OttiePrinter    *printer)
+{
+  ottie_printer_start_object (printer, name);
+
+  ottie_printer_add_boolean (printer, "a", !self->is_static);
+  if (self->is_static)
+    ottie_printer_add_color (printer, "k", &self->static_value);
+  else
+    ottie_color_keyframes_print (self->keyframes, printer);
+
+  ottie_printer_end_object (printer);
+}
diff --git a/ottie/ottiecolorvalueprivate.h b/ottie/ottiecolorvalueprivate.h
index 48998d807a..495e3d8cd1 100644
--- a/ottie/ottiecolorvalueprivate.h
+++ b/ottie/ottiecolorvalueprivate.h
@@ -22,6 +22,7 @@
 
 #include <json-glib/json-glib.h>
 
+#include "ottieprinterprivate.h"
 #include <gdk/gdk.h>
 
 G_BEGIN_DECLS
@@ -48,6 +49,9 @@ void                      ottie_color_value_get                 (OttieColorValue
 gboolean                  ottie_color_value_parse               (JsonReader             *reader,
                                                                  gsize                   offset,
                                                                  gpointer                data);
+void                      ottie_color_value_print               (OttieColorValue        *self,
+                                                                 const char             *name,
+                                                                 OttiePrinter           *printer);
 
 G_END_DECLS
 
diff --git a/ottie/ottiecomposition.c b/ottie/ottiecomposition.c
index 2999451826..7f30bad018 100644
--- a/ottie/ottiecomposition.c
+++ b/ottie/ottiecomposition.c
@@ -276,3 +276,13 @@ ottie_composition_parse_layers (JsonReader *reader,
   return TRUE;
 }
 
+void
+ottie_composition_print (OttiePrinter     *printer,
+                         OttieComposition *composition)
+{
+  for (int i = 0; i < ottie_layer_list_get_size (&composition->layers); i++)
+    {
+      OttieObject *obj = OTTIE_OBJECT (ottie_layer_list_get (&composition->layers, i));
+      ottie_object_print (obj, NULL, printer);
+    }
+}
diff --git a/ottie/ottiecompositionprivate.h b/ottie/ottiecompositionprivate.h
index 7848eb8fa9..9026b5774f 100644
--- a/ottie/ottiecompositionprivate.h
+++ b/ottie/ottiecompositionprivate.h
@@ -21,6 +21,7 @@
 #define __OTTIE_COMPOSITION_PRIVATE_H__
 
 #include "ottielayerprivate.h"
+#include "ottieprinterprivate.h"
 
 #include <json-glib/json-glib.h>
 
@@ -41,6 +42,9 @@ gboolean                ottie_composition_parse_layers      (JsonReader
                                                              gsize                       offset,
                                                              gpointer                    data);
 
+void                    ottie_composition_print             (OttiePrinter               *printer,
+                                                             OttieComposition           *composition);
+
 G_END_DECLS
 
 #endif /* __OTTIE_COMPOSITION_PRIVATE_H__ */
diff --git a/ottie/ottiecreation.c b/ottie/ottiecreation.c
index 94351a275a..9cf558a3d7 100644
--- a/ottie/ottiecreation.c
+++ b/ottie/ottiecreation.c
@@ -24,6 +24,7 @@
 #include "ottielayerprivate.h"
 #include "ottieparserprivate.h"
 #include "ottiecompositionprivate.h"
+#include "ottieprinterprivate.h"
 
 #include <glib/gi18n-lib.h>
 #include <json-glib/json-glib.h>
@@ -758,3 +759,53 @@ ottie_creation_get_composition (OttieCreation *self)
   return self->layers;
 }
 
+static void
+ottie_creation_print (OttiePrinter  *printer,
+                      OttieCreation *self)
+{
+  const char *id;
+  OttieComposition *composition;
+  GHashTableIter iter;
+
+  ottie_printer_start_object (printer, NULL);
+
+  ottie_printer_add_double (printer, "fr", self->frame_rate);
+  ottie_printer_add_double (printer, "w", self->width);
+  ottie_printer_add_double (printer, "h", self->height);
+  ottie_printer_add_string (printer, "nm", self->name);
+  ottie_printer_add_double (printer, "ip", self->start_frame);
+  ottie_printer_add_double (printer, "op", self->end_frame);
+  ottie_printer_add_boolean (printer, "ddd", 0);
+
+  ottie_printer_start_array (printer, "assets");
+  g_hash_table_iter_init (&iter, self->composition_assets);
+  while (g_hash_table_iter_next (&iter, (gpointer *)&id, (gpointer *)&composition))
+    {
+      ottie_printer_start_object (printer, NULL);
+      ottie_printer_add_string (printer, "id", id);
+      ottie_printer_start_array (printer, "layers");
+      ottie_composition_print (printer, composition);
+      ottie_printer_end_array (printer);
+      ottie_printer_end_object (printer);
+    }
+
+  ottie_printer_end_array (printer);
+
+  ottie_printer_start_array (printer, "layers");
+  ottie_composition_print (printer, self->layers);
+  ottie_printer_end_array (printer);
+
+  ottie_printer_end_object (printer);
+}
+
+GBytes *
+ottie_creation_to_bytes (OttieCreation *self)
+{
+  OttiePrinter p;
+
+  ottie_printer_init (&p);
+
+  ottie_creation_print (&p, self);
+
+  return g_string_free_to_bytes (p.str);
+}
diff --git a/ottie/ottiecreation.h b/ottie/ottiecreation.h
index ad795ed8ee..352e0678c9 100644
--- a/ottie/ottiecreation.h
+++ b/ottie/ottiecreation.h
@@ -63,6 +63,9 @@ gboolean                ottie_creation_is_loading               (OttieCreation
 GDK_AVAILABLE_IN_ALL
 gboolean                ottie_creation_is_prepared              (OttieCreation          *self);
 
+GDK_AVAILABLE_IN_ALL
+GBytes *                ottie_creation_to_bytes                 (OttieCreation          *self);
+
 GDK_AVAILABLE_IN_ALL
 const char *            ottie_creation_get_name                 (OttieCreation          *self);
 GDK_AVAILABLE_IN_ALL
diff --git a/ottie/ottiedoublevalue.c b/ottie/ottiedoublevalue.c
index e3897ea033..11ef620aa9 100644
--- a/ottie/ottiedoublevalue.c
+++ b/ottie/ottiedoublevalue.c
@@ -58,6 +58,7 @@ ottie_double_value_interpolate (double start,
 #define OTTIE_KEYFRAMES_ELEMENT_TYPE double
 #define OTTIE_KEYFRAMES_PARSE_FUNC ottie_double_value_parse_value
 #define OTTIE_KEYFRAMES_INTERPOLATE_FUNC ottie_double_value_interpolate
+#define OTTIE_KEYFRAMES_PRINT_FUNC ottie_printer_add_double
 #include "ottiekeyframesimpl.c"
 
 void
@@ -119,3 +120,19 @@ ottie_double_value_parse (JsonReader *reader,
   return TRUE;
 }
 
+void
+ottie_double_value_print (OttieDoubleValue *self,
+                          const char       *name,
+                          OttiePrinter     *printer)
+{
+  ottie_printer_start_object (printer, name);
+
+  ottie_printer_add_boolean (printer, "a", !self->is_static);
+  if (self->is_static)
+    ottie_printer_add_double (printer, "k", self->static_value);
+  else
+    ottie_double_keyframes_print (self->keyframes, printer);
+
+  ottie_printer_end_object (printer);
+}
+
diff --git a/ottie/ottiedoublevalueprivate.h b/ottie/ottiedoublevalueprivate.h
index ed33e9227b..3b0bfd160e 100644
--- a/ottie/ottiedoublevalueprivate.h
+++ b/ottie/ottiedoublevalueprivate.h
@@ -21,6 +21,7 @@
 #define __OTTIE_DOUBLE_VALUE_PRIVATE_H__
 
 #include <json-glib/json-glib.h>
+#include "ottie/ottieprinterprivate.h"
 
 G_BEGIN_DECLS
 
@@ -47,6 +48,10 @@ gboolean                  ottie_double_value_parse              (JsonReader
                                                                  gsize                   offset,
                                                                  gpointer                data);
 
+void                      ottie_double_value_print              (OttieDoubleValue       *self,
+                                                                 const char             *name,
+                                                                 OttiePrinter           *printer);
+
 static inline gboolean
 ottie_double_value_is_static (OttieDoubleValue *self)
 {
diff --git a/ottie/ottieellipseshape.c b/ottie/ottieellipseshape.c
index e26e96b02b..2873b76e84 100644
--- a/ottie/ottieellipseshape.c
+++ b/ottie/ottieellipseshape.c
@@ -85,6 +85,19 @@ ottie_ellipse_shape_render (OttieShape  *shape,
                          gsk_path_builder_free_to_path (builder));
 }
 
+static void
+ottie_ellipse_shape_print (OttieObject  *obj,
+                           OttiePrinter *printer)
+{
+  OttieEllipseShape *self = OTTIE_ELLIPSE_SHAPE (obj);
+
+  OTTIE_OBJECT_CLASS (ottie_ellipse_shape_parent_class)->print (obj, printer);
+
+  ottie_printer_add_double (printer, "d", self->diellipseion);
+  ottie_point_value_print (&self->position, "p", printer);
+  ottie_point_value_print (&self->size, "s", printer);
+}
+
 static void
 ottie_ellipse_shape_dispose (GObject *object)
 {
@@ -99,9 +112,12 @@ ottie_ellipse_shape_dispose (GObject *object)
 static void
 ottie_ellipse_shape_class_init (OttieEllipseShapeClass *klass)
 {
+  OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (klass);
   OttieShapeClass *shape_class = OTTIE_SHAPE_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  oobject_class->print = ottie_ellipse_shape_print;
+
   shape_class->render = ottie_ellipse_shape_render;
 
   gobject_class->dispose = ottie_ellipse_shape_dispose;
diff --git a/ottie/ottiefillshape.c b/ottie/ottiefillshape.c
index f26ca9ee53..65006cbaaf 100644
--- a/ottie/ottiefillshape.c
+++ b/ottie/ottiefillshape.c
@@ -77,6 +77,20 @@ ottie_fill_shape_render (OttieShape  *shape,
   gsk_render_node_unref (color_node);
 }
 
+static void
+ottie_fill_shape_print (OttieObject  *obj,
+                        OttiePrinter *printer)
+{
+  OttieFillShape *self = OTTIE_FILL_SHAPE (obj);
+
+  OTTIE_OBJECT_CLASS (ottie_fill_shape_parent_class)->print (obj, printer);
+
+  ottie_double_value_print (&self->opacity, "o", printer);
+  ottie_color_value_print (&self->color, "c", printer);
+  ottie_printer_add_int (printer, "bm", self->blend_mode);
+  ottie_printer_add_int (printer, "r", self->fill_rule);
+}
+
 static void
 ottie_fill_shape_dispose (GObject *object)
 {
@@ -91,9 +105,12 @@ ottie_fill_shape_dispose (GObject *object)
 static void
 ottie_fill_shape_class_init (OttieFillShapeClass *klass)
 {
+  OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (klass);
   OttieShapeClass *shape_class = OTTIE_SHAPE_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  oobject_class->print = ottie_fill_shape_print;
+
   shape_class->render = ottie_fill_shape_render;
 
   gobject_class->dispose = ottie_fill_shape_dispose;
diff --git a/ottie/ottiegroupshape.c b/ottie/ottiegroupshape.c
index 949dabf26c..ee1e6e3e86 100644
--- a/ottie/ottiegroupshape.c
+++ b/ottie/ottiegroupshape.c
@@ -113,6 +113,19 @@ ottie_group_shape_render (OttieShape  *shape,
   ottie_render_clear (&child_render);
 }
 
+static void
+ottie_group_shape_print (OttieObject  *obj,
+                         OttiePrinter *printer)
+{
+  OttieGroupShape *self = OTTIE_GROUP_SHAPE (obj);
+
+  OTTIE_OBJECT_CLASS (ottie_group_shape_parent_class)->print (obj, printer);
+
+  ottie_printer_add_string (printer, "ty", "gr");
+  ottie_printer_add_int (printer, "bm", self->blend_mode);
+  ottie_group_shape_print_shapes (OTTIE_SHAPE (self), "it", printer);
+}
+
 static void
 ottie_group_shape_dispose (GObject *object)
 {
@@ -126,9 +139,12 @@ ottie_group_shape_dispose (GObject *object)
 static void
 ottie_group_shape_class_init (OttieGroupShapeClass *klass)
 {
+  OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (klass);
   OttieShapeClass *shape_class = OTTIE_SHAPE_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  oobject_class->print = ottie_group_shape_print;
+
   shape_class->render = ottie_group_shape_render;
 
   gobject_class->dispose = ottie_group_shape_dispose;
@@ -245,3 +261,21 @@ ottie_group_shape_parse (JsonReader *reader)
   return self;
 }
 
+void
+ottie_group_shape_print_shapes (OttieShape   *shape,
+                                const char   *name,
+                                OttiePrinter *printer)
+{
+  OttieGroupShape *self = OTTIE_GROUP_SHAPE (shape);
+
+  ottie_printer_start_array (printer, name);
+
+  for (gsize i = 0; i < ottie_shape_list_get_size (&self->shapes); i++)
+    {
+      OttieObject *obj = OTTIE_OBJECT (ottie_shape_list_get (&self->shapes, i));
+      ottie_object_print (obj, NULL, printer);
+    }
+
+  ottie_printer_end_array (printer);
+}
+
diff --git a/ottie/ottiegroupshapeprivate.h b/ottie/ottiegroupshapeprivate.h
index d0f9b02e88..bcb2f89d87 100644
--- a/ottie/ottiegroupshapeprivate.h
+++ b/ottie/ottiegroupshapeprivate.h
@@ -45,6 +45,10 @@ gboolean                ottie_group_shape_parse_shapes          (JsonReader
                                                                  gsize                   offset,
                                                                  gpointer                data);
 
+void                    ottie_group_shape_print_shapes          (OttieShape             *shape,
+                                                                 const char             *name,
+                                                                 OttiePrinter           *printer);
+
 G_END_DECLS
 
 #endif /* __OTTIE_GROUP_SHAPE_PRIVATE_H__ */
diff --git a/ottie/ottiekeyframesimpl.c b/ottie/ottiekeyframesimpl.c
index 255d17e3a4..dcfd224335 100644
--- a/ottie/ottiekeyframesimpl.c
+++ b/ottie/ottiekeyframesimpl.c
@@ -364,6 +364,63 @@ ottie_keyframes(parse) (JsonReader *reader)
   return parse.keyframes;
 }
 
+static inline void
+ottie_keyframes(print_control_point) (OttiePrinter            *printer,
+                                      const char              *name,
+                                      const OttieControlPoint *c)
+{
+  ottie_printer_start_object (printer, name);
+  ottie_printer_indent (printer);
+  g_string_append_printf (printer->str, "\"x\" : [");
+  for (int i = 0; i < OTTIE_KEYFRAMES_DIMENSIONS; i++)
+    {
+      if (i > 0)
+        g_string_append (printer->str, ",");
+      g_string_append_printf (printer->str, " %g", c->x[i]);
+    }
+  g_string_append_printf (printer->str, " ],\n");
+  ottie_printer_indent (printer);
+  g_string_append_printf (printer->str, "\"y\" : [");
+  for (int i = 0; i < OTTIE_KEYFRAMES_DIMENSIONS; i++)
+    {
+      if (i > 0)
+        g_string_append (printer->str, ",");
+      g_string_append_printf (printer->str, " %g", c->x[i]);
+    }
+  g_string_append_printf (printer->str, " ]");
+  printer->has_member = TRUE;
+  ottie_printer_end_object (printer);
+}
+
+#ifdef OTTIE_KEYFRAMES_PRINT_FUNC
+static inline void
+ottie_keyframes(print) (OttieKeyframes *self,
+                        OttiePrinter   *printer)
+{
+  ottie_printer_start_array (printer, "k");
+  for (int i = 0; i < self->n_items; i++)
+    {
+      const OttieKeyframe *keyframe = &self->items[i];
+
+      ottie_printer_start_object (printer, NULL);
+
+#ifdef OTTIE_KEYFRAMES_BY_VALUE
+      OTTIE_KEYFRAMES_PRINT_FUNC (printer, "s", &keyframe->start_value);
+      OTTIE_KEYFRAMES_PRINT_FUNC (printer, "e", &keyframe->end_value);
+#else
+      OTTIE_KEYFRAMES_PRINT_FUNC (printer, "s", keyframe->start_value);
+      OTTIE_KEYFRAMES_PRINT_FUNC (printer, "e", keyframe->end_value);
+#endif
+      ottie_printer_add_double (printer, "t", keyframe->start_time);
+      ottie_keyframes(print_control_point) (printer, "i", &keyframe->in);
+      ottie_keyframes(print_control_point) (printer, "o", &keyframe->out);
+
+      ottie_printer_end_object (printer);
+    }
+  ottie_printer_end_array (printer);
+}
+#endif
+
 #ifndef OTTIE_KEYFRAMES_NO_UNDEF
 
 #undef _T_
@@ -374,6 +431,7 @@ ottie_keyframes(parse) (JsonReader *reader)
 
 #undef OTTIE_KEYFRAMES_COPY_FUNC
 #undef OTTIE_KEYFRAMES_PARSE_FUNC
+#undef OTTIE_KEYFRAMES_PRINT_FUNC
 #undef OTTIE_KEYFRAMES_BY_VALUE
 #undef OTTIE_KEYFRAMES_ELEMENT_TYPE
 #undef OTTIE_KEYFRAMES_FREE_FUNC
diff --git a/ottie/ottielayer.c b/ottie/ottielayer.c
index df13a08d6e..0effae466d 100644
--- a/ottie/ottielayer.c
+++ b/ottie/ottielayer.c
@@ -51,6 +51,33 @@ ottie_layer_default_render (OttieLayer  *self,
 {
 }
 
+static void
+ottie_layer_print (OttieObject  *obj,
+                   OttiePrinter *printer)
+{
+  OttieLayer *self = OTTIE_LAYER (obj);
+
+  OTTIE_OBJECT_CLASS (ottie_layer_parent_class)->print (obj, printer);
+
+  if (self->auto_orient != FALSE)
+    ottie_printer_add_boolean (printer, "ao", self->auto_orient);
+  if (self->blend_mode != GSK_BLEND_MODE_DEFAULT)
+    ottie_printer_add_int (printer, "bm", self->blend_mode);
+  if (self->layer_name != NULL)
+    ottie_printer_add_string (printer, "ln", self->layer_name);
+  ottie_object_print (OTTIE_OBJECT (self->transform), "ks", printer);
+  ottie_printer_add_double (printer, "ip", self->start_frame);
+  ottie_printer_add_int (printer, "op", self->end_frame);
+  if (self->index != OTTIE_INT_UNSET)
+    ottie_printer_add_int (printer, "ind", self->index);
+  if (self->parent_index != OTTIE_INT_UNSET)
+    ottie_printer_add_int (printer, "parent", self->parent_index);
+  ottie_printer_add_double (printer, "st", self->start_time);
+  if (self->stretch != 1)
+    ottie_printer_add_double (printer, "sr", self->stretch);
+  ottie_printer_add_boolean (printer, "ddd", FALSE);
+}
+
 static void
 ottie_layer_dispose (GObject *object)
 {
@@ -66,11 +93,14 @@ static void
 ottie_layer_class_init (OttieLayerClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (klass);
 
   klass->update = ottie_layer_default_update;
   klass->render = ottie_layer_default_render;
 
   gobject_class->dispose = ottie_layer_dispose;
+
+  oobject_class->print = ottie_layer_print;
 }
 
 static void
@@ -109,4 +139,3 @@ ottie_layer_render (OttieLayer  *self,
 
   ottie_render_end_object (render, OTTIE_OBJECT (self));
 }
-
diff --git a/ottie/ottielayerprivate.h b/ottie/ottielayerprivate.h
index 21b2eef7ef..4a60ea6463 100644
--- a/ottie/ottielayerprivate.h
+++ b/ottie/ottielayerprivate.h
@@ -24,6 +24,7 @@
 #include "ottie/ottieobjectprivate.h"
 #include "ottie/ottieparserprivate.h"
 #include "ottie/ottierenderprivate.h"
+#include "ottie/ottieprinterprivate.h"
 
 G_BEGIN_DECLS
 
@@ -61,6 +62,8 @@ struct _OttieLayerClass
   void                  (* render)                           (OttieLayer                *layer,
                                                               OttieRender               *render,
                                                               double                     timestamp);
+  void                 (* print)                             (OttieLayer                *layer,
+                                                              OttiePrinter              *printer);
 };
 
 GType                   ottie_layer_get_type                 (void) G_GNUC_CONST;
diff --git a/ottie/ottieobject.c b/ottie/ottieobject.c
index 101464f4af..a8065c877d 100644
--- a/ottie/ottieobject.c
+++ b/ottie/ottieobject.c
@@ -104,6 +104,17 @@ ottie_object_dispose (GObject *object)
   G_OBJECT_CLASS (ottie_object_parent_class)->dispose (object);
 }
 
+static void
+ottie_object_default_print (OttieObject  *self,
+                            OttiePrinter *printer)
+{
+  if (self->name != NULL)
+    ottie_printer_add_string (printer, "nm", self->name);
+
+  if (self->match_name != NULL)
+    ottie_printer_add_string (printer, "mn", self->match_name);
+}
+
 static void
 ottie_object_class_init (OttieObjectClass *class)
 {
@@ -113,6 +124,8 @@ ottie_object_class_init (OttieObjectClass *class)
   gobject_class->get_property = ottie_object_get_property;
   gobject_class->dispose = ottie_object_dispose;
 
+  class->print = ottie_object_default_print;
+
   properties[PROP_NAME] =
     g_param_spec_string ("name",
                          P_("Name"),
@@ -181,4 +194,14 @@ ottie_object_get_match_name (OttieObject *self)
   return self->match_name;
 }
 
+void
+ottie_object_print (OttieObject  *self,
+                    const char   *name,
+                    OttiePrinter *printer)
+{
+  ottie_printer_start_object (printer, name);
 
+  OTTIE_OBJECT_GET_CLASS (self)->print (self, printer);
+
+  ottie_printer_end_object (printer);
+}
diff --git a/ottie/ottieobjectprivate.h b/ottie/ottieobjectprivate.h
index 541436f315..fc039d461a 100644
--- a/ottie/ottieobjectprivate.h
+++ b/ottie/ottieobjectprivate.h
@@ -23,6 +23,7 @@
 #include <glib-object.h>
 
 #include "ottie/ottietypesprivate.h"
+#include "ottie/ottieprinterprivate.h"
 
 G_BEGIN_DECLS
 
@@ -46,6 +47,9 @@ struct _OttieObject
 struct _OttieObjectClass
 {
   GObjectClass parent_class;
+
+  void (*print) (OttieObject  *self,
+                 OttiePrinter *printer);
 };
 
 GType                   ottie_object_get_type                   (void) G_GNUC_CONST;
@@ -58,6 +62,10 @@ void                    ottie_object_set_match_name             (OttieObject
                                                                  const char             *match_name);
 const char *            ottie_object_get_match_name             (OttieObject            *self);
 
+void                    ottie_object_print                      (OttieObject            *self,
+                                                                 const char             *name,
+                                                                 OttiePrinter           *printer);
+
 #define OTTIE_PARSE_OPTIONS_OBJECT \
     { "nm", ottie_parser_option_string, G_STRUCT_OFFSET (OttieObject, name) }, \
     { "mn", ottie_parser_option_string, G_STRUCT_OFFSET (OttieObject, match_name) }
diff --git a/ottie/ottieparser.c b/ottie/ottieparser.c
index c0be81c951..03a8b9c00a 100644
--- a/ottie/ottieparser.c
+++ b/ottie/ottieparser.c
@@ -581,7 +581,7 @@ ottie_parser_option_transform (JsonReader *reader,
   t = ottie_transform_parse (reader);
   if (t == NULL)
     return FALSE;
-  
+
   target = (OttieShape **) ((guint8 *) data + offset);
 
   g_clear_object (target);
diff --git a/ottie/ottiepathshape.c b/ottie/ottiepathshape.c
index b8e9d04de2..45e12cff2b 100644
--- a/ottie/ottiepathshape.c
+++ b/ottie/ottiepathshape.c
@@ -55,6 +55,19 @@ ottie_path_shape_render (OttieShape  *shape,
                                                self->direction));
 }
 
+static void
+ottie_path_shape_print (OttieObject  *obj,
+                        OttiePrinter *printer)
+{
+  OttiePathShape *self = OTTIE_PATH_SHAPE (obj);
+
+  OTTIE_OBJECT_CLASS (ottie_path_shape_parent_class)->print (obj, printer);
+
+  ottie_printer_add_string (printer, "ty", "sh");
+  ottie_printer_add_double (printer, "d", self->direction);
+  ottie_path_value_print (&self->path, "ks", printer);
+}
+
 static void
 ottie_path_shape_dispose (GObject *object)
 {
@@ -68,9 +81,12 @@ ottie_path_shape_dispose (GObject *object)
 static void
 ottie_path_shape_class_init (OttiePathShapeClass *klass)
 {
+  OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (klass);
   OttieShapeClass *shape_class = OTTIE_SHAPE_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  oobject_class->print = ottie_path_shape_print;
+
   shape_class->render = ottie_path_shape_render;
 
   gobject_class->dispose = ottie_path_shape_dispose;
diff --git a/ottie/ottiepathvalue.c b/ottie/ottiepathvalue.c
index 7099ea26c7..617691ebf4 100644
--- a/ottie/ottiepathvalue.c
+++ b/ottie/ottiepathvalue.c
@@ -22,6 +22,7 @@
 #include "ottiepathvalueprivate.h"
 
 #include "ottieparserprivate.h"
+#include "ottie/ottieprinterprivate.h"
 
 #include <glib/gi18n-lib.h>
 
@@ -289,6 +290,7 @@ ottie_path_interpolate (const OttiePath *start,
 #define OTTIE_KEYFRAMES_FREE_FUNC ottie_path_unref
 #define OTTIE_KEYFRAMES_PARSE_FUNC ottie_path_value_parse_one
 #define OTTIE_KEYFRAMES_INTERPOLATE_FUNC ottie_path_interpolate
+#define OTTIE_KEYFRAMES_PRINT_FUNC ottie_printer_add_path
 #include "ottiekeyframesimpl.c"
 
 void
@@ -400,3 +402,67 @@ ottie_path_value_parse (JsonReader *reader,
   return TRUE;
 }
 
+static inline void
+ottie_printer_add_curves (OttiePrinter *printer,
+                          OttieContour *contour,
+                          const char   *name,
+                          gsize         offset)
+{
+  ottie_printer_start_array (printer, name);
+  for (int i = 0; i < contour->n_curves; i++)
+    {
+      OttieCurve *curve = &contour->curves[i];
+      double *p = (double *)(curve + offset);
+
+      ottie_printer_start_array (printer, NULL);
+      ottie_printer_indent (printer);
+      g_string_append_printf (printer->str, "%g,\n", p[0]);
+      ottie_printer_indent (printer);
+      g_string_append_printf (printer->str, "%g\n", p[1]);
+      ottie_printer_end_array (printer);
+    }
+  ottie_printer_end_array (printer);
+}
+
+static void
+ottie_printer_add_contour (OttiePrinter *printer,
+                           OttieContour *contour)
+{
+  ottie_printer_start_object (printer, NULL);
+  ottie_printer_add_boolean (printer, "c", contour->closed);
+  ottie_printer_add_curves (printer, contour, "v", G_STRUCT_OFFSET (OttieCurve, point));
+  ottie_printer_add_curves (printer, contour, "i", G_STRUCT_OFFSET (OttieCurve, in));
+  ottie_printer_add_curves (printer, contour, "o", G_STRUCT_OFFSET (OttieCurve, out));
+  ottie_printer_end_object (printer);
+}
+
+void
+ottie_printer_add_path (OttiePrinter *printer,
+                        const char   *name,
+                        gpointer      value)
+{
+  OttiePath *path = value;
+
+  ottie_printer_start_array (printer, name);
+  for (int i = 0; i < path->n_contours; i++)
+    ottie_printer_add_contour (printer, path->contours[i]);
+  ottie_printer_end_array (printer);
+  printer->has_member = TRUE;
+}
+
+void
+ottie_path_value_print (OttiePathValue *self,
+                        const char     *name,
+                        OttiePrinter   *printer)
+{
+  ottie_printer_start_object (printer, name);
+
+  ottie_printer_add_boolean (printer, "a", !self->is_static);
+  if (self->is_static)
+    ottie_printer_add_path (printer, "k", self->static_value);
+  else
+    ottie_path_keyframes_print (self->keyframes, printer);
+
+  ottie_printer_end_object (printer);
+}
+
diff --git a/ottie/ottiepathvalueprivate.h b/ottie/ottiepathvalueprivate.h
index a7035cc783..b1130cdd83 100644
--- a/ottie/ottiepathvalueprivate.h
+++ b/ottie/ottiepathvalueprivate.h
@@ -23,6 +23,7 @@
 #include <json-glib/json-glib.h>
 
 #include <gsk/gsk.h>
+#include "ottieprinterprivate.h"
 
 G_BEGIN_DECLS
 
@@ -47,6 +48,10 @@ GskPath *                 ottie_path_value_get                  (OttiePathValue
 gboolean                  ottie_path_value_parse                (JsonReader             *reader,
                                                                  gsize                   offset,
                                                                  gpointer                data);
+void                      ottie_path_value_print                (OttiePathValue         *self,
+                                                                 const char             *name,
+                                                                 OttiePrinter           *printer);
+
 
 G_END_DECLS
 
diff --git a/ottie/ottiepoint3dvalue.c b/ottie/ottiepoint3dvalue.c
index 37ee149e90..e6b7ed3e9c 100644
--- a/ottie/ottiepoint3dvalue.c
+++ b/ottie/ottiepoint3dvalue.c
@@ -22,6 +22,7 @@
 #include "ottiepoint3dvalueprivate.h"
 
 #include "ottieparserprivate.h"
+#include "ottieprinterprivate.h"
 
 #include <glib/gi18n-lib.h>
 
@@ -54,6 +55,7 @@ ottie_point3d_value_parse_value (JsonReader *reader,
 #define OTTIE_KEYFRAMES_DIMENSIONS 3
 #define OTTIE_KEYFRAMES_PARSE_FUNC ottie_point3d_value_parse_value
 #define OTTIE_KEYFRAMES_INTERPOLATE_FUNC graphene_point3d_interpolate
+#define OTTIE_KEYFRAMES_PRINT_FUNC ottie_printer_add_point3d
 #include "ottiekeyframesimpl.c"
 
 void
@@ -152,3 +154,18 @@ ottie_point3d_value_parse (JsonReader *reader,
   return TRUE;
 }
 
+void
+ottie_point3d_value_print (OttiePoint3DValue *self,
+                           const char        *name,
+                           OttiePrinter      *printer)
+{
+  ottie_printer_start_object (printer, name);
+
+  ottie_printer_add_boolean (printer, "a", !self->is_static);
+  if (self->is_static)
+    ottie_printer_add_point3d (printer, "k", &self->static_value);
+  else
+    ottie_point_keyframes_print (self->keyframes, printer);
+
+  ottie_printer_end_object (printer);
+}
diff --git a/ottie/ottiepoint3dvalueprivate.h b/ottie/ottiepoint3dvalueprivate.h
index f735f06b95..6f3c37bf25 100644
--- a/ottie/ottiepoint3dvalueprivate.h
+++ b/ottie/ottiepoint3dvalueprivate.h
@@ -22,6 +22,7 @@
 
 #include <json-glib/json-glib.h>
 #include <graphene.h>
+#include "ottieprinterprivate.h"
 
 G_BEGIN_DECLS
 
@@ -48,6 +49,11 @@ gboolean                ottie_point3d_value_parse               (JsonReader
                                                                  float                           
default_value,
                                                                  gsize                           offset,
                                                                  gpointer                        data);
+void                    ottie_point3d_value_print               (OttiePoint3DValue              *self,
+                                                                 const char                     *name,
+                                                                 OttiePrinter                   *printer);
+
+
 
 G_END_DECLS
 
diff --git a/ottie/ottiepointvalue.c b/ottie/ottiepointvalue.c
index 875c4c1a24..d481b57ed7 100644
--- a/ottie/ottiepointvalue.c
+++ b/ottie/ottiepointvalue.c
@@ -22,6 +22,7 @@
 #include "ottiepointvalueprivate.h"
 
 #include "ottieparserprivate.h"
+#include "ottieprinterprivate.h"
 
 #include <glib/gi18n-lib.h>
 
@@ -50,6 +51,7 @@ ottie_point_value_parse_value (JsonReader *reader,
 #define OTTIE_KEYFRAMES_DIMENSIONS 2
 #define OTTIE_KEYFRAMES_PARSE_FUNC ottie_point_value_parse_value
 #define OTTIE_KEYFRAMES_INTERPOLATE_FUNC graphene_point_interpolate
+#define OTTIE_KEYFRAMES_PRINT_FUNC ottie_printer_add_point
 #include "ottiekeyframesimpl.c"
 
 void
@@ -138,3 +140,18 @@ ottie_point_value_parse (JsonReader *reader,
   return TRUE;
 }
 
+void
+ottie_point_value_print (OttiePointValue *self,
+                         const char      *name,
+                         OttiePrinter    *printer)
+{
+  ottie_printer_start_object (printer, name);
+
+  ottie_printer_add_boolean (printer, "a", !self->is_static);
+  if (self->is_static)
+    ottie_printer_add_point (printer, "k", &self->static_value);
+  else
+    ottie_point_keyframes_print (self->keyframes, printer);
+
+  ottie_printer_end_object (printer);
+}
diff --git a/ottie/ottiepointvalueprivate.h b/ottie/ottiepointvalueprivate.h
index 635fa78d6d..e8a3ec6fb5 100644
--- a/ottie/ottiepointvalueprivate.h
+++ b/ottie/ottiepointvalueprivate.h
@@ -22,6 +22,7 @@
 
 #include <json-glib/json-glib.h>
 #include <graphene.h>
+#include "ottieprinterprivate.h"
 
 G_BEGIN_DECLS
 
@@ -47,6 +48,10 @@ void                    ottie_point_value_get                   (OttiePointValue
 gboolean                ottie_point_value_parse                 (JsonReader                     *reader,
                                                                  gsize                           offset,
                                                                  gpointer                        data);
+void                    ottie_point_value_print                 (OttiePointValue                *self,
+                                                                 const char                     *name,
+                                                                 OttiePrinter                   *printer);
+
 
 G_END_DECLS
 
diff --git a/ottie/ottieprinter.c b/ottie/ottieprinter.c
new file mode 100644
index 0000000000..5a6c00b3f9
--- /dev/null
+++ b/ottie/ottieprinter.c
@@ -0,0 +1,155 @@
+#include "ottieprinterprivate.h"
+
+void
+ottie_printer_init (OttiePrinter *printer)
+{
+  printer->str = g_string_new ("");
+  printer->indent_level = 0;
+  printer->has_member = FALSE;
+}
+
+#define INDENT 2
+
+void
+ottie_printer_indent (OttiePrinter *printer)
+{
+  if (printer->indent_level > 0)
+    g_string_append_printf (printer->str, "%*s", printer->indent_level * INDENT, " ");
+}
+
+void
+ottie_printer_start_object (OttiePrinter *printer,
+                            const char   *name)
+{
+  if (printer->has_member)
+    g_string_append (printer->str, ",\n");
+  ottie_printer_indent (printer);
+  if (name)
+    g_string_append_printf (printer->str, "\"%s\" : ", name);
+  g_string_append (printer->str, "{\n");
+  printer->indent_level++;
+  printer->has_member = FALSE;
+}
+
+void
+ottie_printer_end_object (OttiePrinter *printer)
+{
+  printer->indent_level--;
+  if (printer->has_member)
+    g_string_append (printer->str, "\n");
+  ottie_printer_indent (printer);
+  g_string_append (printer->str, "}");
+  printer->has_member = TRUE;
+}
+
+void
+ottie_printer_start_array (OttiePrinter *printer,
+                           const char   *name)
+{
+  if (printer->has_member)
+    g_string_append (printer->str, ",\n");
+  ottie_printer_indent (printer);
+  if (name)
+    g_string_append_printf (printer->str, "\"%s\" : ", name);
+  g_string_append (printer->str, "[\n");
+  printer->indent_level++;
+  printer->has_member = FALSE;
+}
+
+void
+ottie_printer_end_array (OttiePrinter *printer)
+{
+  printer->indent_level--;
+  if (printer->has_member)
+    g_string_append (printer->str, "\n");
+  ottie_printer_indent (printer);
+  g_string_append (printer->str, "]");
+  printer->has_member = TRUE;
+}
+
+void
+ottie_printer_add_double (OttiePrinter *printer,
+                          const char   *name,
+                          double        value)
+{
+  if (printer->has_member)
+    g_string_append (printer->str, ",\n");
+  ottie_printer_indent (printer);
+  g_string_append_printf (printer->str, "\"%s\" : %g", name, value);
+  printer->has_member = TRUE;
+}
+
+void
+ottie_printer_add_int (OttiePrinter *printer,
+                       const char   *name,
+                       int           value)
+{
+  if (printer->has_member)
+    g_string_append (printer->str, ",\n");
+  ottie_printer_indent (printer);
+  g_string_append_printf (printer->str, "\"%s\" : %d", name, value);
+  printer->has_member = TRUE;
+}
+
+void
+ottie_printer_add_boolean (OttiePrinter *printer,
+                           const char   *name,
+                           gboolean      value)
+{
+  if (printer->has_member)
+    g_string_append (printer->str, ",\n");
+  ottie_printer_indent (printer);
+  g_string_append_printf (printer->str, "\"%s\" : %d", name, value);
+  printer->has_member = TRUE;
+}
+
+void
+ottie_printer_add_string (OttiePrinter *printer,
+                          const char   *name,
+                          const char   *value)
+{
+  if (printer->has_member)
+    g_string_append (printer->str, ",\n");
+  ottie_printer_indent (printer);
+  g_string_append_printf (printer->str, "\"%s\" : \"%s\"", name, value);
+  printer->has_member = TRUE;
+}
+
+void
+ottie_printer_add_color (OttiePrinter  *printer,
+                         const char    *name,
+                         const GdkRGBA *value)
+{
+  if (printer->has_member)
+    g_string_append (printer->str, ",\n");
+  ottie_printer_indent (printer);
+  g_string_append_printf (printer->str, "\"%s\" : [ %g, %g, %g ]",
+                          name, value->red, value->green, value->blue);
+  printer->has_member = TRUE;
+}
+
+void
+ottie_printer_add_point (OttiePrinter           *printer,
+                         const char             *name,
+                         const graphene_point_t *value)
+{
+  if (printer->has_member)
+    g_string_append (printer->str, ",\n");
+  ottie_printer_indent (printer);
+  g_string_append_printf (printer->str, "\"%s\" : [ %g, %g ]",
+                          name, value->x, value->y);
+  printer->has_member = TRUE;
+}
+
+void
+ottie_printer_add_point3d (OttiePrinter             *printer,
+                           const char               *name,
+                           const graphene_point3d_t *value)
+{
+  if (printer->has_member)
+    g_string_append (printer->str, ",\n");
+  ottie_printer_indent (printer);
+  g_string_append_printf (printer->str, "\"%s\" : [ %g, %g, %g ]",
+                          name, value->x, value->y, value->z);
+  printer->has_member = TRUE;
+}
diff --git a/ottie/ottieprinterprivate.h b/ottie/ottieprinterprivate.h
new file mode 100644
index 0000000000..f584e04ec8
--- /dev/null
+++ b/ottie/ottieprinterprivate.h
@@ -0,0 +1,72 @@
+
+/*
+ * Copyright © 2020 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __OTTIE_PRINTER_PRIVATE_H__
+#define __OTTIE_PRINTER_PRIVATE_H__
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <graphene.h>
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+  GString *str;
+  int indent_level;
+  int has_member;
+} OttiePrinter;
+
+void ottie_printer_init               (OttiePrinter             *printer);
+void ottie_printer_indent             (OttiePrinter             *printer);
+void ottie_printer_start_object       (OttiePrinter             *printer,
+                                       const char               *name);
+void ottie_printer_end_object         (OttiePrinter             *printer);
+void ottie_printer_start_array        (OttiePrinter             *printer,
+                                       const char               *name);
+void ottie_printer_end_array          (OttiePrinter             *printer);
+void ottie_printer_add_double         (OttiePrinter             *printer,
+                                       const char               *name,
+                                       double                    value);
+void ottie_printer_add_int            (OttiePrinter             *printer,
+                                       const char               *name,
+                                       int                       value);
+void ottie_printer_add_boolean        (OttiePrinter             *printer,
+                                       const char               *name,
+                                       gboolean                  value);
+void ottie_printer_add_string         (OttiePrinter             *printer,
+                                       const char               *name,
+                                       const char               *value);
+void ottie_printer_add_color          (OttiePrinter             *printer,
+                                       const char               *name,
+                                       const GdkRGBA            *value);
+void ottie_printer_add_point          (OttiePrinter             *printer,
+                                       const char               *name,
+                                       const graphene_point_t   *value);
+void ottie_printer_add_point3d        (OttiePrinter             *printer,
+                                       const char               *name,
+                                       const graphene_point3d_t *value);
+void ottie_printer_add_path           (OttiePrinter             *printer,
+                                       const char               *name,
+                                       gpointer                  value);
+
+G_END_DECLS
+
+#endif /* __OTTIE_PRINTER_PRIVATE_H__ */
diff --git a/ottie/ottierectshape.c b/ottie/ottierectshape.c
index 8301ea775c..86393141ec 100644
--- a/ottie/ottierectshape.c
+++ b/ottie/ottierectshape.c
@@ -163,6 +163,20 @@ ottie_rect_shape_render (OttieShape  *shape,
                          gsk_path_builder_free_to_path (builder));
 }
 
+static void
+ottie_rect_shape_print (OttieObject  *obj,
+                        OttiePrinter *printer)
+{
+  OttieRectShape *self = OTTIE_RECT_SHAPE (obj);
+
+  OTTIE_OBJECT_CLASS (ottie_rect_shape_parent_class)->print (obj, printer);
+
+  ottie_printer_add_double (printer, "d", self->direction);
+  ottie_point_value_print (&self->position, "p", printer);
+  ottie_point_value_print (&self->size, "s", printer);
+  ottie_double_value_print (&self->rounded, "r", printer);
+}
+
 static void
 ottie_rect_shape_dispose (GObject *object)
 {
@@ -178,9 +192,12 @@ ottie_rect_shape_dispose (GObject *object)
 static void
 ottie_rect_shape_class_init (OttieRectShapeClass *klass)
 {
+  OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (klass);
   OttieShapeClass *shape_class = OTTIE_SHAPE_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  oobject_class->print = ottie_rect_shape_print;
+
   shape_class->render = ottie_rect_shape_render;
 
   gobject_class->dispose = ottie_rect_shape_dispose;
diff --git a/ottie/ottieshape.c b/ottie/ottieshape.c
index fdfb6b922a..382f843a0a 100644
--- a/ottie/ottieshape.c
+++ b/ottie/ottieshape.c
@@ -44,6 +44,18 @@
  */
 G_DEFINE_TYPE (OttieShape, ottie_shape, OTTIE_TYPE_OBJECT)
 
+static void
+ottie_shape_print (OttieObject  *obj,
+                   OttiePrinter *printer)
+{
+  OttieShape *self = OTTIE_SHAPE (obj);
+
+  OTTIE_OBJECT_CLASS (ottie_shape_parent_class)->print (obj, printer);
+
+  if (self->hidden)
+    ottie_printer_add_boolean (printer, "hd", self->hidden);
+}
+
 static void
 ottie_shape_dispose (GObject *object)
 {
@@ -56,8 +68,11 @@ static void
 ottie_shape_class_init (OttieShapeClass *class)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (class);
 
   gobject_class->dispose = ottie_shape_dispose;
+
+  oobject_class->print = ottie_shape_print;
 }
 
 static void
diff --git a/ottie/ottieshapelayer.c b/ottie/ottieshapelayer.c
index 2d76fb048d..fbf43a3f2e 100644
--- a/ottie/ottieshapelayer.c
+++ b/ottie/ottieshapelayer.c
@@ -58,6 +58,17 @@ ottie_shape_layer_render (OttieLayer  *layer,
                       timestamp);
 }
 
+static void
+ottie_shape_layer_print (OttieObject  *obj,
+                         OttiePrinter *printer)
+{
+  OttieShapeLayer *self = OTTIE_SHAPE_LAYER (obj);
+
+  OTTIE_OBJECT_CLASS (ottie_shape_layer_parent_class)->print (obj, printer);
+
+  ottie_group_shape_print_shapes (self->shapes, "shapes", printer);
+}
+
 static void
 ottie_shape_layer_dispose (GObject *object)
 {
@@ -71,9 +82,12 @@ ottie_shape_layer_dispose (GObject *object)
 static void
 ottie_shape_layer_class_init (OttieShapeLayerClass *klass)
 {
+  OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (klass);
   OttieLayerClass *layer_class = OTTIE_LAYER_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  oobject_class->print = ottie_shape_layer_print;
+
   layer_class->render = ottie_shape_layer_render;
 
   gobject_class->dispose = ottie_shape_layer_dispose;
diff --git a/ottie/ottiestrokeshape.c b/ottie/ottiestrokeshape.c
index 38de557823..2fc691c902 100644
--- a/ottie/ottiestrokeshape.c
+++ b/ottie/ottiestrokeshape.c
@@ -91,6 +91,23 @@ ottie_stroke_shape_render (OttieShape  *shape,
   gsk_stroke_free (stroke);
 }
 
+static void
+ottie_stroke_shape_print (OttieObject  *obj,
+                          OttiePrinter *printer)
+{
+  OttieStrokeShape *self = OTTIE_STROKE_SHAPE (obj);
+
+  OTTIE_OBJECT_CLASS (ottie_stroke_shape_parent_class)->print (obj, printer);
+
+  ottie_double_value_print (&self->line_width, "w", printer);
+  ottie_double_value_print (&self->opacity, "o", printer);
+  ottie_color_value_print (&self->color, "c", printer);
+  ottie_printer_add_int (printer, "lc", self->line_cap);
+  ottie_printer_add_int (printer, "lj", self->line_join);
+  ottie_printer_add_double (printer, "ml", self->miter_limit);
+  ottie_printer_add_int (printer, "bm", self->blend_mode);
+}
+
 static void
 ottie_stroke_shape_dispose (GObject *object)
 {
@@ -106,9 +123,12 @@ ottie_stroke_shape_dispose (GObject *object)
 static void
 ottie_stroke_shape_class_init (OttieStrokeShapeClass *klass)
 {
+  OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (klass);
   OttieShapeClass *shape_class = OTTIE_SHAPE_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  oobject_class->print = ottie_stroke_shape_print;
+
   shape_class->render = ottie_stroke_shape_render;
 
   gobject_class->dispose = ottie_stroke_shape_dispose;
diff --git a/ottie/ottietransform.c b/ottie/ottietransform.c
index cfd8c2aeb2..bd8ebe9168 100644
--- a/ottie/ottietransform.c
+++ b/ottie/ottietransform.c
@@ -62,6 +62,23 @@ ottie_transform_render (OttieShape  *shape,
   gsk_transform_unref (transform);
 }
 
+static void
+ottie_transform_print (OttieObject  *obj,
+                       OttiePrinter *printer)
+{
+  OttieTransform *self = OTTIE_TRANSFORM (obj);
+
+  OTTIE_OBJECT_CLASS (ottie_transform_parent_class)->print (obj, printer);
+
+  ottie_double_value_print (&self->opacity, "o", printer);
+  ottie_double_value_print (&self->rotation, "r", printer);
+  ottie_double_value_print (&self->skew, "sk", printer);
+  ottie_double_value_print (&self->skew_angle, "sa", printer);
+  ottie_point3d_value_print (&self->anchor, "a", printer);
+  ottie_point3d_value_print (&self->position, "p", printer);
+  ottie_point3d_value_print (&self->scale, "s", printer);
+}
+
 static void
 ottie_transform_dispose (GObject *object)
 {
@@ -89,9 +106,12 @@ ottie_transform_finalize (GObject *object)
 static void
 ottie_transform_class_init (OttieTransformClass *klass)
 {
+  OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (klass);
   OttieShapeClass *shape_class = OTTIE_SHAPE_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  oobject_class->print = ottie_transform_print;
+
   shape_class->render = ottie_transform_render;
 
   gobject_class->finalize = ottie_transform_finalize;
@@ -126,7 +146,6 @@ ottie_transform_value_parse_scale (JsonReader *reader,
   return ottie_point3d_value_parse (reader, 100, offset, data);
 }
 
-
 OttieShape *
 ottie_transform_parse (JsonReader *reader)
 {
diff --git a/ottie/ottietrimshape.c b/ottie/ottietrimshape.c
index 7791e2a121..816da6aa4a 100644
--- a/ottie/ottietrimshape.c
+++ b/ottie/ottietrimshape.c
@@ -129,6 +129,20 @@ ottie_trim_shape_render (OttieShape  *shape,
     }
 }
 
+static void
+ottie_trim_shape_print (OttieObject  *obj,
+                        OttiePrinter *printer)
+{
+  OttieTrimShape *self = OTTIE_TRIM_SHAPE (obj);
+
+  OTTIE_OBJECT_CLASS (ottie_trim_shape_parent_class)->print (obj, printer);
+
+  ottie_double_value_print (&self->start, "s", printer);
+  ottie_double_value_print (&self->end, "e", printer);
+  ottie_double_value_print (&self->offset, "o", printer);
+  ottie_printer_add_int (printer, "m", self->mode);
+}
+
 static void
 ottie_trim_shape_dispose (GObject *object)
 {
@@ -144,9 +158,12 @@ ottie_trim_shape_dispose (GObject *object)
 static void
 ottie_trim_shape_class_init (OttieTrimShapeClass *klass)
 {
+  OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (klass);
   OttieShapeClass *shape_class = OTTIE_SHAPE_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  oobject_class->print = ottie_trim_shape_print;
+
   shape_class->render = ottie_trim_shape_render;
 
   gobject_class->dispose = ottie_trim_shape_dispose;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]