forked from AuroraMiddleware/gtk
Merge branch 'cairo-script-interpreter' into 'master'
rendernodeparser: Parse cairo script See merge request GNOME/gtk!876
This commit is contained in:
commit
b9dc13ad99
@ -297,6 +297,8 @@
|
||||
|
||||
#mesondefine GTK_PRINT_BACKENDS
|
||||
|
||||
#mesondefine HAVE_CAIRO_SCRIPT_INTERPRETER
|
||||
|
||||
#mesondefine HAVE_HARFBUZZ
|
||||
|
||||
#mesondefine HAVE_PANGOFT
|
||||
|
@ -36,6 +36,9 @@
|
||||
#ifdef CAIRO_HAS_SCRIPT_SURFACE
|
||||
#include <cairo-script.h>
|
||||
#endif
|
||||
#ifdef HAVE_CAIRO_SCRIPT_INTERPRETER
|
||||
#include <cairo-script-interpreter.h>
|
||||
#endif
|
||||
|
||||
typedef struct _Declaration Declaration;
|
||||
|
||||
@ -132,6 +135,131 @@ clear_texture (gpointer inout_texture)
|
||||
g_clear_object ((GdkTexture **) inout_texture);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
csi_hooks_surface_create (void *closure,
|
||||
cairo_content_t content,
|
||||
double width,
|
||||
double height,
|
||||
long uid)
|
||||
{
|
||||
return cairo_surface_create_similar (closure, content, width, height);
|
||||
}
|
||||
|
||||
static const cairo_user_data_key_t csi_hooks_key;
|
||||
|
||||
static cairo_t *
|
||||
csi_hooks_context_create (void *closure,
|
||||
cairo_surface_t *surface)
|
||||
{
|
||||
cairo_t *cr = cairo_create (surface);
|
||||
|
||||
cairo_set_user_data (cr,
|
||||
&csi_hooks_key,
|
||||
cairo_surface_reference (surface),
|
||||
(cairo_destroy_func_t) cairo_surface_destroy);
|
||||
|
||||
return cr;
|
||||
}
|
||||
|
||||
static void
|
||||
csi_hooks_context_destroy (void *closure,
|
||||
void *ptr)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
|
||||
surface = cairo_get_user_data (ptr, &csi_hooks_key);
|
||||
cr = cairo_create (closure);
|
||||
cairo_set_source_surface (cr, surface, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_script (GtkCssParser *parser,
|
||||
gpointer out_data)
|
||||
{
|
||||
#ifdef HAVE_CAIRO_SCRIPT_INTERPRETER
|
||||
GError *error = NULL;
|
||||
GBytes *bytes;
|
||||
GtkCssLocation start_location;
|
||||
char *url, *scheme;
|
||||
cairo_script_interpreter_t *csi;
|
||||
cairo_script_interpreter_hooks_t hooks = {
|
||||
.surface_create = csi_hooks_surface_create,
|
||||
.context_create = csi_hooks_context_create,
|
||||
.context_destroy = csi_hooks_context_destroy,
|
||||
};
|
||||
|
||||
start_location = *gtk_css_parser_get_start_location (parser);
|
||||
url = gtk_css_parser_consume_url (parser);
|
||||
if (url == NULL)
|
||||
return FALSE;
|
||||
|
||||
scheme = g_uri_parse_scheme (url);
|
||||
if (scheme && g_ascii_strcasecmp (scheme, "data") == 0)
|
||||
{
|
||||
bytes = gtk_css_data_url_parse (url, NULL, &error);
|
||||
}
|
||||
else
|
||||
{
|
||||
GFile *file;
|
||||
|
||||
file = gtk_css_parser_resolve_url (parser, url);
|
||||
bytes = g_file_load_bytes (file, NULL, NULL, &error);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
g_free (scheme);
|
||||
g_free (url);
|
||||
|
||||
if (bytes == NULL)
|
||||
{
|
||||
gtk_css_parser_emit_error (parser,
|
||||
&start_location,
|
||||
gtk_css_parser_get_end_location (parser),
|
||||
error);
|
||||
g_clear_error (&error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hooks.closure = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
|
||||
csi = cairo_script_interpreter_create ();
|
||||
cairo_script_interpreter_install_hooks (csi, &hooks);
|
||||
cairo_script_interpreter_feed_string (csi, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes));
|
||||
g_bytes_unref (bytes);
|
||||
if (cairo_surface_status (hooks.closure) != CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
gtk_css_parser_error_value (parser, "Invalid Cairo script: %s", cairo_status_to_string (cairo_surface_status (hooks.closure)));
|
||||
cairo_script_interpreter_destroy (csi);
|
||||
return FALSE;
|
||||
}
|
||||
if (cairo_script_interpreter_destroy (csi) != CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
gtk_css_parser_error_value (parser, "Invalid Cairo script");
|
||||
cairo_surface_destroy (hooks.closure);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*(cairo_surface_t **) out_data = hooks.closure;
|
||||
return TRUE;
|
||||
#else
|
||||
gtk_css_parser_warn (parser,
|
||||
GTK_CSS_PARSER_WARNING_UNIMPLEMENTED,
|
||||
gtk_css_parser_get_block_location (parser),
|
||||
gtk_css_parser_get_start_location (parser),
|
||||
"GTK was compiled with script interpreter support. Using fallback pixel data for Cairo node.");
|
||||
*(cairo_surface_t **) out_data = NULL;
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
clear_surface (gpointer inout_surface)
|
||||
{
|
||||
g_clear_pointer ((cairo_surface_t **) inout_surface, cairo_surface_destroy);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_rounded_rect (GtkCssParser *parser,
|
||||
gpointer out_rect)
|
||||
@ -930,35 +1058,40 @@ parse_cairo_node (GtkCssParser *parser)
|
||||
{
|
||||
graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50);
|
||||
GdkTexture *pixels = NULL;
|
||||
cairo_surface_t *surface = NULL;
|
||||
const Declaration declarations[] = {
|
||||
{ "bounds", parse_rect, NULL, &bounds },
|
||||
{ "pixels", parse_texture, clear_texture, &pixels }
|
||||
{ "pixels", parse_texture, clear_texture, &pixels },
|
||||
{ "script", parse_script, clear_surface, &surface }
|
||||
};
|
||||
GskRenderNode *node;
|
||||
cairo_t *cr;
|
||||
|
||||
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
|
||||
|
||||
node = gsk_cairo_node_new (&bounds);
|
||||
|
||||
cr = gsk_cairo_node_get_draw_context (node);
|
||||
|
||||
if (pixels != NULL)
|
||||
if (surface != NULL)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr = gsk_cairo_node_get_draw_context (node);
|
||||
cairo_set_source_surface (cr, surface, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
else if (pixels != NULL)
|
||||
{
|
||||
cairo_t *cr = gsk_cairo_node_get_draw_context (node);
|
||||
surface = gdk_texture_download_surface (pixels);
|
||||
cairo_set_source_surface (cr, surface, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_surface_destroy (surface);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
gdk_cairo_set_source_rgba (cr, &GDK_RGBA ("FF00CC"));
|
||||
cairo_paint (cr);
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
g_clear_object (&pixels);
|
||||
g_clear_pointer (&surface, cairo_surface_destroy);
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -2246,36 +2379,39 @@ render_node_print (Printer *p,
|
||||
start_node (p, "cairo");
|
||||
append_rect_param (p, "bounds", &node->bounds);
|
||||
|
||||
array = g_byte_array_new ();
|
||||
cairo_surface_write_to_png_stream (surface, cairo_write_array, array);
|
||||
b64 = g_base64_encode (array->data, array->len);
|
||||
if (surface != NULL)
|
||||
{
|
||||
array = g_byte_array_new ();
|
||||
cairo_surface_write_to_png_stream (surface, cairo_write_array, array);
|
||||
b64 = g_base64_encode (array->data, array->len);
|
||||
|
||||
_indent (p);
|
||||
g_string_append_printf (p->str, "pixels: url(\"data:image/png;base64,%s\");\n", b64);
|
||||
_indent (p);
|
||||
g_string_append_printf (p->str, "pixels: url(\"data:image/png;base64,%s\");\n", b64);
|
||||
|
||||
g_free (b64);
|
||||
g_byte_array_free (array, TRUE);
|
||||
g_free (b64);
|
||||
g_byte_array_free (array, TRUE);
|
||||
|
||||
#ifdef CAIRO_HAS_SCRIPT_SURFACE
|
||||
if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_RECORDING)
|
||||
{
|
||||
cairo_device_t *script;
|
||||
|
||||
array = g_byte_array_new ();
|
||||
script = cairo_script_create_for_stream (cairo_write_array, array);
|
||||
|
||||
if (cairo_script_from_recording_surface (script, surface) == CAIRO_STATUS_SUCCESS)
|
||||
if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_RECORDING)
|
||||
{
|
||||
b64 = g_base64_encode (array->data, array->len);
|
||||
_indent (p);
|
||||
g_string_append_printf (p->str, "script: url(\"data:;base64,%s\");\n", b64);
|
||||
g_free (b64);
|
||||
}
|
||||
cairo_device_t *script;
|
||||
|
||||
cairo_device_destroy (script);
|
||||
g_byte_array_free (array, TRUE);
|
||||
}
|
||||
array = g_byte_array_new ();
|
||||
script = cairo_script_create_for_stream (cairo_write_array, array);
|
||||
|
||||
if (cairo_script_from_recording_surface (script, surface) == CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
b64 = g_base64_encode (array->data, array->len);
|
||||
_indent (p);
|
||||
g_string_append_printf (p->str, "script: url(\"data:;base64,%s\");\n", b64);
|
||||
g_free (b64);
|
||||
}
|
||||
|
||||
cairo_device_destroy (script);
|
||||
g_byte_array_free (array, TRUE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
end_node (p);
|
||||
}
|
||||
|
@ -156,6 +156,7 @@ gsk_deps = [
|
||||
graphene_dep,
|
||||
pango_dep,
|
||||
cairo_dep,
|
||||
cairo_csi_dep,
|
||||
pixbuf_dep,
|
||||
libgdk_dep,
|
||||
]
|
||||
|
@ -62,6 +62,8 @@ typedef enum
|
||||
* deprecated and will be removed in a future version
|
||||
* @GTK_CSS_PARSER_WARNING_SYNTAX: A syntax construct was used
|
||||
* that should be avoided
|
||||
* @GTK_CSS_PARSER_WARNING_UNIMPLEMENTED: A feature is not
|
||||
* implemented
|
||||
*
|
||||
* Warnings that can occur while parsing CSS.
|
||||
*
|
||||
|
@ -461,11 +461,14 @@ if cc.get_id() == 'msvc'
|
||||
endif
|
||||
endif
|
||||
|
||||
cairo_csi_dep = cc.find_library('cairo-script-interpreter')
|
||||
|
||||
if not harfbuzz_dep.found()
|
||||
harfbuzz_dep = dependency('harfbuzz', version: '>= 0.9', required: false,
|
||||
fallback: ['harfbuzz', 'libharfbuzz_dep'])
|
||||
endif
|
||||
|
||||
cdata.set('HAVE_CAIRO_SCRIPT_INTERPRETER', cairo_csi_dep.found())
|
||||
cdata.set('HAVE_HARFBUZZ', harfbuzz_dep.found())
|
||||
cdata.set('HAVE_PANGOFT', pangoft_dep.found())
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 153 B After Width: | Height: | Size: 1.3 KiB |
7
testsuite/gsk/compare/scaled-cairo.node
Normal file
7
testsuite/gsk/compare/scaled-cairo.node
Normal file
@ -0,0 +1,7 @@
|
||||
transform {
|
||||
transform: scale(0.5);
|
||||
child: cairo {
|
||||
bounds: 0 0 100 100;
|
||||
script: url("data:;base64,JSFDYWlyb1NjcmlwdAo8PCAvY29udGVudCAvL0NPTE9SX0FMUEhBIC93aWR0aCA1MCAvaGVpZ2h0IDUwID4+IHN1cmZhY2UgY29udGV4dAoxIDAgMC44IHJnYiBzZXQtc291cmNlCnBhaW50CnBvcAo=");
|
||||
}
|
||||
}
|
BIN
testsuite/gsk/compare/scaled-cairo.png
Normal file
BIN
testsuite/gsk/compare/scaled-cairo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 151 B |
@ -23,6 +23,7 @@ compare_render_tests = [
|
||||
'clip-coordinates-3d',
|
||||
'clipped_rounded_clip',
|
||||
'color-blur0',
|
||||
'color-matrix-identity',
|
||||
'cross-fade-in-opacity',
|
||||
'empty-blend',
|
||||
'empty-blur',
|
||||
@ -50,9 +51,9 @@ compare_render_tests = [
|
||||
'outset_shadow_offset_y',
|
||||
'outset_shadow_rounded_top',
|
||||
'outset_shadow_simple',
|
||||
'scaled-cairo',
|
||||
'shadow-in-opacity',
|
||||
'texture-url',
|
||||
'color-matrix-identity',
|
||||
]
|
||||
|
||||
renderers = [
|
||||
|
@ -1,5 +1,3 @@
|
||||
cairo {
|
||||
bounds: 0 0 50 50;
|
||||
pixels: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAABmJLR0QA/wD/AP+gvaeTAAAATklEQVRYhe3OMQHAIADAMJh/aXgCA3t6wZEoyNxjjfd8twP/tAqtQqvQKrQKrUKr0Cq0Cq1Cq9AqtAqtQqvQKrQKrUKr0Cq0Cq1Cq9AqDsEHAi9RKkB7AAAAAElFTkSuQmCC");
|
||||
script: url("data:;base64,JSFDYWlyb1NjcmlwdAo8PCAvY29udGVudCAvL0NPTE9SX0FMUEhBIC93aWR0aCA1MCAvaGVpZ2h0IDUwID4+IHN1cmZhY2UgY29udGV4dAoxIDAgMC44IHJnYiBzZXQtc291cmNlCnBhaW50CnBvcAo=");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user