cairo_status_t _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, cairo_scaled_font_t *scaled_font, unsigned long scaled_font_glyph_index, const char * utf8, int utf8_len, cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_t key, *sub_font; cairo_scaled_glyph_t *scaled_glyph; cairo_font_face_t *font_face; cairo_matrix_t identity; cairo_font_options_t font_options; cairo_scaled_font_t *unscaled_font; cairo_int_status_t status; int max_glyphs; cairo_bool_t type1_font; /* Lookup glyph in unscaled subsets */ if (subsets->type != CAIRO_SUBSETS_SCALED) { key.is_scaled = FALSE; _cairo_sub_font_init_key (&key, scaled_font); sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base); if (sub_font != NULL) { status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, utf8, utf8_len, subset_glyph); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } } /* Lookup glyph in scaled subsets */ key.is_scaled = TRUE; _cairo_sub_font_init_key (&key, scaled_font); sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base); if (sub_font != NULL) { status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, utf8, utf8_len, subset_glyph); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } /* Glyph not found. Determine whether the glyph is outline or * bitmap and add to the appropriate subset. * * glyph_index 0 (the .notdef glyph) is a special case. Some fonts * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates * empty glyphs in this case so we can put the glyph in a unscaled * subset. */ if (scaled_font_glyph_index == 0 || _cairo_font_face_is_user (scaled_font->font_face)) { status = CAIRO_STATUS_SUCCESS; } else { _cairo_scaled_font_freeze_cache (scaled_font); status = _cairo_scaled_glyph_lookup (scaled_font, scaled_font_glyph_index, CAIRO_SCALED_GLYPH_INFO_PATH, &scaled_glyph); _cairo_scaled_font_thaw_cache (scaled_font); } if (_cairo_int_status_is_error (status)) return status; if (status == CAIRO_INT_STATUS_SUCCESS && subsets->type != CAIRO_SUBSETS_SCALED && ! _cairo_font_face_is_user (scaled_font->font_face)) { /* Path available. Add to unscaled subset. */ key.is_scaled = FALSE; _cairo_sub_font_init_key (&key, scaled_font); sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base); if (sub_font == NULL) { font_face = cairo_scaled_font_get_font_face (scaled_font); cairo_matrix_init_identity (&identity); _cairo_font_options_init_default (&font_options); cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE); cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF); unscaled_font = cairo_scaled_font_create (font_face, &identity, &identity, &font_options); if (unlikely (unscaled_font->status)) return unscaled_font->status; subset_glyph->is_scaled = FALSE; type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font); if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) { max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT; subset_glyph->is_composite = TRUE; } else { max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; subset_glyph->is_composite = FALSE; } status = _cairo_sub_font_create (subsets, unscaled_font, subsets->num_sub_fonts, max_glyphs, subset_glyph->is_scaled, subset_glyph->is_composite, &sub_font); if (unlikely (status)) { cairo_scaled_font_destroy (unscaled_font); return status; } status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts, &sub_font->base); if (unlikely (status)) { _cairo_sub_font_destroy (sub_font); return status; } if (!subsets->unscaled_sub_fonts_list) subsets->unscaled_sub_fonts_list = sub_font; else subsets->unscaled_sub_fonts_list_end->next = sub_font; subsets->unscaled_sub_fonts_list_end = sub_font; subsets->num_sub_fonts++; } } else { /* No path available. Add to scaled subset. */ key.is_scaled = TRUE; _cairo_sub_font_init_key (&key, scaled_font); sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base); if (sub_font == NULL) { subset_glyph->is_scaled = TRUE; subset_glyph->is_composite = FALSE; if (subsets->type == CAIRO_SUBSETS_SCALED) max_glyphs = INT_MAX; else max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; status = _cairo_sub_font_create (subsets, cairo_scaled_font_reference (scaled_font), subsets->num_sub_fonts, max_glyphs, subset_glyph->is_scaled, subset_glyph->is_composite, &sub_font); if (unlikely (status)) { cairo_scaled_font_destroy (scaled_font); return status; } status = _cairo_hash_table_insert (subsets->scaled_sub_fonts, &sub_font->base); if (unlikely (status)) { _cairo_sub_font_destroy (sub_font); return status; } if (!subsets->scaled_sub_fonts_list) subsets->scaled_sub_fonts_list = sub_font; else subsets->scaled_sub_fonts_list_end->next = sub_font; subsets->scaled_sub_fonts_list_end = sub_font; subsets->num_sub_fonts++; } } return _cairo_sub_font_map_glyph (sub_font, scaled_font_glyph_index, utf8, utf8_len, subset_glyph); }
cairo_int_status_t _cairo_analysis_surface_merge_status (cairo_int_status_t status_a, cairo_int_status_t status_b) { /* fatal errors should be checked and propagated at source */ assert (! _cairo_int_status_is_error (status_a)); assert (! _cairo_int_status_is_error (status_b)); /* return the most important status */ if (status_a == CAIRO_INT_STATUS_UNSUPPORTED || status_b == CAIRO_INT_STATUS_UNSUPPORTED) return CAIRO_INT_STATUS_UNSUPPORTED; if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK || status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK) return CAIRO_INT_STATUS_IMAGE_FALLBACK; if (status_a == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN || status_b == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; /* at this point we have checked all the valid internal codes, so... */ assert (status_a == CAIRO_INT_STATUS_SUCCESS && status_b == CAIRO_INT_STATUS_SUCCESS); return CAIRO_INT_STATUS_SUCCESS; }
static cairo_int_status_t _cairo_analysis_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; cairo_int_status_t backend_status; cairo_rectangle_int_t extents; if (surface->target->backend->paint == NULL) { backend_status = CAIRO_INT_STATUS_UNSUPPORTED; } else { backend_status = surface->target->backend->paint (surface->target, op, source, clip); if (_cairo_int_status_is_error (backend_status)) return backend_status; } if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) backend_status = _analyze_recording_surface_pattern (surface, source); _cairo_analysis_surface_operation_extents (surface, op, source, clip, &extents); return _add_operation (surface, &extents, backend_status); }
static cairo_int_status_t _cairo_analysis_surface_tag (void *abstract_surface, cairo_bool_t begin, const char *tag_name, const char *attributes, const cairo_pattern_t *source, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, const cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; cairo_int_status_t backend_status; backend_status = CAIRO_INT_STATUS_SUCCESS; if (surface->target->backend->tag != NULL) { backend_status = surface->target->backend->tag (surface->target, begin, tag_name, attributes, source, stroke_style, ctm, ctm_inverse, clip); if (_cairo_int_status_is_error (backend_status)) return backend_status; } return backend_status; }
static cairo_int_status_t _cairo_analysis_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, const cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; cairo_int_status_t backend_status; cairo_rectangle_int_t extents; if (surface->target->backend->stroke == NULL) { backend_status = CAIRO_INT_STATUS_UNSUPPORTED; } else { backend_status = surface->target->backend->stroke (surface->target, op, source, path, style, ctm, ctm_inverse, tolerance, antialias, clip); if (_cairo_int_status_is_error (backend_status)) return backend_status; } _cairo_analysis_surface_operation_extents (surface, op, source, clip, &extents); if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { cairo_rectangle_int_t rec_extents; backend_status = _analyze_recording_surface_pattern (surface, source, &rec_extents); _cairo_rectangle_intersect (&extents, &rec_extents); } if (_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_int_t mask_extents; cairo_int_status_t status; status = _cairo_path_fixed_stroke_extents (path, style, ctm, ctm_inverse, tolerance, &mask_extents); if (unlikely (status)) return status; _cairo_rectangle_intersect (&extents, &mask_extents); } return _add_operation (surface, &extents, backend_status); }
static cairo_status_t render_glyphs (cairo_gl_surface_t *dst, int dst_x, int dst_y, cairo_operator_t op, cairo_surface_t *source, cairo_composite_glyphs_info_t *info, cairo_bool_t *has_component_alpha, cairo_clip_t *clip, cairo_bool_t via_msaa_compositor) { cairo_format_t last_format = CAIRO_FORMAT_INVALID; cairo_gl_glyph_cache_t *cache = NULL; cairo_gl_context_t *ctx; cairo_gl_composite_t setup; cairo_int_status_t status; int i = 0; cairo_bool_t is_argb32; TRACE ((stderr, "%s (%d, %d)x(%d, %d)\n", __FUNCTION__, info->extents.x, info->extents.y, info->extents.width, info->extents.height)); *has_component_alpha = FALSE; status = _cairo_gl_context_acquire (dst->base.device, &ctx); if (unlikely (status)) return status; /* Traps compositor never has CLEAR operator. */ is_argb32 = info->font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL || info->font->options.antialias == CAIRO_ANTIALIAS_BEST; /* If we are invoked by traps compositor, we keep what is in code otherwise, we handle non-subpixel/best directly in msaa compositor. */ if (!via_msaa_compositor) status = _cairo_gl_composite_init (&setup, op, dst, TRUE); else if (info->font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL || info->font->options.antialias == CAIRO_ANTIALIAS_BEST) status = _cairo_gl_composite_init (&setup, op, dst, TRUE); else status = _cairo_gl_composite_init (&setup, op, dst, FALSE); if (unlikely (status)) goto FINISH; if (source == NULL) { _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_WHITE); } else { _cairo_gl_composite_set_source_operand (&setup, source_to_operand (source)); } if (setup.src.type == CAIRO_GL_OPERAND_CONSTANT) setup.src.use_color_attribute = TRUE; _cairo_gl_composite_set_clip (&setup, clip); for (i = 0; i < info->num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; cairo_gl_glyph_t *glyph; double x_offset, y_offset; double x1, x2, y1, y2; status = _cairo_scaled_glyph_lookup (info->font, info->glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); if (unlikely (status)) goto FINISH; if (scaled_glyph->surface->width == 0 || scaled_glyph->surface->height == 0) { continue; } if (scaled_glyph->surface->format != last_format) { status = cairo_gl_context_get_glyph_cache (ctx, scaled_glyph->surface->format, &cache); if (unlikely (status)) goto FINISH; last_format = scaled_glyph->surface->format; /* In msaa compositor, clear operator needs component alpha, we need to reset to FALSE if previously clear operator has set it to TRUE. */ if (via_msaa_compositor) { if (op == CAIRO_OPERATOR_CLEAR || is_argb32) cache->surface->operand.texture.attributes.has_component_alpha = TRUE; else cache->surface->operand.texture.attributes.has_component_alpha = FALSE; } _cairo_gl_composite_set_mask_operand (&setup, &cache->surface->operand); *has_component_alpha |= cache->surface->operand.texture.attributes.has_component_alpha; /* XXX Shoot me. */ status = _cairo_gl_composite_begin (&setup, &ctx); status = _cairo_gl_context_release (ctx, status); if (unlikely (status)) goto FINISH; } if (scaled_glyph->dev_private_key != cache) { cairo_scaled_glyph_private_t *priv; priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache); if (priv) { scaled_glyph->dev_private_key = cache; scaled_glyph->dev_private = cairo_container_of (priv, cairo_gl_glyph_t, base); } else { status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph); if (status == CAIRO_INT_STATUS_UNSUPPORTED) { /* Cache is full, so flush existing prims and try again. */ _cairo_gl_composite_flush (ctx); _cairo_gl_glyph_cache_unlock (cache); status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph); } if (unlikely (_cairo_int_status_is_error (status))) goto FINISH; } } x_offset = scaled_glyph->surface->base.device_transform.x0; y_offset = scaled_glyph->surface->base.device_transform.y0; x1 = _cairo_lround (info->glyphs[i].x - x_offset - dst_x); y1 = _cairo_lround (info->glyphs[i].y - y_offset - dst_y); x2 = x1 + scaled_glyph->surface->width; y2 = y1 + scaled_glyph->surface->height; glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph); _cairo_gl_composite_emit_glyph (ctx, x1, y1, x2, y2, glyph->p1.x, glyph->p1.y, glyph->p2.x, glyph->p2.y); } status = CAIRO_STATUS_SUCCESS; FINISH: status = _cairo_gl_context_release (ctx, status); _cairo_gl_composite_fini (&setup); return status; }
static cairo_int_status_t _cairo_analysis_surface_show_text_glyphs (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const char *utf8, int utf8_len, cairo_glyph_t *glyphs, int num_glyphs, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; cairo_int_status_t status, backend_status; cairo_rectangle_int_t extents, glyph_extents; /* Adapted from _cairo_surface_show_glyphs */ backend_status = CAIRO_INT_STATUS_UNSUPPORTED; if (surface->target->backend->show_text_glyphs != NULL) { backend_status = surface->target->backend->show_text_glyphs (surface->target, op, source, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, scaled_font, clip); if (_cairo_int_status_is_error (backend_status)) return backend_status; } if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs != NULL) { backend_status = surface->target->backend->show_glyphs (surface->target, op, source, glyphs, num_glyphs, scaled_font, clip); if (_cairo_int_status_is_error (backend_status)) return backend_status; } if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) backend_status = _analyze_recording_surface_pattern (surface, source); _cairo_analysis_surface_operation_extents (surface, op, source, clip, &extents); if (_cairo_operator_bounded_by_mask (op)) { status = _cairo_scaled_font_glyph_device_extents (scaled_font, glyphs, num_glyphs, &glyph_extents, NULL); if (unlikely (status)) return status; _cairo_rectangle_intersect (&extents, &glyph_extents); } return _add_operation (surface, &extents, backend_status); }
static cairo_int_status_t _cairo_analysis_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, const cairo_clip_t *clip) { cairo_analysis_surface_t *surface = abstract_surface; cairo_int_status_t backend_status; cairo_rectangle_int_t extents; if (surface->target->backend->mask == NULL) { backend_status = CAIRO_INT_STATUS_UNSUPPORTED; } else { backend_status = surface->target->backend->mask (surface->target, op, source, mask, clip); if (_cairo_int_status_is_error (backend_status)) return backend_status; } if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS; cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS; if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_t *src_surface = ((cairo_surface_pattern_t *)source)->surface; src_surface = _cairo_surface_get_source (src_surface, NULL); if (_cairo_surface_is_recording (src_surface)) { backend_source_status = _analyze_recording_surface_pattern (surface, source); if (_cairo_int_status_is_error (backend_source_status)) return backend_source_status; } } if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_t *mask_surface = ((cairo_surface_pattern_t *)mask)->surface; mask_surface = _cairo_surface_get_source (mask_surface, NULL); if (_cairo_surface_is_recording (mask_surface)) { backend_mask_status = _analyze_recording_surface_pattern (surface, mask); if (_cairo_int_status_is_error (backend_mask_status)) return backend_mask_status; } } backend_status = _cairo_analysis_surface_merge_status (backend_source_status, backend_mask_status); } _cairo_analysis_surface_operation_extents (surface, op, source, clip, &extents); if (_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_int_t mask_extents; _cairo_pattern_get_extents (mask, &mask_extents); _cairo_rectangle_intersect (&extents, &mask_extents); } return _add_operation (surface, &extents, backend_status); }
static cairo_status_t render_glyphs (cairo_gl_surface_t *dst, int dst_x, int dst_y, cairo_operator_t op, cairo_surface_t *source, cairo_composite_glyphs_info_t *info, cairo_bool_t *has_component_alpha, cairo_clip_t *clip) { cairo_format_t last_format = CAIRO_FORMAT_INVALID; cairo_gl_glyph_cache_t *cache = NULL; cairo_gl_context_t *ctx; cairo_gl_emit_glyph_t emit = NULL; cairo_gl_composite_t setup; cairo_int_status_t status; int i = 0; TRACE ((stderr, "%s (%d, %d)x(%d, %d)\n", __FUNCTION__, info->extents.x, info->extents.y, info->extents.width, info->extents.height)); *has_component_alpha = FALSE; status = _cairo_gl_context_acquire (dst->base.device, &ctx); if (unlikely (status)) return status; status = _cairo_gl_composite_init (&setup, op, dst, TRUE); if (unlikely (status)) goto FINISH; if (source == NULL) { _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_WHITE); } else { _cairo_gl_composite_set_source_operand (&setup, source_to_operand (source)); } _cairo_gl_composite_set_clip (&setup, clip); for (i = 0; i < info->num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; cairo_gl_glyph_t *glyph; double x_offset, y_offset; double x1, x2, y1, y2; status = _cairo_scaled_glyph_lookup (info->font, info->glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); if (unlikely (status)) goto FINISH; if (scaled_glyph->surface->width == 0 || scaled_glyph->surface->height == 0) { continue; } if (scaled_glyph->surface->format != last_format) { status = cairo_gl_context_get_glyph_cache (ctx, scaled_glyph->surface->format, &cache); if (unlikely (status)) goto FINISH; last_format = scaled_glyph->surface->format; _cairo_gl_composite_set_mask_operand (&setup, &cache->surface->operand); *has_component_alpha |= cache->surface->operand.texture.attributes.has_component_alpha; /* XXX Shoot me. */ status = _cairo_gl_composite_begin (&setup, &ctx); status = _cairo_gl_context_release (ctx, status); if (unlikely (status)) goto FINISH; emit = _cairo_gl_context_choose_emit_glyph (ctx); } if (scaled_glyph->dev_private_key != cache) { cairo_scaled_glyph_private_t *priv; priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache); if (priv) { scaled_glyph->dev_private_key = cache; scaled_glyph->dev_private = cairo_container_of (priv, cairo_gl_glyph_t, base); } else { status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph); if (status == CAIRO_INT_STATUS_UNSUPPORTED) { /* Cache is full, so flush existing prims and try again. */ _cairo_gl_composite_flush (ctx); _cairo_gl_glyph_cache_unlock (cache); status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph); } if (unlikely (_cairo_int_status_is_error (status))) goto FINISH; } } x_offset = scaled_glyph->surface->base.device_transform.x0; y_offset = scaled_glyph->surface->base.device_transform.y0; x1 = _cairo_lround (info->glyphs[i].x - x_offset - dst_x); y1 = _cairo_lround (info->glyphs[i].y - y_offset - dst_y); x2 = x1 + scaled_glyph->surface->width; y2 = y1 + scaled_glyph->surface->height; glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph); assert (emit); emit (ctx, x1, y1, x2, y2, glyph->p1.x, glyph->p1.y, glyph->p2.x, glyph->p2.y); } status = CAIRO_STATUS_SUCCESS; FINISH: status = _cairo_gl_context_release (ctx, status); _cairo_gl_composite_fini (&setup); return status; }