[pango/line-breaker: 12/16] Serialization
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pango/line-breaker: 12/16] Serialization
- Date: Tue, 18 Jan 2022 04:02:21 +0000 (UTC)
commit edb75623dbdb558d7e420a39884151c775350646
Author: Matthias Clasen <mclasen redhat com>
Date: Fri Jan 14 22:13:01 2022 -0500
Serialization
pango/serializer.c | 415 +++++++++++++++++++++++++++++++++++++++++++++++++-
tests/testserialize.c | 39 +++++
2 files changed, 450 insertions(+), 4 deletions(-)
---
diff --git a/pango/serializer.c b/pango/serializer.c
index 2dab93b4..eadb9742 100644
--- a/pango/serializer.c
+++ b/pango/serializer.c
@@ -26,6 +26,9 @@
#include <pango/pango-context-private.h>
#include <pango/pango-enum-types.h>
#include <pango/pango-font-private.h>
+#include <pango/pango-line-private.h>
+#include <pango/pango-lines.h>
+#include <pango/pango-simple-layout.h>
#include <hb-ot.h>
#include "pango/json/gtkjsonparserprivate.h"
@@ -246,6 +249,15 @@ static const char *alignment_names[] = {
NULL
};
+static const char *alignment_names2[] = {
+ "left",
+ "center",
+ "right",
+ "justify",
+ "justify-all",
+ NULL
+};
+
static const char *wrap_names[] = {
"word",
"char",
@@ -634,7 +646,7 @@ add_font (GtkJsonPrinter *printer,
static void
add_run (GtkJsonPrinter *printer,
- PangoLayout *layout,
+ const char *text,
PangoLayoutRun *run)
{
char *str;
@@ -644,7 +656,7 @@ add_run (GtkJsonPrinter *printer,
gtk_json_printer_add_integer (printer, "offset", run->item->offset);
gtk_json_printer_add_integer (printer, "length", run->item->length);
- str = g_strndup (layout->text + run->item->offset, run->item->length);
+ str = g_strndup (text + run->item->offset, run->item->length);
gtk_json_printer_add_string (printer, "text", str);
g_free (str);
@@ -721,7 +733,7 @@ add_line (GtkJsonPrinter *printer,
for (GSList *l = line->runs; l; l = l->next)
{
PangoLayoutRun *run = l->data;
- add_run (printer, line->layout, run);
+ add_run (printer, line->layout->text, run);
}
gtk_json_printer_end (printer);
@@ -827,6 +839,125 @@ layout_to_json (GtkJsonPrinter *printer,
gtk_json_printer_end (printer);
}
+static void
+line_to_json (GtkJsonPrinter *printer,
+ PangoLine *line,
+ int x,
+ int y)
+{
+ gtk_json_printer_start_object (printer, NULL);
+
+ gtk_json_printer_start_array (printer, "position");
+ gtk_json_printer_add_number (printer, NULL, x);
+ gtk_json_printer_add_number (printer, NULL, y);
+ gtk_json_printer_end (printer);
+
+ gtk_json_printer_start_object (printer, "line");
+
+ gtk_json_printer_add_integer (printer, "start-index", line->start_index);
+ gtk_json_printer_add_integer (printer, "length", line->length);
+ gtk_json_printer_add_integer (printer, "start-offset", line->start_offset);
+ gtk_json_printer_add_integer (printer, "n-chars", line->n_chars);
+
+ gtk_json_printer_add_boolean (printer, "wrapped", line->wrapped);
+ gtk_json_printer_add_boolean (printer, "ellipsized", line->ellipsized);
+ gtk_json_printer_add_boolean (printer, "hyphenated", line->hyphenated);
+ gtk_json_printer_add_boolean (printer, "justified", line->justified);
+ gtk_json_printer_add_boolean (printer, "paragraph-start", line->starts_paragraph);
+ gtk_json_printer_add_boolean (printer, "paragraph-end", line->ends_paragraph);
+ gtk_json_printer_add_string (printer, "direction", direction_names[line->direction]);
+
+ gtk_json_printer_start_array (printer, "runs");
+ for (GSList *l = line->runs; l; l = l->next)
+ {
+ PangoLayoutRun *run = l->data;
+ add_run (printer, line->data->text, run);
+ }
+ gtk_json_printer_end (printer);
+
+ gtk_json_printer_end (printer);
+
+ gtk_json_printer_end (printer);
+}
+
+static void
+lines_to_json (GtkJsonPrinter *printer,
+ PangoLines *lines,
+ const char *name)
+{
+ gtk_json_printer_start_array (printer, name);
+
+ for (int i = 0; i < pango_lines_get_n_lines (lines); i++)
+ {
+ PangoLine *line;
+ int x, y;
+ pango_lines_get_line (lines, i, &line, &x, &y);
+ line_to_json (printer, line, x, y);
+ }
+
+ gtk_json_printer_end (printer);
+}
+
+static void
+simple_layout_to_json (GtkJsonPrinter *printer,
+ PangoSimpleLayout *layout,
+ PangoSimpleLayoutSerializeFlags flags)
+{
+ const char *str;
+
+ gtk_json_printer_start_object (printer, NULL);
+
+ if (flags & PANGO_SIMPLE_LAYOUT_SERIALIZE_CONTEXT)
+ add_context (printer, pango_simple_layout_get_context (layout));
+
+ str = (const char *) g_object_get_data (G_OBJECT (layout), "comment");
+ if (str)
+ gtk_json_printer_add_string (printer, "comment", str);
+
+ gtk_json_printer_add_string (printer, "text", pango_simple_layout_get_text (layout));
+
+ add_attr_list (printer, pango_simple_layout_get_attributes (layout));
+
+ if (pango_simple_layout_get_font_description (layout))
+ {
+ char *str = pango_font_description_to_string (pango_simple_layout_get_font_description (layout));
+ gtk_json_printer_add_string (printer, "font", str);
+ g_free (str);
+ }
+
+ if (pango_simple_layout_get_tabs (layout))
+ add_tab_array (printer, pango_simple_layout_get_tabs (layout));
+
+ if (!pango_simple_layout_get_auto_dir (layout))
+ gtk_json_printer_add_boolean (printer, "auto-dir", FALSE);
+
+ if (pango_simple_layout_get_alignment (layout) != PANGO_ALIGNMENT_LEFT)
+ gtk_json_printer_add_string (printer, "alignment", alignment_names2[pango_simple_layout_get_alignment
(layout)]);
+
+ if (pango_simple_layout_get_wrap (layout))
+ gtk_json_printer_add_string (printer, "wrap", wrap_names[pango_simple_layout_get_wrap (layout)]);
+
+ if (pango_simple_layout_get_ellipsize (layout) != PANGO_ELLIPSIZE_NONE)
+ gtk_json_printer_add_string (printer, "ellipsize", ellipsize_names[pango_simple_layout_get_ellipsize
(layout)]);
+
+ if (pango_simple_layout_get_width (layout) != -1)
+ gtk_json_printer_add_integer (printer, "width", pango_simple_layout_get_width (layout));
+
+ if (pango_simple_layout_get_height (layout) != -1)
+ gtk_json_printer_add_integer (printer, "height", pango_simple_layout_get_height (layout));
+
+ if (pango_simple_layout_get_indent (layout) != 0)
+ gtk_json_printer_add_integer (printer, "indent", pango_simple_layout_get_indent (layout));
+
+ if (pango_simple_layout_get_line_spacing (layout) != 0.)
+ gtk_json_printer_add_number (printer, "line-spacing", pango_simple_layout_get_line_spacing (layout));
+
+ if (flags & PANGO_LAYOUT_SERIALIZE_OUTPUT)
+ lines_to_json (printer, pango_simple_layout_get_lines (layout), "lines");
+
+ gtk_json_printer_end (printer);
+}
+
static void
gstring_write (GtkJsonPrinter *printer,
const char *s,
@@ -1522,6 +1653,142 @@ json_parser_fill_layout (GtkJsonParser *parser,
gtk_json_parser_end (parser);
}
+enum {
+ SIMPLE_LAYOUT_CONTEXT,
+ SIMPLE_LAYOUT_COMMENT,
+ SIMPLE_LAYOUT_TEXT,
+ SIMPLE_LAYOUT_ATTRIBUTES,
+ SIMPLE_LAYOUT_FONT,
+ SIMPLE_LAYOUT_TABS,
+ SIMPLE_LAYOUT_AUTO_DIR,
+ SIMPLE_LAYOUT_ALIGNMENT,
+ SIMPLE_LAYOUT_WRAP,
+ SIMPLE_LAYOUT_ELLIPSIZE,
+ SIMPLE_LAYOUT_WIDTH,
+ SIMPLE_LAYOUT_HEIGHT,
+ SIMPLE_LAYOUT_INDENT,
+ SIMPLE_LAYOUT_LINE_SPACING,
+ SIMPLE_LAYOUT_LINES
+};
+
+static const char *simple_layout_members[] = {
+ "context",
+ "comment",
+ "text",
+ "attributes",
+ "font",
+ "tabs",
+ "auto-dir",
+ "alignment",
+ "wrap",
+ "ellipsize",
+ "width",
+ "height",
+ "indent",
+ "line-spacing"
+ "lines",
+ NULL
+};
+
+static void
+json_parser_fill_simple_layout (GtkJsonParser *parser,
+ PangoSimpleLayout *layout,
+ PangoSimpleLayoutDeserializeFlags flags)
+{
+ gtk_json_parser_start_object (parser);
+
+ do
+ {
+ char *str;
+
+ switch (gtk_json_parser_select_member (parser, simple_layout_members))
+ {
+ case SIMPLE_LAYOUT_CONTEXT:
+ if (flags & PANGO_LAYOUT_DESERIALIZE_CONTEXT)
+ json_parser_fill_context (parser, pango_simple_layout_get_context (layout));
+ break;
+
+ case SIMPLE_LAYOUT_COMMENT:
+ str = gtk_json_parser_get_string (parser);
+ g_object_set_data_full (G_OBJECT (layout), "comment", str, g_free);
+ break;
+
+ case SIMPLE_LAYOUT_TEXT:
+ str = gtk_json_parser_get_string (parser);
+ pango_simple_layout_set_text (layout, str, -1);
+ g_free (str);
+ break;
+
+ case SIMPLE_LAYOUT_ATTRIBUTES:
+ {
+ PangoAttrList *attributes = pango_attr_list_new ();
+ json_parser_fill_attr_list (parser, attributes);
+ pango_simple_layout_set_attributes (layout, attributes);
+ pango_attr_list_unref (attributes);
+ }
+ break;
+
+ case SIMPLE_LAYOUT_FONT:
+ {
+ PangoFontDescription *desc = parser_get_font_description (parser);;
+ pango_simple_layout_set_font_description (layout, desc);
+ pango_font_description_free (desc);
+ }
+ break;
+
+ case SIMPLE_LAYOUT_AUTO_DIR:
+ pango_simple_layout_set_auto_dir (layout, gtk_json_parser_get_boolean (parser));
+ break;
+
+ case SIMPLE_LAYOUT_LINE_SPACING:
+ pango_simple_layout_set_line_spacing (layout, gtk_json_parser_get_number (parser));
+ break;
+
+ case SIMPLE_LAYOUT_TABS:
+ {
+ PangoTabArray *tabs = pango_tab_array_new (0, FALSE);
+ json_parser_fill_tab_array (parser, tabs);
+ pango_simple_layout_set_tabs (layout, tabs);
+ pango_tab_array_free (tabs);
+ }
+ break;
+
+ case SIMPLE_LAYOUT_ALIGNMENT:
+ pango_simple_layout_set_alignment (layout, (PangoAlignment) parser_select_string (parser,
alignment_names2));
+ break;
+
+ case SIMPLE_LAYOUT_WRAP:
+ pango_simple_layout_set_wrap (layout, (PangoWrapMode) parser_select_string (parser, wrap_names));
+ break;
+
+ case SIMPLE_LAYOUT_ELLIPSIZE:
+ pango_simple_layout_set_ellipsize (layout, (PangoEllipsizeMode) parser_select_string (parser,
ellipsize_names));
+ break;
+
+ case SIMPLE_LAYOUT_WIDTH:
+ pango_simple_layout_set_width (layout, (int) gtk_json_parser_get_number (parser));
+ break;
+
+ case SIMPLE_LAYOUT_HEIGHT:
+ pango_simple_layout_set_height (layout, (int) gtk_json_parser_get_number (parser));
+ break;
+
+ case SIMPLE_LAYOUT_INDENT:
+ pango_simple_layout_set_indent (layout, (int) gtk_json_parser_get_number (parser));
+ break;
+
+ case SIMPLE_LAYOUT_LINES:
+ break;
+
+ default:
+ break;
+ }
+ }
+ while (gtk_json_parser_next (parser));
+
+ gtk_json_parser_end (parser);
+}
+
enum {
FONT_DESCRIPTION,
FONT_CHECKSUM,
@@ -1749,7 +2016,7 @@ pango_font_serialize (PangoFont *font)
gsize size;
g_return_val_if_fail (PANGO_IS_FONT (font), NULL);
-
+
str = g_string_new ("");
printer = gtk_json_printer_new (gstring_write, str, NULL);
@@ -1798,6 +2065,146 @@ pango_font_deserialize (PangoContext *context,
return font;
}
+/**
+ * pango_lines_serialize:
+ * @lines: a `PangoLines` object
+ *
+ * Serializes the @lines.
+ *
+ * There are no guarantees about the format of the output across different
+ * versions of Pango.
+ *
+ * The intended use of this function is testing, benchmarking and debugging.
+ * The format is not meant as a permanent storage format.
+ *
+ * Returns: a `GBytes` containing the serialized form of @lines
+ */
+GBytes *
+pango_lines_serialize (PangoLines *lines)
+{
+ GString *str;
+ GtkJsonPrinter *printer;
+ char *data;
+ gsize size;
+
+ str = g_string_new ("");
+
+ printer = gtk_json_printer_new (gstring_write, str, NULL);
+ gtk_json_printer_set_flags (printer, GTK_JSON_PRINTER_PRETTY);
+ lines_to_json (printer, lines, NULL);
+ gtk_json_printer_free (printer);
+
+ g_string_append_c (str, '\n');
+
+ size = str->len;
+ data = g_string_free (str, FALSE);
+
+ return g_bytes_new_take (data, size);
+}
+
+/**
+ * pango_simple_layout_serialize:
+ * @layout: a `PangoSimpleLayout`
+ * @flags: `PangoSipleLayoutSerializeFlags`
+ *
+ * Serializes the @layout for later deserialization via [func@Pango.SimpleLayout.deserialize].
+ *
+ * There are no guarantees about the format of the output across different
+ * versions of Pango and [func@Pango.SimpleLayout.deserialize] will reject data
+ * that it cannot parse.
+ *
+ * The intended use of this function is testing, benchmarking and debugging.
+ * The format is not meant as a permanent storage format.
+ *
+ * Returns: a `GBytes` containing the serialized form of @layout
+ */
+GBytes *
+pango_simple_layout_serialize (PangoSimpleLayout *layout,
+ PangoSimpleLayoutSerializeFlags flags)
+{
+ GString *str;
+ GtkJsonPrinter *printer;
+ char *data;
+ gsize size;
+
+ g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), NULL);
+
+ str = g_string_new ("");
+
+ printer = gtk_json_printer_new (gstring_write, str, NULL);
+ gtk_json_printer_set_flags (printer, GTK_JSON_PRINTER_PRETTY);
+ simple_layout_to_json (printer, layout, flags);
+ gtk_json_printer_free (printer);
+
+ g_string_append_c (str, '\n');
+
+ size = str->len;
+ data = g_string_free (str, FALSE);
+
+ return g_bytes_new_take (data, size);
+}
+
+/**
+ * pango_simple_layout_deserialize:
+ * @context: a `PangoContext`
+ * @flags: `PangoSimpleLayoutDeserializeFlags`
+ * @bytes: the bytes containing the data
+ * @error: return location for an error
+ *
+ * Loads data previously created via [method@Pango.SimpleLayout.serialize].
+ *
+ * For a discussion of the supported format, see that function.
+ *
+ * Note: to verify that the returned layout is identical to
+ * the one that was serialized, you can compare @bytes to the
+ * result of serializing the layout again.
+ *
+ * Returns: (nullable) (transfer full): a new `PangoSimpleLayout`
+ */
+PangoSimpleLayout *
+pango_simple_layout_deserialize (PangoContext *context,
+ GBytes *bytes,
+ PangoSimpleLayoutDeserializeFlags flags,
+ GError **error)
+{
+ PangoSimpleLayout *layout;
+ GtkJsonParser *parser;
+ const GError *parser_error;
+
+ g_return_val_if_fail (PANGO_IS_CONTEXT (context), NULL);
+
+ layout = pango_simple_layout_new (context);
+
+ parser = gtk_json_parser_new_for_bytes (bytes);
+ json_parser_fill_simple_layout (parser, layout, flags);
+
+ parser_error = gtk_json_parser_get_error (parser);
+
+ if (parser_error)
+ {
+ gsize start, end;
+ int code;
+
+ gtk_json_parser_get_error_offset (parser, &start, &end);
+
+ if (g_error_matches (parser_error, GTK_JSON_ERROR, GTK_JSON_ERROR_VALUE))
+ code = PANGO_LAYOUT_DESERIALIZE_INVALID_VALUE;
+ else if (g_error_matches (parser_error, GTK_JSON_ERROR, GTK_JSON_ERROR_SCHEMA))
+ code = PANGO_LAYOUT_DESERIALIZE_MISSING_VALUE;
+ else
+ code = PANGO_LAYOUT_DESERIALIZE_INVALID;
+
+ g_set_error (error, PANGO_LAYOUT_DESERIALIZE_ERROR, code,
+ "%ld:%ld: %s", start, end, parser_error->message);
+
+ g_clear_object (&layout);
+ }
+
+ gtk_json_parser_free (parser);
+
+ return layout;
+}
+
/* }}} */
/* vim:set foldmethod=marker expandtab: */
diff --git a/tests/testserialize.c b/tests/testserialize.c
index e480da31..ecaa537b 100644
--- a/tests/testserialize.c
+++ b/tests/testserialize.c
@@ -465,6 +465,44 @@ install_fonts (void)
g_free (dir);
}
+static void
+test_serialize_linebreaker (void)
+{
+ PangoContext *context;
+ PangoLineBreaker *breaker;
+ const char *text =
+ "This is a long paragraph that should get "
+ "broken over at least two lines, if not more.";
+ int x, y, width;
+ PangoLines *lines;
+ GBytes *bytes;
+
+ context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
+
+ breaker = pango_line_breaker_new (context);
+
+ pango_line_breaker_add_text (breaker, text, -1, NULL);
+
+ lines = pango_lines_new ();
+
+ x = y = 0;
+ width = 200;
+ while (!pango_line_breaker_done (breaker))
+ {
+ PangoLine *line = pango_line_breaker_next_line (breaker, x, width,
+ PANGO_WRAP_WORD,
+ PANGO_ELLIPSIZE_NONE);
+ pango_lines_add_line (lines, line, 0, 0);
+ }
+
+ bytes = pango_lines_serialize (lines);
+ g_print ("%s\n", (char *)g_bytes_get_data (bytes, NULL));
+
+ g_object_unref (lines);
+
+ g_object_unref (context);
+}
+
int
main (int argc, char *argv[])
{
@@ -479,6 +517,7 @@ main (int argc, char *argv[])
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);
+ g_test_add_func ("/serialize/linebreaker", test_serialize_linebreaker);
return g_test_run ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]