Merge branch 'fix-user-fonts-foreground' into 'master'

Add new cairo_user_scaled_font_get_foreground_source() function

See merge request cairo/cairo!422
This commit is contained in:
Adrian Johnson 2023-01-26 11:55:40 +00:00
commit 055ca7fb09
28 changed files with 466 additions and 183 deletions

View file

@ -57,6 +57,8 @@ cairo_user_font_face_set_unicode_to_glyph_func
cairo_user_font_face_get_unicode_to_glyph_func
cairo_user_font_face_set_text_to_glyphs_func
cairo_user_font_face_get_text_to_glyphs_func
cairo_user_scaled_font_get_foreground_marker
cairo_user_scaled_font_get_foreground_source
</SECTION>
<SECTION>

View file

@ -2685,7 +2685,7 @@ _cairo_ft_scaled_glyph_init_surface (cairo_ft_scaled_font_t *scaled_font,
_cairo_scaled_glyph_set_color_surface (scaled_glyph,
&scaled_font->base,
surface,
uses_foreground_color);
uses_foreground_color ? foreground_color : NULL);
scaled_glyph->color_glyph = TRUE;
} else {
@ -2797,7 +2797,8 @@ _cairo_ft_scaled_glyph_init_record_colr_v0_glyph (cairo_ft_scaled_font_t *scaled
_cairo_scaled_glyph_set_recording_surface (scaled_glyph,
&scaled_font->base,
recording_surface);
recording_surface,
NULL);
return status;
}
#endif
@ -2862,7 +2863,8 @@ _cairo_ft_scaled_glyph_init_record_colr_v1_glyph (cairo_ft_scaled_font_t *scaled
_cairo_scaled_glyph_set_recording_surface (scaled_glyph,
&scaled_font->base,
recording_surface);
recording_surface,
NULL);
scaled_glyph->color_glyph = TRUE;
scaled_glyph->color_glyph_set = TRUE;
@ -3009,7 +3011,8 @@ _cairo_ft_scaled_glyph_init_record_svg_glyph (cairo_ft_scaled_font_t *scaled_fon
_cairo_scaled_glyph_set_recording_surface (scaled_glyph,
&scaled_font->base,
recording_surface);
recording_surface,
NULL);
scaled_glyph->color_glyph = TRUE;
scaled_glyph->color_glyph_set = TRUE;
@ -3118,7 +3121,7 @@ _cairo_ft_scaled_glyph_init_surface_for_recording_surface (cairo_ft_scaled_font_
_cairo_scaled_glyph_set_color_surface (scaled_glyph,
&scaled_font->base,
(cairo_image_surface_t *)surface,
foreground_used);
foreground_used ? foreground_color : NULL);
surface = NULL;
if (surface)

View file

@ -656,7 +656,7 @@ _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
cairo_surface_mark_dirty (&surface->base);
if (is_color)
_cairo_scaled_glyph_set_color_surface (scaled_glyph, &font->base, surface, fg_color != NULL);
_cairo_scaled_glyph_set_color_surface (scaled_glyph, &font->base, surface, fg_color);
else
_cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface);

View file

@ -149,8 +149,12 @@ struct _cairo_scaled_glyph {
cairo_list_t dev_privates;
cairo_color_t foreground_color; /* only used for color glyphs */
/* TRUE if the recording_surface required the foreground_color to render. */
unsigned recording_uses_foreground_color : 1;
/* TRUE if the color_surface required the foreground_color to render. */
unsigned uses_foreground_color : 1;
unsigned image_uses_foreground_color : 1;
/* TRUE if color_glyph specifies if glyph is color or non color, FALSE if glyph color type unknown. */
unsigned color_glyph_set : 1;

View file

@ -2653,10 +2653,19 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_PATH;
}
/**
* _cairo_scaled_glyph_set_recording_surface:
* @scaled_glyph: a #cairo_scaled_glyph_t
* @scaled_font: a #cairo_scaled_font_t
* @recording_surface: The recording surface
* @foreground_color: The foreground color that was used to record the
* glyph, or NULL if foreground color not required.
*/
void
_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_surface_t *recording_surface)
cairo_scaled_font_t *scaled_font,
cairo_surface_t *recording_surface,
const cairo_color_t * foreground_color)
{
if (scaled_glyph->recording_surface != NULL) {
cairo_surface_finish (scaled_glyph->recording_surface);
@ -2664,6 +2673,9 @@ _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
}
scaled_glyph->recording_surface = recording_surface;
scaled_glyph->recording_uses_foreground_color = foreground_color != NULL;
if (foreground_color)
scaled_glyph->foreground_color = *foreground_color;
if (recording_surface != NULL)
scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
@ -2671,11 +2683,19 @@ _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
}
/**
* _cairo_scaled_glyph_set_color_surface:
* @scaled_glyph: a #cairo_scaled_glyph_t
* @scaled_font: a #cairo_scaled_font_t
* @surface: The image surface
* @foreground_color: The foreground color that was used to render the
* glyph, or NULL if foreground color not required.
*/
void
_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_image_surface_t *surface,
cairo_bool_t uses_foreground_color)
const cairo_color_t *foreground_color)
{
if (scaled_glyph->color_surface != NULL)
cairo_surface_destroy (&scaled_glyph->color_surface->base);
@ -2683,7 +2703,9 @@ _cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph,
/* sanity check the backend glyph contents */
_cairo_debug_check_image_surface_is_defined (&surface->base);
scaled_glyph->color_surface = surface;
scaled_glyph->uses_foreground_color = uses_foreground_color;
scaled_glyph->image_uses_foreground_color = foreground_color != NULL;
if (foreground_color)
scaled_glyph->foreground_color = *foreground_color;
if (surface != NULL)
scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
@ -2814,8 +2836,11 @@ _cairo_scaled_font_free_last_glyph (cairo_scaled_font_t *scaled_font,
* @index: the glyph to create
* @info: a #cairo_scaled_glyph_info_t marking which portions of
* the glyph should be filled in.
* @foreground_color - foreground color to use when rendering color fonts. Use NULL
* if not requesting CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE or foreground color is unknown.
* @foreground_color - foreground color to use when rendering color
* fonts. Use NULL if not requesting
* CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE or
* CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, or foreground color is
* unknown.
* @scaled_glyph_ret: a #cairo_scaled_glyph_t where the glyph
* is returned.
*
@ -2909,14 +2934,23 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
scaled_glyph->color_glyph_set && !scaled_glyph->color_glyph)
return CAIRO_INT_STATUS_UNSUPPORTED;
/* If requesting a color surface for a glyph that has used the
* foreground color to render the color_surface, and the
* foreground color has changed, request a new image. */
if ((info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) &&
scaled_glyph->uses_foreground_color &&
/* If requesting a color surface or recording for a glyph that has
* used the foreground color to render the color_surface, and the
* foreground color has changed, request a new image and/or
* recording. */
if (info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE &&
scaled_glyph->recording_uses_foreground_color &&
!_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color))
{
need_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
need_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
}
if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE &&
scaled_glyph->image_uses_foreground_color &&
!_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color))
{
need_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
}
if (need_info) {

View file

@ -95,13 +95,19 @@ typedef struct _cairo_user_scaled_font {
double snap_x_scale;
double snap_y_scale;
cairo_pattern_t *foreground_marker;
cairo_pattern_t *foreground_pattern;
cairo_bool_t foreground_marker_used;
cairo_bool_t foreground_colors_used;
} cairo_user_scaled_font_t;
/* #cairo_user_scaled_font_t */
static cairo_surface_t *
_cairo_user_scaled_font_create_recording_surface (const cairo_user_scaled_font_t *scaled_font,
cairo_bool_t color)
_cairo_user_scaled_font_create_recording_surface (cairo_user_scaled_font_t *scaled_font,
cairo_bool_t color,
const cairo_color_t *foreground_color)
{
cairo_content_t content;
@ -113,10 +119,20 @@ _cairo_user_scaled_font_create_recording_surface (const cairo_user_scaled_font_t
CAIRO_CONTENT_ALPHA;
}
if (scaled_font->foreground_pattern)
cairo_pattern_destroy (scaled_font->foreground_pattern);
scaled_font->foreground_marker_used = FALSE;
scaled_font->foreground_colors_used = FALSE;
if (foreground_color) {
scaled_font->foreground_pattern = _cairo_pattern_create_solid (foreground_color);
} else {
scaled_font->foreground_pattern = cairo_pattern_create_rgb (0, 0, 0);
}
return cairo_recording_surface_create (content, NULL);
}
static cairo_t *
_cairo_user_scaled_font_create_recording_context (const cairo_user_scaled_font_t *scaled_font,
cairo_surface_t *recording_surface,
@ -143,7 +159,8 @@ _cairo_user_scaled_font_create_recording_context (const cairo_user_scaled_font_t
static cairo_int_status_t
_cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph)
cairo_scaled_glyph_t *scaled_glyph,
const cairo_color_t *foreground_color)
{
cairo_user_font_face_t *face =
(cairo_user_font_face_t *) scaled_font->base.font_face;
@ -151,29 +168,25 @@ _cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_fon
cairo_surface_t *recording_surface = NULL;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_t *cr;
cairo_bool_t foreground_used = FALSE;
if (!face->scaled_font_methods.render_color_glyph && !face->scaled_font_methods.render_glyph)
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
/* special case for 0 rank matrix (as in _cairo_scaled_font_init): empty surface */
if (_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE);
recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE, foreground_color);
_cairo_scaled_glyph_set_recording_surface (scaled_glyph,
&scaled_font->base,
recording_surface);
recording_surface,
NULL);
} else {
status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
if (face->scaled_font_methods.render_color_glyph) {
cairo_pattern_t *pattern;
recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, TRUE);
recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, TRUE, foreground_color);
cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface, TRUE);
pattern = cairo_pattern_create_rgb (0, 0, 0);
pattern->is_userfont_foreground = TRUE;
cairo_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
status = face->scaled_font_methods.render_color_glyph ((cairo_scaled_font_t *)scaled_font,
_cairo_scaled_glyph_index(scaled_glyph),
cr, &extents);
@ -182,14 +195,16 @@ _cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_fon
scaled_glyph->color_glyph = TRUE;
scaled_glyph->color_glyph_set = TRUE;
}
cairo_destroy (cr);
foreground_used = scaled_font->foreground_marker_used || scaled_font->foreground_colors_used;
}
if (status == (cairo_int_status_t)CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED &&
face->scaled_font_methods.render_glyph) {
if (recording_surface)
cairo_surface_destroy (recording_surface);
recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE);
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);
@ -205,6 +220,7 @@ _cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_fon
}
cairo_destroy (cr);
foreground_used = FALSE;
}
if (status != CAIRO_INT_STATUS_SUCCESS) {
@ -215,7 +231,8 @@ _cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_fon
_cairo_scaled_glyph_set_recording_surface (scaled_glyph,
&scaled_font->base,
recording_surface);
recording_surface,
foreground_used ? foreground_color : NULL);
}
/* set metrics */
@ -265,8 +282,8 @@ _cairo_user_scaled_glyph_init_surface (cairo_user_scaled_font_t *scaled_font,
cairo_surface_t *surface;
cairo_format_t format;
int width, height;
cairo_bool_t foreground_used;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_bool_t foreground_used;
/* TODO
* extend the glyph cache to support argb glyphs.
@ -313,20 +330,23 @@ _cairo_user_scaled_glyph_init_surface (cairo_user_scaled_font_t *scaled_font,
surface,
foreground_color,
&foreground_used);
} else {
status = _cairo_recording_surface_replay (scaled_glyph->recording_surface, surface);
foreground_used = FALSE;
}
if (unlikely (status)) {
cairo_surface_destroy(surface);
return status;
}
foreground_used = foreground_used || scaled_glyph->recording_uses_foreground_color;
if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) {
_cairo_scaled_glyph_set_color_surface (scaled_glyph,
&scaled_font->base,
(cairo_image_surface_t *)surface,
foreground_used);
foreground_used ? foreground_color : NULL);
surface = NULL;
} else {
_cairo_scaled_glyph_set_surface (scaled_glyph,
@ -341,6 +361,18 @@ _cairo_user_scaled_glyph_init_surface (cairo_user_scaled_font_t *scaled_font,
return status;
}
static void
_cairo_user_scaled_glyph_fini (void *abstract_font)
{
cairo_user_scaled_font_t *scaled_font = abstract_font;
if (scaled_font->foreground_pattern)
cairo_pattern_destroy (scaled_font->foreground_pattern);
if (scaled_font->foreground_marker)
cairo_pattern_destroy (scaled_font->foreground_marker);
}
static cairo_int_status_t
_cairo_user_scaled_glyph_init (void *abstract_font,
cairo_scaled_glyph_t *scaled_glyph,
@ -349,9 +381,21 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_user_scaled_font_t *scaled_font = abstract_font;
cairo_bool_t need_recording = FALSE;
if (!scaled_glyph->recording_surface) {
status = _cairo_user_scaled_glyph_init_record_glyph (scaled_font, scaled_glyph);
need_recording = TRUE;
} else {
if ((info & (CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE|CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) &&
scaled_glyph->recording_uses_foreground_color &&
!_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color))
{
need_recording = TRUE;
}
}
if (need_recording) {
status = _cairo_user_scaled_glyph_init_record_glyph (scaled_font, scaled_glyph, foreground_color);
if (status)
return status;
}
@ -511,7 +555,7 @@ _cairo_user_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
static const cairo_scaled_font_backend_t _cairo_user_scaled_font_backend = {
CAIRO_FONT_TYPE_USER,
NULL, /* scaled_font_fini */
_cairo_user_scaled_glyph_fini,
_cairo_user_scaled_glyph_init,
_cairo_user_text_to_glyphs,
_cairo_user_ucs4_to_index,
@ -553,6 +597,10 @@ _cairo_user_font_face_scaled_font_create (void *abstract_
return status;
}
user_scaled_font->foreground_pattern = NULL;
user_scaled_font->foreground_marker = cairo_pattern_create_rgb (0, 0, 0);
user_scaled_font->foreground_marker->is_userfont_foreground = TRUE;
/* XXX metrics hinting? */
/* compute a normalized version of font scale matrix to compute
@ -601,7 +649,7 @@ _cairo_user_font_face_scaled_font_create (void *abstract_
cairo_surface_t *recording_surface;
cairo_t *cr;
recording_surface = _cairo_user_scaled_font_create_recording_surface (user_scaled_font, FALSE);
recording_surface = _cairo_user_scaled_font_create_recording_surface (user_scaled_font, FALSE, NULL);
cr = _cairo_user_scaled_font_create_recording_context (user_scaled_font, recording_surface, FALSE);
cairo_surface_destroy (recording_surface);
@ -1056,3 +1104,119 @@ cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face)
user_font_face = (cairo_user_font_face_t *) font_face;
return user_font_face->scaled_font_methods.unicode_to_glyph;
}
/**
* cairo_user_scaled_font_get_foreground_marker:
* @scaled_font: A user scaled font
*
* Gets the foreground pattern of the glyph currently being
* rendered. A #cairo_user_scaled_font_render_glyph_func_t function
* that has been set with
* cairo_user_font_face_set_render_color_glyph_func() may call this
* function to retrieve the current foreground pattern for the glyph
* being rendered. The function should not be called outside of a
* cairo_user_font_face_set_render_color_glyph_func() callback.
*
* The foreground marker pattern contains an internal marker to
* indicate that it is to be substituted with the current source when
* rendered to a surface. Querying the foreground marker will reveal a
* solid black color, however this is not representative of the color
* that will actually be used. Similarly, setting a solid black color
* will render black, not the foreground pattern when the glyph is
* painted to a surface. Using the foreground marker as the source
* instead of cairo_user_scaled_font_get_foreground_source() in a
* color render callback has the following benefits:
*
* 1. Cairo only needs to call the render callback once as it can
* cache the recording. Cairo will substitute the actual foreground
* color when rendering the recording.
*
* 2. On backends that have the concept of a foreground color in fonts such as
* PDF, PostScript, and SVG, cairo can generate more optimal
* output. The glyph can be included in an embedded font.
*
* The one drawback of the using foreground marker is the render
* callback can not access the color components of the pattern as the
* actual foreground pattern is not available at the time the render
* callback is invoked. If the render callback needs to query the
* foreground pattern, use
* cairo_user_scaled_font_get_foreground_source().
*
* If the render callback simply wants to call cairo_set_source() with
* the foreground pattern,
* cairo_user_scaled_font_get_foreground_marker() is the preferred
* function to use as it results in better performance than
* cairo_user_scaled_font_get_foreground_source().
*
* Return value: the current foreground source marker pattern. This
* object is owned by cairo. This object must not be modified or used
* outside of a color render callback. To keep a reference to it,
* you must call cairo_pattern_reference().
*
* Since: 1.18
**/
cairo_pattern_t *
cairo_user_scaled_font_get_foreground_marker (cairo_scaled_font_t *scaled_font)
{
cairo_user_scaled_font_t *user_scaled_font;
if (scaled_font->backend != &_cairo_user_scaled_font_backend)
return _cairo_pattern_create_in_error (CAIRO_STATUS_FONT_TYPE_MISMATCH);
user_scaled_font = (cairo_user_scaled_font_t *)scaled_font;
return user_scaled_font->foreground_marker;
}
/**
* cairo_user_scaled_font_get_foreground_source:
* @scaled_font: A user scaled font
*
* Gets the foreground pattern of the glyph currently being
* rendered. A #cairo_user_scaled_font_render_glyph_func_t function
* that has been set with
* cairo_user_font_face_set_render_color_glyph_func() may call this
* function to retrieve the current foreground pattern for the glyph
* being rendered. The function should not be called outside of a
* cairo_user_font_face_set_render_color_glyph_func() callback.
*
* This function returns the current source at the time the glyph is
* rendered. Compared with
* cairo_user_scaled_font_get_foreground_marker(), this function
* returns the actual source pattern that will be used to render the
* glyph. The render callback is free to query the pattern and
* extract color components or other pattern data. For example if the
* render callback wants to create a gradient stop based on colors in
* the foreground source pattern, it will need to use this function in
* order to be able to query the colors in the foreground pattern.
*
* While this function does not have the restrictions on using the
* pattern that cairo_user_scaled_font_get_foreground_marker() has, it
* does incur a performance penalty. If a render callback calls this
* function:
*
* 1. Cairo will call the render callback whenever the current pattern
* of the context in which the glyph is rendered changes.
*
* 2. On backends that support font embedding (PDF, PostScript, and
* SVG), cairo can not embed this glyph in a font. Instead the glyph
* will be emitted as an image or sequence of drawing operations each
* time it is used.
*
* Return value: the current foreground source pattern. This object is
* owned by cairo. To keep a reference to it, you must call
* cairo_pattern_reference().
*
* Since: 1.18
**/
cairo_pattern_t *
cairo_user_scaled_font_get_foreground_source (cairo_scaled_font_t *scaled_font)
{
cairo_user_scaled_font_t *user_scaled_font;
if (scaled_font->backend != &_cairo_user_scaled_font_backend)
return _cairo_pattern_create_in_error (CAIRO_STATUS_FONT_TYPE_MISMATCH);
user_scaled_font = (cairo_user_scaled_font_t *)scaled_font;
user_scaled_font->foreground_colors_used = TRUE;
return user_scaled_font->foreground_pattern;
}

View file

@ -1815,25 +1815,14 @@ typedef cairo_status_t (*cairo_user_scaled_font_init_func_t) (cairo_scaled_font_
* cairo_user_font_face_set_render_glyph_func(), the result is
* undefined if any source other than the default source on @cr is
* used. That means, glyph bitmaps should be rendered using
* cairo_mask() instead of cairo_paint(). When this callback is set with
* cairo_user_font_face_set_render_color_glyph_func(), setting the
* source is a valid operation.
* cairo_mask() instead of cairo_paint().
*
* When this callback is set with
* cairo_user_font_face_set_render_color_glyph_func(), the default
* source is the current source color of the context that is rendering
* the user font. That is, the same color a non-color user font will
* be rendered in. In most cases the callback will want to set a
* specific color. If the callback wishes to use the current context
* color after using another source, it should retain a reference to
* the source or use cairo_save()/cairo_restore() prior to changing
* the source. Note that the default source contains an internal
* marker to indicate that it is to be substituted with the current
* context source color when rendered to a surface. Querying the
* default source pattern will reveal a solid black color, however
* this is not representative of the color that will actually be
* used. Similarly, setting a solid black color will render black, not
* the current context source when the glyph is painted to a surface.
* source is black. Setting the source is a valid
* operation. cairo_user_scaled_font_get_foreground_marker() or
* cairo_user_scaled_font_get_foreground_source() may be called to
* obtain the current source at the time the glyph is rendered.
*
* Other non-default settings on @cr include a font size of 1.0 (given that
* it is set up to be in font space), and font options corresponding to
@ -1856,10 +1845,13 @@ typedef cairo_status_t (*cairo_user_scaled_font_init_func_t) (cairo_scaled_font_
* Where both color and non-color callbacks has been set using
* cairo_user_font_face_set_render_color_glyph_func(), and
* cairo_user_font_face_set_render_glyph_func(), the color glyph
* callback may return %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED if the
* glyph is not a color glyph. This is the only case in which the
* %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED may be returned from a
* render callback.
* callback will be called first. If the color glyph callback returns
* %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, any drawing operations are
* discarded and the non-color callback will be called. This is the
* only case in which the %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED may
* be returned from a render callback. This fallback sequence allows a
* user font face to contain a combination of both color and non-color
* glyphs.
*
* Returns: %CAIRO_STATUS_SUCCESS upon success,
* %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED if fallback options should be tried,
@ -2027,6 +2019,11 @@ cairo_user_font_face_get_text_to_glyphs_func (cairo_font_face_t *font_face);
cairo_public cairo_user_scaled_font_unicode_to_glyph_func_t
cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face);
cairo_public cairo_pattern_t *
cairo_user_scaled_font_get_foreground_marker (cairo_scaled_font_t *scaled_font);
cairo_public cairo_pattern_t *
cairo_user_scaled_font_get_foreground_source (cairo_scaled_font_t *scaled_font);
/* Query functions */

View file

@ -1292,13 +1292,14 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
cairo_private void
_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_surface_t *recording_surface);
cairo_surface_t *recording_surface,
const cairo_color_t *foreground_color);
cairo_private void
_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_image_surface_t *surface,
cairo_bool_t uses_foreground_color);
const cairo_color_t *foreground_color);
cairo_private cairo_int_status_t
_cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,

View file

@ -1065,7 +1065,7 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
_cairo_scaled_glyph_set_color_surface (scaled_glyph,
&scaled_font->base,
(cairo_image_surface_t *) image,
uses_foreground_color);
uses_foreground_color ? foreground_color : NULL);
scaled_glyph->color_glyph = TRUE;
scaled_glyph->color_glyph_set = TRUE;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -32,16 +32,27 @@
#include "cairo-test.h"
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#define BORDER 10
#define TEXT_SIZE 64
#define WIDTH (TEXT_SIZE * 12 + 2*BORDER)
#define HEIGHT (TEXT_SIZE + 2*BORDER)
#define WIDTH (TEXT_SIZE * 11 + 2*BORDER)
#define HEIGHT (4*TEXT_SIZE + 5*BORDER)
#define TEXT "abcdefghijkl"
#define TEXT "abcdefghij"
/* These characters will be drawn twice with a different foreground color */
#define FG_TEXT "acfh"
/* Uppercase draws the same text but forces the use of the non-color
* render callback */
#define TEXT_NO_COLOR "ABCDEFGHIJ"
#define FG_TEXT_NO_COLOR "ACFH"
#define TEXT_PATH "aabccdeffghhij"
static cairo_status_t
@ -55,40 +66,60 @@ test_scaled_font_init (cairo_scaled_font_t *scaled_font,
}
static void
render_glyph_solid (cairo_t *cr, double width, double height, cairo_bool_t color)
render_glyph_solid (cairo_t *cr,
double width,
double height,
cairo_bool_t color,
cairo_scaled_font_t *scaled_font)
{
cairo_pattern_t *pattern = cairo_pattern_reference(cairo_get_source (cr));
if (color)
cairo_set_source_rgba (cr, 0, 1, 1, 0.5);
cairo_set_source_rgba (cr, 0.7, 0.2, 0.1, 0.9);
cairo_rectangle (cr, 0, 0, width/2, height/2);
cairo_fill (cr);
/* Draw the middle rectangle using the foreground color */
if (color)
cairo_set_source (cr, pattern);
if (color) {
if (scaled_font)
cairo_set_source (cr, cairo_user_scaled_font_get_foreground_marker (scaled_font));
else
cairo_set_source_rgba (cr, 0.2, 0.5, 0.3, 0.9);
}
cairo_rectangle (cr, width/4, height/4, width/2, height/2);
cairo_fill (cr);
if (color)
cairo_set_source_rgba (cr, 1, 1, 0, 0.5);
cairo_set_source_rgba (cr, 0.2, 0.3, 0.5, 0.9);
cairo_rectangle (cr, width/2, height/2, width/2, height/2);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
}
static void
render_glyph_linear (cairo_t *cr, double width, double height, cairo_bool_t color)
render_glyph_linear (cairo_t *cr,
double width,
double height,
cairo_bool_t color,
cairo_scaled_font_t *scaled_font)
{
cairo_pattern_t *pat;
cairo_pattern_t *fg;
pat = cairo_pattern_create_linear (0.0, 0.0, width, height);
cairo_pattern_add_color_stop_rgba (pat, 0, 1, 0, 0, 1);
cairo_pattern_add_color_stop_rgba (pat, 0.5, 0, 1, 0, color ? 0.5 : 1);
cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 1, 1);
cairo_set_source (cr, pat);
if (scaled_font) {
double r, g, b, a;
fg = cairo_user_scaled_font_get_foreground_source (scaled_font);
if (cairo_pattern_get_rgba (fg, &r, &g, &b, &a) != CAIRO_STATUS_SUCCESS) {
r = g = b = 0;
a = 1;
}
cairo_pattern_add_color_stop_rgba (pat, 0, r, g, b, a);
cairo_pattern_add_color_stop_rgb (pat, 1, 0, 0, 1);
} else {
cairo_pattern_add_color_stop_rgb (pat, 0, 1, 0.4, 0.2);
cairo_pattern_add_color_stop_rgb (pat, 0.5, 0.2, 1, 0.4);
cairo_pattern_add_color_stop_rgb (pat, 1, 0.2, 0.3, 1);
}
cairo_set_source (cr, pat);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
}
@ -102,23 +133,23 @@ render_glyph_text (cairo_t *cr, double width, double height, cairo_bool_t color)
cairo_set_font_size(cr, 0.5);
if (color)
cairo_set_source_rgb (cr, 0.5, 0.5, 0);
cairo_set_source_rgb (cr, 0.5, 0.7, 0);
cairo_move_to (cr, width*0.1, height/2);
cairo_show_text (cr, "a");
if (color)
cairo_set_source_rgb (cr, 0, 0.5, 0.5);
cairo_set_source_rgb (cr, 0, 0.5, 0.7);
cairo_move_to (cr, width*0.4, height*0.9);
cairo_show_text (cr, "z");
}
static cairo_status_t
test_scaled_font_render_color_glyph (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *metrics)
test_scaled_font_render_glyph_common (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *metrics,
cairo_bool_t color)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
double width = 0.5;
double height = 0.8;
@ -126,101 +157,80 @@ test_scaled_font_render_color_glyph (cairo_scaled_font_t *scaled_font,
cairo_translate (cr, 0.125, -0.6);
switch (glyph) {
case 'a':
render_glyph_solid (cr, width, height, TRUE);
render_glyph_solid (cr, width, height, color, scaled_font);
break;
case 'b':
render_glyph_linear (cr, width, height, TRUE);
render_glyph_solid (cr, width, height, color, NULL);
break;
case 'c':
render_glyph_text (cr, width, height, TRUE);
render_glyph_linear (cr, width, height, color, scaled_font);
break;
/* Ensure that the following glyphs are rendered with
* test_scaled_font_render_glyph() even if we draw
* something before returning.
*/
case 'd':
render_glyph_solid (cr, width, height, TRUE);
status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
render_glyph_linear (cr, width, height, color, NULL);
break;
case 'e':
render_glyph_linear (cr, width, height, TRUE);
status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
render_glyph_text (cr, width, height, color);
break;
case 'f':
render_glyph_solid (cr, width, height, TRUE);
status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
cairo_push_group (cr);
render_glyph_solid (cr, width, height, color, scaled_font);
cairo_pop_group_to_source (cr);
cairo_paint (cr);
break;
case 'g':
cairo_push_group (cr);
render_glyph_solid (cr, width, height, TRUE);
render_glyph_solid (cr, width, height, color, NULL);
cairo_pop_group_to_source (cr);
cairo_paint (cr);
break;
case 'h':
cairo_push_group (cr);
render_glyph_linear (cr, width, height, TRUE);
render_glyph_linear (cr, width, height, color, scaled_font);
cairo_pop_group_to_source (cr);
cairo_paint (cr);
break;
case 'i':
cairo_push_group (cr);
render_glyph_text (cr, width, height, TRUE);
render_glyph_linear (cr, width, height, color, NULL);
cairo_pop_group_to_source (cr);
cairo_paint (cr);
break;
default:
status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
}
return status;
}
static cairo_status_t
test_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *metrics)
{
double width = 0.5;
double height = 0.8;
metrics->x_advance = 0.75;
cairo_translate (cr, 0.125, -0.6);
switch (glyph) {
case 'd':
render_glyph_solid (cr, width, height, FALSE);
break;
case 'e':
render_glyph_linear (cr, width, height, FALSE);
break;
case 'f':
render_glyph_text (cr, width, height, FALSE);
break;
case 'j':
cairo_push_group (cr);
render_glyph_solid (cr, width, height, FALSE);
render_glyph_text (cr, width, height, color);
cairo_pop_group_to_source (cr);
cairo_paint (cr);
break;
case 'k':
cairo_push_group (cr);
render_glyph_linear (cr, width, height, FALSE);
cairo_pop_group_to_source (cr);
cairo_paint (cr);
break;
case 'l':
cairo_push_group (cr);
render_glyph_text (cr, width, height, FALSE);
cairo_pop_group_to_source (cr);
cairo_paint (cr);
break;
default:
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
test_scaled_font_render_color_glyph_callback (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *metrics)
{
if (isupper(glyph))
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
return test_scaled_font_render_glyph_common (scaled_font, glyph, cr, metrics, TRUE);
}
static cairo_status_t
test_scaled_font_render_glyph_callback (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *metrics)
{
int c = glyph;
if (isupper(c))
c = tolower(c);
return test_scaled_font_render_glyph_common (scaled_font, c, cr, metrics, FALSE);
}
static cairo_status_t
_user_font_face_create (cairo_font_face_t **out)
{
@ -229,13 +239,35 @@ _user_font_face_create (cairo_font_face_t **out)
user_font_face = cairo_user_font_face_create ();
cairo_user_font_face_set_init_func (user_font_face, test_scaled_font_init);
cairo_user_font_face_set_render_color_glyph_func (user_font_face, test_scaled_font_render_color_glyph);
cairo_user_font_face_set_render_glyph_func (user_font_face, test_scaled_font_render_glyph);
cairo_user_font_face_set_render_color_glyph_func (user_font_face,
test_scaled_font_render_color_glyph_callback);
cairo_user_font_face_set_render_glyph_func (user_font_face,
test_scaled_font_render_glyph_callback);
*out = user_font_face;
return CAIRO_STATUS_SUCCESS;
}
/* Any text characters that are in fg_text will be drawn with a different color */
static void
draw_line (cairo_t *cr, const char *text, const char *fg_text)
{
char buf[10];
for (unsigned i = 0; i < strlen(text); i++) {
buf[0] = text[i];
buf[1] = 0;
if (strchr (fg_text, text[i])) {
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_show_text (cr, buf);
}
cairo_set_source_rgb (cr, 0, 1, 0);
cairo_show_text (cr, buf);
}
}
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
@ -244,6 +276,7 @@ draw (cairo_t *cr, int width, int height)
cairo_font_extents_t font_extents;
cairo_text_extents_t extents;
cairo_status_t status;
cairo_font_options_t *font_options;
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
@ -285,10 +318,31 @@ draw (cairo_t *cr, int width, int height)
cairo_set_line_width (cr, 2);
cairo_stroke (cr);
/* text in color */
cairo_set_source_rgb (cr, 0, 0.3, 0);
/* Line 1: text in color */
cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
cairo_show_text (cr, text);
draw_line (cr, TEXT, FG_TEXT);
/* Line 2: text in non-color (color render callback returns
* CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED.
*/
cairo_move_to (cr, BORDER, BORDER + font_extents.height + 1*BORDER + font_extents.ascent);
draw_line (cr, TEXT_NO_COLOR, FG_TEXT_NO_COLOR);
/* Line 3: Filled version of color text in blue */
cairo_move_to (cr, BORDER, BORDER + 2*font_extents.height + 2*BORDER + font_extents.ascent);
cairo_set_source_rgb (cr, 0, 0, 1);
cairo_text_path (cr, TEXT_PATH);
cairo_fill (cr);
/* Line 4: color glyphs with CAIRO_COLOR_MODE_NO_COLOR font option. */
font_options = cairo_font_options_create ();
cairo_get_font_options (cr, font_options);
cairo_font_options_set_color_mode (font_options, CAIRO_COLOR_MODE_NO_COLOR);
cairo_set_font_options (cr, font_options);
cairo_font_options_destroy (font_options);
cairo_move_to (cr, BORDER, BORDER + 3*font_extents.height + 3*BORDER + font_extents.ascent);
draw_line (cr, TEXT, FG_TEXT);
return CAIRO_TEST_SUCCESS;
}

View file

@ -40,7 +40,9 @@
#else
#define HEIGHT WIDTH
#endif
#define TEXT "geez... cairo user-font"
#define TEXT1 "cairo user-font."
#define TEXT2 " zg"
static cairo_user_data_key_t fallback_font_key;
@ -148,11 +150,16 @@ _user_font_face_create (cairo_font_face_t **out)
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
const char text[] = TEXT;
cairo_font_extents_t font_extents;
cairo_text_extents_t extents;
cairo_font_face_t *font_face;
cairo_status_t status;
char full_text[100];
strcpy(full_text, TEXT1);
strcat(full_text, TEXT2);
strcat(full_text, TEXT2);
strcat(full_text, TEXT2);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
@ -174,7 +181,7 @@ draw (cairo_t *cr, int width, int height)
cairo_set_font_size (cr, TEXT_SIZE);
cairo_font_extents (cr, &font_extents);
cairo_text_extents (cr, text, &extents);
cairo_text_extents (cr, full_text, &extents);
/* logical boundaries in red */
cairo_move_to (cr, 0, BORDER);
@ -199,16 +206,26 @@ draw (cairo_t *cr, int width, int height)
cairo_set_line_width (cr, 2);
cairo_stroke (cr);
/* text in gray */
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
cairo_show_text (cr, text);
/* TEXT1 in black */
cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_show_text (cr, TEXT1);
/* Draw TEXT2 three times with three different foreground colors.
* This checks that cairo uses the foreground color and does not cache
* glyph images when the foreground color changes.
*/
cairo_show_text (cr, TEXT2);
cairo_set_source_rgb (cr, 0, 0.5, 0);
cairo_show_text (cr, TEXT2);
cairo_set_source_rgb (cr, 0.2, 0.5, 0.5);
cairo_show_text (cr, TEXT2);
/* filled version of text in light blue */
cairo_set_source_rgb (cr, 0, 0, 1);
cairo_move_to (cr, BORDER, BORDER + font_extents.height + BORDER + font_extents.ascent);
cairo_text_path (cr, text);
cairo_text_path (cr, full_text);
cairo_fill (cr);
return CAIRO_TEST_SUCCESS;

View file

@ -34,7 +34,7 @@
#define BORDER 10
#define TEXT_SIZE 64
#define WIDTH (TEXT_SIZE * 15 + 2*BORDER)
#define WIDTH (TEXT_SIZE * 16 + 2*BORDER)
#ifndef ROTATED
#define HEIGHT ((TEXT_SIZE + 2*BORDER)*3)
#else
@ -42,7 +42,7 @@
#endif
#define TEXT1 "cairo user-font."
#define TEXT2 " zg."
#define TEXT2 " zg"
#define END_GLYPH 0
#define STROKE 126
@ -202,6 +202,24 @@ _user_font_face_create (cairo_font_face_t **out, cairo_bool_t color_render)
return CAIRO_STATUS_SUCCESS;
}
static void
draw_line (cairo_t *cr)
{
/* TEXT1 in black */
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_show_text (cr, TEXT1);
/* Draw TEXT2 three times with three different foreground colors.
* This checks that cairo uses the foreground color and does not cache
* glyph images when the foreground color changes.
*/
cairo_show_text (cr, TEXT2);
cairo_set_source_rgb (cr, 0, 0.5, 0);
cairo_show_text (cr, TEXT2);
cairo_set_source_rgb (cr, 0.2, 0.5, 0.5);
cairo_show_text (cr, TEXT2);
}
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
@ -214,6 +232,7 @@ draw (cairo_t *cr, int width, int height)
strcpy(full_text, TEXT1);
strcat(full_text, TEXT2);
strcat(full_text, TEXT2);
strcat(full_text, TEXT2);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
@ -260,21 +279,14 @@ draw (cairo_t *cr, int width, int height)
cairo_set_line_width (cr, 2);
cairo_stroke (cr);
/* First line. Text in black, except first "zg." in green */
cairo_set_source_rgb (cr, 0, 0, 0);
/* First line. TEXT1 in black. TEXT2 in different colors. */
cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
cairo_show_text (cr, TEXT1);
cairo_set_source_rgb (cr, 0, 1, 0);
cairo_show_text (cr, TEXT2);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_show_text (cr, TEXT2);
draw_line (cr);
/* Now draw the second line using the render_color_glyph callback. The
* output should be the same because same render function is used
* and the render function does not set a color. This exercises
* the paint color glyph with foreground color code path and
* ensures cairo updates the glyph image when the foreground color
* changes.
/* Now draw the second line using the render_color_glyph
* callback. The text should be all black because the default
* color of render function is used instead of the foreground
* color.
*/
status = _user_font_face_create (&font_face, TRUE);
if (status) {
@ -287,13 +299,8 @@ draw (cairo_t *cr, int width, int height)
cairo_set_font_size (cr, TEXT_SIZE);
/* text in black, except first "zg." in green */
cairo_move_to (cr, BORDER, BORDER + font_extents.height + 2*BORDER + font_extents.ascent);
cairo_show_text (cr, TEXT1);
cairo_set_source_rgb (cr, 0, 1, 0);
cairo_show_text (cr, TEXT2);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_show_text (cr, TEXT2);
draw_line (cr);
/* Third line. Filled version of text in blue */
cairo_set_source_rgb (cr, 0, 0, 1);