Improve the subpixel positioning machinery

Extract the resolution of the subpixel grid. This is in
preparation for allowing a finer subpixel grid. No functional
change.
This commit is contained in:
Matthias Clasen 2025-03-22 10:36:42 -04:00
parent c4f291bc3a
commit 3625b20901
6 changed files with 66 additions and 30 deletions

View file

@ -2449,10 +2449,11 @@ _cairo_ft_scaled_glyph_load_glyph (cairo_ft_scaled_font_t *scaled_font,
_cairo_ft_scaled_glyph_vertical_layout_bearing_fix (scaled_font, face->glyph);
if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
unsigned int bits = _cairo_subpixel_bits (scaled_font->base.options.subpixel_positions);
FT_Pos xshift, yshift;
xshift = _cairo_scaled_glyph_xphase (scaled_glyph) << 4;
yshift = _cairo_scaled_glyph_yphase (scaled_glyph) << 4;
xshift = _cairo_scaled_glyph_xphase (scaled_glyph) << (6 - bits);
yshift = _cairo_scaled_glyph_yphase (scaled_glyph) << (6 - bits);
FT_Outline_Translate (&face->glyph->outline, xshift, -yshift);
}

View file

@ -845,9 +845,6 @@ _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
}
#define PHASE(x) ((int)(floor (4 * (x + 0.125)) - 4 * floor (x + 0.125)))
#define POSITION(x) ((int) floor (x + 0.125))
static cairo_int_status_t
composite_glyphs (void *_dst,
cairo_operator_t op,
@ -891,12 +888,11 @@ composite_glyphs (void *_dst,
const void *glyph;
if (info->font->options.subpixel_positions != CAIRO_SUBPIXEL_POSITIONS_OFF) {
int res = _cairo_subpixel_resolution (info->font->options.subpixel_positions);
unsigned long xphase, yphase;
xphase = PHASE(info->glyphs[i].x);
yphase = PHASE(info->glyphs[i].y);
index = index | (xphase << 24) | (yphase << 26);
xphase = _cairo_subpixel_phase (info->glyphs[i].x, res);
yphase = _cairo_subpixel_phase (info->glyphs[i].y, res);
index = index | (xphase << XSHIFT) | (yphase << YSHIFT);
}
glyph = pixman_glyph_cache_lookup (glyph_cache, info->font, (void *)(uintptr_t)index);
@ -929,8 +925,9 @@ composite_glyphs (void *_dst,
}
if (info->font->options.subpixel_positions != CAIRO_SUBPIXEL_POSITIONS_OFF) {
pg->x = POSITION (info->glyphs[i].x);
pg->y = POSITION (info->glyphs[i].y);
int res = _cairo_subpixel_resolution (info->font->options.subpixel_positions);
pg->x = _cairo_subpixel_position (info->glyphs[i].x, res);
pg->y = _cairo_subpixel_position (info->glyphs[i].y, res);
}
else {
pg->x = _cairo_lround (info->glyphs[i].x);

View file

@ -208,8 +208,9 @@ _cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_fon
cairo_surface_destroy (recording_surface);
recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE, foreground_color);
if (scaled_font->base.options.subpixel_positions != CAIRO_SUBPIXEL_POSITIONS_OFF) {
recording_surface->device_transform.x0 = .25 * _cairo_scaled_glyph_xphase (scaled_glyph);
recording_surface->device_transform.y0 = .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
double res = _cairo_subpixel_resolution (scaled_font->base.options.subpixel_positions);
recording_surface->device_transform.x0 = _cairo_scaled_glyph_xphase (scaled_glyph) / res;
recording_surface->device_transform.y0 = _cairo_scaled_glyph_yphase (scaled_glyph) / res;
}
cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface, FALSE);

View file

@ -1570,9 +1570,6 @@ check_composite_glyphs (const cairo_composite_rectangles_t *extents,
* enough room for padding */
#define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
#define PHASE(x) ((int)(floor (4 * (x + 0.125)) - 4 * floor (x + 0.125)))
#define POSITION(x) ((int) floor (x + 0.125))
static cairo_int_status_t
composite_glyphs (void *surface,
cairo_operator_t op,
@ -1612,12 +1609,18 @@ composite_glyphs (void *surface,
int old_width;
if (info->font->options.subpixel_positions != CAIRO_SUBPIXEL_POSITIONS_OFF) {
int res = _cairo_subpixel_resolution (info->font->options.subpixel_positions);
unsigned long xphase, yphase;
xphase = _cairo_subpixel_phase (glyphs[i].d.x, res);
yphase = _cairo_subpixel_phase (glyphs[i].d.y, res);
glyphs[i].index |= (xphase << XSHIFT) | (yphase << YSHIFT);
xphase = PHASE(glyphs[i].d.x);
yphase = PHASE(glyphs[i].d.y);
glyphs[i].index |= (xphase << 24) | (yphase << 26);
this_x = _cairo_subpixel_position (glyphs[i].d.x, res);
this_y = _cairo_subpixel_position (glyphs[i].d.y, res);
}
else {
this_x = _cairo_lround (glyphs[i].d.x);
this_y = _cairo_lround (glyphs[i].d.y);
}
status = _cairo_scaled_glyph_lookup (info->font,
@ -1628,9 +1631,6 @@ composite_glyphs (void *surface,
if (unlikely (status))
return status;
this_x = POSITION (glyphs[i].d.x);
this_y = POSITION (glyphs[i].d.y);
/* Send unsent glyphs to the server */
if (glyph->dev_private_key != display) {
status = _cairo_xlib_surface_add_glyph (display, info->font, &glyph);

View file

@ -400,10 +400,46 @@ cairo_private uintptr_t
_cairo_hash_uintptr (uintptr_t hash,
uintptr_t u);
/* We use bits 24-27 to store phases for subpixel positions */
#define _cairo_scaled_glyph_index(g) ((unsigned long)((g)->hash_entry.hash & 0xffffff))
#define _cairo_scaled_glyph_xphase(g) (int)(((g)->hash_entry.hash >> 24) & 3)
#define _cairo_scaled_glyph_yphase(g) (int)(((g)->hash_entry.hash >> 26) & 3)
/* We use the upper 8 bits to store phases for 64x64 subpixel positions */
static inline int _cairo_subpixel_bits (cairo_subpixel_positions_t subpixel_positions)
{
int bits[] = {
[CAIRO_SUBPIXEL_POSITIONS_DEFAULT] = 2,
[CAIRO_SUBPIXEL_POSITIONS_OFF] = 0,
[CAIRO_SUBPIXEL_POSITIONS_ON] = 2,
};
return bits[subpixel_positions];
}
static inline int _cairo_subpixel_resolution (cairo_subpixel_positions_t subpixel_positions)
{
return 1 << _cairo_subpixel_bits (subpixel_positions);
}
static inline int _cairo_subpixel_phase (double pos, int res)
{
double shifted_pos = pos + 1.0 / (2 * res);
return (int) (floor (res * shifted_pos) - res * floor (shifted_pos));
}
static inline double _cairo_subpixel_position (double pos, int res)
{
return floor (pos + 1.0 / (2 * res));
}
#define MAX_PHASE_BITS 4
#define XSHIFT (32 - 2 * MAX_PHASE_BITS)
#define YSHIFT (32 - MAX_PHASE_BITS)
#define PHASE_MASK ((1 << MAX_PHASE_BITS) - 1)
#define INDEX_MASK ((1 << XSHIFT) - 1)
#define _cairo_scaled_glyph_index(g) ((unsigned long)((g)->hash_entry.hash & INDEX_MASK))
#define _cairo_scaled_glyph_xphase(g) (unsigned int)(((g)->hash_entry.hash >> XSHIFT) & PHASE_MASK)
#define _cairo_scaled_glyph_yphase(g) ((unsigned int)(((g)->hash_entry.hash >> YSHIFT) & PHASE_MASK))
#define _cairo_scaled_glyph_set_index(g, i) ((g)->hash_entry.hash = (i))
#include "cairo-scaled-font-private.h"

View file

@ -1112,8 +1112,9 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
double x = -x1;
double y = -y1;
if (scaled_font->base.options.subpixel_positions != CAIRO_SUBPIXEL_POSITIONS_OFF) {
x += .25 * _cairo_scaled_glyph_xphase (scaled_glyph);
y += .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
double res = _cairo_subpixel_resolution (scaled_font->base.options.subpixel_positions);
x += _cairo_scaled_glyph_xphase (scaled_glyph) / res;
y += _cairo_scaled_glyph_yphase (scaled_glyph) / res;
}
DWRITE_MATRIX matrix;
D2D1_POINT_2F origin = {0, 0};