diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt index 2aeecdca1..4b07fa3c7 100644 --- a/doc/public/cairo-sections.txt +++ b/doc/public/cairo-sections.txt @@ -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
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 254dcf25e..e6a8d20e3 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -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) diff --git a/src/cairo-quartz-font.c b/src/cairo-quartz-font.c index 641a2dfc7..1e7531356 100644 --- a/src/cairo-quartz-font.c +++ b/src/cairo-quartz-font.c @@ -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); diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h index bcc13bdc8..8c10b60c7 100644 --- a/src/cairo-scaled-font-private.h +++ b/src/cairo-scaled-font-private.h @@ -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; diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index cc52ed577..d7e3f1e4b 100755 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -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) { diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c index 80cd4c303..913395fd9 100644 --- a/src/cairo-user-font.c +++ b/src/cairo-user-font.c @@ -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; +} diff --git a/src/cairo.h b/src/cairo.h index c74d7c2c5..a9b423b28 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -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 */ diff --git a/src/cairoint.h b/src/cairoint.h index 65bc16f53..af2501057 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -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, diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp index 764835bc8..f0657d636 100644 --- a/src/win32/cairo-dwrite-font.cpp +++ b/src/win32/cairo-dwrite-font.cpp @@ -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; diff --git a/test/reference/user-font-color.image16.ref.png b/test/reference/user-font-color.image16.ref.png index 6e3fe434c..25a95ddac 100644 Binary files a/test/reference/user-font-color.image16.ref.png and b/test/reference/user-font-color.image16.ref.png differ diff --git a/test/reference/user-font-color.pdf.ref.png b/test/reference/user-font-color.pdf.ref.png index 9cb145202..dc0962d70 100644 Binary files a/test/reference/user-font-color.pdf.ref.png and b/test/reference/user-font-color.pdf.ref.png differ diff --git a/test/reference/user-font-color.quartz.ref.png b/test/reference/user-font-color.quartz.ref.png index 712e9a3d9..bb76c16ab 100644 Binary files a/test/reference/user-font-color.quartz.ref.png and b/test/reference/user-font-color.quartz.ref.png differ diff --git a/test/reference/user-font-color.recording.ref.png b/test/reference/user-font-color.recording.ref.png index 68c058adc..e6f9f389e 100644 Binary files a/test/reference/user-font-color.recording.ref.png and b/test/reference/user-font-color.recording.ref.png differ diff --git a/test/reference/user-font-color.ref.png b/test/reference/user-font-color.ref.png index 9c33df7cd..e210c718d 100644 Binary files a/test/reference/user-font-color.ref.png and b/test/reference/user-font-color.ref.png differ diff --git a/test/reference/user-font-color.script.xfail.png b/test/reference/user-font-color.script.xfail.png index 61ceab505..19b45e714 100644 Binary files a/test/reference/user-font-color.script.xfail.png and b/test/reference/user-font-color.script.xfail.png differ diff --git a/test/reference/user-font-color.svg.xfail.png b/test/reference/user-font-color.svg.xfail.png new file mode 100644 index 000000000..fd10d6653 Binary files /dev/null and b/test/reference/user-font-color.svg.xfail.png differ diff --git a/test/reference/user-font-color.xcb.ref.png b/test/reference/user-font-color.xcb.ref.png new file mode 100644 index 000000000..45b323473 Binary files /dev/null and b/test/reference/user-font-color.xcb.ref.png differ diff --git a/test/reference/user-font-color.xlib.ref.png b/test/reference/user-font-color.xlib.ref.png new file mode 100644 index 000000000..45b323473 Binary files /dev/null and b/test/reference/user-font-color.xlib.ref.png differ diff --git a/test/reference/user-font-proxy.pdf.argb32.ref.png b/test/reference/user-font-proxy.pdf.argb32.ref.png index 749c61bcd..bda5eec9d 100644 Binary files a/test/reference/user-font-proxy.pdf.argb32.ref.png and b/test/reference/user-font-proxy.pdf.argb32.ref.png differ diff --git a/test/reference/user-font-proxy.pdf.rgb24.ref.png b/test/reference/user-font-proxy.pdf.rgb24.ref.png index 749c61bcd..bda5eec9d 100644 Binary files a/test/reference/user-font-proxy.pdf.rgb24.ref.png and b/test/reference/user-font-proxy.pdf.rgb24.ref.png differ diff --git a/test/reference/user-font-proxy.ref.png b/test/reference/user-font-proxy.ref.png index 95c04633f..65014847a 100644 Binary files a/test/reference/user-font-proxy.ref.png and b/test/reference/user-font-proxy.ref.png differ diff --git a/test/reference/user-font-proxy.svg.ref.png b/test/reference/user-font-proxy.svg.ref.png index 106583e0f..7a083e6d8 100644 Binary files a/test/reference/user-font-proxy.svg.ref.png and b/test/reference/user-font-proxy.svg.ref.png differ diff --git a/test/reference/user-font.quartz.ref.png b/test/reference/user-font.quartz.ref.png index f1a8d5752..665801d37 100644 Binary files a/test/reference/user-font.quartz.ref.png and b/test/reference/user-font.quartz.ref.png differ diff --git a/test/reference/user-font.recording.ref.png b/test/reference/user-font.recording.ref.png index aefe4c9fe..c1cb2bbc3 100644 Binary files a/test/reference/user-font.recording.ref.png and b/test/reference/user-font.recording.ref.png differ diff --git a/test/reference/user-font.ref.png b/test/reference/user-font.ref.png index 87a3f68e3..5a6af5490 100644 Binary files a/test/reference/user-font.ref.png and b/test/reference/user-font.ref.png differ diff --git a/test/user-font-color.c b/test/user-font-color.c index c35e693be..db8b6a173 100644 --- a/test/user-font-color.c +++ b/test/user-font-color.c @@ -32,16 +32,27 @@ #include "cairo-test.h" +#include #include #include #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; } diff --git a/test/user-font-proxy.c b/test/user-font-proxy.c index e4063f0eb..42f51b602 100644 --- a/test/user-font-proxy.c +++ b/test/user-font-proxy.c @@ -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; diff --git a/test/user-font.c b/test/user-font.c index d02a90f4d..a8aed23b3 100644 --- a/test/user-font.c +++ b/test/user-font.c @@ -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);