mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-02-17 06:40:37 +01:00
Merge branch 'subpixel-positions-revisited' into 'master'
Improve subpixel positioning See merge request cairo/cairo!617
This commit is contained in:
commit
5a6e37ef19
9 changed files with 178 additions and 32 deletions
|
|
@ -60,6 +60,7 @@ static const cairo_font_options_t _cairo_font_options_nil = {
|
|||
CAIRO_COLOR_MODE_DEFAULT,
|
||||
CAIRO_COLOR_PALETTE_DEFAULT,
|
||||
NULL, 0, /* custom palette */
|
||||
CAIRO_SUBPIXEL_POSITIONS_DEFAULT,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -82,6 +83,7 @@ _cairo_font_options_init_default (cairo_font_options_t *options)
|
|||
options->palette_index = CAIRO_COLOR_PALETTE_DEFAULT;
|
||||
options->custom_palette = NULL;
|
||||
options->custom_palette_size = 0;
|
||||
options->subpixel_positions = CAIRO_SUBPIXEL_POSITIONS_DEFAULT;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -103,6 +105,7 @@ _cairo_font_options_init_copy (cairo_font_options_t *options,
|
|||
options->custom_palette = (cairo_palette_color_t *) malloc (sizeof (cairo_palette_color_t) * options->custom_palette_size);
|
||||
memcpy (options->custom_palette, other->custom_palette, sizeof (cairo_palette_color_t) * options->custom_palette_size);
|
||||
}
|
||||
options->subpixel_positions = other->subpixel_positions;
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
|
|
@ -117,7 +120,8 @@ _cairo_font_options_compare (const cairo_font_options_t *a,
|
|||
a->round_glyph_positions != b->round_glyph_positions ||
|
||||
a->color_mode != b->color_mode ||
|
||||
a->palette_index != b->palette_index ||
|
||||
a->custom_palette_size != b->custom_palette_size)
|
||||
a->custom_palette_size != b->custom_palette_size ||
|
||||
a->subpixel_positions != b->subpixel_positions)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
|
@ -287,6 +291,8 @@ cairo_font_options_merge (cairo_font_options_t *options,
|
|||
options->hint_metrics = other->hint_metrics;
|
||||
if (other->round_glyph_positions != CAIRO_ROUND_GLYPH_POS_DEFAULT)
|
||||
options->round_glyph_positions = other->round_glyph_positions;
|
||||
if (other->subpixel_positions != CAIRO_SUBPIXEL_POSITIONS_DEFAULT)
|
||||
options->subpixel_positions = other->subpixel_positions;
|
||||
|
||||
if (other->variations) {
|
||||
if (options->variations) {
|
||||
|
|
@ -349,6 +355,7 @@ cairo_font_options_equal (const cairo_font_options_t *options,
|
|||
options->hint_style == other->hint_style &&
|
||||
options->hint_metrics == other->hint_metrics &&
|
||||
options->round_glyph_positions == other->round_glyph_positions &&
|
||||
options->subpixel_positions == other->subpixel_positions &&
|
||||
((options->variations == NULL && other->variations == NULL) ||
|
||||
(options->variations != NULL && other->variations != NULL &&
|
||||
strcmp (options->variations, other->variations) == 0)) &&
|
||||
|
|
@ -393,7 +400,8 @@ cairo_font_options_hash (const cairo_font_options_t *options)
|
|||
(options->lcd_filter << 8) |
|
||||
(options->hint_style << 12) |
|
||||
(options->hint_metrics << 16) |
|
||||
(options->color_mode << 20)) ^ hash;
|
||||
(options->subpixel_positions << 20) |
|
||||
(options->color_mode << 22)) ^ hash;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -869,3 +877,43 @@ cairo_font_options_get_custom_palette_color (cairo_font_options_t *options,
|
|||
|
||||
return CAIRO_STATUS_INVALID_INDEX;
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_font_options_set_subpixel_positions:
|
||||
* @options: a #cairo_font_options_t
|
||||
* @subpixel_positions: the new value
|
||||
*
|
||||
* Sets the subpixel positions value for the font options object.
|
||||
* This controls whether glyph positions are rounded when rendering.
|
||||
*
|
||||
* Since: 1.20
|
||||
**/
|
||||
void
|
||||
cairo_font_options_set_subpixel_positions (cairo_font_options_t *options,
|
||||
cairo_subpixel_positions_t subpixel_positions)
|
||||
{
|
||||
if (cairo_font_options_status (options))
|
||||
return;
|
||||
|
||||
options->subpixel_positions = subpixel_positions;
|
||||
}
|
||||
|
||||
/**
|
||||
* cairo_font_options_get_subpixel_positions:
|
||||
* @options: a #cairo_font_options_t
|
||||
*
|
||||
* Gets the subpixel positions value for the font options object.
|
||||
* See the documentation for #cairo_subpixel_positions_t for full details.
|
||||
*
|
||||
* Return value: the subpixel positions value for the font options object
|
||||
*
|
||||
* Since: 1.20
|
||||
*/
|
||||
cairo_public cairo_subpixel_positions_t
|
||||
cairo_font_options_get_subpixel_positions (const cairo_font_options_t *options)
|
||||
{
|
||||
if (cairo_font_options_status ((cairo_font_options_t *) options))
|
||||
return CAIRO_SUBPIXEL_POSITIONS_DEFAULT;
|
||||
|
||||
return options->subpixel_positions;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -889,12 +886,14 @@ composite_glyphs (void *_dst,
|
|||
for (i = 0; i < info->num_glyphs; i++) {
|
||||
unsigned long index = info->glyphs[i].index;
|
||||
const void *glyph;
|
||||
unsigned long xphase, yphase;
|
||||
|
||||
xphase = PHASE(info->glyphs[i].x);
|
||||
yphase = PHASE(info->glyphs[i].y);
|
||||
|
||||
index = index | (xphase << 24) | (yphase << 26);
|
||||
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 (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);
|
||||
if (!glyph) {
|
||||
|
|
@ -925,8 +924,15 @@ composite_glyphs (void *_dst,
|
|||
}
|
||||
}
|
||||
|
||||
pg->x = POSITION (info->glyphs[i].x);
|
||||
pg->y = POSITION (info->glyphs[i].y);
|
||||
if (info->font->options.subpixel_positions != CAIRO_SUBPIXEL_POSITIONS_OFF) {
|
||||
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);
|
||||
pg->y = _cairo_lround (info->glyphs[i].y);
|
||||
}
|
||||
pg->glyph = glyph;
|
||||
pg++;
|
||||
}
|
||||
|
|
@ -954,6 +960,20 @@ composite_glyphs (void *_dst,
|
|||
glyph_cache, pg - pglyphs, pglyphs);
|
||||
}
|
||||
|
||||
/* Don't keep 64x64 versions of each glyph in the cache */
|
||||
if (info->font->options.subpixel_positions == CAIRO_SUBPIXEL_POSITIONS_FINE) {
|
||||
int res = _cairo_subpixel_resolution (info->font->options.subpixel_positions);
|
||||
for (i = 0; i < info->num_glyphs; i++) {
|
||||
unsigned long index = info->glyphs[i].index;
|
||||
unsigned long xphase, yphase;
|
||||
xphase = _cairo_subpixel_phase (info->glyphs[i].x, res);
|
||||
yphase = _cairo_subpixel_phase (info->glyphs[i].y, res);
|
||||
index = index | (xphase << XSHIFT) | (yphase << YSHIFT);
|
||||
|
||||
pixman_glyph_cache_remove (glyph_cache, info->font, (void *)(uintptr_t)index);
|
||||
}
|
||||
}
|
||||
|
||||
out_thaw:
|
||||
pixman_glyph_cache_thaw (glyph_cache);
|
||||
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ struct _cairo_font_options {
|
|||
unsigned int palette_index;
|
||||
cairo_palette_color_t *custom_palette;
|
||||
unsigned int custom_palette_size;
|
||||
cairo_subpixel_positions_t subpixel_positions;
|
||||
};
|
||||
|
||||
struct _cairo_glyph_text_info {
|
||||
|
|
|
|||
|
|
@ -207,8 +207,11 @@ _cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_fon
|
|||
if (recording_surface)
|
||||
cairo_surface_destroy (recording_surface);
|
||||
recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE, foreground_color);
|
||||
recording_surface->device_transform.x0 = .25 * _cairo_scaled_glyph_xphase (scaled_glyph);
|
||||
recording_surface->device_transform.y0 = .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
|
||||
if (scaled_font->base.options.subpixel_positions != CAIRO_SUBPIXEL_POSITIONS_OFF) {
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -1608,14 +1605,23 @@ composite_glyphs (void *surface,
|
|||
op = _render_operator (op),
|
||||
_cairo_xlib_surface_ensure_picture (dst);
|
||||
for (i = 0; i < num_glyphs; i++) {
|
||||
unsigned long xphase, yphase;
|
||||
int this_x, this_y;
|
||||
int old_width;
|
||||
|
||||
xphase = PHASE(glyphs[i].d.x);
|
||||
yphase = PHASE(glyphs[i].d.y);
|
||||
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);
|
||||
|
||||
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,
|
||||
glyphs[i].index,
|
||||
|
|
@ -1625,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);
|
||||
|
|
|
|||
28
src/cairo.h
28
src/cairo.h
|
|
@ -1437,6 +1437,27 @@ typedef enum _cairo_color_mode {
|
|||
CAIRO_COLOR_MODE_COLOR
|
||||
} cairo_color_mode_t;
|
||||
|
||||
/**
|
||||
* cairo_subpixel_positions_t:
|
||||
* @CAIRO_SUBPIXEL_POSITONS_DEFAULT: Use subpixel positions in
|
||||
* the default manner for the font backend and target device, since 1.20
|
||||
* @CAIRO_SUBPIXEL_POSITIONS_OFF: Do not use subpixel positions, since 1.20
|
||||
* @CAIRO_SUBPIXEL_POSITIONS_ON: Use subpixel positions, since 1.20
|
||||
* @CAIRO_SUBPIXEL_POSITIONS_FINE: Use fine subpixel positions, since 1.20
|
||||
*
|
||||
* Specifies whether to use subpixel positions when rendering glyphs.
|
||||
* Without subpixel positions, glyph positions will be rounded to pixels.
|
||||
* With subpixel positions, glyph positions rounded to a subpixel grid.
|
||||
*
|
||||
* Since: 1.20
|
||||
*/
|
||||
typedef enum _cairo_subpixel_positions {
|
||||
CAIRO_SUBPIXEL_POSITIONS_DEFAULT,
|
||||
CAIRO_SUBPIXEL_POSITIONS_OFF,
|
||||
CAIRO_SUBPIXEL_POSITIONS_ON,
|
||||
CAIRO_SUBPIXEL_POSITIONS_FINE
|
||||
} cairo_subpixel_positions_t;
|
||||
|
||||
/**
|
||||
* cairo_font_options_t:
|
||||
*
|
||||
|
|
@ -1542,6 +1563,13 @@ cairo_font_options_get_custom_palette_color (cairo_font_options_t *options,
|
|||
double *red, double *green,
|
||||
double *blue, double *alpha);
|
||||
|
||||
cairo_public cairo_subpixel_positions_t
|
||||
cairo_font_options_get_subpixel_positions (const cairo_font_options_t *options);
|
||||
|
||||
cairo_public void
|
||||
cairo_font_options_set_subpixel_positions (cairo_font_options_t *options,
|
||||
cairo_subpixel_positions_t value);
|
||||
|
||||
/* This interface is for dealing with text as text, not caring about the
|
||||
font object inside the cairo_t. */
|
||||
|
||||
|
|
|
|||
|
|
@ -400,10 +400,47 @@ 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,
|
||||
[CAIRO_SUBPIXEL_POSITIONS_FINE] = 4,
|
||||
};
|
||||
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -1109,8 +1109,13 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
|
|||
FLOAT advance = 0;
|
||||
UINT16 index = (UINT16)_cairo_scaled_glyph_index (scaled_glyph);
|
||||
DWRITE_GLYPH_OFFSET offset;
|
||||
double x = -x1 + .25 * _cairo_scaled_glyph_xphase (scaled_glyph);
|
||||
double y = -y1 + .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
|
||||
double x = -x1;
|
||||
double y = -y1;
|
||||
if (scaled_font->base.options.subpixel_positions != CAIRO_SUBPIXEL_POSITIONS_OFF) {
|
||||
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};
|
||||
RefPtr<IDWriteColorGlyphRunEnumerator1> run_enumerator;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue