summaryrefslogtreecommitdiff
path: root/src/cairo-scaled-font.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-scaled-font.c')
-rw-r--r--src/cairo-scaled-font.c359
1 files changed, 197 insertions, 162 deletions
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index e342eb8..199ad39 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -651,7 +651,7 @@ _cairo_scaled_font_matches (const cairo_scaled_font_t *scaled_font,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options)
{
- return scaled_font->font_face == font_face &&
+ return scaled_font->original_font_face == font_face &&
memcmp ((unsigned char *)(&scaled_font->font_matrix.xx),
(unsigned char *)(&font_matrix->xx),
sizeof(cairo_matrix_t)) == 0 &&
@@ -838,6 +838,22 @@ _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
_cairo_user_data_array_fini (&scaled_font->user_data);
}
+/* XXX: allow multiple backends to share the font */
+void
+_cairo_scaled_font_revoke_ownership (cairo_scaled_font_t *scaled_font)
+{
+ if (scaled_font->surface_backend == NULL)
+ return;
+
+ _cairo_scaled_font_reset_cache (scaled_font);
+
+ if (scaled_font->surface_backend->scaled_font_fini != NULL)
+ scaled_font->surface_backend->scaled_font_fini (scaled_font);
+
+ scaled_font->surface_backend = NULL;
+ scaled_font->surface_private = NULL;
+}
+
void
_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
{
@@ -899,13 +915,6 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
/* Note that degenerate ctm or font_matrix *are* allowed.
* We want to support a font size of 0. */
- if (font_face->backend->get_implementation != NULL) {
- font_face = font_face->backend->get_implementation (font_face,
- font_matrix,
- ctm,
- options);
- }
-
font_map = _cairo_scaled_font_map_lock ();
if (unlikely (font_map == NULL))
return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
@@ -931,9 +940,26 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
_cairo_hash_table_remove (font_map->hash_table,
&scaled_font->hash_entry);
scaled_font->hash_entry.hash = ZOMBIE;
+
+ if (font_face->backend->get_implementation != NULL) {
+ font_face = font_face->backend->get_implementation (font_face,
+ font_matrix,
+ ctm,
+ options);
+ }
+
+ _cairo_scaled_font_init_key (&key, font_face,
+ font_matrix, ctm, options);
}
else
{
+ if (font_face->backend->get_implementation != NULL) {
+ font_face = font_face->backend->get_implementation (font_face,
+ font_matrix,
+ ctm,
+ options);
+ }
+
_cairo_scaled_font_init_key (&key, font_face,
font_matrix, ctm, options);
@@ -991,6 +1017,8 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
_cairo_scaled_font_map_unlock ();
cairo_scaled_font_destroy (old);
+ if (font_face != original_font_face)
+ cairo_font_face_destroy (font_face);
return scaled_font;
}
@@ -1008,12 +1036,18 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
/* Did we leave the backend in an error state? */
if (unlikely (status)) {
_cairo_scaled_font_map_unlock ();
+ if (font_face != original_font_face)
+ cairo_font_face_destroy (font_face);
+
status = _cairo_font_face_set_error (font_face, status);
return _cairo_scaled_font_create_in_error (status);
}
/* Or did we encounter an error whilst constructing the scaled font? */
if (unlikely (scaled_font->status)) {
_cairo_scaled_font_map_unlock ();
+ if (font_face != original_font_face)
+ cairo_font_face_destroy (font_face);
+
return scaled_font;
}
@@ -1026,7 +1060,6 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
scaled_font->original_font_face =
cairo_font_face_reference (original_font_face);
- assert (scaled_font->hash_entry.hash == key.hash_entry.hash);
status = _cairo_hash_table_insert (font_map->hash_table,
&scaled_font->hash_entry);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
@@ -1037,6 +1070,10 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
_cairo_scaled_font_map_unlock ();
+ cairo_scaled_font_destroy (old);
+ if (font_face != original_font_face)
+ cairo_font_face_destroy (font_face);
+
if (unlikely (status)) {
/* We can't call _cairo_scaled_font_destroy here since it expects
* that the font has already been successfully inserted into the
@@ -1046,11 +1083,6 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
return _cairo_scaled_font_create_in_error (status);
}
- cairo_scaled_font_destroy (old);
-
- if (font_face != original_font_face)
- cairo_font_face_destroy (font_face);
-
return scaled_font;
}
slim_hidden_def (cairo_scaled_font_create);
@@ -1421,22 +1453,22 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
extents->x_advance = 0.0;
extents->y_advance = 0.0;
- if (scaled_font->status)
- return;
+ if (unlikely (scaled_font->status))
+ goto ZERO_EXTENTS;
if (num_glyphs == 0)
- return;
+ goto ZERO_EXTENTS;
- if (num_glyphs < 0) {
+ if (unlikely (num_glyphs < 0)) {
_cairo_error_throw (CAIRO_STATUS_NEGATIVE_COUNT);
/* XXX Can't propagate error */
- return;
+ goto ZERO_EXTENTS;
}
- if (glyphs == NULL) {
+ if (unlikely (glyphs == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
/* XXX Can't propagate error */
- return;
+ goto ZERO_EXTENTS;
}
_cairo_scaled_font_freeze_cache (scaled_font);
@@ -1507,6 +1539,15 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
UNLOCK:
_cairo_scaled_font_thaw_cache (scaled_font);
+ return;
+
+ZERO_EXTENTS:
+ 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;
}
slim_hidden_def (cairo_scaled_font_glyph_extents);
@@ -1886,6 +1927,15 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
}
slim_hidden_def (cairo_scaled_font_text_to_glyphs);
+static inline cairo_bool_t
+_range_contains_glyph (const cairo_point_int_t *min,
+ const cairo_point_int_t *max,
+ int left, int top,
+ int right, int bottom)
+{
+ return right > min->x && left < max->x && bottom > min->y && top < max->y;
+}
+
/*
* Compute a device-space bounding box for the glyphs.
*/
@@ -1893,13 +1943,15 @@ 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_int_t *extents)
+ cairo_rectangle_int_t *extents,
+ cairo_bool_t *overlap_out)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- int i;
cairo_point_int_t min = { CAIRO_RECT_INT_MAX, CAIRO_RECT_INT_MAX };
cairo_point_int_t max = { CAIRO_RECT_INT_MIN, CAIRO_RECT_INT_MIN };
cairo_scaled_glyph_t *glyph_cache[64];
+ cairo_bool_t overlap = overlap_out ? FALSE : TRUE;
+ int i;
if (unlikely (scaled_font->status))
return scaled_font->status;
@@ -1938,6 +1990,11 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
right = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
bottom = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
+ if (overlap == FALSE) {
+ overlap = _range_contains_glyph (&min, &max,
+ left, top, right, bottom);
+ }
+
if (left < min.x) min.x = left;
if (right > max.x) max.x = right;
if (top < min.y) min.y = top;
@@ -1958,22 +2015,62 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
extents->width = extents->height = 0;
}
+ if (overlap_out != NULL)
+ *overlap_out = overlap;
+
return CAIRO_STATUS_SUCCESS;
}
+void
+_cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t *scaled_font,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_rectangle_int_t *extents)
+{
+ double x0 = HUGE_VAL, x1 = -HUGE_VAL;
+ double y0 = HUGE_VAL, y1 = -HUGE_VAL;
+ int i;
+
+ for (i = 0; i < num_glyphs; i++) {
+ double g;
+
+ g = glyphs[i].x;
+ if (g < x0) x0 = g;
+ if (g > x1) x1 = g;
+
+ g = glyphs[i].y;
+ if (g < y0) y0 = g;
+ if (g > y1) y1 = g;
+ }
+
+ if (x0 <= x1 && y0 <= y1) {
+ extents->x = floor (x0 - scaled_font->extents.max_x_advance);
+ extents->width = ceil (x1 + scaled_font->extents.max_x_advance);
+ extents->width -= extents->x;
+
+ extents->y = floor (y0 - scaled_font->extents.ascent);
+ extents->height = ceil (y1 + scaled_font->extents.descent);
+ extents->height -= extents->y;
+ } else {
+ extents->x = extents->y = 0;
+ extents->width = extents->height = 0;
+ }
+}
+
cairo_status_t
-_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
- cairo_operator_t op,
+_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t op,
const 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,
- cairo_glyph_t *glyphs,
- int num_glyphs)
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_region_t *clip_region)
{
cairo_status_t status;
cairo_surface_t *mask = NULL;
@@ -2001,7 +2098,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
source_x, source_y,
dest_x, dest_y,
width, height,
- glyphs, num_glyphs, &remaining_glyphs);
+ glyphs, num_glyphs,
+ clip_region,
+ &remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
@@ -2018,7 +2117,6 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
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;
@@ -2036,8 +2134,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
* glyph. Later we'll deal with different formats. */
if (mask == NULL) {
mask_format = glyph_surface->format;
- mask = cairo_image_surface_create (mask_format,
- width, height);
+ mask = cairo_image_surface_create (mask_format, width, height);
status = mask->status;
if (unlikely (status))
goto CLEANUP_MASK;
@@ -2064,10 +2161,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
break;
}
- new_mask = cairo_image_surface_create (mask_format,
- width, height);
- if (new_mask->status) {
- status = new_mask->status;
+ new_mask = cairo_image_surface_create (mask_format, width, height);
+ status = new_mask->status;
+ if (unlikely (status)) {
cairo_surface_destroy (new_mask);
goto CLEANUP_MASK;
}
@@ -2081,7 +2177,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
0, 0,
0, 0,
0, 0,
- width, height);
+ width, height,
+ NULL);
_cairo_pattern_fini (&mask_pattern.base);
@@ -2094,32 +2191,41 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
mask = new_mask;
}
- /* round glyph locations to the nearest pixel */
- /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
- x = _cairo_lround (glyphs[i].x - glyph_surface->base.device_transform.x0);
- y = _cairo_lround (glyphs[i].y - glyph_surface->base.device_transform.y0);
+ if (glyph_surface->width && glyph_surface->height) {
+ cairo_surface_pattern_t glyph_pattern;
- _cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);
+ /* round glyph locations to the nearest pixel */
+ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+ x = _cairo_lround (glyphs[i].x -
+ glyph_surface->base.device_transform.x0);
+ y = _cairo_lround (glyphs[i].y -
+ glyph_surface->base.device_transform.y0);
- status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
- &white_pattern.base,
- &glyph_pattern.base,
- mask,
- 0, 0,
- 0, 0,
- x - dest_x, y - dest_y,
- glyph_surface->width,
- glyph_surface->height);
+ _cairo_pattern_init_for_surface (&glyph_pattern,
+ &glyph_surface->base);
- _cairo_pattern_fini (&glyph_pattern.base);
+ status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
+ &white_pattern.base,
+ &glyph_pattern.base,
+ mask,
+ 0, 0,
+ 0, 0,
+ x - dest_x, y - dest_y,
+ glyph_surface->width,
+ glyph_surface->height,
+ NULL);
- if (unlikely (status))
- goto CLEANUP_MASK;
+ _cairo_pattern_fini (&glyph_pattern.base);
+
+ if (unlikely (status))
+ goto CLEANUP_MASK;
+ }
}
- if (mask_format == CAIRO_FORMAT_ARGB32)
+ if (mask_format == CAIRO_FORMAT_ARGB32) {
pixman_image_set_component_alpha (((cairo_image_surface_t*) mask)->
pixman_image, TRUE);
+ }
_cairo_pattern_init_for_surface (&mask_pattern, mask);
status = _cairo_surface_composite (op, pattern, &mask_pattern.base,
@@ -2127,7 +2233,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
source_x, source_y,
0, 0,
dest_x, dest_y,
- width, height);
+ width, height,
+ clip_region);
_cairo_pattern_fini (&mask_pattern.base);
@@ -2141,67 +2248,15 @@ CLEANUP_MASK:
return _cairo_scaled_font_set_error (scaled_font, 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,
- const 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,
- const 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,
- const cairo_point_t *p0,
- const cairo_point_t *p1,
- const 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);
-}
-
/* Add a single-device-unit rectangle to a path. */
static cairo_status_t
-_add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y)
+_add_unit_rectangle_to_path (cairo_path_fixed_t *path,
+ cairo_fixed_t x,
+ cairo_fixed_t y)
{
cairo_status_t status;
- status = _cairo_path_fixed_move_to (path,
- _cairo_fixed_from_int (x),
- _cairo_fixed_from_int (y));
+ status = _cairo_path_fixed_move_to (path, x, y);
if (unlikely (status))
return status;
@@ -2223,11 +2278,7 @@ _add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y)
if (unlikely (status))
return status;
- status = _cairo_path_fixed_close_path (path);
- if (unlikely (status))
- return status;
-
- return CAIRO_STATUS_SUCCESS;
+ return _cairo_path_fixed_close_path (path);
}
/**
@@ -2249,12 +2300,15 @@ _add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y)
**/
static cairo_status_t
_trace_mask_to_path (cairo_image_surface_t *mask,
- cairo_path_fixed_t *path)
+ cairo_path_fixed_t *path,
+ double tx, double ty)
{
const uint8_t *row;
int rows, cols, bytes_per_row;
int x, y, bit;
double xoff, yoff;
+ cairo_fixed_t x0, y0;
+ cairo_fixed_t px, py;
cairo_status_t status;
mask = _cairo_image_surface_coerce (mask, CAIRO_FORMAT_A1);
@@ -2263,12 +2317,15 @@ _trace_mask_to_path (cairo_image_surface_t *mask,
return status;
cairo_surface_get_device_offset (&mask->base, &xoff, &yoff);
+ x0 = _cairo_fixed_from_double (tx - xoff);
+ y0 = _cairo_fixed_from_double (ty - yoff);
bytes_per_row = (mask->width + 7) / 8;
row = mask->data;
for (y = 0, rows = mask->height; rows--; row += mask->stride, y++) {
const uint8_t *byte_ptr = row;
x = 0;
+ py = _cairo_fixed_from_int (y);
for (cols = bytes_per_row; cols--; ) {
uint8_t byte = *byte_ptr++;
if (byte == 0) {
@@ -2279,8 +2336,10 @@ _trace_mask_to_path (cairo_image_surface_t *mask,
byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (byte);
for (bit = 1 << 7; bit && x < mask->width; bit >>= 1, x++) {
if (byte & bit) {
+ px = _cairo_fixed_from_int (x);
status = _add_unit_rectangle_to_path (path,
- x - xoff, y - yoff);
+ px + x0,
+ py + y0);
if (unlikely (status))
goto BAIL;
}
@@ -2302,14 +2361,11 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
{
cairo_status_t status;
int i;
- cairo_scaled_glyph_path_closure_t closure;
- cairo_path_fixed_t *glyph_path;
status = scaled_font->status;
if (unlikely (status))
return status;
- closure.path = path;
_cairo_scaled_font_freeze_cache (scaled_font);
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
@@ -2318,14 +2374,16 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_PATH,
&scaled_glyph);
- if (status == CAIRO_STATUS_SUCCESS)
- glyph_path = scaled_glyph->path;
- else if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- goto BAIL;
-
- /* If the font is incapable of providing a path, then we'll
- * have to trace our own from a surface. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ if (status == CAIRO_STATUS_SUCCESS) {
+ status = _cairo_path_fixed_append (path,
+ scaled_glyph->path, CAIRO_DIRECTION_FORWARD,
+ _cairo_fixed_from_double (glyphs[i].x),
+ _cairo_fixed_from_double (glyphs[i].y));
+
+ } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ /* If the font is incapable of providing a path, then we'll
+ * have to trace our own from a surface.
+ */
status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
@@ -2333,32 +2391,10 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
if (unlikely (status))
goto BAIL;
- glyph_path = _cairo_path_fixed_create ();
- if (unlikely (glyph_path == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
-
- status = _trace_mask_to_path (scaled_glyph->surface, glyph_path);
- if (unlikely (status)) {
- _cairo_path_fixed_destroy (glyph_path);
- goto BAIL;
- }
+ status = _trace_mask_to_path (scaled_glyph->surface, path,
+ glyphs[i].x, glyphs[i].y);
}
- 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 (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);
- if (glyph_path != scaled_glyph->path)
- _cairo_path_fixed_destroy (glyph_path);
-
if (unlikely (status))
goto BAIL;
}
@@ -2730,8 +2766,7 @@ _cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
* @scaled_font: a #cairo_scaled_font_t
*
* Gets the font face that this scaled font uses. This is the
- * font face passed to cairo_scaled_font_create() if that font face
- * was not of type %CAIRO_FONT_TYPE_TOY.
+ * font face passed to cairo_scaled_font_create().
*
* Return value: The #cairo_font_face_t with which @scaled_font was
* created.