Fix user-font with foreground in group failures on image, PDF, and PS

This commit is contained in:
Adrian Johnson 2022-12-31 20:53:37 +10:30
parent 513c49e623
commit f0ce8658f9
27 changed files with 94 additions and 160 deletions

View file

@ -50,4 +50,6 @@ text-antialias-subpixel-rgb
text-antialias-subpixel-vbgr
text-antialias-subpixel-vrgb
text-unhinted-metrics
user-font-color
user-font-proxy
user-font-rescale

View file

@ -81,4 +81,6 @@ text-antialias-subpixel-vbgr
text-antialias-subpixel-vrgb
text-unhinted-metrics
thin-lines
user-font-color
user-font-proxy
user-font-rescale

View file

@ -50,3 +50,4 @@ text-rotate
text-unhinted-metrics
tighten-bounds
unbounded-operator
user-font-color

View file

@ -107,3 +107,4 @@ tighten-bounds
unbounded-operator
xcb-surface-source
xlib-surface-source
user-font-color

View file

@ -2944,6 +2944,7 @@ _cairo_ft_scaled_glyph_init_surface_svg_glyph (cairo_ft_scaled_font_t *scaled_fo
cairo_surface_t *surface;
int width, height;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_bool_t foreground_used;
width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) -
_cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
@ -2958,7 +2959,8 @@ _cairo_ft_scaled_glyph_init_surface_svg_glyph (cairo_ft_scaled_font_t *scaled_fo
status = _cairo_recording_surface_replay_with_foreground_color (scaled_glyph->recording_surface,
surface,
foreground_color);
foreground_color,
&foreground_used);
if (unlikely (status)) {
cairo_surface_destroy(surface);
return status;
@ -2967,7 +2969,7 @@ _cairo_ft_scaled_glyph_init_surface_svg_glyph (cairo_ft_scaled_font_t *scaled_fo
_cairo_scaled_glyph_set_color_surface (scaled_glyph,
&scaled_font->base,
(cairo_image_surface_t *)surface,
TRUE);
foreground_used);
surface = NULL;
if (surface)

View file

@ -1207,6 +1207,8 @@ _pixman_image_for_recording (cairo_image_surface_t *dst,
clone = _cairo_image_surface_create_with_content (source->content,
limit.width,
limit.height);
if (dst->base.foreground_source)
clone->foreground_source = cairo_pattern_reference (dst->base.foreground_source);
}
m = NULL;
@ -1224,6 +1226,8 @@ _pixman_image_for_recording (cairo_image_surface_t *dst,
/* Handle recursion by returning future reads from the current image */
proxy = attach_proxy (source, clone);
status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL);
if (clone->foreground_used)
dst->base.foreground_used = clone->foreground_used;
detach_proxy (source, proxy);
if (unlikely (status)) {
cairo_surface_destroy (clone);

View file

@ -6453,47 +6453,6 @@ _cairo_pdf_emit_imagemask (cairo_image_surface_t *image,
return _cairo_output_stream_get_status (stream);
}
static cairo_int_status_t
_cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
void *closure)
{
cairo_pdf_surface_t *surface = closure;
cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
cairo_int_status_t status2;
unsigned int i;
cairo_surface_t *type3_surface;
cairo_output_stream_t *null_stream;
null_stream = _cairo_null_stream_create ();
type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
null_stream,
_cairo_pdf_emit_imagemask,
surface->font_subsets,
FALSE);
if (unlikely (type3_surface->status)) {
status2 = _cairo_output_stream_destroy (null_stream);
return type3_surface->status;
}
_cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
_cairo_pdf_surface_add_font,
surface);
for (i = 0; i < font_subset->num_glyphs; i++) {
status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
font_subset->glyphs[i]);
if (unlikely (status))
break;
}
cairo_surface_destroy (type3_surface);
status2 = _cairo_output_stream_destroy (null_stream);
if (status == CAIRO_INT_STATUS_SUCCESS)
status = status2;
return status;
}
static cairo_int_status_t
_cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
@ -6731,12 +6690,6 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
{
cairo_int_status_t status;
status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
_cairo_pdf_surface_analyze_user_font_subset,
surface);
if (unlikely (status))
goto BAIL;
status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
_cairo_pdf_surface_emit_unscaled_font_subset,
surface);

View file

@ -734,34 +734,6 @@ _cairo_ps_emit_imagemask (cairo_image_surface_t *image,
return _cairo_output_stream_get_status (stream);
}
static cairo_int_status_t
_cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
void *closure)
{
cairo_ps_surface_t *surface = closure;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
unsigned int i;
cairo_surface_t *type3_surface;
type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
NULL,
_cairo_ps_emit_imagemask,
surface->font_subsets,
TRUE);
for (i = 0; i < font_subset->num_glyphs; i++) {
status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
font_subset->glyphs[i]);
if (unlikely (status))
break;
}
cairo_surface_finish (type3_surface);
cairo_surface_destroy (type3_surface);
return status;
}
static cairo_status_t
_cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
@ -928,12 +900,6 @@ _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
"%% _cairo_ps_surface_emit_font_subsets\n");
#endif
status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
_cairo_ps_surface_analyze_user_font_subset,
surface);
if (unlikely (status))
return status;
status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
_cairo_ps_surface_emit_unscaled_font_subset,
surface);

View file

@ -173,9 +173,10 @@ _cairo_recording_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
cairo_surface_t *target,
const cairo_color_t *color);
_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
cairo_surface_t *target,
const cairo_color_t *foreground_color,
cairo_bool_t *foreground_used);
cairo_private cairo_status_t
_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,

View file

@ -105,6 +105,7 @@ typedef struct _cairo_recording_surface_replay_params {
cairo_recording_replay_type_t type;
cairo_recording_region_type_t region;
const cairo_color_t *foreground_color;
cairo_bool_t foreground_used;
} cairo_recording_surface_replay_params_t;
static const cairo_surface_backend_t cairo_recording_surface_backend;
@ -1829,7 +1830,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
}
_cairo_surface_wrapper_set_inverse_transform (&wrapper, params->surface_transform);
_cairo_surface_wrapper_set_clip (&wrapper, params->target_clip);
_cairo_surface_wrapper_set_foreground_color (&wrapper, params->foreground_color);
if (params->foreground_color) {
params->target->foreground_source = _cairo_pattern_create_solid (params->foreground_color);
params->target->foreground_used = FALSE;
}
/* Compute the extents of the target clip in recorded device space */
if (! _cairo_surface_wrapper_get_target_extents (&wrapper, params->surface_is_unbounded, &extents))
@ -2019,6 +2024,12 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
}
done:
if (params->foreground_color) {
cairo_pattern_destroy (params->target->foreground_source);
params->target->foreground_source = NULL;
params->foreground_used = params->target->foreground_used;
}
_cairo_surface_wrapper_fini (&wrapper);
return _cairo_surface_set_error (&surface->base, status);
}
@ -2151,11 +2162,13 @@ _cairo_recording_surface_replay (cairo_surface_t *surface,
}
cairo_status_t
_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
cairo_surface_t *target,
const cairo_color_t *color)
_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
cairo_surface_t *target,
const cairo_color_t *foreground_color,
cairo_bool_t *foreground_used)
{
cairo_recording_surface_replay_params_t params;
cairo_status_t status;
params.surface_extents = NULL;
params.surface_transform = NULL;
@ -2164,9 +2177,13 @@ _cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
params.surface_is_unbounded = FALSE;
params.type = CAIRO_RECORDING_REPLAY;
params.region = CAIRO_RECORDING_REGION_ALL;
params.foreground_color = color;
params.foreground_color = foreground_color;
params.foreground_used = FALSE;
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
status = _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
*foreground_used = params.foreground_used;
return status;
}
cairo_status_t

View file

@ -104,6 +104,9 @@ struct _cairo_surface {
* cairo_surface_create_similar().
*/
cairo_font_options_t font_options;
cairo_pattern_t *foreground_source;
cairo_bool_t foreground_used;
};
cairo_private cairo_surface_t *

View file

@ -53,7 +53,6 @@ struct _cairo_surface_wrapper {
cairo_bool_t has_extents;
cairo_rectangle_int_t extents;
const cairo_clip_t *clip;
cairo_pattern_t *foreground_source;
cairo_bool_t needs_transform;
};
@ -74,10 +73,6 @@ cairo_private void
_cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
const cairo_clip_t *clip);
cairo_private void
_cairo_surface_wrapper_set_foreground_color (cairo_surface_wrapper_t *wrapper,
const cairo_color_t *color);
cairo_private void
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper);

View file

@ -144,9 +144,6 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (source->is_userfont_foreground && wrapper->foreground_source)
source = wrapper->foreground_source;
if (wrapper->needs_transform) {
cairo_matrix_t m;
@ -185,9 +182,6 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (source->is_userfont_foreground && wrapper->foreground_source)
source = wrapper->foreground_source;
if (wrapper->needs_transform) {
cairo_matrix_t m;
@ -235,9 +229,6 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (source->is_userfont_foreground && wrapper->foreground_source)
source = wrapper->foreground_source;
if (wrapper->needs_transform) {
cairo_matrix_t m;
@ -306,12 +297,6 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (fill_source->is_userfont_foreground && wrapper->foreground_source)
fill_source = wrapper->foreground_source;
if (stroke_source->is_userfont_foreground && wrapper->foreground_source)
stroke_source = wrapper->foreground_source;
if (wrapper->needs_transform) {
cairo_matrix_t m;
@ -377,9 +362,6 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (source->is_userfont_foreground && wrapper->foreground_source)
source = wrapper->foreground_source;
if (wrapper->needs_transform) {
cairo_matrix_t m;
@ -443,9 +425,6 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_surface_get_font_options (wrapper->target, &options);
cairo_font_options_merge (&options, &scaled_font->options);
if (source->is_userfont_foreground && wrapper->foreground_source)
source = wrapper->foreground_source;
if (wrapper->needs_transform) {
cairo_matrix_t m;
int i;
@ -612,14 +591,6 @@ _cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
wrapper->clip = clip;
}
void
_cairo_surface_wrapper_set_foreground_color (cairo_surface_wrapper_t *wrapper,
const cairo_color_t *color)
{
if (color)
wrapper->foreground_source = _cairo_pattern_create_solid (color);
}
void
_cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t *wrapper,
cairo_font_options_t *options)
@ -651,7 +622,6 @@ _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
wrapper->has_extents = FALSE;
wrapper->extents.x = wrapper->extents.y = 0;
wrapper->clip = NULL;
wrapper->foreground_source = NULL;
wrapper->needs_transform = FALSE;
if (target) {
@ -663,9 +633,6 @@ _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
void
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
{
if (wrapper->foreground_source)
cairo_pattern_destroy (wrapper->foreground_source);
cairo_surface_destroy (wrapper->target);
}

View file

@ -134,7 +134,9 @@ const cairo_surface_t name = { \
CAIRO_HINT_STYLE_DEFAULT, /* hint_style */ \
CAIRO_HINT_METRICS_DEFAULT, /* hint_metrics */ \
CAIRO_ROUND_GLYPH_POS_DEFAULT /* round_glyph_positions */ \
} /* font_options */ \
}, /* font_options */ \
NULL, /* foreground_source */ \
FALSE, /* foreground_used */ \
}
/* XXX error object! */
@ -439,6 +441,9 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->snapshot_of = NULL;
surface->has_font_options = FALSE;
surface->foreground_source = NULL;
surface->foreground_used = FALSE;
}
static void
@ -976,6 +981,9 @@ cairo_surface_destroy (cairo_surface_t *surface)
_cairo_user_data_array_fini (&surface->user_data);
_cairo_user_data_array_fini (&surface->mime_data);
if (surface->foreground_source)
cairo_pattern_destroy (surface->foreground_source);
if (surface->owns_device)
cairo_device_destroy (surface->device);
@ -2196,6 +2204,11 @@ _cairo_surface_paint (cairo_surface_t *surface,
if (unlikely (status))
return status;
if (source->is_userfont_foreground && surface->foreground_source) {
source = surface->foreground_source;
surface->foreground_used = TRUE;
}
status = surface->backend->paint (surface, op, source, clip);
is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL;
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO || is_clear) {
@ -2246,6 +2259,11 @@ _cairo_surface_mask (cairo_surface_t *surface,
if (unlikely (status))
return status;
if (source->is_userfont_foreground && surface->foreground_source) {
source = surface->foreground_source;
surface->foreground_used = TRUE;
}
status = surface->backend->mask (surface, op, source, mask, clip);
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
surface->is_clear = FALSE;
@ -2302,6 +2320,16 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
if (unlikely (status))
return status;
if (fill_source->is_userfont_foreground && surface->foreground_source) {
fill_source = surface->foreground_source;
surface->foreground_used = TRUE;
}
if (stroke_source->is_userfont_foreground && surface->foreground_source) {
stroke_source = surface->foreground_source;
surface->foreground_used = TRUE;
}
if (surface->backend->fill_stroke) {
cairo_matrix_t dev_ctm = *stroke_ctm;
cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
@ -2376,6 +2404,11 @@ _cairo_surface_stroke (cairo_surface_t *surface,
if (unlikely (status))
return status;
if (source->is_userfont_foreground && surface->foreground_source) {
source = surface->foreground_source;
surface->foreground_used = TRUE;
}
status = surface->backend->stroke (surface, op, source,
path, stroke_style,
ctm, ctm_inverse,
@ -2421,6 +2454,11 @@ _cairo_surface_fill (cairo_surface_t *surface,
if (unlikely (status))
return status;
if (source->is_userfont_foreground && surface->foreground_source) {
source = surface->foreground_source;
surface->foreground_used = TRUE;
}
status = surface->backend->fill (surface, op, source,
path, fill_rule,
tolerance, antialias,
@ -2901,6 +2939,9 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
if (unlikely (status))
return status;
if (source->is_userfont_foreground && surface->foreground_source)
source = surface->foreground_source;
if (_cairo_scaled_font_has_color_glyphs (scaled_font) &&
scaled_font->options.color_mode != CAIRO_COLOR_MODE_NO_COLOR)
{

View file

@ -207,6 +207,9 @@ _cairo_type3_glyph_surface_paint (void *abstract_surface,
return status;
pattern = (const cairo_surface_pattern_t *) source;
if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
status = _cairo_surface_acquire_source_image (pattern->surface,
&image, &image_extra);
if (unlikely (status))
@ -291,33 +294,7 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
cairo_int_status_t status;
cairo_scaled_font_t *font;
cairo_matrix_t new_ctm;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
cairo_matrix_multiply (&new_ctm, &surface->cairo_to_pdf, &scaled_font->ctm);
font = cairo_scaled_font_create (scaled_font->font_face,
&scaled_font->font_matrix,
&new_ctm,
&scaled_font->options);
if (unlikely (font->status))
return font->status;
status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
font);
cairo_scaled_font_destroy (font);
return status;
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = {

View file

@ -265,6 +265,7 @@ _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;
/* TODO
@ -310,7 +311,8 @@ _cairo_user_scaled_glyph_init_surface (cairo_user_scaled_font_t *scaled_font,
if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) {
status = _cairo_recording_surface_replay_with_foreground_color (scaled_glyph->recording_surface,
surface,
foreground_color);
foreground_color,
&foreground_used);
} else {
status = _cairo_recording_surface_replay (scaled_glyph->recording_surface, surface);
}
@ -324,7 +326,7 @@ _cairo_user_scaled_glyph_init_surface (cairo_user_scaled_font_t *scaled_font,
_cairo_scaled_glyph_set_color_surface (scaled_glyph,
&scaled_font->base,
(cairo_image_surface_t *)surface,
TRUE);
foreground_used);
surface = NULL;
} else {
_cairo_scaled_glyph_set_surface (scaled_glyph,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB