Compare commits

...

7 Commits

Author SHA1 Message Date
Matthias Clasen
39051aec9b gsk: Use scaled font for glyph rendering
This changes the approach we take to rendering glyphs in the
presence of a scale transform: Instead of scaling the extents
and rendering to an image surface with device scale, simply
create a scaled font and use it for extents and rendering.
2024-02-21 21:11:36 -05:00
Matthias Clasen
f3612c8616 gsk: Add a way to get a scaled font 2024-02-21 21:11:36 -05:00
Matthias Clasen
49491cf5f8 gsk: Use unhinted extents for glyphs 2024-02-21 21:11:36 -05:00
Matthias Clasen
65bf74a96d gsk: Use unhinted extents for text nodes 2024-02-21 21:11:36 -05:00
Matthias Clasen
52f7e7ea22 Add a way to get an unhinted font 2024-02-21 21:11:36 -05:00
Matthias Clasen
43f9e1ea90 Add another failing font test 2024-02-21 21:11:36 -05:00
Matthias Clasen
afc6f1c5ea Add a failing text test 2024-02-21 21:11:36 -05:00
9 changed files with 168 additions and 14 deletions

View File

@@ -11,6 +11,7 @@
#include "gdk/gdkprofilerprivate.h"
#include "gsk/gskdebugprivate.h"
#include "gsk/gskprivate.h"
#define MAX_SLICES_PER_ATLAS 64
@@ -905,6 +906,7 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
GskGpuImage *image;
gsize atlas_x, atlas_y, padding;
float subpixel_x, subpixel_y;
PangoFont *scaled_font;
cache = g_hash_table_lookup (priv->glyph_cache, &lookup);
if (cache)
@@ -916,13 +918,14 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
return cache->image;
}
scaled_font = gsk_get_scaled_font (font, scale);
subpixel_x = (flags & 3) / 4.f;
subpixel_y = ((flags >> 2) & 3) / 4.f;
pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
origin.x = floor (ink_rect.x * scale / PANGO_SCALE + subpixel_x);
origin.y = floor (ink_rect.y * scale / PANGO_SCALE + subpixel_y);
rect.size.width = ceil ((ink_rect.x + ink_rect.width) * scale / PANGO_SCALE + subpixel_x) - origin.x;
rect.size.height = ceil ((ink_rect.y + ink_rect.height) * scale / PANGO_SCALE + subpixel_y) - origin.y;
pango_font_get_glyph_extents (scaled_font, glyph, &ink_rect, NULL);
origin.x = floor (ink_rect.x * 1.0 / PANGO_SCALE + subpixel_x);
origin.y = floor (ink_rect.y * 1.0 / PANGO_SCALE + subpixel_y);
rect.size.width = ceil ((ink_rect.x + ink_rect.width) * 1.0 / PANGO_SCALE + subpixel_x) - origin.x;
rect.size.height = ceil ((ink_rect.y + ink_rect.height) * 1.0 / PANGO_SCALE + subpixel_y) - origin.y;
padding = 1;
image = gsk_gpu_device_add_atlas_image (self,
@@ -956,7 +959,7 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
gsk_gpu_upload_glyph_op (frame,
cache->image,
font,
scaled_font,
glyph,
&(cairo_rectangle_int_t) {
.x = rect.origin.x - padding,
@@ -964,7 +967,7 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
.width = rect.size.width + 2 * padding,
.height = rect.size.height + 2 * padding,
},
scale,
1.0,
&GRAPHENE_POINT_INIT (cache->origin.x + padding,
cache->origin.y + padding));

View File

@@ -1,6 +1,10 @@
#include "gskresources.h"
#include "gskprivate.h"
#include <cairo.h>
#include <pango/pangocairo.h>
#include <math.h>
static gpointer
register_resources (gpointer data)
{
@@ -15,3 +19,106 @@ gsk_ensure_resources (void)
g_once (&register_resources_once, register_resources, NULL);
}
/*< private >
* gsk_get_unhinted_font:
* @font: (transfer full): a `PangoFont`
*
* Returns a font that is just like @font, but does not apply
* hinting to its glyphs or metrics.
*
* Returns: (transfer full): an unhinted `PangoFont`
*/
PangoFont *
gsk_get_unhinted_font (PangoFont *font)
{
PangoFont *font2 = font;
cairo_scaled_font_t *sc;
cairo_font_options_t *options;
sc = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font));
options = cairo_font_options_create ();
cairo_scaled_font_get_font_options (sc, options);
if (cairo_font_options_get_hint_metrics (options) != CAIRO_HINT_METRICS_OFF ||
cairo_font_options_get_hint_style (options) != CAIRO_HINT_STYLE_NONE)
{
font2 = PANGO_FONT (g_object_get_data (G_OBJECT (font), "gsk-unhinted-font"));
if (!font2)
{
PangoFontMap *fontmap = pango_font_get_font_map (font);
PangoContext *context;
PangoFontDescription *desc;
cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
context = pango_font_map_create_context (fontmap);
pango_cairo_context_set_font_options (context, options);
desc = pango_font_describe (font);
font2 = pango_font_map_load_font (fontmap, context, desc);
pango_font_description_free (desc);
g_object_unref (context);
g_object_set_data_full (G_OBJECT (font), "gsk-unhinted-font",
font2, g_object_unref);
}
}
cairo_font_options_destroy (options);
return font2;
}
PangoFont *
gsk_get_scaled_font (PangoFont *font,
float scale)
{
GHashTable *fonts;
int key;
PangoFont *font2;
PangoFontDescription *desc;
int size;
PangoFontMap *fontmap;
PangoContext *context;
key = (int) CLAMP (roundf (scale * PANGO_SCALE), G_MININT, G_MAXINT);
if (key == PANGO_SCALE)
return font;
fonts = (GHashTable *) g_object_get_data (G_OBJECT (font), "gsk-scaled-fonts");
if (fonts)
{
font2 = g_hash_table_lookup (fonts, GINT_TO_POINTER (key));
if (font2)
return font2;
}
else
{
fonts = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
g_object_set_data_full (G_OBJECT (font), "gsk-scaled-fonts",
fonts, (GDestroyNotify) g_hash_table_unref);
}
desc = pango_font_describe (font);
size = pango_font_description_get_size (desc);
if (pango_font_description_get_size_is_absolute (desc))
pango_font_description_set_absolute_size (desc, size * scale);
else
pango_font_description_set_size (desc, (int) roundf (size * scale));
fontmap = pango_font_get_font_map (font);
context = pango_font_map_create_context (fontmap);
font2 = pango_font_map_load_font (fontmap, context, desc);
pango_font_description_free (desc);
g_object_unref (context);
g_hash_table_insert (fonts, GINT_TO_POINTER (key), font2);
return font2;
}

View File

@@ -5,7 +5,11 @@
G_BEGIN_DECLS
void gsk_ensure_resources (void);
void gsk_ensure_resources (void);
PangoFont *gsk_get_unhinted_font (PangoFont *font);
PangoFont *gsk_get_scaled_font (PangoFont *font,
float scale);
G_END_DECLS

View File

@@ -31,6 +31,7 @@
#include "gskroundedrectprivate.h"
#include "gskstrokeprivate.h"
#include "gsktransformprivate.h"
#include "gskprivate.h"
#include "gdk/gdkmemoryformatprivate.h"
#include "gdk/gdkprivate.h"
@@ -5791,6 +5792,12 @@ gsk_text_node_class_init (gpointer g_class,
node_class->diff = gsk_text_node_diff;
}
static inline float
pango_units_to_float (int i)
{
return (float) i / PANGO_SCALE;
}
/**
* gsk_text_node_new:
* @font: the `PangoFont` containing the glyphs
@@ -5817,8 +5824,7 @@ gsk_text_node_new (PangoFont *font,
PangoGlyphInfo *glyph_infos;
int n;
pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
pango_extents_to_pixels (&ink_rect, NULL);
pango_glyph_string_extents (glyphs, gsk_get_unhinted_font (font), &ink_rect, NULL);
/* Don't create nodes with empty bounds */
if (ink_rect.width == 0 || ink_rect.height == 0)
@@ -5855,10 +5861,10 @@ gsk_text_node_new (PangoFont *font,
self->num_glyphs = n;
gsk_rect_init (&node->bounds,
offset->x + ink_rect.x,
offset->y + ink_rect.y,
ink_rect.width,
ink_rect.height);
offset->x + pango_units_to_float (ink_rect.x),
offset->y + pango_units_to_float (ink_rect.y),
pango_units_to_float (ink_rect.width),
pango_units_to_float (ink_rect.height));
return node;
}

View File

@@ -0,0 +1,16 @@
blend {
mode: difference;
bottom: text {
color: rgb(255,0,0);
font: "Noto Sans Mono 300";
glyphs: "o";
}
top: transform {
transform: scale(100);
child: text {
color: rgb(255,0,0);
font: "Noto Sans Mono 3";
glyphs: "o";
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -0,0 +1,16 @@
blend {
mode: difference;
bottom: text {
color: rgb(255,0,0);
font: "Noto Sans Mono 300";
glyphs: "o";
}
top: transform {
transform: scale(0.01);
child: text {
color: rgb(255,0,0);
font: "Noto Sans Mono 30000";
glyphs: "o";
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -98,6 +98,8 @@ compare_render_tests = [
'mask-texture-color-alpha',
'mipmap-generation-later',
'nested-rounded-clips',
'o-from-hell',
'o-from-hell2',
'offscreen-fractional-translate-nogl',
'offscreen-pixel-alignment-nogl-nocairo',
'offscreen-pixel-alignment2',