[gtk/wip/otte/nodeeditor] transform: Add gsk_transform_from_string()
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/nodeeditor] transform: Add gsk_transform_from_string()
- Date: Thu, 21 Mar 2019 05:50:35 +0000 (UTC)
commit 4a0b73ce5881fa356756eac1ffd9257a1a171b75
Author: Benjamin Otte <otte redhat com>
Date: Thu Mar 21 05:52:41 2019 +0100
transform: Add gsk_transform_from_string()
It uses the CSS parser, so we can also use it for parsing transform nodes.
docs/reference/gsk/gsk4-sections.txt | 2 +
gsk/gskrendernodeparser.c | 53 +++++++-
gsk/gsktransform.c | 255 ++++++++++++++++++++++++++++++++++-
gsk/gsktransform.h | 3 +
gsk/gsktransformprivate.h | 6 +-
5 files changed, 313 insertions(+), 6 deletions(-)
---
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt
index 0e4e5468b4..1ab448b01c 100644
--- a/docs/reference/gsk/gsk4-sections.txt
+++ b/docs/reference/gsk/gsk4-sections.txt
@@ -157,6 +157,8 @@ gsk_transform_get_category
<SUBSECTION>
gsk_transform_print
gsk_transform_to_string
+gsk_transform_from_string
+<SUBSECTION>
gsk_transform_to_matrix
gsk_transform_to_2d
gsk_transform_to_affine
diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c
index 902c44495a..c61c24a279 100644
--- a/gsk/gskrendernodeparser.c
+++ b/gsk/gskrendernodeparser.c
@@ -4,7 +4,7 @@
#include "gskcssparserprivate.h"
#include "gskroundedrectprivate.h"
#include "gskrendernodeprivate.h"
-#include "gsktransform.h"
+#include "gsktransformprivate.h"
typedef struct _Declaration Declaration;
@@ -363,6 +363,25 @@ parse_point (GskCssParser *parser,
return TRUE;
}
+static gboolean
+parse_transform (GskCssParser *parser,
+ gpointer out_transform)
+{
+ GskTransform *transform;
+
+ if (!gsk_transform_parse (parser, &transform) ||
+ !parse_semicolon (parser))
+ {
+ gsk_transform_unref (transform);
+ return FALSE;
+ }
+
+ gsk_transform_unref (*(GskTransform **) out_transform);
+ *(GskTransform **) out_transform = transform;
+
+ return TRUE;
+}
+
static gboolean
parse_string (GskCssParser *parser,
gpointer out_string)
@@ -624,6 +643,36 @@ parse_outset_shadow_node (GskCssParser *parser)
return gsk_outset_shadow_node_new (&outline, &color, dx, dy, spread, blur);
}
+static GskRenderNode *
+parse_transform_node (GskCssParser *parser)
+{
+ GskRenderNode *child = NULL;
+ GskTransform *transform = NULL;
+ const Declaration declarations[] = {
+ { "transform", parse_transform, &transform },
+ { "child", parse_node, &child },
+ };
+ GskRenderNode *result;
+
+ parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
+ if (child == NULL)
+ {
+ gsk_css_parser_error_syntax (parser, "Missing \"child\" property definition");
+ gsk_transform_unref (transform);
+ return NULL;
+ }
+ /* This is very much cheating, isn't it? */
+ if (transform == NULL)
+ transform = gsk_transform_new ();
+
+ result = gsk_transform_node_new (child, transform);
+
+ gsk_render_node_unref (child);
+ gsk_transform_unref (transform);
+
+ return result;
+}
+
static GskRenderNode *
parse_opacity_node (GskCssParser *parser)
{
@@ -762,9 +811,7 @@ parse_node (GskCssParser *parser,
#endif
{ "inset-shadow", parse_inset_shadow_node },
{ "outset-shadow", parse_outset_shadow_node },
-#if 0
{ "transform", parse_transform_node },
-#endif
{ "opacity", parse_opacity_node },
#if 0
{ "color-matrix", parse_color-matrix_node },
diff --git a/gsk/gsktransform.c b/gsk/gsktransform.c
index d5e4ac4e5a..13b2dea3b8 100644
--- a/gsk/gsktransform.c
+++ b/gsk/gsktransform.c
@@ -1264,8 +1264,8 @@ gsk_transform_unref (GskTransform *self)
* @self: (allow-none): a #GskTransform
* @string: The string to print into
*
- * Converts @self into a string representation suitable for printing that
- * can later be parsed with gsk_transform_parse().
+ * Converts @self into a human-readable string representation suitable
+ * for printing that can later be parsed with gsk_transform_from_string().
**/
void
gsk_transform_print (GskTransform *self,
@@ -1651,3 +1651,254 @@ gsk_transform_transform_bounds (GskTransform *self,
break;
}
}
+
+static guint
+gsk_transform_parse_float (GskCssParser *parser,
+ guint n,
+ gpointer data)
+{
+ float *f = data;
+ double d;
+
+ if (!gsk_css_parser_consume_number (parser, &d))
+ return 0;
+
+ f[n] = d;
+ return 1;
+}
+
+static guint
+gsk_transform_parse_scale (GskCssParser *parser,
+ guint n,
+ gpointer data)
+{
+ float *f = data;
+ double d;
+
+ if (!gsk_css_parser_consume_number (parser, &d))
+ return 0;
+
+ f[n] = d;
+ f[1] = d;
+ return 1;
+}
+
+gboolean
+gsk_transform_parse (GskCssParser *parser,
+ GskTransform **out_transform)
+{
+ const GskCssToken *token;
+ GskTransform *transform = NULL;
+ float f[16] = { 0, };
+
+ token = gsk_css_parser_get_token (parser);
+ if (gsk_css_token_is_ident (token, "none"))
+ {
+ gsk_css_parser_consume_token (parser);
+ *out_transform = NULL;
+ return TRUE;
+ }
+
+ while (TRUE)
+ {
+ if (gsk_css_token_is_function (token, "matrix"))
+ {
+ graphene_matrix_t matrix;
+ if (!gsk_css_parser_consume_function (parser, 6, 6, gsk_transform_parse_float, f))
+ goto fail;
+
+ graphene_matrix_init_from_2d (&matrix, f[0], f[1], f[2], f[3], f[4], f[5]);
+ transform = gsk_transform_matrix_with_category (transform,
+ &matrix,
+ GSK_TRANSFORM_CATEGORY_2D);
+ }
+ else if (gsk_css_token_is_function (token, "matrix3d"))
+ {
+ graphene_matrix_t matrix;
+ if (!gsk_css_parser_consume_function (parser, 16, 16, gsk_transform_parse_float, f))
+ goto fail;
+
+ graphene_matrix_init_from_float (&matrix, f);
+ transform = gsk_transform_matrix (transform, &matrix);
+ }
+ else if (gsk_css_token_is_function (token, "perspective"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_perspective (transform, f[0]);
+ }
+ else if (gsk_css_token_is_function (token, "rotate") ||
+ gsk_css_token_is_function (token, "rotateZ"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_rotate (transform, f[0]);
+ }
+ else if (gsk_css_token_is_function (token, "rotate3d"))
+ {
+ graphene_vec3_t axis;
+
+ if (!gsk_css_parser_consume_function (parser, 4, 4, gsk_transform_parse_float, f))
+ goto fail;
+
+ graphene_vec3_init (&axis, f[0], f[1], f[2]);
+ transform = gsk_transform_rotate_3d (transform, f[3], &axis);
+ }
+ else if (gsk_css_token_is_function (token, "rotateX"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_rotate_3d (transform, f[0], graphene_vec3_x_axis ());
+ }
+ else if (gsk_css_token_is_function (token, "rotateY"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_rotate_3d (transform, f[0], graphene_vec3_y_axis ());
+ }
+ else if (gsk_css_token_is_function (token, "scale"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 1, 2, gsk_transform_parse_scale, f))
+ goto fail;
+
+ transform = gsk_transform_scale (transform, f[0], f[1]);
+ }
+ else if (gsk_css_token_is_function (token, "scale3d"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 3, 3, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_scale_3d (transform, f[0], f[1], f[2]);
+ }
+ else if (gsk_css_token_is_function (token, "scaleX"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_scale (transform, f[0], 1.f);
+ }
+ else if (gsk_css_token_is_function (token, "scaleY"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_scale (transform, 1.f, f[0]);
+ }
+ else if (gsk_css_token_is_function (token, "scaleZ"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_scale_3d (transform, 1.f, 1.f, f[0]);
+ }
+ else if (gsk_css_token_is_function (token, "translate"))
+ {
+ f[1] = 0.f;
+ if (!gsk_css_parser_consume_function (parser, 1, 2, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (f[0], f[1]));
+ }
+ else if (gsk_css_token_is_function (token, "translate3d"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 3, 3, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (f[0], f[1], f[2]));
+ }
+ else if (gsk_css_token_is_function (token, "translateX"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (f[0], 0.f));
+ }
+ else if (gsk_css_token_is_function (token, "translateY"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (0.f, f[0]));
+ }
+ else if (gsk_css_token_is_function (token, "translateZ"))
+ {
+ if (!gsk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
+ goto fail;
+
+ transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (0.f, 0.f, f[0]));
+ }
+#if 0
+ /* FIXME: add these */
+ else if (gsk_css_token_is_function (token, "skew"))
+ {
+ }
+ else if (gsk_css_token_is_function (token, "skewX"))
+ {
+ }
+ else if (gsk_css_token_is_function (token, "skewY"))
+ {
+ }
+#endif
+ else
+ {
+ break;
+ }
+
+ token = gsk_css_parser_get_token (parser);
+ }
+
+ if (transform == NULL)
+ {
+ gsk_css_parser_error_syntax (parser, "Expected a transform");
+ goto fail;
+ }
+
+ *out_transform = transform;
+ return TRUE;
+
+fail:
+ gsk_transform_unref (transform);
+ *out_transform = NULL;
+ return FALSE;
+}
+
+/**
+ * gsk_transform_from_string:
+ * @string: the string to parse
+ * @out_transform: (out): The location to put the transform in
+ *
+ * Parses the given @string into a transform and puts it in
+ * @out_transform. Strings printed via gsk_transform_to_string()
+ * can be read in again successfully using this function.
+ *
+ * If @string does not describe a valid transform, %FALSE is
+ * returned and %NULL is put in @out_transform.
+ *
+ * Returns: %TRUE if @string described a valid transform.
+ **/
+gboolean
+gsk_transform_from_string (const char *string,
+ GskTransform **out_transform)
+{
+ GskCssParser *parser;
+ GBytes *bytes;
+ gboolean result;
+
+ g_return_val_if_fail (string != NULL, FALSE);
+ g_return_val_if_fail (out_transform != NULL, FALSE);
+
+ bytes = g_bytes_new_static (string, strlen (string));
+ parser = gsk_css_parser_new (NULL, NULL, NULL);
+ gsk_css_parser_add_bytes (parser, bytes);
+
+ result = gsk_transform_parse (parser, out_transform);
+
+ gsk_css_parser_unref (parser);
+ g_bytes_unref (bytes);
+
+ return result;
+}
diff --git a/gsk/gsktransform.h b/gsk/gsktransform.h
index 6cbe3659f2..8a55d387a8 100644
--- a/gsk/gsktransform.h
+++ b/gsk/gsktransform.h
@@ -46,6 +46,9 @@ void gsk_transform_print (GskTransform
GDK_AVAILABLE_IN_ALL
char * gsk_transform_to_string (GskTransform *self);
GDK_AVAILABLE_IN_ALL
+gboolean gsk_transform_from_string (const char *string,
+ GskTransform
**out_transform);
+GDK_AVAILABLE_IN_ALL
void gsk_transform_to_matrix (GskTransform *self,
graphene_matrix_t *out_matrix);
GDK_AVAILABLE_IN_ALL
diff --git a/gsk/gsktransformprivate.h b/gsk/gsktransformprivate.h
index 5ea45e03fb..34fe23d3d5 100644
--- a/gsk/gsktransformprivate.h
+++ b/gsk/gsktransformprivate.h
@@ -23,7 +23,7 @@
#include "gsktransform.h"
-#include <gsk/gsk.h>
+#include "gsk/gskcssparserprivate.h"
#include "gsk/gskrendernodeprivate.h"
G_BEGIN_DECLS
@@ -32,6 +32,10 @@ GskTransform * gsk_transform_matrix_with_category (GskTransform
const graphene_matrix_t*matrix,
GskTransformCategory category);
+gboolean gsk_transform_parse (GskCssParser *parser,
+ GskTransform **out_transform);
+
+
G_END_DECLS
#endif /* __GSK_TRANSFORM_PRIVATE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]