summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2020-12-29 02:37:06 -0500
committerMatthias Clasen <mclasen@redhat.com>2020-12-29 10:14:32 -0500
commit7515715fe4ce9407c6022b167c4c95565e5de85b (patch)
tree3cc43de546bcf64eb4419a4fab73e2e3370ab167
parent43d9fe9320c25c07a859cded02d245be4260e630 (diff)
downloadgtk+-wip/ottie/print.tar.gz
ottie: Support text layerswip/ottie/print
Add basic support for text layers. We are parsing the toplevel "fonts" and "chars", and support static text.
-rw-r--r--ottie/meson.build4
-rw-r--r--ottie/ottiechar.c86
-rw-r--r--ottie/ottiecharprivate.h55
-rw-r--r--ottie/ottiecolorvalue.c29
-rw-r--r--ottie/ottiecomposition.c11
-rw-r--r--ottie/ottiecompositionlayer.c4
-rw-r--r--ottie/ottiecreation.c186
-rw-r--r--ottie/ottiefont.c43
-rw-r--r--ottie/ottiefontprivate.h43
-rw-r--r--ottie/ottielayer.c10
-rw-r--r--ottie/ottielayerprivate.h8
-rw-r--r--ottie/ottieparser.c64
-rw-r--r--ottie/ottieparserprivate.h13
-rw-r--r--ottie/ottiepathshapeprivate.h2
-rw-r--r--ottie/ottierender.c13
-rw-r--r--ottie/ottierenderprivate.h3
-rw-r--r--ottie/ottietextlayer.c295
-rw-r--r--ottie/ottietextvalue.c194
-rw-r--r--ottie/ottietextvalueprivate.h80
19 files changed, 1102 insertions, 41 deletions
diff --git a/ottie/meson.build b/ottie/meson.build
index 9c91630b4c..8dc624e793 100644
--- a/ottie/meson.build
+++ b/ottie/meson.build
@@ -26,9 +26,13 @@ ottie_private_sources = files([
'ottieshape.c',
'ottieshapelayer.c',
'ottiestrokeshape.c',
+ 'ottietextlayer.c',
+ 'ottietextvalue.c',
'ottietransform.c',
'ottietrimshape.c',
'ottieprinter.c',
+ 'ottiefont.c',
+ 'ottiechar.c',
])
ottie_public_headers = files([
diff --git a/ottie/ottiechar.c b/ottie/ottiechar.c
new file mode 100644
index 0000000000..f2e802c0ba
--- /dev/null
+++ b/ottie/ottiechar.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * 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: Matthias Clasen
+ */
+
+#include "ottiecharprivate.h"
+
+static void
+ottie_char_key_clear (OttieCharKey *key)
+{
+ g_free (key->ch);
+ g_free (key->family);
+ g_free (key->style);
+}
+
+void
+ottie_char_key_free (OttieCharKey *key)
+{
+ ottie_char_key_clear (key);
+ g_free (key);
+}
+
+guint
+ottie_char_key_hash (const OttieCharKey *key)
+{
+ guint res = 0;
+
+ res = 31 * res + g_str_hash (key->ch);
+ res = 31 * res + g_str_hash (key->family);
+ res = 31 * res + g_str_hash (key->style);
+
+ return res;
+}
+
+gboolean
+ottie_char_key_equal (const OttieCharKey *key1,
+ const OttieCharKey *key2)
+{
+ return strcmp (key1->ch, key2->ch) == 0 &&
+ strcmp (key1->family, key2->family) == 0 &&
+ strcmp (key1->style, key2->style) == 0;
+}
+
+OttieChar *
+ottie_char_copy (OttieChar *ch)
+{
+ OttieChar *c;
+
+ c = g_new0 (OttieChar, 1);
+ c->key.ch = g_strdup (ch->key.ch);
+ c->key.family = g_strdup (ch->key.family);
+ c->key.style = g_strdup (ch->key.style);
+ c->size = ch->size;
+ c->width = ch->width;
+ c->shapes = g_object_ref (ch->shapes);
+
+ return c;
+}
+
+void
+ottie_char_clear (OttieChar *ch)
+{
+ ottie_char_key_clear (&ch->key);
+ g_object_unref (ch->shapes);
+}
+
+void
+ottie_char_free (OttieChar *ch)
+{
+ ottie_char_clear (ch);
+ g_free (ch);
+}
diff --git a/ottie/ottiecharprivate.h b/ottie/ottiecharprivate.h
new file mode 100644
index 0000000000..0551c56065
--- /dev/null
+++ b/ottie/ottiecharprivate.h
@@ -0,0 +1,55 @@
+
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * 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: Matthias Clasen
+ */
+
+#ifndef __OTTIE_CHAR_PRIVATE_H__
+#define __OTTIE_CHAR_PRIVATE_H__
+
+#include <glib.h>
+
+#include "ottieshapeprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+ char *ch;
+ char *family;
+ char *style;
+} OttieCharKey;
+
+typedef struct
+{
+ OttieCharKey key;
+ double size;
+ double width;
+ OttieShape *shapes;
+} OttieChar;
+
+void ottie_char_key_free (OttieCharKey *key);
+guint ottie_char_key_hash (const OttieCharKey *key);
+gboolean ottie_char_key_equal (const OttieCharKey *key1,
+ const OttieCharKey *key2);
+OttieChar * ottie_char_copy (OttieChar *ch);
+void ottie_char_clear (OttieChar *ch);
+void ottie_char_free (OttieChar *ch);
+
+G_END_DECLS
+
+#endif /* __OTTIE_CHAR_PRIVATE_H__ */
diff --git a/ottie/ottiecolorvalue.c b/ottie/ottiecolorvalue.c
index 72cfa4c808..01f51b7fbf 100644
--- a/ottie/ottiecolorvalue.c
+++ b/ottie/ottiecolorvalue.c
@@ -26,31 +26,6 @@
#include <glib/gi18n-lib.h>
-static gboolean
-ottie_color_value_parse_one (JsonReader *reader,
- gsize offset,
- gpointer data)
-{
- GdkRGBA *rgba = (GdkRGBA *) ((guint8 *) data + offset);
- double d[3];
-
- if (!ottie_parser_parse_array (reader, "color value",
- 3, 3, NULL,
- 0, sizeof (double),
- ottie_parser_option_double,
- d))
- {
- d[0] = d[1] = d[2] = 0;
- }
-
- rgba->red = d[0];
- rgba->green = d[1];
- rgba->blue = d[2];
- rgba->alpha = 1;
-
- return TRUE;
-}
-
static void
ottie_color_value_interpolate (const GdkRGBA *start,
const GdkRGBA *end,
@@ -68,7 +43,7 @@ ottie_color_value_interpolate (const GdkRGBA *start,
#define OTTIE_KEYFRAMES_ELEMENT_TYPE GdkRGBA
#define OTTIE_KEYFRAMES_BY_VALUE 1
#define OTTIE_KEYFRAMES_DIMENSIONS 4
-#define OTTIE_KEYFRAMES_PARSE_FUNC ottie_color_value_parse_one
+#define OTTIE_KEYFRAMES_PARSE_FUNC ottie_parser_option_color
#define OTTIE_KEYFRAMES_INTERPOLATE_FUNC ottie_color_value_interpolate
#define OTTIE_KEYFRAMES_PRINT_FUNC ottie_printer_add_color
#include "ottiekeyframesimpl.c"
@@ -127,7 +102,7 @@ ottie_color_value_parse (JsonReader *reader,
if (is_static)
{
self->is_static = TRUE;
- ottie_color_value_parse_one (reader, 0, &self->static_value);
+ ottie_parser_option_color (reader, 0, &self->static_value);
}
else
{
diff --git a/ottie/ottiecomposition.c b/ottie/ottiecomposition.c
index 7f30bad018..d3b4111020 100644
--- a/ottie/ottiecomposition.c
+++ b/ottie/ottiecomposition.c
@@ -25,6 +25,7 @@
#include "ottiecompositionlayerprivate.h"
#include "ottienulllayerprivate.h"
#include "ottieshapelayerprivate.h"
+#include "ottietextlayerprivate.h"
#include <glib/gi18n-lib.h>
#include <gsk/gsk.h>
@@ -98,13 +99,15 @@ G_DEFINE_TYPE_WITH_CODE (OttieComposition, ottie_composition, OTTIE_TYPE_LAYER,
static void
ottie_composition_update (OttieLayer *layer,
- GHashTable *compositions)
+ GHashTable *compositions,
+ GHashTable *fonts,
+ GHashTable *chars)
{
OttieComposition *self = OTTIE_COMPOSITION (layer);
for (gsize i = ottie_layer_list_get_size (&self->layers); i-- > 0; )
{
- ottie_layer_update (ottie_layer_list_get (&self->layers, i), compositions);
+ ottie_layer_update (ottie_layer_list_get (&self->layers, i), compositions, fonts, chars);
}
}
@@ -236,6 +239,10 @@ ottie_composition_parse_layer (JsonReader *reader,
layer = ottie_shape_layer_parse (reader);
break;
+ case 5:
+ layer = ottie_text_layer_parse (reader);
+ break;
+
default:
ottie_parser_error_value (reader, "Layer %zu has unknown type %d",
ottie_layer_list_get_size (&self->layers),
diff --git a/ottie/ottiecompositionlayer.c b/ottie/ottiecompositionlayer.c
index 034374e531..adc9b96618 100644
--- a/ottie/ottiecompositionlayer.c
+++ b/ottie/ottiecompositionlayer.c
@@ -46,7 +46,9 @@ G_DEFINE_TYPE (OttieCompositionLayer, ottie_composition_layer, OTTIE_TYPE_LAYER)
static void
ottie_composition_layer_update (OttieLayer *layer,
- GHashTable *compositions)
+ GHashTable *compositions,
+ GHashTable *fonts,
+ GHashTable *chars)
{
OttieCompositionLayer *self = OTTIE_COMPOSITION_LAYER (layer);
diff --git a/ottie/ottiecreation.c b/ottie/ottiecreation.c
index d48182da19..6ceff8ee1c 100644
--- a/ottie/ottiecreation.c
+++ b/ottie/ottiecreation.c
@@ -25,6 +25,9 @@
#include "ottieparserprivate.h"
#include "ottiecompositionprivate.h"
#include "ottieprinterprivate.h"
+#include "ottiegroupshapeprivate.h"
+#include "ottiefontprivate.h"
+#include "ottiecharprivate.h"
#include <glib/gi18n-lib.h>
#include <json-glib/json-glib.h>
@@ -56,6 +59,8 @@ struct _OttieCreation
OttieComposition *layers;
GHashTable *composition_assets;
+ GHashTable *fonts;
+ GHashTable *chars;
GCancellable *cancellable;
};
@@ -164,6 +169,8 @@ ottie_creation_reset (OttieCreation *self)
{
g_clear_object (&self->layers);
g_hash_table_remove_all (self->composition_assets);
+ g_hash_table_remove_all (self->fonts);
+ g_hash_table_remove_all (self->chars);
g_clear_pointer (&self->name, g_free);
self->frame_rate = 0;
@@ -190,6 +197,8 @@ ottie_creation_finalize (GObject *object)
OttieCreation *self = OTTIE_CREATION (object);
g_hash_table_unref (self->composition_assets);
+ g_hash_table_unref (self->fonts);
+ g_hash_table_unref (self->chars);
G_OBJECT_CLASS (ottie_creation_parent_class)->finalize (object);
}
@@ -307,6 +316,11 @@ static void
ottie_creation_init (OttieCreation *self)
{
self->composition_assets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ self->fonts = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify)ottie_font_free);
+ self->chars = g_hash_table_new_full ((GHashFunc)ottie_char_key_hash,
+ (GEqualFunc)ottie_char_key_equal,
+ NULL, (GDestroyNotify)ottie_char_free);
}
/**
@@ -436,6 +450,130 @@ ottie_creation_parse_markers (JsonReader *reader,
}
static gboolean
+ottie_creation_parse_font (JsonReader *reader,
+ gsize offset,
+ gpointer data)
+{
+ OttieParserOption options[] = {
+ { "fName", ottie_parser_option_string, G_STRUCT_OFFSET (OttieFont, name) },
+ { "fFamily", ottie_parser_option_string, G_STRUCT_OFFSET (OttieFont, family) },
+ { "fStyle", ottie_parser_option_string, G_STRUCT_OFFSET (OttieFont, style) },
+ { "ascent", ottie_parser_option_double, G_STRUCT_OFFSET (OttieFont, ascent) },
+ };
+ OttieCreation *self = data;
+ OttieFont font = { };
+ gboolean result;
+
+ result = ottie_parser_parse_object (reader, "font", options, G_N_ELEMENTS (options), &font);
+
+ if (result)
+ {
+ if (font.name == NULL)
+ ottie_parser_error_syntax (reader, "No name given to font");
+ else if (g_hash_table_contains (self->fonts, font.name))
+ ottie_parser_error_syntax (reader, "Duplicate font name: %s", font.name);
+ else
+ g_hash_table_insert (self->fonts, g_strdup (font.name), ottie_font_copy (&font));
+ }
+
+ g_clear_pointer (&font.name, g_free);
+ g_clear_pointer (&font.family, g_free);
+ g_clear_pointer (&font.style, g_free);
+
+ return result;
+}
+
+static gboolean
+ottie_creation_parse_font_list (JsonReader *reader,
+ gsize offset,
+ gpointer data)
+{
+ return ottie_parser_parse_array (reader, "assets",
+ 0, G_MAXUINT, NULL,
+ offset, 0,
+ ottie_creation_parse_font,
+ data);
+}
+
+static gboolean
+ottie_creation_parse_fonts (JsonReader *reader,
+ gsize offset,
+ gpointer data)
+{
+ OttieParserOption options[] = {
+ { "list", ottie_creation_parse_font_list, 0 }
+ };
+
+ return ottie_parser_parse_object (reader, "fonts",
+ options, G_N_ELEMENTS (options),
+ data);
+}
+
+static gboolean
+ottie_creation_parse_char_data (JsonReader *reader,
+ gsize offset,
+ gpointer data)
+{
+ OttieParserOption options[] = {
+ { "shapes", ottie_group_shape_parse_shapes, 0 }
+ };
+ OttieChar *ch = data;
+
+ ch->shapes = ottie_group_shape_new ();
+
+ return ottie_parser_parse_object (reader, "char data",
+ options, G_N_ELEMENTS (options),
+ ch->shapes);
+}
+
+static gboolean
+ottie_creation_parse_char (JsonReader *reader,
+ gsize offset,
+ gpointer data)
+{
+ OttieParserOption options[] = {
+ { "ch", ottie_parser_option_string, G_STRUCT_OFFSET (OttieCharKey, ch) },
+ { "fFamily", ottie_parser_option_string, G_STRUCT_OFFSET (OttieCharKey, family) },
+ { "style", ottie_parser_option_string, G_STRUCT_OFFSET (OttieCharKey, style) },
+ { "size", ottie_parser_option_double, G_STRUCT_OFFSET (OttieChar, size) },
+ { "w", ottie_parser_option_double, G_STRUCT_OFFSET (OttieChar, width) },
+ { "data", ottie_creation_parse_char_data, G_STRUCT_OFFSET (OttieChar, shapes) },
+ };
+ OttieCreation *self = data;
+ OttieChar ch = { };
+ gboolean result;
+
+ result = ottie_parser_parse_object (reader, "char", options, G_N_ELEMENTS (options), &ch);
+
+ if (result)
+ {
+ if (ch.key.ch == NULL)
+ ottie_parser_error_syntax (reader, "Char without \"ch\"");
+ else if (ch.shapes == NULL)
+ ottie_parser_error_syntax (reader, "Char without \"data\"");
+ else if (g_hash_table_contains (self->chars, &ch))
+ ottie_parser_error_syntax (reader, "Duplicate char: %s/%s/%s", ch.key.ch, ch.key.family, ch.key.style);
+ else
+ g_hash_table_add (self->chars, ottie_char_copy (&ch));
+ }
+
+ ottie_char_clear (&ch);
+
+ return result;
+}
+static gboolean
+ottie_creation_parse_chars (JsonReader *reader,
+ gsize offset,
+ gpointer data)
+{
+ return ottie_parser_parse_array (reader, "chars",
+ 0, G_MAXUINT, NULL,
+ offset, 0,
+ ottie_creation_parse_char,
+ data);
+}
+
+static gboolean
ottie_creation_load_from_reader (OttieCreation *self,
JsonReader *reader)
{
@@ -451,6 +589,8 @@ ottie_creation_load_from_reader (OttieCreation *self,
{ "layers", ottie_composition_parse_layers, G_STRUCT_OFFSET (OttieCreation, layers) },
{ "assets", ottie_creation_parse_assets, 0 },
{ "markers", ottie_creation_parse_markers, 0 },
+ { "fonts", ottie_creation_parse_fonts, 0 },
+ { "chars", ottie_creation_parse_chars, 0 },
};
return ottie_parser_parse_object (reader, "toplevel", options, G_N_ELEMENTS (options), self);
@@ -465,9 +605,9 @@ ottie_creation_update_layers (OttieCreation *self)
g_hash_table_iter_init (&iter, self->composition_assets);
while (g_hash_table_iter_next (&iter, NULL, &layer))
- ottie_layer_update (layer, self->composition_assets);
+ ottie_layer_update (layer, self->composition_assets, self->fonts, self->chars);
- ottie_layer_update (OTTIE_LAYER (self->layers), self->composition_assets);
+ ottie_layer_update (OTTIE_LAYER (self->layers), self->composition_assets, self->fonts, self->chars);
}
static void
@@ -766,6 +906,9 @@ ottie_creation_print (OttiePrinter *printer,
const char *id;
OttieComposition *composition;
GHashTableIter iter;
+ const char *name;
+ OttieFont *font;
+ OttieChar *ch;
ottie_printer_start_object (printer, NULL);
@@ -788,13 +931,50 @@ ottie_creation_print (OttiePrinter *printer,
ottie_printer_end_array (printer);
ottie_printer_end_object (printer);
}
-
ottie_printer_end_array (printer);
ottie_printer_start_array (printer, "layers");
ottie_composition_print (printer, self->layers);
ottie_printer_end_array (printer);
+ if (g_hash_table_size (self->fonts) > 0)
+ {
+ ottie_printer_start_object (printer, "fonts");
+ ottie_printer_start_array (printer, "list");
+ g_hash_table_iter_init (&iter, self->fonts);
+ while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&font))
+ {
+ ottie_printer_start_object (printer, NULL);
+ ottie_printer_add_string (printer, "fName", font->name);
+ ottie_printer_add_string (printer, "fFamily", font->family);
+ ottie_printer_add_string (printer, "fStyle", font->style);
+ ottie_printer_add_double (printer, "ascent", font->ascent);
+ ottie_printer_end_object (printer);
+ }
+ ottie_printer_end_array (printer);
+ ottie_printer_end_object (printer);
+ }
+
+ if (g_hash_table_size (self->chars) > 0)
+ {
+ ottie_printer_start_array (printer, "chars");
+ g_hash_table_iter_init (&iter, self->chars);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&ch))
+ {
+ ottie_printer_start_object (printer, NULL);
+ ottie_printer_add_string (printer, "ch", ch->key.ch);
+ ottie_printer_add_string (printer, "fFamily", ch->key.family);
+ ottie_printer_add_string (printer, "style", ch->key.style);
+ ottie_printer_add_double (printer, "size", ch->size);
+ ottie_printer_add_double (printer, "w", ch->width);
+ ottie_printer_start_object (printer, "data");
+ ottie_group_shape_print_shapes (ch->shapes, "shapes", printer);
+ ottie_printer_end_object (printer);
+ ottie_printer_end_object (printer);
+ }
+ ottie_printer_end_array (printer);
+ }
+
ottie_printer_end_object (printer);
}
diff --git a/ottie/ottiefont.c b/ottie/ottiefont.c
new file mode 100644
index 0000000000..b51c8efd57
--- /dev/null
+++ b/ottie/ottiefont.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * 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: Matthias Clasen
+ */
+
+#include "ottiefontprivate.h"
+
+OttieFont *
+ottie_font_copy (OttieFont *font)
+{
+ OttieFont *f;
+
+ f = g_new0 (OttieFont, 1);
+ f->name = g_strdup (font->name);
+ f->family = g_strdup (font->family);
+ f->style = g_strdup (font->style);
+ f->ascent = font->ascent;
+
+ return f;
+}
+
+void
+ottie_font_free (OttieFont *font)
+{
+ g_free (font->name);
+ g_free (font->family);
+ g_free (font->style);
+ g_free (font);
+}
diff --git a/ottie/ottiefontprivate.h b/ottie/ottiefontprivate.h
new file mode 100644
index 0000000000..629186bedd
--- /dev/null
+++ b/ottie/ottiefontprivate.h
@@ -0,0 +1,43 @@
+
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * 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: Matthias Clasen
+ */
+
+#ifndef __OTTIE_FONT_PRIVATE_H__
+#define __OTTIE_FONT_PRIVATE_H__
+
+#include <json-glib/json-glib.h>
+
+#include "ottieprinterprivate.h"
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+ char *name;
+ char *family;
+ char *style;
+ double ascent;
+} OttieFont;
+
+OttieFont * ottie_font_copy (OttieFont *font);
+void ottie_font_free (OttieFont *font);
+
+
+#endif /* __OTTIE_FONT_PRIVATE_H__ */
diff --git a/ottie/ottielayer.c b/ottie/ottielayer.c
index d0b442f7b7..b418c8f5cd 100644
--- a/ottie/ottielayer.c
+++ b/ottie/ottielayer.c
@@ -40,7 +40,9 @@ G_DEFINE_TYPE (OttieLayer, ottie_layer, OTTIE_TYPE_OBJECT)
static void
ottie_layer_default_update (OttieLayer *self,
- GHashTable *compositions)
+ GHashTable *compositions,
+ GHashTable *fonts,
+ GHashTable *chars)
{
}
@@ -116,9 +118,11 @@ ottie_layer_init (OttieLayer *self)
void
ottie_layer_update (OttieLayer *self,
- GHashTable *compositions)
+ GHashTable *compositions,
+ GHashTable *fonts,
+ GHashTable *chars)
{
- OTTIE_LAYER_GET_CLASS (self)->update (self, compositions);
+ OTTIE_LAYER_GET_CLASS (self)->update (self, compositions, fonts, chars);
}
void
diff --git a/ottie/ottielayerprivate.h b/ottie/ottielayerprivate.h
index 4a60ea6463..788d5af2db 100644
--- a/ottie/ottielayerprivate.h
+++ b/ottie/ottielayerprivate.h
@@ -58,7 +58,9 @@ struct _OttieLayerClass
OttieObjectClass parent_class;
void (* update) (OttieLayer *layer,
- GHashTable *compositions);
+ GHashTable *compositions,
+ GHashTable *fonts,
+ GHashTable *chars);
void (* render) (OttieLayer *layer,
OttieRender *render,
double timestamp);
@@ -69,7 +71,9 @@ struct _OttieLayerClass
GType ottie_layer_get_type (void) G_GNUC_CONST;
void ottie_layer_update (OttieLayer *self,
- GHashTable *compositions);
+ GHashTable *compositions,
+ GHashTable *fonts,
+ GHashTable *chars);
void ottie_layer_render (OttieLayer *self,
OttieRender *render,
double timestamp);
diff --git a/ottie/ottieparser.c b/ottie/ottieparser.c
index 03a8b9c00a..b8f44485f4 100644
--- a/ottie/ottieparser.c
+++ b/ottie/ottieparser.c
@@ -590,3 +590,67 @@ ottie_parser_option_transform (JsonReader *reader,
return TRUE;
}
+gboolean
+ottie_parser_option_color (JsonReader *reader,
+ gsize offset,
+ gpointer data)
+{
+ GdkRGBA *rgba = (GdkRGBA *) ((guint8 *) data + offset);
+ double d[3];
+
+ if (!ottie_parser_parse_array (reader, "color value",
+ 3, 3, NULL,
+ 0, sizeof (double),
+ ottie_parser_option_double,
+ d))
+ {
+ d[0] = d[1] = d[2] = 0;
+ }
+
+ rgba->red = d[0];
+ rgba->green = d[1];
+ rgba->blue = d[2];
+ rgba->alpha = 1;
+
+ return TRUE;
+}
+
+gboolean
+ottie_parser_option_text_justify (JsonReader *reader,
+ gsize offset,
+ gpointer data)
+{
+ OttieTextJustify justify;
+ gint64 i;
+
+ i = json_reader_get_int_value (reader);
+ if (json_reader_get_error (reader))
+ {
+ ottie_parser_emit_error (reader, json_reader_get_error (reader));
+ return FALSE;
+ }
+
+ switch (i)
+ {
+ case 0:
+ justify = OTTIE_TEXT_JUSTIFY_LEFT;
+ break;
+
+ case 1:
+ justify = OTTIE_TEXT_JUSTIFY_RIGHT;
+ break;
+
+ case 2:
+ justify = OTTIE_TEXT_JUSTIFY_CENTER;
+ break;
+
+ default:
+ ottie_parser_error_value (reader, "%"G_GINT64_FORMAT" is not a known text justification", i);
+ return FALSE;
+ }
+
+ *(OttieTextJustify *) ((guint8 *) data + offset) = justify;
+
+ return TRUE;
+}
+
diff --git a/ottie/ottieparserprivate.h b/ottie/ottieparserprivate.h
index 27fc41acdc..0a8dde2ad9 100644
--- a/ottie/ottieparserprivate.h
+++ b/ottie/ottieparserprivate.h
@@ -33,6 +33,13 @@ typedef enum
OTTIE_DIRECTION_BACKWARD
} OttieDirection;
+typedef enum
+{
+ OTTIE_TEXT_JUSTIFY_LEFT,
+ OTTIE_TEXT_JUSTIFY_RIGHT,
+ OTTIE_TEXT_JUSTIFY_CENTER
+} OttieTextJustify;
+
typedef struct _OttieParserOption OttieParserOption;
typedef gboolean (* OttieParseFunc) (JsonReader *reader, gsize offset, gpointer data);
@@ -109,6 +116,12 @@ gboolean ottie_parser_option_fill_rule (JsonReader
gboolean ottie_parser_option_transform (JsonReader *reader,
gsize offset,
gpointer data);
+gboolean ottie_parser_option_color (JsonReader *reader,
+ gsize offset,
+ gpointer data);
+gboolean ottie_parser_option_text_justify (JsonReader *reader,
+ gsize offset,
+ gpointer data);
G_END_DECLS
diff --git a/ottie/ottiepathshapeprivate.h b/ottie/ottiepathshapeprivate.h
index 827e3cf3b1..830923c42b 100644
--- a/ottie/ottiepathshapeprivate.h
+++ b/ottie/ottiepathshapeprivate.h
@@ -22,6 +22,8 @@
#include "ottieshapeprivate.h"
+#include <gsk/gsk.h>
+
#include <json-glib/json-glib.h>
G_BEGIN_DECLS
diff --git a/ottie/ottierender.c b/ottie/ottierender.c
index daa764a1be..f1b2a9fd9d 100644
--- a/ottie/ottierender.c
+++ b/ottie/ottierender.c
@@ -109,6 +109,14 @@ void
ottie_render_add_path (OttieRender *self,
GskPath *path)
{
+ ottie_render_add_transformed_path (self, path, NULL);
+}
+
+void
+ottie_render_add_transformed_path (OttieRender *self,
+ GskPath *path,
+ GskTransform *transform)
+{
g_clear_pointer (&self->cached_path, gsk_path_unref);
if (gsk_path_is_empty (path))
@@ -116,11 +124,10 @@ ottie_render_add_path (OttieRender *self,
gsk_path_unref (path);
return;
}
-
- ottie_render_paths_append (&self->paths, &(OttieRenderPath) { path, NULL });
+ ottie_render_paths_append (&self->paths, &(OttieRenderPath) { path, transform });
}
-typedef struct
+typedef struct
{
GskPathBuilder *builder;
GskTransform *transform;
diff --git a/ottie/ottierenderprivate.h b/ottie/ottierenderprivate.h
index 57c5fa46e4..4ea1330c78 100644
--- a/ottie/ottierenderprivate.h
+++ b/ottie/ottierenderprivate.h
@@ -75,6 +75,9 @@ void ottie_render_merge (OttieRender
void ottie_render_add_path (OttieRender *self,
GskPath *path);
+void ottie_render_add_transformed_path (OttieRender *self,
+ GskPath *path,
+ GskTransform *transform);
GskPath * ottie_render_get_path (OttieRender *self);
void ottie_render_clear_path (OttieRender *self);
gsize ottie_render_get_n_subpaths (OttieRender *self);
diff --git a/ottie/ottietextlayer.c b/ottie/ottietextlayer.c
new file mode 100644
index 0000000000..894c5b7b19
--- /dev/null
+++ b/ottie/ottietextlayer.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright © 2020 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 "ottietextlayerprivate.h"
+
+#include "ottietextvalueprivate.h"
+#include "ottieparserprivate.h"
+#include "ottiefontprivate.h"
+#include "ottiecharprivate.h"
+#include "ottiepathshapeprivate.h"
+
+#include <glib/gi18n-lib.h>
+#include <gsk/gsk.h>
+
+struct _OttieTextLayer
+{
+ OttieLayer parent;
+
+ OttieTextValue text;
+
+ GHashTable *fonts;
+ GHashTable *chars;
+};
+
+struct _OttieTextLayerClass
+{
+ OttieLayerClass parent_class;
+};
+
+G_DEFINE_TYPE (OttieTextLayer, ottie_text_layer, OTTIE_TYPE_LAYER)
+
+static void
+ottie_text_layer_update (OttieLayer *layer,
+ GHashTable *compositions,
+ GHashTable *fonts,
+ GHashTable *chars)
+{
+ OttieTextLayer *self = OTTIE_TEXT_LAYER (layer);
+
+ g_clear_pointer (&self->fonts, g_hash_table_unref);
+ g_clear_pointer (&self->chars, g_hash_table_unref);
+
+ self->fonts = g_hash_table_ref (fonts);
+ self->chars = g_hash_table_ref (chars);
+}
+
+static GskPath *
+get_char_path (OttieChar *ch,
+ OttieRender *render,
+ double timestamp)
+{
+ OttieRender child_render;
+ GskPath *path;
+
+ ottie_render_init_child (&child_render, render);
+ ottie_shape_render (ch->shapes, &child_render, timestamp);
+ path = gsk_path_ref (ottie_render_get_path (&child_render));
+
+ ottie_render_clear (&child_render);
+
+ return path;
+}
+
+static OttieChar *
+get_char (OttieTextLayer *self,
+ OttieFont *font,
+ gunichar ch)
+{
+ OttieCharKey key;
+ char s[6] = { 0, };
+
+ g_unichar_to_utf8 (ch, s);
+
+ key.ch = s;
+ key.family = font->family;
+ key.style = font->style;
+
+ return g_hash_table_lookup (self->chars, &key);
+}
+
+static void
+render_text_item (OttieTextLayer *self,
+ OttieTextItem *item,
+ OttieRender *render,
+ double timestamp)
+{
+ OttieFont *font;
+ GskTransform *transform, *transform2;
+ float font_scale, tx;
+ char **lines;
+ int n_lines;
+
+ font = g_hash_table_lookup (self->fonts, item->font);
+ if (font == NULL)
+ {
+ g_print ("Ottie is missing a font (%s). Sad!\n", item->font);
+ return;
+ }
+
+ font_scale = item->size / 100.0;
+ transform = gsk_transform_scale (NULL, font_scale, font_scale);
+
+ lines = g_strsplit (item->text, "\r", -1);
+ n_lines = g_strv_length (lines);
+
+ transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (0, - (n_lines - 1) * item->line_height / 2 - item->line_shift));
+
+ for (int i = 0; i < n_lines; i++)
+ {
+ float line_width = 0;
+ char *p;
+
+ for (p = lines[i]; *p; p = g_utf8_next_char (p))
+ {
+ OttieChar *ch = get_char (self, font, g_utf8_get_char (p));
+ if (ch == NULL)
+ continue;
+ line_width += ch->width * font_scale;
+ }
+
+ transform2 = gsk_transform_ref (transform);
+
+ switch (item->justify)
+ {
+ case OTTIE_TEXT_JUSTIFY_LEFT:
+ break;
+ case OTTIE_TEXT_JUSTIFY_RIGHT:
+ transform2 = gsk_transform_translate (transform2, &GRAPHENE_POINT_INIT (- line_width, 0));
+ break;
+ case OTTIE_TEXT_JUSTIFY_CENTER:
+ transform2 = gsk_transform_translate (transform2, &GRAPHENE_POINT_INIT (- line_width/2, 0));
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ for (p = lines[i]; *p; p = g_utf8_next_char (p))
+ {
+ OttieChar *ch = get_char (self, font, g_utf8_get_char (p));
+ GskPath *path;
+
+ if (ch == NULL)
+ {
+ g_print ("Ottie is missing a char. Sad!\n");
+ continue;
+ }
+
+ path = get_char_path (ch, render, timestamp);
+
+ ottie_render_add_transformed_path (render, path, gsk_transform_ref (transform2));
+
+ tx = ch->width * font_scale + item->tracking / 10.0;
+ transform2 = gsk_transform_translate (transform2, &GRAPHENE_POINT_INIT (tx, 0));
+ }
+
+ gsk_transform_unref (transform2);
+
+ transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (0, item->line_height));
+ }
+
+ gsk_transform_unref (transform);
+
+ g_strfreev (lines);
+}
+
+static void
+ottie_text_layer_render (OttieLayer *layer,
+ OttieRender *render,
+ double timestamp)
+{
+ OttieTextLayer *self = OTTIE_TEXT_LAYER (layer);
+ OttieTextItem item;
+ OttieRender child_render;
+ GskPath *path;
+ graphene_rect_t bounds;
+ GskRenderNode *color_node;
+
+ ottie_text_value_get (&self->text, timestamp, &item);
+
+ ottie_render_init_child (&child_render, render);
+
+ render_text_item (self, &item, &child_render, timestamp);
+
+ path = ottie_render_get_path (&child_render);
+
+ gsk_path_get_bounds (path, &bounds);
+
+ color_node = gsk_color_node_new (&item.color, &bounds);
+
+ ottie_render_add_node (&child_render, gsk_fill_node_new (color_node, path, GSK_FILL_RULE_WINDING));
+
+ gsk_render_node_unref (color_node);
+
+ ottie_render_merge (render, &child_render);
+
+ ottie_render_clear (&child_render);
+}
+
+static void
+ottie_text_layer_print (OttieObject *obj,
+ OttiePrinter *printer)
+{
+ OttieTextLayer *self = OTTIE_TEXT_LAYER (obj);
+
+ OTTIE_OBJECT_CLASS (ottie_text_layer_parent_class)->print (obj, printer);
+
+ ottie_printer_add_int (printer, "ty", 5);
+ ottie_printer_start_object (printer, "t");
+ ottie_text_value_print (&self->text, "d", printer);
+ ottie_printer_end_object (printer);
+}
+
+static void
+ottie_text_layer_dispose (GObject *object)
+{
+ OttieTextLayer *self = OTTIE_TEXT_LAYER (object);
+
+ ottie_text_value_clear (&self->text);
+
+ g_clear_pointer (&self->fonts, g_hash_table_unref);
+ g_clear_pointer (&self->chars, g_hash_table_unref);
+
+ G_OBJECT_CLASS (ottie_text_layer_parent_class)->dispose (object);
+}
+
+static void
+ottie_text_layer_class_init (OttieTextLayerClass *klass)
+{
+ OttieObjectClass *oobject_class = OTTIE_OBJECT_CLASS (klass);
+ OttieLayerClass *layer_class = OTTIE_LAYER_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ oobject_class->print = ottie_text_layer_print;
+
+ layer_class->update = ottie_text_layer_update;
+ layer_class->render = ottie_text_layer_render;
+
+ gobject_class->dispose = ottie_text_layer_dispose;
+}
+
+static void
+ottie_text_layer_init (OttieTextLayer *self)
+{
+}
+
+static gboolean
+ottie_text_layer_parse_text (JsonReader *reader,
+ gsize offset,
+ gpointer data)
+{
+ OttieTextLayer *self = data;
+ OttieParserOption options[] = {
+ { "d", ottie_text_value_parse, G_STRUCT_OFFSET (OttieTextLayer, text) },
+ };
+
+ return ottie_parser_parse_object (reader, "text data", options, G_N_ELEMENTS (options), self);
+}
+
+OttieLayer *
+ottie_text_layer_parse (JsonReader *reader)
+{
+ OttieParserOption options[] = {
+ OTTIE_PARSE_OPTIONS_LAYER,
+ { "t", ottie_text_layer_parse_text, 0 },
+ };
+ OttieTextLayer *self;
+
+ self = g_object_new (OTTIE_TYPE_TEXT_LAYER, NULL);
+
+ if (!ottie_parser_parse_object (reader, "text layer", options, G_N_ELEMENTS (options), self))
+ {
+ g_object_unref (self);
+ return NULL;
+ }
+
+ return OTTIE_LAYER (self);
+}
diff --git a/ottie/ottietextvalue.c b/ottie/ottietextvalue.c
new file mode 100644
index 0000000000..74495befd3
--- /dev/null
+++ b/ottie/ottietextvalue.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * 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: Matthias Clasen
+ */
+
+#include "config.h"
+
+#include "ottietextvalueprivate.h"
+
+#include "ottieparserprivate.h"
+#include "ottieprinterprivate.h"
+
+#include <glib/gi18n-lib.h>
+
+static inline void
+text_item_copy (const OttieTextItem *source,
+ OttieTextItem *dest)
+{
+ *dest = *source;
+ dest->font = g_strdup (dest->font);
+ dest->text = g_strdup (dest->text);
+}
+
+static gboolean
+ottie_text_value_parse_one (JsonReader *reader,
+ gsize offset,
+ gpointer data)
+{
+ OttieTextItem *item = (OttieTextItem *) ((guint8 *) data + offset);
+ OttieParserOption options[] = {
+ { "f", ottie_parser_option_string, G_STRUCT_OFFSET (OttieTextItem, font) },
+ { "t", ottie_parser_option_string, G_STRUCT_OFFSET (OttieTextItem, text) },
+ { "s", ottie_parser_option_double, G_STRUCT_OFFSET (OttieTextItem, size) },
+ { "fc", ottie_parser_option_color, G_STRUCT_OFFSET (OttieTextItem, color) },
+ { "j", ottie_parser_option_text_justify, G_STRUCT_OFFSET (OttieTextItem, justify) },
+ { "lh", ottie_parser_option_double, G_STRUCT_OFFSET (OttieTextItem, line_height) },
+ { "ls", ottie_parser_option_double, G_STRUCT_OFFSET (OttieTextItem, line_shift) },
+ { "tr", ottie_parser_option_double, G_STRUCT_OFFSET (OttieTextItem, tracking) },
+ };
+
+ if (!ottie_parser_parse_object (reader, "text value",
+ options, G_N_ELEMENTS (options),
+ item))
+ {
+ g_print ("sorry no text\n");
+ }
+
+ return TRUE;
+}
+
+static void
+ottie_text_value_print_one (OttiePrinter *printer,
+ const char *name,
+ const OttieTextItem *text)
+{
+ ottie_printer_start_object (printer, name);
+ ottie_printer_add_string (printer, "f", text->font);
+ ottie_printer_add_string (printer, "t", text->text);
+ ottie_printer_add_double (printer, "s", text->size);
+ g_string_append (printer->str, ",\n");
+ ottie_printer_indent (printer);
+ g_string_append_printf (printer->str, "\"fc\" : [ %g, %g, %g ]",
+ text->color.red, text->color.green, text->color.blue);
+ ottie_printer_add_int (printer, "j", text->justify);
+ ottie_printer_add_double (printer, "lh", text->line_height);
+ ottie_printer_add_double (printer, "ls", text->line_shift);
+ ottie_printer_add_double (printer, "tr", text->tracking);
+ ottie_printer_end_object (printer);
+}
+
+static void
+ottie_text_value_interpolate (const OttieTextItem *start,
+ const OttieTextItem *end,
+ double progress,
+ OttieTextItem *result)
+{
+ text_item_copy (start, result);
+}
+
+#define OTTIE_KEYFRAMES_NAME ottie_text_keyframes
+#define OTTIE_KEYFRAMES_TYPE_NAME OttieTextKeyframes
+#define OTTIE_KEYFRAMES_ELEMENT_TYPE OttieTextItem
+#define OTTIE_KEYFRAMES_BY_VALUE 1
+#define OTTIE_KEYFRAMES_PARSE_FUNC ottie_text_value_parse_one
+#define OTTIE_KEYFRAMES_INTERPOLATE_FUNC ottie_text_value_interpolate
+#define OTTIE_KEYFRAMES_PRINT_FUNC ottie_text_value_print_one
+#include "ottiekeyframesimpl.c"
+
+void
+ottie_text_value_init (OttieTextValue *self,
+ const OttieTextItem *value)
+{
+ self->is_static = TRUE;
+ text_item_copy (value, &self->static_value);
+}
+
+void
+ottie_text_value_clear (OttieTextValue *self)
+{
+ if (!self->is_static)
+ g_clear_pointer (&self->keyframes, ottie_text_keyframes_free);
+}
+
+void
+ottie_text_value_get (OttieTextValue *self,
+ double timestamp,
+ OttieTextItem *text)
+{
+ if (self->is_static)
+ {
+ text_item_copy (&self->static_value, text);
+ return;
+ }
+
+ ottie_text_keyframes_get (self->keyframes, timestamp, text);
+}
+
+gboolean
+ottie_text_value_parse (JsonReader *reader,
+ gsize offset,
+ gpointer data)
+{
+ OttieTextValue *self = (OttieTextValue *) ((guint8 *) data + offset);
+
+ if (json_reader_read_member (reader, "k"))
+ {
+ gboolean is_static;
+
+ if (!json_reader_is_array (reader))
+ is_static = TRUE;
+ else
+ {
+ if (json_reader_read_element (reader, 0))
+ is_static = !json_reader_is_object (reader);
+ else
+ is_static = TRUE;
+ json_reader_end_element (reader);
+ }
+
+ if (is_static)
+ {
+ self->is_static = TRUE;
+ ottie_text_value_parse_one (reader, 0, &self->static_value);
+ }
+ else
+ {
+ self->is_static = FALSE;
+ self->keyframes = ottie_text_keyframes_parse (reader);
+ if (self->keyframes == NULL)
+ {
+ json_reader_end_member (reader);
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ ottie_parser_error_syntax (reader, "Property is not a text value");
+ }
+ json_reader_end_member (reader);
+
+ return TRUE;
+}
+
+void
+ottie_text_value_print (OttieTextValue *self,
+ const char *name,
+ OttiePrinter *printer)
+{
+ ottie_printer_start_object (printer, name);
+
+ ottie_printer_add_boolean (printer, "a", !self->is_static);
+ if (self->is_static)
+ ottie_text_value_print_one (printer, "k", &self->static_value);
+ else
+ ottie_text_keyframes_print (self->keyframes, printer);
+
+ ottie_printer_end_object (printer);
+}
+
diff --git a/ottie/ottietextvalueprivate.h b/ottie/ottietextvalueprivate.h
new file mode 100644
index 0000000000..6bb5766b55
--- /dev/null
+++ b/ottie/ottietextvalueprivate.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * 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: Matthias Clasen
+ */
+
+#ifndef __OTTIE_TEXT_VALUE_PRIVATE_H__
+#define __OTTIE_TEXT_VALUE_PRIVATE_H__
+
+#include <json-glib/json-glib.h>
+#include "ottie/ottieparserprivate.h"
+#include "ottie/ottieprinterprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _OttieTextItem OttieTextItem;
+
+struct _OttieTextItem
+{
+ const char *font;
+ const char *text;
+ GdkRGBA color;
+ double size;
+ OttieTextJustify justify;
+ double line_height;
+ double line_shift;
+ double tracking;
+};
+
+typedef struct _OttieTextValue OttieTextValue;
+
+struct _OttieTextValue
+{
+ gboolean is_static;
+ union {
+ OttieTextItem static_value;
+ gpointer keyframes;
+ };
+};
+
+void ottie_text_value_init (OttieTextValue *self,
+ const OttieTextItem *item);
+
+void ottie_text_value_clear (OttieTextValue *self);
+
+static inline gboolean ottie_text_value_is_static (OttieTextValue *self);
+void ottie_text_value_get (OttieTextValue *self,
+ double timestamp,
+ OttieTextItem *item);
+
+gboolean ottie_text_value_parse (JsonReader *reader,
+ gsize offset,
+ gpointer data);
+
+void ottie_text_value_print (OttieTextValue *self,
+ const char *name,
+ OttiePrinter *printer);
+
+static inline gboolean
+ottie_text_value_is_static (OttieTextValue *self)
+{
+ return self->is_static;
+}
+
+G_END_DECLS
+
+#endif /* __OTTIE_TEXT_VALUE_PRIVATE_H__ */