cairo-scaled-font.c [plain text]
#include "cairoint.h"
static cairo_bool_t
_cairo_scaled_glyph_keys_equal (void *abstract_key_a, void *abstract_key_b)
{
cairo_scaled_glyph_t *key_a = abstract_key_a;
cairo_scaled_glyph_t *key_b = abstract_key_b;
return (_cairo_scaled_glyph_index (key_a) ==
_cairo_scaled_glyph_index (key_b));
}
static void
_cairo_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph)
{
cairo_scaled_font_t *scaled_font = scaled_glyph->scaled_font;
const cairo_surface_backend_t *surface_backend = scaled_font->surface_backend;
if (surface_backend != NULL && surface_backend->scaled_glyph_fini != NULL)
surface_backend->scaled_glyph_fini (scaled_glyph, scaled_font);
if (scaled_glyph->surface != NULL)
cairo_surface_destroy (&scaled_glyph->surface->base);
if (scaled_glyph->path != NULL)
_cairo_path_fixed_destroy (scaled_glyph->path);
}
static void
_cairo_scaled_glyph_destroy (void *abstract_glyph)
{
cairo_scaled_glyph_t *scaled_glyph = abstract_glyph;
_cairo_scaled_glyph_fini (scaled_glyph);
free (scaled_glyph);
}
static const cairo_scaled_font_t _cairo_scaled_font_nil = {
{ 0 },
CAIRO_STATUS_NO_MEMORY,
-1,
NULL,
{ 1., 0., 0., 1., 0, 0},
{ 1., 0., 0., 1., 0, 0},
{ CAIRO_ANTIALIAS_DEFAULT,
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT} ,
{ 1., 0., 0., 1., 0, 0},
{ 0., 0., 0., 0., 0. },
NULL,
NULL,
NULL,
CAIRO_SCALED_FONT_BACKEND_DEFAULT,
};
void
_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
cairo_status_t status)
{
if (scaled_font->status == CAIRO_STATUS_SUCCESS)
scaled_font->status = status;
_cairo_error (status);
}
cairo_font_type_t
cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font)
{
return scaled_font->backend->type;
}
cairo_status_t
cairo_scaled_font_status (cairo_scaled_font_t *scaled_font)
{
return scaled_font->status;
}
#define CAIRO_SCALED_FONT_MAX_HOLDOVERS 256
typedef struct _cairo_scaled_font_map {
cairo_hash_table_t *hash_table;
cairo_scaled_font_t *holdovers[CAIRO_SCALED_FONT_MAX_HOLDOVERS];
int num_holdovers;
} cairo_scaled_font_map_t;
static cairo_scaled_font_map_t *cairo_scaled_font_map = NULL;
CAIRO_MUTEX_DECLARE (cairo_scaled_font_map_mutex);
static int
_cairo_scaled_font_keys_equal (void *abstract_key_a, void *abstract_key_b);
static cairo_scaled_font_map_t *
_cairo_scaled_font_map_lock (void)
{
CAIRO_MUTEX_LOCK (cairo_scaled_font_map_mutex);
if (cairo_scaled_font_map == NULL) {
cairo_scaled_font_map = malloc (sizeof (cairo_scaled_font_map_t));
if (cairo_scaled_font_map == NULL)
goto CLEANUP_MUTEX_LOCK;
cairo_scaled_font_map->hash_table =
_cairo_hash_table_create (_cairo_scaled_font_keys_equal);
if (cairo_scaled_font_map->hash_table == NULL)
goto CLEANUP_SCALED_FONT_MAP;
cairo_scaled_font_map->num_holdovers = 0;
}
return cairo_scaled_font_map;
CLEANUP_SCALED_FONT_MAP:
free (cairo_scaled_font_map);
CLEANUP_MUTEX_LOCK:
CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
return NULL;
}
static void
_cairo_scaled_font_map_unlock (void)
{
CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
}
void
_cairo_scaled_font_map_destroy (void)
{
int i;
cairo_scaled_font_map_t *font_map = cairo_scaled_font_map;
cairo_scaled_font_t *scaled_font;
if (font_map == NULL)
return;
CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
for (i = 0; i < font_map->num_holdovers; i++) {
scaled_font = font_map->holdovers[i];
assert (scaled_font->ref_count == 0);
_cairo_hash_table_remove (font_map->hash_table,
&scaled_font->hash_entry);
_cairo_scaled_font_fini (scaled_font);
free (scaled_font);
}
_cairo_hash_table_destroy (font_map->hash_table);
free (cairo_scaled_font_map);
cairo_scaled_font_map = NULL;
}
#define FNV_32_PRIME ((uint32_t)0x01000193)
#define FNV1_32_INIT ((uint32_t)0x811c9dc5)
static uint32_t
_hash_bytes_fnv (unsigned char *buffer,
int len,
uint32_t hval)
{
while (len--) {
hval *= FNV_32_PRIME;
hval ^= *buffer++;
}
return hval;
}
static void
_cairo_scaled_font_init_key (cairo_scaled_font_t *scaled_font,
cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options)
{
uint32_t hash = FNV1_32_INIT;
scaled_font->status = CAIRO_STATUS_SUCCESS;
scaled_font->font_face = font_face;
scaled_font->font_matrix = *font_matrix;
scaled_font->ctm = *ctm;
scaled_font->options = *options;
hash = _hash_bytes_fnv ((unsigned char *)(&scaled_font->font_matrix.xx),
sizeof(cairo_matrix_t), hash);
hash = _hash_bytes_fnv ((unsigned char *)(&scaled_font->ctm.xx),
sizeof(double) * 4, hash);
hash ^= (unsigned long) scaled_font->font_face;
hash ^= cairo_font_options_hash (&scaled_font->options);
scaled_font->hash_entry.hash = hash;
}
static cairo_bool_t
_cairo_scaled_font_keys_equal (void *abstract_key_a, void *abstract_key_b)
{
cairo_scaled_font_t *key_a = abstract_key_a;
cairo_scaled_font_t *key_b = abstract_key_b;
return (key_a->font_face == key_b->font_face &&
memcmp ((unsigned char *)(&key_a->font_matrix.xx),
(unsigned char *)(&key_b->font_matrix.xx),
sizeof(cairo_matrix_t)) == 0 &&
memcmp ((unsigned char *)(&key_a->ctm.xx),
(unsigned char *)(&key_b->ctm.xx),
sizeof(double) * 4) == 0 &&
cairo_font_options_equal (&key_a->options, &key_b->options));
}
cairo_status_t
_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
const cairo_scaled_font_backend_t *backend)
{
scaled_font->ref_count = 1;
_cairo_scaled_font_init_key (scaled_font, font_face,
font_matrix, ctm, options);
cairo_font_face_reference (font_face);
cairo_matrix_multiply (&scaled_font->scale,
&scaled_font->font_matrix,
&scaled_font->ctm);
scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal,
_cairo_scaled_glyph_destroy,
256);
scaled_font->surface_backend = NULL;
scaled_font->surface_private = NULL;
scaled_font->backend = backend;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *fs_metrics)
{
double font_scale_x, font_scale_y;
_cairo_matrix_compute_scale_factors (&scaled_font->font_matrix,
&font_scale_x, &font_scale_y,
1);
scaled_font->extents.ascent = fs_metrics->ascent * font_scale_y;
scaled_font->extents.descent = fs_metrics->descent * font_scale_y;
scaled_font->extents.height = fs_metrics->height * font_scale_y;
scaled_font->extents.max_x_advance = fs_metrics->max_x_advance * font_scale_x;
scaled_font->extents.max_y_advance = fs_metrics->max_y_advance * font_scale_y;
}
void
_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
{
if (scaled_font->font_face != NULL)
cairo_font_face_destroy (scaled_font->font_face);
if (scaled_font->glyphs != NULL)
_cairo_cache_destroy (scaled_font->glyphs);
if (scaled_font->surface_backend != NULL &&
scaled_font->surface_backend->scaled_font_fini != NULL)
scaled_font->surface_backend->scaled_font_fini (scaled_font);
scaled_font->backend->fini (scaled_font);
}
cairo_scaled_font_t *
cairo_scaled_font_create (cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options)
{
cairo_status_t status;
cairo_scaled_font_map_t *font_map;
cairo_scaled_font_t key, *scaled_font = NULL;
if (font_face->status)
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
font_map = _cairo_scaled_font_map_lock ();
if (font_map == NULL)
goto UNWIND;
_cairo_scaled_font_init_key (&key, font_face,
font_matrix, ctm, options);
if (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
(cairo_hash_entry_t**) &scaled_font))
{
_cairo_scaled_font_map_unlock ();
return cairo_scaled_font_reference (scaled_font);
}
status = font_face->backend->scaled_font_create (font_face, font_matrix,
ctm, options, &scaled_font);
if (status)
goto UNWIND_FONT_MAP_LOCK;
status = _cairo_hash_table_insert (font_map->hash_table,
&scaled_font->hash_entry);
if (status)
goto UNWIND_SCALED_FONT_CREATE;
_cairo_scaled_font_map_unlock ();
return scaled_font;
UNWIND_SCALED_FONT_CREATE:
_cairo_scaled_font_fini (scaled_font);
free (scaled_font);
UNWIND_FONT_MAP_LOCK:
_cairo_scaled_font_map_unlock ();
UNWIND:
return NULL;
}
cairo_scaled_font_t *
cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_map_t *font_map;
if (scaled_font == NULL)
return NULL;
if (scaled_font->ref_count == (unsigned int)-1)
return scaled_font;
font_map = _cairo_scaled_font_map_lock ();
{
if (scaled_font->ref_count == 0) {
int i;
for (i = 0; i < font_map->num_holdovers; i++)
if (font_map->holdovers[i] == scaled_font)
break;
assert (i < font_map->num_holdovers);
font_map->num_holdovers--;
memmove (&font_map->holdovers[i],
&font_map->holdovers[i+1],
(font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*));
}
scaled_font->ref_count++;
}
_cairo_scaled_font_map_unlock ();
return scaled_font;
}
void
cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_map_t *font_map;
if (scaled_font == NULL)
return;
if (scaled_font->ref_count == (unsigned int)-1)
return;
font_map = _cairo_scaled_font_map_lock ();
{
assert (font_map != NULL);
assert (scaled_font->ref_count > 0);
if (--(scaled_font->ref_count) == 0)
{
if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) {
cairo_scaled_font_t *lru;
lru = font_map->holdovers[0];
assert (lru->ref_count == 0);
_cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry);
_cairo_scaled_font_fini (lru);
free (lru);
font_map->num_holdovers--;
memmove (&font_map->holdovers[0],
&font_map->holdovers[1],
font_map->num_holdovers * sizeof (cairo_scaled_font_t*));
}
font_map->holdovers[font_map->num_holdovers] = scaled_font;
font_map->num_holdovers++;
}
}
_cairo_scaled_font_map_unlock ();
}
void
cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *extents)
{
*extents = scaled_font->extents;
}
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);
}
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_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;
}
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;
}
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_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;
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;
}
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;
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);
}
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;
}
typedef struct _cairo_scaled_glyph_path_closure {
cairo_point_t offset;
cairo_path_fixed_t *path;
} cairo_scaled_glyph_path_closure_t;
static cairo_status_t
_scaled_glyph_path_move_to (void *abstract_closure, cairo_point_t *point)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_move_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
static cairo_status_t
_scaled_glyph_path_line_to (void *abstract_closure, cairo_point_t *point)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_line_to (closure->path,
point->x + closure->offset.x,
point->y + closure->offset.y);
}
static cairo_status_t
_scaled_glyph_path_curve_to (void *abstract_closure,
cairo_point_t *p0,
cairo_point_t *p1,
cairo_point_t *p2)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_curve_to (closure->path,
p0->x + closure->offset.x,
p0->y + closure->offset.y,
p1->x + closure->offset.x,
p1->y + closure->offset.y,
p2->x + closure->offset.x,
p2->y + closure->offset.y);
}
static cairo_status_t
_scaled_glyph_path_close_path (void *abstract_closure)
{
cairo_scaled_glyph_path_closure_t *closure = abstract_closure;
return _cairo_path_fixed_close_path (closure->path);
}
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;
}
void
_cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_text_extents_t *fs_metrics)
{
cairo_bool_t first = TRUE;
double hm, wm;
double min_user_x = 0.0, max_user_x = 0.0, min_user_y = 0.0, max_user_y = 0.0;
double min_device_x = 0.0, max_device_x = 0.0, min_device_y = 0.0, max_device_y = 0.0;
for (hm = 0.0; hm <= 1.0; hm += 1.0)
for (wm = 0.0; wm <= 1.0; wm += 1.0) {
double x, y;
x = fs_metrics->x_bearing + fs_metrics->width * wm;
y = fs_metrics->y_bearing + fs_metrics->height * hm;
cairo_matrix_transform_point (&scaled_font->font_matrix,
&x, &y);
if (first) {
min_user_x = max_user_x = x;
min_user_y = max_user_y = y;
} else {
if (x < min_user_x) min_user_x = x;
if (x > max_user_x) max_user_x = x;
if (y < min_user_y) min_user_y = y;
if (y > max_user_y) max_user_y = y;
}
x = fs_metrics->x_bearing + fs_metrics->width * wm;
y = fs_metrics->y_bearing + fs_metrics->height * hm;
cairo_matrix_transform_distance (&scaled_font->scale,
&x, &y);
if (first) {
min_device_x = max_device_x = x;
min_device_y = max_device_y = y;
} else {
if (x < min_device_x) min_device_x = x;
if (x > max_device_x) max_device_x = x;
if (y < min_device_y) min_device_y = y;
if (y > max_device_y) max_device_y = y;
}
first = FALSE;
}
scaled_glyph->metrics.x_bearing = min_user_x;
scaled_glyph->metrics.y_bearing = min_user_y;
scaled_glyph->metrics.width = max_user_x - min_user_x;
scaled_glyph->metrics.height = max_user_y - min_user_y;
scaled_glyph->metrics.x_advance = fs_metrics->x_advance;
scaled_glyph->metrics.y_advance = fs_metrics->y_advance;
cairo_matrix_transform_point (&scaled_font->font_matrix,
&scaled_glyph->metrics.x_advance,
&scaled_glyph->metrics.y_advance);
scaled_glyph->bbox.p1.x = _cairo_fixed_from_double (min_device_x);
scaled_glyph->bbox.p1.y = _cairo_fixed_from_double (min_device_y);
scaled_glyph->bbox.p2.x = _cairo_fixed_from_double (max_device_x);
scaled_glyph->bbox.p2.y = _cairo_fixed_from_double (max_device_y);
}
void
_cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_image_surface_t *surface)
{
if (scaled_glyph->surface != NULL)
cairo_surface_destroy (&scaled_glyph->surface->base);
scaled_glyph->surface = surface;
}
void
_cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_path_fixed_t *path)
{
if (scaled_glyph->path != NULL)
_cairo_path_fixed_destroy (scaled_glyph->path);
scaled_glyph->path = path;
}
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;
info |= CAIRO_SCALED_GLYPH_INFO_METRICS;
if (!_cairo_cache_lookup (scaled_font->glyphs, &key,
(cairo_cache_entry_t **) &scaled_glyph))
{
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;
scaled_glyph->scaled_font = scaled_font;
scaled_glyph->surface = NULL;
scaled_glyph->path = NULL;
scaled_glyph->surface_private = NULL;
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;
}
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;
}
cairo_font_face_t *
cairo_scaled_font_get_font_face (cairo_scaled_font_t *scaled_font)
{
if (scaled_font->status)
return (cairo_font_face_t*) &_cairo_font_face_nil;
return scaled_font->font_face;
}
void
cairo_scaled_font_get_font_matrix (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *font_matrix)
{
if (scaled_font->status) {
cairo_matrix_init_identity (font_matrix);
return;
}
*font_matrix = scaled_font->font_matrix;
}
void
cairo_scaled_font_get_ctm (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *ctm)
{
if (scaled_font->status) {
cairo_matrix_init_identity (ctm);
return;
}
*ctm = scaled_font->ctm;
}
void
cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font,
cairo_font_options_t *options)
{
if (scaled_font->status) {
_cairo_font_options_init_default (options);
return;
}
_cairo_font_options_init_copy (options, &scaled_font->options);
}