diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c
index 4a50751f0e..e2e292964d 100644
--- a/gdk/gdkgltexture.c
+++ b/gdk/gdkgltexture.c
@@ -108,6 +108,37 @@ gdk_gl_texture_run (GdkGLTexture *self,
while (g_atomic_int_get (&invoke.spinlock) == 0);
}
+static inline void
+gdk_gl_texture_get_tex_image (GdkGLTexture *self,
+ GLenum gl_format,
+ GLenum gl_type,
+ GLvoid *data)
+{
+ if (gdk_gl_context_get_use_es (self->context))
+ {
+ GdkTexture *texture = GDK_TEXTURE (self);
+ GLuint fbo;
+
+ glGenFramebuffers (1, &fbo);
+ glBindFramebuffer (GL_FRAMEBUFFER, fbo);
+ glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->id, 0);
+ glReadPixels (0, 0,
+ texture->width, texture->height,
+ gl_format,
+ gl_type,
+ data);
+ glBindFramebuffer (GL_FRAMEBUFFER, 0);
+ glDeleteFramebuffers (1, &fbo);
+ }
+ else
+ {
+ glGetTexImage (GL_TEXTURE_2D,
+ 0,
+ gl_format,
+ gl_type,
+ data);
+ }
+}
static void
gdk_gl_texture_do_download_texture (gpointer texture_,
gpointer result_)
@@ -185,11 +216,10 @@ gdk_gl_texture_do_download_texture (gpointer texture_,
stride = gdk_memory_format_bytes_per_pixel (format) * texture->width;
data = g_malloc (stride * texture->height);
- glGetTexImage (GL_TEXTURE_2D,
- 0,
- gl_format,
- gl_type,
- data);
+ gdk_gl_texture_get_tex_image (texture_,
+ gl_format,
+ gl_type,
+ data);
bytes = g_bytes_new_take (data, stride * texture->height);
*result = gdk_memory_texture_new (texture->width,
@@ -230,7 +260,6 @@ gdk_gl_texture_do_download (gpointer texture,
#error "Unknown byte order for gdk_gl_texture_download()"
#endif
data);
-
}
static void
@@ -273,8 +302,6 @@ gdk_gl_texture_download_float (GdkTexture *texture,
gsize stride)
{
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
- int width, height, y;
- float *copy;
if (self->saved)
{
@@ -282,22 +309,14 @@ gdk_gl_texture_download_float (GdkTexture *texture,
return;
}
- width = gdk_texture_get_width (texture);
- height = gdk_texture_get_height (texture);
-
- if (stride == width * 4)
+ if (gdk_gl_context_get_use_es (self->context) ||
+ stride != texture->width * 4)
{
- gdk_gl_texture_run (self, gdk_gl_texture_do_download_float, data);
+ GDK_TEXTURE_CLASS (gdk_gl_texture_parent_class)->download_float (texture, data, stride);
return;
}
- copy = g_new (float, width * height * 4);
-
- gdk_gl_texture_run (self, gdk_gl_texture_do_download_float, copy);
- for (y = 0; y < height; y++)
- memcpy (data + y * stride, copy + y * 4 * width, 4 * width);
-
- g_free (copy);
+ gdk_gl_texture_run (self, gdk_gl_texture_do_download_float, data);
}
static void
diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c
index edcf7a9d9c..ec03c72370 100644
--- a/gdk/gdktexture.c
+++ b/gdk/gdktexture.c
@@ -441,6 +441,39 @@ gdk_texture_new_from_bytes (GBytes *bytes,
return texture;
}
+/**
+ * gdk_texture_new_from_filename:
+ * @path: (type filename): the filename to load
+ * @error: Return location for an error
+ *
+ * Creates a new texture by loading an image from a file.
+ *
+ * The file format is detected automatically. The supported formats
+ * are PNG and JPEG, though more formats might be available.
+ *
+ * If %NULL is returned, then @error will be set.
+ *
+ * Return value: A newly-created `GdkTexture`
+ */
+GdkTexture *
+gdk_texture_new_from_filename (const char *path,
+ GError **error)
+{
+ GdkTexture *texture;
+ GFile *file;
+
+ g_return_val_if_fail (path, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ file = g_file_new_for_path (path);
+
+ texture = gdk_texture_new_from_file (file, error);
+
+ g_object_unref (file);
+
+ return texture;
+}
+
/**
* gdk_texture_get_width: (attributes org.gtk.Method.get_property=width)
* @texture: a `GdkTexture`
diff --git a/gdk/gdktexture.h b/gdk/gdktexture.h
index 7cccdb5928..e080679ca1 100644
--- a/gdk/gdktexture.h
+++ b/gdk/gdktexture.h
@@ -50,6 +50,9 @@ GDK_AVAILABLE_IN_ALL
GdkTexture * gdk_texture_new_from_file (GFile *file,
GError **error);
GDK_AVAILABLE_IN_4_6
+GdkTexture * gdk_texture_new_from_filename (const char *path,
+ GError **error);
+GDK_AVAILABLE_IN_4_6
GdkTexture * gdk_texture_new_from_bytes (GBytes *bytes,
GError **error);
diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c
index 9aa091001f..c4c721e2e3 100644
--- a/gsk/gskrendernodeparser.c
+++ b/gsk/gskrendernodeparser.c
@@ -802,6 +802,11 @@ parse_glyphs (GtkCssParser *parser,
gi.attr.is_cluster_start = 0;
else
gi.attr.is_cluster_start = 1;
+
+ if (gtk_css_parser_try_ident (parser, "color"))
+ gi.attr.is_color = 1;
+ else
+ gi.attr.is_color = 0;
}
pango_glyph_string_set_size (glyph_string, glyph_string->num_glyphs + 1);
@@ -2336,7 +2341,8 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node,
glyphs[i].geometry.width == ascii->glyphs[j].geometry.width &&
glyphs[i].geometry.x_offset == 0 &&
glyphs[i].geometry.y_offset == 0 &&
- glyphs[i].attr.is_cluster_start)
+ glyphs[i].attr.is_cluster_start &&
+ !glyphs[i].attr.is_color)
{
switch (j + MIN_ASCII_GLYPH)
{
@@ -2366,6 +2372,7 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node,
g_string_append_printf (p, "%u ", glyphs[i].glyph);
string_append_double (p, (double) glyphs[i].geometry.width / PANGO_SCALE);
if (!glyphs[i].attr.is_cluster_start ||
+ glyphs[i].attr.is_color ||
glyphs[i].geometry.x_offset != 0 ||
glyphs[i].geometry.y_offset != 0)
{
@@ -2375,6 +2382,8 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node,
string_append_double (p, (double) glyphs[i].geometry.y_offset / PANGO_SCALE);
if (!glyphs[i].attr.is_cluster_start)
g_string_append (p, " same-cluster");
+ if (!glyphs[i].attr.is_color)
+ g_string_append (p, " color");
}
if (i + 1 < n_glyphs)
diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c
index 4b04310e66..4cccd89ba5 100644
--- a/gsk/ngl/gsknglrenderjob.c
+++ b/gsk/ngl/gsknglrenderjob.c
@@ -252,6 +252,9 @@ node_supports_transform (const GskRenderNode *node)
case GSK_TEXT_NODE:
return TRUE;
+ case GSK_SHADOW_NODE:
+ return node_supports_transform (gsk_shadow_node_get_child (node));
+
case GSK_TRANSFORM_NODE:
return node_supports_transform (gsk_transform_node_get_child (node));
@@ -1734,7 +1737,7 @@ gsk_ngl_render_job_visit_rect_border_node (GskNglRenderJob *job,
{
rgba_to_half (&colors[2], color);
gsk_ngl_render_job_draw_rect_with_color (job,
- &GRAPHENE_RECT_INIT (origin->x + widths[3], origin->y + size->height - widths[2], size->width - widths[1], widths[2]),
+ &GRAPHENE_RECT_INIT (origin->x + widths[3], origin->y + size->height - widths[2], size->width - widths[3], widths[2]),
color);
}
@@ -2768,6 +2771,58 @@ gsk_ngl_render_job_visit_cross_fade_node (GskNglRenderJob *job,
gsk_ngl_render_job_end_draw (job);
}
+static gboolean
+is_non_branching (const GskRenderNode *node)
+{
+ switch ((int)gsk_render_node_get_node_type (node))
+ {
+ case GSK_COLOR_NODE:
+ case GSK_LINEAR_GRADIENT_NODE:
+ case GSK_REPEATING_LINEAR_GRADIENT_NODE:
+ case GSK_RADIAL_GRADIENT_NODE:
+ case GSK_REPEATING_RADIAL_GRADIENT_NODE:
+ case GSK_CONIC_GRADIENT_NODE:
+ case GSK_BORDER_NODE:
+ case GSK_TEXTURE_NODE:
+ case GSK_INSET_SHADOW_NODE:
+ case GSK_OUTSET_SHADOW_NODE:
+ case GSK_TEXT_NODE:
+ case GSK_CAIRO_NODE:
+ return TRUE;
+
+ case GSK_TRANSFORM_NODE:
+ return is_non_branching (gsk_transform_node_get_child (node));
+
+ case GSK_OPACITY_NODE:
+ return is_non_branching (gsk_opacity_node_get_child (node));
+
+ case GSK_COLOR_MATRIX_NODE:
+ return is_non_branching (gsk_color_matrix_node_get_child (node));
+
+ case GSK_CLIP_NODE:
+ return is_non_branching (gsk_clip_node_get_child (node));
+
+ case GSK_ROUNDED_CLIP_NODE:
+ return is_non_branching (gsk_rounded_clip_node_get_child (node));
+
+ case GSK_SHADOW_NODE:
+ return is_non_branching (gsk_shadow_node_get_child (node));
+
+ case GSK_BLUR_NODE:
+ return is_non_branching (gsk_shadow_node_get_child (node));
+
+ case GSK_DEBUG_NODE:
+ return is_non_branching (gsk_debug_node_get_child (node));
+
+ case GSK_CONTAINER_NODE:
+ return gsk_container_node_get_n_children (node) == 1 &&
+ is_non_branching (gsk_container_node_get_child (node, 0));
+
+ default:
+ return FALSE;
+ }
+}
+
static inline void
gsk_ngl_render_job_visit_opacity_node (GskNglRenderJob *job,
const GskRenderNode *node)
@@ -2780,7 +2835,16 @@ gsk_ngl_render_job_visit_opacity_node (GskNglRenderJob *job,
{
float prev_alpha = gsk_ngl_render_job_set_alpha (job, new_alpha);
- if (gsk_render_node_get_node_type (child) == GSK_CONTAINER_NODE)
+ /* Handle a few easy cases without offscreen. We bail out
+ * as soon as we see nodes with multiple children - in theory,
+ * we would only need offscreens for overlapping children.
+ */
+ if (is_non_branching (child))
+ {
+ gsk_ngl_render_job_visit_node (job, child);
+ gsk_ngl_render_job_set_alpha (job, prev_alpha);
+ }
+ else
{
GskNglRenderOffscreen offscreen = {0};
@@ -2788,9 +2852,7 @@ gsk_ngl_render_job_visit_opacity_node (GskNglRenderJob *job,
offscreen.force_offscreen = TRUE;
offscreen.reset_clip = TRUE;
- /* The semantics of an opacity node mandate that when, e.g., two
- * color nodes overlap, there may not be any blending between them.
- */
+ /* Note: offscreen rendering resets alpha to 1.0 */
if (!gsk_ngl_render_job_visit_node_with_offscreen (job, child, &offscreen))
return;
@@ -2805,10 +2867,6 @@ gsk_ngl_render_job_visit_opacity_node (GskNglRenderJob *job,
gsk_ngl_render_job_draw_offscreen (job, &node->bounds, &offscreen);
gsk_ngl_render_job_end_draw (job);
}
- else
- {
- gsk_ngl_render_job_visit_node (job, child);
- }
gsk_ngl_render_job_set_alpha (job, prev_alpha);
}
@@ -3000,21 +3058,24 @@ gsk_ngl_render_job_visit_shadow_node (GskNglRenderJob *job,
graphene_rect_t bounds;
guint16 color[4];
- if (shadow->radius == 0 &&
- gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
- {
- gsk_ngl_render_job_offset (job, dx, dy);
- gsk_ngl_render_job_visit_text_node (job, shadow_child, &shadow->color, TRUE);
- gsk_ngl_render_job_offset (job, -dx, -dy);
- continue;
- }
-
if (RGBA_IS_CLEAR (&shadow->color))
continue;
if (node_is_invisible (shadow_child))
continue;
+ if (shadow->radius == 0 &&
+ gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
+ {
+ if (dx != 0 || dy != 0)
+ {
+ gsk_ngl_render_job_offset (job, dx, dy);
+ gsk_ngl_render_job_visit_text_node (job, shadow_child, &shadow->color, TRUE);
+ gsk_ngl_render_job_offset (job, -dx, -dy);
+ }
+ continue;
+ }
+
if (shadow->radius > 0)
{
float min_x;
@@ -3999,7 +4060,7 @@ gsk_ngl_render_job_new (GskNglDriver *driver,
job->scale_y = scale_factor;
job->viewport = *viewport;
- gsk_ngl_render_job_set_alpha (job, 1.0);
+ gsk_ngl_render_job_set_alpha (job, 1.0f);
gsk_ngl_render_job_set_projection_from_rect (job, viewport, NULL);
gsk_ngl_render_job_set_modelview (job, gsk_transform_scale (NULL, scale_factor, scale_factor));
diff --git a/tests/rendernode.c b/tests/rendernode.c
index d0e3230663..a758cd964c 100644
--- a/tests/rendernode.c
+++ b/tests/rendernode.c
@@ -49,6 +49,7 @@ main(int argc, char **argv)
gsize len;
int run;
GOptionContext *context;
+ GdkTexture *texture;
context = g_option_context_new ("NODE-FILE PNG-FILE");
g_option_context_add_main_entries (context, options, NULL);
@@ -109,9 +110,16 @@ main(int argc, char **argv)
{
graphene_rect_t bounds;
cairo_t *cr;
+ int width, height, stride;
+ guchar *pixels;
gsk_render_node_get_bounds (node, &bounds);
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ceil (bounds.size.width), ceil (bounds.size.height));
+ width = ceil (bounds.size.width);
+ height = ceil (bounds.size.height);
+ stride = width * 4;
+ pixels = g_malloc0_n (stride, height);
+
+ surface = cairo_image_surface_create_for_data (pixels, CAIRO_FORMAT_ARGB32, width, height, stride);
cr = cairo_create (surface);
cairo_translate (cr, - bounds.origin.x, - bounds.origin.y);
@@ -132,15 +140,23 @@ main(int argc, char **argv)
}
cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ bytes = g_bytes_new_take (pixels, stride * height);
+ texture = gdk_memory_texture_new (width, height,
+ GDK_MEMORY_DEFAULT,
+ bytes,
+ stride);
+ g_bytes_unref (bytes);
}
else
{
GskRenderer *renderer;
GdkSurface *window;
- GdkTexture *texture = NULL;
window = gdk_surface_new_toplevel (gdk_display_get_default());
renderer = gsk_renderer_new_for_surface (window);
+ texture = NULL; /* poor gcc can't see that runs > 0 */
for (run = 0; run < runs; run++)
{
@@ -153,15 +169,7 @@ main(int argc, char **argv)
g_print ("Run %u: Rendered using %s in %.4gs\n", run, G_OBJECT_TYPE_NAME (renderer), (double) (end - start) / G_USEC_PER_SEC);
}
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- gdk_texture_get_width (texture),
- gdk_texture_get_height (texture));
- gdk_texture_download (texture,
- cairo_image_surface_get_data (surface),
- cairo_image_surface_get_stride (surface));
- cairo_surface_mark_dirty (surface);
gsk_renderer_unrealize (renderer);
- g_object_unref (texture);
g_object_unref (window);
g_object_unref (renderer);
}
@@ -170,19 +178,15 @@ main(int argc, char **argv)
if (argc > 2)
{
- cairo_status_t status;
-
- status = cairo_surface_write_to_png (surface, argv[2]);
-
- if (status != CAIRO_STATUS_SUCCESS)
+ if (!gdk_texture_save_to_png (texture, argv[2]))
{
- cairo_surface_destroy (surface);
- g_print ("Failed to save PNG file: %s\n", cairo_status_to_string (status));
+ g_object_unref (texture);
+ g_print ("Failed to save PNG file\n");
return 1;
}
}
- cairo_surface_destroy (surface);
+ g_object_unref (texture);
return 0;
}
diff --git a/testsuite/gdk/texture-threads.c b/testsuite/gdk/texture-threads.c
index e4587b12a1..ca970ab3e2 100644
--- a/testsuite/gdk/texture-threads.c
+++ b/testsuite/gdk/texture-threads.c
@@ -11,6 +11,7 @@ ensure_texture_access (GdkTexture *texture)
guint32 pixel = 0;
float float_pixel[4] = { INFINITY, INFINITY, INFINITY, INFINITY };
+ g_test_message ("Checking texture access in thread %p...", g_thread_self());
/* Just to be sure */
g_assert_cmpint (gdk_texture_get_width (texture), ==, 1);
g_assert_cmpint (gdk_texture_get_height (texture), ==, 1);
@@ -25,6 +26,8 @@ ensure_texture_access (GdkTexture *texture)
g_assert_cmpfloat (float_pixel[1], ==, 0.0);
g_assert_cmpfloat (float_pixel[2], ==, 0.0);
g_assert_cmpfloat (float_pixel[3], ==, 1.0);
+
+ g_test_message ("...done in thread %p", g_thread_self());
}
static void
@@ -43,8 +46,18 @@ texture_download_thread (GTask *task,
gpointer unused,
GCancellable *cancellable)
{
+ g_test_message ("Starting thread %p.", g_thread_self());
+ /* not sure this can happen, but if it does, we
+ * should clear_current() here. */
+ g_assert_null (gdk_gl_context_get_current ());
+
ensure_texture_access (GDK_TEXTURE (texture));
+ /* Makes sure the GL context is still NULL, because all the
+ * GL stuff should have happened in the main thread. */
+ g_assert_null (gdk_gl_context_get_current ());
+ g_test_message ("Returning from thread %p.", g_thread_self());
+
g_task_return_boolean (task, TRUE);
}
@@ -76,20 +89,26 @@ texture_threads (void)
ensure_texture_access (texture);
g_assert_nonnull (gdk_gl_context_get_current ());
- /* 4. Run a thread trying to download the texture */
+ /* 4. Acquire the main loop, so the run_in_thread() doesn't
+ * try to acquire it if it manages to outrace this thread.
+ */
+ g_assert_true (g_main_context_acquire (NULL));
+
+ /* 5. Run a thread trying to download the texture */
loop = g_main_loop_new (NULL, TRUE);
task = g_task_new (texture, NULL, texture_download_done, loop);
g_task_run_in_thread (task, texture_download_thread);
g_clear_object (&task);
- /* 5. Run the main loop waiting for the thread to return */
+ /* 6. Run the main loop waiting for the thread to return */
g_main_loop_run (loop);
- /* 6. All good */
+ /* 7. All good */
gsk_renderer_unrealize (gl_renderer);
g_clear_pointer (&loop, g_main_loop_unref);
g_clear_object (&gl_renderer);
g_clear_object (&surface);
+ g_main_context_release (NULL);
}
int
diff --git a/testsuite/gsk/compare-render.c b/testsuite/gsk/compare-render.c
index a62252ab35..919957e70d 100644
--- a/testsuite/gsk/compare-render.c
+++ b/testsuite/gsk/compare-render.c
@@ -99,16 +99,16 @@ get_output_file (const char *file,
}
static void
-save_image (cairo_surface_t *surface,
- const char *test_name,
- const char *extension)
+save_image (GdkTexture *texture,
+ const char *test_name,
+ const char *extension)
{
char *filename = get_output_file (test_name, ".node", extension);
- int status;
+ gboolean result;
g_print ("Storing test result image at %s\n", filename);
- status = cairo_surface_write_to_png (surface, filename);
- g_assert_true (status == CAIRO_STATUS_SUCCESS);
+ result = gdk_texture_save_to_png (texture, filename);
+ g_assert_true (result);
g_free (filename);
}
@@ -149,10 +149,8 @@ static const GOptionEntry options[] = {
int
main (int argc, char **argv)
{
- cairo_surface_t *reference_surface = NULL;
- cairo_surface_t *rendered_surface = NULL;
- cairo_surface_t *diff_surface = NULL;
- GdkTexture *texture;
+ GdkTexture *reference_texture;
+ GdkTexture *rendered_texture;
GskRenderer *renderer;
GdkSurface *window;
GskRenderNode *node;
@@ -215,43 +213,36 @@ main (int argc, char **argv)
}
/* Render the .node file and download to cairo surface */
- texture = gsk_renderer_render_texture (renderer, node, NULL);
- g_assert_nonnull (texture);
-
- rendered_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- gdk_texture_get_width (texture),
- gdk_texture_get_height (texture));
- gdk_texture_download (texture,
- cairo_image_surface_get_data (rendered_surface),
- cairo_image_surface_get_stride (rendered_surface));
- cairo_surface_mark_dirty (rendered_surface);
+ rendered_texture = gsk_renderer_render_texture (renderer, node, NULL);
+ g_assert_nonnull (rendered_texture);
/* Load the given reference png file */
- reference_surface = cairo_image_surface_create_from_png (png_file);
- if (cairo_surface_status (reference_surface))
+ reference_texture = gdk_texture_new_from_filename (png_file, &error);
+ if (reference_texture == NULL)
{
- g_print ("Error loading reference surface: %s\n",
- cairo_status_to_string (cairo_surface_status (reference_surface)));
+ g_print ("Error loading reference surface: %s\n", error->message);
+ g_clear_error (&error);
success = FALSE;
}
else
{
- /* Now compare the two */
- diff_surface = reftest_compare_surfaces (rendered_surface, reference_surface);
+ GdkTexture *diff_texture;
- if (diff_surface)
+ /* Now compare the two */
+ diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
+
+ if (diff_texture)
{
- save_image (diff_surface, node_file, ".diff.png");
- cairo_surface_destroy (diff_surface);
+ save_image (diff_texture, node_file, ".diff.png");
+ g_object_unref (diff_texture);
success = FALSE;
}
}
- save_image (rendered_surface, node_file, ".out.png");
+ save_image (rendered_texture, node_file, ".out.png");
- cairo_surface_destroy (reference_surface);
- cairo_surface_destroy (rendered_surface);
- g_object_unref (texture);
+ g_object_unref (reference_texture);
+ g_object_unref (rendered_texture);
gsk_render_node_unref (node);
diff --git a/testsuite/gsk/compare/border-bottom-right.node b/testsuite/gsk/compare/border-bottom-right.node
new file mode 100644
index 0000000000..d71790a4f7
--- /dev/null
+++ b/testsuite/gsk/compare/border-bottom-right.node
@@ -0,0 +1,5 @@
+border {
+ colors: red;
+ outline: 0 0 20 20;
+ widths: 0 10 10 0;
+}
diff --git a/testsuite/gsk/compare/border-bottom-right.png b/testsuite/gsk/compare/border-bottom-right.png
new file mode 100644
index 0000000000..579f7efeb2
Binary files /dev/null and b/testsuite/gsk/compare/border-bottom-right.png differ
diff --git a/testsuite/gsk/compare/opacity-overdraw.node b/testsuite/gsk/compare/opacity-overdraw.node
new file mode 100644
index 0000000000..78057f43a8
--- /dev/null
+++ b/testsuite/gsk/compare/opacity-overdraw.node
@@ -0,0 +1,15 @@
+opacity {
+ child: transform {
+ transform: translate(15, 15);
+ child: container {
+ color {
+ bounds: -15 -15 30 30;
+ color: rgb(0,0,255);
+ }
+ color {
+ bounds: -10 -10 20 20;
+ color: rgb(255,0,0);
+ }
+ }
+ }
+}
diff --git a/testsuite/gsk/compare/opacity-overdraw.png b/testsuite/gsk/compare/opacity-overdraw.png
new file mode 100644
index 0000000000..4499664e58
Binary files /dev/null and b/testsuite/gsk/compare/opacity-overdraw.png differ
diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build
index d225653491..a857646752 100644
--- a/testsuite/gsk/meson.build
+++ b/testsuite/gsk/meson.build
@@ -23,6 +23,7 @@ compare_render_tests = [
'blend-difference',
'blend-invisible-child',
'blend-normal',
+ 'border-bottom-right',
'borders-rotated',
'borders-scaled',
'clip-coordinates-2d',
@@ -62,6 +63,7 @@ compare_render_tests = [
'issue-3615',
'nested-rounded-clips',
'opacity_clip',
+ 'opacity-overdraw',
'opacity-overlapping-children',
'outset_shadow_offset_both',
'outset_shadow_offset_x',
diff --git a/testsuite/reftests/background-image-multiple.css b/testsuite/reftests/background-image-multiple.css
index b254f4204b..f316d6e8f2 100644
--- a/testsuite/reftests/background-image-multiple.css
+++ b/testsuite/reftests/background-image-multiple.css
@@ -1,17 +1,17 @@
@import "reset-to-defaults.css";
#button1 {
- background-image: linear-gradient(alpha(red, 0.50),alpha(red,0.50)), linear-gradient(lime,lime);
+ background-image: linear-gradient(alpha(red, 0.60),alpha(red,0.60)), linear-gradient(lime,lime);
}
#button2 {
background-color: lime;
- background-image: linear-gradient(alpha(red, 0.50),alpha(red,0.50)), linear-gradient(transparent,transparent);
+ background-image: linear-gradient(alpha(red, 0.60),alpha(red,0.60)), linear-gradient(transparent,transparent);
}
#button3 {
padding: 12px;
- background-image: linear-gradient(alpha(red, 0.50),alpha(red,0.50)), linear-gradient(lime,lime);
+ background-image: linear-gradient(alpha(red, 0.60),alpha(red,0.60)), linear-gradient(lime,lime);
background-clip: content-box;
}
@@ -30,12 +30,12 @@
#ref1,
#ref2 {
- background-color: #807f00;
+ background-color: #996600;
}
#ref3 {
padding: 12px;
- background-color: #807f00;
+ background-color: #996600;
background-clip: content-box;
}
diff --git a/testsuite/reftests/background-origin.css b/testsuite/reftests/background-origin.css
index 53ad92b586..f4a3154848 100644
--- a/testsuite/reftests/background-origin.css
+++ b/testsuite/reftests/background-origin.css
@@ -7,7 +7,7 @@ window {
button {
border-width: 5px;
border-style: solid;
- border-color: rgba(255,0,0,0.5);
+ border-color: rgba(255,0,0,0.6);
padding: 10px;
background-color: rgb(0,0,255);
diff --git a/testsuite/reftests/border-corner-zero-width-rendering.css b/testsuite/reftests/border-corner-zero-width-rendering.css
index 30cdcda102..f0812a1efe 100644
--- a/testsuite/reftests/border-corner-zero-width-rendering.css
+++ b/testsuite/reftests/border-corner-zero-width-rendering.css
@@ -3,7 +3,7 @@
}
.background {
- background-color: khaki;
+ background-color: yellow;
color: purple;
}
@@ -13,21 +13,21 @@ button {
}
.top {
- border-top: 5px solid khaki;
+ border-top: 5px solid yellow;
padding-top: 0px;
}
.right {
- border-right: 5px solid khaki;
+ border-right: 5px solid yellow;
padding-right: 0px;
}
.bottom {
- border-bottom: 5px solid khaki;
+ border-bottom: 5px solid yellow;
padding-bottom: 0px;
}
.left {
- border-left: 5px solid khaki;
+ border-left: 5px solid yellow;
padding-left: 0px;
}
diff --git a/testsuite/reftests/box-order.css b/testsuite/reftests/box-order.css
deleted file mode 100644
index b4ab59b7d4..0000000000
--- a/testsuite/reftests/box-order.css
+++ /dev/null
@@ -1,32 +0,0 @@
-* {
- all: unset;
- color: transparent;
-}
-
-GtkBox *:nth-child(1) {
- background-color: red;
-}
-
-GtkBox *:nth-child(2) {
- background-color: orange;
-}
-
-GtkBox *:nth-child(3) {
- background-color: yellow;
-}
-
-GtkBox *:nth-child(4) {
- background-color: lime;
-}
-
-GtkBox *:nth-child(5) {
- background-color: blue;
-}
-
-GtkBox *:nth-child(6) {
- background-color: indigo;
-}
-
-GtkBox *:nth-child(7) {
- background-color: darkViolet;
-}
diff --git a/testsuite/reftests/box-order.ref.ui b/testsuite/reftests/box-order.ref.ui
deleted file mode 100644
index 192e27a8e7..0000000000
--- a/testsuite/reftests/box-order.ref.ui
+++ /dev/null
@@ -1,225 +0,0 @@
-
-
-
-
diff --git a/testsuite/reftests/box-order.ui b/testsuite/reftests/box-order.ui
deleted file mode 100644
index 06689143e0..0000000000
--- a/testsuite/reftests/box-order.ui
+++ /dev/null
@@ -1,245 +0,0 @@
-
-
-
- 0
-
-
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
- 0
- 0
-
-
-
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
- 0
- 1
-
-
-
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
- 0
- 2
-
-
-
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
- 0
- 3
-
-
-
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
-
- X X X
-
-
-
- 0
- 4
-
-
-
-
-
-
-
diff --git a/testsuite/reftests/gtk-reftest.c b/testsuite/reftests/gtk-reftest.c
index efe48e6480..f247ac4ef1 100644
--- a/testsuite/reftests/gtk-reftest.c
+++ b/testsuite/reftests/gtk-reftest.c
@@ -269,13 +269,13 @@ remove_extra_css (GtkStyleProvider *provider)
}
static void
-save_image (cairo_surface_t *surface,
- const char *test_name,
- const char *extension)
+save_image (GdkTexture *texture,
+ const char *test_name,
+ const char *extension)
{
GError *error = NULL;
char *filename;
- int ret;
+ gboolean ret;
filename = get_output_file (test_name, extension, &error);
if (filename == NULL)
@@ -286,8 +286,8 @@ save_image (cairo_surface_t *surface,
}
g_test_message ("Storing test result image at %s", filename);
- ret = cairo_surface_write_to_png (surface, filename);
- g_assert_true (ret == CAIRO_STATUS_SUCCESS);
+ ret = gdk_texture_save_to_png (texture, filename);
+ g_assert_true (ret);
g_free (filename);
}
@@ -296,7 +296,7 @@ static void
test_ui_file (GFile *file)
{
char *ui_file, *reference_file;
- cairo_surface_t *ui_image, *reference_image, *diff_image;
+ GdkTexture *ui_image, *reference_image, *diff_image;
GtkStyleProvider *provider;
ui_file = g_file_get_path (file);
@@ -306,25 +306,37 @@ test_ui_file (GFile *file)
ui_image = reftest_snapshot_ui_file (ui_file);
if ((reference_file = get_reference_image (ui_file)) != NULL)
- reference_image = cairo_image_surface_create_from_png (reference_file);
+ {
+ GError *error = NULL;
+
+ reference_image = gdk_texture_new_from_filename (reference_file, &error);
+ if (reference_image == NULL)
+ {
+ g_test_message ("Failed to load reference image: %s", error->message);
+ g_clear_error (&error);
+ g_test_fail ();
+ }
+ }
else if ((reference_file = get_test_file (ui_file, ".ref.ui", TRUE)) != NULL)
reference_image = reftest_snapshot_ui_file (reference_file);
else
{
- reference_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ reference_image = NULL;
g_test_message ("No reference image.");
g_test_fail ();
}
g_free (reference_file);
+ if (reference_image == NULL)
+ reference_image = gdk_memory_texture_new (1, 1, GDK_MEMORY_DEFAULT, g_bytes_new ((guchar[4]) {0, 0, 0, 0}, 4), 4);
- diff_image = reftest_compare_surfaces (ui_image, reference_image);
+ diff_image = reftest_compare_textures (ui_image, reference_image);
save_image (ui_image, ui_file, ".out.png");
save_image (reference_image, ui_file, ".ref.png");
if (diff_image)
{
save_image (diff_image, ui_file, ".diff.png");
- cairo_surface_destroy (diff_image);
+ g_object_unref (diff_image);
g_test_fail ();
}
@@ -332,8 +344,8 @@ test_ui_file (GFile *file)
g_free (ui_file);
- cairo_surface_destroy (ui_image);
- cairo_surface_destroy (reference_image);
+ g_clear_object (&ui_image);
+ g_clear_object (&reference_image);
}
static int
diff --git a/testsuite/reftests/image-compare.c b/testsuite/reftests/image-compare.c
index 07bb79e4e0..dd9c26c231 100644
--- a/testsuite/reftests/image-compare.c
+++ b/testsuite/reftests/image-compare.c
@@ -10,9 +10,9 @@ static gboolean opt_quiet;
int
main (int argc, char **argv)
{
- cairo_surface_t *image1;
- cairo_surface_t *image2;
- cairo_surface_t *diff;
+ GdkTexture *image1;
+ GdkTexture *image2;
+ GdkTexture *diff;
GOptionEntry entries[] = {
{"output", 'o', 0, G_OPTION_ARG_FILENAME, &opt_filename, "Output location", "FILE" },
{"quiet", 'q', 0, G_OPTION_ARG_NONE, &opt_quiet, "Don't talk", NULL },
@@ -38,13 +38,29 @@ main (int argc, char **argv)
exit (1);
}
- image1 = cairo_image_surface_create_from_png (argv[1]);
- image2 = cairo_image_surface_create_from_png (argv[2]);
+ image1 = gdk_texture_new_from_filename (argv[1], &error);
+ if (image1 == NULL)
+ {
+ g_printerr ("Error loading %s: %s\n", argv[1], error->message);
+ exit (1);
+ }
+ image2 = gdk_texture_new_from_filename (argv[2], &error);
+ if (image2 == NULL)
+ {
+ g_printerr ("Error loading %s: %s\n", argv[2], error->message);
+ exit (1);
+ }
- diff = reftest_compare_surfaces (image1, image2);
+ diff = reftest_compare_textures (image1, image2);
if (opt_filename && diff)
- cairo_surface_write_to_png (diff, opt_filename);
+ {
+ if (!gdk_texture_save_to_png (diff, opt_filename))
+ {
+ g_printerr ("Could not save diff image to %s\n", opt_filename);
+ exit (1);
+ }
+ }
if (!opt_quiet)
{
@@ -59,7 +75,5 @@ main (int argc, char **argv)
g_print ("No differences.\n");
}
- if (!opt_quiet)
-
return diff != NULL ? 1 : 0;
}
diff --git a/testsuite/reftests/label-attribute-preference.ref.ui b/testsuite/reftests/label-attribute-preference.ref.ui
index 6ef8fdc0cd..942bf5e8d6 100644
--- a/testsuite/reftests/label-attribute-preference.ref.ui
+++ b/testsuite/reftests/label-attribute-preference.ref.ui
@@ -6,12 +6,12 @@
Hello linky World
-
+
-
-
+
+
diff --git a/testsuite/reftests/label-attribute-preference.ui b/testsuite/reftests/label-attribute-preference.ui
index 9f1f53d17c..da2b8dde31 100644
--- a/testsuite/reftests/label-attribute-preference.ui
+++ b/testsuite/reftests/label-attribute-preference.ui
@@ -5,10 +5,10 @@
1
- H<span color="#008000">ell</span>o <a href="http://example.com">l<span color="#00FF00">in</span>ky</a> <span color="#80FF80">Worl</span>d
+ H<span color="#009900">ell</span>o <a href="http://example.com">l<span color="#00FF00">in</span>ky</a> <span color="#99FF99">Worl</span>d
-
+
diff --git a/testsuite/reftests/meson.build b/testsuite/reftests/meson.build
index c166233ad9..a7c295137e 100644
--- a/testsuite/reftests/meson.build
+++ b/testsuite/reftests/meson.build
@@ -150,9 +150,6 @@ testdata = [
'border-style.ui',
'boxlayout-invisible-child.ref.ui',
'boxlayout-invisible-child.ui',
- 'box-order.css',
- 'box-order.ref.ui',
- 'box-order.ui',
'box-pseudo-classes.css',
'box-pseudo-classes.ref.ui',
'box-pseudo-classes.ui',
@@ -466,11 +463,12 @@ xfails = [
'sizegroups-evolution-identity-page.ui',
# these depend on details of text layout
'label-sizing.ui',
+ # the NGL renderer can't deal with non-integer sizes
+ 'border-half-pixel.ui'
]
reftest_env = environment()
reftest_env.set('GTK_A11Y', 'test')
-reftest_env.set('GSK_RENDERER', 'opengl')
reftest_env.set('G_TEST_SRCDIR', meson.current_source_dir())
reftest_env.set('G_TEST_BUILDDIR', meson.current_build_dir())
reftest_env.set('GIO_USE_VFS', 'local')
diff --git a/testsuite/reftests/reference-background-origin.png b/testsuite/reftests/reference-background-origin.png
index 3d02cb5b96..67e9c5816c 100644
Binary files a/testsuite/reftests/reference-background-origin.png and b/testsuite/reftests/reference-background-origin.png differ
diff --git a/testsuite/reftests/reftest-compare.c b/testsuite/reftests/reftest-compare.c
index 5bccb697b8..bb6c6ebc1a 100644
--- a/testsuite/reftests/reftest-compare.c
+++ b/testsuite/reftests/reftest-compare.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Red Hat Inc.
+ * Copyright (C) 2011,2021 Red Hat Inc.
*
* Author:
* Benjamin Otte
@@ -22,62 +22,14 @@
#include "reftest-compare.h"
-static void
-get_surface_size (cairo_surface_t *surface,
- int *width,
- int *height)
-{
- cairo_t *cr;
- double x1, x2, y1, y2;
-
- cr = cairo_create (surface);
- cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
- cairo_destroy (cr);
-
- g_assert_true (x1 == 0 && y1 == 0);
- g_assert_true (x2 > 0 && y2 > 0);
- g_assert_true ((int) x2 == x2 && (int) y2 == y2);
-
- *width = x2;
- *height = y2;
-}
-
-
-static cairo_surface_t *
-coerce_surface_for_comparison (cairo_surface_t *surface,
- int width,
- int height)
-{
- cairo_surface_t *coerced;
- cairo_t *cr;
-
- coerced = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- width,
- height);
- cr = cairo_create (coerced);
-
- cairo_set_source_surface (cr, surface, 0, 0);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint (cr);
-
- cairo_destroy (cr);
-
- g_assert_true (cairo_surface_status (coerced) == CAIRO_STATUS_SUCCESS);
-
- return coerced;
-}
-
-/* Compares two CAIRO_FORMAT_ARGB32 buffers, returning NULL if the
+/* Compares two GDK_MEMORY_DEFAULT buffers, returning NULL if the
* buffers are equal or a surface containing a diff between the two
* surfaces.
*
- * This function should be rewritten to compare all formats supported by
- * cairo_format_t instead of taking a mask as a parameter.
- *
* This function is originally from cairo:test/buffer-diff.c.
* Copyright © 2004 Richard D. Worth
*/
-static cairo_surface_t *
+static GdkTexture *
buffer_diff_core (const guchar *buf_a,
int stride_a,
const guchar *buf_b,
@@ -88,7 +40,7 @@ buffer_diff_core (const guchar *buf_a,
int x, y;
guchar *buf_diff = NULL;
int stride_diff = 0;
- cairo_surface_t *diff = NULL;
+ GdkTexture *diff = NULL;
for (y = 0; y < height; y++)
{
@@ -112,12 +64,15 @@ buffer_diff_core (const guchar *buf_a,
if (diff == NULL)
{
- diff = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
- width,
- height);
- g_assert_true (cairo_surface_status (diff) == CAIRO_STATUS_SUCCESS);
- buf_diff = cairo_image_surface_get_data (diff);
- stride_diff = cairo_image_surface_get_stride (diff);
+ GBytes *bytes;
+
+ stride_diff = 4 * width;
+ buf_diff = g_malloc0_n (stride_diff, height);
+ bytes = g_bytes_new_take (buf_diff, stride_diff * height);
+ diff = gdk_memory_texture_new (width, height,
+ GDK_MEMORY_DEFAULT,
+ bytes,
+ stride_diff);
row = (guint32 *) (buf_diff + y * stride_diff);
}
@@ -143,6 +98,8 @@ buffer_diff_core (const guchar *buf_a,
guint8 alpha = diff_pixel >> 24;
diff_pixel = alpha * 0x010101;
}
+ /* make the pixel fully opaque */
+ diff_pixel |= 0xff000000;
row[x] = diff_pixel;
}
@@ -151,29 +108,28 @@ buffer_diff_core (const guchar *buf_a,
return diff;
}
-cairo_surface_t *
-reftest_compare_surfaces (cairo_surface_t *surface1,
- cairo_surface_t *surface2)
+GdkTexture *
+reftest_compare_textures (GdkTexture *texture1,
+ GdkTexture *texture2)
{
- int w1, h1, w2, h2, w, h;
- cairo_surface_t *coerced1, *coerced2, *diff;
+ int w, h;
+ guchar *data1, *data2;
+ GdkTexture *diff;
- get_surface_size (surface1, &w1, &h1);
- get_surface_size (surface2, &w2, &h2);
- w = MAX (w1, w2);
- h = MAX (h1, h2);
- coerced1 = coerce_surface_for_comparison (surface1, w, h);
- coerced2 = coerce_surface_for_comparison (surface2, w, h);
+ w = MAX (gdk_texture_get_width (texture1), gdk_texture_get_width (texture2));
+ h = MAX (gdk_texture_get_height (texture1), gdk_texture_get_height (texture2));
- diff = buffer_diff_core (cairo_image_surface_get_data (coerced1),
- cairo_image_surface_get_stride (coerced1),
- cairo_image_surface_get_data (coerced2),
- cairo_image_surface_get_stride (coerced2),
+ data1 = g_malloc_n (w * 4, h);
+ gdk_texture_download (texture1, data1, w * 4);
+ data2 = g_malloc_n (w * 4, h);
+ gdk_texture_download (texture2, data2, w * 4);
+
+ diff = buffer_diff_core (data1, w * 4,
+ data2, w * 4,
w, h);
- cairo_surface_destroy (coerced1);
- cairo_surface_destroy (coerced2);
+ g_free (data1);
+ g_free (data2);
return diff;
}
-
diff --git a/testsuite/reftests/reftest-compare.h b/testsuite/reftests/reftest-compare.h
index 551b1c5a92..d5e02a1a7d 100644
--- a/testsuite/reftests/reftest-compare.h
+++ b/testsuite/reftests/reftest-compare.h
@@ -23,8 +23,8 @@
G_BEGIN_DECLS
G_MODULE_EXPORT
-cairo_surface_t * reftest_compare_surfaces (cairo_surface_t *surface1,
- cairo_surface_t *surface2);
+GdkTexture * reftest_compare_textures (GdkTexture *texture1,
+ GdkTexture *texture2);
G_END_DECLS
diff --git a/testsuite/reftests/reftest-snapshot.c b/testsuite/reftests/reftest-snapshot.c
index 7a7a77fd96..1787c73ab8 100644
--- a/testsuite/reftests/reftest-snapshot.c
+++ b/testsuite/reftests/reftest-snapshot.c
@@ -215,12 +215,12 @@ reftest_uninhibit_snapshot (void)
static void
draw_paintable (GdkPaintable *paintable,
- gpointer out_surface)
+ gpointer out_texture)
{
GtkSnapshot *snapshot;
GskRenderNode *node;
- cairo_surface_t *surface;
- cairo_t *cr;
+ GdkTexture *texture;
+ GskRenderer *renderer;
if (inhibit_count > 0)
return;
@@ -238,27 +238,30 @@ draw_paintable (GdkPaintable *paintable,
if (node == NULL)
return;
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- gdk_paintable_get_intrinsic_width (paintable),
- gdk_paintable_get_intrinsic_height (paintable));
-
- cr = cairo_create (surface);
- gsk_render_node_draw (node, cr);
- cairo_destroy (cr);
+ renderer = gtk_native_get_renderer (
+ gtk_widget_get_native (
+ gtk_widget_paintable_get_widget (GTK_WIDGET_PAINTABLE (paintable))));
+ texture = gsk_renderer_render_texture (renderer,
+ node,
+ &GRAPHENE_RECT_INIT (
+ 0, 0,
+ gdk_paintable_get_intrinsic_width (paintable),
+ gdk_paintable_get_intrinsic_height (paintable)
+ ));
gsk_render_node_unref (node);
- g_signal_handlers_disconnect_by_func (paintable, draw_paintable, out_surface);
+ g_signal_handlers_disconnect_by_func (paintable, draw_paintable, out_texture);
- *(cairo_surface_t **) out_surface = surface;
+ *(GdkTexture **) out_texture = texture;
g_idle_add (quit_when_idle, loop);
}
-static cairo_surface_t *
+static GdkTexture *
snapshot_widget (GtkWidget *widget)
{
GdkPaintable *paintable;
- cairo_surface_t *surface;
+ GdkTexture *texture = NULL;
g_assert_true (gtk_widget_get_realized (widget));
@@ -270,17 +273,17 @@ snapshot_widget (GtkWidget *widget)
* to delay the snapshot.
*/
paintable = gtk_widget_paintable_new (widget);
- g_signal_connect (paintable, "invalidate-contents", G_CALLBACK (draw_paintable), &surface);
+ g_signal_connect (paintable, "invalidate-contents", G_CALLBACK (draw_paintable), &texture);
g_main_loop_run (loop);
g_main_loop_unref (loop);
g_object_unref (paintable);
gtk_window_destroy (GTK_WINDOW (widget));
- return surface;
+ return texture;
}
-cairo_surface_t *
+GdkTexture *
reftest_snapshot_ui_file (const char *ui_file)
{
GtkWidget *window;
diff --git a/testsuite/reftests/reftest-snapshot.h b/testsuite/reftests/reftest-snapshot.h
index 5a24388722..31dca9e6af 100644
--- a/testsuite/reftests/reftest-snapshot.h
+++ b/testsuite/reftests/reftest-snapshot.h
@@ -23,7 +23,7 @@
G_BEGIN_DECLS
G_MODULE_EXPORT
-cairo_surface_t * reftest_snapshot_ui_file (const char *ui_file);
+GdkTexture * reftest_snapshot_ui_file (const char *ui_file);
G_END_DECLS