Merge branch 'subpixel-positioning' into 'master'

Subpixel positioning

See merge request GNOME/gtk!1024
This commit is contained in:
Matthias Clasen 2019-07-28 21:02:31 +00:00
commit 4a631787bd
12 changed files with 105 additions and 28 deletions

View File

@ -83,6 +83,8 @@ glyph_cache_equal (gconstpointer v1, gconstpointer v2)
return key1->font == key2->font && return key1->font == key2->font &&
key1->glyph == key2->glyph && key1->glyph == key2->glyph &&
key1->xshift == key2->xshift &&
key1->yshift == key2->yshift &&
key1->scale == key2->scale; key1->scale == key2->scale;
} }
@ -91,7 +93,11 @@ glyph_cache_hash (gconstpointer v)
{ {
const GlyphCacheKey *key = v; const GlyphCacheKey *key = v;
return GPOINTER_TO_UINT (key->font) ^ key->glyph ^ key->scale; return GPOINTER_TO_UINT (key->font) ^
key->glyph ^
(key->xshift << 24) ^
(key->yshift << 26) ^
key->scale;
} }
static void static void
@ -146,10 +152,10 @@ render_glyph (GlyphCacheKey *key,
cairo_glyph.index = key->glyph; cairo_glyph.index = key->glyph;
if (key->glyph & PANGO_GLYPH_UNKNOWN_FLAG) if (key->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
cairo_glyph.x = 0; cairo_glyph.x = 0.25 * key->xshift;
else else
cairo_glyph.x = - value->draw_x; cairo_glyph.x = 0.25 * key->xshift - value->draw_x;
cairo_glyph.y = - value->draw_y; cairo_glyph.y = 0.25 * key->yshift - value->draw_y;
cairo_show_glyphs (cr, &cairo_glyph, 1); cairo_show_glyphs (cr, &cairo_glyph, 1);
cairo_destroy (cr); cairo_destroy (cr);
@ -243,20 +249,28 @@ add_to_cache (GskGLGlyphCache *self,
upload_glyph (key, value); upload_glyph (key, value);
} }
#define PHASE(x) ((x % PANGO_SCALE) * 4 / PANGO_SCALE)
gboolean gboolean
gsk_gl_glyph_cache_lookup (GskGLGlyphCache *cache, gsk_gl_glyph_cache_lookup (GskGLGlyphCache *cache,
PangoFont *font, PangoFont *font,
PangoGlyph glyph, PangoGlyph glyph,
int x,
int y,
float scale, float scale,
GskGLDriver *driver, GskGLDriver *driver,
GskGLCachedGlyph *cached_glyph_out) GskGLCachedGlyph *cached_glyph_out)
{ {
GskGLCachedGlyph *value; GskGLCachedGlyph *value;
guint xshift = PHASE (x);
guint yshift = PHASE (y);
value = g_hash_table_lookup (cache->hash_table, value = g_hash_table_lookup (cache->hash_table,
&(GlyphCacheKey) { &(GlyphCacheKey) {
.font = font, .font = font,
.glyph = glyph, .glyph = glyph,
.xshift = xshift,
.yshift = yshift,
.scale = (guint)(scale * 1024) .scale = (guint)(scale * 1024)
}); });
@ -288,6 +302,10 @@ gsk_gl_glyph_cache_lookup (GskGLGlyphCache *cache,
pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL); pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
pango_extents_to_pixels (&ink_rect, NULL); pango_extents_to_pixels (&ink_rect, NULL);
if (xshift != 0)
ink_rect.width += 1;
if (yshift != 0)
ink_rect.height += 1;
value = g_new0 (GskGLCachedGlyph, 1); value = g_new0 (GskGLCachedGlyph, 1);
@ -302,6 +320,8 @@ gsk_gl_glyph_cache_lookup (GskGLGlyphCache *cache,
key->font = g_object_ref (font); key->font = g_object_ref (font);
key->glyph = glyph; key->glyph = glyph;
key->xshift = xshift;
key->yshift = yshift;
key->scale = key_scale; key->scale = key_scale;
if (key->scale > 0 && if (key->scale > 0 &&

View File

@ -22,6 +22,8 @@ typedef struct
{ {
PangoFont *font; PangoFont *font;
PangoGlyph glyph; PangoGlyph glyph;
guint xshift;
guint yshift;
guint scale; /* times 1024 */ guint scale; /* times 1024 */
} GlyphCacheKey; } GlyphCacheKey;
@ -55,6 +57,8 @@ void gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache
gboolean gsk_gl_glyph_cache_lookup (GskGLGlyphCache *self, gboolean gsk_gl_glyph_cache_lookup (GskGLGlyphCache *self,
PangoFont *font, PangoFont *font,
PangoGlyph glyph, PangoGlyph glyph,
int x,
int y,
float scale, float scale,
GskGLDriver *driver, GskGLDriver *driver,
GskGLCachedGlyph *cached_glyph_out); GskGLCachedGlyph *cached_glyph_out);

View File

@ -595,6 +595,8 @@ render_text_node (GskGLRenderer *self,
gsk_gl_glyph_cache_lookup (self->glyph_cache, gsk_gl_glyph_cache_lookup (self->glyph_cache,
(PangoFont *)font, (PangoFont *)font,
gi->glyph, gi->glyph,
x * PANGO_SCALE + x_position + gi->geometry.x_offset,
+ y * PANGO_SCALE + gi->geometry.y_offset,
text_scale, text_scale,
self->gl_driver, self->gl_driver,
&glyph); &glyph);
@ -606,8 +608,8 @@ render_text_node (GskGLRenderer *self,
if (glyph.texture_id == 0) if (glyph.texture_id == 0)
goto next; goto next;
cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE; cx = (x_position + gi->geometry.x_offset) / PANGO_SCALE;
cy = (double)(gi->geometry.y_offset) / PANGO_SCALE; cy = gi->geometry.y_offset / PANGO_SCALE;
ops_set_texture (builder, glyph.texture_id); ops_set_texture (builder, glyph.texture_id);

View File

@ -119,12 +119,17 @@ gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *
if (gi->glyph != PANGO_GLYPH_EMPTY) if (gi->glyph != PANGO_GLYPH_EMPTY)
{ {
double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE; double cx = (x_position + gi->geometry.x_offset) / PANGO_SCALE;
double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE; double cy = gi->geometry.y_offset / PANGO_SCALE;
GskVulkanColorTextInstance *instance = &instances[count]; GskVulkanColorTextInstance *instance = &instances[count];
GskVulkanCachedGlyph *glyph; GskVulkanCachedGlyph *glyph;
glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale); glyph = gsk_vulkan_renderer_get_cached_glyph (renderer,
font,
gi->glyph,
x_position + gi->geometry.x_offset,
gi->geometry.y_offset,
scale);
instance->tex_rect[0] = glyph->tx; instance->tex_rect[0] = glyph->tx;
instance->tex_rect[1] = glyph->ty; instance->tex_rect[1] = glyph->ty;

View File

@ -115,6 +115,8 @@ gsk_vulkan_glyph_cache_class_init (GskVulkanGlyphCacheClass *klass)
typedef struct { typedef struct {
PangoFont *font; PangoFont *font;
PangoGlyph glyph; PangoGlyph glyph;
guint xshift;
guint yshift;
guint scale; /* times 1024 */ guint scale; /* times 1024 */
} GlyphCacheKey; } GlyphCacheKey;
@ -126,6 +128,8 @@ glyph_cache_equal (gconstpointer v1, gconstpointer v2)
return key1->font == key2->font && return key1->font == key2->font &&
key1->glyph == key2->glyph && key1->glyph == key2->glyph &&
key1->xshift == key2->xshift &&
key1->yshift == key2->yshift &&
key1->scale == key2->scale; key1->scale == key2->scale;
} }
@ -134,7 +138,7 @@ glyph_cache_hash (gconstpointer v)
{ {
const GlyphCacheKey *key = v; const GlyphCacheKey *key = v;
return GPOINTER_TO_UINT (key->font) ^ key->glyph ^ key->scale; return GPOINTER_TO_UINT (key->font) ^ key->glyph ^ (key->xshift << 24) ^ (key->yshift << 26) ^ key->scale;
} }
static void static void
@ -267,10 +271,10 @@ render_glyph (Atlas *atlas,
gi.glyph = key->glyph; gi.glyph = key->glyph;
gi.geometry.width = value->draw_width * 1024; gi.geometry.width = value->draw_width * 1024;
if (key->glyph & PANGO_GLYPH_UNKNOWN_FLAG) if (key->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
gi.geometry.x_offset = 0; gi.geometry.x_offset = key->xshift * 256;
else else
gi.geometry.x_offset = - value->draw_x * 1024; gi.geometry.x_offset = key->xshift * 256 - value->draw_x * 1024;
gi.geometry.y_offset = - value->draw_y * 1024; gi.geometry.y_offset = key->yshift * 256 - value->draw_y * 1024;
glyphs.num_glyphs = 1; glyphs.num_glyphs = 1;
glyphs.glyphs = &gi; glyphs.glyphs = &gi;
@ -328,18 +332,29 @@ gsk_vulkan_glyph_cache_new (GskRenderer *renderer,
return cache; return cache;
} }
#define PHASE(x) ((x % PANGO_SCALE) * 4 / PANGO_SCALE)
GskVulkanCachedGlyph * GskVulkanCachedGlyph *
gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache, gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache,
gboolean create, gboolean create,
PangoFont *font, PangoFont *font,
PangoGlyph glyph, PangoGlyph glyph,
int x,
int y,
float scale) float scale)
{ {
GlyphCacheKey lookup_key; GlyphCacheKey lookup_key;
GskVulkanCachedGlyph *value; GskVulkanCachedGlyph *value;
guint xshift;
guint yshift;
xshift = PHASE (x);
yshift = PHASE (y);
lookup_key.font = font; lookup_key.font = font;
lookup_key.glyph = glyph; lookup_key.glyph = glyph;
lookup_key.xshift = xshift;
lookup_key.yshift = yshift;
lookup_key.scale = (guint)(scale * 1024); lookup_key.scale = (guint)(scale * 1024);
value = g_hash_table_lookup (cache->hash_table, &lookup_key); value = g_hash_table_lookup (cache->hash_table, &lookup_key);
@ -374,6 +389,8 @@ gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache *cache,
key->font = g_object_ref (font); key->font = g_object_ref (font);
key->glyph = glyph; key->glyph = glyph;
key->xshift = xshift;
key->yshift = yshift;
key->scale = (guint)(scale * 1024); key->scale = (guint)(scale * 1024);
if (ink_rect.width > 0 && ink_rect.height > 0) if (ink_rect.width > 0 && ink_rect.height > 0)

View File

@ -22,6 +22,9 @@ GskVulkanCachedGlyph *gsk_vulkan_glyph_cache_lookup (GskVulkanGlyphCache
gboolean create, gboolean create,
PangoFont *font, PangoFont *font,
PangoGlyph glyph, PangoGlyph glyph,
int x,
int y,
float scale); float scale);
void gsk_vulkan_glyph_cache_begin_frame (GskVulkanGlyphCache *cache); void gsk_vulkan_glyph_cache_begin_frame (GskVulkanGlyphCache *cache);

View File

@ -362,15 +362,6 @@ gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
return image; return image;
} }
guint
gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *self,
PangoFont *font,
PangoGlyph glyph,
float scale)
{
return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, TRUE, font, glyph, scale)->texture_index;
}
GskVulkanImage * GskVulkanImage *
gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self, gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
GskVulkanUploader *uploader, GskVulkanUploader *uploader,
@ -379,13 +370,26 @@ gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
return g_object_ref (gsk_vulkan_glyph_cache_get_glyph_image (self->glyph_cache, uploader, index)); return g_object_ref (gsk_vulkan_glyph_cache_get_glyph_image (self->glyph_cache, uploader, index));
} }
guint
gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *self,
PangoFont *font,
PangoGlyph glyph,
int x,
int y,
float scale)
{
return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, TRUE, font, glyph, x, y, scale)->texture_index;
}
GskVulkanCachedGlyph * GskVulkanCachedGlyph *
gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self, gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
PangoFont *font, PangoFont *font,
PangoGlyph glyph, PangoGlyph glyph,
int x,
int y,
float scale) float scale)
{ {
return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph, scale); return gsk_vulkan_glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph, x, y, scale);
} }
/** /**

View File

@ -30,6 +30,8 @@ typedef struct
guint gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *renderer, guint gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *renderer,
PangoFont *font, PangoFont *font,
PangoGlyph glyph, PangoGlyph glyph,
int x,
int y,
float scale); float scale);
GskVulkanImage * gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self, GskVulkanImage * gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
@ -39,6 +41,8 @@ GskVulkanImage * gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *
GskVulkanCachedGlyph * gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self, GskVulkanCachedGlyph * gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
PangoFont *font, PangoFont *font,
PangoGlyph glyph, PangoGlyph glyph,
int x,
int y,
float scale); float scale);

View File

@ -370,6 +370,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
int i; int i;
guint count; guint count;
guint texture_index; guint texture_index;
gint x_position;
GskVulkanRenderer *renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)); GskVulkanRenderer *renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render));
if (font_has_color_glyphs (font)) if (font_has_color_glyphs (font))
@ -402,11 +403,17 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
op.text.texture_index = G_MAXUINT; op.text.texture_index = G_MAXUINT;
op.text.scale = self->scale_factor; op.text.scale = self->scale_factor;
x_position = 0;
for (i = 0, count = 0; i < num_glyphs; i++) for (i = 0, count = 0; i < num_glyphs; i++)
{ {
const PangoGlyphInfo *gi = &glyphs[i]; const PangoGlyphInfo *gi = &glyphs[i];
texture_index = gsk_vulkan_renderer_cache_glyph (renderer, (PangoFont *)font, gi->glyph, op.text.scale); texture_index = gsk_vulkan_renderer_cache_glyph (renderer,
(PangoFont *)font,
gi->glyph,
x_position + gi->geometry.x_offset,
gi->geometry.y_offset,
op.text.scale);
if (op.text.texture_index == G_MAXUINT) if (op.text.texture_index == G_MAXUINT)
op.text.texture_index = texture_index; op.text.texture_index = texture_index;
if (texture_index != op.text.texture_index) if (texture_index != op.text.texture_index)
@ -421,6 +428,8 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
} }
else else
count++; count++;
x_position += gi->geometry.width;
} }
if (op.text.texture_index != G_MAXUINT && count != 0) if (op.text.texture_index != G_MAXUINT && count != 0)

View File

@ -127,12 +127,17 @@ gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline *pipeline,
if (gi->glyph != PANGO_GLYPH_EMPTY) if (gi->glyph != PANGO_GLYPH_EMPTY)
{ {
double cx = (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE; double cx = (x_position + gi->geometry.x_offset) / PANGO_SCALE;
double cy = (double)(gi->geometry.y_offset) / PANGO_SCALE; double cy = gi->geometry.y_offset / PANGO_SCALE;
GskVulkanTextInstance *instance = &instances[count]; GskVulkanTextInstance *instance = &instances[count];
GskVulkanCachedGlyph *glyph; GskVulkanCachedGlyph *glyph;
glyph = gsk_vulkan_renderer_get_cached_glyph (renderer, font, gi->glyph, scale); glyph = gsk_vulkan_renderer_get_cached_glyph (renderer,
font,
gi->glyph,
x_position + gi->geometry.x_offset,
gi->geometry.y_offset,
scale);
instance->tex_rect[0] = glyph->tx; instance->tex_rect[0] = glyph->tx;
instance->tex_rect[1] = glyph->ty; instance->tex_rect[1] = glyph->ty;

View File

@ -2062,7 +2062,7 @@ settings_update_font_options (GtkSettings *settings)
priv->font_options = cairo_font_options_create (); priv->font_options = cairo_font_options_create ();
cairo_font_options_set_hint_metrics (priv->font_options, CAIRO_HINT_METRICS_ON); cairo_font_options_set_hint_metrics (priv->font_options, CAIRO_HINT_METRICS_OFF);
hint_style = CAIRO_HINT_STYLE_DEFAULT; hint_style = CAIRO_HINT_STYLE_DEFAULT;
if (hinting == 0) if (hinting == 0)

View File

@ -430,6 +430,10 @@ xfails = [
'textview-border-windows.ui', 'textview-border-windows.ui',
'window-show-contents-on-map.ui', 'window-show-contents-on-map.ui',
'toplevel-vs-popup.ui', 'toplevel-vs-popup.ui',
# these depend on details of text layout
'label-background.ui',
'label-wrap-justify.ui',
'quit-mnemonic.ui',
] ]
foreach testname : testdata foreach testname : testdata