diff options
author | Adrian Johnson <ajohnson@redneon.com> | 2022-04-22 21:18:09 +0930 |
---|---|---|
committer | Adrian Johnson <ajohnson@redneon.com> | 2022-04-25 17:08:07 +0930 |
commit | 4815949d2fd9053c5550de71c2f296005a4aa22d (patch) | |
tree | eb76515c991892c65fc0c326b3e0d16620a67bca /src/cairo-user-font.c | |
parent | cdcb67ef87790ab01c4f32a432f6bd47df0434e5 (diff) | |
download | cairo-4815949d2fd9053c5550de71c2f296005a4aa22d.tar.gz |
Fix the scaled_glyph_init color glyph logic
and split _cairo_user_scaled_glyph_init() into multiple functions.
Update user-font test to test changing foreground text color.
Diffstat (limited to 'src/cairo-user-font.c')
-rw-r--r-- | src/cairo-user-font.c | 365 |
1 files changed, 205 insertions, 160 deletions
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c index b2a05d67d..fd989eaa0 100644 --- a/src/cairo-user-font.c +++ b/src/cairo-user-font.c @@ -142,192 +142,237 @@ _cairo_user_scaled_font_create_recording_context (const cairo_user_scaled_font_t } static cairo_int_status_t -_cairo_user_scaled_glyph_init (void *abstract_font, - cairo_scaled_glyph_t *scaled_glyph, - cairo_scaled_glyph_info_t info, - const cairo_color_t *foreground_color) +_cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) { + cairo_user_font_face_t *face = + (cairo_user_font_face_t *) scaled_font->base.font_face; + cairo_text_extents_t extents = scaled_font->default_glyph_extents; + cairo_surface_t *recording_surface = NULL; cairo_int_status_t status = CAIRO_STATUS_SUCCESS; - cairo_user_scaled_font_t *scaled_font = abstract_font; - cairo_surface_t *recording_surface = scaled_glyph->recording_surface; + cairo_t *cr; - if (!scaled_glyph->recording_surface) { - cairo_user_font_face_t *face = - (cairo_user_font_face_t *) scaled_font->base.font_face; - cairo_text_extents_t extents = scaled_font->default_glyph_extents; - cairo_t *cr; + if (!face->scaled_font_methods.render_color_glyph && !face->scaled_font_methods.render_glyph) + return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; - recording_surface = NULL; - 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); + _cairo_scaled_glyph_set_recording_surface (scaled_glyph, + &scaled_font->base, + recording_surface); + } 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); + + 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); + if (status == CAIRO_INT_STATUS_SUCCESS) { + status = cairo_status (cr); + scaled_glyph->color_glyph = TRUE; + scaled_glyph->color_glyph_set = TRUE; + } + cairo_destroy (cr); + } - /* special case for 0 rank matrix (as in _cairo_scaled_font_init): empty surface */ - if (_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) { + 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); - _cairo_scaled_glyph_set_recording_surface (scaled_glyph, - &scaled_font->base, - recording_surface); - } 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); - - 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); - if (status == CAIRO_INT_STATUS_SUCCESS) { - status = cairo_status (cr); - scaled_glyph->recording_is_color = TRUE; - } - cairo_destroy (cr); + recording_surface->device_transform.x0 = .25 * _cairo_scaled_glyph_xphase (scaled_glyph); + recording_surface->device_transform.y0 = .25 * _cairo_scaled_glyph_yphase (scaled_glyph); + + cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface, FALSE); + + status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font, + _cairo_scaled_glyph_index(scaled_glyph), + cr, &extents); + if (status == CAIRO_INT_STATUS_SUCCESS) { + status = cairo_status (cr); + scaled_glyph->color_glyph = FALSE; + scaled_glyph->color_glyph_set = TRUE; } - 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->device_transform.x0 = .25 * _cairo_scaled_glyph_xphase (scaled_glyph); - recording_surface->device_transform.y0 = .25 * _cairo_scaled_glyph_yphase (scaled_glyph); + cairo_destroy (cr); + } - cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface, FALSE); + if (status != CAIRO_INT_STATUS_SUCCESS) { + if (recording_surface) + cairo_surface_destroy (recording_surface); + return status; + } - status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font, - _cairo_scaled_glyph_index(scaled_glyph), - cr, &extents); - if (status == CAIRO_INT_STATUS_SUCCESS) - status = cairo_status (cr); + _cairo_scaled_glyph_set_recording_surface (scaled_glyph, + &scaled_font->base, + recording_surface); + } - cairo_destroy (cr); - } + /* set metrics */ - if (status != CAIRO_INT_STATUS_SUCCESS) { - if (recording_surface) - cairo_surface_destroy (recording_surface); - return status; - } + if (extents.width == 0.) { + cairo_box_t bbox; + double x1, y1, x2, y2; + double x_scale, y_scale; - _cairo_scaled_glyph_set_recording_surface (scaled_glyph, - &scaled_font->base, - recording_surface); - } + /* Compute extents.x/y/width/height from recording_surface, + * in font space. + */ + status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface, + &bbox, + &scaled_font->extent_scale); + if (unlikely (status)) + return status; - /* set metrics */ - - if (extents.width == 0.) { - cairo_box_t bbox; - double x1, y1, x2, y2; - double x_scale, y_scale; - - /* Compute extents.x/y/width/height from recording_surface, - * in font space. - */ - status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface, - &bbox, - &scaled_font->extent_scale); - if (unlikely (status)) - return status; - - _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2); - - x_scale = scaled_font->extent_x_scale; - y_scale = scaled_font->extent_y_scale; - extents.x_bearing = x1 * x_scale; - extents.y_bearing = y1 * y_scale; - extents.width = (x2 - x1) * x_scale; - extents.height = (y2 - y1) * y_scale; - } + _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2); + + x_scale = scaled_font->extent_x_scale; + y_scale = scaled_font->extent_y_scale; + extents.x_bearing = x1 * x_scale; + extents.y_bearing = y1 * y_scale; + extents.width = (x2 - x1) * x_scale; + extents.height = (y2 - y1) * y_scale; + } + + if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { + extents.x_advance = _cairo_lround (extents.x_advance / scaled_font->snap_x_scale) * scaled_font->snap_x_scale; + extents.y_advance = _cairo_lround (extents.y_advance / scaled_font->snap_y_scale) * scaled_font->snap_y_scale; + } + + _cairo_scaled_glyph_set_metrics (scaled_glyph, + &scaled_font->base, + &extents); + + return status; +} + +static cairo_int_status_t +_cairo_user_scaled_glyph_init_surface (cairo_user_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color) +{ + cairo_surface_t *surface; + cairo_format_t format; + int width, height; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + /* TODO + * extend the glyph cache to support argb glyphs. + * need to figure out the semantics and interaction with subpixel + * rendering first. + */ + + /* Only one info type at a time handled in this function */ + assert (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE || info == CAIRO_SCALED_GLYPH_INFO_SURFACE); - if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { - extents.x_advance = _cairo_lround (extents.x_advance / scaled_font->snap_x_scale) * scaled_font->snap_x_scale; - extents.y_advance = _cairo_lround (extents.y_advance / scaled_font->snap_y_scale) * scaled_font->snap_y_scale; + width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) - + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); + height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) - + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); + + if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + format = CAIRO_FORMAT_ARGB32; + } else { + switch (scaled_font->base.options.antialias) { + default: + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_FAST: + case CAIRO_ANTIALIAS_GOOD: + case CAIRO_ANTIALIAS_GRAY: + format = CAIRO_FORMAT_A8; + break; + case CAIRO_ANTIALIAS_NONE: + format = CAIRO_FORMAT_A1; + break; + case CAIRO_ANTIALIAS_BEST: + case CAIRO_ANTIALIAS_SUBPIXEL: + format = CAIRO_FORMAT_ARGB32; + break; } + } + surface = cairo_image_surface_create (format, width, height); - _cairo_scaled_glyph_set_metrics (scaled_glyph, + cairo_surface_set_device_offset (surface, + - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x), + - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y)); + + if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + status = _cairo_recording_surface_replay_with_foreground_color (scaled_glyph->recording_surface, + surface, + foreground_color); + } else { + status = _cairo_recording_surface_replay (scaled_glyph->recording_surface, surface); + } + + if (unlikely (status)) { + cairo_surface_destroy(surface); + return status; + } + + if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + _cairo_scaled_glyph_set_color_surface (scaled_glyph, + &scaled_font->base, + (cairo_image_surface_t *)surface, + TRUE); + surface = NULL; + } else { + _cairo_scaled_glyph_set_surface (scaled_glyph, &scaled_font->base, - &extents); + (cairo_image_surface_t *) surface); + surface = NULL; } - if (info & (CAIRO_SCALED_GLYPH_INFO_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) { - cairo_surface_t *surface; - cairo_format_t format; - int width, height; + if (surface) + cairo_surface_destroy (surface); - /* TODO - * extend the glyph cache to support argb glyphs. - * need to figure out the semantics and interaction with subpixel - * rendering first. - */ + return status; +} - width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) - - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); - height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) - - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); - - if (scaled_glyph->recording_is_color) { - format = CAIRO_FORMAT_ARGB32; - } else { - switch (scaled_font->base.options.antialias) { - default: - case CAIRO_ANTIALIAS_DEFAULT: - case CAIRO_ANTIALIAS_FAST: - case CAIRO_ANTIALIAS_GOOD: - case CAIRO_ANTIALIAS_GRAY: - format = CAIRO_FORMAT_A8; - break; - case CAIRO_ANTIALIAS_NONE: - format = CAIRO_FORMAT_A1; - break; - case CAIRO_ANTIALIAS_BEST: - case CAIRO_ANTIALIAS_SUBPIXEL: - format = CAIRO_FORMAT_ARGB32; - break; - } - } - surface = cairo_image_surface_create (format, width, height); - - cairo_surface_set_device_offset (surface, - - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x), - - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y)); - - if (scaled_glyph->recording_is_color) { - status = _cairo_recording_surface_replay_with_foreground_color (recording_surface, - surface, - foreground_color); - } else { - status = _cairo_recording_surface_replay (recording_surface, surface); - } +static cairo_int_status_t +_cairo_user_scaled_glyph_init (void *abstract_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_user_scaled_font_t *scaled_font = abstract_font; - if (unlikely (status)) { - cairo_surface_destroy(surface); + if (!scaled_glyph->recording_surface) { + status = _cairo_user_scaled_glyph_init_record_glyph (scaled_font, scaled_glyph); + if (status) return status; - } + } - if (!scaled_glyph->recording_is_color && (info & CAIRO_SCALED_GLYPH_INFO_SURFACE)) { - _cairo_scaled_glyph_set_surface (scaled_glyph, - &scaled_font->base, - (cairo_image_surface_t *) surface); - surface = NULL; - } + if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + if (!scaled_glyph->color_glyph ) + return CAIRO_INT_STATUS_UNSUPPORTED; - if (scaled_glyph->recording_is_color && (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) { - _cairo_scaled_glyph_set_color_surface (scaled_glyph, - &scaled_font->base, - (cairo_image_surface_t *)surface, - FALSE); - surface = NULL; - } + status = _cairo_user_scaled_glyph_init_surface (scaled_font, + scaled_glyph, + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, + foreground_color); + if (status) + return status; + } - if (surface) - cairo_surface_destroy (surface); + if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) { + status = _cairo_user_scaled_glyph_init_surface (scaled_font, + scaled_glyph, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL); + if (status) + return status; } if (info & CAIRO_SCALED_GLYPH_INFO_PATH) { @@ -335,7 +380,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font, if (!path) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - status = _cairo_recording_surface_get_path (recording_surface, path); + status = _cairo_recording_surface_get_path (scaled_glyph->recording_surface, path); if (unlikely (status)) { _cairo_path_fixed_destroy (path); return status; |