summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-12-03 01:34:40 +0000
committerMatthias Clasen <mclasen@redhat.com>2021-12-03 01:34:40 +0000
commitfdef4305de8cd7e411a3da61bf1dcbd3a628b035 (patch)
tree1031695726cfd04b91c0891efa99d49b1fcb6a7e
parent50d630321da94186fe46590574b79c1d7f631605 (diff)
parent2e1a0a4b255cb1a40babbd6e72055bf06f85b1a9 (diff)
downloadpango-fdef4305de8cd7e411a3da61bf1dcbd3a628b035.tar.gz
Merge branch 'serializer-rewrite' into 'main'
Port the serializer to use our own json parser and printer See merge request GNOME/pango!531
-rw-r--r--meson.build5
-rw-r--r--pango/json/gtkjsonparser.c1142
-rw-r--r--pango/json/gtkjsonparserprivate.h69
-rw-r--r--pango/json/gtkjsonprinter.c405
-rw-r--r--pango/json/gtkjsonprinterprivate.h79
-rw-r--r--pango/meson.build2
-rw-r--r--pango/pango-font.h5
-rw-r--r--pango/pango-layout.h10
-rw-r--r--pango/pango-tabs.c19
-rw-r--r--pango/pango-tabs.h4
-rw-r--r--pango/serializer.c1714
-rw-r--r--tests/layouts/bratwurst.layout43
-rw-r--r--tests/layouts/bratwurst2.layout31
-rw-r--r--tests/layouts/bratwurst3.layout67
-rw-r--r--tests/layouts/bratwurst4.layout45
-rw-r--r--tests/layouts/effigy.layout43
-rw-r--r--tests/layouts/kebab.layout44
-rw-r--r--tests/layouts/tabs.layout374
-rw-r--r--tests/layouts/valid-1.layout50
-rw-r--r--tests/layouts/valid-10.layout74
-rw-r--r--tests/layouts/valid-11.layout74
-rw-r--r--tests/layouts/valid-12.layout194
-rw-r--r--tests/layouts/valid-13.layout194
-rw-r--r--tests/layouts/valid-14.layout86
-rw-r--r--tests/layouts/valid-15.layout50
-rw-r--r--tests/layouts/valid-16.layout50
-rw-r--r--tests/layouts/valid-17.layout104
-rw-r--r--tests/layouts/valid-18.layout50
-rw-r--r--tests/layouts/valid-19.layout144
-rw-r--r--tests/layouts/valid-2.layout74
-rw-r--r--tests/layouts/valid-20.layout38
-rw-r--r--tests/layouts/valid-21.layout36
-rw-r--r--tests/layouts/valid-22.layout110
-rw-r--r--tests/layouts/valid-3.layout48
-rw-r--r--tests/layouts/valid-4.layout74
-rw-r--r--tests/layouts/valid-5.layout86
-rw-r--r--tests/layouts/valid-6.layout48
-rw-r--r--tests/layouts/valid-7.layout62
-rw-r--r--tests/layouts/valid-8.layout62
-rw-r--r--tests/layouts/valid-9.layout74
-rw-r--r--tests/testserialize.c51
41 files changed, 3781 insertions, 2153 deletions
diff --git a/meson.build b/meson.build
index c91ddb52..7afe6193 100644
--- a/meson.build
+++ b/meson.build
@@ -232,7 +232,6 @@ 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)
@@ -252,10 +251,6 @@ 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/json/gtkjsonparser.c b/pango/json/gtkjsonparser.c
new file mode 100644
index 00000000..91048fec
--- /dev/null
+++ b/pango/json/gtkjsonparser.c
@@ -0,0 +1,1142 @@
+/*
+ * Copyright © 2021 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+
+#include "config.h"
+
+#include "gtkjsonparserprivate.h"
+
+typedef struct _GtkJsonBlock GtkJsonBlock;
+
+typedef enum {
+ GTK_JSON_BLOCK_TOPLEVEL,
+ GTK_JSON_BLOCK_OBJECT,
+ GTK_JSON_BLOCK_ARRAY,
+} GtkJsonBlockType;
+
+struct _GtkJsonBlock
+{
+ GtkJsonBlockType type;
+ const guchar *value; /* start of current value to be consumed by external code */
+ const guchar *member_name; /* name of current value, only used for object types */
+ gsize index; /* index of the current element */
+};
+
+struct _GtkJsonParser
+{
+ GBytes *bytes;
+ const guchar *reader; /* current read head, pointing as far as we've read */
+ const guchar *end; /* pointer after end of data we're reading */
+
+ GError *error; /* if an error has happened, it's stored here. Errors aren't recoverable. */
+
+ GtkJsonBlock *block; /* current block */
+ GtkJsonBlock *blocks; /* blocks array */
+ GtkJsonBlock *blocks_end; /* blocks array */
+ GtkJsonBlock blocks_preallocated[128]; /* preallocated */
+};
+
+typedef enum {
+ WHITESPACE = (1 << 4),
+ STRING_ELEMENT = (1 << 5),
+ STRING_MARKER = (1 << 6),
+} JsonCharacterType;
+
+#define JSON_CHARACTER_NODE_MASK ((1 << 4) - 1)
+
+static const guchar json_character_table[256] = {
+ ['\t'] = WHITESPACE,
+ ['\r'] = WHITESPACE,
+ ['\n'] = WHITESPACE,
+ [' '] = WHITESPACE | STRING_ELEMENT,
+ ['!'] = STRING_ELEMENT,
+ ['"'] = GTK_JSON_STRING | STRING_MARKER,
+ ['#'] = STRING_ELEMENT,
+ ['$'] = STRING_ELEMENT,
+ ['%'] = STRING_ELEMENT,
+ ['&'] = STRING_ELEMENT,
+ ['\''] = STRING_ELEMENT,
+ ['('] = STRING_ELEMENT,
+ [')'] = STRING_ELEMENT,
+ ['*'] = STRING_ELEMENT,
+ ['+'] = STRING_ELEMENT,
+ [','] = STRING_ELEMENT,
+ ['-'] = GTK_JSON_NUMBER | STRING_ELEMENT,
+ ['.'] = STRING_ELEMENT,
+ ['/'] = STRING_ELEMENT,
+ ['0'] = GTK_JSON_NUMBER | STRING_ELEMENT,
+ ['1'] = GTK_JSON_NUMBER | STRING_ELEMENT,
+ ['2'] = GTK_JSON_NUMBER | STRING_ELEMENT,
+ ['3'] = GTK_JSON_NUMBER | STRING_ELEMENT,
+ ['4'] = GTK_JSON_NUMBER | STRING_ELEMENT,
+ ['5'] = GTK_JSON_NUMBER | STRING_ELEMENT,
+ ['6'] = GTK_JSON_NUMBER | STRING_ELEMENT,
+ ['7'] = GTK_JSON_NUMBER | STRING_ELEMENT,
+ ['8'] = GTK_JSON_NUMBER | STRING_ELEMENT,
+ ['9'] = GTK_JSON_NUMBER | STRING_ELEMENT,
+ [':'] = STRING_ELEMENT,
+ [';'] = STRING_ELEMENT,
+ ['<'] = STRING_ELEMENT,
+ ['='] = STRING_ELEMENT,
+ ['>'] = STRING_ELEMENT,
+ ['?'] = STRING_ELEMENT,
+ ['@'] = STRING_ELEMENT,
+ ['A'] = STRING_ELEMENT,
+ ['B'] = STRING_ELEMENT,
+ ['C'] = STRING_ELEMENT,
+ ['D'] = STRING_ELEMENT,
+ ['E'] = STRING_ELEMENT,
+ ['F'] = STRING_ELEMENT,
+ ['G'] = STRING_ELEMENT,
+ ['H'] = STRING_ELEMENT,
+ ['I'] = STRING_ELEMENT,
+ ['J'] = STRING_ELEMENT,
+ ['K'] = STRING_ELEMENT,
+ ['L'] = STRING_ELEMENT,
+ ['M'] = STRING_ELEMENT,
+ ['N'] = STRING_ELEMENT,
+ ['O'] = STRING_ELEMENT,
+ ['P'] = STRING_ELEMENT,
+ ['Q'] = STRING_ELEMENT,
+ ['R'] = STRING_ELEMENT,
+ ['S'] = STRING_ELEMENT,
+ ['T'] = STRING_ELEMENT,
+ ['U'] = STRING_ELEMENT,
+ ['V'] = STRING_ELEMENT,
+ ['W'] = STRING_ELEMENT,
+ ['X'] = STRING_ELEMENT,
+ ['Y'] = STRING_ELEMENT,
+ ['Z'] = STRING_ELEMENT,
+ ['['] = GTK_JSON_ARRAY | STRING_ELEMENT,
+ ['\\'] = STRING_MARKER,
+ [']'] = STRING_ELEMENT,
+ ['^'] = STRING_ELEMENT,
+ ['_'] = STRING_ELEMENT,
+ ['`'] = STRING_ELEMENT,
+ ['a'] = STRING_ELEMENT,
+ ['b'] = STRING_ELEMENT,
+ ['c'] = STRING_ELEMENT,
+ ['d'] = STRING_ELEMENT,
+ ['e'] = STRING_ELEMENT,
+ ['f'] = GTK_JSON_BOOLEAN | STRING_ELEMENT,
+ ['g'] = STRING_ELEMENT,
+ ['h'] = STRING_ELEMENT,
+ ['i'] = STRING_ELEMENT,
+ ['j'] = STRING_ELEMENT,
+ ['k'] = STRING_ELEMENT,
+ ['l'] = STRING_ELEMENT,
+ ['m'] = STRING_ELEMENT,
+ ['n'] = GTK_JSON_NULL | STRING_ELEMENT,
+ ['o'] = STRING_ELEMENT,
+ ['p'] = STRING_ELEMENT,
+ ['q'] = STRING_ELEMENT,
+ ['r'] = STRING_ELEMENT,
+ ['s'] = STRING_ELEMENT,
+ ['t'] = GTK_JSON_BOOLEAN | STRING_ELEMENT,
+ ['u'] = STRING_ELEMENT,
+ ['v'] = STRING_ELEMENT,
+ ['w'] = STRING_ELEMENT,
+ ['x'] = STRING_ELEMENT,
+ ['y'] = STRING_ELEMENT,
+ ['z'] = STRING_ELEMENT,
+ ['{'] = GTK_JSON_OBJECT | STRING_ELEMENT,
+ ['|'] = STRING_ELEMENT,
+ ['}'] = STRING_ELEMENT,
+ ['~'] = STRING_ELEMENT,
+ [127] = STRING_ELEMENT,
+};
+
+static const guchar *
+json_skip_characters (const guchar *start,
+ const guchar *end,
+ JsonCharacterType type)
+{
+ const guchar *s;
+
+ for (s = start; s < end; s++)
+ {
+ if (!(json_character_table[*s] & type))
+ break;
+ }
+ return s;
+}
+
+static const guchar *
+json_find_character (const guchar *start,
+ JsonCharacterType type)
+{
+ const guchar *s;
+
+ for (s = start; ; s++)
+ {
+ if ((json_character_table[*s] & type))
+ break;
+ }
+ return s;
+}
+
+static void
+gtk_json_parser_value_error (GtkJsonParser *self,
+ const char *format,
+ ...) G_GNUC_PRINTF(2, 3);
+static void
+gtk_json_parser_value_error (GtkJsonParser *self,
+ const char *format,
+ ...)
+{
+ va_list args;
+
+ if (self->error)
+ return;
+
+ va_start (args, format);
+ self->error = g_error_new_valist (G_FILE_ERROR,
+ G_FILE_ERROR_FAILED,
+ format, args);
+ va_end (args);
+}
+
+static void
+gtk_json_parser_syntax_error (GtkJsonParser *self,
+ const char *format,
+ ...) G_GNUC_PRINTF(2, 3);
+static void
+gtk_json_parser_syntax_error (GtkJsonParser *self,
+ const char *format,
+ ...)
+{
+ va_list args;
+
+ if (self->error)
+ return;
+
+ va_start (args, format);
+ self->error = g_error_new_valist (G_FILE_ERROR,
+ G_FILE_ERROR_FAILED,
+ format, args);
+ va_end (args);
+}
+
+static gboolean
+gtk_json_parser_is_eof (GtkJsonParser *self)
+{
+ return self->reader >= self->end || *self->reader == '\0';
+}
+
+static gsize
+gtk_json_parser_remaining (GtkJsonParser *self)
+{
+ g_return_val_if_fail (self->reader <= self->end, 0);
+
+ return self->end - self->reader;
+}
+
+static void
+gtk_json_parser_skip_whitespace (GtkJsonParser *self)
+{
+ self->reader = json_skip_characters (self->reader, self->end, WHITESPACE);
+}
+
+static gboolean
+gtk_json_parser_has_char (GtkJsonParser *self,
+ char c)
+{
+ return gtk_json_parser_remaining (self) && *self->reader == c;
+}
+
+static gboolean
+gtk_json_parser_try_char (GtkJsonParser *self,
+ char c)
+{
+ if (!gtk_json_parser_has_char (self, c))
+ return FALSE;
+
+ self->reader++;
+ return TRUE;
+}
+
+static gboolean
+gtk_json_parser_try_identifier_len (GtkJsonParser *self,
+ const char *ident,
+ gsize len)
+{
+ if (gtk_json_parser_remaining (self) < len)
+ return FALSE;
+
+ if (memcmp (self->reader, ident, len) != 0)
+ return FALSE;
+
+ self->reader += len;
+ return TRUE;
+}
+
+#define gtk_json_parser_try_identifier(parser, ident) gtk_json_parser_try_identifier_len(parser, ident, strlen(ident))
+
+/*
+ * decode_utf16_surrogate_pair:
+ * @first: the first UTF-16 code point
+ * @second: the second UTF-16 code point
+ *
+ * Decodes a surrogate pair of UTF-16 code points into the equivalent
+ * Unicode code point.
+ *
+ * If the code points are not valid, 0 is returned.
+ *
+ * Returns: the Unicode code point equivalent to the surrogate pair
+ */
+static inline gunichar
+decode_utf16_surrogate_pair (gunichar first,
+ gunichar second)
+{
+ if (0xd800 > first || first > 0xdbff ||
+ 0xdc00 > second || second > 0xdfff)
+ return 0;
+
+ return 0x10000
+ | (first & 0x3ff) << 10
+ | (second & 0x3ff);
+}
+
+static gsize
+gtk_json_unescape_char (const guchar *json_escape,
+ char out_data[6],
+ gsize *out_len)
+{
+ switch (json_escape[1])
+ {
+ case '"':
+ case '\\':
+ case '/':
+ out_data[0] = json_escape[1];
+ *out_len = 1;
+ return 2;
+ case 'b':
+ out_data[0] = '\b';
+ *out_len = 1;
+ return 2;
+ case 'f':
+ out_data[0] = '\f';
+ *out_len = 1;
+ return 2;
+ case 'n':
+ out_data[0] = '\n';
+ *out_len = 1;
+ return 2;
+ case 'r':
+ out_data[0] = '\r';
+ *out_len = 1;
+ return 2;
+ case 't':
+ out_data[0] = '\t';
+ *out_len = 1;
+ return 2;
+ case 'u':
+ {
+ gunichar unichar = (g_ascii_xdigit_value (json_escape[2]) << 12) |
+ (g_ascii_xdigit_value (json_escape[3]) << 8) |
+ (g_ascii_xdigit_value (json_escape[4]) << 4) |
+ (g_ascii_xdigit_value (json_escape[5]));
+ gsize result = 6;
+
+ /* resolve UTF-16 surrogates for Unicode characters not in the BMP,
+ * as per ECMA 404, § 9, "String"
+ */
+ if (g_unichar_type (unichar) == G_UNICODE_SURROGATE)
+ {
+ unichar = decode_utf16_surrogate_pair (unichar,
+ (g_ascii_xdigit_value (json_escape[8]) << 12) |
+ (g_ascii_xdigit_value (json_escape[9]) << 8) |
+ (g_ascii_xdigit_value (json_escape[10]) << 4) |
+ (g_ascii_xdigit_value (json_escape[11])));
+ result += 6;
+ }
+ *out_len = g_unichar_to_utf8 (unichar, out_data);
+ return result;
+ }
+ default:
+ g_assert_not_reached ();
+ return 0;
+ }
+}
+
+/* The escaped string MUST be valid json, so it must begin
+ * with " and end with " and must not contain any invalid
+ * escape codes.
+ * This function is meant to be fast
+ */
+static char *
+gtk_json_unescape_string (const guchar *escaped)
+{
+ char buf[6];
+ gsize buf_size;
+ GString *string;
+ const guchar *last, *s;
+
+ string = NULL;
+
+ g_assert (*escaped == '"');
+ last = escaped + 1;
+ for (s = json_find_character (last, STRING_MARKER);
+ *s != '"';
+ s = json_find_character (last, STRING_MARKER))
+ {
+ g_assert (*s == '\\');
+ if (string == NULL)
+ string = g_string_new (NULL);
+ g_string_append_len (string, (const char *) last, s - last);
+ last = s + gtk_json_unescape_char (s, buf, &buf_size);
+ g_string_append_len (string, buf, buf_size);
+ }
+
+ if (string)
+ {
+ g_string_append_len (string, (const char *) last, s - last);
+ return g_string_free (string, FALSE);
+ }
+ else
+ {
+ return g_strndup ((const char *) last, s - last);
+ }
+}
+
+static gboolean
+gtk_json_parser_parse_string (GtkJsonParser *self)
+{
+ if (!gtk_json_parser_try_char (self, '"'))
+ {
+ gtk_json_parser_syntax_error (self, "Not a string");
+ return FALSE;
+ }
+
+ self->reader = json_skip_characters (self->reader, self->end, STRING_ELEMENT);
+
+ while (gtk_json_parser_remaining (self))
+ {
+ if (*self->reader < 0x20)
+ {
+ gtk_json_parser_syntax_error (self, "Disallowed control character in string literal");
+ return FALSE;
+ }
+ else if (*self->reader > 127)
+ {
+ gunichar c = g_utf8_get_char_validated ((const char *) self->reader, gtk_json_parser_remaining (self));
+ if (c == (gunichar) -2 || c == (gunichar) -1)
+ {
+ gtk_json_parser_syntax_error (self, "Invalid UTF-8");
+ return FALSE;
+ }
+ self->reader = (const guchar *) g_utf8_next_char ((const char *) self->reader);
+ }
+ else if (*self->reader == '"')
+ {
+ self->reader++;
+ return TRUE;
+ }
+ else if (*self->reader == '\\')
+ {
+ if (gtk_json_parser_remaining (self) < 2)
+ goto end;
+ self->reader++;
+ switch (*self->reader)
+ {
+ case '"':
+ case '\\':
+ case '/':
+ case 'b':
+ case 'f':
+ case 'n':
+ case 'r':
+ case 't':
+ break;
+
+ case 'u':
+ /* lots of work necessary to validate the unicode escapes here */
+ if (gtk_json_parser_remaining (self) < 5 ||
+ !g_ascii_isxdigit (self->reader[1]) ||
+ !g_ascii_isxdigit (self->reader[2]) ||
+ !g_ascii_isxdigit (self->reader[3]) ||
+ !g_ascii_isxdigit (self->reader[4]))
+ {
+ gtk_json_parser_syntax_error (self, "Invalid Unicode escape sequence");
+ return FALSE;
+ }
+ else
+ {
+ gunichar unichar = (g_ascii_xdigit_value (self->reader[1]) << 12) |
+ (g_ascii_xdigit_value (self->reader[2]) << 8) |
+ (g_ascii_xdigit_value (self->reader[3]) << 4) |
+ (g_ascii_xdigit_value (self->reader[4]));
+
+ self->reader += 4;
+ /* resolve UTF-16 surrogates for Unicode characters not in the BMP,
+ * as per ECMA 404, § 9, "String"
+ */
+ if (g_unichar_type (unichar) == G_UNICODE_SURROGATE)
+ {
+ if (gtk_json_parser_remaining (self) >= 7 &&
+ self->reader[1] == '\\' &&
+ self->reader[2] == 'u' &&
+ g_ascii_isxdigit (self->reader[3]) &&
+ g_ascii_isxdigit (self->reader[4]) &&
+ g_ascii_isxdigit (self->reader[5]) &&
+ g_ascii_isxdigit (self->reader[6]))
+ {
+ unichar = decode_utf16_surrogate_pair (unichar,
+ (g_ascii_xdigit_value (self->reader[3]) << 12) |
+ (g_ascii_xdigit_value (self->reader[4]) << 8) |
+ (g_ascii_xdigit_value (self->reader[5]) << 4) |
+ (g_ascii_xdigit_value (self->reader[6])));
+ self->reader += 6;
+ }
+ else
+ {
+ unichar = 0;
+ }
+ }
+
+ if (unichar == 0)
+ {
+ gtk_json_parser_syntax_error (self, "Invalid UTF-16 surrogate pair");
+ return FALSE;
+ }
+ }
+ break;
+ default:
+ gtk_json_parser_syntax_error (self, "Unknown escape sequence");
+ return FALSE;
+ }
+ self->reader++;
+ }
+
+ self->reader = json_skip_characters (self->reader, self->end, STRING_ELEMENT);
+ }
+
+end:
+ gtk_json_parser_syntax_error (self, "Unterminated string literal");
+ return FALSE;
+}
+
+static gboolean
+gtk_json_parser_parse_number (GtkJsonParser *self)
+{
+ /* sign */
+ gtk_json_parser_try_char (self, '-');
+
+ /* integer part */
+ if (!gtk_json_parser_try_char (self, '0'))
+ {
+ if (gtk_json_parser_is_eof (self) ||
+ !g_ascii_isdigit (*self->reader))
+ goto out;
+
+ self->reader++;
+
+ while (!gtk_json_parser_is_eof (self) && g_ascii_isdigit (*self->reader))
+ self->reader++;
+ }
+
+ /* fractional part */
+ if (gtk_json_parser_remaining (self) >= 2 && *self->reader == '.' && g_ascii_isdigit (self->reader[1]))
+ {
+ self->reader += 2;
+
+ while (!gtk_json_parser_is_eof (self) && g_ascii_isdigit (*self->reader))
+ self->reader++;
+ }
+
+ /* exponent */
+ if (gtk_json_parser_remaining (self) >= 2 && (self->reader[0] == 'e' || self->reader[0] == 'E') &&
+ (g_ascii_isdigit (self->reader[1]) ||
+ (gtk_json_parser_remaining (self) >= 3 && (self->reader[1] == '+' || self->reader[1] == '-') && g_ascii_isdigit (self->reader[2]))))
+ {
+ self->reader += 2;
+
+ while (!gtk_json_parser_is_eof (self) && g_ascii_isdigit (*self->reader))
+ self->reader++;
+ }
+ return TRUE;
+
+out:
+ gtk_json_parser_syntax_error (self, "Not a valid number");
+ return FALSE;
+}
+
+static gboolean
+gtk_json_parser_parse_value (GtkJsonParser *self)
+{
+ if (gtk_json_parser_is_eof (self))
+ {
+ gtk_json_parser_syntax_error (self, "Unexpected end of document");
+ return FALSE;
+ }
+
+ switch (json_character_table[*self->block->value] & JSON_CHARACTER_NODE_MASK)
+ {
+ case GTK_JSON_STRING:
+ return gtk_json_parser_parse_string (self);
+
+ case GTK_JSON_NUMBER:
+ return gtk_json_parser_parse_number (self);
+
+ case GTK_JSON_NULL:
+ if (gtk_json_parser_try_identifier (self, "null"))
+ return TRUE;
+ break;
+
+ case GTK_JSON_BOOLEAN:
+ if (gtk_json_parser_try_identifier (self, "true") ||
+ gtk_json_parser_try_identifier (self, "false"))
+ return TRUE;
+ break;
+
+ case GTK_JSON_OBJECT:
+ case GTK_JSON_ARRAY:
+ /* don't preparse objects */
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ gtk_json_parser_syntax_error (self, "Expected a value");
+ return FALSE;
+}
+
+static void
+gtk_json_parser_push_block (GtkJsonParser *self,
+ GtkJsonBlockType type)
+{
+ self->block++;
+ if (self->block == self->blocks_end)
+ {
+ gsize old_size = self->blocks_end - self->blocks;
+ gsize new_size = old_size + 128;
+
+ if (self->blocks == self->blocks_preallocated)
+ {
+ self->blocks = g_new (GtkJsonBlock, new_size);
+ memcpy (self->blocks, self->blocks_preallocated, sizeof (GtkJsonBlock) * G_N_ELEMENTS (self->blocks_preallocated));
+ }
+ else
+ {
+ self->blocks = g_renew (GtkJsonBlock, self->blocks, new_size);
+ }
+ self->blocks_end = self->blocks + new_size;
+ self->block = self->blocks + old_size;
+ }
+
+ self->block->type = type;
+ self->block->member_name = 0;
+ self->block->value = 0;
+ self->block->index = 0;
+}
+
+static void
+gtk_json_parser_pop_block (GtkJsonParser *self)
+{
+ g_assert (self->block > self->blocks);
+ self->block--;
+}
+
+GtkJsonParser *
+gtk_json_parser_new_for_string (const char *string,
+ gssize size)
+{
+ GtkJsonParser *self;
+ GBytes *bytes;
+
+ bytes = g_bytes_new (string, size >= 0 ? size : strlen (string));
+
+ self = gtk_json_parser_new_for_bytes (bytes);
+
+ g_bytes_unref (bytes);
+
+ return self;
+}
+
+GtkJsonParser *
+gtk_json_parser_new_for_bytes (GBytes *bytes)
+{
+ GtkJsonParser *self;
+ gsize size;
+
+ g_return_val_if_fail (bytes != NULL, NULL);
+
+ self = g_slice_new0 (GtkJsonParser);
+
+ self->bytes = g_bytes_ref (bytes);
+ self->reader = g_bytes_get_data (bytes, &size);
+ self->end = self->reader + size;
+
+ self->blocks = self->blocks_preallocated;
+ self->blocks_end = self->blocks + G_N_ELEMENTS (self->blocks_preallocated);
+ self->block = self->blocks;
+ self->block->type = GTK_JSON_BLOCK_TOPLEVEL;
+
+ gtk_json_parser_skip_whitespace (self);
+ self->block->value = self->reader;
+ gtk_json_parser_parse_value (self);
+
+ return self;
+}
+
+void
+gtk_json_parser_free (GtkJsonParser *self)
+{
+ if (self == NULL)
+ return;
+
+ g_clear_error (&self->error);
+
+ g_bytes_unref (self->bytes);
+
+ if (self->blocks != self->blocks_preallocated)
+ g_free (self->blocks);
+
+ g_slice_free (GtkJsonParser, self);
+}
+
+static gboolean
+gtk_json_parser_skip_block (GtkJsonParser *self)
+{
+ if (self->reader != self->block->value)
+ return TRUE;
+
+ if (*self->reader == '{')
+ {
+ return gtk_json_parser_start_object (self) &&
+ gtk_json_parser_end (self);
+ }
+ else if (*self->reader == '[')
+ {
+ return gtk_json_parser_start_array (self) &&
+ gtk_json_parser_end (self);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ return FALSE;
+ }
+}
+
+gboolean
+gtk_json_parser_next (GtkJsonParser *self)
+{
+ if (self->error)
+ return FALSE;
+
+ if (self->block->value == NULL)
+ return FALSE;
+
+ if (!gtk_json_parser_skip_block (self))
+ {
+ g_assert (self->error);
+ return FALSE;
+ }
+
+ switch (self->block->type)
+ {
+ case GTK_JSON_BLOCK_TOPLEVEL:
+ gtk_json_parser_skip_whitespace (self);
+ if (gtk_json_parser_is_eof (self))
+ {
+ self->block->value = NULL;
+ if (gtk_json_parser_remaining (self))
+ {
+ gtk_json_parser_syntax_error (self, "Unexpected nul byte in document");
+ }
+ }
+ else
+ {
+ gtk_json_parser_syntax_error (self, "Data at end of document");
+ }
+ return FALSE;
+
+ case GTK_JSON_BLOCK_OBJECT:
+ gtk_json_parser_skip_whitespace (self);
+ if (gtk_json_parser_is_eof (self))
+ {
+ gtk_json_parser_syntax_error (self, "Unexpected end of document");
+ self->block->member_name = NULL;
+ self->block->value = NULL;
+ }
+ if (gtk_json_parser_has_char (self, '}'))
+ {
+ self->block->member_name = NULL;
+ self->block->value = NULL;
+ return FALSE;
+ }
+ if (!gtk_json_parser_try_char (self, ','))
+ {
+ gtk_json_parser_syntax_error (self, "Expected a ',' to separate object members");
+ return FALSE;
+ }
+ gtk_json_parser_skip_whitespace (self);
+ self->block->member_name = self->reader;
+
+ if (!gtk_json_parser_parse_string (self))
+ return FALSE;
+ gtk_json_parser_skip_whitespace (self);
+ if (!gtk_json_parser_try_char (self, ':'))
+ {
+ gtk_json_parser_syntax_error (self, "Missing ':' after member name");
+ return FALSE;
+ }
+
+ gtk_json_parser_skip_whitespace (self);
+ self->block->value = self->reader;
+ if (!gtk_json_parser_parse_value (self))
+ return FALSE;
+ break;
+
+ case GTK_JSON_BLOCK_ARRAY:
+ gtk_json_parser_skip_whitespace (self);
+ if (gtk_json_parser_is_eof (self))
+ {
+ gtk_json_parser_syntax_error (self, "Unexpected end of document");
+ self->block->member_name = NULL;
+ self->block->value = NULL;
+ }
+ if (gtk_json_parser_has_char (self, ']'))
+ {
+ self->block->value = NULL;
+ return FALSE;
+ }
+
+ if (!gtk_json_parser_try_char (self, ','))
+ {
+ gtk_json_parser_syntax_error (self, "Expected a ',' to separate array members");
+ return FALSE;
+ }
+
+ gtk_json_parser_skip_whitespace (self);
+ self->block->value = self->reader;
+ if (!gtk_json_parser_parse_value (self))
+ return FALSE;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return TRUE;
+}
+
+GtkJsonNode
+gtk_json_parser_get_node (GtkJsonParser *self)
+{
+ if (self->error)
+ return GTK_JSON_NONE;
+
+ if (self->block->value == NULL)
+ return GTK_JSON_NONE;
+
+ return (json_character_table[*self->block->value] & JSON_CHARACTER_NODE_MASK);
+}
+
+const GError *
+gtk_json_parser_get_error (GtkJsonParser *self)
+{
+ return self->error;
+}
+
+char *
+gtk_json_parser_get_member_name (GtkJsonParser *self)
+{
+ if (self->error)
+ return NULL;
+
+ if (self->block->type != GTK_JSON_BLOCK_OBJECT)
+ return NULL;
+
+ if (self->block->member_name == NULL)
+ return NULL;
+
+ return gtk_json_unescape_string (self->block->member_name);
+}
+
+gssize
+gtk_json_parser_select_member (GtkJsonParser *self,
+ const char * const *options)
+{
+ char *member_name;
+ gssize i;
+
+ member_name = gtk_json_parser_get_member_name (self);
+ if (member_name == NULL)
+ return -1;
+
+ for (i = 0; options[i]; i++)
+ {
+ if (strcmp (member_name, options[i]) == 0)
+ break;
+ }
+ if (options[i] == NULL)
+ i = -1;
+
+ g_free (member_name);
+
+ return i;
+}
+
+gboolean
+gtk_json_parser_get_boolean (GtkJsonParser *self)
+{
+ if (self->error)
+ return FALSE;
+
+ if (self->block->value == NULL)
+ return FALSE;
+
+ if (*self->block->value == 't')
+ return TRUE;
+ else if (*self->block->value == 'f')
+ return FALSE;
+
+ gtk_json_parser_value_error (self, "Expected a boolean value");
+ return FALSE;
+}
+
+double
+gtk_json_parser_get_number (GtkJsonParser *self)
+{
+ double result;
+
+ if (self->error)
+ return 0;
+
+ if (self->block->value == NULL)
+ return 0;
+
+ if (!strchr ("-0123456789", *self->block->value))
+ {
+ gtk_json_parser_value_error (self, "Expected a number");
+ return 0;
+ }
+
+ errno = 0;
+ if (gtk_json_parser_remaining (self) == 0)
+ {
+ /* need terminated string here */
+ char *s = g_strndup ((const char *) self->block->value, self->reader - self->block->value);
+ result = g_ascii_strtod (s, NULL);
+ g_free (s);
+ }
+ else
+ {
+ result = g_ascii_strtod ((const char *) self->block->value, NULL);
+ }
+
+ if (errno)
+ {
+ if (errno == ERANGE)
+ gtk_json_parser_value_error (self, "Number out of range");
+ else
+ gtk_json_parser_value_error (self, "%s", g_strerror (errno));
+
+ return 0;
+ }
+
+ return result;
+}
+
+int
+gtk_json_parser_get_int (GtkJsonParser *self)
+{
+ int result;
+
+ if (self->error)
+ return 0;
+
+ if (self->block->value == NULL)
+ return 0;
+
+ if (!strchr ("-0123456789", *self->block->value))
+ {
+ gtk_json_parser_value_error (self, "Expected a number");
+ return 0;
+ }
+
+ errno = 0;
+ if (gtk_json_parser_remaining (self) == 0)
+ {
+ /* need terminated string here */
+ char *s = g_strndup ((const char *) self->block->value, self->reader - self->block->value);
+ result = g_ascii_strtod (s, NULL);
+ g_free (s);
+ }
+ else
+ {
+ result = (int) g_ascii_strtoll ((const char *) self->block->value, NULL, 10);
+ }
+
+ if (errno)
+ {
+ if (errno == ERANGE)
+ gtk_json_parser_value_error (self, "Number out of range");
+ else
+ gtk_json_parser_value_error (self, "%s", g_strerror (errno));
+
+ return 0;
+ }
+
+ return result;
+}
+
+#if 0
+int gtk_json_parser_get_int (GtkJsonParser *self);
+guint gtk_json_parser_get_uint (GtkJsonParser *self);
+#endif
+
+char *
+gtk_json_parser_get_string (GtkJsonParser *self)
+{
+ if (self->error)
+ return g_strdup ("");
+
+ if (self->block->value == NULL)
+ return g_strdup ("");
+
+ if (*self->block->value != '"')
+ {
+ gtk_json_parser_value_error (self, "Expected a string");
+ return g_strdup ("");
+ }
+
+ return gtk_json_unescape_string (self->block->value);
+}
+
+gboolean
+gtk_json_parser_start_object (GtkJsonParser *self)
+{
+ if (self->error)
+ return FALSE;
+
+ if (!gtk_json_parser_try_char (self, '{'))
+ {
+ gtk_json_parser_value_error (self, "Expected an object");
+ return FALSE;
+ }
+
+ gtk_json_parser_push_block (self, GTK_JSON_BLOCK_OBJECT);
+
+ gtk_json_parser_skip_whitespace (self);
+ if (gtk_json_parser_is_eof (self))
+ {
+ gtk_json_parser_syntax_error (self, "Unexpected end of document");
+ return FALSE;
+ }
+ if (gtk_json_parser_has_char (self, '}'))
+ return TRUE;
+ self->block->member_name = self->reader;
+
+ if (!gtk_json_parser_parse_string (self))
+ return FALSE;
+ gtk_json_parser_skip_whitespace (self);
+ if (!gtk_json_parser_try_char (self, ':'))
+ {
+ gtk_json_parser_syntax_error (self, "Missing ':' after member name");
+ return FALSE;
+ }
+
+ gtk_json_parser_skip_whitespace (self);
+ self->block->value = self->reader;
+ if (!gtk_json_parser_parse_value (self))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
+gtk_json_parser_start_array (GtkJsonParser *self)
+{
+ if (self->error)
+ return FALSE;
+
+ if (!gtk_json_parser_try_char (self, '['))
+ {
+ gtk_json_parser_value_error (self, "Expected an array");
+ return FALSE;
+ }
+
+ gtk_json_parser_push_block (self, GTK_JSON_BLOCK_ARRAY);
+ gtk_json_parser_skip_whitespace (self);
+ if (gtk_json_parser_is_eof (self))
+ {
+ gtk_json_parser_syntax_error (self, "Unexpected end of document");
+ return FALSE;
+ }
+ if (gtk_json_parser_has_char (self, ']'))
+ {
+ self->block->value = NULL;
+ return TRUE;
+ }
+ self->block->value = self->reader;
+ if (!gtk_json_parser_parse_value (self))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
+gtk_json_parser_end (GtkJsonParser *self)
+{
+ char bracket;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+
+ while (gtk_json_parser_next (self));
+
+ if (self->error)
+ return FALSE;
+
+ switch (self->block->type)
+ {
+ case GTK_JSON_BLOCK_OBJECT:
+ bracket = '}';
+ break;
+ case GTK_JSON_BLOCK_ARRAY:
+ bracket = ']';
+ break;
+ case GTK_JSON_BLOCK_TOPLEVEL:
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ if (!gtk_json_parser_try_char (self, bracket))
+ {
+ gtk_json_parser_syntax_error (self, "No terminating '%c'", bracket);
+ return FALSE;
+ }
+
+ gtk_json_parser_pop_block (self);
+
+ return TRUE;
+}
+
+void
+gtk_json_parser_set_error (GtkJsonParser *self,
+ GError *error)
+{
+ if (self->error)
+ g_error_free (error);
+ else
+ self->error = error;
+}
diff --git a/pango/json/gtkjsonparserprivate.h b/pango/json/gtkjsonparserprivate.h
new file mode 100644
index 00000000..81c001cc
--- /dev/null
+++ b/pango/json/gtkjsonparserprivate.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2021 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+
+#ifndef __GTK_JSON_PARSER_H__
+#define __GTK_JSON_PARSER_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GTK_JSON_NONE,
+ GTK_JSON_NULL,
+ GTK_JSON_BOOLEAN,
+ GTK_JSON_NUMBER,
+ GTK_JSON_STRING,
+ GTK_JSON_OBJECT,
+ GTK_JSON_ARRAY
+} GtkJsonNode;
+
+typedef struct _GtkJsonParser GtkJsonParser;
+
+GtkJsonParser * gtk_json_parser_new_for_bytes (GBytes *bytes);
+GtkJsonParser * gtk_json_parser_new_for_string (const char *string,
+ gssize size);
+
+void gtk_json_parser_free (GtkJsonParser *self);
+
+gboolean gtk_json_parser_next (GtkJsonParser *self);
+GtkJsonNode gtk_json_parser_get_node (GtkJsonParser *self);
+const GError * gtk_json_parser_get_error (GtkJsonParser *self) G_GNUC_PURE;
+char * gtk_json_parser_get_member_name (GtkJsonParser *self);
+gssize gtk_json_parser_select_member (GtkJsonParser *self,
+ const char * const *options);
+
+gboolean gtk_json_parser_get_boolean (GtkJsonParser *self);
+double gtk_json_parser_get_number (GtkJsonParser *self);
+int gtk_json_parser_get_int (GtkJsonParser *self);
+guint gtk_json_parser_get_uint (GtkJsonParser *self);
+char * gtk_json_parser_get_string (GtkJsonParser *self);
+
+gboolean gtk_json_parser_start_object (GtkJsonParser *self);
+gboolean gtk_json_parser_start_array (GtkJsonParser *self);
+gboolean gtk_json_parser_end (GtkJsonParser *self);
+
+void gtk_json_parser_set_error (GtkJsonParser *self,
+ GError *error);
+
+
+G_END_DECLS
+
+#endif /* __GTK_JSON_PARSER_H__ */
diff --git a/pango/json/gtkjsonprinter.c b/pango/json/gtkjsonprinter.c
new file mode 100644
index 00000000..f2f1e273
--- /dev/null
+++ b/pango/json/gtkjsonprinter.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright © 2021 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+
+#include "config.h"
+
+#include "gtkjsonprinterprivate.h"
+
+typedef struct _GtkJsonBlock GtkJsonBlock;
+
+typedef enum {
+ GTK_JSON_BLOCK_TOPLEVEL,
+ GTK_JSON_BLOCK_OBJECT,
+ GTK_JSON_BLOCK_ARRAY,
+} GtkJsonBlockType;
+
+struct _GtkJsonBlock
+{
+ GtkJsonBlockType type;
+ gsize n_elements; /* number of elements already written */
+};
+
+struct _GtkJsonPrinter
+{
+ GtkJsonPrinterFlags flags;
+ char *indentation;
+
+ GtkJsonPrinterWriteFunc write_func;
+ gpointer user_data;
+ GDestroyNotify user_destroy;
+
+ GtkJsonBlock *block; /* current block */
+ GtkJsonBlock *blocks; /* blocks array */
+ GtkJsonBlock *blocks_end; /* blocks array */
+ GtkJsonBlock blocks_preallocated[128]; /* preallocated */
+};
+
+static void
+gtk_json_printer_push_block (GtkJsonPrinter *self,
+ GtkJsonBlockType type)
+{
+ self->block++;
+ if (self->block == self->blocks_end)
+ {
+ gsize old_size = self->blocks_end - self->blocks;
+ gsize new_size = old_size + 128;
+
+ if (self->blocks == self->blocks_preallocated)
+ {
+ self->blocks = g_new (GtkJsonBlock, new_size);
+ memcpy (self->blocks, self->blocks_preallocated, sizeof (GtkJsonBlock) * G_N_ELEMENTS (self->blocks_preallocated));
+ }
+ else
+ {
+ self->blocks = g_renew (GtkJsonBlock, self->blocks, new_size);
+ }
+ self->blocks_end = self->blocks + new_size;
+ self->block = self->blocks + old_size;
+ }
+
+ self->block->type = type;
+ self->block->n_elements = 0;
+}
+
+static void
+gtk_json_printer_pop_block (GtkJsonPrinter *self)
+{
+ g_assert (self->block > self->blocks);
+ self->block--;
+}
+
+GtkJsonPrinter *
+gtk_json_printer_new (GtkJsonPrinterWriteFunc write_func,
+ gpointer data,
+ GDestroyNotify destroy)
+{
+ GtkJsonPrinter *self;
+
+ g_return_val_if_fail (write_func, NULL);
+
+ self = g_slice_new0 (GtkJsonPrinter);
+
+ self->flags = 0;
+ self->indentation = g_strdup (" ");
+
+ self->write_func = write_func;
+ self->user_data = data;
+ self->user_destroy = destroy;
+
+ self->blocks = self->blocks_preallocated;
+ self->blocks_end = self->blocks + G_N_ELEMENTS (self->blocks_preallocated);
+ self->block = self->blocks;
+ self->block->type = GTK_JSON_BLOCK_TOPLEVEL;
+
+ return self;
+}
+
+void
+gtk_json_printer_free (GtkJsonPrinter *self)
+{
+ g_return_if_fail (self != NULL);
+
+ g_free (self->indentation);
+
+ if (self->user_destroy)
+ self->user_destroy (self->user_data);
+
+ if (self->blocks != self->blocks_preallocated)
+ g_free (self->blocks);
+
+ g_slice_free (GtkJsonPrinter, self);
+}
+
+static gboolean
+gtk_json_printer_has_flag (GtkJsonPrinter *self,
+ GtkJsonPrinterFlags flag)
+{
+ return (self->flags & flag) ? TRUE : FALSE;
+}
+
+gsize
+gtk_json_printer_get_depth (GtkJsonPrinter *self)
+{
+ return self->block - self->blocks;
+}
+
+gsize
+gtk_json_printer_get_n_elements (GtkJsonPrinter *self)
+{
+ return self->block->n_elements;
+}
+
+void
+gtk_json_printer_set_flags (GtkJsonPrinter *self,
+ GtkJsonPrinterFlags flags)
+{
+ g_return_if_fail (self != NULL);
+
+ self->flags = flags;
+}
+
+GtkJsonPrinterFlags
+gtk_json_printer_get_flags (GtkJsonPrinter *self)
+{
+ g_return_val_if_fail (self != NULL, 0);
+
+ return self->flags;
+}
+
+void
+gtk_json_printer_set_indentation (GtkJsonPrinter *self,
+ gsize amount)
+{
+ g_return_if_fail (self != NULL);
+
+ g_free (self->indentation);
+
+ self->indentation = g_malloc (amount + 1);
+ memset (self->indentation, ' ', amount);
+ self->indentation[amount] = 0;
+}
+
+gsize
+gtk_json_printer_get_indentation (GtkJsonPrinter *self)
+{
+ g_return_val_if_fail (self != NULL, 2);
+
+ return strlen (self->indentation);
+}
+
+static void
+gtk_json_printer_write (GtkJsonPrinter *self,
+ const char *s)
+{
+ self->write_func (self, s, self->user_data);
+}
+
+static char *
+gtk_json_printer_escape_string (GtkJsonPrinter *self,
+ const char *str)
+{
+ GString *string;
+
+ string = g_string_new (NULL);
+ string = g_string_append_c (string, '"');
+
+ for (; *str != '\0'; str = g_utf8_next_char (str))
+ {
+ switch (*str)
+ {
+ case '"':
+ g_string_append (string, "\\\"");
+ break;
+ case '\\':
+ g_string_append (string, "\\\\");
+ break;
+ case '\b':
+ g_string_append (string, "\\b");
+ break;
+ case '\f':
+ g_string_append (string, "\\f");
+ break;
+ case '\n':
+ g_string_append (string, "\\n");
+ break;
+ case '\r':
+ g_string_append (string, "\\r");
+ break;
+ case '\t':
+ g_string_append (string, "\\t");
+ break;
+ default:
+ if ((int) *str < 0x20)
+ {
+ if ((guint) *str < 0x20 || gtk_json_printer_has_flag (self, GTK_JSON_PRINTER_ASCII))
+ g_string_append_printf (string, "\\u%04x", g_utf8_get_char (str));
+ else
+ g_string_append_unichar (string, g_utf8_get_char (str));
+ }
+ else
+ g_string_append_c (string, *str);
+ }
+ }
+
+ string = g_string_append_c (string, '"');
+ return g_string_free (string, FALSE);
+}
+
+static void
+gtk_json_printer_newline (GtkJsonPrinter *self)
+{
+ gsize depth;
+
+ if (!gtk_json_printer_has_flag (self, GTK_JSON_PRINTER_PRETTY))
+ return;
+
+ gtk_json_printer_write (self, "\n");
+ for (depth = gtk_json_printer_get_depth (self); depth-->0;)
+ gtk_json_printer_write (self, self->indentation);
+}
+
+static void
+gtk_json_printer_begin_member (GtkJsonPrinter *self,
+ const char *name)
+{
+ if (gtk_json_printer_get_n_elements (self) > 0)
+ gtk_json_printer_write (self, ",");
+ if (self->block->type != GTK_JSON_BLOCK_TOPLEVEL || gtk_json_printer_get_n_elements (self) > 0)
+ gtk_json_printer_newline (self);
+
+ self->block->n_elements++;
+
+ if (name)
+ {
+ char *escaped = gtk_json_printer_escape_string (self, name);
+ gtk_json_printer_write (self, escaped);
+ g_free (escaped);
+ if (gtk_json_printer_has_flag (self, GTK_JSON_PRINTER_PRETTY))
+ gtk_json_printer_write (self, " : ");
+ else
+ gtk_json_printer_write (self, ":");
+ }
+}
+
+void
+gtk_json_printer_add_boolean (GtkJsonPrinter *self,
+ const char *name,
+ gboolean value)
+{
+ g_return_if_fail (self != NULL);
+ g_return_if_fail ((self->block->type == GTK_JSON_BLOCK_OBJECT) == (name != NULL));
+
+ gtk_json_printer_begin_member (self, name);
+ gtk_json_printer_write (self, value ? "true" : "false");
+}
+
+void
+gtk_json_printer_add_number (GtkJsonPrinter *self,
+ const char *name,
+ double value)
+{
+ char buf[G_ASCII_DTOSTR_BUF_SIZE];
+
+ g_return_if_fail (self != NULL);
+ g_return_if_fail ((self->block->type == GTK_JSON_BLOCK_OBJECT) == (name != NULL));
+
+ gtk_json_printer_begin_member (self, name);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, value);
+ gtk_json_printer_write (self, buf);
+}
+
+void
+gtk_json_printer_add_integer (GtkJsonPrinter *self,
+ const char *name,
+ int value)
+{
+ char buf[128];
+
+ g_return_if_fail (self != NULL);
+ g_return_if_fail ((self->block->type == GTK_JSON_BLOCK_OBJECT) == (name != NULL));
+
+ gtk_json_printer_begin_member (self, name);
+ g_snprintf (buf, sizeof (buf), "%d", value);
+ gtk_json_printer_write (self, buf);
+}
+
+void
+gtk_json_printer_add_string (GtkJsonPrinter *self,
+ const char *name,
+ const char *s)
+{
+ char *escaped;
+
+ g_return_if_fail (self != NULL);
+ g_return_if_fail ((self->block->type == GTK_JSON_BLOCK_OBJECT) == (name != NULL));
+ g_return_if_fail (s != NULL);
+
+ gtk_json_printer_begin_member (self, name);
+ escaped = gtk_json_printer_escape_string (self, s);
+ gtk_json_printer_write (self, escaped);
+ g_free (escaped);
+}
+
+void
+gtk_json_printer_add_null (GtkJsonPrinter *self,
+ const char *name)
+{
+ g_return_if_fail (self != NULL);
+ g_return_if_fail ((self->block->type == GTK_JSON_BLOCK_OBJECT) == (name != NULL));
+
+ gtk_json_printer_begin_member (self, name);
+ gtk_json_printer_write (self, "null");
+}
+
+void
+gtk_json_printer_start_object (GtkJsonPrinter *self,
+ const char *name)
+{
+ g_return_if_fail (self != NULL);
+ g_return_if_fail ((self->block->type == GTK_JSON_BLOCK_OBJECT) == (name != NULL));
+
+ gtk_json_printer_begin_member (self, name);
+ gtk_json_printer_write (self, "{");
+ gtk_json_printer_push_block (self, GTK_JSON_BLOCK_OBJECT);
+}
+
+void
+gtk_json_printer_start_array (GtkJsonPrinter *self,
+ const char *name)
+{
+ g_return_if_fail (self != NULL);
+ g_return_if_fail ((self->block->type == GTK_JSON_BLOCK_OBJECT) == (name != NULL));
+
+ gtk_json_printer_begin_member (self, name);
+ gtk_json_printer_write (self, "[");
+ gtk_json_printer_push_block (self, GTK_JSON_BLOCK_ARRAY);
+}
+
+void
+gtk_json_printer_end (GtkJsonPrinter *self)
+{
+ const char *bracket;
+ gboolean empty;
+
+ g_return_if_fail (self != NULL);
+
+ switch (self->block->type)
+ {
+ case GTK_JSON_BLOCK_OBJECT:
+ bracket = "}";
+ break;
+ case GTK_JSON_BLOCK_ARRAY:
+ bracket = "]";
+ break;
+ case GTK_JSON_BLOCK_TOPLEVEL:
+ default:
+ g_return_if_reached ();
+ }
+
+ empty = gtk_json_printer_get_n_elements (self) == 0;
+ gtk_json_printer_pop_block (self);
+
+ if (!empty)
+ {
+ gtk_json_printer_newline (self);
+ }
+ gtk_json_printer_write (self, bracket);
+}
+
diff --git a/pango/json/gtkjsonprinterprivate.h b/pango/json/gtkjsonprinterprivate.h
new file mode 100644
index 00000000..e25a1b1d
--- /dev/null
+++ b/pango/json/gtkjsonprinterprivate.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2021 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+
+#ifndef __GTK_JSON_PRINTER_H__
+#define __GTK_JSON_PRINTER_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GtkJsonPrinter GtkJsonPrinter;
+
+typedef enum {
+ GTK_JSON_PRINTER_PRETTY = (1 << 0),
+ GTK_JSON_PRINTER_ASCII = (1 << 1),
+} GtkJsonPrinterFlags;
+
+typedef void (* GtkJsonPrinterWriteFunc) (GtkJsonPrinter *printer,
+ const char *s,
+ gpointer user_data);
+
+
+GtkJsonPrinter * gtk_json_printer_new (GtkJsonPrinterWriteFunc write_func,
+ gpointer data,
+ GDestroyNotify destroy);
+void gtk_json_printer_free (GtkJsonPrinter *self);
+
+void gtk_json_printer_set_flags (GtkJsonPrinter *self,
+ GtkJsonPrinterFlags flags);
+GtkJsonPrinterFlags gtk_json_printer_get_flags (GtkJsonPrinter *self);
+void gtk_json_printer_set_indentation (GtkJsonPrinter *self,
+ gsize amount);
+gsize gtk_json_printer_get_indentation (GtkJsonPrinter *self);
+
+gsize gtk_json_printer_get_depth (GtkJsonPrinter *self);
+gsize gtk_json_printer_get_n_elements (GtkJsonPrinter *self);
+
+void gtk_json_printer_add_boolean (GtkJsonPrinter *self,
+ const char *name,
+ gboolean value);
+void gtk_json_printer_add_number (GtkJsonPrinter *self,
+ const char *name,
+ double value);
+void gtk_json_printer_add_integer (GtkJsonPrinter *self,
+ const char *name,
+ int value);
+void gtk_json_printer_add_string (GtkJsonPrinter *self,
+ const char *name,
+ const char *s);
+void gtk_json_printer_add_null (GtkJsonPrinter *self,
+ const char *name);
+
+void gtk_json_printer_start_object (GtkJsonPrinter *self,
+ const char *name);
+void gtk_json_printer_start_array (GtkJsonPrinter *self,
+ const char *name);
+void gtk_json_printer_end (GtkJsonPrinter *self);
+
+
+G_END_DECLS
+
+#endif /* __GTK_JSON_PRINTER_H__ */
diff --git a/pango/meson.build b/pango/meson.build
index 7c7bb280..4e6f746e 100644
--- a/pango/meson.build
+++ b/pango/meson.build
@@ -28,6 +28,8 @@ pango_sources = [
'reorder-items.c',
'shape.c',
'serializer.c',
+ 'json/gtkjsonparser.c',
+ 'json/gtkjsonprinter.c',
]
pango_headers = [
diff --git a/pango/pango-font.h b/pango/pango-font.h
index bfe4bc31..f4e619a1 100644
--- a/pango/pango-font.h
+++ b/pango/pango-font.h
@@ -637,6 +637,11 @@ PangoLanguage ** pango_font_get_languages (PangoFont *font);
PANGO_AVAILABLE_IN_1_50
GBytes * pango_font_serialize (PangoFont *font);
+PANGO_AVAILABLE_IN_1_50
+PangoFont * pango_font_deserialize (PangoContext *context,
+ GBytes *bytes,
+ GError **error);
+
/**
* PANGO_GLYPH_EMPTY:
*
diff --git a/pango/pango-layout.h b/pango/pango-layout.h
index 32dc16f0..7b3c6ca6 100644
--- a/pango/pango-layout.h
+++ b/pango/pango-layout.h
@@ -382,20 +382,16 @@ gboolean pango_layout_write_to_file (PangoLayout
/**
* PangoLayoutDeserializeError:
- * @PANGO_LAYOUT_SERIALIZE_INVALID: Unspecified error
- * @PANGO_LAYOUT_SERIALIZE_INVALID_SYNTAX: The serialized data had
- * the wrong structure (e.g. a member was expected to be a JSon object,
- * but was an array)
- * @PANGO_LAYOUT_SERIALIZE_INVALID_VALUE: A JSon value could not be
+ * @PANGO_LAYOUT_DESERIALIZE_INVALID: Unspecified error
+ * @PANGO_LAYOUT_DESERIALIZE_INVALID_VALUE: A JSon value could not be
* interpreted
- * @PANGO_LAYOUT_SERIALIZE_MISSING_VALUE: A required JSon member was
+ * @PANGO_LAYOUT_DESERIALIZE_MISSING_VALUE: A required JSon member was
* not found
*
* Errors that can be returned by [func@Pango.Layout.deserialize].
*/
typedef enum {
PANGO_LAYOUT_DESERIALIZE_INVALID,
- PANGO_LAYOUT_DESERIALIZE_INVALID_SYNTAX,
PANGO_LAYOUT_DESERIALIZE_INVALID_VALUE,
PANGO_LAYOUT_DESERIALIZE_MISSING_VALUE,
} PangoLayoutDeserializeError;
diff --git a/pango/pango-tabs.c b/pango/pango-tabs.c
index 0665161c..ab01cfe5 100644
--- a/pango/pango-tabs.c
+++ b/pango/pango-tabs.c
@@ -370,6 +370,25 @@ pango_tab_array_get_positions_in_pixels (PangoTabArray *tab_array)
}
/**
+ * pango_tab_array_set_positions_in_pixels:
+ * @tab_array: a `PangoTabArray`
+ * @positions_in_pixels: whether positions are in pixels
+ *
+ * Sets whether positions in this array are specified in
+ * pixels.
+ *
+ * Since: 1.50
+ */
+void
+pango_tab_array_set_positions_in_pixels (PangoTabArray *tab_array,
+ gboolean positions_in_pixels)
+{
+ g_return_if_fail (tab_array != NULL);
+
+ tab_array->positions_in_pixels = positions_in_pixels;
+}
+
+/**
* pango_tab_array_to_string:
* @tab_array: a `PangoTabArray`
*
diff --git a/pango/pango-tabs.h b/pango/pango-tabs.h
index 8ca94fdb..a804977b 100644
--- a/pango/pango-tabs.h
+++ b/pango/pango-tabs.h
@@ -94,6 +94,10 @@ PANGO_AVAILABLE_IN_ALL
gboolean pango_tab_array_get_positions_in_pixels (PangoTabArray *tab_array);
PANGO_AVAILABLE_IN_1_50
+void pango_tab_array_set_positions_in_pixels (PangoTabArray *tab_array,
+ gboolean positions_in_pixels);
+
+PANGO_AVAILABLE_IN_1_50
char * pango_tab_array_to_string (PangoTabArray *tab_array);
PANGO_AVAILABLE_IN_1_50
PangoTabArray * pango_tab_array_from_string (const char *text);
diff --git a/pango/serializer.c b/pango/serializer.c
index fe0fc25c..86e6b004 100644
--- a/pango/serializer.c
+++ b/pango/serializer.c
@@ -28,7 +28,8 @@
#include <pango/pango-font-private.h>
#include <hb-ot.h>
-#include <json-glib/json-glib.h>
+#include "pango/json/gtkjsonparserprivate.h"
+#include "pango/json/gtkjsonprinterprivate.h"
/* {{{ Error handling */
@@ -58,10 +59,11 @@ get_enum_type (PangoAttrType attr_type)
}
static void
-add_enum_value (JsonBuilder *builder,
- GType type,
- int value,
- gboolean allow_extra)
+add_enum_value (GtkJsonPrinter *printer,
+ const char *member,
+ GType type,
+ int value,
+ gboolean allow_extra)
{
GEnumClass *enum_class;
GEnumValue *enum_value;
@@ -70,51 +72,38 @@ add_enum_value (JsonBuilder *builder,
enum_value = g_enum_get_value (enum_class, value);
if (enum_value)
- json_builder_add_string_value (builder, enum_value->value_nick);
+ gtk_json_printer_add_string (printer, member, enum_value->value_nick);
else if (allow_extra)
- {
- char buf[128];
- g_snprintf (buf, 128, "%d", value);
- json_builder_add_string_value (builder, buf);
- }
+ gtk_json_printer_add_integer (printer, member, value);
else
- json_builder_add_string_value (builder, "ERROR");
-
+ gtk_json_printer_add_string (printer, member, "ERROR");
}
static void
-add_attribute (JsonBuilder *builder,
+add_attribute (GtkJsonPrinter *printer,
PangoAttribute *attr)
{
char *str;
- json_builder_begin_object (builder);
+ gtk_json_printer_start_object (printer, NULL);
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);
- }
+ gtk_json_printer_add_integer (printer, "start", (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);
+ gtk_json_printer_add_integer (printer, "end", (int)attr->end_index);
+ add_enum_value (printer, "type", 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));
+ gtk_json_printer_add_string (printer, "value", 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);
+ gtk_json_printer_add_string (printer, "value", ((PangoAttrString*)attr)->value);
break;
case PANGO_ATTR_STYLE:
case PANGO_ATTR_VARIANT:
@@ -125,11 +114,11 @@ add_attribute (JsonBuilder *builder,
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);
+ add_enum_value (printer, "value", 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);
+ add_enum_value (printer, "value", get_enum_type (attr->klass->type), ((PangoAttrInt*)attr)->value, TRUE);
break;
case PANGO_ATTR_SIZE:
case PANGO_ATTR_RISE:
@@ -141,11 +130,11 @@ add_attribute (JsonBuilder *builder,
case PANGO_ATTR_WORD:
case PANGO_ATTR_SENTENCE:
case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT:
- json_builder_add_int_value (builder, ((PangoAttrInt*)attr)->value);
+ gtk_json_printer_add_integer (printer, "value", ((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);
+ gtk_json_printer_add_string (printer, "value", str);
g_free (str);
break;
case PANGO_ATTR_FOREGROUND:
@@ -154,29 +143,29 @@ add_attribute (JsonBuilder *builder,
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);
+ gtk_json_printer_add_string (printer, "value", 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);
+ gtk_json_printer_add_boolean (printer, "value", ((PangoAttrInt*)attr)->value != 0);
break;
case PANGO_ATTR_SHAPE:
- json_builder_add_string_value (builder, "shape");
+ gtk_json_printer_add_string (printer, "value", "shape");
break;
case PANGO_ATTR_SCALE:
case PANGO_ATTR_LINE_HEIGHT:
- json_builder_add_double_value (builder, ((PangoAttrFloat*)attr)->value);
+ gtk_json_printer_add_number (printer, "value", ((PangoAttrFloat*)attr)->value);
}
- json_builder_end_object (builder);
+ gtk_json_printer_end (printer);
}
static void
-add_attr_list (JsonBuilder *builder,
- PangoAttrList *attrs)
+add_attr_list (GtkJsonPrinter *printer,
+ PangoAttrList *attrs)
{
GSList *attributes, *l;
@@ -188,62 +177,54 @@ add_attr_list (JsonBuilder *builder,
if (!attributes)
return;
- json_builder_set_member_name (builder, "attributes");
- json_builder_begin_array (builder);
+ gtk_json_printer_start_array (printer, "attributes");
for (l = attributes; l; l = l->next)
{
PangoAttribute *attr = l->data;
- add_attribute (builder, attr);
+ add_attribute (printer, attr);
}
g_slist_free_full (attributes, (GDestroyNotify) pango_attribute_destroy);
- json_builder_end_array (builder);
+ gtk_json_printer_end (printer);
}
static void
-add_tab_array (JsonBuilder *builder,
- PangoTabArray *tabs)
+add_tab_array (GtkJsonPrinter *printer,
+ PangoTabArray *tabs)
{
if (!tabs || pango_tab_array_get_size (tabs) == 0)
return;
- json_builder_set_member_name (builder, "tabs");
-
- json_builder_begin_object (builder);
+ gtk_json_printer_start_object (printer, "tabs");
- 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);
+ gtk_json_printer_add_boolean (printer, "positions-in-pixels", pango_tab_array_get_positions_in_pixels (tabs));
+ gtk_json_printer_start_array (printer, "positions");
for (int i = 0; i < pango_tab_array_get_size (tabs); i++)
{
PangoTabAlign align;
int pos;
pango_tab_array_get_tab (tabs, i, &align, &pos);
- json_builder_begin_object (builder);
- json_builder_set_member_name (builder, "position");
- json_builder_add_int_value (builder, pos);
- json_builder_set_member_name (builder, "alignment");
- add_enum_value (builder, PANGO_TYPE_TAB_ALIGN, align, FALSE);
- json_builder_set_member_name (builder, "decimal-point");
- json_builder_add_int_value (builder, pango_tab_array_get_decimal_point (tabs, i));
- json_builder_end_object (builder);
+ gtk_json_printer_start_object (printer, NULL);
+ gtk_json_printer_add_integer (printer, "position", pos);
+ add_enum_value (printer, "alignment", PANGO_TYPE_TAB_ALIGN, align, FALSE);
+ gtk_json_printer_add_integer (printer, "decimal-point", pango_tab_array_get_decimal_point (tabs, i));
+ gtk_json_printer_end (printer);
}
- json_builder_end_array (builder);
+ gtk_json_printer_end (printer);
- json_builder_end_object (builder);
+ gtk_json_printer_end (printer);
}
static void
-add_context (JsonBuilder *builder,
- PangoContext *context)
+add_context (GtkJsonPrinter *printer,
+ PangoContext *context)
{
char *str;
const PangoMatrix *matrix;
PangoMatrix identity = PANGO_MATRIX_INIT;
- json_builder_begin_object (builder);
+ gtk_json_printer_start_object (printer, "context");
/* Note: since we don't create the context when deserializing,
* we don't strip out default values here to ensure that the
@@ -251,143 +232,86 @@ add_context (JsonBuilder *builder,
*/
str = pango_font_description_to_string (context->font_desc);
- json_builder_set_member_name (builder, "font");
- json_builder_add_string_value (builder, str);
+ gtk_json_printer_add_string (printer, "font", str);
g_free (str);
if (context->set_language)
- {
- json_builder_set_member_name (builder, "language");
- json_builder_add_string_value (builder, pango_language_to_string (context->set_language));
- }
-
- json_builder_set_member_name (builder, "base-gravity");
- add_enum_value (builder, PANGO_TYPE_GRAVITY, context->base_gravity, FALSE);
+ gtk_json_printer_add_string (printer, "language", pango_language_to_string (context->set_language));
- json_builder_set_member_name (builder, "gravity-hint");
- add_enum_value (builder, PANGO_TYPE_GRAVITY_HINT, context->gravity_hint, FALSE);
+ add_enum_value (printer, "base-gravity", PANGO_TYPE_GRAVITY, context->base_gravity, FALSE);
+ add_enum_value (printer, "gravity-hint", PANGO_TYPE_GRAVITY_HINT, context->gravity_hint, FALSE);
+ add_enum_value (printer, "base-dir", PANGO_TYPE_DIRECTION, context->base_dir, FALSE);
+ gtk_json_printer_add_boolean (printer, "round-glyph-positions", context->round_glyph_positions);
- 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");
- json_builder_add_boolean_value (builder, context->round_glyph_positions);
-
- json_builder_set_member_name (builder, "transform");
matrix = pango_context_get_matrix (context);
if (!matrix)
matrix = &identity;
- json_builder_begin_array (builder);
- json_builder_add_double_value (builder, matrix->xx);
- json_builder_add_double_value (builder, matrix->xy);
- json_builder_add_double_value (builder, matrix->yx);
- json_builder_add_double_value (builder, matrix->yy);
- json_builder_add_double_value (builder, matrix->x0);
- json_builder_add_double_value (builder, matrix->y0);
- json_builder_end_array (builder);
+ gtk_json_printer_start_array (printer, "transform");
+ gtk_json_printer_add_number (printer, NULL, matrix->xx);
+ gtk_json_printer_add_number (printer, NULL, matrix->xy);
+ gtk_json_printer_add_number (printer, NULL, matrix->yx);
+ gtk_json_printer_add_number (printer, NULL, matrix->yy);
+ gtk_json_printer_add_number (printer, NULL, matrix->x0);
+ gtk_json_printer_add_number (printer, NULL, matrix->y0);
+ gtk_json_printer_end (printer);
- json_builder_end_object (builder);
+ gtk_json_printer_end (printer);
}
static void
-add_log_attrs (JsonBuilder *builder,
- PangoLayout *layout)
+add_log_attrs (GtkJsonPrinter *printer,
+ PangoLayout *layout)
{
const PangoLogAttr *log_attrs;
int n_attrs;
- json_builder_set_member_name (builder, "log-attrs");
- json_builder_begin_array (builder);
+ gtk_json_printer_start_array (printer, "log-attrs");
log_attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
for (int i = 0; i < n_attrs; i++)
{
- json_builder_begin_object (builder);
+ gtk_json_printer_start_object (printer, NULL);
if (log_attrs[i].is_line_break)
- {
- json_builder_set_member_name (builder, "line-break");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "line-break", TRUE);
if (log_attrs[i].is_mandatory_break)
- {
- json_builder_set_member_name (builder, "mandatory-break");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "mandatory-break", TRUE);
if (log_attrs[i].is_char_break)
- {
- json_builder_set_member_name (builder, "char-break");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "char-break", TRUE);
if (log_attrs[i].is_white)
- {
- json_builder_set_member_name (builder, "white");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "white", TRUE);
if (log_attrs[i].is_cursor_position)
- {
- json_builder_set_member_name (builder, "cursor-position");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "cursor-position", TRUE);
if (log_attrs[i].is_word_start)
- {
- json_builder_set_member_name (builder, "word-start");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "word-start", TRUE);
if (log_attrs[i].is_word_end)
- {
- json_builder_set_member_name (builder, "word-end");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "word-end", TRUE);
if (log_attrs[i].is_sentence_boundary)
- {
- json_builder_set_member_name (builder, "sentence-boundary");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "sentence-boundary", TRUE);
if (log_attrs[i].is_sentence_start)
- {
- json_builder_set_member_name (builder, "sentence-start");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "sentence-start", TRUE);
if (log_attrs[i].is_sentence_end)
- {
- json_builder_set_member_name (builder, "sentence-end");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "sentence-end", TRUE);
if (log_attrs[i].backspace_deletes_character)
- {
- json_builder_set_member_name (builder, "backspace-deletes-character");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "backspace-deletes-character", TRUE);
if (log_attrs[i].is_expandable_space)
- {
- json_builder_set_member_name (builder, "expandable-space");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "expandable-space", TRUE);
if (log_attrs[i].is_word_boundary)
- {
- json_builder_set_member_name (builder, "word-boundary");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "word-boundary", TRUE);
if (log_attrs[i].break_inserts_hyphen)
- {
- json_builder_set_member_name (builder, "break-inserts-hyphen");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "break-inserts-hyphen", 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);
+ gtk_json_printer_add_boolean (printer, "break-removes-preceding", TRUE);
+ gtk_json_printer_end (printer);
}
- json_builder_end_array (builder);
+ gtk_json_printer_end (printer);
}
static void
-add_font (JsonBuilder *builder,
- PangoFont *font)
+add_font (GtkJsonPrinter *printer,
+ const char *member,
+ PangoFont *font)
{
PangoFontDescription *desc;
char *str;
@@ -400,13 +324,11 @@ add_font (JsonBuilder *builder,
hb_feature_t features[32];
PangoMatrix matrix;
- json_builder_begin_object (builder);
-
- json_builder_set_member_name (builder, "description");
+ gtk_json_printer_start_object (printer, member);
desc = pango_font_describe (font);
str = pango_font_description_to_string (desc);
- json_builder_add_string_value (builder, str);
+ gtk_json_printer_add_string (printer, "description", str);
g_free (str);
pango_font_description_free (desc);
@@ -417,8 +339,7 @@ add_font (JsonBuilder *builder,
data = hb_blob_get_data (blob, &length);
str = g_compute_checksum_for_data (G_CHECKSUM_SHA256, (const guchar *)data, length);
- json_builder_set_member_name (builder, "checksum");
- json_builder_add_string_value (builder, str);
+ gtk_json_printer_add_string (printer, "checksum", str);
g_free (str);
hb_blob_destroy (blob);
@@ -435,55 +356,50 @@ add_font (JsonBuilder *builder,
axes = g_alloca (count * sizeof (hb_ot_var_axis_info_t));
hb_ot_var_get_axis_infos (face, 0, &count, axes);
- json_builder_set_member_name (builder, "variations");
- json_builder_begin_object (builder);
+ gtk_json_printer_start_object (printer, "variations");
for (int i = 0; i < length; i++)
{
char buf[5] = { 0, };
hb_tag_to_string (axes[i].tag, buf);
- json_builder_set_member_name (builder, buf);
- json_builder_add_int_value (builder, coords[i]);
+ gtk_json_printer_add_integer (printer, buf, coords[i]);
}
- json_builder_end_object (builder);
+ gtk_json_printer_end (printer);
}
length = 0;
pango_font_get_features (font, features, G_N_ELEMENTS (features), &length);
if (length > 0)
{
- json_builder_set_member_name (builder, "features");
- json_builder_begin_object (builder);
+ gtk_json_printer_start_object (printer, "features");
for (int i = 0; i < length; i++)
{
char buf[5] = { 0, };
hb_tag_to_string (features[i].tag, buf);
- json_builder_set_member_name (builder, buf);
- json_builder_add_int_value (builder, features[i].value);
+ gtk_json_printer_add_integer (printer, buf, features[i].value);
}
- json_builder_end_object (builder);
+ gtk_json_printer_end (printer);
}
pango_font_get_matrix (font, &matrix);
if (memcmp (&matrix, &(PangoMatrix)PANGO_MATRIX_INIT, sizeof (PangoMatrix)) != 0)
{
- json_builder_set_member_name (builder, "matrix");
- json_builder_begin_array (builder);
- json_builder_add_double_value (builder, matrix.xx);
- json_builder_add_double_value (builder, matrix.xy);
- json_builder_add_double_value (builder, matrix.yx);
- json_builder_add_double_value (builder, matrix.yy);
- json_builder_add_double_value (builder, matrix.x0);
- json_builder_add_double_value (builder, matrix.y0);
- json_builder_end_array (builder);
+ gtk_json_printer_start_array (printer, "matrix");
+ gtk_json_printer_add_number (printer, NULL, matrix.xx);
+ gtk_json_printer_add_number (printer, NULL, matrix.xy);
+ gtk_json_printer_add_number (printer, NULL, matrix.yx);
+ gtk_json_printer_add_number (printer, NULL, matrix.yy);
+ gtk_json_printer_add_number (printer, NULL, matrix.x0);
+ gtk_json_printer_add_number (printer, NULL, matrix.y0);
+ gtk_json_printer_end (printer);
}
- json_builder_end_object (builder);
+ gtk_json_printer_end (printer);
}
#define ANALYSIS_FLAGS (PANGO_ANALYSIS_FLAG_CENTERED_BASELINE | \
@@ -491,998 +407,962 @@ add_font (JsonBuilder *builder,
PANGO_ANALYSIS_FLAG_NEED_HYPHEN)
static void
-add_run (JsonBuilder *builder,
+add_run (GtkJsonPrinter *printer,
PangoLayout *layout,
PangoLayoutRun *run)
{
- json_builder_begin_object (builder);
char *str;
- json_builder_set_member_name (builder, "offset");
- json_builder_add_int_value (builder, run->item->offset);
+ gtk_json_printer_start_object (printer, NULL);
- json_builder_set_member_name (builder, "length");
- json_builder_add_int_value (builder, run->item->length);
+ 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);
- json_builder_set_member_name (builder, "text");
- json_builder_add_string_value (builder, str);
+ gtk_json_printer_add_string (printer, "text", 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);
+ gtk_json_printer_add_integer (printer, "bidi-level", run->item->analysis.level);
+ add_enum_value (printer, "gravity", PANGO_TYPE_GRAVITY, run->item->analysis.gravity, FALSE);
+ gtk_json_printer_add_string (printer, "language", pango_language_to_string (run->item->analysis.language));
+ add_enum_value (printer, "script", PANGO_TYPE_SCRIPT, run->item->analysis.script, FALSE);
- json_builder_set_member_name (builder, "font");
- add_font (builder, run->item->analysis.font);
+ add_font (printer, "font", run->item->analysis.font);
- json_builder_set_member_name (builder, "flags");
- json_builder_add_int_value (builder, run->item->analysis.flags & ANALYSIS_FLAGS);
+ gtk_json_printer_add_integer (printer, "flags", 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);
+ gtk_json_printer_start_array (printer, "extra-attributes");
for (l = run->item->analysis.extra_attrs; l; l = l->next)
{
PangoAttribute *attr = l->data;
- add_attribute (builder, attr);
+ add_attribute (printer, attr);
}
- json_builder_end_array (builder);
+ gtk_json_printer_end (printer);
}
- 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);
+ gtk_json_printer_add_integer (printer, "y-offset", run->y_offset);
+ gtk_json_printer_add_integer (printer, "start-x-offset", run->start_x_offset);
+ gtk_json_printer_add_integer (printer, "end-x-offset", run->end_x_offset);
- json_builder_set_member_name (builder, "glyphs");
- json_builder_begin_array (builder);
+ gtk_json_printer_start_array (printer, "glyphs");
for (int i = 0; i < run->glyphs->num_glyphs; i++)
{
- json_builder_begin_object (builder);
+ gtk_json_printer_start_object (printer, NULL);
- 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);
+ gtk_json_printer_add_integer (printer, "glyph", run->glyphs->glyphs[i].glyph);
+ gtk_json_printer_add_integer (printer, "width", 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);
- }
+ gtk_json_printer_add_integer (printer, "x-offset", 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);
- }
+ gtk_json_printer_add_integer (printer, "y-offset", 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);
- }
+ gtk_json_printer_add_boolean (printer, "is-cluster-start", TRUE);
if (run->glyphs->glyphs[i].attr.is_color)
- {
- json_builder_set_member_name (builder, "is-color");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "is-color", TRUE);
- json_builder_set_member_name (builder, "log-cluster");
- json_builder_add_int_value (builder, run->glyphs->log_clusters[i]);
+ gtk_json_printer_add_integer (printer, "log-cluster", run->glyphs->log_clusters[i]);
- json_builder_end_object (builder);
+ gtk_json_printer_end (printer);
}
- json_builder_end_array (builder);
+ gtk_json_printer_end (printer);
- json_builder_end_object (builder);
+ gtk_json_printer_end (printer);
}
#undef ANALYSIS_FLAGS
static void
-add_line (JsonBuilder *builder,
+add_line (GtkJsonPrinter *printer,
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);
+ gtk_json_printer_start_object (printer, NULL);
- json_builder_set_member_name (builder, "direction");
- add_enum_value (builder, PANGO_TYPE_DIRECTION, line->resolved_dir, FALSE);
+ gtk_json_printer_add_integer (printer, "start-index", line->start_index);
+ gtk_json_printer_add_integer (printer, "length", line->length);
+ gtk_json_printer_add_boolean (printer, "paragraph-start", line->is_paragraph_start);
+ add_enum_value (printer, "direction", PANGO_TYPE_DIRECTION, line->resolved_dir, FALSE);
- json_builder_set_member_name (builder, "runs");
- json_builder_begin_array (builder);
+ gtk_json_printer_start_array (printer, "runs");
for (GSList *l = line->runs; l; l = l->next)
{
PangoLayoutRun *run = l->data;
- add_run (builder, line->layout, run);
+ add_run (printer, line->layout, run);
}
- json_builder_end_array (builder);
+ gtk_json_printer_end (printer);
- json_builder_end_object (builder);
+ gtk_json_printer_end (printer);
}
static void
-add_output (JsonBuilder *builder,
- PangoLayout *layout)
+add_output (GtkJsonPrinter *printer,
+ PangoLayout *layout)
{
int width, height;
- json_builder_begin_object (builder);
+ gtk_json_printer_start_object (printer, "output");
- 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));
-
- json_builder_set_member_name (builder, "unknown-glyphs");
- json_builder_add_int_value (builder, pango_layout_get_unknown_glyphs_count (layout));
+ gtk_json_printer_add_boolean (printer, "is-wrapped", pango_layout_is_wrapped (layout));
+ gtk_json_printer_add_boolean (printer, "is-ellipsized", pango_layout_is_ellipsized (layout));
+ gtk_json_printer_add_integer (printer, "unknown-glyphs", pango_layout_get_unknown_glyphs_count (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);
+ gtk_json_printer_add_integer (printer, "width", width);
+ gtk_json_printer_add_integer (printer, "height", width);
+
+ add_log_attrs (printer, layout);
+ gtk_json_printer_start_array (printer, "lines");
for (GSList *l = layout->lines; l; l = l->next)
{
PangoLayoutLine *line = l->data;
- add_line (builder, line);
+ add_line (printer, line);
}
- json_builder_end_array (builder);
+ gtk_json_printer_end (printer);
- json_builder_end_object (builder);
+ gtk_json_printer_end (printer);
}
-static JsonNode *
-layout_to_json (PangoLayout *layout,
+static void
+layout_to_json (GtkJsonPrinter *printer,
+ PangoLayout *layout,
PangoLayoutSerializeFlags flags)
{
- JsonBuilder *builder;
- JsonNode *root;
const char *str;
- builder = json_builder_new_immutable ();
-
- json_builder_begin_object (builder);
+ gtk_json_printer_start_object (printer, NULL);
if (flags & PANGO_LAYOUT_SERIALIZE_CONTEXT)
- {
- json_builder_set_member_name (builder, "context");
- add_context (builder, layout->context);
- }
+ add_context (printer, layout->context);
str = (const char *) g_object_get_data (G_OBJECT (layout), "comment");
if (str)
- {
- json_builder_set_member_name (builder, "comment");
- if (strstr (str, "\n") != NULL)
- {
- char **strs = g_strsplit (str, "\n", -1);
-
- json_builder_begin_array (builder);
- for (int i = 0; strs[i]; i++)
- json_builder_add_string_value (builder, strs[i]);
- json_builder_end_array (builder);
+ gtk_json_printer_add_string (printer, "comment", str);
- g_strfreev (strs);
- }
- else
- json_builder_add_string_value (builder, str);
- }
+ gtk_json_printer_add_string (printer, "text", layout->text);
- json_builder_set_member_name (builder, "text");
- json_builder_add_string_value (builder, layout->text);
-
- add_attr_list (builder, layout->attrs);
+ add_attr_list (printer, 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);
+ gtk_json_printer_add_string (printer, "font", str);
g_free (str);
}
- add_tab_array (builder, layout->tabs);
+ add_tab_array (printer, layout->tabs);
if (layout->justify)
- {
- json_builder_set_member_name (builder, "justify");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "justify", TRUE);
if (layout->justify_last_line)
- {
- json_builder_set_member_name (builder, "justify-last-line");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "justify-last-line", TRUE);
if (layout->single_paragraph)
- {
- json_builder_set_member_name (builder, "single-paragraph");
- json_builder_add_boolean_value (builder, TRUE);
- }
+ gtk_json_printer_add_boolean (printer, "single-paragraph", TRUE);
if (!layout->auto_dir)
- {
- json_builder_set_member_name (builder, "auto-dir");
- json_builder_add_boolean_value (builder, FALSE);
- }
+ gtk_json_printer_add_boolean (printer, "auto-dir", FALSE);
if (layout->alignment != PANGO_ALIGN_LEFT)
- {
- json_builder_set_member_name (builder, "alignment");
- add_enum_value (builder, PANGO_TYPE_ALIGNMENT, layout->alignment, FALSE);
- }
+ add_enum_value (printer, "alignment", 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);
- }
+ add_enum_value (printer, "wrap", 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);
- }
+ add_enum_value (printer, "ellipsize", 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);
- }
+ gtk_json_printer_add_integer (printer, "width", layout->width);
if (layout->height != -1)
- {
- json_builder_set_member_name (builder, "height");
- json_builder_add_int_value (builder, layout->height);
- }
+ gtk_json_printer_add_integer (printer, "height", layout->height);
if (layout->indent != 0)
- {
- json_builder_set_member_name (builder, "indent");
- json_builder_add_int_value (builder, layout->indent);
- }
+ gtk_json_printer_add_integer (printer, "indent", layout->indent);
if (layout->spacing != 0)
- {
- json_builder_set_member_name (builder, "spacing");
- json_builder_add_int_value (builder, layout->spacing);
- }
+ gtk_json_printer_add_integer (printer, "spacing", layout->spacing);
if (layout->line_spacing != 0.)
- {
- json_builder_set_member_name (builder, "line-spacing");
- json_builder_add_double_value (builder, layout->line_spacing);
- }
+ gtk_json_printer_add_number (printer, "line-spacing", 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);
+ add_output (printer, layout);
- root = json_builder_get_root (builder);
- g_object_unref (builder);
-
- return root;
+ gtk_json_printer_end (printer);
}
-static JsonNode *
-font_to_json (PangoFont *font)
+static void
+gstring_write (GtkJsonPrinter *printer,
+ const char *s,
+ gpointer data)
{
- JsonBuilder *builder;
- JsonNode *root;
-
- builder = json_builder_new_immutable ();
- add_font (builder, font);
- root = json_builder_get_root (builder);
- g_object_unref (builder);
-
- return root;
+ GString *str = data;
+ g_string_append (str, s);
}
/* }}} */
/* {{{ Deserialization */
static int
-get_enum_value (GType type,
- const char *str,
- gboolean allow_extra,
- GError **error)
+parser_get_enum_value (GtkJsonParser *parser,
+ GType type,
+ gboolean allow_extra)
{
GEnumClass *enum_class;
GEnumValue *enum_value;
+ char *str = gtk_json_parser_get_string (parser);
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;
+ {
+ g_free (str);
+ return enum_value->value;
+ }
if (allow_extra)
{
- gint64 value;
+ gint64 v;
char *endp;
- value = g_ascii_strtoll (str, &endp, 10);
+ v = g_ascii_strtoll (str, &endp, 10);
if (*endp == '\0')
- return value;
+ {
+ g_free (str);
+ return (int)v;
+ }
}
- g_set_error (error,
- PANGO_LAYOUT_DESERIALIZE_ERROR,
- PANGO_LAYOUT_DESERIALIZE_INVALID_VALUE,
- "Could not parse enum value of type %s: %s",
- g_type_name (type),
- str);
+ gtk_json_parser_set_error (parser,
+ g_error_new (PANGO_LAYOUT_DESERIALIZE_ERROR,
+ PANGO_LAYOUT_DESERIALIZE_INVALID_VALUE,
+ "Could not parse enum value of type %s: %s",
+ g_type_name (type),
+ str));
+
+ g_free (str);
- return -1;
+ return 0;
}
-static PangoAttribute *
-json_to_attribute (JsonReader *reader,
- GError **error)
+static PangoFontDescription *
+parser_get_font_description (GtkJsonParser *parser)
{
- 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;
- int value;
-
- if (!json_reader_is_object (reader))
- {
- g_set_error (error,
- PANGO_LAYOUT_DESERIALIZE_ERROR,
- PANGO_LAYOUT_DESERIALIZE_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);
+ char *str = gtk_json_parser_get_string (parser);
+ PangoFontDescription *desc = pango_font_description_from_string (str);
+
+ if (!desc)
+ gtk_json_parser_set_error (parser,
+ g_error_new (PANGO_LAYOUT_DESERIALIZE_ERROR,
+ PANGO_LAYOUT_DESERIALIZE_INVALID_VALUE,
+ "Failed to parse font: %s", str));
+ g_free (str);
- if (json_reader_read_member (reader, "end"))
- end = json_reader_get_int_value (reader);
- json_reader_end_member (reader);
+ return desc;
+}
- if (json_reader_read_member (reader, "type"))
- {
- type = get_enum_value (PANGO_TYPE_ATTR_TYPE, json_reader_get_string_value (reader), FALSE, error);
- if (type == -1)
- return NULL;
- }
- else
+static void
+parser_get_color (GtkJsonParser *parser,
+ PangoColor *color)
+{
+ char *str = gtk_json_parser_get_string (parser);
+ if (!pango_color_parse (color, str))
{
- g_set_error (error,
- PANGO_LAYOUT_DESERIALIZE_ERROR,
- PANGO_LAYOUT_DESERIALIZE_MISSING_VALUE,
- "Attribute \"type\" missing");
- return NULL;
+ gtk_json_parser_set_error (parser,
+ g_error_new (PANGO_LAYOUT_DESERIALIZE_ERROR,
+ PANGO_LAYOUT_DESERIALIZE_INVALID_VALUE,
+ "Failed to parse color: %s", str));
+ color->red = color->green = color->blue = 0;
}
- json_reader_end_member (reader);
- if (!json_reader_read_member (reader, "value"))
- {
- g_set_error (error,
- PANGO_LAYOUT_DESERIALIZE_ERROR,
- PANGO_LAYOUT_DESERIALIZE_MISSING_VALUE,
- "Attribute \"value\" missing");
- return NULL;
- }
+ g_free (str);
+}
+
+static PangoAttribute *
+attr_for_type (GtkJsonParser *parser,
+ PangoAttrType type,
+ int start,
+ int end)
+{
+ PangoAttribute *attr;
+ PangoFontDescription *desc;
+ PangoColor color;
+ char *str;
switch (type)
{
default:
- case PANGO_ATTR_INVALID:
g_assert_not_reached ();
+ case PANGO_ATTR_INVALID:
+ gtk_json_parser_set_error (parser,
+ g_error_new (PANGO_LAYOUT_DESERIALIZE_ERROR,
+ PANGO_LAYOUT_DESERIALIZE_MISSING_VALUE,
+ "Missing attribute type"));
+ return NULL;
+
case PANGO_ATTR_LANGUAGE:
- attr = pango_attr_language_new (pango_language_from_string (json_reader_get_string_value (reader)));
+ str = gtk_json_parser_get_string (parser);
+ attr = pango_attr_language_new (pango_language_from_string (str));
+ g_free (str);
break;
+
case PANGO_ATTR_FAMILY:
- attr = pango_attr_family_new (json_reader_get_string_value (reader));
+ str = gtk_json_parser_get_string (parser);
+ attr = pango_attr_family_new (str);
+ g_free (str);
break;
+
case PANGO_ATTR_STYLE:
- value = get_enum_value (PANGO_TYPE_STYLE, json_reader_get_string_value (reader), FALSE, error);
- if (value == -1)
- return NULL;
- attr = pango_attr_style_new ((PangoStyle)value);
+ attr = pango_attr_style_new ((PangoStyle)parser_get_enum_value (parser, PANGO_TYPE_STYLE, FALSE));
break;
+
case PANGO_ATTR_WEIGHT:
- value = get_enum_value (PANGO_TYPE_WEIGHT, json_reader_get_string_value (reader), TRUE, error);
- if (value == -1)
- return NULL;
- attr = pango_attr_weight_new (value);
+ attr = pango_attr_weight_new (parser_get_enum_value (parser, PANGO_TYPE_WEIGHT, TRUE));
break;
+
case PANGO_ATTR_VARIANT:
- value = get_enum_value (PANGO_TYPE_VARIANT, json_reader_get_string_value (reader), FALSE, error);
- if (value == -1)
- return NULL;
- attr = pango_attr_variant_new ((PangoVariant)value);
+ attr = pango_attr_variant_new ((PangoVariant)parser_get_enum_value (parser, PANGO_TYPE_VARIANT, FALSE));
break;
+
case PANGO_ATTR_STRETCH:
- value = get_enum_value (PANGO_TYPE_STRETCH, json_reader_get_string_value (reader), FALSE, error);
- if (value == -1)
- attr = pango_attr_stretch_new ((PangoStretch)value);
+ attr = pango_attr_stretch_new ((PangoStretch)parser_get_enum_value (parser, PANGO_TYPE_STRETCH, FALSE));
break;
+
case PANGO_ATTR_SIZE:
- attr = pango_attr_size_new (json_reader_get_int_value (reader));
+ attr = pango_attr_size_new (gtk_json_parser_get_int (parser));
break;
+
case PANGO_ATTR_FONT_DESC:
- desc = pango_font_description_from_string (json_reader_get_string_value (reader));
+ desc = parser_get_font_description (parser);
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));
+ parser_get_color (parser, &color);
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));
+ parser_get_color (parser, &color);
attr = pango_attr_background_new (color.red, color.green, color.blue);
break;
+
case PANGO_ATTR_UNDERLINE:
- value = get_enum_value (PANGO_TYPE_UNDERLINE, json_reader_get_string_value (reader), FALSE, error);
- if (value == -1)
- return NULL;
- attr = pango_attr_underline_new ((PangoUnderline)value);
+ attr = pango_attr_underline_new ((PangoUnderline)parser_get_enum_value (parser, PANGO_TYPE_UNDERLINE, FALSE));
break;
+
case PANGO_ATTR_STRIKETHROUGH:
- attr = pango_attr_strikethrough_new (json_reader_get_boolean_value (reader));
+ attr = pango_attr_strikethrough_new (gtk_json_parser_get_boolean (parser));
break;
+
case PANGO_ATTR_RISE:
- attr = pango_attr_rise_new (json_reader_get_int_value (reader));
+ attr = pango_attr_rise_new (gtk_json_parser_get_int (parser));
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));
+ attr = pango_attr_scale_new (gtk_json_parser_get_number (parser));
break;
+
case PANGO_ATTR_FALLBACK:
- attr = pango_attr_fallback_new (json_reader_get_boolean_value (reader));
+ attr = pango_attr_fallback_new (gtk_json_parser_get_boolean (parser));
break;
+
case PANGO_ATTR_LETTER_SPACING:
- attr = pango_attr_letter_spacing_new (json_reader_get_int_value (reader));
+ attr = pango_attr_letter_spacing_new (gtk_json_parser_get_int (parser));
break;
+
case PANGO_ATTR_UNDERLINE_COLOR:
- pango_color_parse (&color, json_reader_get_string_value (reader));
+ parser_get_color (parser, &color);
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));
+ parser_get_color (parser, &color);
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));
+ attr = pango_attr_size_new_absolute (gtk_json_parser_get_int (parser));
break;
+
case PANGO_ATTR_GRAVITY:
- value = get_enum_value (PANGO_TYPE_GRAVITY, json_reader_get_string_value (reader), FALSE, error);
- if (value == -1)
- return NULL;
- attr = pango_attr_gravity_new ((PangoGravity)value);
+ attr = pango_attr_gravity_new ((PangoGravity)parser_get_enum_value (parser, PANGO_TYPE_GRAVITY, FALSE));
break;
+
case PANGO_ATTR_GRAVITY_HINT:
- value = get_enum_value (PANGO_TYPE_GRAVITY_HINT, json_reader_get_string_value (reader), FALSE, error);
- if (value == -1)
- return NULL;
- attr = pango_attr_gravity_hint_new ((PangoGravityHint)value);
+ attr = pango_attr_gravity_hint_new ((PangoGravityHint)parser_get_enum_value (parser, PANGO_TYPE_GRAVITY_HINT, FALSE));
break;
+
case PANGO_ATTR_FONT_FEATURES:
- attr = pango_attr_font_features_new (json_reader_get_string_value (reader));
+ str = gtk_json_parser_get_string (parser);
+ attr = pango_attr_font_features_new (str);
+ g_free (str);
break;
+
case PANGO_ATTR_FOREGROUND_ALPHA:
- attr = pango_attr_foreground_alpha_new (json_reader_get_int_value (reader));
+ attr = pango_attr_foreground_alpha_new (gtk_json_parser_get_int (parser));
break;
+
case PANGO_ATTR_BACKGROUND_ALPHA:
- attr = pango_attr_background_alpha_new (json_reader_get_int_value (reader));
+ attr = pango_attr_background_alpha_new (gtk_json_parser_get_int (parser));
break;
+
case PANGO_ATTR_ALLOW_BREAKS:
- attr = pango_attr_allow_breaks_new (json_reader_get_boolean_value (reader));
+ attr = pango_attr_allow_breaks_new (gtk_json_parser_get_boolean (parser));
break;
+
case PANGO_ATTR_SHOW:
- attr = pango_attr_show_new (json_reader_get_int_value (reader));
+ attr = pango_attr_show_new (gtk_json_parser_get_int (parser));
break;
+
case PANGO_ATTR_INSERT_HYPHENS:
- attr = pango_attr_insert_hyphens_new (json_reader_get_boolean_value (reader));
+ attr = pango_attr_insert_hyphens_new (gtk_json_parser_get_int (parser));
break;
+
case PANGO_ATTR_OVERLINE:
- value = get_enum_value (PANGO_TYPE_OVERLINE, json_reader_get_string_value (reader), FALSE, error);
- if (value == -1)
- return NULL;
- attr = pango_attr_overline_new ((PangoOverline)value);
+ attr = pango_attr_overline_new ((PangoOverline)parser_get_enum_value (parser, PANGO_TYPE_OVERLINE, FALSE));
break;
+
case PANGO_ATTR_OVERLINE_COLOR:
- pango_color_parse (&color, json_reader_get_string_value (reader));
+ parser_get_color (parser, &color);
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));
+ attr = pango_attr_line_height_new (gtk_json_parser_get_number (parser));
break;
+
case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT:
- attr = pango_attr_line_height_new_absolute (json_reader_get_int_value (reader));
+ attr = pango_attr_line_height_new_absolute (gtk_json_parser_get_int (parser));
break;
+
case PANGO_ATTR_TEXT_TRANSFORM:
- value = get_enum_value (PANGO_TYPE_TEXT_TRANSFORM, json_reader_get_string_value (reader), FALSE, error);
- if (value == -1)
- return NULL;
- attr = pango_attr_text_transform_new ((PangoTextTransform)value);
+ attr = pango_attr_text_transform_new ((PangoTextTransform)parser_get_enum_value (parser, PANGO_TYPE_TEXT_TRANSFORM, 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:
- value = get_enum_value (PANGO_TYPE_BASELINE_SHIFT, json_reader_get_string_value (reader), TRUE, error);
- if (value == -1)
- return NULL;
- attr = pango_attr_baseline_shift_new (value);
+ attr = pango_attr_baseline_shift_new (parser_get_enum_value (parser, PANGO_TYPE_BASELINE_SHIFT, FALSE));
break;
+
case PANGO_ATTR_FONT_SCALE:
- value = get_enum_value (PANGO_TYPE_FONT_SCALE, json_reader_get_string_value (reader), FALSE, error);
- if (value == -1)
- return NULL;
- attr = pango_attr_font_scale_new ((PangoFontScale)value);
+ attr = pango_attr_font_scale_new ((PangoFontScale)parser_get_enum_value (parser, PANGO_TYPE_FONT_SCALE, 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;
-
- attributes = pango_attr_list_new ();
-
- if (!json_reader_is_array (reader))
- {
- g_set_error (error,
- PANGO_LAYOUT_DESERIALIZE_ERROR,
- PANGO_LAYOUT_DESERIALIZE_INVALID_SYNTAX,
- "\"attributes\" must be a Json array");
- goto fail;
- }
-
- 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;
+enum {
+ ATTR_START,
+ ATTR_END,
+ ATTR_TYPE,
+ ATTR_VALUE
+};
+
+static const char *attr_members[] = {
+ "start",
+ "end",
+ "type",
+ "value",
+ NULL
+};
-fail:
- if (attributes)
- pango_attr_list_unref (attributes);
- return NULL;
-}
-
-static PangoTabArray *
-json_to_tab_array (JsonReader *reader,
- GError **error)
+static PangoAttribute *
+json_to_attribute (GtkJsonParser *parser)
{
- 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);
+ PangoAttribute *attr = NULL;
+ PangoAttrType type = PANGO_ATTR_INVALID;
+ guint start = PANGO_ATTR_INDEX_FROM_TEXT_BEGINNING;
+ guint end = PANGO_ATTR_INDEX_TO_TEXT_END;
- tabs = pango_tab_array_new (0, positions_in_pixels);
+ gtk_json_parser_start_object (parser);
- if (json_reader_read_member (reader, "positions"))
+ do
{
- if (!json_reader_is_array (reader))
+ switch (gtk_json_parser_select_member (parser, attr_members))
{
- g_set_error (error,
- PANGO_LAYOUT_DESERIALIZE_ERROR,
- PANGO_LAYOUT_DESERIALIZE_INVALID_SYNTAX,
- "Tab \"positions\" must be a Json array");
- goto fail;
- }
+ case ATTR_START:
+ start = gtk_json_parser_get_int (parser);
+ break;
- pango_tab_array_resize (tabs, json_reader_count_elements (reader));
- for (int i = 0; i < json_reader_count_elements (reader); i++)
- {
- int pos;
- PangoTabAlign align = PANGO_TAB_LEFT;
- gunichar ch = 0;
+ case ATTR_END:
+ end = gtk_json_parser_get_int (parser);
+ break;
- json_reader_read_element (reader, i);
- if (json_reader_is_object (reader))
- {
- json_reader_read_member (reader, "position");
- pos = json_reader_get_int_value (reader);
- json_reader_end_member (reader);
- json_reader_read_member (reader, "alignment");
-
- align = get_enum_value (PANGO_TYPE_TAB_ALIGN,
- json_reader_get_string_value (reader),
- FALSE,
- error);
- if (align == -1)
- goto fail;
- json_reader_end_member (reader);
- json_reader_read_member (reader, "decimal-point");
- ch = json_reader_get_int_value (reader);
- json_reader_end_member (reader);
- }
- else
- {
- pos = json_reader_get_int_value (reader);
- }
+ case ATTR_TYPE:
+ type = parser_get_enum_value (parser, PANGO_TYPE_ATTR_TYPE, FALSE);
+ break;
- pango_tab_array_set_tab (tabs, i, align, pos);
- pango_tab_array_set_decimal_point (tabs, i, ch);
- json_reader_end_element (reader);
+ case ATTR_VALUE:
+ attr = attr_for_type (parser, type, start, end);
+ break;
+
+ default:
+ break;
}
}
- json_reader_end_member (reader);
+ while (gtk_json_parser_next (parser));
+
+ if (!attr && !gtk_json_parser_get_error (parser))
+ gtk_json_parser_set_error (parser,
+ g_error_new (PANGO_LAYOUT_DESERIALIZE_ERROR,
+ PANGO_LAYOUT_DESERIALIZE_MISSING_VALUE,
+ "Attribute missing \"value\""));
- return tabs;
+ gtk_json_parser_end (parser);
-fail:
- if (tabs)
- pango_tab_array_free (tabs);
- return NULL;
+ return attr;
}
-static gboolean
-apply_json_to_context (JsonReader *reader,
- PangoContext *context,
- GError **error)
+static void
+json_parser_fill_attr_list (GtkJsonParser *parser,
+ PangoAttrList *attributes)
{
- if (json_reader_read_member (reader, "language"))
- {
- const char *value;
- PangoLanguage *language;
-
- value = json_reader_get_string_value (reader);
- language = pango_language_from_string (value);
- pango_context_set_language (context, language);
- }
- json_reader_end_member (reader);
-
- if (json_reader_read_member (reader, "font"))
- {
- PangoFontDescription *desc;
-
- desc = pango_font_description_from_string (json_reader_get_string_value (reader));
- pango_context_set_font_description (context, desc);
- pango_font_description_free (desc);
- }
- json_reader_end_member (reader);
+ gtk_json_parser_start_array (parser);
- if (json_reader_read_member (reader, "base-gravity"))
+ do
{
- PangoGravity gravity = get_enum_value (PANGO_TYPE_GRAVITY,
- json_reader_get_string_value (reader),
- FALSE,
- error);
- if (gravity == -1)
- return FALSE;
-
- pango_context_set_base_gravity (context, gravity);
+ PangoAttribute *attr = json_to_attribute (parser);
+ if (attr)
+ pango_attr_list_insert (attributes, attr);
}
- json_reader_end_member (reader);
+ while (gtk_json_parser_next (parser));
- if (json_reader_read_member (reader, "gravity-hint"))
- {
- PangoGravityHint gravity_hint = get_enum_value (PANGO_TYPE_GRAVITY_HINT,
- json_reader_get_string_value (reader),
- FALSE,
- error);
- if (gravity_hint == -1)
- return FALSE;
-
- pango_context_set_gravity_hint (context, gravity_hint);
- }
- json_reader_end_member (reader);
-
- if (json_reader_read_member (reader, "base-dir"))
- {
- PangoDirection direction = get_enum_value (PANGO_TYPE_DIRECTION,
- json_reader_get_string_value (reader),
- FALSE,
- error);
- if (direction == -1)
- return FALSE;
-
- pango_context_set_base_dir (context, direction);
- }
- json_reader_end_member (reader);
-
- if (json_reader_read_member (reader, "round-glyph-positions"))
- {
- pango_context_set_round_glyph_positions (context, json_reader_get_boolean_value (reader));
- }
- json_reader_end_member (reader);
+ gtk_json_parser_end (parser);
+}
- if (json_reader_read_member (reader, "transform"))
- {
- PangoMatrix m;
-
- json_reader_read_element (reader, 0);
- m.xx = json_reader_get_double_value (reader);
- json_reader_end_element (reader);
- json_reader_read_element (reader, 1);
- m.xy = json_reader_get_double_value (reader);
- json_reader_end_element (reader);
- json_reader_read_element (reader, 2);
- m.yx = json_reader_get_double_value (reader);
- json_reader_end_element (reader);
- json_reader_read_element (reader, 3);
- m.yy = json_reader_get_double_value (reader);
- json_reader_end_element (reader);
- json_reader_read_element (reader, 4);
- m.x0 = json_reader_get_double_value (reader);
- json_reader_end_element (reader);
- json_reader_read_element (reader, 5);
- m.y0 = json_reader_get_double_value (reader);
- json_reader_end_element (reader);
-
- pango_context_set_matrix (context, &m);
- }
- json_reader_end_member (reader);
+enum {
+ TAB_POSITION,
+ TAB_ALIGNMENT,
+ TAB_DECIMAL_POINT
+};
- return TRUE;
-}
+static const char *tab_members[] = {
+ "position",
+ "alignment",
+ "decimal-point",
+ NULL,
+};
-static PangoLayout *
-json_to_layout (PangoContext *context,
- JsonNode *node,
- PangoLayoutDeserializeFlags flags,
- GError **error)
+static void
+json_parser_fill_tabs (GtkJsonParser *parser,
+ PangoTabArray *tabs)
{
- JsonReader *reader;
- PangoLayout *layout;
+ int index;
- reader = json_reader_new (node);
- if (!json_reader_is_object (reader))
- {
- g_set_error (error,
- PANGO_LAYOUT_DESERIALIZE_ERROR,
- PANGO_LAYOUT_DESERIALIZE_INVALID_SYNTAX,
- "Layout must be a Json object");
- goto fail;
- }
+ gtk_json_parser_start_array (parser);
- if (flags & PANGO_LAYOUT_DESERIALIZE_CONTEXT)
+ index = 0;
+ do
{
- if (json_reader_read_member (reader, "context"))
- {
- if (!apply_json_to_context (reader, context, error))
- goto fail;
- }
- json_reader_end_member (reader);
- }
-
- layout = pango_layout_new (context);
+ int pos;
+ PangoTabAlign align = PANGO_TAB_LEFT;
+ gunichar ch = 0;
- if (json_reader_read_member (reader, "comment"))
- {
- if (json_reader_is_array (reader))
+ if (gtk_json_parser_get_node (parser) == GTK_JSON_OBJECT)
{
- GString *s;
-
- s = g_string_new ("");
- for (int i = 0; i < json_reader_count_elements (reader); i++)
+ gtk_json_parser_start_object (parser);
+ do
{
- json_reader_read_element (reader, i);
- if (s->len > 0)
- g_string_append_c (s, '\n');
- g_string_append (s, json_reader_get_string_value (reader));
- json_reader_end_element (reader);
+ switch (gtk_json_parser_select_member (parser, tab_members))
+ {
+ case TAB_POSITION:
+ pos = gtk_json_parser_get_int (parser);
+ break;
+
+ case TAB_ALIGNMENT:
+ align = parser_get_enum_value (parser, PANGO_TYPE_TAB_ALIGN, FALSE);
+ break;
+
+ case TAB_DECIMAL_POINT:
+ ch = gtk_json_parser_get_int (parser);
+ break;
+
+ default:
+ break;
+ }
}
+ while (gtk_json_parser_next (parser));
- g_object_set_data_full (G_OBJECT (layout), "comment",
- g_string_free (s, FALSE),
- g_free);
+ gtk_json_parser_end (parser);
}
else
- g_object_set_data_full (G_OBJECT (layout), "comment",
- g_strdup (json_reader_get_string_value (reader)),
- g_free);
- }
- json_reader_end_member (reader);
+ pos = gtk_json_parser_get_int (parser);
- if (json_reader_read_member (reader, "text"))
- pango_layout_set_text (layout, json_reader_get_string_value (reader), -1);
- json_reader_end_member (reader);
+ pango_tab_array_set_tab (tabs, index, align, pos);
+ pango_tab_array_set_decimal_point (tabs, index, ch);
+ index++;
+ }
+ while (gtk_json_parser_next (parser));
- if (json_reader_read_member (reader, "attributes"))
- {
- PangoAttrList *attributes;
+ gtk_json_parser_end (parser);
+}
- attributes = json_to_attr_list (reader, error);
+enum {
+ TABS_POSITIONS_IN_PIXELS,
+ TABS_POSITIONS
+};
- if (!attributes)
- goto fail;
+static const char *tabs_members[] = {
+ "positions-in-pixels",
+ "positions",
+ NULL
+};
- pango_layout_set_attributes (layout, attributes);
- pango_attr_list_unref (attributes);
- }
- json_reader_end_member (reader);
+static void
+json_parser_fill_tab_array (GtkJsonParser *parser,
+ PangoTabArray *tabs)
+{
+ gtk_json_parser_start_object (parser);
- if (json_reader_read_member (reader, "font"))
+ do
{
- PangoFontDescription *desc;
-
- desc = pango_font_description_from_string ( json_reader_get_string_value (reader));
- if (!desc)
+ switch (gtk_json_parser_select_member (parser, tabs_members))
{
- g_set_error (error,
- PANGO_LAYOUT_DESERIALIZE_ERROR,
- PANGO_LAYOUT_DESERIALIZE_INVALID_VALUE,
- "Could not parse \"%s\" value: %s",
- "font",
- 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);
+ case TABS_POSITIONS_IN_PIXELS:
+ pango_tab_array_set_positions_in_pixels (tabs, gtk_json_parser_get_boolean (parser));
+ break;
- if (json_reader_read_member (reader, "tabs"))
- {
- PangoTabArray *tabs;
-
- tabs = json_to_tab_array (reader, error);
-
- if (!tabs)
- goto fail;
+ case TABS_POSITIONS:
+ json_parser_fill_tabs (parser, tabs);
+ break;
- pango_layout_set_tabs (layout, tabs);
- pango_tab_array_free (tabs);
+ default:
+ break;
+ }
}
- 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);
+ while (gtk_json_parser_next (parser));
- 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);
+ gtk_json_parser_end (parser);
+}
- 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);
+enum {
+ CONTEXT_LANGUAGE,
+ CONTEXT_FONT,
+ CONTEXT_BASE_GRAVITY,
+ CONTEXT_GRAVITY_HINT,
+ CONTEXT_BASE_DIR,
+ CONTEXT_ROUND_GLYPH_POSITIONS,
+ CONTEXT_TRANSFORM,
+};
+
+static const char *context_members[] = {
+ "language",
+ "font",
+ "base-gravity",
+ "gravity-hint",
+ "base-dir",
+ "round-glyph-positions",
+ "transform",
+ NULL,
+};
- 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);
+static void
+json_parser_fill_context (GtkJsonParser *parser,
+ PangoContext *context)
+{
+ gtk_json_parser_start_object (parser);
- if (json_reader_read_member (reader, "alignment"))
+ do
{
- PangoAlignment align = get_enum_value (PANGO_TYPE_ALIGNMENT,
- json_reader_get_string_value (reader),
- FALSE,
- error);
- if (align == -1)
- goto fail;
-
- pango_layout_set_alignment (layout, align);
- }
-
- json_reader_end_member (reader);
+ char *str;
- if (json_reader_read_member (reader, "wrap"))
- {
- PangoWrapMode wrap = get_enum_value (PANGO_TYPE_WRAP_MODE,
- json_reader_get_string_value (reader),
- FALSE,
- error);
+ switch (gtk_json_parser_select_member (parser, context_members))
+ {
+ case CONTEXT_LANGUAGE:
+ str = gtk_json_parser_get_string (parser);
+ PangoLanguage *language = pango_language_from_string (str);
+ pango_context_set_language (context, language);
+ g_free (str);
+ break;
+
+ case CONTEXT_FONT:
+ {
+ PangoFontDescription *desc = parser_get_font_description (parser);
+ pango_context_set_font_description (context, desc);
+ pango_font_description_free (desc);
+ }
+ break;
+
+ case CONTEXT_BASE_GRAVITY:
+ pango_context_set_base_gravity (context, (PangoGravity)parser_get_enum_value (parser, PANGO_TYPE_GRAVITY, FALSE));
+ break;
+
+ case CONTEXT_GRAVITY_HINT:
+ pango_context_set_gravity_hint (context, (PangoGravityHint)parser_get_enum_value (parser, PANGO_TYPE_GRAVITY_HINT, FALSE));
+ break;
+
+ case CONTEXT_BASE_DIR:
+ pango_context_set_base_dir (context, (PangoDirection)parser_get_enum_value (parser, PANGO_TYPE_DIRECTION, FALSE));
+ break;
+
+ case CONTEXT_ROUND_GLYPH_POSITIONS:
+ pango_context_set_round_glyph_positions (context, gtk_json_parser_get_boolean (parser));
+ break;
+
+ case CONTEXT_TRANSFORM:
+ {
+ PangoMatrix m = PANGO_MATRIX_INIT;
+
+ gtk_json_parser_start_array (parser);
+ m.xx = gtk_json_parser_get_number (parser);
+ gtk_json_parser_next (parser);
+ m.xy = gtk_json_parser_get_number (parser);
+ gtk_json_parser_next (parser);
+ m.yx = gtk_json_parser_get_number (parser);
+ gtk_json_parser_next (parser);
+ m.yy = gtk_json_parser_get_number (parser);
+ gtk_json_parser_next (parser);
+ m.x0 = gtk_json_parser_get_number (parser);
+ gtk_json_parser_next (parser);
+ m.y0 = gtk_json_parser_get_number (parser);
+ gtk_json_parser_end (parser);
+
+ pango_context_set_matrix (context, &m);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ while (gtk_json_parser_next (parser));
- if (wrap == -1)
- goto fail;
+ gtk_json_parser_end (parser);
+}
- pango_layout_set_wrap (layout, wrap);
- }
+enum {
+ LAYOUT_CONTEXT,
+ LAYOUT_COMMENT,
+ LAYOUT_TEXT,
+ LAYOUT_ATTRIBUTES,
+ LAYOUT_FONT,
+ LAYOUT_TABS,
+ LAYOUT_JUSTIFY,
+ LAYOUT_JUSTIFY_LAST_LINE,
+ LAYOUT_SINGLE_PARAGRAPH,
+ LAYOUT_AUTO_DIR,
+ LAYOUT_ALIGNMENT,
+ LAYOUT_WRAP,
+ LAYOUT_ELLIPSIZE,
+ LAYOUT_WIDTH,
+ LAYOUT_HEIGHT,
+ LAYOUT_INDENT,
+ LAYOUT_SPACING,
+ LAYOUT_LINE_SPACING,
+ LAYOUT_OUTPUT
+};
+
+static const char *layout_members[] = {
+ "context",
+ "comment",
+ "text",
+ "attributes",
+ "font",
+ "tabs",
+ "justify",
+ "justify-last-line",
+ "single-paragraph",
+ "auto-dir",
+ "alignment",
+ "wrap",
+ "ellipsize",
+ "width",
+ "height",
+ "indent",
+ "spacing",
+ "line-spacing",
+ "output",
+ NULL
+};
- json_reader_end_member (reader);
+static void
+json_parser_fill_layout (GtkJsonParser *parser,
+ PangoLayout *layout,
+ PangoLayoutDeserializeFlags flags)
+{
+ gtk_json_parser_start_object (parser);
- if (json_reader_read_member (reader, "ellipsize"))
+ do
{
- PangoEllipsizeMode ellipsize = get_enum_value (PANGO_TYPE_ELLIPSIZE_MODE,
- json_reader_get_string_value (reader),
- FALSE,
- error);
+ char *str;
- if (ellipsize == -1)
- goto fail;
-
- pango_layout_set_ellipsize (layout, ellipsize);
+ switch (gtk_json_parser_select_member (parser, layout_members))
+ {
+ case LAYOUT_CONTEXT:
+ if (flags & PANGO_LAYOUT_DESERIALIZE_CONTEXT)
+ json_parser_fill_context (parser, pango_layout_get_context (layout));
+ break;
+
+ case LAYOUT_COMMENT:
+ str = gtk_json_parser_get_string (parser);
+ g_object_set_data_full (G_OBJECT (layout), "comment", str, g_free);
+ break;
+
+ case LAYOUT_TEXT:
+ str = gtk_json_parser_get_string (parser);
+ pango_layout_set_text (layout, str, -1);
+ g_free (str);
+ break;
+
+ case LAYOUT_ATTRIBUTES:
+ {
+ PangoAttrList *attributes = pango_attr_list_new ();
+ json_parser_fill_attr_list (parser, attributes);
+ pango_layout_set_attributes (layout, attributes);
+ pango_attr_list_unref (attributes);
+ }
+ break;
+
+ case LAYOUT_FONT:
+ {
+ PangoFontDescription *desc = parser_get_font_description (parser);;
+ pango_layout_set_font_description (layout, desc);
+ pango_font_description_free (desc);
+ }
+ break;
+
+ case LAYOUT_TABS:
+ {
+ PangoTabArray *tabs = pango_tab_array_new (0, FALSE);
+ json_parser_fill_tab_array (parser, tabs);
+ pango_layout_set_tabs (layout, tabs);
+ pango_tab_array_free (tabs);
+ }
+ break;
+
+ case LAYOUT_JUSTIFY:
+ pango_layout_set_justify (layout, gtk_json_parser_get_boolean (parser));
+ break;
+
+ case LAYOUT_JUSTIFY_LAST_LINE:
+ pango_layout_set_justify_last_line (layout, gtk_json_parser_get_boolean (parser));
+ break;
+
+ case LAYOUT_SINGLE_PARAGRAPH:
+ pango_layout_set_single_paragraph_mode (layout, gtk_json_parser_get_boolean (parser));
+ break;
+
+ case LAYOUT_AUTO_DIR:
+ pango_layout_set_auto_dir (layout, gtk_json_parser_get_boolean (parser));
+ break;
+
+ case LAYOUT_ALIGNMENT:
+ pango_layout_set_alignment (layout, (PangoAlignment)parser_get_enum_value (parser, PANGO_TYPE_ALIGNMENT, FALSE));
+ break;
+
+ case LAYOUT_WRAP:
+ pango_layout_set_wrap (layout, (PangoWrapMode)parser_get_enum_value (parser, PANGO_TYPE_WRAP_MODE, FALSE));
+ break;
+
+ case LAYOUT_ELLIPSIZE:
+ pango_layout_set_ellipsize (layout, (PangoEllipsizeMode)parser_get_enum_value (parser, PANGO_TYPE_ELLIPSIZE_MODE, FALSE));
+ break;
+
+ case LAYOUT_WIDTH:
+ pango_layout_set_width (layout, gtk_json_parser_get_int (parser));
+ break;
+
+ case LAYOUT_HEIGHT:
+ pango_layout_set_height (layout, gtk_json_parser_get_int (parser));
+ break;
+
+ case LAYOUT_INDENT:
+ pango_layout_set_indent (layout, gtk_json_parser_get_int (parser));
+ break;
+
+ case LAYOUT_SPACING:
+ pango_layout_set_spacing (layout, gtk_json_parser_get_int (parser));
+ break;
+
+ case LAYOUT_LINE_SPACING:
+ pango_layout_set_line_spacing (layout, gtk_json_parser_get_number (parser));
+ break;
+
+ case LAYOUT_OUTPUT:
+ break;
+
+ default:
+ break;
+ }
}
+ while (gtk_json_parser_next (parser));
- 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);
+ gtk_json_parser_end (parser);
+}
- if (json_reader_read_member (reader, "indent"))
- pango_layout_set_indent (layout, json_reader_get_int_value (reader));
- json_reader_end_member (reader);
+enum {
+ FONT_DESCRIPTION,
+ FONT_CHECKSUM,
+ FONT_VARIATIONS,
+ FONT_FEATURES,
+ FONT_MATRIX
+};
+
+static const char *font_members[] = {
+ "description",
+ "checksum",
+ "variations",
+ "features",
+ "matrix",
+ NULL
+};
+
+static PangoFont *
+json_parser_load_font (GtkJsonParser *parser,
+ PangoContext *context,
+ GError **error)
+{
+ PangoFont *font = NULL;
- if (json_reader_read_member (reader, "spacing"))
- pango_layout_set_spacing (layout, json_reader_get_int_value (reader));
- json_reader_end_member (reader);
+ gtk_json_parser_start_object (parser);
- 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);
+ switch (gtk_json_parser_select_member (parser, font_members))
+ {
+ case FONT_DESCRIPTION:
+ {
+ PangoFontDescription *desc = parser_get_font_description (parser);
+ font = pango_context_load_font (context, desc);
+ pango_font_description_free (desc);
+ }
+ break;
- g_object_unref (reader);
+ default:
+ break;
+ }
- return layout;
+ gtk_json_parser_end (parser);
-fail:
- g_object_unref (reader);
- if (layout)
- g_object_unref (layout);
- return NULL;
+ return font;
}
/* }}} */
@@ -1510,29 +1390,25 @@ GBytes *
pango_layout_serialize (PangoLayout *layout,
PangoLayoutSerializeFlags flags)
{
- JsonGenerator *generator;
- JsonNode *node;
GString *str;
+ GtkJsonPrinter *printer;
char *data;
gsize size;
g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
- node = layout_to_json (layout, flags);
+ str = g_string_new ("");
- generator = json_generator_new ();
- json_generator_set_pretty (generator, TRUE);
- json_generator_set_indent (generator, 2);
+ printer = gtk_json_printer_new (gstring_write, str, NULL);
+ gtk_json_printer_set_flags (printer, GTK_JSON_PRINTER_PRETTY);
+ layout_to_json (printer, layout, flags);
+ gtk_json_printer_free (printer);
+
+ g_string_append_c (str, '\n');
- json_generator_set_root (generator, node);
- str = g_string_new ("");
- g_string_append_c (json_generator_to_gstring (generator, str), '\n');
size = str->len;
data = g_string_free (str, FALSE);
- json_node_free (node);
- g_object_unref (generator);
-
return g_bytes_new_take (data, size);
}
@@ -1590,6 +1466,10 @@ pango_layout_write_to_file (PangoLayout *layout,
*
* 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 `PangoLayout`
*
* Since: 1.50
@@ -1600,26 +1480,23 @@ pango_layout_deserialize (PangoContext *context,
PangoLayoutDeserializeFlags flags,
GError **error)
{
- JsonParser *parser;
- JsonNode *node;
PangoLayout *layout;
+ GtkJsonParser *parser;
g_return_val_if_fail (PANGO_IS_CONTEXT (context), NULL);
- parser = json_parser_new_immutable ();
- if (!json_parser_load_from_data (parser,
- g_bytes_get_data (bytes, NULL),
- g_bytes_get_size (bytes),
- error))
+ layout = pango_layout_new (context);
+
+ parser = gtk_json_parser_new_for_bytes (bytes);
+ json_parser_fill_layout (parser, layout, flags);
+
+ if (gtk_json_parser_get_error (parser))
{
- g_object_unref (parser);
- return NULL;
+ g_propagate_error (error, g_error_copy (gtk_json_parser_get_error (parser)));
+ g_clear_object (&layout);
}
- node = json_parser_get_root (parser);
- layout = json_to_layout (context, node, flags, error);
-
- g_object_unref (parser);
+ gtk_json_parser_free (parser);
return layout;
}
@@ -1643,28 +1520,61 @@ pango_layout_deserialize (PangoContext *context,
GBytes *
pango_font_serialize (PangoFont *font)
{
- JsonGenerator *generator;
- JsonNode *node;
+ GString *str;
+ GtkJsonPrinter *printer;
char *data;
gsize size;
g_return_val_if_fail (PANGO_IS_FONT (font), NULL);
- node = font_to_json (font);
-
- generator = json_generator_new ();
- json_generator_set_pretty (generator, TRUE);
- json_generator_set_indent (generator, 2);
+ str = g_string_new ("");
- json_generator_set_root (generator, node);
- data = json_generator_to_data (generator, &size);
+ printer = gtk_json_printer_new (gstring_write, str, NULL);
+ gtk_json_printer_set_flags (printer, GTK_JSON_PRINTER_PRETTY);
+ add_font (printer, NULL, font);
+ gtk_json_printer_free (printer);
- json_node_free (node);
- g_object_unref (generator);
+ size = str->len;
+ data = g_string_free (str, FALSE);
return g_bytes_new_take (data, size);
}
+/**
+ * pango_font_deserialize:
+ * @context: a `PangoContext`
+ * @bytes: the bytes containing the data
+ * @error: return location for an error
+ *
+ * Loads data previously created via [method@Pango.Font.serialize].
+ *
+ * For a discussion of the supported format, see that function.
+ *
+ * Note: to verify that the returned font is identical to
+ * the one that was serialized, you can compare @bytes to the
+ * result of serializing the font again.
+ *
+ * Returns: (nullable) (transfer full): a new `PangoFont`
+ *
+ * Since: 1.50
+ */
+PangoFont *
+pango_font_deserialize (PangoContext *context,
+ GBytes *bytes,
+ GError **error)
+{
+ PangoFont *font;
+ GtkJsonParser *parser;
+
+ g_return_val_if_fail (PANGO_IS_CONTEXT (context), NULL);
+
+ parser = gtk_json_parser_new_for_bytes (bytes);
+ font = json_parser_load_font (parser, context, error);
+ gtk_json_parser_free (parser);
+
+ return font;
+}
+
/* }}} */
/* vim:set foldmethod=marker expandtab: */
diff --git a/tests/layouts/bratwurst.layout b/tests/layouts/bratwurst.layout
index c31446ac..18a02eca 100644
--- a/tests/layouts/bratwurst.layout
+++ b/tests/layouts/bratwurst.layout
@@ -7,18 +7,15 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
- "comment" : [
- "A case with a single word made up of two items,",
- "expected to produce a single overlong line."
- ],
+ "comment" : "A case with a single word made up of two items,\nexpected to produce a single overlong line.",
"text" : "Bratwurst",
"attributes" : [
{
@@ -34,7 +31,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 202752,
- "height" : 53248,
+ "height" : 202752,
"log-attrs" : [
{
"char-break" : true,
@@ -119,12 +116,12 @@
"wght" : 8374
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -173,12 +170,12 @@
"wght" : 8374
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/bratwurst2.layout b/tests/layouts/bratwurst2.layout
index ffd37cdd..34d83ec8 100644
--- a/tests/layouts/bratwurst2.layout
+++ b/tests/layouts/bratwurst2.layout
@@ -7,18 +7,15 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
- "comment" : [
- "A single word, expected to produce a single",
- "overlong line."
- ],
+ "comment" : "A single word, expected to produce a single\noverlong line.",
"text" : "Bratwurst",
"font" : "Cantarell Bold 32",
"width" : 87040,
@@ -27,7 +24,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 202752,
- "height" : 53248,
+ "height" : 202752,
"log-attrs" : [
{
"char-break" : true,
@@ -112,12 +109,12 @@
"wght" : 8374
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/bratwurst3.layout b/tests/layouts/bratwurst3.layout
index e79ba81c..04914992 100644
--- a/tests/layouts/bratwurst3.layout
+++ b/tests/layouts/bratwurst3.layout
@@ -7,18 +7,15 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
- "comment" : [
- "A single word with word-char wrapping,",
- "expected to be broken to fit the line width."
- ],
+ "comment" : "A single word with word-char wrapping,\nexpected to be broken to fit the line width.",
"text" : "Bratwurst",
"font" : "Cantarell Bold 32",
"wrap" : "word-char",
@@ -28,7 +25,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 78848,
- "height" : 212992,
+ "height" : 78848,
"log-attrs" : [
{
"char-break" : true,
@@ -113,12 +110,12 @@
"wght" : 8374
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 4,
@@ -168,12 +165,12 @@
"wght" : 8374
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 4,
@@ -223,12 +220,12 @@
"wght" : 8374
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 4,
@@ -278,12 +275,12 @@
"wght" : 8374
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/bratwurst4.layout b/tests/layouts/bratwurst4.layout
index f25f1e9e..7b63ab46 100644
--- a/tests/layouts/bratwurst4.layout
+++ b/tests/layouts/bratwurst4.layout
@@ -7,20 +7,15 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
- "comment" : [
- "A single word with a soft hyphen,",
- "expected to be broken at the soft",
- "hyphen and still produce overlong",
- "lines."
- ],
+ "comment" : "A single word with a soft hyphen,\nexpected to be broken at the soft\nhyphen and still produce overlong\nlines.",
"text" : "Brat­wurst",
"font" : "Cantarell Bold 32",
"width" : 87040,
@@ -29,7 +24,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 115712,
- "height" : 106496,
+ "height" : 115712,
"log-attrs" : [
{
"char-break" : true,
@@ -120,12 +115,12 @@
"wght" : 8374
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 4,
@@ -193,12 +188,12 @@
"wght" : 8374
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/effigy.layout b/tests/layouts/effigy.layout
index 73c6ce2d..b5b67d85 100644
--- a/tests/layouts/effigy.layout
+++ b/tests/layouts/effigy.layout
@@ -7,18 +7,15 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
- "comment" : [
- "A ligature that is expected to be borken",
- "to produce two fitting lines."
- ],
+ "comment" : "A ligature that is expected to be borken\nto produce two fitting lines.",
"text" : "effigy",
"font" : "DejaVu Sans 32",
"wrap" : "char",
@@ -29,7 +26,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 73728,
- "height" : 104448,
+ "height" : 73728,
"log-attrs" : [
{
"char-break" : true,
@@ -96,12 +93,12 @@
"description" : "DejaVu Sans 32",
"checksum" : "69ccd07023a72ceb27a5e5c22f728627353b60a198170f5e58dd7014221abf01",
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 4,
@@ -148,12 +145,12 @@
"description" : "DejaVu Sans 32",
"checksum" : "69ccd07023a72ceb27a5e5c22f728627353b60a198170f5e58dd7014221abf01",
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/kebab.layout b/tests/layouts/kebab.layout
index 357fd40d..a54b5c8b 100644
--- a/tests/layouts/kebab.layout
+++ b/tests/layouts/kebab.layout
@@ -7,19 +7,15 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
- "comment" : [
- "Two words, expected to be broken",
- "between words, collapsing the space",
- "and still produce two overlong lines."
- ],
+ "comment" : "Two words, expected to be broken\nbetween words, collapsing the space\nand still produce two overlong lines.",
"text" : "Döner Kebab",
"font" : "Cantarell Bold 32",
"width" : 87040,
@@ -28,7 +24,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 126976,
- "height" : 106496,
+ "height" : 126976,
"log-attrs" : [
{
"char-break" : true,
@@ -128,12 +124,12 @@
"wght" : 8374
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -202,12 +198,12 @@
"wght" : 8374
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/tabs.layout b/tests/layouts/tabs.layout
index deafe91e..ee022a9b 100644
--- a/tests/layouts/tabs.layout
+++ b/tests/layouts/tabs.layout
@@ -6,12 +6,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"text" : "\t0.1\t100.5\tso\tmore\tso\n\t0.02\t20.25\tand\tand\tand\n\t0.003\t1.9\tmore\tso\tmore",
@@ -52,7 +52,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 460800,
- "height" : 73728,
+ "height" : 460800,
"log-attrs" : [
{
"char-break" : true,
@@ -526,12 +526,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -562,12 +562,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -610,12 +610,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -646,12 +646,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -706,12 +706,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -742,12 +742,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -784,12 +784,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -820,12 +820,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -874,12 +874,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -910,12 +910,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -960,12 +960,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -996,12 +996,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1050,12 +1050,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1086,12 +1086,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1146,12 +1146,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1182,12 +1182,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1230,12 +1230,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1266,12 +1266,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1314,12 +1314,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1350,12 +1350,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1406,12 +1406,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1442,12 +1442,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1502,12 +1502,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1538,12 +1538,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1586,12 +1586,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1622,12 +1622,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1676,12 +1676,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1712,12 +1712,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1754,12 +1754,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1790,12 +1790,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-1.layout b/tests/layouts/valid-1.layout
index db84fb5c..8559d572 100644
--- a/tests/layouts/valid-1.layout
+++ b/tests/layouts/valid-1.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"text" : "This is a test of the automatic emergency brake!",
@@ -38,7 +38,7 @@
"is-ellipsized" : true,
"unknown-glyphs" : 0,
"width" : 225280,
- "height" : 19456,
+ "height" : 225280,
"log-attrs" : [
{
"char-break" : true,
@@ -358,12 +358,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -520,12 +520,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -630,12 +630,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 2,
diff --git a/tests/layouts/valid-10.layout b/tests/layouts/valid-10.layout
index 0be9d333..bec277e7 100644
--- a/tests/layouts/valid-10.layout
+++ b/tests/layouts/valid-10.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "Mixed-direction ellipsization",
@@ -26,7 +26,7 @@
"is-ellipsized" : true,
"unknown-glyphs" : 0,
"width" : 102400,
- "height" : 19456,
+ "height" : 102400,
"log-attrs" : [
{
"char-break" : true,
@@ -180,12 +180,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -243,12 +243,12 @@
"description" : "DejaVu Sans 11",
"checksum" : "69ccd07023a72ceb27a5e5c22f728627353b60a198170f5e58dd7014221abf01",
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -297,12 +297,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -333,12 +333,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -369,12 +369,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 2,
diff --git a/tests/layouts/valid-11.layout b/tests/layouts/valid-11.layout
index 63c58ca2..0b8bb870 100644
--- a/tests/layouts/valid-11.layout
+++ b/tests/layouts/valid-11.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"text" : "double low error",
@@ -60,7 +60,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 109568,
- "height" : 20480,
+ "height" : 109568,
"log-attrs" : [
{
"char-break" : true,
@@ -190,12 +190,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -268,12 +268,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -304,12 +304,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -366,12 +366,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -402,12 +402,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-12.layout b/tests/layouts/valid-12.layout
index 44eb064b..099813ce 100644
--- a/tests/layouts/valid-12.layout
+++ b/tests/layouts/valid-12.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "Testing tabs",
@@ -53,7 +53,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 1,
"width" : 202752,
- "height" : 38912,
+ "height" : 202752,
"log-attrs" : [
{
"char-break" : true,
@@ -207,12 +207,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -243,12 +243,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -279,12 +279,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -315,12 +315,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -351,12 +351,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -387,12 +387,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -423,12 +423,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -459,12 +459,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -503,12 +503,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -539,12 +539,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -575,12 +575,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -611,12 +611,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -647,12 +647,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -683,12 +683,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -719,12 +719,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-13.layout b/tests/layouts/valid-13.layout
index 57dad35d..bd0f04fa 100644
--- a/tests/layouts/valid-13.layout
+++ b/tests/layouts/valid-13.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "Tabs in single-paragraph mode",
@@ -54,7 +54,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 1,
"width" : 386048,
- "height" : 19456,
+ "height" : 386048,
"log-attrs" : [
{
"char-break" : true,
@@ -208,12 +208,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -250,12 +250,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -292,12 +292,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -334,12 +334,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -376,12 +376,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -418,12 +418,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -460,12 +460,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -502,12 +502,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -544,12 +544,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -586,12 +586,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -628,12 +628,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -670,12 +670,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -712,12 +712,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -754,12 +754,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -796,12 +796,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-14.layout b/tests/layouts/valid-14.layout
index 70ee954c..ca686814 100644
--- a/tests/layouts/valid-14.layout
+++ b/tests/layouts/valid-14.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"text" : "你好 Hello שלום Γειά σας",
@@ -25,7 +25,7 @@
"is-ellipsized" : true,
"unknown-glyphs" : 1,
"width" : 161792,
- "height" : 20480,
+ "height" : 161792,
"log-attrs" : [
{
"char-break" : true,
@@ -202,12 +202,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 2,
@@ -252,12 +252,12 @@
"description" : "Droid Sans Japanese 11",
"checksum" : "9e7449c453527829c963330ba36f4de3b20911e185a1df08a97082bb69e795d7",
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -294,12 +294,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -357,12 +357,12 @@
"description" : "DejaVu Sans 11",
"checksum" : "69ccd07023a72ceb27a5e5c22f728627353b60a198170f5e58dd7014221abf01",
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -411,12 +411,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -447,12 +447,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-15.layout b/tests/layouts/valid-15.layout
index 6c3b786c..aa65dc84 100644
--- a/tests/layouts/valid-15.layout
+++ b/tests/layouts/valid-15.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "",
@@ -26,7 +26,7 @@
"is-ellipsized" : true,
"unknown-glyphs" : 0,
"width" : 153600,
- "height" : 38912,
+ "height" : 153600,
"log-attrs" : [
{
"char-break" : true,
@@ -654,12 +654,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -842,12 +842,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -992,12 +992,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 2,
diff --git a/tests/layouts/valid-16.layout b/tests/layouts/valid-16.layout
index d8d0d63b..de5338a3 100644
--- a/tests/layouts/valid-16.layout
+++ b/tests/layouts/valid-16.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "",
@@ -27,7 +27,7 @@
"is-ellipsized" : true,
"unknown-glyphs" : 0,
"width" : 153600,
- "height" : 38912,
+ "height" : 153600,
"log-attrs" : [
{
"char-break" : true,
@@ -655,12 +655,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -843,12 +843,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -993,12 +993,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 2,
diff --git a/tests/layouts/valid-17.layout b/tests/layouts/valid-17.layout
index 9660e37d..cc04f0f8 100644
--- a/tests/layouts/valid-17.layout
+++ b/tests/layouts/valid-17.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "Hyphenation point should get replaced with a hyphen",
@@ -25,7 +25,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 96976,
- "height" : 38912,
+ "height" : 96976,
"log-attrs" : [
{
"char-break" : true,
@@ -63,7 +63,7 @@
"word-start" : true,
"backspace-deletes-character" : true,
"break-inserts-hyphen" : true,
- "break-removes_preceding" : true
+ "break-removes-preceding" : true
},
{
"char-break" : true,
@@ -87,7 +87,7 @@
"word-start" : true,
"backspace-deletes-character" : true,
"break-inserts-hyphen" : true,
- "break-removes_preceding" : true
+ "break-removes-preceding" : true
},
{
"char-break" : true,
@@ -111,7 +111,7 @@
"word-start" : true,
"backspace-deletes-character" : true,
"break-inserts-hyphen" : true,
- "break-removes_preceding" : true
+ "break-removes-preceding" : true
},
{
"char-break" : true,
@@ -157,12 +157,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -211,12 +211,12 @@
"description" : "DejaVu Sans 11",
"checksum" : "69ccd07023a72ceb27a5e5c22f728627353b60a198170f5e58dd7014221abf01",
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -248,12 +248,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -296,12 +296,12 @@
"description" : "DejaVu Sans 11",
"checksum" : "69ccd07023a72ceb27a5e5c22f728627353b60a198170f5e58dd7014221abf01",
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -333,12 +333,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -381,12 +381,12 @@
"description" : "DejaVu Sans 11",
"checksum" : "69ccd07023a72ceb27a5e5c22f728627353b60a198170f5e58dd7014221abf01",
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 4,
@@ -426,12 +426,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-18.layout b/tests/layouts/valid-18.layout
index 8c56a7ed..f0a3fd2b 100644
--- a/tests/layouts/valid-18.layout
+++ b/tests/layouts/valid-18.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "Miscellaneous ignorables",
@@ -30,7 +30,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 5,
"width" : 302080,
- "height" : 38912,
+ "height" : 302080,
"log-attrs" : [
{
"char-break" : true,
@@ -345,12 +345,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -478,12 +478,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -529,12 +529,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-19.layout b/tests/layouts/valid-19.layout
index ef6ff650..4f478f67 100644
--- a/tests/layouts/valid-19.layout
+++ b/tests/layouts/valid-19.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "Emoji",
@@ -23,7 +23,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 167936,
- "height" : 19456,
+ "height" : 167936,
"log-attrs" : [
{
"char-break" : true,
@@ -33,7 +33,7 @@
"backspace-deletes-character" : true,
"word-boundary" : true
},
- { },
+ {},
{
"char-break" : true,
"white" : true,
@@ -47,7 +47,7 @@
"cursor-position" : true,
"word-boundary" : true
},
- { },
+ {},
{
"char-break" : true,
"white" : true,
@@ -61,7 +61,7 @@
"cursor-position" : true,
"word-boundary" : true
},
- { },
+ {},
{
"char-break" : true,
"white" : true,
@@ -88,7 +88,7 @@
"cursor-position" : true,
"word-boundary" : true
},
- { },
+ {},
{
"char-break" : true,
"white" : true,
@@ -130,11 +130,11 @@
"cursor-position" : true,
"word-boundary" : true
},
- { },
- { },
- { },
- { },
- { },
+ {},
+ {},
+ {},
+ {},
+ {},
{
"char-break" : true,
"white" : true,
@@ -179,12 +179,12 @@
"description" : "DejaVu Sans 11",
"checksum" : "69ccd07023a72ceb27a5e5c22f728627353b60a198170f5e58dd7014221abf01",
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -225,11 +225,11 @@
"checksum" : "054c1c2e2ca956b920262840dcad39dcf27bb88d6f70b892b2b1180de2c2ab47",
"matrix" : [
0.13455956135321101,
- -0.0,
- -0.0,
+ -0,
+ -0,
0.13455956135321101,
- 0.0,
- 0.0
+ 0,
+ 0
]
},
"flags" : 0,
@@ -267,12 +267,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -301,11 +301,11 @@
"checksum" : "054c1c2e2ca956b920262840dcad39dcf27bb88d6f70b892b2b1180de2c2ab47",
"matrix" : [
0.13455956135321101,
- -0.0,
- -0.0,
+ -0,
+ -0,
0.13455956135321101,
- 0.0,
- 0.0
+ 0,
+ 0
]
},
"flags" : 0,
@@ -337,12 +337,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -371,11 +371,11 @@
"checksum" : "054c1c2e2ca956b920262840dcad39dcf27bb88d6f70b892b2b1180de2c2ab47",
"matrix" : [
0.13455956135321101,
- -0.0,
- -0.0,
+ -0,
+ -0,
0.13455956135321101,
- 0.0,
- 0.0
+ 0,
+ 0
]
},
"flags" : 0,
@@ -407,12 +407,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -441,11 +441,11 @@
"checksum" : "054c1c2e2ca956b920262840dcad39dcf27bb88d6f70b892b2b1180de2c2ab47",
"matrix" : [
0.13455956135321101,
- -0.0,
- -0.0,
+ -0,
+ -0,
0.13455956135321101,
- 0.0,
- 0.0
+ 0,
+ 0
]
},
"flags" : 0,
@@ -477,12 +477,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -535,11 +535,11 @@
"checksum" : "054c1c2e2ca956b920262840dcad39dcf27bb88d6f70b892b2b1180de2c2ab47",
"matrix" : [
0.13455956135321101,
- -0.0,
- -0.0,
+ -0,
+ -0,
0.13455956135321101,
- 0.0,
- 0.0
+ 0,
+ 0
]
},
"flags" : 0,
@@ -583,12 +583,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-2.layout b/tests/layouts/valid-2.layout
index f8f1f865..6d875e3c 100644
--- a/tests/layouts/valid-2.layout
+++ b/tests/layouts/valid-2.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "",
@@ -37,7 +37,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 200704,
- "height" : 19456,
+ "height" : 200704,
"log-attrs" : [
{
"char-break" : true,
@@ -262,12 +262,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -346,12 +346,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -400,12 +400,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -472,12 +472,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -540,12 +540,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-20.layout b/tests/layouts/valid-20.layout
index 7c00d5dc..8217b28b 100644
--- a/tests/layouts/valid-20.layout
+++ b/tests/layouts/valid-20.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "mixed gravity fun",
@@ -41,7 +41,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 79872,
- "height" : 25600,
+ "height" : 79872,
"log-attrs" : [
{
"char-break" : true,
@@ -111,12 +111,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -177,12 +177,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-21.layout b/tests/layouts/valid-21.layout
index 9088c721..7d690bdf 100644
--- a/tests/layouts/valid-21.layout
+++ b/tests/layouts/valid-21.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "Visible and nickless ignorables",
@@ -29,7 +29,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 1,
"width" : 45056,
- "height" : 19456,
+ "height" : 45056,
"log-attrs" : [
{
"char-break" : true,
@@ -39,7 +39,7 @@
"backspace-deletes-character" : true,
"word-boundary" : true
},
- { },
+ {},
{
"char-break" : true,
"white" : true,
@@ -82,11 +82,11 @@
"checksum" : "054c1c2e2ca956b920262840dcad39dcf27bb88d6f70b892b2b1180de2c2ab47",
"matrix" : [
0.13455956135321101,
- -0.0,
- -0.0,
+ -0,
+ -0,
0.13455956135321101,
- 0.0,
- 0.0
+ 0,
+ 0
]
},
"flags" : 0,
@@ -130,12 +130,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-22.layout b/tests/layouts/valid-22.layout
index 4731ac08..1d8f51c4 100644
--- a/tests/layouts/valid-22.layout
+++ b/tests/layouts/valid-22.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "",
@@ -103,7 +103,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 49152,
- "height" : 22658,
+ "height" : 49152,
"log-attrs" : [
{
"char-break" : true,
@@ -206,12 +206,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -242,12 +242,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -292,12 +292,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -346,12 +346,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -396,12 +396,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -458,12 +458,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -532,12 +532,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -618,12 +618,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-3.layout b/tests/layouts/valid-3.layout
index 2f0c4ba5..595dd169 100644
--- a/tests/layouts/valid-3.layout
+++ b/tests/layouts/valid-3.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "Emoji",
@@ -23,7 +23,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 56320,
- "height" : 19456,
+ "height" : 56320,
"log-attrs" : [
{
"char-break" : true,
@@ -51,7 +51,7 @@
"word-end" : true,
"word-boundary" : true
},
- { },
+ {},
{
"line-break" : true,
"char-break" : true,
@@ -93,12 +93,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -139,11 +139,11 @@
"checksum" : "054c1c2e2ca956b920262840dcad39dcf27bb88d6f70b892b2b1180de2c2ab47",
"matrix" : [
0.13455956135321101,
- -0.0,
- -0.0,
+ -0,
+ -0,
0.13455956135321101,
- 0.0,
- 0.0
+ 0,
+ 0
]
},
"flags" : 0,
@@ -181,12 +181,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-4.layout b/tests/layouts/valid-4.layout
index 31c1b44a..2ba19616 100644
--- a/tests/layouts/valid-4.layout
+++ b/tests/layouts/valid-4.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"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!",
@@ -23,7 +23,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 197632,
- "height" : 97280,
+ "height" : 197632,
"log-attrs" : [
{
"char-break" : true,
@@ -898,12 +898,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 4,
@@ -1121,12 +1121,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1345,12 +1345,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 4,
@@ -1562,12 +1562,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1792,12 +1792,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-5.layout b/tests/layouts/valid-5.layout
index 54154347..0810f3f2 100644
--- a/tests/layouts/valid-5.layout
+++ b/tests/layouts/valid-5.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"text" : "A test with multiple paragraphs and with no-break attributes, which might trigger a crash.\nIf it doesn't the fix has worked.",
@@ -31,7 +31,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 194560,
- "height" : 116736,
+ "height" : 194560,
"log-attrs" : [
{
"char-break" : true,
@@ -798,12 +798,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -970,12 +970,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1154,12 +1154,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1380,12 +1380,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1522,12 +1522,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -1710,12 +1710,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-6.layout b/tests/layouts/valid-6.layout
index a1b171cf..0b81c833 100644
--- a/tests/layouts/valid-6.layout
+++ b/tests/layouts/valid-6.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "A keycap sequence",
@@ -23,7 +23,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 142336,
- "height" : 19456,
+ "height" : 142336,
"log-attrs" : [
{
"char-break" : true,
@@ -42,7 +42,7 @@
"sentence-start" : true,
"word-boundary" : true
},
- { },
+ {},
{
"break-inserts-hyphen" : true
},
@@ -185,12 +185,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -219,11 +219,11 @@
"checksum" : "054c1c2e2ca956b920262840dcad39dcf27bb88d6f70b892b2b1180de2c2ab47",
"matrix" : [
0.13455956135321101,
- -0.0,
- -0.0,
+ -0,
+ -0,
0.13455956135321101,
- 0.0,
- 0.0
+ 0,
+ 0
]
},
"flags" : 0,
@@ -255,12 +255,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-7.layout b/tests/layouts/valid-7.layout
index 49b70180..f0c3cba9 100644
--- a/tests/layouts/valid-7.layout
+++ b/tests/layouts/valid-7.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"text" : "This is a test of the automatic emergency brake!",
@@ -39,7 +39,7 @@
"is-ellipsized" : true,
"unknown-glyphs" : 0,
"width" : 153600,
- "height" : 19456,
+ "height" : 153600,
"log-attrs" : [
{
"char-break" : true,
@@ -359,12 +359,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -461,12 +461,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 2,
@@ -504,12 +504,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -566,12 +566,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-8.layout b/tests/layouts/valid-8.layout
index 3e084bea..fdaeee93 100644
--- a/tests/layouts/valid-8.layout
+++ b/tests/layouts/valid-8.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "",
@@ -26,7 +26,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 134144,
- "height" : 19456,
+ "height" : 134144,
"log-attrs" : [
{
"char-break" : true,
@@ -180,12 +180,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -243,12 +243,12 @@
"description" : "DejaVu Sans 11",
"checksum" : "69ccd07023a72ceb27a5e5c22f728627353b60a198170f5e58dd7014221abf01",
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -297,12 +297,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -333,12 +333,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/layouts/valid-9.layout b/tests/layouts/valid-9.layout
index 6e083b58..71a146ff 100644
--- a/tests/layouts/valid-9.layout
+++ b/tests/layouts/valid-9.layout
@@ -7,12 +7,12 @@
"base-dir" : "weak-ltr",
"round-glyph-positions" : true,
"transform" : [
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
]
},
"comment" : "Letterspacing with scripts",
@@ -31,7 +31,7 @@
"is-ellipsized" : false,
"unknown-glyphs" : 0,
"width" : 71392,
- "height" : 77824,
+ "height" : 71392,
"log-attrs" : [
{
"char-break" : true,
@@ -185,12 +185,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -268,12 +268,12 @@
"description" : "DejaVu Sans 11",
"checksum" : "69ccd07023a72ceb27a5e5c22f728627353b60a198170f5e58dd7014221abf01",
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -332,12 +332,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -384,12 +384,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
@@ -463,12 +463,12 @@
"wght" : 0
},
"matrix" : [
- 1.0,
- -0.0,
- -0.0,
- 1.0,
- 0.0,
- 0.0
+ 1,
+ -0,
+ -0,
+ 1,
+ 0,
+ 0
]
},
"flags" : 0,
diff --git a/tests/testserialize.c b/tests/testserialize.c
index 95fb4cd4..e480da31 100644
--- a/tests/testserialize.c
+++ b/tests/testserialize.c
@@ -135,7 +135,10 @@ test_serialize_font (void)
PangoContext *context;
PangoFontDescription *desc;
PangoFont *font;
+ PangoFont *font2;
GBytes *bytes;
+ GBytes *bytes2;
+ GError *error = NULL;
const char *expected =
"{\n"
" \"description\" : \"Cantarell 20 @wght=600\",\n"
@@ -144,12 +147,12 @@ test_serialize_font (void)
" \"wght\" : 5583\n"
" },\n"
" \"matrix\" : [\n"
- " 1.0,\n"
- " -0.0,\n"
- " -0.0,\n"
- " 1.0,\n"
- " 0.0,\n"
- " 0.0\n"
+ " 1,\n"
+ " -0,\n"
+ " -0,\n"
+ " 1,\n"
+ " 0,\n"
+ " 0\n"
" ]\n"
"}";
@@ -159,10 +162,20 @@ test_serialize_font (void)
bytes = pango_font_serialize (font);
g_assert_cmpstr (g_bytes_get_data (bytes, NULL), ==, expected);
- g_bytes_unref (bytes);
+
+ font2 = pango_font_deserialize (context, bytes, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (font2);
+
+ bytes2 = pango_font_serialize (font2);
+ g_assert_true (g_bytes_equal (bytes2, bytes));
g_object_unref (font);
+ g_object_unref (font2);
pango_font_description_free (desc);
+
+ g_bytes_unref (bytes);
+ g_bytes_unref (bytes2);
g_object_unref (context);
}
@@ -183,7 +196,7 @@ test_serialize_layout_minimal (void)
context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
- bytes = g_bytes_new_static (test, -1);
+ bytes = g_bytes_new_static (test, strlen (test) + 1);
layout = pango_layout_deserialize (context, bytes, PANGO_LAYOUT_DESERIALIZE_DEFAULT, &error);
g_assert_no_error (error);
@@ -267,7 +280,7 @@ test_serialize_layout_valid (void)
context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
- bytes = g_bytes_new_static (test, -1);
+ bytes = g_bytes_new_static (test, strlen (test) + 1);
layout = pango_layout_deserialize (context, bytes, PANGO_LAYOUT_DESERIALIZE_DEFAULT, &error);
g_assert_no_error (error);
@@ -286,6 +299,13 @@ test_serialize_layout_valid (void)
out_bytes = pango_layout_serialize (layout, PANGO_LAYOUT_SERIALIZE_DEFAULT);
+ if (strcmp (g_bytes_get_data (out_bytes, NULL), g_bytes_get_data (bytes, NULL)) != 0)
+ {
+ g_print ("expected:\n%s\ngot:\n%s\n",
+ (char *)g_bytes_get_data (bytes, NULL),
+ (char *)g_bytes_get_data (out_bytes, NULL));
+ }
+
g_assert_cmpstr (g_bytes_get_data (out_bytes, NULL), ==, g_bytes_get_data (bytes, NULL));
g_bytes_unref (out_bytes);
@@ -303,7 +323,7 @@ test_serialize_layout_context (void)
" \"context\" : {\n"
" \"base-gravity\" : \"east\",\n"
" \"language\" : \"de-de\",\n"
- " \"round-glyph-positions\" : \"false\"\n"
+ " \"round-glyph-positions\" : false\n"
" },\n"
" \"text\" : \"Some fun with layouts!\"\n"
"}\n";
@@ -315,7 +335,7 @@ test_serialize_layout_context (void)
context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
- bytes = g_bytes_new_static (test, -1);
+ bytes = g_bytes_new_static (test, strlen (test) + 1);
layout = pango_layout_deserialize (context, bytes, PANGO_LAYOUT_DESERIALIZE_CONTEXT, &error);
g_assert_no_error (error);
@@ -381,7 +401,7 @@ test_serialize_layout_invalid (void)
" \"name\" : \"This is wrong\"\n"
" }\n"
"}\n",
- PANGO_LAYOUT_DESERIALIZE_INVALID_SYNTAX
+ 0,
}
};
@@ -395,10 +415,13 @@ test_serialize_layout_invalid (void)
PangoLayout *layout;
GError *error = NULL;
- bytes = g_bytes_new_static (test[i].json, -1);
+ bytes = g_bytes_new_static (test[i].json, strlen (test[i].json) + 1);
layout = pango_layout_deserialize (context, bytes, PANGO_LAYOUT_DESERIALIZE_DEFAULT, &error);
g_assert_null (layout);
- g_assert_error (error, PANGO_LAYOUT_DESERIALIZE_ERROR, test[i].expected_error);
+ if (test[i].expected_error)
+ g_assert_error (error, PANGO_LAYOUT_DESERIALIZE_ERROR, test[i].expected_error);
+ else
+ g_assert_nonnull (error);
g_bytes_unref (bytes);
g_clear_error (&error);
}