[pango/serialization-improvements: 12/16] Optionally serialize output




commit 5b9ecfad93f70ce430cea4d240074791c2ac67a4
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Nov 22 20:33:11 2021 -0500

    Optionally serialize output
    
    If requested, serialize lines, runs, and log attrs.
    This will let us use the serialization format to
    record not just the test inputs, but outputs as
    well.

 pango/pango-layout.h            |   4 +-
 pango/serializer.c              | 286 +++++++++++++++++++++++++++++++++++++++-
 tests/layouts/valid-1.expected  |  43 ------
 tests/layouts/valid-10.expected |  37 ------
 tests/layouts/valid-11.expected |  53 --------
 tests/layouts/valid-12.expected |  35 -----
 tests/layouts/valid-13.expected |  35 -----
 tests/layouts/valid-14.expected |  38 ------
 tests/layouts/valid-15.expected |  36 -----
 tests/layouts/valid-16.expected |  37 ------
 tests/layouts/valid-17.expected |  35 -----
 tests/layouts/valid-18.expected |  40 ------
 tests/layouts/valid-19.expected |  42 ------
 tests/layouts/valid-2.expected  |  42 ------
 tests/layouts/valid-20.expected |  40 ------
 tests/layouts/valid-22.expected | 111 ----------------
 tests/layouts/valid-3.expected  |  33 -----
 tests/layouts/valid-4.expected  |  44 -------
 tests/layouts/valid-5.expected  |  56 --------
 tests/layouts/valid-6.expected  |  33 -----
 tests/layouts/valid-7.expected  |  43 ------
 tests/layouts/valid-8.expected  |  34 -----
 tests/layouts/valid-9.expected  |  49 -------
 23 files changed, 288 insertions(+), 918 deletions(-)
---
diff --git a/pango/pango-layout.h b/pango/pango-layout.h
index 5ddc8073..92d53d17 100644
--- a/pango/pango-layout.h
+++ b/pango/pango-layout.h
@@ -355,7 +355,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
+ * @PANGO_LAYOUT_SERIALIZE_OUTPUT: Include information about the
+ *   formatted output in the serialization
  *
  * Flags that influence the behavior of [method@Pango.Layout.serialize].
  *
@@ -364,6 +365,7 @@ GSList *         pango_layout_get_lines_readonly   (PangoLayout    *layout);
 typedef enum {
   PANGO_LAYOUT_SERIALIZE_DEFAULT = 0,
   PANGO_LAYOUT_SERIALIZE_CONTEXT = 1 << 0,
+  PANGO_LAYOUT_SERIALIZE_OUTPUT = 1 << 1,
 } PangoLayoutSerializeFlags;
 
 PANGO_AVAILABLE_IN_1_50
diff --git a/pango/serializer.c b/pango/serializer.c
index 204c88bb..1a7cdcf5 100644
--- a/pango/serializer.c
+++ b/pango/serializer.c
@@ -257,7 +257,7 @@ add_context (JsonBuilder  *builder,
   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");
+  json_builder_set_member_name (builder, "base-dir");
   add_enum_value (builder, PANGO_TYPE_DIRECTION, context->base_dir, FALSE);
 
   json_builder_set_member_name (builder, "round-glyph-positions");
@@ -280,6 +280,284 @@ add_context (JsonBuilder  *builder,
   json_builder_end_object (builder);
 }
 
+static void
+add_log_attrs (JsonBuilder *builder,
+               PangoLayout *layout)
+{
+  const PangoLogAttr *log_attrs;
+  int n_attrs;
+
+  json_builder_set_member_name (builder, "log-attrs");
+  json_builder_begin_array (builder);
+
+  log_attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
+  for (int i = 0; i < n_attrs; i++)
+    {
+      json_builder_begin_object (builder);
+      if (log_attrs[i].is_line_break)
+        {
+          json_builder_set_member_name (builder, "line-break");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].is_mandatory_break)
+        {
+          json_builder_set_member_name (builder, "mandatory-break");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].is_char_break)
+        {
+          json_builder_set_member_name (builder, "char-break");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].is_white)
+        {
+          json_builder_set_member_name (builder, "white");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].is_cursor_position)
+        {
+          json_builder_set_member_name (builder, "cursor-position");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].is_word_start)
+        {
+          json_builder_set_member_name (builder, "word-start");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].is_word_end)
+        {
+          json_builder_set_member_name (builder, "word-end");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].is_sentence_boundary)
+        {
+          json_builder_set_member_name (builder, "sentence-boundary");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].is_sentence_start)
+        {
+          json_builder_set_member_name (builder, "sentence-start");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].is_sentence_end)
+        {
+          json_builder_set_member_name (builder, "sentence-end");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].backspace_deletes_character)
+        {
+          json_builder_set_member_name (builder, "backspace-deletes-character");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].is_expandable_space)
+        {
+          json_builder_set_member_name (builder, "expandable-space");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].is_word_boundary)
+        {
+          json_builder_set_member_name (builder, "word-boundary");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].break_inserts_hyphen)
+        {
+          json_builder_set_member_name (builder, "break-inserts-hyphen");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      if (log_attrs[i].break_removes_preceding)
+        {
+          json_builder_set_member_name (builder, "break-removes_preceding");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+      json_builder_end_object (builder);
+    }
+
+  json_builder_end_array (builder);
+}
+
+#define ANALYSIS_FLAGS (PANGO_ANALYSIS_FLAG_CENTERED_BASELINE | \
+                        PANGO_ANALYSIS_FLAG_IS_ELLIPSIS | \
+                        PANGO_ANALYSIS_FLAG_NEED_HYPHEN)
+
+static void
+add_run (JsonBuilder    *builder,
+         PangoLayout    *layout,
+         PangoLayoutRun *run)
+{
+  PangoFontDescription *desc;
+  char *str;
+
+  json_builder_begin_object (builder);
+
+  json_builder_set_member_name (builder, "offset");
+  json_builder_add_int_value (builder, run->item->offset);
+
+  json_builder_set_member_name (builder, "length");
+  json_builder_add_int_value (builder, run->item->length);
+
+  str = g_strndup (layout->text + run->item->offset, run->item->length);
+  json_builder_set_member_name (builder, "text");
+  json_builder_add_string_value (builder, str);
+  g_free (str);
+
+  json_builder_set_member_name (builder, "bidi-level");
+  json_builder_add_int_value (builder, run->item->analysis.level);
+
+  json_builder_set_member_name (builder, "gravity");
+  add_enum_value (builder, PANGO_TYPE_GRAVITY, run->item->analysis.gravity, FALSE);
+
+  json_builder_set_member_name (builder, "language");
+  json_builder_add_string_value (builder, pango_language_to_string (run->item->analysis.language));
+
+  json_builder_set_member_name (builder, "script");
+  add_enum_value (builder, PANGO_TYPE_SCRIPT, run->item->analysis.script, FALSE);
+
+  json_builder_set_member_name (builder, "font");
+  desc = pango_font_describe (run->item->analysis.font);
+  str = pango_font_description_to_string (desc);
+  json_builder_add_string_value (builder, str);
+  g_free (str);
+  pango_font_description_free (desc);
+
+  json_builder_set_member_name (builder, "flags");
+  json_builder_add_int_value (builder, run->item->analysis.flags & ANALYSIS_FLAGS);
+
+  if (run->item->analysis.extra_attrs)
+    {
+      GSList *l;
+
+      json_builder_set_member_name (builder, "extra-attributes");
+
+      json_builder_begin_array (builder);
+      for (l = run->item->analysis.extra_attrs; l; l = l->next)
+        {
+          PangoAttribute *attr = l->data;
+          add_attribute (builder, attr);
+        }
+      json_builder_end_array (builder);
+    }
+
+  json_builder_set_member_name (builder, "y-offset");
+  json_builder_add_int_value (builder, run->y_offset);
+
+  json_builder_set_member_name (builder, "start-x-offset");
+  json_builder_add_int_value (builder, run->start_x_offset);
+
+  json_builder_set_member_name (builder, "end-x-offset");
+  json_builder_add_int_value (builder, run->end_x_offset);
+
+  json_builder_set_member_name (builder, "glyphs");
+  json_builder_begin_array (builder);
+  for (int i = 0; i < run->glyphs->num_glyphs; i++)
+    {
+      json_builder_begin_object (builder);
+
+      json_builder_set_member_name (builder, "glyph");
+      json_builder_add_int_value (builder, run->glyphs->glyphs[i].glyph);
+
+      json_builder_set_member_name (builder, "width");
+      json_builder_add_int_value (builder, run->glyphs->glyphs[i].geometry.width);
+
+      if (run->glyphs->glyphs[i].geometry.x_offset != 0)
+        {
+          json_builder_set_member_name (builder, "x-offset");
+          json_builder_add_int_value (builder, run->glyphs->glyphs[i].geometry.x_offset);
+        }
+
+      if (run->glyphs->glyphs[i].geometry.y_offset != 0)
+        {
+          json_builder_set_member_name (builder, "y-offset");
+          json_builder_add_int_value (builder, run->glyphs->glyphs[i].geometry.y_offset);
+        }
+
+      if (run->glyphs->glyphs[i].attr.is_cluster_start)
+        {
+          json_builder_set_member_name (builder, "is-cluster-start");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+
+      if (run->glyphs->glyphs[i].attr.is_color)
+        {
+          json_builder_set_member_name (builder, "is-color");
+          json_builder_add_boolean_value (builder, TRUE);
+        }
+
+      json_builder_set_member_name (builder, "log-cluster");
+      json_builder_add_int_value (builder, run->glyphs->log_clusters[i]);
+
+      json_builder_end_object (builder);
+    }
+
+  json_builder_end_array (builder);
+
+  json_builder_end_object (builder);
+}
+
+#undef ANALYSIS_FLAGS
+
+static void
+add_line (JsonBuilder     *builder,
+          PangoLayoutLine *line)
+{
+  json_builder_begin_object (builder);
+
+  json_builder_set_member_name (builder, "start-index");
+  json_builder_add_int_value (builder, line->start_index);
+
+  json_builder_set_member_name (builder, "length");
+  json_builder_add_int_value (builder, line->length);
+
+  json_builder_set_member_name (builder, "paragraph-start");
+  json_builder_add_boolean_value (builder, line->is_paragraph_start);
+
+  json_builder_set_member_name (builder, "direction");
+  add_enum_value (builder, PANGO_TYPE_DIRECTION, line->resolved_dir, FALSE);
+
+  json_builder_set_member_name (builder, "runs");
+  json_builder_begin_array (builder);
+  for (GSList *l = line->runs; l; l = l->next)
+    {
+      PangoLayoutRun *run = l->data;
+      add_run (builder, line->layout, run);
+    }
+  json_builder_end_array (builder);
+
+  json_builder_end_object (builder);
+}
+
+static void
+add_output (JsonBuilder *builder,
+            PangoLayout *layout)
+{
+  int width, height;
+
+  json_builder_begin_object (builder);
+
+  json_builder_set_member_name (builder, "is-wrapped");
+  json_builder_add_boolean_value (builder, pango_layout_is_wrapped (layout));
+
+  json_builder_set_member_name (builder, "is-ellipsized");
+  json_builder_add_boolean_value (builder, pango_layout_is_ellipsized (layout));
+
+  pango_layout_get_size (layout, &width, &height);
+  json_builder_set_member_name (builder, "width");
+  json_builder_add_int_value (builder, width);
+  json_builder_set_member_name (builder, "height");
+  json_builder_add_int_value (builder, height);
+
+  add_log_attrs (builder, layout);
+  json_builder_set_member_name (builder, "lines");
+  json_builder_begin_array (builder);
+  for (GSList *l = layout->lines; l; l = l->next)
+    {
+      PangoLayoutLine *line = l->data;
+      add_line (builder, line);
+    }
+  json_builder_end_array (builder);
+
+  json_builder_end_object (builder);
+}
+
 static JsonNode *
 layout_to_json (PangoLayout               *layout,
                 PangoLayoutSerializeFlags  flags)
@@ -384,6 +662,12 @@ layout_to_json (PangoLayout               *layout,
       json_builder_add_double_value (builder, layout->line_spacing);
     }
 
+  if (flags & PANGO_LAYOUT_SERIALIZE_OUTPUT)
+    {
+      json_builder_set_member_name (builder, "output");
+      add_output (builder, layout);
+    }
+
   json_builder_end_object (builder);
 
   root = json_builder_get_root (builder);


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