Compare commits

..

30 Commits

Author SHA1 Message Date
Matthias Clasen
34990b6dc2 gsk: Give up on text nodes with unuploadable glyphs
If we can't upload the glyphs, just give up and use fallback.
2024-01-11 14:54:34 -05:00
Matthias Clasen
8d74defbc1 gsk: Don't try to upload NULL images
It doesn't work. Just return NULL and let the caller handle it,
like we do in other cases where obtaining an image fails.
2024-01-11 06:26:23 -05:00
Matthias Clasen
fe95da256b gpu: Plug a memory leak 2024-01-11 06:25:22 -05:00
Benjamin Otte
61595af586 Merge branch 'ngl-backbuffer-leak' into 'main'
ngl: Don't leak the backbuffer

See merge request GNOME/gtk!6736
2024-01-11 11:16:31 +00:00
Matthias Clasen
d240c35850 ngl: Don't leak the backbuffer
Clear it in unrealize, just like the vulkan renderer does with
its targets.
2024-01-10 23:08:01 -05:00
Matthias Clasen
d276eb9e9a Merge branch 'test-font-tweaks' into 'main'
tests: Change the way custom fonts are handled

See merge request GNOME/gtk!6734
2024-01-11 03:33:15 +00:00
Matthias Clasen
afe4cbf26d tests: Change the way custom fonts are handled
Instead of setting FONTCONFIG_FILE to a custom font configuration,
pass the directory containing the fonts as TEST_FONTS and use
FcConfigAppFontAddDir to add them to the default font configuration.
2024-01-10 22:18:37 -05:00
Matthias Clasen
76e5ef6937 Merge branch 'node-editor-tweaks' into 'main'
node-editor: Make test fonts available

See merge request GNOME/gtk!6733
2024-01-11 02:55:50 +00:00
Matthias Clasen
0ed43f66a9 docs: Beef up the node-editor man page
Mention the GTK_SOURCE_DIR environment variable in the man page.
2024-01-10 21:10:36 -05:00
Matthias Clasen
4882514234 node-editor: Make test fonts available
Add the directory containing test fonts for gsk tests to the
font configuration, so that node files from the testsuite using
these fonts just work.
2024-01-10 21:10:36 -05:00
Matthias Clasen
a15e87d2a6 Merge branch 'mixed-color-test' into 'main'
gsk: Add another font text

See merge request GNOME/gtk!6732
2024-01-11 01:50:09 +00:00
Matthias Clasen
cc92b9b19f gsk: Add another font text
This is similar to text-mixed-color, but it uses the COLRv1 table,
to test our support for this font technology.
2024-01-10 19:44:55 -05:00
Matthias Clasen
7f06eed8da Merge branch 'hc-cleanup' into 'main'
wayland/display: Don't notify "icon-theme" on high-contrast changes

See merge request GNOME/gtk!6730
2024-01-10 21:38:55 +00:00
Matthias Clasen
dc30044829 Merge branch 'gpu-fix-mixed-color-text' into 'main'
gpu: Fix handling of mixed-color text runs

See merge request GNOME/gtk!6725
2024-01-10 18:11:23 +00:00
Matthias Clasen
781fe2d7fa gsk: Add a compare test for mixed color runs
This tests the fixes in aa82190da659b5 and dcaa2c4ccb182c74cb40.

The test uses a custom font named 'text-mixed-color' which contains
six glyphs that are just boxes. Glyphs 1, 2, 3 are just plain glyphs,
and glyphs 4, 5, 6 are color glyphs in red, green and blue.

The glyphs are mapped to the characters A, B, C, D, E, F.

The test is currently disabled for cairo, since it has some issues
with transformed color glyphs.
2024-01-10 12:49:08 -05:00
Florian Müllner
b8a61f7899 wayland/display: Don't notify "icon-theme" on high-contrast changes
Since commit c3706ea9ec, the "high-contrast" setting no longer
forces the "HighContrast" icon theme.
2024-01-10 15:46:46 +01:00
Matthias Clasen
a44ca6756a gpu: Use the right format for atlases
The glyph atlas format needs to match the cairo memory format.
NGL was getting this wrong, causing color glyphs to have their
red and blue swapped.
2024-01-10 08:00:15 -05:00
Matthias Clasen
490a9f193d gpu: Fix handling of mixed color text runs
We need to decide per-glyph whether to use coloring or texture ops.
2024-01-10 08:00:15 -05:00
Matthias Clasen
754d364efd gsk: Allow custom fonts in tests
The commit adds a custom fontconfig configuration in
testsuite/gsk/fonts/fonts.conf and sets the FONTCONFIG_FILE
environment variable for the gsk compare tests to point at it.

To use a custom font in tests, just drop it into the
testsuite/gsk/fonts/ directory.

The font configuration includes the system configuration,
so existing tests should not be affected.
2024-01-10 07:58:19 -05:00
Benjamin Otte
4939f0bb75 Merge branch 'wip/otte/for-main' into 'main'
contour: Fix stroke bounds for rect contour

See merge request GNOME/gtk!6728
2024-01-10 01:05:22 +00:00
Carlos Garnacho
7537d80047 Merge branch 'wip/show-tablet-cursor' into 'main'
gdk/wayland: reset cursor_is_default on proximity out

Closes #6312

See merge request GNOME/gtk!6720
2024-01-10 00:55:32 +00:00
Benjamin Otte
c5bdf0a995 testsuite: Add tests for pixel grid accuracy
See previous commit for details.
2024-01-10 01:33:49 +01:00
Peter Hutterer
04870fc1a1 gdk/wayland: Reset cursor_is_default on proximity out
For tablet tools if we have NULL cursor, we use the default cursor
instead. This provides us with a tablet cursor when an application never
sets the cursor.

However, on proximity out when we clear said cursor we also
need to toggle off cursor_is_default, otherwise on the next proximity in
we assume we already have a cursor and never update it again.

This leads to an invisible cursor over GTK application when the tablet
tool is brought into proximity over the widget (but not when moving into
the widget from the outside).

Closes: #6312
2024-01-10 00:25:01 +00:00
Matthias Clasen
43e5bc795a Merge branch 'log_whitespace' into 'main'
Add missing space to warning

See merge request GNOME/gtk!6729
2024-01-10 00:06:05 +00:00
Spencer Burris
f3ec58d290 Add missing space to warning 2024-01-09 16:57:26 -07:00
Benjamin Otte
5b3d14e15b gpu: respect pixel grid for Cairo rendering
Make sure fallbacks and fill/stroke masks use image surfaces with the
same pixel grid as the target if possible.

Fixes blurriness with some path renderings.
2024-01-10 00:13:52 +01:00
Benjamin Otte
131ab11f5c testsuite: Check that pixel grid math respects offsets 2024-01-10 00:13:52 +01:00
Benjamin Otte
a2eb467663 gpu: Change rect_round_pixels() to take an offset
We need to respect the offset when converting to the pixel grid, so pass
the current offset into the function.

Also move the rounded out of gsk_gpu_get_node_as_image() and into the 2
callers, because the offset is not passed into the function and I see no
reason to change that.
2024-01-10 00:13:52 +01:00
Benjamin Otte
06f85ee566 contour: Fix stroke bounds for rect contour
There's no tests for stroke bounds, oh no!
2024-01-09 23:27:55 +01:00
Benjamin Otte
aab40ad6a2 gpu: Fix text coordinates in the ubershader 2024-01-09 23:27:55 +01:00
30 changed files with 733 additions and 68 deletions

View File

@@ -19,6 +19,10 @@
#include "config.h"
#ifdef HAVE_PANGOFT
#include <pango/pangofc-fontmap.h>
#endif
#include "node-editor-application.h"
#include "node-editor-window.h"
@@ -45,11 +49,47 @@ struct _NodeEditorApplicationClass
GtkApplicationClass parent_class;
};
G_DEFINE_TYPE(NodeEditorApplication, node_editor_application, GTK_TYPE_APPLICATION);
G_DEFINE_TYPE (NodeEditorApplication, node_editor_application, GTK_TYPE_APPLICATION);
static void
maybe_add_test_fonts (void)
{
#ifdef HAVE_PANGOFT
const char *subdir = "testsuite/gsk/fonts";
const char *source_dir;
char *dir;
source_dir = g_getenv ("GTK_SOURCE_DIR");
if (source_dir)
{
char *abs_source_dir = g_canonicalize_filename (source_dir, NULL);
dir = g_canonicalize_filename (subdir, abs_source_dir);
g_free (abs_source_dir);
}
else
{
char *current_dir = g_get_current_dir ();
dir = g_canonicalize_filename (subdir, current_dir);
g_free (current_dir);
}
if (g_file_test (dir, G_FILE_TEST_EXISTS))
{
FcConfig *config;
config = FcConfigGetCurrent ();
FcConfigAppFontAddDir (config, (const FcChar8 *) dir);
}
g_free (dir);
#endif
}
static void
node_editor_application_init (NodeEditorApplication *app)
{
maybe_add_test_fonts ();
}
static void

View File

@@ -11,13 +11,17 @@ Editor render nodes
SYNOPSIS
--------
| **gtk4-node-editor** [OPTIONS...]
| **gtk4-node-editor** [OPTIONS...] [FILE]
DESCRIPTION
-----------
``gtk4-node-editor`` is a utility to show and edit render node files.
Such render node files can be obtained e.g. from the GTK inspector.
Such render node files can be obtained e.g. from the GTK inspector or
as part of the testsuite in the GTK sources.
``gtk4-node-editor`` is used by GTK developers for debugging and testing,
and it has built-in support for saving testcases as part of the GTK testsuite.
OPTIONS
-------
@@ -25,3 +29,13 @@ OPTIONS
``-h, --help``
Show the application help.
ENVIRONMENT
-----------
``GTK_SOURCE_DIR``
can be set to point to the location where the GTK sources reside, so that
testcases can be saved to the right location. If unsed, `gtk4-node-editor``
checks if the current working directory looks like a GTK checkout, and failing
that, saves testcase in the the current working directory.

View File

@@ -194,7 +194,7 @@ _gdk_wayland_cursor_get_buffer (GdkWaylandDisplay *display,
if ((image->width % cursor_scale != 0) ||
(image->height % cursor_scale != 0))
{
g_warning (G_STRLOC " cursor image size (%dx%d) not an integer"
g_warning (G_STRLOC " cursor image size (%dx%d) not an integer "
"multiple of scale (%d)", image->width, image->height,
cursor_scale);
cursor_scale = 1;

View File

@@ -1845,13 +1845,6 @@ find_translation_entry_by_setting (const char *setting)
return NULL;
}
static void
high_contrast_changed (GdkDisplay *display)
{
gdk_display_setting_changed (display, "gtk-theme-name");
gdk_display_setting_changed (display, "gtk-icon-theme-name");
}
static void
settings_changed (GSettings *settings,
const char *key,
@@ -1866,7 +1859,7 @@ settings_changed (GSettings *settings,
if (entry->type != G_TYPE_NONE)
gdk_display_setting_changed (display, entry->setting);
else if (strcmp (key, "high-contrast") == 0)
high_contrast_changed (display);
gdk_display_setting_changed (display, "gtk-theme-name");
else
update_xft_settings (display);
}

View File

@@ -2859,6 +2859,7 @@ tablet_tool_handle_proximity_out (void *data,
gdk_device_update_tool (tablet->stylus_device, NULL);
g_clear_object (&tablet->pointer_info.cursor);
tablet->pointer_info.cursor_is_default = FALSE;
}
static double *

View File

@@ -119,7 +119,7 @@ gsk_gl_device_create_atlas_image (GskGpuDevice *device,
GskGLDevice *self = GSK_GL_DEVICE (device);
return gsk_gl_image_new (self,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
GDK_MEMORY_DEFAULT,
GSK_GPU_IMAGE_RENDERABLE,
width,
height);

View File

@@ -661,19 +661,11 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
return cache->image;
}
cache = g_new (GskGpuCachedGlyph, 1);
pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
pango_extents_to_pixels (&ink_rect, NULL);
ink_rect.x -= 1;
ink_rect.width += 2;
ink_rect.y -= 1;
ink_rect.height += 2;
origin.x = floor (ink_rect.x * scale);
origin.y = floor (ink_rect.y * scale);
rect.size.width = ceil ((ink_rect.x + ink_rect.width) * scale) - origin.x;
rect.size.height = ceil ((ink_rect.y + ink_rect.height) * scale) - origin.y;
origin.x = floor (ink_rect.x * scale / PANGO_SCALE);
origin.y = floor (ink_rect.y * scale / PANGO_SCALE);
rect.size.width = ceil ((ink_rect.x + ink_rect.width) * scale / PANGO_SCALE) - origin.x;
rect.size.height = ceil ((ink_rect.y + ink_rect.height) * scale / PANGO_SCALE) - origin.y;
padding = 1;
image = gsk_gpu_device_add_atlas_image (self,
@@ -689,9 +681,13 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
}
else
{
image = gsk_gpu_device_create_upload_image (self, FALSE, GDK_MEMORY_DEFAULT, rect.size.width + 2 * padding, rect.size.height + 2 * padding),
rect.origin.x = padding;
rect.origin.y = padding;
image = gsk_gpu_device_create_upload_image (self, FALSE, GDK_MEMORY_DEFAULT, rect.size.width, rect.size.height);
if (!image)
return NULL;
rect.origin.x = 0;
rect.origin.y = 0;
padding = 0;
cache = gsk_gpu_cached_new (self, &GSK_GPU_CACHED_GLYPH_CLASS, NULL);
}

View File

@@ -305,9 +305,10 @@ gsk_gpu_node_processor_add_images (GskGpuNodeProcessor *self,
}
static void
rect_round_to_pixels (const graphene_rect_t *src,
const graphene_vec2_t *pixel_scale,
graphene_rect_t *dest)
rect_round_to_pixels (const graphene_rect_t *src,
const graphene_vec2_t *pixel_scale,
const graphene_point_t *pixel_offset,
graphene_rect_t *dest)
{
float x, y, xscale, yscale, inv_xscale, inv_yscale;
@@ -316,13 +317,13 @@ rect_round_to_pixels (const graphene_rect_t *src,
inv_xscale = 1.0f / xscale;
inv_yscale = 1.0f / yscale;
x = floorf (src->origin.x * xscale);
y = floorf (src->origin.y * yscale);
x = floorf ((src->origin.x + pixel_offset->x) * xscale);
y = floorf ((src->origin.y + pixel_offset->y) * yscale);
*dest = GRAPHENE_RECT_INIT (
x * inv_xscale,
y * inv_yscale,
(ceil ((src->origin.x + src->size.width) * xscale) - x) * inv_xscale,
(ceil ((src->origin.y + src->size.height) * yscale) - y) * inv_yscale);
x * inv_xscale - pixel_offset->x,
y * inv_yscale - pixel_offset->y,
(ceil ((src->origin.x + pixel_offset->x + src->size.width) * xscale) - x) * inv_xscale,
(ceil ((src->origin.y + pixel_offset->y + src->size.height) * yscale) - y) * inv_yscale);
}
static GskGpuImage *
@@ -787,7 +788,6 @@ gsk_gpu_get_node_as_image (GskGpuFrame *frame,
gsk_rect_intersection (clip_bounds, &node->bounds, &clipped);
if (gsk_rect_is_empty (&clipped))
return NULL;
rect_round_to_pixels (&clipped, scale, &clipped);
result = gsk_gpu_upload_cairo_op (frame,
scale,
@@ -808,7 +808,6 @@ gsk_gpu_get_node_as_image (GskGpuFrame *frame,
gsk_rect_intersection (clip_bounds, &node->bounds, &clipped);
if (gsk_rect_is_empty (&clipped))
return NULL;
rect_round_to_pixels (&clipped, scale, &clipped);
GSK_DEBUG (FALLBACK, "Offscreening node '%s'", g_type_name_from_instance ((GTypeInstance *) node));
result = gsk_gpu_render_pass_op_offscreen (frame,
@@ -931,17 +930,18 @@ gsk_gpu_node_processor_get_node_as_image (GskGpuNodeProcessor *self,
graphene_rect_t *out_bounds)
{
GskGpuImage *image, *ensure;
graphene_rect_t default_clip;
graphene_rect_t clip;
if (clip_bounds == NULL)
{
if (!gsk_gpu_node_processor_clip_node_bounds (self, node, &default_clip))
if (!gsk_gpu_node_processor_clip_node_bounds (self, node, &clip))
return NULL;
clip_bounds = &default_clip;
clip_bounds = &clip;
}
rect_round_to_pixels (clip_bounds, &self->scale, &self->offset, &clip);
image = gsk_gpu_get_node_as_image (self->frame,
clip_bounds,
&clip,
&self->scale,
node,
out_bounds);
@@ -1073,6 +1073,8 @@ gsk_gpu_node_processor_add_fallback_node (GskGpuNodeProcessor *self,
if (!gsk_gpu_node_processor_clip_node_bounds (self, node, &clipped_bounds))
return;
rect_round_to_pixels (&clipped_bounds, &self->scale, &self->offset, &clipped_bounds);
gsk_gpu_node_processor_sync_globals (self, 0);
image = gsk_gpu_upload_cairo_op (self->frame,
@@ -1426,7 +1428,7 @@ gsk_gpu_node_processor_add_rounded_clip_node_with_mask (GskGpuNodeProcessor *sel
if (!gsk_gpu_node_processor_clip_node_bounds (self, node, &clip_bounds))
return;
rect_round_to_pixels (&clip_bounds, &self->scale, &clip_bounds);
rect_round_to_pixels (&clip_bounds, &self->scale, &self->offset, &clip_bounds);
child_image = gsk_gpu_node_processor_get_node_as_image (self,
0,
@@ -2250,7 +2252,7 @@ gsk_gpu_node_processor_add_gradient_node (GskGpuNodeProcessor *self,
if (!gsk_gpu_node_processor_clip_node_bounds (self, node, &bounds))
return;
rect_round_to_pixels (&bounds, &self->scale, &bounds);
rect_round_to_pixels (&bounds, &self->scale, &self->offset, &bounds);
image = gsk_gpu_node_processor_init_draw (&other,
self->frame,
@@ -3013,12 +3015,33 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self,
&glyph_bounds,
&glyph_offset);
if (!image)
{
if (GSK_DEBUG_CHECK (FALLBACK))
{
PangoFontDescription *desc;
char *name;
desc = pango_font_describe (font);
name = pango_font_description_to_string (desc);
gdk_debug_message ("failed to cache glyph %u for font %s at scale %g",
glyphs[i].glyph,
name,
scale);
g_free (name);
pango_font_description_free (desc);
}
gsk_gpu_node_processor_add_fallback_node (self, node);
return;
}
graphene_rect_scale (&GRAPHENE_RECT_INIT (-glyph_bounds.origin.x, -glyph_bounds.origin.y, gsk_gpu_image_get_width (image), gsk_gpu_image_get_height (image)), inv_scale, inv_scale, &glyph_tex_rect);
graphene_rect_scale (&GRAPHENE_RECT_INIT(0, 0, glyph_bounds.size.width, glyph_bounds.size.height), inv_scale, inv_scale, &glyph_bounds);
glyph_offset = GRAPHENE_POINT_INIT (offset.x - glyph_offset.x * inv_scale + (float) glyphs[i].geometry.x_offset / PANGO_SCALE,
offset.y - glyph_offset.y * inv_scale + (float) glyphs[i].geometry.y_offset / PANGO_SCALE);
descriptor = gsk_gpu_node_processor_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT);
if (gsk_text_node_has_color_glyphs (node))
if (glyphs[i].attr.is_color)
gsk_gpu_texture_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &glyph_offset, &glyph_bounds),
self->desc,
@@ -3088,6 +3111,9 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
&glyph_bounds,
&glyph_offset);
if (!image)
return FALSE;
if (image != last_image)
{
if (!gsk_gpu_pattern_writer_add_image (self, image, GSK_GPU_SAMPLER_DEFAULT, &tex_id))
@@ -3096,21 +3122,26 @@ gsk_gpu_node_processor_create_glyph_pattern (GskGpuPatternWriter *self,
last_image = image;
}
graphene_rect_scale (&glyph_bounds, inv_scale, inv_scale, &glyph_bounds);
glyph_offset = GRAPHENE_POINT_INIT (offset.x - glyph_offset.x * inv_scale + (float) glyphs[i].geometry.x_offset / PANGO_SCALE,
offset.y - glyph_offset.y * inv_scale + (float) glyphs[i].geometry.y_offset / PANGO_SCALE);
gsk_gpu_pattern_writer_append_uint (self, tex_id);
gsk_gpu_pattern_writer_append_rect (self,
&glyph_bounds,
&glyph_offset);
&GRAPHENE_RECT_INIT (
0,
0,
glyph_bounds.size.width * inv_scale,
glyph_bounds.size.height * inv_scale
),
&glyph_offset);
gsk_gpu_pattern_writer_append_rect (self,
&GRAPHENE_RECT_INIT (
0, 0,
gsk_gpu_image_get_width (image) * inv_scale,
gsk_gpu_image_get_height (image) * inv_scale
),
&glyph_offset);
&GRAPHENE_RECT_INIT (
- glyph_bounds.origin.x * inv_scale,
- glyph_bounds.origin.y * inv_scale,
gsk_gpu_image_get_width (image) * inv_scale,
gsk_gpu_image_get_height (image) * inv_scale
),
&glyph_offset);
offset.x += (float) glyphs[i].geometry.width / PANGO_SCALE;
}
@@ -3476,6 +3507,7 @@ gsk_gpu_node_processor_add_fill_node (GskGpuNodeProcessor *self,
if (!gsk_gpu_node_processor_clip_node_bounds (self, node, &clip_bounds))
return;
rect_round_to_pixels (&clip_bounds, &self->scale, &self->offset, &clip_bounds);
child = gsk_fill_node_get_child (node);
@@ -3517,9 +3549,9 @@ gsk_gpu_node_processor_add_fill_node (GskGpuNodeProcessor *self,
descriptors);
gsk_gpu_mask_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &clip_bounds),
self->desc,
&node->bounds,
&clip_bounds,
&self->offset,
self->opacity,
GSK_MASK_MODE_ALPHA,
@@ -3572,6 +3604,7 @@ gsk_gpu_node_processor_add_stroke_node (GskGpuNodeProcessor *self,
if (!gsk_gpu_node_processor_clip_node_bounds (self, node, &clip_bounds))
return;
rect_round_to_pixels (&clip_bounds, &self->scale, &self->offset, &clip_bounds);
child = gsk_stroke_node_get_child (node);
@@ -3613,9 +3646,9 @@ gsk_gpu_node_processor_add_stroke_node (GskGpuNodeProcessor *self,
descriptors);
gsk_gpu_mask_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &clip_bounds),
self->desc,
&node->bounds,
&clip_bounds,
&self->offset,
self->opacity,
GSK_MASK_MODE_ALPHA,
@@ -3970,13 +4003,17 @@ gsk_gpu_node_processor_create_node_pattern (GskGpuPatternWriter *self,
gsk_gpu_descriptors_set_size (self->desc, images_before, buffers_before);
}
rect_round_to_pixels (&GRAPHENE_RECT_INIT (
self->bounds.origin.x - self->offset.x,
self->bounds.origin.y - self->offset.y,
self->bounds.size.width,
self->bounds.size.height
),
&self->scale,
&self->offset,
&bounds);
image = gsk_gpu_get_node_as_image (self->frame,
&GRAPHENE_RECT_INIT (
self->bounds.origin.x - self->offset.x,
self->bounds.origin.y - self->offset.y,
self->bounds.size.width,
self->bounds.size.height
),
&bounds,
&self->scale,
node,
&bounds);

View File

@@ -75,6 +75,12 @@ gsk_ngl_renderer_make_current (GskGpuRenderer *renderer)
gdk_gl_context_make_current (GDK_GL_CONTEXT (gsk_gpu_renderer_get_context (renderer)));
}
static void
gsk_ngl_renderer_free_backbuffer (GskNglRenderer *self)
{
g_clear_object (&self->backbuffer);
}
static GskGpuImage *
gsk_ngl_renderer_get_backbuffer (GskGpuRenderer *renderer)
{
@@ -91,7 +97,7 @@ gsk_ngl_renderer_get_backbuffer (GskGpuRenderer *renderer)
gsk_gpu_image_get_width (self->backbuffer) != ceil (gdk_surface_get_width (surface) * scale) ||
gsk_gpu_image_get_height (self->backbuffer) != ceil (gdk_surface_get_height (surface) * scale))
{
g_clear_object (&self->backbuffer);
gsk_ngl_renderer_free_backbuffer (self);
self->backbuffer = gsk_gl_image_new_backbuffer (GSK_GL_DEVICE (gsk_gpu_renderer_get_device (renderer)),
GDK_MEMORY_DEFAULT /* FIXME */,
ceil (gdk_surface_get_width (surface) * scale),
@@ -124,10 +130,21 @@ gsk_ngl_renderer_get_dmabuf_formats (GskGpuRenderer *renderer)
return display->egl_dmabuf_formats;
}
static void
gsk_ngl_renderer_unrealize (GskRenderer *renderer)
{
GskNglRenderer *self = GSK_NGL_RENDERER (renderer);
gsk_ngl_renderer_free_backbuffer (self);
GSK_RENDERER_CLASS (gsk_ngl_renderer_parent_class)->unrealize (renderer);
}
static void
gsk_ngl_renderer_class_init (GskNglRendererClass *klass)
{
GskGpuRendererClass *gpu_renderer_class = GSK_GPU_RENDERER_CLASS (klass);
GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass);
gpu_renderer_class->frame_type = GSK_TYPE_GL_FRAME;
@@ -138,6 +155,8 @@ gsk_ngl_renderer_class_init (GskNglRendererClass *klass)
gpu_renderer_class->wait = gsk_ngl_renderer_wait;
gpu_renderer_class->get_scale = gsk_ngl_renderer_get_scale;
gpu_renderer_class->get_dmabuf_formats = gsk_ngl_renderer_get_dmabuf_formats;
renderer_class->unrealize = gsk_ngl_renderer_unrealize;
}
static void

View File

@@ -1819,7 +1819,7 @@ gsk_rect_contour_get_stroke_bounds (const GskContour *contour,
graphene_rect_t rect;
graphene_rect_init (&rect, self->x, self->y, self->width, self->height);
graphene_rect_inset (&rect, - stroke->line_width, - stroke->line_width);
graphene_rect_inset (&rect, - 0.5 * stroke->line_width, - 0.5 * stroke->line_width);
gsk_bounding_box_init_from_rect (bounds, &rect);
return TRUE;

View File

@@ -1,9 +1,15 @@
#include "config.h"
#include <string.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include <stdlib.h>
#include "../reftests/reftest-compare.h"
#ifdef HAVE_PANGOFT
#include <pango/pangofc-fontmap.h>
#endif
static char *arg_output_dir = NULL;
static gboolean flip = FALSE;
static gboolean rotate = FALSE;
@@ -232,6 +238,22 @@ apply_mask_to_pixbuf (GdkPixbuf *pixbuf)
return copy;
}
static void
maybe_add_test_fonts (void)
{
#ifdef HAVE_PANGOFT
const char *dir;
dir = g_getenv ("TEST_FONT_DIR");
if (dir && g_file_test (dir, G_FILE_TEST_EXISTS))
{
FcConfig *config = FcConfigGetCurrent ();
FcConfigAppFontAddDir (config, (const FcChar8 *) dir);
}
#endif
}
/*
* Non-option arguments:
* 1) .node file to compare
@@ -252,6 +274,8 @@ main (int argc, char **argv)
GOptionContext *context;
GdkTexture *diff_texture;
maybe_add_test_fonts ();
(g_test_init) (&argc, &argv, NULL);
context = g_option_context_new ("NODE REF - run GSK node tests");

View File

@@ -0,0 +1,27 @@
color {
bounds: 0 0 15 15;
color: rgb(0,0,0);
}
transform {
transform: translate(2, 2.6);
child: fill {
child: linear-gradient {
bounds: -1 -1 12 12;
start: -1 0;
end: 11 0;
stops: 0.5 rgb(0,80,0), 0.5 rgb(80,0,0);
}
path: "\
M 0 0\
L 10 0\
L 10 10\
L 0 10\
Z\
M 1 1\
L 1 9\
L 9 9\
L 9 1\
Z";
fill-rule: winding;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

View File

@@ -0,0 +1,25 @@
color {
bounds: 0 0 15 15;
color: rgba(0,0,0,1);
}
transform {
transform: translate(2, 2.6);
child: fill {
child: color {
bounds: 0 0 50 50;
color: rgb(0,120,0);
}
path: "\
M 0 0\
L 10 0\
L 10 10\
L 0 10\
Z\
M 1 1\
L 1 9\
L 9 9\
L 9 1\
Z";
fill-rule: winding;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

View File

@@ -0,0 +1,17 @@
color {
bounds: 0 0 14 14;
color: rgb(255,0,0);
}
transform {
transform: scale(2) translate(0.75, 0.25);
child: color-matrix {
matrix: matrix3d(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
child: transform {
transform: translate(0.25, 0.75);
child: color {
bounds: 0 0 5 5;
color: rgb(255,255,255);
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 B

View File

@@ -0,0 +1,20 @@
color {
bounds: 0 0 15 15;
color: rgb(0,0,0);
}
transform {
transform: translate(2.6, 2);
child: stroke {
child: linear-gradient {
bounds: -1 -1 12 12;
start: 0 -1;
end: 0 11;
stops: 0.5 rgb(0,80,0), 0.5 rgb(80,0,0);
}
path: "\
M 0.5 0.5 h 9 v 9 h -9 z";
line-width: 1;
line-cap: butt;
line-join: miter;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

View File

@@ -0,0 +1,18 @@
color {
bounds: 0 0 15 15;
color: rgb(0,0,0);
}
transform {
transform: translate(2.6, 2);
child: stroke {
child: color {
bounds: 0 0 50 50;
color: rgb(0,80,0);
}
path: "\
M 0.5 0.5 h 9 v 9 h -9 z";
line-width: 1;
line-cap: butt;
line-join: miter;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

View File

@@ -0,0 +1,4 @@
text {
font: "text-mixed-color-colrv1 15";
glyphs: 1 20, 2 20, 3 20, 4 20 0 0 color, 5 20 0 0 color, 6 20 0 0 color;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

View File

@@ -0,0 +1,7 @@
transform {
transform: translate(0, 100);
child: text {
font: "text-mixed-color 20";
glyphs: 1 20, 2 20, 3 20, 4 20 0 0 color, 5 20 0 0 color, 6 20 0 0 color;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

View File

@@ -0,0 +1,226 @@
<?xml version="1.0" encoding="utf-8"?>
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="2.4">
<GlyphOrder>
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
<GlyphID id="0" name=".notdef"/>
<GlyphID id="1" name="A"/>
<GlyphID id="2" name="B"/>
<GlyphID id="3" name="C"/>
<GlyphID id="4" name="D"/>
<GlyphID id="5" name="E"/>
<GlyphID id="6" name="F"/>
</GlyphOrder>
<head>
<!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="1.0"/>
<fontRevision value="1.1"/>
<checkSumAdjustment value="0x2a3f4cae"/>
<magicNumber value="0x5f0f3cf5"/>
<flags value="00000000 00000010"/>
<unitsPerEm value="2048"/>
<created value="Tue Jan 9 00:00:00 2024"/>
<modified value="Tue Jan 9 00:00:00 2024"/>
<xMin value="0"/>
<yMin value="0"/>
<xMax value="0"/>
<yMax value="0"/>
<macStyle value="00000000 00000000"/>
<lowestRecPPEM value="1"/>
<fontDirectionHint value="2"/>
<indexToLocFormat value="0"/>
<glyphDataFormat value="0"/>
</head>
<hhea>
<tableVersion value="1.0"/>
<ascent value="2048"/>
<descent value="0"/>
<lineGap value="0"/>
<advanceWidthMax value="20480"/>
<minLeftSideBearing value="0"/>
<minRightSideBearing value="0"/>
<xMaxExtent value="0"/>
<caretSlopeRise value="1"/>
<caretSlopeRun value="0"/>
<caretOffset value="0"/>
<reserved0 value="0"/>
<reserved1 value="0"/>
<reserved2 value="0"/>
<reserved3 value="0"/>
<metricDataFormat value="0"/>
<numberOfHMetrics value="2"/>
</hhea>
<maxp>
<!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="0x10000"/>
<numGlyphs value="4"/>
<maxPoints value="0"/>
<maxContours value="0"/>
<maxCompositePoints value="0"/>
<maxCompositeContours value="0"/>
<maxZones value="1"/>
<maxTwilightPoints value="0"/>
<maxStorage value="0"/>
<maxFunctionDefs value="0"/>
<maxInstructionDefs value="0"/>
<maxStackElements value="0"/>
<maxSizeOfInstructions value="0"/>
<maxComponentElements value="0"/>
<maxComponentDepth value="0"/>
</maxp>
<hmtx>
<mtx name=".notdef" width="1024" lsb="0"/>
<mtx name="A" width="1024" lsb="0"/>
<mtx name="B" width="1024" lsb="0"/>
<mtx name="C" width="1024" lsb="0"/>
<mtx name="D" width="1024" lsb="0"/>
<mtx name="E" width="1024" lsb="0"/>
<mtx name="F" width="1024" lsb="0"/>
</hmtx>
<loca>
</loca>
<glyf> <!-- Will result in empty table -->
<TTGlyph name=".notdef"/>
<TTGlyph name="A">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
<TTGlyph name="B">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
<TTGlyph name="C">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
<TTGlyph name="D">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
<TTGlyph name="E">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
<TTGlyph name="F">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
</glyf>
<COLR>
<Version value="1"/>
<BaseGlyphList>
<BaseGlyphPaintRecord index="0">
<BaseGlyph value="D"/>
<Paint Format="1">
<NumLayers value="1"/>
<FirstLayerIndex value="0"/>
</Paint>
</BaseGlyphPaintRecord>
<BaseGlyphPaintRecord index="1">
<BaseGlyph value="E"/>
<Paint Format="1">
<NumLayers value="1"/>
<FirstLayerIndex value="1"/>
</Paint>
</BaseGlyphPaintRecord>
<BaseGlyphPaintRecord index="2">
<BaseGlyph value="F"/>
<Paint Format="1">
<NumLayers value="1"/>
<FirstLayerIndex value="2"/>
</Paint>
</BaseGlyphPaintRecord>
</BaseGlyphList>
<LayerList>
<Paint index="0" Format="10">
<Paint Format="2">
<PaletteIndex value="0"/>
<Alpha value="1.0"/>
</Paint>
<Glyph value="A"/>
</Paint>
<Paint index="1" Format="10">
<Paint Format="2">
<PaletteIndex value="1"/>
<Alpha value="1.0"/>
</Paint>
<Glyph value="B"/>
</Paint>
<Paint index="2" Format="10">
<Paint Format="2">
<PaletteIndex value="2"/>
<Alpha value="1.0"/>
</Paint>
<Glyph value="C"/>
</Paint>
</LayerList>
</COLR>
<CPAL>
<version value="0"/>
<numPaletteEntries value="3"/>
<palette index="0">
<color index="0" value="#FF0000FF"/>
<color index="1" value="#00FF00FF"/>
<color index="2" value="#0000FFFF"/>
</palette>
</CPAL>
<name>
<namerecord nameID="0" platformID="1" platEncID="0" langID="0x0" unicode="True">
text-mixed-color-colrv1
</namerecord>
</name>
<cmap>
<tableVersion version="0"/>
<cmap_format_4 platformID="0" platEncID="3" language="0">
<map code="0x20" name=".notdef"/>
<map code="0x41" name="A"/>
<map code="0x42" name="B"/>
<map code="0x43" name="C"/>
<map code="0x44" name="D"/>
<map code="0x45" name="E"/>
<map code="0x46" name="F"/>
</cmap_format_4>
</cmap>
</ttFont>

Binary file not shown.

View File

@@ -0,0 +1,189 @@
<?xml version="1.0" encoding="utf-8"?>
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="2.4">
<GlyphOrder>
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
<GlyphID id="0" name=".notdef"/>
<GlyphID id="1" name="A"/>
<GlyphID id="2" name="B"/>
<GlyphID id="3" name="C"/>
<GlyphID id="4" name="D"/>
<GlyphID id="5" name="E"/>
<GlyphID id="6" name="F"/>
</GlyphOrder>
<head>
<!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="1.0"/>
<fontRevision value="1.1"/>
<checkSumAdjustment value="0x2a3f4cae"/>
<magicNumber value="0x5f0f3cf5"/>
<flags value="00000000 00000010"/>
<unitsPerEm value="2048"/>
<created value="Tue Jan 9 00:00:00 2024"/>
<modified value="Tue Jan 9 00:00:00 2024"/>
<xMin value="0"/>
<yMin value="0"/>
<xMax value="0"/>
<yMax value="0"/>
<macStyle value="00000000 00000000"/>
<lowestRecPPEM value="1"/>
<fontDirectionHint value="2"/>
<indexToLocFormat value="0"/>
<glyphDataFormat value="0"/>
</head>
<hhea>
<tableVersion value="1.0"/>
<ascent value="2048"/>
<descent value="0"/>
<lineGap value="0"/>
<advanceWidthMax value="20480"/>
<minLeftSideBearing value="0"/>
<minRightSideBearing value="0"/>
<xMaxExtent value="0"/>
<caretSlopeRise value="1"/>
<caretSlopeRun value="0"/>
<caretOffset value="0"/>
<reserved0 value="0"/>
<reserved1 value="0"/>
<reserved2 value="0"/>
<reserved3 value="0"/>
<metricDataFormat value="0"/>
<numberOfHMetrics value="2"/>
</hhea>
<maxp>
<!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="0x10000"/>
<numGlyphs value="4"/>
<maxPoints value="0"/>
<maxContours value="0"/>
<maxCompositePoints value="0"/>
<maxCompositeContours value="0"/>
<maxZones value="1"/>
<maxTwilightPoints value="0"/>
<maxStorage value="0"/>
<maxFunctionDefs value="0"/>
<maxInstructionDefs value="0"/>
<maxStackElements value="0"/>
<maxSizeOfInstructions value="0"/>
<maxComponentElements value="0"/>
<maxComponentDepth value="0"/>
</maxp>
<hmtx>
<mtx name=".notdef" width="1024" lsb="0"/>
<mtx name="A" width="1024" lsb="0"/>
<mtx name="B" width="1024" lsb="0"/>
<mtx name="C" width="1024" lsb="0"/>
<mtx name="D" width="1024" lsb="0"/>
<mtx name="E" width="1024" lsb="0"/>
<mtx name="F" width="1024" lsb="0"/>
</hmtx>
<loca>
</loca>
<glyf> <!-- Will result in empty table -->
<TTGlyph name=".notdef"/>
<TTGlyph name="A">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
<TTGlyph name="B">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
<TTGlyph name="C">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
<TTGlyph name="D">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
<TTGlyph name="E">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
<TTGlyph name="F">
<contour>
<pt x="0" y="0" on="1"/>
<pt x="1024" y="0" on="1"/>
<pt x="1024" y="2048" on="1"/>
<pt x="0" y="2048" on="1"/>
</contour>
<instructions><assembly></assembly></instructions>
</TTGlyph>
</glyf>
<COLR>
<version value="0"/>
<ColorGlyph name="D">
<layer colorID="0" name="B"/>
</ColorGlyph>
<ColorGlyph name="E">
<layer colorID="1" name="C"/>
</ColorGlyph>
<ColorGlyph name="F">
<layer colorID="2" name="C"/>
</ColorGlyph>
</COLR>
<CPAL>
<version value="0"/>
<numPaletteEntries value="3"/>
<palette index="0">
<color index="0" value="#FF0000FF"/>
<color index="1" value="#00FF00FF"/>
<color index="2" value="#0000FFFF"/>
</palette>
</CPAL>
<name>
<namerecord nameID="0" platformID="1" platEncID="0" langID="0x0" unicode="True">
text-mixed-color
</namerecord>
</name>
<cmap>
<tableVersion version="0"/>
<cmap_format_4 platformID="0" platEncID="3" language="0">
<map code="0x20" name=".notdef"/>
<map code="0x41" name="A"/>
<map code="0x42" name="B"/>
<map code="0x43" name="C"/>
<map code="0x44" name="D"/>
<map code="0x45" name="E"/>
<map code="0x46" name="F"/>
</cmap_format_4>
</cmap>
</ttFont>

View File

@@ -70,6 +70,8 @@ compare_render_tests = [
'empty-transform',
'fill',
'fill-clipped-nogl',
'fill-fractional-translate-gradient-nogl',
'fill-fractional-translate-nogl',
'fill-opacity',
'fill-scaled-up',
'fill-with-3d-contents-nogl-nocairo',
@@ -89,6 +91,7 @@ compare_render_tests = [
'mask-texture-color-alpha',
'mipmap-generation-later',
'nested-rounded-clips',
'offscreen-fractional-translate-nogl',
'offscreen-pixel-alignment-nogl-nocairo',
'opacity_clip',
'opacity-colormatrix-combinations',
@@ -127,8 +130,12 @@ compare_render_tests = [
'shrink-rounded-border',
'stroke',
'stroke-clipped-nogl',
'stroke-fractional-translate-gradient-nogl',
'stroke-fractional-translate-nogl',
'stroke-opacity',
'stroke-with-3d-contents-nogl-nocairo',
'text-mixed-color-nocairo',
'text-mixed-color-colrv1',
'texture-coords',
'texture-scale-filters-nocairo',
'texture-scale-magnify-10000x',
@@ -196,7 +203,8 @@ foreach renderer : renderers
'GSK_RENDERER=' + renderer_name,
'GTK_A11Y=test',
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
'TEST_FONT_DIR=@0@/fonts'.format(meson.current_source_dir())
]
if ((not testname.contains(exclude_term)) and