[pango/serialization-improvements: 9/16] Allow serializing context information




commit 0712927fe72f8a6becd43e8cc0da0344332d7cac
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Nov 21 23:19:27 2021 -0500

    Allow serializing context information
    
    Optionally include context information in the
    serialization and restore it. This will be useful
    for transporting for giving tests complete data
    that affects their output.
    
    Some tests included.

 pango/pango-layout.h  |   6 +++
 pango/serializer.c    | 139 ++++++++++++++++++++++++++++++++++++++++++++++----
 tests/testserialize.c |  45 ++++++++++++++++
 3 files changed, 180 insertions(+), 10 deletions(-)
---
diff --git a/pango/pango-layout.h b/pango/pango-layout.h
index e9b4710c..5ddc8073 100644
--- a/pango/pango-layout.h
+++ b/pango/pango-layout.h
@@ -354,6 +354,8 @@ GSList *         pango_layout_get_lines_readonly   (PangoLayout    *layout);
 /**
  * PangoLayoutSerializeFlags:
  * @PANGO_LAYOUT_SERIALIZE_DEFAULT: Default behavior
+ * @PANGO_LAYOUT_SERIALIZE_CONTEXT: Include context information in
+ *   the serialization
  *
  * Flags that influence the behavior of [method@Pango.Layout.serialize].
  *
@@ -361,6 +363,7 @@ GSList *         pango_layout_get_lines_readonly   (PangoLayout    *layout);
  */
 typedef enum {
   PANGO_LAYOUT_SERIALIZE_DEFAULT = 0,
+  PANGO_LAYOUT_SERIALIZE_CONTEXT = 1 << 0,
 } PangoLayoutSerializeFlags;
 
 PANGO_AVAILABLE_IN_1_50
@@ -402,6 +405,8 @@ GQuark          pango_layout_deserialize_error_quark (void);
 /**
  * PangoLayoutDeserializeFlags:
  * @PANGO_LAYOUT_DESERIALIZE_DEFAULT: Default behavior
+ * @PANGO_LAYOUT_DESERIALIZE_CONTEXT: Apply context information
+ *   from the serialization to the `PangoContext`
  *
  * Flags that influence the behavior of [method@Pango.Layout.deserialize].
  *
@@ -409,6 +414,7 @@ GQuark          pango_layout_deserialize_error_quark (void);
  */
 typedef enum {
   PANGO_LAYOUT_DESERIALIZE_DEFAULT = 0,
+  PANGO_LAYOUT_DESERIALIZE_CONTEXT = 1 << 0,
 } PangoLayoutDeserializeFlags;
 
 PANGO_AVAILABLE_IN_1_50
diff --git a/pango/serializer.c b/pango/serializer.c
index 54bc1c0b..84d377ee 100644
--- a/pango/serializer.c
+++ b/pango/serializer.c
@@ -23,6 +23,7 @@
 
 #include <pango/pango-layout.h>
 #include <pango/pango-layout-private.h>
+#include <pango/pango-context-private.h>
 #include <pango/pango-enum-types.h>
 
 #include <json-glib/json-glib.h>
@@ -211,8 +212,43 @@ add_tab_array (JsonBuilder   *builder,
   json_builder_end_object (builder);
 }
 
+static void
+add_context (JsonBuilder  *builder,
+             PangoContext *context)
+{
+  json_builder_begin_object (builder);
+
+  /* Note: since we don't create the context when deserializing,
+   * we don't strip out default values here to ensure that the
+   * context gets updated as expected.
+   */
+
+  if (context->set_language)
+    {
+      json_builder_set_member_name (builder, "language");
+      json_builder_add_string_value (builder, pango_language_to_string (context->set_language));
+    }
+
+  json_builder_set_member_name (builder, "base-gravity");
+  add_enum_value (builder, PANGO_TYPE_GRAVITY, context->base_gravity, FALSE);
+
+  json_builder_set_member_name (builder, "gravity-hint");
+  add_enum_value (builder, PANGO_TYPE_GRAVITY_HINT, context->gravity_hint, FALSE);
+
+  json_builder_set_member_name (builder, "direction");
+  add_enum_value (builder, PANGO_TYPE_DIRECTION, context->base_dir, FALSE);
+
+  json_builder_set_member_name (builder, "round-glyph-positions");
+  json_builder_add_boolean_value (builder, context->round_glyph_positions);
+
+  /* FIXME transform */
+
+  json_builder_end_object (builder);
+}
+
 static JsonNode *
-layout_to_json (PangoLayout *layout)
+layout_to_json (PangoLayout               *layout,
+                PangoLayoutSerializeFlags  flags)
 {
   JsonBuilder *builder;
   JsonNode *root;
@@ -221,6 +257,12 @@ layout_to_json (PangoLayout *layout)
 
   json_builder_begin_object (builder);
 
+  if (flags & PANGO_LAYOUT_SERIALIZE_CONTEXT)
+    {
+      json_builder_set_member_name (builder, "context");
+      add_context (builder, layout->context);
+    }
+
   json_builder_set_member_name (builder, "text");
   json_builder_add_string_value (builder, layout->text);
 
@@ -663,16 +705,79 @@ fail:
   return NULL;
 }
 
+static gboolean
+apply_json_to_context (JsonReader    *reader,
+                       PangoContext  *context,
+                       GError       **error)
+{
+  if (json_reader_read_member (reader, "language"))
+    {
+      const char *value;
+      PangoLanguage *language;
+
+      value = json_reader_get_string_value (reader);
+      language = pango_language_from_string (value);
+      pango_context_set_language (context, language);
+    }
+  json_reader_end_member (reader);
+
+  if (json_reader_read_member (reader, "base-gravity"))
+    {
+      PangoGravity gravity = get_enum_value (PANGO_TYPE_GRAVITY,
+                                             json_reader_get_string_value (reader),
+                                             FALSE,
+                                             error);
+      if (gravity == -1)
+        return FALSE;
+
+      pango_context_set_base_gravity (context, gravity);
+    }
+  json_reader_end_member (reader);
+
+  if (json_reader_read_member (reader, "gravity-hint"))
+    {
+      PangoGravityHint gravity_hint = get_enum_value (PANGO_TYPE_GRAVITY_HINT,
+                                                      json_reader_get_string_value (reader),
+                                                      FALSE,
+                                                      error);
+      if (gravity_hint == -1)
+        return FALSE;
+
+      pango_context_set_gravity_hint (context, gravity_hint);
+    }
+  json_reader_end_member (reader);
+
+  if (json_reader_read_member (reader, "base-dir"))
+    {
+      PangoDirection direction = get_enum_value (PANGO_TYPE_DIRECTION,
+                                                 json_reader_get_string_value (reader),
+                                                 FALSE,
+                                                 error);
+      if (direction == -1)
+        return FALSE;
+
+      pango_context_set_base_dir (context, direction);
+    }
+  json_reader_end_member (reader);
+
+  if (json_reader_read_member (reader, "round-glyph-positions"))
+    {
+      pango_context_set_round_glyph_positions (context, json_reader_get_boolean_value (reader));
+    }
+  json_reader_end_member (reader);
+
+  return TRUE;
+}
+
 static PangoLayout *
-json_to_layout (PangoContext *context,
-                JsonNode     *node,
-                GError      **error)
+json_to_layout (PangoContext                 *context,
+                JsonNode                     *node,
+                PangoLayoutDeserializeFlags   flags,
+                GError                      **error)
 {
   JsonReader *reader;
   PangoLayout *layout;
 
-  layout = pango_layout_new (context);
-
   reader = json_reader_new (node);
   if (!json_reader_is_object (reader))
     {
@@ -683,6 +788,18 @@ json_to_layout (PangoContext *context,
       goto fail;
     }
 
+  if (flags & PANGO_LAYOUT_DESERIALIZE_CONTEXT)
+    {
+      if (json_reader_read_member (reader, "context"))
+        {
+          if (!apply_json_to_context (reader, context, error))
+            goto fail;
+        }
+      json_reader_end_member (reader);
+    }
+
+  layout = pango_layout_new (context);
+
   if (json_reader_read_member (reader, "text"))
     pango_layout_set_text (layout, json_reader_get_string_value (reader), -1);
   json_reader_end_member (reader);
@@ -711,7 +828,8 @@ json_to_layout (PangoContext *context,
           g_set_error (error,
                        PANGO_LAYOUT_DESERIALIZE_ERROR,
                        PANGO_LAYOUT_DESERIALIZE_INVALID_VALUE,
-                       "Could not parse \"font\" value: %s",
+                       "Could not parse \"%s\" value: %s",
+                       "font",
                        json_reader_get_string_value (reader));
           goto fail;
         }
@@ -820,7 +938,8 @@ json_to_layout (PangoContext *context,
 
 fail:
   g_object_unref (reader);
-  g_object_unref (layout);
+  if (layout)
+    g_object_unref (layout);
   return NULL;
 }
 
@@ -856,7 +975,7 @@ pango_layout_serialize (PangoLayout               *layout,
 
   g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
 
-  node = layout_to_json (layout);
+  node = layout_to_json (layout, flags);
 
   generator = json_generator_new ();
   json_generator_set_pretty (generator, TRUE);
@@ -952,7 +1071,7 @@ pango_layout_deserialize (PangoContext                 *context,
     }
 
   node = json_parser_get_root (parser);
-  layout = json_to_layout (context, node, error);
+  layout = json_to_layout (context, node, flags, error);
 
   g_object_unref (parser);
 
diff --git a/tests/testserialize.c b/tests/testserialize.c
index d04ec7cf..43248777 100644
--- a/tests/testserialize.c
+++ b/tests/testserialize.c
@@ -242,6 +242,42 @@ test_serialize_layout_valid (void)
   g_object_unref (context);
 }
 
+static void
+test_serialize_layout_context (void)
+{
+  const char *test =
+    "{\n"
+    "  \"text\" : \"Some fun with layouts!\",\n"
+    "  \"context\" : {\n"
+    "    \"base-gravity\" : \"east\",\n"
+    "    \"language\" : \"de-de\",\n"
+    "    \"round-glyph-positions\" : \"false\"\n"
+    "  }\n"
+    "}";
+
+  PangoContext *context;
+  GBytes *bytes;
+  PangoLayout *layout;
+  GError *error = NULL;
+
+  context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
+
+  bytes = g_bytes_new_static (test, -1);
+
+  layout = pango_layout_deserialize (context, bytes, PANGO_LAYOUT_DESERIALIZE_CONTEXT, &error);
+  g_assert_no_error (error);
+  g_assert_true (PANGO_IS_LAYOUT (layout));
+  g_assert_cmpstr (pango_layout_get_text (layout), ==, "Some fun with layouts!");
+
+  g_assert_cmpint (pango_context_get_base_gravity (context), ==, PANGO_GRAVITY_EAST);
+  g_assert_true (pango_context_get_language (context) == pango_language_from_string ("de-de"));
+  g_assert_false (pango_context_get_round_glyph_positions (context));
+
+  g_object_unref (layout);
+  g_bytes_unref (bytes);
+  g_object_unref (context);
+}
+
 static void
 test_serialize_layout_invalid (void)
 {
@@ -285,6 +321,14 @@ test_serialize_layout_invalid (void)
       "  \"alignment\" : \"nonsense\"\n"
       "}",
       PANGO_LAYOUT_DESERIALIZE_INVALID_VALUE
+    },
+    {
+      "{\n"
+      "  \"attributes\" : {\n"
+      "    \"name\" : \"This is wrong\"\n"
+      "  }\n"
+      "}",
+      PANGO_LAYOUT_DESERIALIZE_INVALID_SYNTAX
     }
   };
 
@@ -317,6 +361,7 @@ main (int argc, char *argv[])
   g_test_add_func ("/serialize/tab-array", test_serialize_tab_array);
   g_test_add_func ("/serialize/layout/minimal", test_serialize_layout_minimal);
   g_test_add_func ("/serialize/layout/valid", test_serialize_layout_valid);
+  g_test_add_func ("/serialize/layout/context", test_serialize_layout_context);
   g_test_add_func ("/serialize/layout/invalid", test_serialize_layout_invalid);
 
   return g_test_run ();


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