[pango/serializer: 7/14] Implement pango_layout_deserialize




commit 59f6c578f30ee49c8147e718a64bbfae7651a756
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Nov 13 11:01:55 2021 -0500

    Implement pango_layout_deserialize

 pango/serializer.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file 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;
 }
 
 /* }}} */


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