diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt index e3b3151c57..35d042fc5c 100644 --- a/docs/reference/gsk/gsk4-sections.txt +++ b/docs/reference/gsk/gsk4-sections.txt @@ -152,6 +152,8 @@ gsk_transform_get_category gsk_transform_print gsk_transform_to_string +gsk_transform_parse + gsk_transform_to_matrix gsk_transform_to_2d gsk_transform_to_affine diff --git a/gsk/gsktransform.c b/gsk/gsktransform.c index d5e4ac4e5a..1dfd9b9740 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_parse(). **/ void gsk_transform_print (GskTransform *self, @@ -1651,3 +1651,258 @@ gsk_transform_transform_bounds (GskTransform *self, break; } } + +static guint +gsk_transform_parse_float (GtkCssParser *parser, + guint n, + gpointer data) +{ + float *f = data; + double d; + + if (!gtk_css_parser_consume_number (parser, &d)) + return 0; + + f[n] = d; + return 1; +} + +static guint +gsk_transform_parse_scale (GtkCssParser *parser, + guint n, + gpointer data) +{ + float *f = data; + double d; + + if (!gtk_css_parser_consume_number (parser, &d)) + return 0; + + f[n] = d; + f[1] = d; + return 1; +} + +gboolean +gsk_transform_parser_parse (GtkCssParser *parser, + GskTransform **out_transform) +{ + const GtkCssToken *token; + GskTransform *transform = NULL; + float f[16] = { 0, }; + + token = gtk_css_parser_get_token (parser); + if (gtk_css_token_is_ident (token, "none")) + { + gtk_css_parser_consume_token (parser); + *out_transform = NULL; + return TRUE; + } + + while (TRUE) + { + if (gtk_css_token_is_function (token, "matrix")) + { + graphene_matrix_t matrix; + if (!gtk_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 (gtk_css_token_is_function (token, "matrix3d")) + { + graphene_matrix_t matrix; + if (!gtk_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 (gtk_css_token_is_function (token, "perspective")) + { + if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f)) + goto fail; + + transform = gsk_transform_perspective (transform, f[0]); + } + else if (gtk_css_token_is_function (token, "rotate") || + gtk_css_token_is_function (token, "rotateZ")) + { + if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f)) + goto fail; + + transform = gsk_transform_rotate (transform, f[0]); + } + else if (gtk_css_token_is_function (token, "rotate3d")) + { + graphene_vec3_t axis; + + if (!gtk_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 (gtk_css_token_is_function (token, "rotateX")) + { + if (!gtk_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 (gtk_css_token_is_function (token, "rotateY")) + { + if (!gtk_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 (gtk_css_token_is_function (token, "scale")) + { + if (!gtk_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 (gtk_css_token_is_function (token, "scale3d")) + { + if (!gtk_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 (gtk_css_token_is_function (token, "scaleX")) + { + if (!gtk_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 (gtk_css_token_is_function (token, "scaleY")) + { + if (!gtk_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 (gtk_css_token_is_function (token, "scaleZ")) + { + if (!gtk_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 (gtk_css_token_is_function (token, "translate")) + { + f[1] = 0.f; + if (!gtk_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 (gtk_css_token_is_function (token, "translate3d")) + { + if (!gtk_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 (gtk_css_token_is_function (token, "translateX")) + { + if (!gtk_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 (gtk_css_token_is_function (token, "translateY")) + { + if (!gtk_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 (gtk_css_token_is_function (token, "translateZ")) + { + if (!gtk_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 (gtk_css_token_is_function (token, "skew")) + { + } + else if (gtk_css_token_is_function (token, "skewX")) + { + } + else if (gtk_css_token_is_function (token, "skewY")) + { + } +#endif + else + { + break; + } + + token = gtk_css_parser_get_token (parser); + } + + if (transform == NULL) + { + gtk_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_parse: + * @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_parse (const char *string, + GskTransform **out_transform) +{ + GtkCssParser *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 = gtk_css_parser_new_for_bytes (bytes, NULL, NULL, NULL, NULL, NULL); + + result = gsk_transform_parser_parse (parser, out_transform); + + if (result && !gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF)) + { + g_clear_pointer (out_transform, gsk_transform_unref); + result = FALSE; + } + gtk_css_parser_unref (parser); + g_bytes_unref (bytes); + + return result; +} diff --git a/gsk/gsktransform.h b/gsk/gsktransform.h index 6cbe3659f2..6ef7427448 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_parse (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..a276a640b3 100644 --- a/gsk/gsktransformprivate.h +++ b/gsk/gsktransformprivate.h @@ -23,15 +23,21 @@ #include "gsktransform.h" -#include #include "gsk/gskrendernodeprivate.h" +#include +#include "gtk/css/gtkcssparserprivate.h" + G_BEGIN_DECLS GskTransform * gsk_transform_matrix_with_category (GskTransform *next, const graphene_matrix_t*matrix, GskTransformCategory category); +gboolean gsk_transform_parser_parse (GtkCssParser *parser, + GskTransform **out_transform); + + G_END_DECLS #endif /* __GSK_TRANSFORM_PRIVATE_H__ */