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 @@ - - - - 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 - - - - 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/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