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); }
static cairo_status_t _cairo_type3_glyph_surface_emit_fallback_image (cairo_type3_glyph_surface_t *surface, unsigned long glyph_index) { cairo_scaled_glyph_t *scaled_glyph; cairo_status_t status; cairo_image_surface_t *image; cairo_matrix_t mat; double x, y; status = _cairo_scaled_glyph_lookup (surface->scaled_font, glyph_index, CAIRO_SCALED_GLYPH_INFO_METRICS | CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); if (status) return status; image = scaled_glyph->surface; if (image->width == 0 || image->height == 0) return CAIRO_STATUS_SUCCESS; x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x); y = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y); mat.xx = image->width; mat.xy = 0; mat.yx = 0; mat.yy = image->height; mat.x0 = x; mat.y0 = y; cairo_matrix_multiply (&mat, &mat, &surface->scaled_font->scale_inverse); mat.y0 *= -1; return _cairo_type3_glyph_surface_emit_image (surface, image, &mat); }
cairo_status_t _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, double x, double y, const char *utf8, cairo_glyph_t **glyphs, int *num_glyphs) { size_t i; uint32_t *ucs4 = NULL; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_scaled_glyph_t *scaled_glyph; if (scaled_font->backend->text_to_glyphs) { status = scaled_font->backend->text_to_glyphs (scaled_font, x, y, utf8, glyphs, num_glyphs); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } status = _cairo_utf8_to_ucs4 ((unsigned char*)utf8, -1, &ucs4, num_glyphs); if (status) return status; *glyphs = (cairo_glyph_t *) malloc ((*num_glyphs) * (sizeof (cairo_glyph_t))); if (*glyphs == NULL) { status = CAIRO_STATUS_NO_MEMORY; goto FAIL; } for (i = 0; i < *num_glyphs; i++) { (*glyphs)[i].index = (*scaled_font->backend-> ucs4_to_index) (scaled_font, ucs4[i]); (*glyphs)[i].x = x; (*glyphs)[i].y = y; status = _cairo_scaled_glyph_lookup (scaled_font, (*glyphs)[i].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); if (status) { free (*glyphs); *glyphs = NULL; goto FAIL; } x += scaled_glyph->metrics.x_advance; y += scaled_glyph->metrics.y_advance; } FAIL: free (ucs4); return status; }
/* * Compute a device-space bounding box for the glyphs. */ cairo_status_t _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font, const cairo_glyph_t *glyphs, int num_glyphs, cairo_rectangle_t *extents) { cairo_status_t status = CAIRO_STATUS_SUCCESS; int i; int min_x = CAIRO_MAXSHORT, max_x = CAIRO_MINSHORT; int min_y = CAIRO_MAXSHORT, max_y = CAIRO_MINSHORT; if (scaled_font->status) return scaled_font->status; for (i = 0; i < num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; int left, top; int right, bottom; int x, y; status = _cairo_scaled_glyph_lookup (scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); if (status) { _cairo_scaled_font_set_error (scaled_font, status); return status; } /* glyph images are snapped to pixel locations */ x = (int) floor (glyphs[i].x + 0.5); y = (int) floor (glyphs[i].y + 0.5); left = x + _cairo_fixed_integer_floor(scaled_glyph->bbox.p1.x); top = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); right = x + _cairo_fixed_integer_ceil(scaled_glyph->bbox.p2.x); bottom = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y); if (left < min_x) min_x = left; if (right > max_x) max_x = right; if (top < min_y) min_y = top; if (bottom > max_y) max_y = bottom; } if (min_x < max_x && min_y < max_y) { extents->x = min_x; extents->width = max_x - min_x; extents->y = min_y; extents->height = max_y - min_y; } else { extents->x = extents->y = 0; extents->width = extents->height = 0; } return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface, unsigned long glyph_index) { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_scaled_glyph_t *scaled_glyph; cairo_status_t status, status2; cairo_output_stream_t *null_stream; if (unlikely (surface->base.status)) return surface->base.status; null_stream = _cairo_null_stream_create (); if (unlikely (null_stream->status)) return null_stream->status; _cairo_type3_glyph_surface_set_stream (surface, null_stream); _cairo_scaled_font_freeze_cache (surface->scaled_font); status = _cairo_scaled_glyph_lookup (surface->scaled_font, glyph_index, CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE, &scaled_glyph); if (_cairo_status_is_error (status)) goto cleanup; if (status == CAIRO_INT_STATUS_UNSUPPORTED) { status = CAIRO_STATUS_SUCCESS; goto cleanup; } status = _cairo_recording_surface_replay (scaled_glyph->recording_surface, &surface->base); if (unlikely (status)) goto cleanup; status = _cairo_pdf_operators_flush (&surface->pdf_operators); if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) status = CAIRO_STATUS_SUCCESS; cleanup: _cairo_scaled_font_thaw_cache (surface->scaled_font); status2 = _cairo_output_stream_destroy (null_stream); if (status == CAIRO_STATUS_SUCCESS) status = status2; return status; }
cairo_int_status_t _cairo_gl_composite_glyphs (void *_dst, cairo_operator_t op, cairo_surface_t *_src, int src_x, int src_y, int dst_x, int dst_y, cairo_composite_glyphs_info_t *info) { cairo_gl_surface_t *dst = _dst; cairo_bool_t has_component_alpha; int i; TRACE ((stderr, "%s\n", __FUNCTION__)); /* If any of the glyphs are component alpha, we have to go through a mask, * since only _cairo_gl_surface_composite() currently supports component * alpha. */ if (!dst->base.is_clear && ! info->use_mask && op != CAIRO_OPERATOR_OVER) { for (i = 0; i < info->num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; if (_cairo_scaled_glyph_lookup (info->font, info->glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph) == CAIRO_INT_STATUS_SUCCESS && scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32) { info->use_mask = TRUE; break; } } } if (info->use_mask) { return render_glyphs_via_mask (dst, dst_x, dst_y, op, _src, info); } else { return render_glyphs (dst, dst_x, dst_y, op, _src, info, &has_component_alpha); } }
cairo_status_t _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface, unsigned long glyph_index) { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_scaled_glyph_t *scaled_glyph; cairo_status_t status, status2; cairo_output_stream_t *null_stream; null_stream = _cairo_null_stream_create (); _cairo_type3_glyph_surface_set_stream (surface, null_stream); status = _cairo_scaled_glyph_lookup (surface->scaled_font, glyph_index, CAIRO_SCALED_GLYPH_INFO_METRICS | CAIRO_SCALED_GLYPH_INFO_META_SURFACE, &scaled_glyph); if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) goto cleanup; if (status == CAIRO_INT_STATUS_UNSUPPORTED) { status = CAIRO_STATUS_SUCCESS; goto cleanup; } status = _cairo_meta_surface_replay (scaled_glyph->meta_surface, &surface->base); status = _cairo_pdf_operators_flush (&surface->pdf_operators); if (status) return status; if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) status = CAIRO_STATUS_SUCCESS; cleanup: status2 = _cairo_output_stream_destroy (null_stream); if (status) return status; return status2; }
cairo_status_t _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, cairo_path_fixed_t *path) { cairo_status_t status; int i; cairo_scaled_glyph_path_closure_t closure; if (scaled_font->status) return scaled_font->status; closure.path = path; for (i = 0; i < num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; status = _cairo_scaled_glyph_lookup (scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_PATH, &scaled_glyph); if (status) return status; closure.offset.x = _cairo_fixed_from_double (glyphs[i].x); closure.offset.y = _cairo_fixed_from_double (glyphs[i].y); status = _cairo_path_fixed_interpret (scaled_glyph->path, CAIRO_DIRECTION_FORWARD, _scaled_glyph_path_move_to, _scaled_glyph_path_line_to, _scaled_glyph_path_curve_to, _scaled_glyph_path_close_path, &closure); } return CAIRO_STATUS_SUCCESS; }
cairo_private 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, 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_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); if (_cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base, (cairo_hash_entry_t **) &sub_font)) { status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, subset_glyph); if (status == CAIRO_STATUS_SUCCESS) return CAIRO_STATUS_SUCCESS; } } /* Lookup glyph in scaled subsets */ key.is_scaled = TRUE; _cairo_sub_font_init_key (&key, scaled_font); if (_cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base, (cairo_hash_entry_t **) &sub_font)) { status = _cairo_sub_font_lookup_glyph (sub_font, scaled_font_glyph_index, subset_glyph); if (status == CAIRO_STATUS_SUCCESS) return CAIRO_STATUS_SUCCESS; } /* Glyph not found. Determine whether the glyph is outline or * bitmap and add to the appropriate subset */ status = _cairo_scaled_glyph_lookup (scaled_font, scaled_font_glyph_index, CAIRO_SCALED_GLYPH_INFO_PATH, &scaled_glyph); if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) return status; if (status == 0 && subsets->type != CAIRO_SUBSETS_SCALED) { /* Path available. Add to unscaled subset. */ key.is_scaled = FALSE; _cairo_sub_font_init_key (&key, scaled_font); if (! _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base, (cairo_hash_entry_t **) &sub_font)) { 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 (unscaled_font->status) return unscaled_font->status; subset_glyph->is_scaled = FALSE; type1_font = FALSE; #if CAIRO_HAS_FT_FONT type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font); #endif 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; } sub_font = _cairo_sub_font_create (subsets, unscaled_font, subsets->num_sub_fonts++, max_glyphs, subset_glyph->is_scaled, subset_glyph->is_composite); if (sub_font == NULL) { cairo_scaled_font_destroy (unscaled_font); return CAIRO_STATUS_NO_MEMORY; } status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts, &sub_font->base); if (status) { _cairo_sub_font_destroy (sub_font); return status; } } } else { /* No path available. Add to scaled subset. */ key.is_scaled = TRUE; _cairo_sub_font_init_key (&key, scaled_font); if (! _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base, (cairo_hash_entry_t **) &sub_font)) { 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; sub_font = _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); if (sub_font == NULL) { cairo_scaled_font_destroy (scaled_font); return CAIRO_STATUS_NO_MEMORY; } status = _cairo_hash_table_insert (subsets->scaled_sub_fonts, &sub_font->base); if (status) { _cairo_sub_font_destroy (sub_font); return status; } } } return _cairo_sub_font_map_glyph (sub_font, scaled_font_glyph_index, subset_glyph); }
static cairo_status_t _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, unsigned long scaled_font_glyph_index, cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_glyph_t key, *sub_font_glyph; cairo_status_t status; cairo_scaled_glyph_t *scaled_glyph; _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); if (! _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base, (cairo_hash_entry_t **) &sub_font_glyph)) { if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset) { sub_font->current_subset++; sub_font->num_glyphs_in_current_subset = 0; if (sub_font->parent->type != CAIRO_SUBSETS_SCALED) { /* Reserve first glyph in subset for the .notdef glyph */ sub_font->num_glyphs_in_current_subset++; } } status = _cairo_scaled_glyph_lookup (sub_font->scaled_font, scaled_font_glyph_index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); if (status) return status; sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index, sub_font->current_subset, sub_font->num_glyphs_in_current_subset++, scaled_glyph->metrics.x_advance); if (sub_font_glyph == NULL) return CAIRO_STATUS_NO_MEMORY; if (sub_font->is_scaled) { if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_scaled_subset_used) sub_font->parent->max_glyphs_per_scaled_subset_used = sub_font->num_glyphs_in_current_subset; } else { if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used) sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset; } status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base); if (status) { _cairo_sub_font_glyph_destroy (sub_font_glyph); return status; } } subset_glyph->font_id = sub_font->font_id; subset_glyph->subset_id = sub_font_glyph->subset_id; subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; subset_glyph->is_scaled = sub_font->is_scaled; subset_glyph->is_composite = sub_font->is_composite; subset_glyph->x_advance = sub_font_glyph->x_advance; return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface, cairo_output_stream_t *stream, unsigned long glyph_index, cairo_box_t *bbox, double *width) { cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_scaled_glyph_t *scaled_glyph; cairo_status_t status, status2; double x_advance, y_advance; cairo_output_stream_t *mem_stream; cairo_matrix_t font_matrix_inverse; _cairo_type3_glyph_surface_set_stream (surface, stream); status = _cairo_scaled_glyph_lookup (surface->scaled_font, glyph_index, CAIRO_SCALED_GLYPH_INFO_METRICS | CAIRO_SCALED_GLYPH_INFO_META_SURFACE, &scaled_glyph); if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) return status; if (status == CAIRO_INT_STATUS_UNSUPPORTED) { status = _cairo_scaled_glyph_lookup (surface->scaled_font, glyph_index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); if (status) return status; status = CAIRO_INT_STATUS_IMAGE_FALLBACK; } x_advance = scaled_glyph->metrics.x_advance; y_advance = scaled_glyph->metrics.y_advance; font_matrix_inverse = surface->scaled_font->font_matrix; status2 = cairo_matrix_invert (&font_matrix_inverse); /* The invertability of font_matrix is tested in * pdf_operators_show_glyphs before any glyphs are mappped to the * subset. */ assert (status2 == CAIRO_STATUS_SUCCESS); cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance); *width = x_advance; *bbox = scaled_glyph->bbox; _cairo_matrix_transform_bounding_box_fixed (&surface->scaled_font->scale_inverse, bbox, NULL); _cairo_output_stream_printf (surface->stream, "%f 0 %f %f %f %f d1\n", x_advance, _cairo_fixed_to_double (bbox->p1.x), - _cairo_fixed_to_double (bbox->p2.y), _cairo_fixed_to_double (bbox->p2.x), - _cairo_fixed_to_double (bbox->p1.y)); if (status == CAIRO_STATUS_SUCCESS) { mem_stream = _cairo_memory_stream_create (); _cairo_type3_glyph_surface_set_stream (surface, mem_stream); _cairo_output_stream_printf (surface->stream, "q\n"); status = _cairo_meta_surface_replay (scaled_glyph->meta_surface, &surface->base); status = _cairo_pdf_operators_flush (&surface->pdf_operators); if (status) return status; _cairo_output_stream_printf (surface->stream, "Q\n"); _cairo_type3_glyph_surface_set_stream (surface, stream); if (status == CAIRO_STATUS_SUCCESS) _cairo_memory_stream_copy (mem_stream, stream); status2 = _cairo_output_stream_destroy (mem_stream); if (status2) return status2; } if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) status = _cairo_type3_glyph_surface_emit_fallback_image (surface, glyph_index); return status; }
/** * cairo_scaled_font_glyph_extents: * @scaled_font: a #cairo_scaled_font_t * @glyphs: an array of glyph IDs with X and Y offsets. * @num_glyphs: the number of glyphs in the @glyphs array * @extents: a #cairo_text_extents_t which to store the retrieved extents. * * Gets the extents for an array of glyphs. The extents describe a * user-space rectangle that encloses the "inked" portion of the * glyphs, (as they would be drawn by cairo_show_glyphs() if the cairo * graphics state were set to the same font_face, font_matrix, ctm, * and font_options as @scaled_font). Additionally, the x_advance and * y_advance values indicate the amount by which the current point * would be advanced by cairo_show_glyphs. * * Note that whitespace glyphs do not contribute to the size of the * rectangle (extents.width and extents.height). **/ void cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents) { cairo_status_t status = CAIRO_STATUS_SUCCESS; int i; double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0; double x_pos = 0.0, y_pos = 0.0; if (scaled_font->status) return; if (!num_glyphs) { extents->x_bearing = 0.0; extents->y_bearing = 0.0; extents->width = 0.0; extents->height = 0.0; extents->x_advance = 0.0; extents->y_advance = 0.0; return; } for (i = 0; i < num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; double left, top, right, bottom; status = _cairo_scaled_glyph_lookup (scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); if (status) { _cairo_scaled_font_set_error (scaled_font, status); return; } left = scaled_glyph->metrics.x_bearing + glyphs[i].x; right = left + scaled_glyph->metrics.width; top = scaled_glyph->metrics.y_bearing + glyphs[i].y; bottom = top + scaled_glyph->metrics.height; if (i == 0) { min_x = left; max_x = right; min_y = top; max_y = bottom; } else { if (left < min_x) min_x = left; if (right > max_x) max_x = right; if (top < min_y) min_y = top; if (bottom > max_y) max_y = bottom; } x_pos = glyphs[i].x + scaled_glyph->metrics.x_advance; y_pos = glyphs[i].y + scaled_glyph->metrics.y_advance; } extents->x_bearing = min_x - glyphs[0].x; extents->y_bearing = min_y - glyphs[0].y; extents->width = max_x - min_x; extents->height = max_y - min_y; extents->x_advance = x_pos - glyphs[0].x; extents->y_advance = y_pos - glyphs[0].y; }
static cairo_status_t _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, unsigned long scaled_font_glyph_index, const char *utf8, int utf8_len, cairo_scaled_font_subsets_glyph_t *subset_glyph) { cairo_sub_font_glyph_t key, *sub_font_glyph; cairo_status_t status; _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base); if (sub_font_glyph == NULL) { cairo_scaled_glyph_t *scaled_glyph; if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset) { cairo_scaled_font_subsets_glyph_t tmp_subset_glyph; sub_font->current_subset++; sub_font->num_glyphs_in_current_subset = 0; /* Reserve first glyph in subset for the .notdef glyph * except for Type 3 fonts */ if (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)) { status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &tmp_subset_glyph); if (unlikely (status)) return status; } } _cairo_scaled_font_freeze_cache (sub_font->scaled_font); status = _cairo_scaled_glyph_lookup (sub_font->scaled_font, scaled_font_glyph_index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); if (unlikely (status)) { _cairo_scaled_font_thaw_cache (sub_font->scaled_font); return status; } sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index, sub_font->current_subset, sub_font->num_glyphs_in_current_subset, scaled_glyph->metrics.x_advance, scaled_glyph->metrics.y_advance); _cairo_scaled_font_thaw_cache (sub_font->scaled_font); if (unlikely (sub_font_glyph == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph, sub_font->scaled_font, scaled_font_glyph_index); if (unlikely (status)) { _cairo_sub_font_glyph_destroy (sub_font_glyph); return status; } status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base); if (unlikely (status)) { _cairo_sub_font_glyph_destroy (sub_font_glyph); return status; } sub_font->num_glyphs_in_current_subset++; if (sub_font->is_scaled) { if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_scaled_subset_used) sub_font->parent->max_glyphs_per_scaled_subset_used = sub_font->num_glyphs_in_current_subset; } else { if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used) sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset; } } subset_glyph->font_id = sub_font->font_id; subset_glyph->subset_id = sub_font_glyph->subset_id; subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; subset_glyph->is_scaled = sub_font->is_scaled; subset_glyph->is_composite = sub_font->is_composite; subset_glyph->x_advance = sub_font_glyph->x_advance; subset_glyph->y_advance = sub_font_glyph->y_advance; status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, utf8, utf8_len, &subset_glyph->utf8_is_mapped); subset_glyph->unicode = sub_font_glyph->unicode; return status; }
static cairo_status_t _render_glyphs (cairo_gl_surface_t *dst, int dst_x, int dst_y, cairo_operator_t op, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, const cairo_rectangle_int_t *glyph_extents, cairo_scaled_font_t *scaled_font, cairo_region_t *clip_region, int *remaining_glyphs) { cairo_format_t last_format = (cairo_format_t) -1; cairo_gl_glyph_cache_t *cache = NULL; cairo_gl_context_t *ctx; cairo_gl_glyphs_setup_t setup; cairo_gl_composite_setup_t composite_setup; cairo_status_t status; int i = 0; GLuint vbo = 0; status = _cairo_gl_operand_init (&composite_setup.src, source, dst, glyph_extents->x, glyph_extents->y, dst_x, dst_y, glyph_extents->width, glyph_extents->height); if (unlikely (status)) return status; ctx = _cairo_gl_context_acquire (dst->ctx); /* Set up the mask to source from the incoming vertex color. */ glActiveTexture (GL_TEXTURE1); glEnable (GL_TEXTURE_2D); /* IN: dst.argb = src.argb * mask.aaaa */ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1); glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1); glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA); glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); _cairo_gl_set_destination (dst); _cairo_gl_set_operator (dst, op); _cairo_gl_set_src_operand (ctx, &composite_setup); _cairo_scaled_font_freeze_cache (scaled_font); if (! _cairo_gl_surface_owns_font (dst, scaled_font)) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto CLEANUP_FONT; } if (scaled_font->surface_private == NULL) { /* XXX couple into list to remove on context destruction */ scaled_font->surface_private = ctx; scaled_font->surface_backend = &_cairo_gl_surface_backend; } /* Create our VBO so that we can accumulate a bunch of glyph primitives * into one giant DrawArrays. */ memset(&setup, 0, sizeof(setup)); setup.composite = &composite_setup; setup.clip = clip_region; setup.dst = dst; setup.vertex_size = 4; if (composite_setup.src.type == OPERAND_TEXTURE) setup.vertex_size += 2; setup.vbo_size = num_glyphs * 4 * setup.vertex_size; if (setup.vbo_size > 4096) setup.vbo_size = 4096; glGenBuffersARB (1, &vbo); glBindBufferARB (GL_ARRAY_BUFFER_ARB, vbo); glVertexPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat), (void *)(uintptr_t)(0)); glEnableClientState (GL_VERTEX_ARRAY); if (composite_setup.src.type == OPERAND_TEXTURE) { /* Note that we're packing texcoord 0 after texcoord 1, for * convenience. */ glClientActiveTexture (GL_TEXTURE0); glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat), (void *)(uintptr_t)(4 * sizeof (GLfloat))); glEnableClientState (GL_TEXTURE_COORD_ARRAY); } glClientActiveTexture (GL_TEXTURE1); glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat), (void *)(uintptr_t)(2 * sizeof (GLfloat))); glEnableClientState (GL_TEXTURE_COORD_ARRAY); for (i = 0; i < num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; double x_offset, y_offset; double x1, x2, y1, y2; status = _cairo_scaled_glyph_lookup (scaled_font, 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->width > GLYPH_CACHE_MAX_SIZE || scaled_glyph->surface->height > GLYPH_CACHE_MAX_SIZE) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto FINISH; } if (scaled_glyph->surface->format != last_format) { /* Switching textures, so flush any queued prims. */ _cairo_gl_flush_glyphs (ctx, &setup); glActiveTexture (GL_TEXTURE1); cache = cairo_gl_context_get_glyph_cache (ctx, scaled_glyph->surface->format); glBindTexture (GL_TEXTURE_2D, cache->tex); last_format = scaled_glyph->surface->format; } if (scaled_glyph->surface_private == NULL) { status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph); if (unlikely (_cairo_status_is_error (status))) goto FINISH; if (status == CAIRO_INT_STATUS_UNSUPPORTED) { /* Cache is full, so flush existing prims and try again. */ _cairo_gl_flush_glyphs (ctx, &setup); _cairo_gl_glyph_cache_unlock (cache); } status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph); if (unlikely (status)) goto FINISH; } x_offset = scaled_glyph->surface->base.device_transform.x0; y_offset = scaled_glyph->surface->base.device_transform.y0; x1 = _cairo_lround (glyphs[i].x - x_offset); y1 = _cairo_lround (glyphs[i].y - y_offset); x2 = x1 + scaled_glyph->surface->width; y2 = y1 + scaled_glyph->surface->height; _cairo_gl_emit_glyph_rectangle (ctx, &setup, x1, y1, x2, y2, _cairo_gl_glyph_cache_lock (cache, scaled_glyph)); } status = CAIRO_STATUS_SUCCESS; FINISH: _cairo_gl_flush_glyphs (ctx, &setup); CLEANUP_FONT: _cairo_scaled_font_thaw_cache (scaled_font); glDisable (GL_BLEND); glDisable (GL_SCISSOR_TEST); glDisableClientState (GL_VERTEX_ARRAY); glClientActiveTexture (GL_TEXTURE0); glDisableClientState (GL_TEXTURE_COORD_ARRAY); glActiveTexture (GL_TEXTURE0); glDisable (GL_TEXTURE_2D); glClientActiveTexture (GL_TEXTURE1); glDisableClientState (GL_TEXTURE_COORD_ARRAY); glActiveTexture (GL_TEXTURE1); glDisable (GL_TEXTURE_2D); if (vbo != 0) { glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0); glDeleteBuffersARB (1, &vbo); } _cairo_gl_context_release (ctx); _cairo_gl_operand_destroy (&composite_setup.src); *remaining_glyphs = num_glyphs - i; return status; }
cairo_int_status_t i965_surface_glyphs (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_glyph_t *g, int num_glyphs, cairo_scaled_font_t *scaled_font, cairo_clip_t *clip, int *num_remaining) { i965_surface_t *surface = abstract_surface; i965_surface_t *mask = NULL; i965_device_t *device; i965_glyphs_t glyphs; cairo_composite_rectangles_t extents; cairo_clip_t local_clip; cairo_bool_t have_clip = FALSE; cairo_bool_t overlap; cairo_region_t *clip_region = NULL; intel_bo_t *last_bo = NULL; cairo_scaled_glyph_t *glyph_cache[64]; cairo_status_t status; int mask_x = 0, mask_y = 0; int i = 0; *num_remaining = 0; status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface->intel.drm.width, surface->intel.drm.height, op, source, scaled_font, g, num_glyphs, clip, &overlap); if (unlikely (status)) return status; if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents.mask)) clip = NULL; if (clip != NULL && extents.is_bounded) { clip = _cairo_clip_init_copy (&local_clip, clip); status = _cairo_clip_rectangle (clip, &extents.bounded); if (unlikely (status)) return status; have_clip = TRUE; } if (overlap || ! extents.is_bounded) { cairo_format_t format; format = CAIRO_FORMAT_A8; if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL) format = CAIRO_FORMAT_ARGB32; mask = (i965_surface_t *) i965_surface_create_internal (&i965_device (surface)->intel.base, format, extents.bounded.width, extents.bounded.height, I965_TILING_DEFAULT, TRUE); if (unlikely (mask->intel.drm.base.status)) return mask->intel.drm.base.status; status = _cairo_surface_paint (&mask->intel.drm.base, CAIRO_OPERATOR_CLEAR, &_cairo_pattern_clear.base, NULL); if (unlikely (status)) { cairo_surface_destroy (&mask->intel.drm.base); return status; } i965_shader_init (&glyphs.shader, mask, CAIRO_OPERATOR_ADD); status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source, &_cairo_pattern_white.base, &extents.bounded); if (unlikely (status)) { cairo_surface_destroy (&mask->intel.drm.base); return status; } mask_x = -extents.bounded.x; mask_y = -extents.bounded.y; } else { i965_shader_init (&glyphs.shader, surface, op); status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source, source, &extents.bounded); if (unlikely (status)) return status; if (clip != NULL) { status = _cairo_clip_get_region (clip, &clip_region); assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED); if (status == CAIRO_INT_STATUS_UNSUPPORTED) i965_shader_set_clip (&glyphs.shader, clip); } } glyphs.head.next = NULL; glyphs.head.bo = NULL; glyphs.head.count = 0; glyphs.tail = &glyphs.head; device = i965_device (surface); if (mask != NULL || clip_region == NULL) { glyphs.get_rectangle = i965_glyphs_emit_rectangle; } else { glyphs.get_rectangle = i965_glyphs_accumulate_rectangle; glyphs.head.bo = intel_bo_create (&device->intel, I965_VERTEX_SIZE, I965_VERTEX_SIZE, FALSE, I915_TILING_NONE, 0); if (unlikely (glyphs.head.bo == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); glyphs.vbo_base = intel_bo_map (&device->intel, glyphs.head.bo); } glyphs.vbo_offset = 0; status = cairo_device_acquire (&device->intel.base.base); if (unlikely (status)) goto CLEANUP_GLYPHS; _cairo_scaled_font_freeze_cache (scaled_font); //private = _cairo_scaled_font_get_device (scaled_font, device); if (scaled_font->surface_private == NULL) { scaled_font->surface_private = device; scaled_font->surface_backend = surface->intel.drm.base.backend; cairo_list_add (&scaled_font->link, &device->intel.fonts); } memset (glyph_cache, 0, sizeof (glyph_cache)); for (i = 0; i < num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; int x, y, x1, x2, y1, y2; int cache_index = g[i].index % ARRAY_LENGTH (glyph_cache); intel_glyph_t *glyph; scaled_glyph = glyph_cache[cache_index]; if (scaled_glyph == NULL || _cairo_scaled_glyph_index (scaled_glyph) != g[i].index) { status = _cairo_scaled_glyph_lookup (scaled_font, g[i].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); if (unlikely (status)) goto FINISH; glyph_cache[cache_index] = scaled_glyph; } if (unlikely (scaled_glyph->metrics.width == 0 || scaled_glyph->metrics.height == 0)) { continue; } /* XXX glyph images are snapped to pixel locations */ x = _cairo_lround (g[i].x); y = _cairo_lround (g[i].y); x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x); y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y); if (x2 < extents.bounded.x || y2 < extents.bounded.y || x1 > extents.bounded.x + extents.bounded.width || y1 > extents.bounded.y + extents.bounded.height) { continue; } if (scaled_glyph->surface_private == NULL) { status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph); if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) { status = CAIRO_STATUS_SUCCESS; continue; } if (unlikely (status)) goto FINISH; } glyph = intel_glyph_pin (scaled_glyph->surface_private); if (glyph->cache->buffer.bo != last_bo) { intel_buffer_cache_t *cache = glyph->cache; glyphs.shader.mask.type.vertex = VS_GLYPHS; glyphs.shader.mask.type.fragment = FS_GLYPHS; glyphs.shader.mask.type.pattern = PATTERN_BASE; glyphs.shader.mask.base.bo = cache->buffer.bo; glyphs.shader.mask.base.format = cache->buffer.format; glyphs.shader.mask.base.width = cache->buffer.width; glyphs.shader.mask.base.height = cache->buffer.height; glyphs.shader.mask.base.stride = cache->buffer.stride; glyphs.shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST); glyphs.shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE); glyphs.shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */ glyphs.shader.committed = FALSE; status = i965_shader_commit (&glyphs.shader, device); if (unlikely (status)) goto FINISH; last_bo = cache->buffer.bo; } x2 = x1 + glyph->width; y2 = y1 + glyph->height; if (mask_x) x1 += mask_x, x2 += mask_x; if (mask_y) y1 += mask_y, y2 += mask_y; i965_add_glyph_rectangle (&glyphs, x1, y1, x2, y2, glyph); } if (mask != NULL && clip_region != NULL) i965_clipped_vertices (device, &glyphs.head, clip_region); status = CAIRO_STATUS_SUCCESS; FINISH: _cairo_scaled_font_thaw_cache (scaled_font); cairo_device_release (surface->intel.drm.base.device); CLEANUP_GLYPHS: i965_shader_fini (&glyphs.shader); if (glyphs.head.bo != NULL) { struct i965_vbo *vbo, *next; intel_bo_destroy (&device->intel, glyphs.head.bo); for (vbo = glyphs.head.next; vbo != NULL; vbo = next) { next = vbo->next; intel_bo_destroy (&device->intel, vbo->bo); free (vbo); } } if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) { cairo_path_fixed_t path; _cairo_path_fixed_init (&path); status = _cairo_scaled_font_glyph_path (scaled_font, g + i, num_glyphs - i, &path); if (mask_x | mask_y) { _cairo_path_fixed_translate (&path, _cairo_fixed_from_int (mask_x), _cairo_fixed_from_int (mask_y)); } if (likely (status == CAIRO_STATUS_SUCCESS)) { status = surface->intel.drm.base.backend->fill (glyphs.shader.target, glyphs.shader.op, mask != NULL ? &_cairo_pattern_white.base : source, &path, CAIRO_FILL_RULE_WINDING, 0, scaled_font->options.antialias, clip); } _cairo_path_fixed_fini (&path); } if (mask != NULL) { if (likely (status == CAIRO_STATUS_SUCCESS)) { status = i965_surface_mask_internal (surface, op, source, mask, clip, &extents); } cairo_surface_finish (&mask->intel.drm.base); cairo_surface_destroy (&mask->intel.drm.base); } if (have_clip) _cairo_clip_fini (&local_clip); return status; }
static cairo_int_status_t composite_glyphs (cairo_image_surface_t *dst, void *closure, cairo_operator_t op, const cairo_pattern_t *pattern, int dst_x, int dst_y, const cairo_rectangle_int_t *extents) { cairo_composite_glyphs_info_t *info = closure; pixman_image_t *mask; cairo_status_t status; int i; mask = pixman_image_create_bits (PIXMAN_a8, extents->width, extents->height, NULL, 0); if (unlikely (mask == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = CAIRO_STATUS_SUCCESS; _cairo_scaled_font_freeze_cache (info->font); for (i = 0; i < info->num_glyphs; i++) { cairo_image_surface_t *glyph_surface; cairo_scaled_glyph_t *scaled_glyph; unsigned long glyph_index = info->glyphs[i].index; int x, y; status = _cairo_scaled_glyph_lookup (info->font, glyph_index, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); if (unlikely (status)) break; glyph_surface = scaled_glyph->surface; if (glyph_surface->width && glyph_surface->height) { /* round glyph locations to the nearest pixel */ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ x = _cairo_lround (info->glyphs[i].x - glyph_surface->base.device_transform.x0); y = _cairo_lround (info->glyphs[i].y - glyph_surface->base.device_transform.y0); pixman_image_composite32 (PIXMAN_OP_ADD, glyph_surface->pixman_image, NULL, mask, 0, 0, 0, 0, x - extents->x, y - extents->y, glyph_surface->width, glyph_surface->height); } } _cairo_scaled_font_thaw_cache (info->font); if (status == CAIRO_STATUS_SUCCESS) { cairo_rectangle_int_t sample; pixman_image_t *src; int src_x, src_y; _cairo_pattern_sampled_area (pattern, extents, &sample); src = _pixman_image_for_pattern (dst, pattern, FALSE, extents, &sample, &src_x, &src_y); if (src != NULL) { dst_x = extents->x - dst_x; dst_y = extents->y - dst_y; pixman_image_composite32 (_pixman_operator (op), src, mask, dst->pixman_image, src_x + dst_x, src_y + dst_y, 0, 0, dst_x, dst_y, extents->width, extents->height); pixman_image_unref (src); } else status = _cairo_error (CAIRO_STATUS_NO_MEMORY); } pixman_image_unref (mask); return status; }
static cairo_status_t _cairo_sub_font_add_glyph (cairo_sub_font_t *sub_font, unsigned long scaled_font_glyph_index, cairo_bool_t is_latin, int latin_character, uint32_t unicode, char *utf8, int utf8_len, cairo_sub_font_glyph_t **sub_font_glyph_out) { cairo_scaled_glyph_t *scaled_glyph; cairo_sub_font_glyph_t *sub_font_glyph; int *num_glyphs_in_subset_ptr; double x_advance; double y_advance; cairo_int_status_t status; _cairo_scaled_font_freeze_cache (sub_font->scaled_font); status = _cairo_scaled_glyph_lookup (sub_font->scaled_font, scaled_font_glyph_index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); if (unlikely (status)) { _cairo_scaled_font_thaw_cache (sub_font->scaled_font); return status; } x_advance = scaled_glyph->metrics.x_advance; y_advance = scaled_glyph->metrics.y_advance; _cairo_scaled_font_thaw_cache (sub_font->scaled_font); if (!is_latin && sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset) { sub_font->current_subset++; sub_font->num_glyphs_in_current_subset = 0; } if (is_latin) num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_latin_subset; else num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_current_subset; /* Reserve first glyph in subset for the .notdef glyph except for * Type 3 fonts */ if (*num_glyphs_in_subset_ptr == 0 && scaled_font_glyph_index != 0 && ! _cairo_font_face_is_user (sub_font->scaled_font->font_face)) { status = _cairo_sub_font_add_glyph (sub_font, 0, is_latin, 0, 0, NULL, -1, &sub_font_glyph); if (unlikely (status)) return status; } sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index, is_latin ? 0 : sub_font->current_subset, *num_glyphs_in_subset_ptr, x_advance, y_advance, is_latin ? latin_character : -1, unicode, utf8, utf8_len); if (unlikely (sub_font_glyph == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base); if (unlikely (status)) { _cairo_sub_font_glyph_destroy (sub_font_glyph); return status; } (*num_glyphs_in_subset_ptr)++; if (sub_font->is_scaled) { if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_scaled_subset_used) sub_font->parent->max_glyphs_per_scaled_subset_used = *num_glyphs_in_subset_ptr; } else { if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_unscaled_subset_used) sub_font->parent->max_glyphs_per_unscaled_subset_used = *num_glyphs_in_subset_ptr; } *sub_font_glyph_out = sub_font_glyph; return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, cairo_operator_t op, cairo_pattern_t *pattern, cairo_surface_t *surface, int source_x, int source_y, int dest_x, int dest_y, unsigned int width, unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs) { cairo_status_t status; cairo_surface_t *mask = NULL; int i; /* These operators aren't interpreted the same way by the backends; * they are implemented in terms of other operators in cairo-gstate.c */ assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR); if (scaled_font->status) return scaled_font->status; if (scaled_font->backend->show_glyphs != NULL) { status = scaled_font->backend->show_glyphs (scaled_font, op, pattern, surface, source_x, source_y, dest_x, dest_y, width, height, glyphs, num_glyphs); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } /* Font display routine either does not exist or failed. */ status = CAIRO_STATUS_SUCCESS; _cairo_cache_freeze (scaled_font->glyphs); for (i = 0; i < num_glyphs; i++) { int x, y; cairo_surface_pattern_t glyph_pattern; cairo_image_surface_t *glyph_surface; cairo_scaled_glyph_t *scaled_glyph; status = _cairo_scaled_glyph_lookup (scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); if (status) goto CLEANUP_MASK; glyph_surface = scaled_glyph->surface; /* Create the mask using the format from the first glyph */ if (mask == NULL) { mask = cairo_image_surface_create (glyph_surface->format, width, height); if (mask->status) { status = mask->status; goto CLEANUP_MASK; } status = _cairo_surface_fill_rectangle (mask, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, 0, 0, width, height); if (status) goto CLEANUP_MASK; if (glyph_surface->format == CAIRO_FORMAT_ARGB32) pixman_image_set_component_alpha (((cairo_image_surface_t*) mask)-> pixman_image, TRUE); } /* round glyph locations to the nearest pixel */ x = (int) floor (glyphs[i].x + glyph_surface->base.device_x_offset + 0.5); y = (int) floor (glyphs[i].y + glyph_surface->base.device_y_offset + 0.5); _cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base); status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, &glyph_pattern.base, NULL, mask, 0, 0, 0, 0, x - dest_x, y - dest_y, glyph_surface->width, glyph_surface->height); _cairo_pattern_fini (&glyph_pattern.base); if (status) break; } if (mask != NULL) { cairo_surface_pattern_t mask_pattern; _cairo_pattern_init_for_surface (&mask_pattern, mask); status = _cairo_surface_composite (op, pattern, &mask_pattern.base, surface, source_x, source_y, 0, 0, dest_x, dest_y, width, height); _cairo_pattern_fini (&mask_pattern.base); } CLEANUP_MASK: _cairo_cache_thaw (scaled_font->glyphs); if (mask != NULL) cairo_surface_destroy (mask); return 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_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; }