static unsigned long _cairo_user_ucs4_to_index (void *abstract_font, uint32_t ucs4) { cairo_user_scaled_font_t *scaled_font = abstract_font; cairo_user_font_face_t *face = (cairo_user_font_face_t *) scaled_font->base.font_face; unsigned long glyph = 0; if (face->scaled_font_methods.unicode_to_glyph) { cairo_status_t status; status = face->scaled_font_methods.unicode_to_glyph (&scaled_font->base, ucs4, &glyph); if (status != CAIRO_STATUS_SUCCESS) { status = _cairo_scaled_font_set_error (&scaled_font->base, status); glyph = 0; } } else { glyph = ucs4; } return glyph; }
/** * cairo_scaled_font_extents: * @scaled_font: a #cairo_scaled_font_t * @extents: a #cairo_font_extents_t which to store the retrieved extents. * * Gets the metrics for a #cairo_scaled_font_t. **/ void cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font, cairo_font_extents_t *extents) { cairo_int_status_t status; double font_scale_x, font_scale_y; if (scaled_font->status) return; status = _cairo_scaled_font_font_extents (scaled_font, extents); if (status) { _cairo_scaled_font_set_error (scaled_font, status); return; } _cairo_matrix_compute_scale_factors (&scaled_font->font_matrix, &font_scale_x, &font_scale_y, /* XXX */ 1); /* * The font responded in unscaled units, scale by the font * matrix scale factors to get to user space */ extents->ascent *= font_scale_y; extents->descent *= font_scale_y; extents->height *= font_scale_y; extents->max_x_advance *= font_scale_x; extents->max_y_advance *= font_scale_y; }
/* * 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_scaled_font_text_extents: * @scaled_font: a #cairo_scaled_font_t * @utf8: a string of text, encoded in UTF-8 * @extents: a #cairo_text_extents_t which to store the retrieved extents. * * Gets the extents for a string of text. The extents describe a * user-space rectangle that encloses the "inked" portion of the text * drawn at the origin (0,0) (as it would be drawn by cairo_show_text() * 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_text(). * * Note that whitespace characters do not directly contribute to the * size of the rectangle (extents.width and extents.height). They do * contribute indirectly by changing the position of non-whitespace * characters. In particular, trailing whitespace characters are * likely to not affect the size of the rectangle, though they will * affect the x_advance and y_advance values. **/ void cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font, const char *utf8, cairo_text_extents_t *extents) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_glyph_t *glyphs; int num_glyphs; status = _cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0., utf8, &glyphs, &num_glyphs); if (status) { _cairo_scaled_font_set_error (scaled_font, status); return; } cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, extents); free (glyphs); }
/** * 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; }
/** * _cairo_scaled_glyph_lookup: * @scaled_font: a #cairo_scaled_font_t * @index: the glyph to create * @info: a #cairo_scaled_glyph_info_t marking which portions of * the glyph should be filled in. * @scaled_glyph_ret: a #cairo_scaled_glyph_t * where the glyph * is returned. * * Returns a glyph with the requested portions filled in. Glyph * lookup is cached and glyph will be automatically freed along * with the scaled_font so no explicit free is required. * @info can be one or more of: * %CAIRO_SCALED_GLYPH_INFO_METRICS - glyph metrics and bounding box * %CAIRO_SCALED_GLYPH_INFO_SURFACE - surface holding glyph image * %CAIRO_SCALED_GLYPH_INFO_PATH - path holding glyph outline in device space **/ cairo_status_t _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, unsigned long index, cairo_scaled_glyph_info_t info, cairo_scaled_glyph_t **scaled_glyph_ret) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_cache_entry_t key; cairo_scaled_glyph_t *scaled_glyph; cairo_scaled_glyph_info_t need_info; if (scaled_font->status) return scaled_font->status; CAIRO_MUTEX_LOCK (cairo_scaled_font_map_mutex); key.hash = index; /* * Check cache for glyph */ info |= CAIRO_SCALED_GLYPH_INFO_METRICS; if (!_cairo_cache_lookup (scaled_font->glyphs, &key, (cairo_cache_entry_t **) &scaled_glyph)) { /* * On miss, create glyph and insert into cache */ scaled_glyph = malloc (sizeof (cairo_scaled_glyph_t)); if (scaled_glyph == NULL) { status = CAIRO_STATUS_NO_MEMORY; goto CLEANUP; } _cairo_scaled_glyph_set_index(scaled_glyph, index); scaled_glyph->cache_entry.size = 1; /* XXX */ scaled_glyph->scaled_font = scaled_font; scaled_glyph->surface = NULL; scaled_glyph->path = NULL; scaled_glyph->surface_private = NULL; /* ask backend to initialize metrics and shape fields */ status = (*scaled_font->backend-> scaled_glyph_init) (scaled_font, scaled_glyph, info); if (status) goto CLEANUP; status = _cairo_cache_insert (scaled_font->glyphs, &scaled_glyph->cache_entry); if (status) goto CLEANUP; } /* * Check and see if the glyph, as provided, * already has the requested data and ammend it if not */ need_info = 0; if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0 && scaled_glyph->surface == NULL) need_info |= CAIRO_SCALED_GLYPH_INFO_SURFACE; if (((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 && scaled_glyph->path == NULL)) need_info |= CAIRO_SCALED_GLYPH_INFO_PATH; if (need_info) { status = (*scaled_font->backend-> scaled_glyph_init) (scaled_font, scaled_glyph, need_info); if (status) goto CLEANUP; } CLEANUP: if (status) { _cairo_scaled_font_set_error (scaled_font, status); if (scaled_glyph) _cairo_scaled_glyph_destroy (scaled_glyph); *scaled_glyph_ret = NULL; } else { *scaled_glyph_ret = scaled_glyph; } CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex); return status; }