summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-11-18 19:31:16 +0000
committerMatthias Clasen <mclasen@redhat.com>2021-11-18 19:31:16 +0000
commitf82c7d11f098d3e4d26c24bc7decf475aed2109d (patch)
tree4a249ef9f4b350dc8a3990041021164a82f6bc4f
parent97300279f62855dc4ef286ed8bd5d363a8b8f710 (diff)
parent43f78996eef19a5b141a604937c36e0121187000 (diff)
downloadpango-f82c7d11f098d3e4d26c24bc7decf475aed2109d.tar.gz
Merge branch 'serializer2' into 'main'
Add layout serialization api See merge request GNOME/pango!513
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--.gitlab-ci/fedora.Dockerfile1
-rw-r--r--meson.build5
-rw-r--r--pango.supp15
-rw-r--r--pango/meson.build1
-rw-r--r--pango/pango-attributes.c5
-rw-r--r--pango/pango-layout.h25
-rw-r--r--pango/serializer.c935
-rw-r--r--subprojects/json-glib.wrap5
-rw-r--r--tests/layouts/valid-1.layout20
-rw-r--r--tests/layouts/valid-1.markup2
-rw-r--r--tests/layouts/valid-10.layout8
-rw-r--r--tests/layouts/valid-10.markup2
-rw-r--r--tests/layouts/valid-11.layout42
-rw-r--r--tests/layouts/valid-11.markup2
-rw-r--r--tests/layouts/valid-12.layout15
-rw-r--r--tests/layouts/valid-12.markup2
-rw-r--r--tests/layouts/valid-13.layout16
-rw-r--r--tests/layouts/valid-13.markup2
-rw-r--r--tests/layouts/valid-14.layout8
-rw-r--r--tests/layouts/valid-14.markup2
-rw-r--r--tests/layouts/valid-15.layout8
-rw-r--r--tests/layouts/valid-15.markup2
-rw-r--r--tests/layouts/valid-16.layout9
-rw-r--r--tests/layouts/valid-16.markup2
-rw-r--r--tests/layouts/valid-17.layout7
-rw-r--r--tests/layouts/valid-17.markup2
-rw-r--r--tests/layouts/valid-18.layout11
-rw-r--r--tests/layouts/valid-18.markup2
-rw-r--r--tests/layouts/valid-19.layout5
-rw-r--r--tests/layouts/valid-19.markup2
-rw-r--r--tests/layouts/valid-2.layout18
-rw-r--r--tests/layouts/valid-2.markup2
-rw-r--r--tests/layouts/valid-20.layout22
-rw-r--r--tests/layouts/valid-20.markup2
-rw-r--r--tests/layouts/valid-21.expected36
-rw-r--r--tests/layouts/valid-21.markup2
-rw-r--r--tests/layouts/valid-22.layout84
-rw-r--r--tests/layouts/valid-22.markup2
-rw-r--r--tests/layouts/valid-3.layout5
-rw-r--r--tests/layouts/valid-3.markup2
-rw-r--r--tests/layouts/valid-4.layout6
-rw-r--r--tests/layouts/valid-4.markup2
-rw-r--r--tests/layouts/valid-5.layout13
-rw-r--r--tests/layouts/valid-5.markup3
-rw-r--r--tests/layouts/valid-6.layout5
-rw-r--r--tests/layouts/valid-6.markup2
-rw-r--r--tests/layouts/valid-7.layout21
-rw-r--r--tests/layouts/valid-7.markup2
-rw-r--r--tests/layouts/valid-8.layout8
-rw-r--r--tests/layouts/valid-8.markup2
-rw-r--r--tests/layouts/valid-9.layout12
-rw-r--r--tests/layouts/valid-9.markup2
-rw-r--r--tests/test-layout.c277
-rw-r--r--tests/testserialize.c189
55 files changed, 1540 insertions, 344 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 3b9f5200..6195501c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -8,7 +8,7 @@ stages:
variables:
COMMON_MESON_FLAGS: "--fatal-meson-warnings --werror"
MESON_TEST_TIMEOUT_MULTIPLIER: 2
- FEDORA_IMAGE: registry.gitlab.gnome.org/gnome/pango/fedora:v6
+ FEDORA_IMAGE: registry.gitlab.gnome.org/gnome/pango/fedora:v7
.only-default:
only:
diff --git a/.gitlab-ci/fedora.Dockerfile b/.gitlab-ci/fedora.Dockerfile
index ebb1e6b5..e905deee 100644
--- a/.gitlab-ci/fedora.Dockerfile
+++ b/.gitlab-ci/fedora.Dockerfile
@@ -26,6 +26,7 @@ RUN dnf -y install \
harfbuzz-devel \
hicolor-icon-theme \
itstool \
+ json-glib-devel \
libasan \
lcov \
libthai-devel \
diff --git a/meson.build b/meson.build
index 37bcf6cb..4a6b128c 100644
--- a/meson.build
+++ b/meson.build
@@ -232,6 +232,7 @@ harfbuzz_req_version = '>= 2.6.0'
fontconfig_req_version = '>= 2.13.0'
xft_req_version = '>= 2.0.0'
cairo_req_version = '>= 1.12.10'
+json_glib_version = '>= 1.6.0'
# libm
mathlib_dep = cc.find_library('m', required: false)
@@ -251,6 +252,10 @@ fribidi_dep = dependency('fribidi', version: fribidi_req_version,
default_options: ['docs=false'])
pango_deps += fribidi_dep
+json_glib_dep = dependency('json-glib-1.0', version: json_glib_version,
+ fallback: ['json-glib', 'json_glib_dep'])
+pango_deps += json_glib_dep
+
thai_dep = dependency('libthai', version: libthai_req_version, required: get_option('libthai'))
if thai_dep.found()
pango_conf.set('HAVE_LIBTHAI', 1)
diff --git a/pango.supp b/pango.supp
index 98450af4..9b542534 100644
--- a/pango.supp
+++ b/pango.supp
@@ -19,6 +19,14 @@
fun:_cairo_ft_font_options_substitute
}
+{
+ pango 3
+ Memcheck:Leak
+ fun:calloc
+ ...
+ fun:pango_language_from_string
+}
+
# Fontconfig
{
FcFontSetList
@@ -84,6 +92,13 @@
...
fun:g_intern_static_string
}
+{
+ glib GThread
+ Memcheck:Leak
+ fun:calloc
+ ...
+ fun:g_thread_new_internal
+}
# libthai
{
diff --git a/pango/meson.build b/pango/meson.build
index 084de229..7c7bb280 100644
--- a/pango/meson.build
+++ b/pango/meson.build
@@ -27,6 +27,7 @@ pango_sources = [
'pango-utils.c',
'reorder-items.c',
'shape.c',
+ 'serializer.c',
]
pango_headers = [
diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c
index 13468963..cfaf9b17 100644
--- a/pango/pango-attributes.c
+++ b/pango/pango-attributes.c
@@ -2802,7 +2802,7 @@ pango_attr_list_from_string (const char *text)
p = endp + strspn (endp, " ");
- endp = (char *)strpbrk (p, " ");
+ endp = (char *)p + strcspn (p, " ");
attr_type = get_attr_type_by_nick (p, endp - p);
p = endp + strspn (endp, " ");
@@ -2929,8 +2929,7 @@ pango_attr_list_from_string (const char *text)
break;
case PANGO_ATTR_SHAPE:
- endp = (char *)strpbrk (p, ",\n");
- p = endp + strspn (endp, " ");
+ endp = (char *)p + strcspn (p, ",\n");
continue; /* FIXME */
case PANGO_ATTR_SCALE:
diff --git a/pango/pango-layout.h b/pango/pango-layout.h
index e28f9295..502f5e29 100644
--- a/pango/pango-layout.h
+++ b/pango/pango-layout.h
@@ -351,6 +351,31 @@ GSList * pango_layout_get_lines (PangoLayout *layout);
PANGO_AVAILABLE_IN_1_16
GSList * pango_layout_get_lines_readonly (PangoLayout *layout);
+#define PANGO_LAYOUT_SERIALIZE_ERROR (pango_layout_serialize_error_quark ())
+
+typedef enum {
+ PANGO_LAYOUT_SERIALIZE_INVALID,
+ PANGO_LAYOUT_SERIALIZE_INVALID_SYNTAX,
+ PANGO_LAYOUT_SERIALIZE_INVALID_VALUE,
+ PANGO_LAYOUT_SERIALIZE_MISSING_VALUE,
+} PangoLayoutSerializeError;
+
+PANGO_AVAILABLE_IN_1_50
+GQuark pango_layout_serialize_error_quark (void);
+
+PANGO_AVAILABLE_IN_1_50
+GBytes * pango_layout_serialize (PangoLayout *layout);
+
+PANGO_AVAILABLE_IN_1_50
+PangoLayout * pango_layout_deserialize (PangoContext *context,
+ GBytes *bytes,
+ GError **error);
+
+PANGO_AVAILABLE_IN_1_50
+gboolean pango_layout_write_to_file (PangoLayout *layout,
+ const char *filename,
+ GError **error);
+
#define PANGO_TYPE_LAYOUT_LINE (pango_layout_line_get_type ())
diff --git a/pango/serializer.c b/pango/serializer.c
new file mode 100644
index 00000000..576e6cf6
--- /dev/null
+++ b/pango/serializer.c
@@ -0,0 +1,935 @@
+/* Pango
+ * serializer.c: Code to serialize various Pango objects
+ *
+ * Copyright (C) 2021 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <pango/pango-layout.h>
+#include <pango/pango-layout-private.h>
+#include <pango/pango-enum-types.h>
+
+#include <json-glib/json-glib.h>
+
+/* {{{ Error handling */
+
+G_DEFINE_QUARK(pango-layout-serialize-error-quark, pango_layout_serialize_error)
+
+/* }}} */
+/* {{{ Serialization */
+
+static GType
+get_enum_type (PangoAttrType attr_type)
+{
+ switch ((int)attr_type)
+ {
+ case PANGO_ATTR_STYLE: return PANGO_TYPE_STYLE;
+ case PANGO_ATTR_WEIGHT: return PANGO_TYPE_WEIGHT;
+ case PANGO_ATTR_VARIANT: return PANGO_TYPE_VARIANT;
+ case PANGO_ATTR_STRETCH: return PANGO_TYPE_STRETCH;
+ case PANGO_ATTR_GRAVITY: return PANGO_TYPE_GRAVITY;
+ case PANGO_ATTR_GRAVITY_HINT: return PANGO_TYPE_GRAVITY_HINT;
+ case PANGO_ATTR_UNDERLINE: return PANGO_TYPE_UNDERLINE;
+ case PANGO_ATTR_OVERLINE: return PANGO_TYPE_OVERLINE;
+ case PANGO_ATTR_BASELINE_SHIFT: return PANGO_TYPE_BASELINE_SHIFT;
+ case PANGO_ATTR_FONT_SCALE: return PANGO_TYPE_FONT_SCALE;
+ case PANGO_ATTR_TEXT_TRANSFORM: return PANGO_TYPE_TEXT_TRANSFORM;
+ default: return G_TYPE_INVALID;
+ }
+}
+
+static void
+add_enum_value (JsonBuilder *builder,
+ GType type,
+ int value,
+ gboolean allow_extra)
+{
+ GEnumClass *enum_class;
+ GEnumValue *enum_value;
+
+ enum_class = g_type_class_ref (type);
+ enum_value = g_enum_get_value (enum_class, value);
+
+ if (enum_value)
+ json_builder_add_string_value (builder, enum_value->value_nick);
+ else if (allow_extra)
+ {
+ char buf[128];
+ g_snprintf (buf, 128, "%d", value);
+ json_builder_add_string_value (builder, buf);
+ }
+ else
+ json_builder_add_string_value (builder, "ERROR");
+
+}
+
+static void
+add_attribute (JsonBuilder *builder,
+ PangoAttribute *attr)
+{
+ char *str;
+
+ json_builder_begin_object (builder);
+
+ if (attr->start_index != PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING)
+ {
+ json_builder_set_member_name (builder, "start");
+ json_builder_add_int_value (builder, (int)attr->start_index);
+ }
+ if (attr->end_index != PANGO_ATTR_INDEX_TO_TEXT_END)
+ {
+ json_builder_set_member_name (builder, "end");
+ json_builder_add_int_value (builder, (int)attr->end_index);
+ }
+ json_builder_set_member_name (builder, "type");
+ add_enum_value (builder, PANGO_TYPE_ATTR_TYPE, attr->klass->type, FALSE);
+
+ json_builder_set_member_name (builder, "value");
+ switch (attr->klass->type)
+ {
+ default:
+ case PANGO_ATTR_INVALID:
+ g_assert_not_reached ();
+ case PANGO_ATTR_LANGUAGE:
+ json_builder_add_string_value (builder, pango_language_to_string (((PangoAttrLanguage*)attr)->value));
+ break;
+ case PANGO_ATTR_FAMILY:
+ case PANGO_ATTR_FONT_FEATURES:
+ json_builder_add_string_value (builder, ((PangoAttrString*)attr)->value);
+ break;
+ case PANGO_ATTR_STYLE:
+ case PANGO_ATTR_VARIANT:
+ case PANGO_ATTR_STRETCH:
+ case PANGO_ATTR_UNDERLINE:
+ case PANGO_ATTR_OVERLINE:
+ case PANGO_ATTR_GRAVITY:
+ case PANGO_ATTR_GRAVITY_HINT:
+ case PANGO_ATTR_TEXT_TRANSFORM:
+ case PANGO_ATTR_FONT_SCALE:
+ add_enum_value (builder, get_enum_type (attr->klass->type), ((PangoAttrInt*)attr)->value, FALSE);
+ break;
+ case PANGO_ATTR_WEIGHT:
+ case PANGO_ATTR_BASELINE_SHIFT:
+ add_enum_value (builder, get_enum_type (attr->klass->type), ((PangoAttrInt*)attr)->value, TRUE);
+ break;
+ case PANGO_ATTR_SIZE:
+ case PANGO_ATTR_RISE:
+ case PANGO_ATTR_LETTER_SPACING:
+ case PANGO_ATTR_ABSOLUTE_SIZE:
+ case PANGO_ATTR_FOREGROUND_ALPHA:
+ case PANGO_ATTR_BACKGROUND_ALPHA:
+ case PANGO_ATTR_SHOW:
+ case PANGO_ATTR_WORD:
+ case PANGO_ATTR_SENTENCE:
+ case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT:
+ json_builder_add_int_value (builder, ((PangoAttrInt*)attr)->value);
+ break;
+ case PANGO_ATTR_FONT_DESC:
+ str = pango_font_description_to_string (((PangoAttrFontDesc*)attr)->desc);
+ json_builder_add_string_value (builder, str);
+ g_free (str);
+ break;
+ case PANGO_ATTR_FOREGROUND:
+ case PANGO_ATTR_BACKGROUND:
+ case PANGO_ATTR_UNDERLINE_COLOR:
+ case PANGO_ATTR_OVERLINE_COLOR:
+ case PANGO_ATTR_STRIKETHROUGH_COLOR:
+ str = pango_color_to_string (&((PangoAttrColor*)attr)->color);
+ json_builder_add_string_value (builder, str);
+ g_free (str);
+ break;
+ case PANGO_ATTR_STRIKETHROUGH:
+ case PANGO_ATTR_FALLBACK:
+ case PANGO_ATTR_ALLOW_BREAKS:
+ case PANGO_ATTR_INSERT_HYPHENS:
+ json_builder_add_boolean_value (builder, ((PangoAttrInt*)attr)->value != 0);
+ break;
+ case PANGO_ATTR_SHAPE:
+ json_builder_add_string_value (builder, "shape");
+ break;
+ case PANGO_ATTR_SCALE:
+ case PANGO_ATTR_LINE_HEIGHT:
+ json_builder_add_double_value (builder, ((PangoAttrFloat*)attr)->value);
+ }
+
+ json_builder_end_object (builder);
+}
+
+static void
+add_attr_list (JsonBuilder *builder,
+ PangoAttrList *attrs)
+{
+ GSList *attributes, *l;
+
+ json_builder_begin_array (builder);
+
+ attributes = pango_attr_list_get_attributes (attrs);
+ for (l = attributes; l; l = l->next)
+ {
+ PangoAttribute *attr = l->data;
+ add_attribute (builder, attr);
+ }
+ g_slist_free_full (attributes, (GDestroyNotify) pango_attribute_destroy);
+
+ json_builder_end_array (builder);
+}
+
+static void
+add_tab_array (JsonBuilder *builder,
+ PangoTabArray *tabs)
+{
+ json_builder_begin_object (builder);
+
+ json_builder_set_member_name (builder, "positions-in-pixels");
+ json_builder_add_boolean_value (builder, pango_tab_array_get_positions_in_pixels (tabs));
+ json_builder_set_member_name (builder, "positions");
+ json_builder_begin_array (builder);
+ for (int i = 0; i < pango_tab_array_get_size (tabs); i++)
+ {
+ int pos;
+ pango_tab_array_get_tab (tabs, i, NULL, &pos);
+ json_builder_add_int_value (builder, pos);
+ }
+ json_builder_end_array (builder);
+
+ json_builder_end_object (builder);
+}
+
+static JsonNode *
+layout_to_json (PangoLayout *layout)
+{
+ JsonBuilder *builder;
+ JsonNode *root;
+
+ builder = json_builder_new_immutable ();
+
+ json_builder_begin_object (builder);
+
+ json_builder_set_member_name (builder, "text");
+ json_builder_add_string_value (builder, layout->text);
+
+ if (layout->attrs)
+ {
+ json_builder_set_member_name (builder, "attributes");
+ add_attr_list (builder, layout->attrs);
+ }
+
+ if (layout->font_desc)
+ {
+ char *str = pango_font_description_to_string (layout->font_desc);
+ json_builder_set_member_name (builder, "font");
+ json_builder_add_string_value (builder, str);
+ g_free (str);
+ }
+
+ if (layout->tabs)
+ {
+ json_builder_set_member_name (builder, "tabs");
+ add_tab_array (builder, layout->tabs);
+ }
+
+ if (layout->justify)
+ {
+ json_builder_set_member_name (builder, "justify");
+ json_builder_add_boolean_value (builder, TRUE);
+ }
+
+ if (layout->justify_last_line)
+ {
+ json_builder_set_member_name (builder, "justify-last-line");
+ json_builder_add_boolean_value (builder, TRUE);
+ }
+
+ if (layout->single_paragraph)
+ {
+ json_builder_set_member_name (builder, "single-paragraph");
+ json_builder_add_boolean_value (builder, TRUE);
+ }
+
+ if (!layout->auto_dir)
+ {
+ json_builder_set_member_name (builder, "auto-dir");
+ json_builder_add_boolean_value (builder, FALSE);
+ }
+
+ if (layout->alignment != PANGO_ALIGN_LEFT)
+ {
+ json_builder_set_member_name (builder, "alignment");
+ add_enum_value (builder, PANGO_TYPE_ALIGNMENT, layout->alignment, FALSE);
+ }
+
+ if (layout->wrap != PANGO_WRAP_WORD)
+ {
+ json_builder_set_member_name (builder, "wrap");
+ add_enum_value (builder, PANGO_TYPE_WRAP_MODE, layout->wrap, FALSE);
+ }
+
+ if (layout->ellipsize != PANGO_ELLIPSIZE_NONE)
+ {
+ json_builder_set_member_name (builder, "ellipsize");
+ add_enum_value (builder, PANGO_TYPE_ELLIPSIZE_MODE, layout->ellipsize, FALSE);
+ }
+
+ if (layout->width != -1)
+ {
+ json_builder_set_member_name (builder, "width");
+ json_builder_add_int_value (builder, layout->width);
+ }
+
+ if (layout->height != -1)
+ {
+ json_builder_set_member_name (builder, "height");
+ json_builder_add_int_value (builder, layout->height);
+ }
+
+ if (layout->indent != 0)
+ {
+ json_builder_set_member_name (builder, "indent");
+ json_builder_add_int_value (builder, layout->indent);
+ }
+
+ if (layout->spacing != 0)
+ {
+ json_builder_set_member_name (builder, "spacing");
+ json_builder_add_int_value (builder, layout->spacing);
+ }
+
+ if (layout->line_spacing != 0.)
+ {
+ json_builder_set_member_name (builder, "line-spacing");
+ json_builder_add_double_value (builder, layout->line_spacing);
+ }
+
+ json_builder_end_object (builder);
+
+ root = json_builder_get_root (builder);
+ g_object_unref (builder);
+
+ return root;
+}
+
+/* }}} */
+/* {{{ Deserialization */
+
+static int
+get_enum_value (GType type,
+ const char *str,
+ gboolean allow_extra)
+{
+ GEnumClass *enum_class;
+ GEnumValue *enum_value;
+
+ enum_class = g_type_class_ref (type);
+ enum_value = g_enum_get_value_by_nick (enum_class, str);
+
+ if (enum_value)
+ return enum_value->value;
+
+ if (allow_extra)
+ {
+ gint64 value;
+ char *endp;
+
+ value = g_ascii_strtoll (str, &endp, 10);
+ if (*endp == '\0')
+ return value;
+ }
+
+ return -1;
+}
+
+static PangoAttribute *
+json_to_attribute (JsonReader *reader,
+ GError **error)
+{
+ PangoAttribute *attr = NULL;
+ PangoAttrType type = PANGO_ATTR_INVALID;
+ guint start = PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING;
+ guint end = PANGO_ATTR_INDEX_TO_TEXT_END;
+ PangoFontDescription *desc;
+ PangoColor color;
+
+ if (!json_reader_is_object (reader))
+ {
+ g_set_error (error,
+ PANGO_LAYOUT_SERIALIZE_ERROR, PANGO_LAYOUT_SERIALIZE_INVALID_SYNTAX,
+ "Attribute must be a Json object");
+ return NULL;
+ }
+
+ if (json_reader_read_member (reader, "start"))
+ start = json_reader_get_int_value (reader);
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "end"))
+ end = json_reader_get_int_value (reader);
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "type"))
+ {
+ type = get_enum_value (PANGO_TYPE_ATTR_TYPE, json_reader_get_string_value (reader), FALSE);
+ if (type == -1 || type == PANGO_ATTR_INVALID)
+ {
+ g_set_error (error,
+ PANGO_LAYOUT_SERIALIZE_ERROR, PANGO_LAYOUT_SERIALIZE_INVALID_VALUE,
+ "Attribute \"type\" invalid: %s",
+ json_reader_get_string_value (reader));
+ return NULL;
+ }
+ json_reader_end_member (reader);
+ }
+ else
+ {
+ g_set_error (error,
+ PANGO_LAYOUT_SERIALIZE_ERROR, PANGO_LAYOUT_SERIALIZE_MISSING_VALUE,
+ "Attribute \"type\" missing");
+ json_reader_end_member (reader);
+ return NULL;
+ }
+
+ if (!json_reader_read_member (reader, "value"))
+ {
+ g_set_error (error,
+ PANGO_LAYOUT_SERIALIZE_ERROR, PANGO_LAYOUT_SERIALIZE_MISSING_VALUE,
+ "Attribute \"value\" missing");
+ json_reader_end_member (reader);
+ return NULL;
+ }
+
+ switch (type)
+ {
+ default:
+ case PANGO_ATTR_INVALID:
+ g_assert_not_reached ();
+
+ case PANGO_ATTR_LANGUAGE:
+ attr = pango_attr_language_new (pango_language_from_string (json_reader_get_string_value (reader)));
+ break;
+ case PANGO_ATTR_FAMILY:
+ attr = pango_attr_family_new (json_reader_get_string_value (reader));
+ break;
+ case PANGO_ATTR_STYLE:
+ attr = pango_attr_style_new (get_enum_value (PANGO_TYPE_STYLE, json_reader_get_string_value (reader), FALSE));
+ break;
+ case PANGO_ATTR_WEIGHT:
+ attr = pango_attr_weight_new (get_enum_value (PANGO_TYPE_WEIGHT, json_reader_get_string_value (reader), TRUE));
+ break;
+ case PANGO_ATTR_VARIANT:
+ attr = pango_attr_variant_new (get_enum_value (PANGO_TYPE_VARIANT, json_reader_get_string_value (reader), FALSE));
+ break;
+ case PANGO_ATTR_STRETCH:
+ attr = pango_attr_stretch_new (get_enum_value (PANGO_TYPE_STRETCH, json_reader_get_string_value (reader), FALSE));
+ break;
+ case PANGO_ATTR_SIZE:
+ attr = pango_attr_size_new (json_reader_get_int_value (reader));
+ break;
+ case PANGO_ATTR_FONT_DESC:
+ desc = pango_font_description_from_string (json_reader_get_string_value (reader));
+ attr = pango_attr_font_desc_new (desc);
+ pango_font_description_free (desc);
+ break;
+ case PANGO_ATTR_FOREGROUND:
+ pango_color_parse (&color, json_reader_get_string_value (reader));
+ attr = pango_attr_foreground_new (color.red, color.green, color.blue);
+ break;
+ case PANGO_ATTR_BACKGROUND:
+ pango_color_parse (&color, json_reader_get_string_value (reader));
+ attr = pango_attr_background_new (color.red, color.green, color.blue);
+ break;
+ case PANGO_ATTR_UNDERLINE:
+ attr = pango_attr_underline_new (get_enum_value (PANGO_TYPE_UNDERLINE, json_reader_get_string_value (reader), FALSE));
+ break;
+ case PANGO_ATTR_STRIKETHROUGH:
+ attr = pango_attr_strikethrough_new (json_reader_get_boolean_value (reader));
+ break;
+ case PANGO_ATTR_RISE:
+ attr = pango_attr_rise_new (json_reader_get_int_value (reader));
+ break;
+ case PANGO_ATTR_SHAPE:
+ /* FIXME */
+ attr = pango_attr_shape_new (&(PangoRectangle) { 0, 0, 0, 0}, &(PangoRectangle) { 0, 0, 0, 0});
+ break;
+ case PANGO_ATTR_SCALE:
+ attr = pango_attr_scale_new (json_reader_get_double_value (reader));
+ break;
+ case PANGO_ATTR_FALLBACK:
+ attr = pango_attr_fallback_new (json_reader_get_boolean_value (reader));
+ break;
+ case PANGO_ATTR_LETTER_SPACING:
+ attr = pango_attr_letter_spacing_new (json_reader_get_int_value (reader));
+ break;
+ case PANGO_ATTR_UNDERLINE_COLOR:
+ pango_color_parse (&color, json_reader_get_string_value (reader));
+ attr = pango_attr_underline_color_new (color.red, color.green, color.blue);
+ break;
+ case PANGO_ATTR_STRIKETHROUGH_COLOR:
+ pango_color_parse (&color, json_reader_get_string_value (reader));
+ attr = pango_attr_strikethrough_color_new (color.red, color.green, color.blue);
+ break;
+ case PANGO_ATTR_ABSOLUTE_SIZE:
+ attr = pango_attr_size_new_absolute (json_reader_get_int_value (reader));
+ break;
+ case PANGO_ATTR_GRAVITY:
+ attr = pango_attr_gravity_new (get_enum_value (PANGO_TYPE_GRAVITY, json_reader_get_string_value (reader), FALSE));
+ break;
+ case PANGO_ATTR_GRAVITY_HINT:
+ attr = pango_attr_gravity_hint_new (get_enum_value (PANGO_TYPE_GRAVITY_HINT, json_reader_get_string_value (reader), FALSE));
+ break;
+ case PANGO_ATTR_FONT_FEATURES:
+ attr = pango_attr_font_features_new (json_reader_get_string_value (reader));
+ break;
+ case PANGO_ATTR_FOREGROUND_ALPHA:
+ attr = pango_attr_foreground_alpha_new (json_reader_get_int_value (reader));
+ break;
+ case PANGO_ATTR_BACKGROUND_ALPHA:
+ attr = pango_attr_background_alpha_new (json_reader_get_int_value (reader));
+ break;
+ case PANGO_ATTR_ALLOW_BREAKS:
+ attr = pango_attr_allow_breaks_new (json_reader_get_boolean_value (reader));
+ break;
+ case PANGO_ATTR_SHOW:
+ attr = pango_attr_show_new (json_reader_get_int_value (reader));
+ break;
+ case PANGO_ATTR_INSERT_HYPHENS:
+ attr = pango_attr_insert_hyphens_new (json_reader_get_boolean_value (reader));
+ break;
+ case PANGO_ATTR_OVERLINE:
+ attr = pango_attr_overline_new (get_enum_value (PANGO_TYPE_OVERLINE, json_reader_get_string_value (reader), FALSE));
+ break;
+ case PANGO_ATTR_OVERLINE_COLOR:
+ pango_color_parse (&color, json_reader_get_string_value (reader));
+ attr = pango_attr_overline_color_new (color.red, color.green, color.blue);
+ break;
+ case PANGO_ATTR_LINE_HEIGHT:
+ attr = pango_attr_line_height_new (json_reader_get_double_value (reader));
+ break;
+ case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT:
+ attr = pango_attr_line_height_new_absolute (json_reader_get_int_value (reader));
+ break;
+ case PANGO_ATTR_TEXT_TRANSFORM:
+ attr = pango_attr_text_transform_new (get_enum_value (PANGO_TYPE_TEXT_TRANSFORM, json_reader_get_string_value (reader), FALSE));
+ break;
+ case PANGO_ATTR_WORD:
+ attr = pango_attr_word_new ();
+ break;
+ case PANGO_ATTR_SENTENCE:
+ attr = pango_attr_sentence_new ();
+ break;
+ case PANGO_ATTR_BASELINE_SHIFT:
+ attr = pango_attr_baseline_shift_new (get_enum_value (PANGO_TYPE_BASELINE_SHIFT, json_reader_get_string_value (reader), TRUE));
+ break;
+ case PANGO_ATTR_FONT_SCALE:
+ attr = pango_attr_font_scale_new (get_enum_value (PANGO_TYPE_BASELINE_SHIFT, json_reader_get_string_value (reader), FALSE));
+ break;
+ }
+
+ attr->start_index = start;
+ attr->end_index = end;
+
+ json_reader_end_member (reader);
+
+ return attr;
+}
+
+static PangoAttrList *
+json_to_attr_list (JsonReader *reader,
+ GError **error)
+{
+ PangoAttrList *attributes;
+
+ if (!json_reader_is_array (reader))
+ {
+ g_set_error (error,
+ PANGO_LAYOUT_SERIALIZE_ERROR, PANGO_LAYOUT_SERIALIZE_INVALID_SYNTAX,
+ "\"attributes\" must be a Json array");
+ goto fail;
+ }
+
+ attributes = pango_attr_list_new ();
+
+ for (int i = 0; i < json_reader_count_elements (reader); i++)
+ {
+ PangoAttribute *attr;
+ json_reader_read_element (reader, i);
+ attr = json_to_attribute (reader, error);
+ if (!attr)
+ goto fail;
+ pango_attr_list_insert (attributes, attr);
+ json_reader_end_element (reader);
+ }
+
+ return attributes;
+
+fail:
+ if (attributes)
+ pango_attr_list_unref (attributes);
+ return NULL;
+}
+
+static PangoTabArray *
+json_to_tab_array (JsonReader *reader,
+ GError **error)
+{
+ PangoTabArray *tabs;
+ gboolean positions_in_pixels = FALSE;
+
+ if (json_reader_read_member (reader, "positions-in-pixels"))
+ positions_in_pixels = json_reader_get_boolean_value (reader);
+ json_reader_end_member (reader);
+
+ tabs = pango_tab_array_new (0, positions_in_pixels);
+
+ if (json_reader_read_member (reader, "positions"))
+ {
+ if (!json_reader_is_array (reader))
+ {
+ g_set_error (error,
+ PANGO_LAYOUT_SERIALIZE_ERROR,
+ PANGO_LAYOUT_SERIALIZE_INVALID_SYNTAX,
+ "Tab \"positions\" must be a Json array");
+ goto fail;
+ }
+
+ pango_tab_array_resize (tabs, json_reader_count_elements (reader));
+ for (int i = 0; i < json_reader_count_elements (reader); i++)
+ {
+ int pos;
+ json_reader_read_element (reader, i);
+ pos = json_reader_get_int_value (reader);
+ pango_tab_array_set_tab (tabs, i, PANGO_TAB_LEFT, pos);
+ json_reader_end_element (reader);
+ }
+ }
+ json_reader_end_member (reader);
+
+ return tabs;
+
+fail:
+ if (tabs)
+ pango_tab_array_free (tabs);
+ return NULL;
+}
+
+static PangoLayout *
+json_to_layout (PangoContext *context,
+ JsonNode *node,
+ GError **error)
+{
+ JsonReader *reader;
+ PangoLayout *layout;
+
+ layout = pango_layout_new (context);
+
+ reader = json_reader_new (node);
+ if (!json_reader_is_object (reader))
+ {
+ g_set_error (error,
+ PANGO_LAYOUT_SERIALIZE_ERROR,
+ PANGO_LAYOUT_SERIALIZE_INVALID_SYNTAX,
+ "Layout must be a Json object");
+ goto fail;
+ }
+
+ if (json_reader_read_member (reader, "text"))
+ pango_layout_set_text (layout, json_reader_get_string_value (reader), -1);
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "attributes"))
+ {
+ PangoAttrList *attributes;
+
+ attributes = json_to_attr_list (reader, error);
+
+ if (!attributes)
+ goto fail;
+
+ pango_layout_set_attributes (layout, attributes);
+ pango_attr_list_unref (attributes);
+ }
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "font"))
+ {
+ PangoFontDescription *desc;
+
+ desc = pango_font_description_from_string ( json_reader_get_string_value (reader));
+ if (!desc)
+ {
+ g_set_error (error,
+ PANGO_LAYOUT_SERIALIZE_ERROR,
+ PANGO_LAYOUT_SERIALIZE_INVALID_VALUE,
+ "Could not parse \"font\" value: %s",
+ json_reader_get_string_value (reader));
+ goto fail;
+ }
+ pango_layout_set_font_description (layout, desc);
+ pango_font_description_free (desc);
+ }
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "tabs"))
+ {
+ PangoTabArray *tabs;
+
+ tabs = json_to_tab_array (reader, error);
+
+ if (!tabs)
+ goto fail;
+
+ pango_layout_set_tabs (layout, tabs);
+ pango_tab_array_free (tabs);
+ }
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "justify"))
+ pango_layout_set_justify (layout, json_reader_get_boolean_value (reader));
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "justify-last-line"))
+ pango_layout_set_justify_last_line (layout, json_reader_get_boolean_value (reader));
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "single-paragraph"))
+ pango_layout_set_single_paragraph_mode (layout, json_reader_get_boolean_value (reader));
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "auto-dir"))
+ pango_layout_set_auto_dir (layout, json_reader_get_boolean_value (reader));
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "alignment"))
+ {
+ PangoAlignment align = get_enum_value (PANGO_TYPE_ALIGNMENT,
+ json_reader_get_string_value (reader),
+ FALSE);
+ if (align == -1)
+ {
+ g_set_error (error,
+ PANGO_LAYOUT_SERIALIZE_ERROR,
+ PANGO_LAYOUT_SERIALIZE_INVALID_VALUE,
+ "Could not parse \"alignment\" value: %s",
+ json_reader_get_string_value (reader));
+ goto fail;
+ }
+
+ pango_layout_set_alignment (layout, align);
+ }
+
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "wrap"))
+ {
+ PangoWrapMode wrap = get_enum_value (PANGO_TYPE_WRAP_MODE,
+ json_reader_get_string_value (reader),
+ FALSE);
+
+ if (wrap == -1)
+ {
+ g_set_error (error,
+ PANGO_LAYOUT_SERIALIZE_ERROR,
+ PANGO_LAYOUT_SERIALIZE_INVALID_VALUE,
+ "Could not parse \"wrap\" value: %s",
+ json_reader_get_string_value (reader));
+ goto fail;
+ }
+
+ pango_layout_set_wrap (layout, wrap);
+ }
+
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "ellipsize"))
+ {
+ PangoEllipsizeMode ellipsize = get_enum_value (PANGO_TYPE_ELLIPSIZE_MODE,
+ json_reader_get_string_value (reader),
+ FALSE);
+
+ if (ellipsize == -1)
+ {
+ g_set_error (error,
+ PANGO_LAYOUT_SERIALIZE_ERROR,
+ PANGO_LAYOUT_SERIALIZE_INVALID_VALUE,
+ "Could not parse \"ellipsize\" value: %s",
+ json_reader_get_string_value (reader));
+ goto fail;
+ }
+
+ pango_layout_set_ellipsize (layout, ellipsize);
+ }
+
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "width"))
+ pango_layout_set_width (layout, json_reader_get_int_value (reader));
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "height"))
+ pango_layout_set_height (layout, json_reader_get_int_value (reader));
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "indent"))
+ pango_layout_set_indent (layout, json_reader_get_int_value (reader));
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "spacing"))
+ pango_layout_set_spacing (layout, json_reader_get_int_value (reader));
+ json_reader_end_member (reader);
+
+ if (json_reader_read_member (reader, "line-spacing"))
+ pango_layout_set_line_spacing (layout, json_reader_get_double_value (reader));
+ json_reader_end_member (reader);
+
+ g_object_unref (reader);
+
+ return layout;
+
+fail:
+ g_object_unref (reader);
+ g_object_unref (layout);
+ return NULL;
+}
+
+ /* }}} */
+ /* {{{ Public API */
+
+/**
+ * pango_layout_serialize:
+ * @layout: a `PangoLayout`
+ *
+ * Serializes the @layout for later deserialization via [method@Pango.Layout.deserialize].
+ *
+ * There are no guarantees about the format of the output accross different
+ * versions of Pango and [method@Pango.Layout.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
+ *
+ * Since: 1.50
+ */
+GBytes *
+pango_layout_serialize (PangoLayout *layout)
+{
+ JsonGenerator *generator;
+ JsonNode *node;
+ char *data;
+ gsize size;
+
+ node = layout_to_json (layout);
+
+ generator = json_generator_new ();
+ json_generator_set_pretty (generator, TRUE);
+ json_generator_set_indent (generator, 2);
+
+ json_generator_set_root (generator, node);
+ data = json_generator_to_data (generator, &size);
+
+ json_node_free (node);
+ g_object_unref (generator);
+
+ return g_bytes_new_take (data, size);
+}
+
+/**
+ * pango_layout_write_to_file:
+ * @layout: a `PangoLayout`
+ * @filename: (type filename): the file to save it to
+ * @error: Return location for a potential error
+ *
+ * This function is equivalent to calling [method@Pango.Layout.serialize]
+ * followed by g_file_set_contents().
+ *
+ * See those two functions for details on the arguments.
+ *
+ * It is mostly intended for use inside a debugger to quickly dump
+ * a layout to a file for later inspection.
+ *
+ * Returns: %TRUE if saving was successful
+ *
+ * Since: 1.50
+ */
+gboolean
+pango_layout_write_to_file (PangoLayout *layout,
+ const char *filename,
+ GError **error)
+{
+ GBytes *bytes;
+ gboolean result;
+
+ g_return_val_if_fail (PANGO_IS_LAYOUT (layout), FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ bytes = pango_layout_serialize (layout);
+ result = g_file_set_contents (filename,
+ g_bytes_get_data (bytes, NULL),
+ g_bytes_get_size (bytes),
+ error);
+ g_bytes_unref (bytes);
+
+ return result;
+
+}
+
+/**
+ * pango_layout_deserialize:
+ * @context: a `PangoContext`
+ * @bytes: the bytes containing the data
+ * @error: return location for an error
+ *
+ * Loads data previously created via [method@Pango.Layout.serialize].
+ *
+ * For a discussion of the supported format, see that function.
+ *
+ * Returns: (nullable) (transfer full): a new `PangoLayout`
+ *
+ * Since: 1.50
+ */
+PangoLayout *
+pango_layout_deserialize (PangoContext *context,
+ GBytes *bytes,
+ GError **error)
+{
+ JsonParser *parser;
+ JsonNode *node;
+ PangoLayout *layout;
+
+ parser = json_parser_new_immutable ();
+ if (!json_parser_load_from_data (parser,
+ g_bytes_get_data (bytes, NULL),
+ g_bytes_get_size (bytes),
+ error))
+ {
+ g_object_unref (parser);
+ return NULL;
+ }
+
+ node = json_parser_get_root (parser);
+ layout = json_to_layout (context, node, error);
+
+ g_object_unref (parser);
+
+ return layout;
+}
+
+/* }}} */
+
+/* vim:set foldmethod=marker expandtab: */
diff --git a/subprojects/json-glib.wrap b/subprojects/json-glib.wrap
new file mode 100644
index 00000000..b88acd72
--- /dev/null
+++ b/subprojects/json-glib.wrap
@@ -0,0 +1,5 @@
+[wrap-git]
+directory=json-glib
+url=https://gitlab.gnome.org/GNOME/json-glib.git
+revision=master
+depth=1
diff --git a/tests/layouts/valid-1.layout b/tests/layouts/valid-1.layout
new file mode 100644
index 00000000..9289830b
--- /dev/null
+++ b/tests/layouts/valid-1.layout
@@ -0,0 +1,20 @@
+{
+ "text" : "This is a test of the automatic emergency brake!\n",
+ "attributes" : [
+ {
+ "start" : 22,
+ "end" : 41,
+ "type" : "foreground",
+ "value" : "#00000000ffff"
+ },
+ {
+ "start" : 22,
+ "end" : 41,
+ "type" : "underline",
+ "value" : "single"
+ }
+ ],
+ "font" : "Cantarell 11",
+ "ellipsize" : "end",
+ "width" : 225280
+}
diff --git a/tests/layouts/valid-1.markup b/tests/layouts/valid-1.markup
deleted file mode 100644
index 780e6831..00000000
--- a/tests/layouts/valid-1.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-width=220,ellipsize=end
-This is a test of the <span foreground="#0000ff" underline="single">automatic emergency</span> brake!
diff --git a/tests/layouts/valid-10.layout b/tests/layouts/valid-10.layout
new file mode 100644
index 00000000..0d36a38d
--- /dev/null
+++ b/tests/layouts/valid-10.layout
@@ -0,0 +1,8 @@
+{
+ "text" : "Hello שלום Γειά σας\n",
+ "attributes" : [],
+ "font" : "Cantarell 11",
+ "justify" : true,
+ "ellipsize" : "end",
+ "width" : 102400
+}
diff --git a/tests/layouts/valid-10.markup b/tests/layouts/valid-10.markup
deleted file mode 100644
index 15bf693d..00000000
--- a/tests/layouts/valid-10.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-width=100,justify=true,ellipsize=end
-Hello שלום Γειά σας
diff --git a/tests/layouts/valid-11.layout b/tests/layouts/valid-11.layout
new file mode 100644
index 00000000..a044cc53
--- /dev/null
+++ b/tests/layouts/valid-11.layout
@@ -0,0 +1,42 @@
+{
+ "text" : "double low error\n",
+ "attributes" : [
+ {
+ "end" : 6,
+ "type" : "underline",
+ "value" : "double"
+ },
+ {
+ "end" : 6,
+ "type" : "overline",
+ "value" : "single"
+ },
+ {
+ "start" : 7,
+ "end" : 10,
+ "type" : "underline",
+ "value" : "low"
+ },
+ {
+ "start" : 7,
+ "end" : 10,
+ "type" : "strikethrough",
+ "value" : true
+ },
+ {
+ "start" : 11,
+ "end" : 16,
+ "type" : "underline",
+ "value" : "error"
+ },
+ {
+ "start" : 11,
+ "end" : 16,
+ "type" : "rise",
+ "value" : 1024
+ }
+ ],
+ "font" : "Cantarell 11",
+ "wrap" : "char",
+ "width" : 225280
+}
diff --git a/tests/layouts/valid-11.markup b/tests/layouts/valid-11.markup
deleted file mode 100644
index fbf1abd2..00000000
--- a/tests/layouts/valid-11.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-width=220,wrap=char
-<span underline='double' overline='single'>double</span> <span underline='low' strikethrough='true'>low</span> <span underline='error' rise='1024'>error</span>
diff --git a/tests/layouts/valid-12.layout b/tests/layouts/valid-12.layout
new file mode 100644
index 00000000..1c9fa227
--- /dev/null
+++ b/tests/layouts/valid-12.layout
@@ -0,0 +1,15 @@
+{
+ "text" : "a b c d
e f g h\n",
+ "attributes" : [],
+ "font" : "Cantarell 11",
+ "tabs" : {
+ "positions-in-pixels" : true,
+ "positions" : [
+ 0,
+ 50,
+ 100,
+ 150,
+ 200
+ ]
+ }
+}
diff --git a/tests/layouts/valid-12.markup b/tests/layouts/valid-12.markup
deleted file mode 100644
index b7306cc6..00000000
--- a/tests/layouts/valid-12.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-wrap=word,tabs=0 50 100 150 200
-a b c d
e f g h
diff --git a/tests/layouts/valid-13.layout b/tests/layouts/valid-13.layout
new file mode 100644
index 00000000..a9f10f86
--- /dev/null
+++ b/tests/layouts/valid-13.layout
@@ -0,0 +1,16 @@
+{
+ "text" : "a b c d
e f g h\n",
+ "attributes" : [],
+ "font" : "Cantarell 11",
+ "tabs" : {
+ "positions-in-pixels" : true,
+ "positions" : [
+ 0,
+ 50,
+ 100,
+ 150,
+ 200
+ ]
+ },
+ "single-paragraph" : true
+}
diff --git a/tests/layouts/valid-13.markup b/tests/layouts/valid-13.markup
deleted file mode 100644
index be2345d1..00000000
--- a/tests/layouts/valid-13.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-wrap=word,tabs=0 50 100 150 200,single_paragraph=true
-a b c d
e f g h
diff --git a/tests/layouts/valid-14.layout b/tests/layouts/valid-14.layout
new file mode 100644
index 00000000..116cc94f
--- /dev/null
+++ b/tests/layouts/valid-14.layout
@@ -0,0 +1,8 @@
+{
+ "text" : "你好 Hello שלום Γειά σας\n",
+ "attributes" : [],
+ "font" : "Cantarell 11",
+ "ellipsize" : "start",
+ "width" : 161792,
+ "line-spacing" : 1.5
+}
diff --git a/tests/layouts/valid-14.markup b/tests/layouts/valid-14.markup
deleted file mode 100644
index 1d556d26..00000000
--- a/tests/layouts/valid-14.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-line_spacing=1.5,width=158,ellipsize=start
-你好 Hello שלום Γειά σας
diff --git a/tests/layouts/valid-15.layout b/tests/layouts/valid-15.layout
new file mode 100644
index 00000000..9f584ba6
--- /dev/null
+++ b/tests/layouts/valid-15.layout
@@ -0,0 +1,8 @@
+{
+ "text" : "Lets see if this text is long enough to wrap due to height limitations. It might, or it might not.\n",
+ "attributes" : [],
+ "font" : "Cantarell 11",
+ "ellipsize" : "end",
+ "width" : 153600,
+ "height" : 40960
+}
diff --git a/tests/layouts/valid-15.markup b/tests/layouts/valid-15.markup
deleted file mode 100644
index e3081c81..00000000
--- a/tests/layouts/valid-15.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-ellipsize=end,height=40,width=150
-Lets see if this text is long enough to wrap due to height limitations. It might, or it might not.
diff --git a/tests/layouts/valid-16.layout b/tests/layouts/valid-16.layout
new file mode 100644
index 00000000..e2a82d96
--- /dev/null
+++ b/tests/layouts/valid-16.layout
@@ -0,0 +1,9 @@
+{
+ "text" : "Lets see if this text is long enough to wrap due to height limitations. It might, or it might not.\n",
+ "attributes" : [],
+ "font" : "Cantarell 11",
+ "wrap" : "word-char",
+ "ellipsize" : "end",
+ "width" : 153600,
+ "height" : -2
+}
diff --git a/tests/layouts/valid-16.markup b/tests/layouts/valid-16.markup
deleted file mode 100644
index 91a8ae37..00000000
--- a/tests/layouts/valid-16.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-wrap=word-char,ellipsize=end,width=150,height=-2
-Lets see if this text is long enough to wrap due to height limitations. It might, or it might not.
diff --git a/tests/layouts/valid-17.layout b/tests/layouts/valid-17.layout
new file mode 100644
index 00000000..062cc241
--- /dev/null
+++ b/tests/layouts/valid-17.layout
@@ -0,0 +1,7 @@
+{
+ "text" : "some|bla|bla|bla\n",
+ "attributes" : [],
+ "font" : "Cantarell 11",
+ "justify" : true,
+ "width" : 102400
+}
diff --git a/tests/layouts/valid-17.markup b/tests/layouts/valid-17.markup
deleted file mode 100644
index d804c20a..00000000
--- a/tests/layouts/valid-17.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-justify=true,width=100
-some|bla|bla|bla
diff --git a/tests/layouts/valid-18.layout b/tests/layouts/valid-18.layout
new file mode 100644
index 00000000..85e9a7d1
--- /dev/null
+++ b/tests/layouts/valid-18.layout
@@ -0,0 +1,11 @@
+{
+ "text" : "some line breaks
and mis­ce­llaneous ignora‌bles\n",
+ "attributes" : [
+ {
+ "end" : 57,
+ "type" : "show",
+ "value" : 7
+ }
+ ],
+ "font" : "Cantarell 11"
+}
diff --git a/tests/layouts/valid-18.markup b/tests/layouts/valid-18.markup
deleted file mode 100644
index ab5f5f35..00000000
--- a/tests/layouts/valid-18.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-
-<span show="spaces|line-breaks|ignorables">some line breaks
and mis­ce­llaneous ignora‌bles</span>
diff --git a/tests/layouts/valid-19.layout b/tests/layouts/valid-19.layout
new file mode 100644
index 00000000..32ad1283
--- /dev/null
+++ b/tests/layouts/valid-19.layout
@@ -0,0 +1,5 @@
+{
+ "text" : " a⃠ 😊︎ 😊️ 🇩🇪 ✊ ✋🏾 0 # 🏴󠁵󠁳󠁣󠁡󠁿 ©\n",
+ "attributes" : [],
+ "font" : "Cantarell 11"
+}
diff --git a/tests/layouts/valid-19.markup b/tests/layouts/valid-19.markup
deleted file mode 100644
index e48c9f0e..00000000
--- a/tests/layouts/valid-19.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-# various Emoji segmentation cases
- a⃠ 😊︎ 😊️ 🇩🇪 ✊ ✋🏾 0 # 🏴󠁵󠁳󠁣󠁡󠁿 ©
diff --git a/tests/layouts/valid-2.layout b/tests/layouts/valid-2.layout
new file mode 100644
index 00000000..303b2b67
--- /dev/null
+++ b/tests/layouts/valid-2.layout
@@ -0,0 +1,18 @@
+{
+ "text" : "test the blue drink after dinner\n",
+ "attributes" : [
+ {
+ "start" : 9,
+ "end" : 13,
+ "type" : "style",
+ "value" : "italic"
+ },
+ {
+ "start" : 20,
+ "end" : 25,
+ "type" : "underline",
+ "value" : "single"
+ }
+ ],
+ "font" : "Cantarell 11"
+}
diff --git a/tests/layouts/valid-2.markup b/tests/layouts/valid-2.markup
deleted file mode 100644
index 677f26f8..00000000
--- a/tests/layouts/valid-2.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-
-test the <i>blue</i> drink <u>after</u> dinner
diff --git a/tests/layouts/valid-20.layout b/tests/layouts/valid-20.layout
new file mode 100644
index 00000000..bde84b6f
--- /dev/null
+++ b/tests/layouts/valid-20.layout
@@ -0,0 +1,22 @@
+{
+ "text" : "abcdef\n",
+ "attributes" : [
+ {
+ "end" : 3,
+ "type" : "gravity",
+ "value" : "east"
+ },
+ {
+ "end" : 3,
+ "type" : "gravity-hint",
+ "value" : "strong"
+ },
+ {
+ "start" : 3,
+ "end" : 6,
+ "type" : "gravity",
+ "value" : "south"
+ }
+ ],
+ "font" : "Cantarell 11"
+}
diff --git a/tests/layouts/valid-20.markup b/tests/layouts/valid-20.markup
deleted file mode 100644
index fe6480d7..00000000
--- a/tests/layouts/valid-20.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-# exercise gravity handling
-<span gravity='east' gravity_hint='strong'>abc</span><span gravity='south'>def</span>
diff --git a/tests/layouts/valid-21.expected b/tests/layouts/valid-21.expected
deleted file mode 100644
index 5999056f..00000000
--- a/tests/layouts/valid-21.expected
+++ /dev/null
@@ -1,36 +0,0 @@
-有一位住在石室裏的詩人叫施氏,abc, 愛吃獅子,決心要吃十隻獅子。
-
---- parameters
-
-wrapped: 0
-ellipsized: 0
-lines: 2
-
---- attributes
-
-range 0 2147483647
-
---- directions
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-
---- cursor positions
-
-0(0) 3(0) 6(0) 9(0) 12(0) 15(0) 18(0) 21(0) 24(0) 27(0) 30(0) 33(0) 36(0) 39(0) 42(0) 45(0) 46(0) 47(0) 48(0) 49(0) 50(0) 53(0) 56(0) 59(0) 62(0) 65(0) 68(0) 71(0) 74(0) 77(0) 80(0) 83(0) 86(0) 89(0) 89(1) 93(0)
-
---- lines
-
-i=1, index=0, paragraph-start=1, dir=ltr '有一位住在石室裏的詩人叫施氏,abc, 愛吃獅子,決心要吃十隻獅子。
-'
-i=2, index=93, paragraph-start=1, dir=ltr ''
-
---- runs
-
-i=1, index=0, chars=14, level=0, gravity=east, flags=1, font=OMITTED, script=han, language=xx, '有一位住在石室裏的詩人叫施氏'
-i=2, index=42, chars=1, level=0, gravity=east, flags=1, font=OMITTED, script=han, language=xx, ','
-i=3, index=45, chars=5, level=0, gravity=south, flags=1, font=OMITTED, script=latin, language=en-us, 'abc, '
-i=4, index=50, chars=4, level=0, gravity=east, flags=1, font=OMITTED, script=han, language=xx, '愛吃獅子'
-i=5, index=62, chars=1, level=0, gravity=east, flags=1, font=OMITTED, script=han, language=xx, ','
-i=6, index=65, chars=9, level=0, gravity=east, flags=1, font=OMITTED, script=han, language=xx, '決心要吃十隻獅子。'
-i=7, index=92, no run, line end
-i=8, index=93, no run, line end
diff --git a/tests/layouts/valid-21.markup b/tests/layouts/valid-21.markup
deleted file mode 100644
index 676a5e56..00000000
--- a/tests/layouts/valid-21.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-gravity=east
-有一位住在石室裏的詩人叫施氏,abc, 愛吃獅子,決心要吃十隻獅子。
diff --git a/tests/layouts/valid-22.layout b/tests/layouts/valid-22.layout
new file mode 100644
index 00000000..be57d26a
--- /dev/null
+++ b/tests/layouts/valid-22.layout
@@ -0,0 +1,84 @@
+{
+ "text" : "e0 = ooo...\n",
+ "attributes" : [
+ {
+ "start" : 1,
+ "end" : 2,
+ "type" : "font-desc",
+ "value" : "Italic"
+ },
+ {
+ "start" : 1,
+ "end" : 2,
+ "type" : "font-scale",
+ "value" : "subscript"
+ },
+ {
+ "start" : 1,
+ "end" : 2,
+ "type" : "baseline-shift",
+ "value" : "subscript"
+ },
+ {
+ "start" : 6,
+ "end" : 11,
+ "type" : "font-scale",
+ "value" : "superscript"
+ },
+ {
+ "start" : 6,
+ "end" : 11,
+ "type" : "baseline-shift",
+ "value" : "superscript"
+ },
+ {
+ "start" : 7,
+ "end" : 11,
+ "type" : "font-scale",
+ "value" : "superscript"
+ },
+ {
+ "start" : 7,
+ "end" : 11,
+ "type" : "baseline-shift",
+ "value" : "superscript"
+ },
+ {
+ "start" : 8,
+ "end" : 11,
+ "type" : "font-scale",
+ "value" : "superscript"
+ },
+ {
+ "start" : 8,
+ "end" : 11,
+ "type" : "baseline-shift",
+ "value" : "superscript"
+ },
+ {
+ "start" : 9,
+ "end" : 11,
+ "type" : "font-scale",
+ "value" : "superscript"
+ },
+ {
+ "start" : 9,
+ "end" : 11,
+ "type" : "baseline-shift",
+ "value" : "superscript"
+ },
+ {
+ "start" : 10,
+ "end" : 11,
+ "type" : "font-scale",
+ "value" : "superscript"
+ },
+ {
+ "start" : 10,
+ "end" : 11,
+ "type" : "baseline-shift",
+ "value" : "superscript"
+ }
+ ],
+ "font" : "Cantarell 11"
+}
diff --git a/tests/layouts/valid-22.markup b/tests/layouts/valid-22.markup
deleted file mode 100644
index d761749a..00000000
--- a/tests/layouts/valid-22.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-
-e<span font_desc="italic"><sub>0</sub></span> = o<sup>o<sup>o<sup>.<sup>.<sup>.</sup></sup></sup></sup></sup>
diff --git a/tests/layouts/valid-3.layout b/tests/layouts/valid-3.layout
new file mode 100644
index 00000000..ef1b1917
--- /dev/null
+++ b/tests/layouts/valid-3.layout
@@ -0,0 +1,5 @@
+{
+ "text" : "ABC😀️D\n",
+ "attributes" : [],
+ "font" : "Cantarell 11"
+}
diff --git a/tests/layouts/valid-3.markup b/tests/layouts/valid-3.markup
deleted file mode 100644
index 4e394a42..00000000
--- a/tests/layouts/valid-3.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-
-ABC😀️D
diff --git a/tests/layouts/valid-4.layout b/tests/layouts/valid-4.layout
new file mode 100644
index 00000000..5504107d
--- /dev/null
+++ b/tests/layouts/valid-4.layout
@@ -0,0 +1,6 @@
+{
+ "text" : "This paragraph should ac­tual­ly have multiple lines, unlike all the other wannabe äöü pa­ra­graph tests in this ugh test-case. Grow some lines!\n",
+ "attributes" : [],
+ "font" : "Cantarell 11",
+ "width" : 198656
+}
diff --git a/tests/layouts/valid-4.markup b/tests/layouts/valid-4.markup
deleted file mode 100644
index d8890baf..00000000
--- a/tests/layouts/valid-4.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-width=194
-This paragraph should ac­tual­ly have multiple lines, unlike all the other wannabe äöü pa­ra­graph tests in this ugh test-case. Grow some lines!
diff --git a/tests/layouts/valid-5.layout b/tests/layouts/valid-5.layout
new file mode 100644
index 00000000..e5e96b9a
--- /dev/null
+++ b/tests/layouts/valid-5.layout
@@ -0,0 +1,13 @@
+{
+ "text" : "A test with multiple paragraphs and with no-break attributes, which might trigger a crash.\nIf it doesn't the fix has worked.\n",
+ "attributes" : [
+ {
+ "start" : 21,
+ "end" : 31,
+ "type" : "font-features",
+ "value" : "tnum=1"
+ }
+ ],
+ "font" : "Cantarell 11",
+ "width" : 194560
+}
diff --git a/tests/layouts/valid-5.markup b/tests/layouts/valid-5.markup
deleted file mode 100644
index 2b2023ad..00000000
--- a/tests/layouts/valid-5.markup
+++ /dev/null
@@ -1,3 +0,0 @@
-width=190
-A test with multiple <span font_features="tnum=1">paragraphs</span> and with no-break attributes, which might trigger a crash.
-If it doesn't the fix has worked.
diff --git a/tests/layouts/valid-6.layout b/tests/layouts/valid-6.layout
new file mode 100644
index 00000000..4423d068
--- /dev/null
+++ b/tests/layouts/valid-6.layout
@@ -0,0 +1,5 @@
+{
+ "text" : " 0️⃣ Keycap Digit Zero\n",
+ "attributes" : [],
+ "font" : "Cantarell 11"
+}
diff --git a/tests/layouts/valid-6.markup b/tests/layouts/valid-6.markup
deleted file mode 100644
index 92c53e28..00000000
--- a/tests/layouts/valid-6.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-
- 0️⃣ Keycap Digit Zero
diff --git a/tests/layouts/valid-7.layout b/tests/layouts/valid-7.layout
new file mode 100644
index 00000000..b49484c6
--- /dev/null
+++ b/tests/layouts/valid-7.layout
@@ -0,0 +1,21 @@
+{
+ "text" : "This is a test of the automatic emergency brake!\n",
+ "attributes" : [
+ {
+ "start" : 22,
+ "end" : 41,
+ "type" : "foreground",
+ "value" : "#00000000ffff"
+ },
+ {
+ "start" : 22,
+ "end" : 41,
+ "type" : "underline",
+ "value" : "single"
+ }
+ ],
+ "font" : "Cantarell 11",
+ "ellipsize" : "middle",
+ "width" : 204800,
+ "indent" : 51200
+}
diff --git a/tests/layouts/valid-7.markup b/tests/layouts/valid-7.markup
deleted file mode 100644
index d5f9821e..00000000
--- a/tests/layouts/valid-7.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-width=200,indent=50,ellipsize=middle
-This is a test of the <span foreground="#0000ff" underline="single">automatic emergency</span> brake!
diff --git a/tests/layouts/valid-8.layout b/tests/layouts/valid-8.layout
new file mode 100644
index 00000000..063ec370
--- /dev/null
+++ b/tests/layouts/valid-8.layout
@@ -0,0 +1,8 @@
+{
+ "text" : "Hello שלום Γειά σας\n",
+ "attributes" : [],
+ "font" : "Cantarell 11",
+ "auto-dir" : false,
+ "alignment" : "center",
+ "spacing" : 51200
+}
diff --git a/tests/layouts/valid-8.markup b/tests/layouts/valid-8.markup
deleted file mode 100644
index 3272ea2b..00000000
--- a/tests/layouts/valid-8.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-spacing=50,auto_dir=false,alignment=center
-Hello שלום Γειά σας
diff --git a/tests/layouts/valid-9.layout b/tests/layouts/valid-9.layout
new file mode 100644
index 00000000..e3dfa57b
--- /dev/null
+++ b/tests/layouts/valid-9.layout
@@ -0,0 +1,12 @@
+{
+ "text" : "Hello שלום Γειά σας\n",
+ "attributes" : [
+ {
+ "end" : 30,
+ "type" : "letter-spacing",
+ "value" : 8888
+ }
+ ],
+ "font" : "Cantarell 11",
+ "width" : 102400
+}
diff --git a/tests/layouts/valid-9.markup b/tests/layouts/valid-9.markup
deleted file mode 100644
index ced8f8e5..00000000
--- a/tests/layouts/valid-9.markup
+++ /dev/null
@@ -1,2 +0,0 @@
-width=100
-<span letter_spacing="8888">Hello שלום Γειά σας</span>
diff --git a/tests/test-layout.c b/tests/test-layout.c
index cd60450e..7415efe7 100644
--- a/tests/test-layout.c
+++ b/tests/test-layout.c
@@ -219,176 +219,14 @@ dump_cursor_positions (PangoLayout *layout, GString *string)
g_string_append (string, "\n");
}
-typedef struct {
- int width;
- int height;
- int indent;
- int spacing;
- float line_spacing;
- PangoEllipsizeMode ellipsize;
- PangoWrapMode wrap;
- PangoAlignment alignment;
- gboolean justify;
- gboolean auto_dir;
- gboolean single_paragraph;
- PangoTabArray *tabs;
- PangoGravity gravity;
-} LayoutParams;
-
-static void
-init_params (LayoutParams *params)
-{
- params->width = -1;
- params->height = -1;
- params->indent = 0;
- params->spacing = 0;
- params->line_spacing = 0.0;
- params->ellipsize = PANGO_ELLIPSIZE_NONE;
- params->wrap = PANGO_WRAP_WORD;
- params->alignment = PANGO_ALIGN_LEFT;
- params->justify = FALSE;
- params->auto_dir = TRUE;
- params->single_paragraph = FALSE;
- params->tabs = NULL;
- params->gravity = PANGO_GRAVITY_AUTO;
-}
-
-static void
-parse_params (const char *str,
- LayoutParams *params)
-{
- char **strings;
- int i;
- GEnumClass *eclass;
- GEnumValue *ev;
-
- strings = g_strsplit (str, ",", -1);
- for (i = 0; strings[i]; i++)
- {
- char **str2 = g_strsplit (strings[i], "=", -1);
- if (strcmp (str2[0], "width") == 0)
- {
- params->width = (int) g_ascii_strtoll (str2[1], NULL, 10);
- }
- else if (strcmp (str2[0], "height") == 0)
- {
- params->height = (int) g_ascii_strtoll (str2[1], NULL, 10);
- }
- else if (strcmp (str2[0], "indent") == 0)
- {
- params->indent = (int) g_ascii_strtoll (str2[1], NULL, 10);
- }
- else if (strcmp (str2[0], "spacing") == 0)
- {
- params->spacing = (int) g_ascii_strtoll (str2[1], NULL, 10);
- }
- else if (strcmp (str2[0], "line_spacing") == 0)
- {
- params->line_spacing = (float) g_ascii_strtod (str2[1], NULL);
- }
- else if (strcmp (str2[0], "ellipsize") == 0)
- {
- eclass = g_type_class_ref (PANGO_TYPE_ELLIPSIZE_MODE);
- ev = g_enum_get_value_by_name (eclass, str2[1]);
- if (!ev)
- ev = g_enum_get_value_by_nick (eclass, str2[1]);
- if (ev)
- params->ellipsize = ev->value;
- g_type_class_unref (eclass);
- }
- else if (strcmp (str2[0], "wrap") == 0)
- {
- eclass = g_type_class_ref (PANGO_TYPE_WRAP_MODE);
- ev = g_enum_get_value_by_name (eclass, str2[1]);
- if (!ev)
- ev = g_enum_get_value_by_nick (eclass, str2[1]);
- if (ev)
- params->wrap = ev->value;
- g_type_class_unref (eclass);
- }
- else if (strcmp (str2[0], "alignment") == 0)
- {
- eclass = g_type_class_ref (PANGO_TYPE_ALIGNMENT);
- ev = g_enum_get_value_by_name (eclass, str2[1]);
- if (!ev)
- ev = g_enum_get_value_by_nick (eclass, str2[1]);
- if (ev)
- params->alignment = ev->value;
- g_type_class_unref (eclass);
- }
- else if (strcmp (str2[0], "justify") == 0)
- {
- params->justify = g_str_equal (str2[1], "true");
- }
- else if (strcmp (str2[0], "auto_dir") == 0)
- {
- params->auto_dir = g_str_equal (str2[1], "true");
- }
- else if (strcmp (str2[0], "single_paragraph") == 0)
- {
- params->single_paragraph = g_str_equal (str2[1], "true");
- }
- else if (strcmp (str2[0], "tabs") == 0)
- {
- char **str3 = g_strsplit (strings[i], " ", -1);
- params->tabs = pango_tab_array_new (g_strv_length (str3), TRUE);
- for (int j = 0; str3[j]; j++)
- {
- int tab = (int) g_ascii_strtoll (str3[j], NULL, 10);
- pango_tab_array_set_tab (params->tabs, j, PANGO_TAB_LEFT, tab);
- }
- g_strfreev (str3);
- }
- else if (strcmp (str2[0], "gravity") == 0)
- {
- eclass = g_type_class_ref (PANGO_TYPE_GRAVITY);
- ev = g_enum_get_value_by_name (eclass, str2[1]);
- if (!ev)
- ev = g_enum_get_value_by_nick (eclass, str2[1]);
- if (ev)
- params->gravity = ev->value;
- g_type_class_unref (eclass);
- }
-
- g_strfreev (str2);
- }
- g_strfreev (strings);
-}
-
-#define assert_layout_changed(layout) \
- g_assert_cmpuint (pango_layout_get_serial (layout), !=, serial); \
- serial = pango_layout_get_serial (layout);
-
-#define assert_rectangle_equal(r1, r2) \
- g_assert_true((r1)->x == (r2)->x && \
- (r1)->y == (r2)->y && \
- (r1)->width == (r2)->width && \
- (r1)->height == (r2)->height)
-
-#define assert_rectangle_contained(r1, r2) \
- g_assert_true ((r1)->x >= (r2)->x && \
- (r1)->y >= (r2)->y && \
- (r1)->x + (r1)->width <= (r2)->x + (r2)->width && \
- (r1)->y + (r1)->height <= (r2)->y + (r2)->height)
-
-#define assert_rectangle_size_contained(r1, r2) \
- g_assert_true ((r1)->width <= (r2)->width && \
- (r1)->height <= (r2)->height)
-
static void
test_file (const char *filename, GString *string)
{
char *contents;
- char *markup;
gsize length;
+ GBytes *bytes;
GError *error = NULL;
PangoLayout *layout;
- char *p;
- LayoutParams params;
- PangoFontDescription *desc;
- const PangoFontDescription *desc2;
- guint serial;
- PangoTabArray *tabs;
if (context == NULL)
context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
@@ -396,85 +234,12 @@ test_file (const char *filename, GString *string)
g_file_get_contents (filename, &contents, &length, &error);
g_assert_no_error (error);
- p = strchr (contents, '\n');
- g_assert (p);
- markup = p + 1;
- *p = '\0';
- length = strlen (markup);
-
- init_params (&params);
-
- layout = pango_layout_new (context);
-
- serial = pango_layout_get_serial (layout);
- g_assert_cmpuint (serial, !=, 0);
-
- /* Check initial values */
- g_assert_cmpint (pango_layout_get_width (layout), ==, params.width);
- g_assert_cmpint (pango_layout_get_height (layout), ==, params.height);
- g_assert_cmpint (pango_layout_get_indent (layout), ==, params.indent);
- g_assert_cmpint (pango_layout_get_spacing (layout), ==, params.spacing);
- g_assert_cmpfloat (pango_layout_get_line_spacing (layout), ==, params.line_spacing);
- g_assert_cmpint (pango_layout_get_ellipsize (layout), ==, params.ellipsize);
- g_assert_cmpint (pango_layout_get_wrap (layout), ==, params.wrap);
- g_assert_cmpint (pango_layout_get_alignment (layout), ==, params.alignment);
- g_assert_cmpint (pango_layout_get_justify (layout), ==, params.justify);
- g_assert_cmpint (pango_layout_get_auto_dir (layout), ==, params.auto_dir);
- g_assert_cmpint (pango_layout_get_single_paragraph_mode (layout), ==, params.single_paragraph);
-
- g_assert_cmpstr (pango_layout_get_text (layout), ==, "");
- g_assert_null (pango_layout_get_attributes (layout));
- g_assert_null (pango_layout_get_tabs (layout));
- g_assert_null (pango_layout_get_font_description (layout));
- g_assert_cmpint (pango_layout_is_ellipsized (layout), ==, FALSE);
- g_assert_cmpint (pango_layout_is_wrapped (layout), ==, FALSE);
-
- desc = pango_font_description_from_string ("Cantarell 11");
- pango_layout_set_font_description (layout, desc);
- desc2 = pango_layout_get_font_description (layout);
- g_assert_true (pango_font_description_equal (desc, desc2));
- pango_font_description_free (desc);
- assert_layout_changed (layout);
-
- pango_layout_set_markup (layout, markup, length);
- assert_layout_changed (layout);
-
- parse_params (contents, &params);
-
- pango_context_set_base_gravity (context, params.gravity);
-
- pango_layout_set_width (layout, params.width > 0 ? params.width * PANGO_SCALE : -1);
- pango_layout_set_height (layout, params.height > 0 ? params.height * PANGO_SCALE : params.height);
- pango_layout_set_indent (layout, params.indent * PANGO_SCALE);
- pango_layout_set_spacing (layout, params.spacing * PANGO_SCALE);
- pango_layout_set_line_spacing (layout, params.line_spacing);
- pango_layout_set_ellipsize (layout, params.ellipsize);
- pango_layout_set_wrap (layout, params.wrap);
- pango_layout_set_alignment (layout, params.alignment);
- pango_layout_set_justify (layout, params.justify);
- pango_layout_set_auto_dir (layout, params.auto_dir);
- pango_layout_set_single_paragraph_mode (layout, params.single_paragraph);
- pango_layout_set_tabs (layout, params.tabs);
-
- /* Check the values we set */
- g_assert_cmpint (pango_layout_get_width (layout), ==, params.width > 0 ? params.width * PANGO_SCALE : -1);
- g_assert_cmpint (pango_layout_get_height (layout), ==, params.height > 0 ? params.height * PANGO_SCALE : params.height);
- g_assert_cmpint (pango_layout_get_indent (layout), ==, params.indent * PANGO_SCALE);
- g_assert_cmpint (pango_layout_get_spacing (layout), ==, params.spacing * PANGO_SCALE);
- g_assert_cmpfloat (pango_layout_get_line_spacing (layout), ==, params.line_spacing);
- g_assert_cmpint (pango_layout_get_ellipsize (layout), ==, params.ellipsize);
- g_assert_cmpint (pango_layout_get_wrap (layout), ==, params.wrap);
- g_assert_cmpint (pango_layout_get_alignment (layout), ==, params.alignment);
- g_assert_cmpint (pango_layout_get_justify (layout), ==, params.justify);
- g_assert_cmpint (pango_layout_get_auto_dir (layout), ==, params.auto_dir);
- g_assert_cmpint (pango_layout_get_single_paragraph_mode (layout), ==, params.single_paragraph);
-
- tabs = pango_layout_get_tabs (layout);
- g_assert_true ((tabs == NULL) == (params.tabs == NULL));
- if (tabs)
- pango_tab_array_free (tabs);
-
- g_assert_cmpint (pango_layout_get_character_count (layout), ==, g_utf8_strlen (pango_layout_get_text (layout), -1));
+ bytes = g_bytes_new_take (contents, length);
+
+ layout = pango_layout_deserialize (context, bytes, &error);
+ g_assert_no_error (error);
+
+ g_bytes_unref (bytes);
/* generate the dumps */
g_string_append (string, pango_layout_get_text (layout));
@@ -484,13 +249,11 @@ test_file (const char *filename, GString *string)
g_string_append_printf (string, "wrapped: %d\n", pango_layout_is_wrapped (layout));
g_string_append_printf (string, "ellipsized: %d\n", pango_layout_is_ellipsized (layout));
g_string_append_printf (string, "lines: %d\n", pango_layout_get_line_count (layout));
- if (params.width > 0)
+ if (pango_layout_get_width (layout) > 0)
g_string_append_printf (string, "width: %d\n", pango_layout_get_width (layout));
-
- if (params.height > 0)
+ if (pango_layout_get_height (layout) > 0)
g_string_append_printf (string, "height: %d\n", pango_layout_get_height (layout));
-
- if (params.indent != 0)
+ if (pango_layout_get_indent (layout) != 0)
g_string_append_printf (string, "indent: %d\n", pango_layout_get_indent (layout));
g_string_append (string, "\n--- attributes\n\n");
@@ -509,19 +272,15 @@ test_file (const char *filename, GString *string)
dump_runs (layout, string);
g_object_unref (layout);
- g_free (contents);
-
- if (params.tabs)
- pango_tab_array_free (params.tabs);
}
static gchar *
-get_expected_filename (const gchar *filename)
+get_expected_filename (const char *filename)
{
- gchar *f, *p, *expected;
+ char *f, *p, *expected;
f = g_strdup (filename);
- p = strstr (f, ".markup");
+ p = strstr (f, ".layout");
if (p)
*p = 0;
expected = g_strconcat (f, ".expected", NULL);
@@ -534,11 +293,11 @@ get_expected_filename (const gchar *filename)
static void
test_layout (gconstpointer d)
{
- const gchar *filename = d;
- gchar *expected_file;
+ const char *filename = d;
+ char *expected_file;
GError *error = NULL;
GString *dump;
- gchar *diff;
+ char *diff;
PangoFontFamily **families;
int n_families;
gboolean found_cantarell;
@@ -616,7 +375,7 @@ main (int argc, char *argv[])
GDir *dir;
GError *error = NULL;
const gchar *name;
- gchar *path;
+ char *path;
GOptionContext *option_context;
GOptionEntry entries[] = {
{ "show-fonts", '0', 0, G_OPTION_ARG_NONE, &opt_show_font, "Print font names in dumps", NULL },
@@ -659,7 +418,7 @@ main (int argc, char *argv[])
g_assert_no_error (error);
while ((name = g_dir_read_name (dir)) != NULL)
{
- if (!strstr (name, "markup"))
+ if (!g_str_has_suffix (name, ".layout"))
continue;
path = g_strdup_printf ("/layout/%s", name);
diff --git a/tests/testserialize.c b/tests/testserialize.c
index cc6c67bc..5fb7543a 100644
--- a/tests/testserialize.c
+++ b/tests/testserialize.c
@@ -21,6 +21,7 @@
#include "config.h"
#include <glib.h>
#include <pango/pangocairo.h>
+#include <gio/gio.h>
static void
test_serialize_attr_list (void)
@@ -122,6 +123,191 @@ test_serialize_tab_array (void)
}
}
+static void
+test_serialize_layout_minimal (void)
+{
+ const char *test =
+ "{\n"
+ " \"text\" : \"Almost nothing\"\n"
+ "}";
+
+ PangoContext *context;
+ GBytes *bytes;
+ PangoLayout *layout;
+ GError *error = NULL;
+ GBytes *out_bytes;
+ const char *str;
+
+ 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, &error);
+ g_assert_no_error (error);
+ g_assert_true (PANGO_IS_LAYOUT (layout));
+ g_assert_cmpstr (pango_layout_get_text (layout), ==, "Almost nothing");
+ g_assert_null (pango_layout_get_attributes (layout));
+ g_assert_null (pango_layout_get_tabs (layout));
+ g_assert_null (pango_layout_get_font_description (layout));
+ g_assert_cmpint (pango_layout_get_alignment (layout), ==, PANGO_ALIGN_LEFT);
+ g_assert_cmpint (pango_layout_get_width (layout), ==, -1);
+
+ out_bytes = pango_layout_serialize (layout);
+ str = g_bytes_get_data (out_bytes, NULL);
+
+ g_assert_cmpstr (str, ==, test);
+
+ g_bytes_unref (out_bytes);
+
+ g_object_unref (layout);
+ g_bytes_unref (bytes);
+ g_object_unref (context);
+}
+
+static void
+test_serialize_layout_valid (void)
+{
+ const char *test =
+ "{\n"
+ " \"text\" : \"Some fun with layouts!\",\n"
+ " \"attributes\" : [\n"
+ " {\n"
+ " \"end\" : 4,\n"
+ " \"type\" : \"foreground\",\n"
+ " \"value\" : \"#ffff00000000\"\n"
+ " },\n"
+ " {\n"
+ " \"start\" : 5,\n"
+ " \"end\" : 8,\n"
+ " \"type\" : \"foreground\",\n"
+ " \"value\" : \"#000080800000\"\n"
+ " },\n"
+ " {\n"
+ " \"start\" : 14,\n"
+ " \"type\" : \"foreground\",\n"
+ " \"value\" : \"#ffff0000ffff\"\n"
+ " }\n"
+ " ],\n"
+ " \"font\" : \"Sans Bold 32\",\n"
+ " \"tabs\" : {\n"
+ " \"positions-in-pixels\" : true,\n"
+ " \"positions\" : [\n"
+ " 0,\n"
+ " 50,\n"
+ " 100\n"
+ " ]\n"
+ " },\n"
+ " \"alignment\" : \"center\",\n"
+ " \"width\" : 350000,\n"
+ " \"line-spacing\" : 1.5\n"
+ "}";
+
+ PangoContext *context;
+ GBytes *bytes;
+ PangoLayout *layout;
+ PangoTabArray *tabs;
+ GError *error = NULL;
+ GBytes *out_bytes;
+ const char *str;
+ char *s;
+
+ 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, &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_nonnull (pango_layout_get_attributes (layout));
+ tabs = pango_layout_get_tabs (layout);
+ g_assert_nonnull (tabs);
+ pango_tab_array_free (tabs);
+ s = pango_font_description_to_string (pango_layout_get_font_description (layout));
+ g_assert_cmpstr (s, ==, "Sans Bold 32");
+ g_free (s);
+ g_assert_cmpint (pango_layout_get_alignment (layout), ==, PANGO_ALIGN_CENTER);
+ g_assert_cmpint (pango_layout_get_width (layout), ==, 350000);
+ g_assert_cmpfloat_with_epsilon (pango_layout_get_line_spacing (layout), 1.5, 0.0001);
+
+ out_bytes = pango_layout_serialize (layout);
+ str = g_bytes_get_data (out_bytes, NULL);
+
+ g_assert_cmpstr (str, ==, test);
+
+ g_bytes_unref (out_bytes);
+
+ g_object_unref (layout);
+ g_bytes_unref (bytes);
+ g_object_unref (context);
+}
+
+static void
+test_serialize_layout_invalid (void)
+{
+ struct {
+ const char *json;
+ int expected_error;
+ } test[] = {
+ {
+ "{\n"
+ " \"attributes\" : [\n"
+ " {\n"
+ " \"type\" : \"caramba\"\n"
+ " }\n"
+ " ]\n"
+ "}",
+ PANGO_LAYOUT_SERIALIZE_INVALID_VALUE
+ },
+ {
+ "{\n"
+ " \"attributes\" : [\n"
+ " {\n"
+ " \"type\" : \"weight\"\n"
+ " }\n"
+ " ]\n"
+ "}",
+ PANGO_LAYOUT_SERIALIZE_MISSING_VALUE
+ },
+ {
+ "{\n"
+ " \"attributes\" : [\n"
+ " {\n"
+ " \"type\" : \"alignment\",\n"
+ " \"value\" : \"nonsense\"\n"
+ " }\n"
+ " ]\n"
+ "}",
+ PANGO_LAYOUT_SERIALIZE_INVALID_VALUE
+ },
+ {
+ "{\n"
+ " \"alignment\" : \"nonsense\"\n"
+ "}",
+ PANGO_LAYOUT_SERIALIZE_INVALID_VALUE
+ }
+ };
+
+ PangoContext *context;
+
+ context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
+
+ for (int i = 0; i < G_N_ELEMENTS (test); i++)
+ {
+ GBytes *bytes;
+ PangoLayout *layout;
+ GError *error = NULL;
+
+ bytes = g_bytes_new_static (test[i].json, -1);
+ layout = pango_layout_deserialize (context, bytes, &error);
+ g_assert_null (layout);
+ g_assert_error (error, PANGO_LAYOUT_SERIALIZE_ERROR, test[i].expected_error);
+ g_bytes_unref (bytes);
+ g_clear_error (&error);
+ }
+
+ g_object_unref (context);
+}
int
main (int argc, char *argv[])
{
@@ -129,6 +315,9 @@ main (int argc, char *argv[])
g_test_add_func ("/serialize/attr-list", test_serialize_attr_list);
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/invalid", test_serialize_layout_invalid);
return g_test_run ();
}