summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-11-13 11:01:55 -0500
committerMatthias Clasen <mclasen@redhat.com>2021-11-13 23:34:21 -0500
commit59f6c578f30ee49c8147e718a64bbfae7651a756 (patch)
tree6cf79cd35e12be5738a22974ba2e71a9280c1a03
parentcf06531bc15786a4f2a2292b532733ea41c4fdee (diff)
downloadpango-59f6c578f30ee49c8147e718a64bbfae7651a756.tar.gz
Implement pango_layout_deserialize
-rw-r--r--pango/serializer.c319
1 files changed, 317 insertions, 2 deletions
diff --git a/pango/serializer.c b/pango/serializer.c
index a7747f38..55b17eac 100644
--- a/pango/serializer.c
+++ b/pango/serializer.c
@@ -25,6 +25,13 @@
#include <pango/pango-layout-private.h>
#include <pango/pango-enum-types.h>
+#include "pango/css/gtkcss.h"
+#include "pango/css/gtkcssdataurlprivate.h"
+#include "pango/css/gtkcssparserprivate.h"
+#include "pango/css/gtkcssserializerprivate.h"
+
+/* {{{ Printer */
+
typedef struct
{
int indentation_level;
@@ -118,6 +125,9 @@ out:
g_string_append_c (str, '"');
}
+/* }}} */
+/* {{{ Serialization */
+
static void
append_string_param (Printer *p,
const char *param_name,
@@ -166,7 +176,6 @@ append_enum_param (Printer *p,
}
else
{
-
char *v = g_strdup_printf ("%d", value);
append_simple_string (p, param_name, v);
g_free (v);
@@ -366,6 +375,288 @@ layout_print (Printer *p,
end_node (p);
}
+/* }}} */
+/* {{{ Deserialization */
+
+static PangoContext *parser_context; /* FIXME */
+
+typedef struct
+{
+ const char *name;
+ gboolean (* parse_func) (GtkCssParser *parser, gpointer result);
+ void (* clear_func) (gpointer data);
+ gpointer result;
+} Declaration;
+
+static guint
+parse_declarations (GtkCssParser *parser,
+ const Declaration *declarations,
+ guint n_declarations)
+{
+ guint parsed = 0;
+ guint i;
+
+ g_assert (n_declarations < 8 * sizeof (guint));
+
+ while (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
+ {
+ gtk_css_parser_start_semicolon_block (parser, GTK_CSS_TOKEN_OPEN_CURLY);
+
+ for (i = 0; i < n_declarations; i++)
+ {
+ if (gtk_css_parser_try_ident (parser, declarations[i].name))
+ {
+ if (!gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COLON))
+ {
+ gtk_css_parser_error_syntax (parser, "Expected ':' after variable declaration");
+ }
+ else
+ {
+ if (parsed & (1 << i))
+ {
+ gtk_css_parser_warn_syntax (parser, "Variable \"%s\" defined multiple times", declarations[i].name);
+ /* Unset, just to be sure */
+ parsed &= ~(1 << i);
+ if (declarations[i].clear_func)
+ declarations[i].clear_func (declarations[i].result);
+ }
+ if (!declarations[i].parse_func (parser, declarations[i].result))
+ {
+ /* nothing to do */
+ }
+ else if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
+ {
+ gtk_css_parser_error_syntax (parser, "Expected ';' at end of statement");
+ if (declarations[i].clear_func)
+ declarations[i].clear_func (declarations[i].result);
+ }
+ else
+ {
+ parsed |= (1 << i);
+ }
+ }
+ break;
+ }
+ }
+ if (i == n_declarations)
+ {
+ if (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_IDENT))
+ gtk_css_parser_error_syntax (parser, "No variable named \"%s\"",
+ gtk_css_parser_get_token (parser)->string.string);
+ else
+ gtk_css_parser_error_syntax (parser, "Expected a variable name");
+ }
+
+ gtk_css_parser_end_block (parser);
+ }
+
+ return parsed;
+}
+
+static gboolean
+parse_text (GtkCssParser *parser,
+ gpointer out_data)
+{
+ *(char **) out_data = gtk_css_parser_consume_string (parser);
+ return TRUE;
+}
+
+static gboolean
+parse_font (GtkCssParser *parser,
+ gpointer out_data)
+{
+ char *string;
+ PangoFontDescription *desc;
+
+ string = gtk_css_parser_consume_string (parser);
+ desc = pango_font_description_from_string (string);
+ g_free (string);
+
+ *(PangoFontDescription **) out_data = desc;
+
+ return desc != NULL;
+}
+
+static gboolean
+parse_enum_value (GtkCssParser *parser,
+ GType enum_type,
+ gpointer out_data)
+{
+ char *string;
+ GEnumClass *enum_class;
+ GEnumValue *enum_value;
+
+ string = gtk_css_parser_consume_ident (parser);
+ enum_class = g_type_class_ref (enum_type);
+ enum_value = g_enum_get_value_by_nick (enum_class, string);
+ g_type_class_unref (enum_class);
+ g_free (string);
+
+ if (enum_value)
+ *(int *) out_data = enum_value->value;
+
+ return enum_value != NULL;
+}
+
+static gboolean
+parse_alignment (GtkCssParser *parser,
+ gpointer out_data)
+{
+ return parse_enum_value (parser, PANGO_TYPE_ALIGNMENT, out_data);
+}
+
+static gboolean
+parse_wrap (GtkCssParser *parser,
+ gpointer out_data)
+{
+ return parse_enum_value (parser, PANGO_TYPE_WRAP_MODE, out_data);
+}
+
+static gboolean
+parse_ellipsize (GtkCssParser *parser,
+ gpointer out_data)
+{
+ return parse_enum_value (parser, PANGO_TYPE_ELLIPSIZE_MODE, out_data);
+}
+
+static gboolean
+parse_boolean (GtkCssParser *parser,
+ gpointer out_data)
+{
+ if (gtk_css_parser_try_ident (parser, "true"))
+ *(gboolean *) out_data = TRUE;
+ else if (gtk_css_parser_try_ident (parser, "false"))
+ *(gboolean *) out_data = FALSE;
+ else
+ return FALSE;
+ return TRUE;
+}
+
+static gboolean
+parse_int (GtkCssParser *parser,
+ gpointer out_data)
+{
+ return gtk_css_parser_consume_integer (parser, (int *)out_data);
+}
+
+static gboolean
+parse_double (GtkCssParser *parser,
+ gpointer out_data)
+{
+ return gtk_css_parser_consume_number (parser, (double *)out_data);
+}
+
+static PangoLayout *
+parse_layout (GtkCssParser *parser)
+{
+ char *text = NULL;
+ PangoAttrList *attrs = NULL;
+ PangoFontDescription *desc = NULL;
+ PangoTabArray *tabs = NULL;
+ gboolean justify = FALSE;
+ gboolean justify_last_line = FALSE;
+ gboolean single_paragraph = FALSE;
+ gboolean auto_dir = TRUE;
+ PangoAlignment align = PANGO_ALIGN_LEFT;
+ PangoWrapMode wrap = PANGO_WRAP_WORD;
+ PangoEllipsizeMode ellipsize = PANGO_ELLIPSIZE_NONE;
+ int width = -1;
+ int height = -1;
+ int indent = 0;
+ int spacing = 0;
+ double line_spacing = 0.;
+ const Declaration declarations[] = {
+ { "text", parse_text, g_free, &text },
+ { "font", parse_font, (GDestroyNotify)pango_font_description_free, &desc },
+ { "alignment", parse_alignment, NULL, &align },
+ { "wrap", parse_wrap, NULL, &wrap },
+ { "ellipsize", parse_ellipsize, NULL, &ellipsize },
+ { "justify", parse_boolean, NULL, &justify },
+ { "justify-last-line", parse_boolean, NULL, &justify_last_line },
+ { "single-paragraph", parse_boolean, NULL, &single_paragraph },
+ { "auto-dir", parse_boolean, NULL, &auto_dir },
+ { "width", parse_int, NULL, &width },
+ { "height", parse_int, NULL, &height },
+ { "indent", parse_int, NULL, &indent },
+ { "spacing", parse_int, NULL, &spacing },
+ { "line-spacing", parse_double, NULL, &line_spacing },
+ };
+ PangoLayout *layout;
+
+ parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
+
+ layout = pango_layout_new (parser_context);
+
+ if (text)
+ {
+ pango_layout_set_text (layout, text, -1);
+ g_free (text);
+ }
+ if (attrs)
+ {
+ pango_layout_set_attributes (layout, attrs);
+ pango_attr_list_unref (attrs);
+ }
+ if (desc)
+ {
+ pango_layout_set_font_description (layout, desc);
+ pango_font_description_free (desc);
+ }
+ if (tabs)
+ {
+ pango_layout_set_tabs (layout, tabs);
+ pango_tab_array_free (tabs);
+ }
+
+ pango_layout_set_justify (layout, justify);
+ pango_layout_set_justify_last_line (layout, justify_last_line);
+ pango_layout_set_single_paragraph_mode (layout, single_paragraph);
+ pango_layout_set_auto_dir (layout, auto_dir);
+ pango_layout_set_alignment (layout, align);
+ pango_layout_set_wrap (layout, wrap);
+ pango_layout_set_ellipsize (layout,ellipsize);
+ pango_layout_set_width (layout, width);
+ pango_layout_set_height (layout, height);
+ pango_layout_set_indent (layout, indent);
+ pango_layout_set_spacing (layout, spacing);
+ pango_layout_set_line_spacing (layout, line_spacing);
+
+ return layout;
+}
+
+static PangoLayout *
+parse_toplevel_layout (GtkCssParser *parser)
+{
+ PangoLayout *layout = NULL;
+
+ gtk_css_parser_start_semicolon_block (parser, GTK_CSS_TOKEN_OPEN_CURLY);
+
+ if (gtk_css_parser_try_ident (parser, "layout"))
+ {
+
+ if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
+ {
+ gtk_css_parser_error_syntax (parser, "Expected '{' after node name");
+ return FALSE;
+ }
+
+ gtk_css_parser_end_block_prelude (parser);
+
+ layout = parse_layout (parser);
+
+ if (layout)
+ {
+ if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
+ gtk_css_parser_error_syntax (parser, "Expected '}' at end of node definition");
+ }
+ }
+
+ gtk_css_parser_end_block (parser);
+
+ return layout;
+}
+
+/* }}} */
/* {{{ Public API */
/**
@@ -396,6 +687,19 @@ pango_layout_serialize (PangoLayout *layout)
return g_string_free_to_bytes (p.str);
}
+static void
+parser_error (GtkCssParser *parser,
+ const GtkCssLocation *start,
+ const GtkCssLocation *end,
+ const GError *error,
+ gpointer user_data)
+{
+ g_print ("from line %ld:%ld to %ld:%ld: %s\n",
+ start->lines, start->line_chars,
+ end->lines, end->line_chars,
+ error->message);
+}
+
/**
* pango_layout_deserialize:
* @context: a `PangoContext`
@@ -413,7 +717,18 @@ PangoLayout *
pango_layout_deserialize (PangoContext *context,
GBytes *bytes)
{
- return NULL;
+ PangoLayout *layout = NULL;
+ GtkCssParser *parser;
+
+ parser = gtk_css_parser_new_for_bytes (bytes, NULL, parser_error, NULL, NULL);
+
+ parser_context = context;
+ layout = parse_toplevel_layout (parser);
+ parser_context = NULL;
+
+ gtk_css_parser_unref (parser);
+
+ return layout;
}
/* }}} */