mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-04-30 13:20:45 +02:00
Add cairo_cache.c
Rewrite using temporary glyph arrays New file. Remove old glyph cache code. (_cairo_font_scale) (_cairo_font_transform): Remove font-transforming code. (_cairo_font_text_extents) (_cairo_font_text_bbox) (_cairo_font_show_text) (_cairo_font_text_path): Remove text-API code. (_cairo_font_cache_key_t): New structure type. (_font_cache_hash) (_font_cache_keys_equal) (_font_cache_create_entry) (_font_cache_destroy_entry) (_font_cache_destroy_cache): New font cache code. (_global_font_cache) (_lock_global_font_cache) (_unlock_global_font_cache) (_get_global_font_cache): New global font cache. (_cairo_font_text_to_glyphs) (_cairo_glyph_cache_hash) (_cairo_glyph_cache_keys_equal) (_image_glyph_cache_create_entry) (_image_glyph_cache_destroy_entry) (_image_glyph_cache_destroy_cache): New glyph cache code. (_global_image_glyph_cache) (_cairo_lock_global_image_glyph_cache) (_cairo_unlock_global_image_glyph_cache) (_cairo_get_global_image_glyph_cache): New global glyph cache. (_cairo_font_cache_backend): New structure. (_cairo_image_cache_backend): Likewise. (_cairo_font_create): Reimplement in terms of font cache. (_cairo_font_init): Remove matrix and glyph cache related code. (_cairo_font_copy): Likewise. (_cairo_font_show_glyphs): Delegate to surface when possible. (_cairo_font_glyph_extents) (_cairo_font_glyph_bbox) (_cairo_font_glyph_path) (_cairo_font_font_extents) (_cairo_font_show_glyphs): Rename to as cairo_unscaled_font_XXX, and add scale parameter. New structure types. (_create_from_face) (_reference_font_val) (_destroy_font_val) (_create_from_library_and_pattern): New functions. (_ft_font_cache_hash) (_ft_font_cache_keys_equal) (_ft_font_cache_create_entry) (_ft_font_cache_destroy_entry) (_ft_font_cache_destroy_cache): New ft font cache code. (_global_ft_cache) (_lock_global_ft_cache) (_unlock_global_ft_cache) (_get_global_ft_cache): New global ft font cache. (_ft_font_cache_backend): New structure. (_cairo_ft_font_create): Rewrite to use cache. (_cairo_ft_font_destroy): Likewise. (_cairo_ft_font_copy): Remove. (_install_font_matrix): Rename as _install_font_scale. (_utf8_to_glyphs): Rename as _cairo_ft_font_text_to_glyphs. (_cairo_ft_font_text_to_glyphs): Use cache for metrics. (_cairo_ft_font_extents): Accept size, use scaled metrics. (_cairo_ft_font_glyph_extents) (_cairo_ft_font_glyph_bbox) (_cairo_ft_font_show_glyphs) (_cairo_ft_font_glyph_path): Modify to use size, cache. (_cairo_ft_font_text_extents) (_cairo_ft_font_text_bbox) (_cairo_ft_font_show_text) (_cairo_ft_font_text_path): Remove text-API code. (cairo_ft_font_create) (cairo_ft_font_create_for_ft_face) (cairo_ft_font_face) (cairo_ft_font_pattern): Rewrite using ft_font_val_t. Just reference font. (_cairo_gstate_fini): Finalize font matrix. (_cairo_gstate_default_matrix): Initialize font matrix. (_cairo_gstate_clip): Re-enable clipping rectangle. (_cairo_gstate_select_font) (_cairo_gstate_set_font): Set font matrix to identity. (_cairo_gstate_scale_font): Scale font matrix, not font. (_cairo_gstate_transform_font): Transform font matrix, not font. (_cairo_gstate_set_font_transform): Install as font matrix, not in font. (_build_font_scale): New helper function. (_cairo_gstate_text_to_glyphs): New function. (_cairo_gstate_current_font_extents) (_cairo_gstate_glyph_extents) (_cairo_gstate_show_glyphs) (_cairo_gstate_glyph_path): Rewrite using font matrix and size. (_cairo_gstate_text_path (_cairo_gstate_text_extents) (_cairo_gstate_show_text): Remove text-API code. Minor bug fix. (_cairo_xlib_surface_show_glyphs): New function. (_cairo_xlib_surface_backend): Add reference to new function. (glyphset_cache_t) (glyphset_cache_entry_t): New structure types. (_next_xlib_glyph): New helper function. (_xlib_glyphset_cache_create_value) (_xlib_glyphset_cache_destroy_cache) (_xlib_glyphset_cache_destroy_value) (_xlib_glyphset_cache_backend): New glyphset cache code. (_xlib_glyphset_caches) (_lock_xlib_glyphset_caches) (_unlock_xlib_glyphset_caches) (_get_glyphset_cache): New global glyphset cache. Add NULL entry for show_glyphs. Add NULL entry for show_glyphs. Add NULL entry for show_glyphs. Add NULL entry for show_glyphs. Add NULL entry for show_glyphs. New structure type. (cairo_cache_entry_base_t) (cairo_cache_arrangement_t) (cairo_cache_t): New structure types. (_cairo_cache_init) (_cairo_cache_reference) (_cairo_cache_destroy) (_cairo_cache_lookup) (_cairo_hash_string): New cache functions. (CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT) (CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT) (CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT) (CAIRO_FT_CACHE_NUM_FONTS_DEFAULT): New constants. (cairo_font_scale_t) (cairo_glyph_cache_key_t) (cairo_image_glyph_cache_entry_t): New structure types. (_cairo_lock_global_image_glyph_cache) (_cairo_unlock_global_image_glyph_cache) (_cairo_get_global_image_glyph_cache) (_cairo_glyph_cache_hash) (_cairo_glyph_cache_keys_equal): New functions for glyph caches. (cairo_font_backend_t): Remove text-API calls, add scale params, remove copy call. (cairo_surface_backend_t): Add show_glyphs entry. (cairo_glyph_surface_t) (cairo_glyph_surface_node_t): Remove old glyph cache structures. (cairo_unscaled_font_t): New structure type. (cairo_font): Remove glyph cache member, add pointer to unscaled. (cairo_gstate): Add font_matrix member, change to hold unscaled. (_cairo_gstate_set_font_transform) (_cairo_gstate_current_font_transform) (_cairo_gstate_text_to_glyphs): New functions. (_cairo_gstate_text_path (_cairo_gstate_text_extents) (_cairo_gstate_show_text) (_cairo_font_text_extents) (_cairo_font_text_bbox) (_cairo_font_show_text) (_cairo_font_text_path): Remove text-API code. (_cairo_font_glyph_extents) (_cairo_font_glyph_bbox) (_cairo_font_glyph_path) (_cairo_font_font_extents) (_cairo_font_show_glyphs): Add scale parameter.
This commit is contained in:
parent
56ccb88376
commit
30131aa463
24 changed files with 5593 additions and 2027 deletions
190
ChangeLog
190
ChangeLog
|
|
@ -1,3 +1,193 @@
|
|||
2004-10-07 Graydon Hoare <graydon@redhat.com>
|
||||
|
||||
* src/Makefile.am (libcairo_la_SOURCES): Add cairo_cache.c
|
||||
|
||||
* src/cairo.c
|
||||
(cairo_text_extents)
|
||||
(cairo_show_text)
|
||||
(cairo_text_path): Rewrite using temporary glyph arrays
|
||||
|
||||
* src/cairo_cache.c: New file.
|
||||
|
||||
* src/cairo_font.c (_cairo_glyph_cache_create)
|
||||
(_cairo_glyph_cache_destroy)
|
||||
(_cairo_glyph_cache_reference)
|
||||
(_cairo_glyph_cache_pop_last)
|
||||
(_cairo_glyph_surface_init)
|
||||
(_cairo_font_lookup_glyph): Remove old glyph cache code.
|
||||
(_cairo_font_scale)
|
||||
(_cairo_font_transform): Remove font-transforming code.
|
||||
(_cairo_font_text_extents)
|
||||
(_cairo_font_text_bbox)
|
||||
(_cairo_font_show_text)
|
||||
(_cairo_font_text_path): Remove text-API code.
|
||||
(_cairo_font_cache_key_t): New structure type.
|
||||
(_font_cache_hash)
|
||||
(_font_cache_keys_equal)
|
||||
(_font_cache_create_entry)
|
||||
(_font_cache_destroy_entry)
|
||||
(_font_cache_destroy_cache): New font cache code.
|
||||
(_global_font_cache)
|
||||
(_lock_global_font_cache)
|
||||
(_unlock_global_font_cache)
|
||||
(_get_global_font_cache): New global font cache.
|
||||
(_cairo_font_text_to_glyphs)
|
||||
(_cairo_glyph_cache_hash)
|
||||
(_cairo_glyph_cache_keys_equal)
|
||||
(_image_glyph_cache_create_entry)
|
||||
(_image_glyph_cache_destroy_entry)
|
||||
(_image_glyph_cache_destroy_cache): New glyph cache code.
|
||||
(_global_image_glyph_cache)
|
||||
(_cairo_lock_global_image_glyph_cache)
|
||||
(_cairo_unlock_global_image_glyph_cache)
|
||||
(_cairo_get_global_image_glyph_cache): New global glyph cache.
|
||||
(_cairo_font_cache_backend): New structure.
|
||||
(_cairo_image_cache_backend): Likewise.
|
||||
(_cairo_font_create): Reimplement in terms of font cache.
|
||||
(_cairo_font_init): Remove matrix and glyph cache related code.
|
||||
(_cairo_font_copy): Likewise.
|
||||
(_cairo_font_show_glyphs): Delegate to surface when possible.
|
||||
(_cairo_font_glyph_extents)
|
||||
(_cairo_font_glyph_bbox)
|
||||
(_cairo_font_glyph_path)
|
||||
(_cairo_font_font_extents)
|
||||
(_cairo_font_show_glyphs): Rename to as cairo_unscaled_font_XXX,
|
||||
and add scale parameter.
|
||||
|
||||
* src/cairo_ft_font.c
|
||||
(ft_cache_t)
|
||||
(ft_font_val_t)
|
||||
(cairo_ft_cache_key_t)
|
||||
(cairo_ft_cache_entry_t): New structure types.
|
||||
(_create_from_face)
|
||||
(_reference_font_val)
|
||||
(_destroy_font_val)
|
||||
(_create_from_library_and_pattern): New functions.
|
||||
(_ft_font_cache_hash)
|
||||
(_ft_font_cache_keys_equal)
|
||||
(_ft_font_cache_create_entry)
|
||||
(_ft_font_cache_destroy_entry)
|
||||
(_ft_font_cache_destroy_cache): New ft font cache code.
|
||||
(_global_ft_cache)
|
||||
(_lock_global_ft_cache)
|
||||
(_unlock_global_ft_cache)
|
||||
(_get_global_ft_cache): New global ft font cache.
|
||||
(_ft_font_cache_backend): New structure.
|
||||
(_cairo_ft_font_create): Rewrite to use cache.
|
||||
(_cairo_ft_font_destroy): Likewise.
|
||||
(_cairo_ft_font_copy): Remove.
|
||||
(_install_font_matrix): Rename as _install_font_scale.
|
||||
(_utf8_to_glyphs): Rename as _cairo_ft_font_text_to_glyphs.
|
||||
(_cairo_ft_font_text_to_glyphs): Use cache for metrics.
|
||||
(_cairo_ft_font_extents): Accept size, use scaled metrics.
|
||||
(_cairo_ft_font_glyph_extents)
|
||||
(_cairo_ft_font_glyph_bbox)
|
||||
(_cairo_ft_font_show_glyphs)
|
||||
(_cairo_ft_font_glyph_path): Modify to use size, cache.
|
||||
(_cairo_ft_font_text_extents)
|
||||
(_cairo_ft_font_text_bbox)
|
||||
(_cairo_ft_font_show_text)
|
||||
(_cairo_ft_font_text_path): Remove text-API code.
|
||||
(cairo_ft_font_create)
|
||||
(cairo_ft_font_create_for_ft_face)
|
||||
(cairo_ft_font_face)
|
||||
(cairo_ft_font_pattern): Rewrite using ft_font_val_t.
|
||||
|
||||
* src/cairo_gstate.c (cairo_gstate_init_copy): Just reference font.
|
||||
(_cairo_gstate_fini): Finalize font matrix.
|
||||
(_cairo_gstate_default_matrix): Initialize font matrix.
|
||||
(_cairo_gstate_clip): Re-enable clipping rectangle.
|
||||
(_cairo_gstate_select_font)
|
||||
(_cairo_gstate_set_font): Set font matrix to identity.
|
||||
(_cairo_gstate_scale_font): Scale font matrix, not font.
|
||||
(_cairo_gstate_transform_font): Transform font matrix, not font.
|
||||
(_cairo_gstate_set_font_transform): Install as font matrix, not in font.
|
||||
(_build_font_scale): New helper function.
|
||||
(_cairo_gstate_text_to_glyphs): New function.
|
||||
(_cairo_gstate_current_font_extents)
|
||||
(_cairo_gstate_glyph_extents)
|
||||
(_cairo_gstate_show_glyphs)
|
||||
(_cairo_gstate_glyph_path): Rewrite using font matrix and size.
|
||||
(_cairo_gstate_text_path
|
||||
(_cairo_gstate_text_extents)
|
||||
(_cairo_gstate_show_text): Remove text-API code.
|
||||
|
||||
* src/cairo_xlib_surface.c
|
||||
(_cairo_xlib_surface_set_clip_region): Minor bug fix.
|
||||
(_cairo_xlib_surface_show_glyphs): New function.
|
||||
(_cairo_xlib_surface_backend): Add reference to new function.
|
||||
(glyphset_cache_t)
|
||||
(glyphset_cache_entry_t): New structure types.
|
||||
(_next_xlib_glyph): New helper function.
|
||||
(_xlib_glyphset_cache_create_value)
|
||||
(_xlib_glyphset_cache_destroy_cache)
|
||||
(_xlib_glyphset_cache_destroy_value)
|
||||
(_xlib_glyphset_cache_backend): New glyphset cache code.
|
||||
(_xlib_glyphset_caches)
|
||||
(_lock_xlib_glyphset_caches)
|
||||
(_unlock_xlib_glyphset_caches)
|
||||
(_get_glyphset_cache): New global glyphset cache.
|
||||
|
||||
* src/cairo_glitz_surface.c (cairo_glitz_surface_backend):
|
||||
Add NULL entry for show_glyphs.
|
||||
|
||||
* src/cairo_image_surface.c (cairo_image_surface_backend):
|
||||
Add NULL entry for show_glyphs.
|
||||
|
||||
* src/cairo_ps_surface.c (cairo_ps_surface_backend):
|
||||
Add NULL entry for show_glyphs.
|
||||
|
||||
* src/cairo_png_surface.c (cairo_png_surface_backend):
|
||||
Add NULL entry for show_glyphs.
|
||||
|
||||
* src/cairo_xcb_surface.c (cairo_xcb_surface_backend):
|
||||
Add NULL entry for show_glyphs.
|
||||
|
||||
* src/cairoint.h (cairo_cache_backend_t): New structure type.
|
||||
(cairo_cache_entry_base_t)
|
||||
(cairo_cache_arrangement_t)
|
||||
(cairo_cache_t): New structure types.
|
||||
(_cairo_cache_init)
|
||||
(_cairo_cache_reference)
|
||||
(_cairo_cache_destroy)
|
||||
(_cairo_cache_lookup)
|
||||
(_cairo_hash_string): New cache functions.
|
||||
(CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT)
|
||||
(CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT)
|
||||
(CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT)
|
||||
(CAIRO_FT_CACHE_NUM_FONTS_DEFAULT): New constants.
|
||||
(cairo_font_scale_t)
|
||||
(cairo_glyph_cache_key_t)
|
||||
(cairo_image_glyph_cache_entry_t): New structure types.
|
||||
(_cairo_lock_global_image_glyph_cache)
|
||||
(_cairo_unlock_global_image_glyph_cache)
|
||||
(_cairo_get_global_image_glyph_cache)
|
||||
(_cairo_glyph_cache_hash)
|
||||
(_cairo_glyph_cache_keys_equal): New functions for glyph caches.
|
||||
(cairo_font_backend_t): Remove text-API calls, add scale params,
|
||||
remove copy call.
|
||||
(cairo_surface_backend_t): Add show_glyphs entry.
|
||||
(cairo_glyph_surface_t)
|
||||
(cairo_glyph_surface_node_t): Remove old glyph cache structures.
|
||||
(cairo_unscaled_font_t): New structure type.
|
||||
(cairo_font): Remove glyph cache member, add pointer to unscaled.
|
||||
(cairo_gstate): Add font_matrix member, change to hold unscaled.
|
||||
(_cairo_gstate_set_font_transform)
|
||||
(_cairo_gstate_current_font_transform)
|
||||
(_cairo_gstate_text_to_glyphs): New functions.
|
||||
(_cairo_gstate_text_path
|
||||
(_cairo_gstate_text_extents)
|
||||
(_cairo_gstate_show_text)
|
||||
(_cairo_font_text_extents)
|
||||
(_cairo_font_text_bbox)
|
||||
(_cairo_font_show_text)
|
||||
(_cairo_font_text_path): Remove text-API code.
|
||||
(_cairo_font_glyph_extents)
|
||||
(_cairo_font_glyph_bbox)
|
||||
(_cairo_font_glyph_path)
|
||||
(_cairo_font_font_extents)
|
||||
(_cairo_font_show_glyphs): Add scale parameter.
|
||||
|
||||
2004-10-04 David Reveman <c99drn@cs.umu.se>
|
||||
|
||||
* configure.in: Require version 0.2.3 of glitz.
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ XRENDER_LIBS=@XRENDER_LIBS@
|
|||
libcairo_la_SOURCES = \
|
||||
cairo.c \
|
||||
cairo.h \
|
||||
cairo_cache.c \
|
||||
cairo_color.c \
|
||||
cairo_fixed.c \
|
||||
cairo_font.c \
|
||||
|
|
|
|||
454
src/cairo-cache.c
Normal file
454
src/cairo-cache.c
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* This file is Copyright © 2004 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it either under the terms of the GNU Lesser General Public
|
||||
* License version 2.1 as published by the Free Software Foundation
|
||||
* (the "LGPL") or, at your option, under the terms of the Mozilla
|
||||
* Public License Version 1.1 (the "MPL"). If you do not alter this
|
||||
* notice, a recipient may use your version of this file under either
|
||||
* the MPL or the LGPL.
|
||||
*
|
||||
* You should have received a copy of the LGPL along with this library
|
||||
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* You should have received a copy of the MPL along with this library
|
||||
* in the file COPYING-MPL-1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
||||
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
||||
* the specific language governing rights and limitations.
|
||||
*
|
||||
* The Original Code is the cairo graphics library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Red Hat, Inc.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Keith Packard
|
||||
* Graydon Hoare <graydon@redhat.com>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
/*
|
||||
* This structure, and accompanying table, is borrowed/modified from the
|
||||
* file xserver/render/glyph.c in the freedesktop.org x server, with
|
||||
* permission (and suggested modification of doubling sizes) by Keith
|
||||
* Packard.
|
||||
*/
|
||||
|
||||
static cairo_cache_arrangement_t cache_arrangements [] = {
|
||||
{ 16, 43, 41 },
|
||||
{ 32, 73, 71 },
|
||||
{ 64, 151, 149 },
|
||||
{ 128, 283, 281 },
|
||||
{ 256, 571, 569 },
|
||||
{ 512, 1153, 1151 },
|
||||
{ 1024, 2269, 2267 },
|
||||
{ 2048, 4519, 4517 },
|
||||
{ 4096, 9013, 9011 },
|
||||
{ 8192, 18043, 18041 },
|
||||
{ 16384, 36109, 36107 },
|
||||
{ 32768, 72091, 72089 },
|
||||
{ 65536, 144409, 144407 },
|
||||
{ 131072, 288361, 288359 },
|
||||
{ 262144, 576883, 576881 },
|
||||
{ 524288, 1153459, 1153457 },
|
||||
{ 1048576, 2307163, 2307161 },
|
||||
{ 2097152, 4613893, 4613891 },
|
||||
{ 4194304, 9227641, 9227639 },
|
||||
{ 8388608, 18455029, 18455027 },
|
||||
{ 16777216, 36911011, 36911009 },
|
||||
{ 33554432, 73819861, 73819859 },
|
||||
{ 67108864, 147639589, 147639587 },
|
||||
{ 134217728, 295279081, 295279079 },
|
||||
{ 268435456, 590559793, 590559791 }
|
||||
};
|
||||
|
||||
#define N_CACHE_SIZES (sizeof(cache_arrangements)/sizeof(cache_arrangements[0]))
|
||||
|
||||
/*
|
||||
* Entries 'e' are poiners, in one of 3 states:
|
||||
*
|
||||
* e == NULL: The entry has never had anything put in it
|
||||
* e != DEAD_ENTRY: The entry has an active value in it currently
|
||||
* e == DEAD_ENTRY: The entry *had* a value in it at some point, but the
|
||||
* entry has been killed. Lookups requesting free space can
|
||||
* reuse these entries; lookups requesting a precise match
|
||||
* should neither return these entries nor stop searching when
|
||||
* seeing these entries.
|
||||
*
|
||||
* We expect keys will not be destroyed frequently, so our table does not
|
||||
* contain any explicit shrinking code nor any chain-coalescing code for
|
||||
* entries randomly deleted by memory pressure (except during rehashing, of
|
||||
* course). These assumptions are potentially bad, but they make the
|
||||
* implementation straightforward.
|
||||
*
|
||||
* Revisit later if evidence appears that we're using excessive memory from
|
||||
* a mostly-dead table.
|
||||
*
|
||||
* Generally you do not need to worry about freeing cache entries; the
|
||||
* cache will expire entries randomly as it experiences memory pressure.
|
||||
* There is currently no explicit entry-removing call, though one can be
|
||||
* added easily.
|
||||
*
|
||||
* This table is open-addressed with double hashing. Each table size is a
|
||||
* prime chosen to be a little more than double the high water mark for a
|
||||
* given arrangement, so the tables should remain < 50% full. The table
|
||||
* size makes for the "first" hash modulus; a second prime (2 less than the
|
||||
* first prime) serves as the "second" hash modulus, which is co-prime and
|
||||
* thus guarantees a complete permutation of table indices.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DEAD_ENTRY ((cairo_cache_entry_base_t *) 1)
|
||||
#define NULL_ENTRY_P(cache, i) ((cache)->entries[i] == NULL)
|
||||
#define DEAD_ENTRY_P(cache, i) ((cache)->entries[i] == DEAD_ENTRY)
|
||||
#define LIVE_ENTRY_P(cache, i) \
|
||||
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
|
||||
|
||||
#ifdef CAIRO_DO_SANITY_CHECKING
|
||||
#include <assert.h>
|
||||
static void
|
||||
_cache_sane_state (cairo_cache_t *cache)
|
||||
{
|
||||
assert (cache != NULL);
|
||||
assert (cache->entries != NULL);
|
||||
assert (cache->backend != NULL);
|
||||
assert (cache->arrangement != NULL);
|
||||
assert (cache->refcount > 0);
|
||||
assert (cache->used_memory <= cache->max_memory);
|
||||
assert (cache->live_entries <= cache->arrangement->size);
|
||||
}
|
||||
#else
|
||||
#define _cache_sane_state(c)
|
||||
#define assert(x)
|
||||
#endif
|
||||
|
||||
static void
|
||||
_entry_destroy (cairo_cache_t *cache, unsigned long i)
|
||||
{
|
||||
_cache_sane_state (cache);
|
||||
|
||||
if (LIVE_ENTRY_P(cache, i))
|
||||
{
|
||||
cairo_cache_entry_base_t *entry = cache->entries[i];
|
||||
assert(cache->live_entries > 0);
|
||||
assert(cache->used_memory > entry->memory);
|
||||
|
||||
cache->live_entries--;
|
||||
cache->used_memory -= entry->memory;
|
||||
cache->backend->destroy_entry (cache, entry);
|
||||
cache->entries[i] = DEAD_ENTRY;
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_cache_entry_base_t **
|
||||
_cache_lookup (cairo_cache_t *cache,
|
||||
void *key,
|
||||
int (*predicate)(void*,void*,void*))
|
||||
{
|
||||
|
||||
cairo_cache_entry_base_t **probe;
|
||||
unsigned long hash;
|
||||
unsigned long table_size, i, idx, step;
|
||||
|
||||
_cache_sane_state (cache);
|
||||
assert (key != NULL);
|
||||
|
||||
table_size = cache->arrangement->size;
|
||||
hash = cache->backend->hash (cache, key);
|
||||
idx = hash % table_size;
|
||||
step = 0;
|
||||
|
||||
for (i = 0; i < table_size; ++i)
|
||||
{
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->probes++;
|
||||
#endif
|
||||
assert(idx < table_size);
|
||||
probe = cache->entries + idx;
|
||||
|
||||
/*
|
||||
* There are two lookup modes: searching for a free slot and searching
|
||||
* for an exact entry.
|
||||
*/
|
||||
|
||||
if (predicate != NULL)
|
||||
{
|
||||
/* We are looking up an exact entry. */
|
||||
if (*probe != NULL
|
||||
&& *probe != DEAD_ENTRY
|
||||
&& (*probe)->hashcode == hash
|
||||
&& predicate (cache, key, *probe))
|
||||
return probe;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We are just looking for a free slot. */
|
||||
if (*probe == NULL
|
||||
|| *probe == DEAD_ENTRY)
|
||||
return probe;
|
||||
}
|
||||
|
||||
if (step == 0) {
|
||||
step = hash % cache->arrangement->rehash;
|
||||
if (step == 0)
|
||||
step = 1;
|
||||
}
|
||||
|
||||
idx += step;
|
||||
if (idx >= table_size)
|
||||
idx -= table_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* The table should not have permitted you to get here if you were just
|
||||
* looking for a free slot: there should have been room.
|
||||
*/
|
||||
assert(predicate != NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static cairo_cache_entry_base_t **
|
||||
_find_available_entry_for (cairo_cache_t *cache,
|
||||
void *key)
|
||||
{
|
||||
return _cache_lookup (cache, key, NULL);
|
||||
}
|
||||
|
||||
static cairo_cache_entry_base_t **
|
||||
_find_exact_live_entry_for (cairo_cache_t *cache,
|
||||
void *key)
|
||||
{
|
||||
return _cache_lookup (cache, key, cache->backend->keys_equal);
|
||||
}
|
||||
|
||||
|
||||
static cairo_cache_arrangement_t *
|
||||
_find_cache_arrangement (unsigned long proposed_size)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
for (idx = 0; idx < N_CACHE_SIZES; ++idx)
|
||||
if (cache_arrangements[idx].high_water_mark >= proposed_size)
|
||||
return &cache_arrangements[idx];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_resize_cache (cairo_cache_t *cache, unsigned long proposed_size)
|
||||
{
|
||||
cairo_cache_t tmp;
|
||||
cairo_cache_entry_base_t **e;
|
||||
unsigned long new_size, i;
|
||||
|
||||
tmp = *cache;
|
||||
tmp.arrangement = _find_cache_arrangement (proposed_size);
|
||||
assert(tmp.arrangement != NULL);
|
||||
if (tmp.arrangement == cache->arrangement)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
new_size = tmp.arrangement->size;
|
||||
tmp.entries = calloc (new_size, sizeof (cairo_cache_entry_base_t *));
|
||||
if (tmp.entries == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
for (i = 0; i < cache->arrangement->size; ++i) {
|
||||
if (LIVE_ENTRY_P(cache, i)) {
|
||||
e = _find_available_entry_for (&tmp, cache->entries[i]);
|
||||
assert (e != NULL);
|
||||
*e = cache->entries[i];
|
||||
}
|
||||
}
|
||||
free (cache->entries);
|
||||
cache->entries = tmp.entries;
|
||||
cache->arrangement = tmp.arrangement;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
static double
|
||||
_load_factor (cairo_cache_t *cache)
|
||||
{
|
||||
return ((double) cache->live_entries)
|
||||
/ ((double) cache->arrangement->size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned long
|
||||
_random_live_entry (cairo_cache_t *cache)
|
||||
{
|
||||
unsigned long idx;
|
||||
assert(cache != NULL);
|
||||
do {
|
||||
idx = rand () % cache->arrangement->size;
|
||||
} while (! LIVE_ENTRY_P(cache, idx));
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
/* public API follows */
|
||||
|
||||
cairo_status_t
|
||||
_cairo_cache_init (cairo_cache_t *cache,
|
||||
const cairo_cache_backend_t *backend,
|
||||
unsigned long max_memory)
|
||||
{
|
||||
assert(backend != NULL);
|
||||
|
||||
if (cache != NULL){
|
||||
cache->arrangement = &cache_arrangements[0];
|
||||
cache->refcount = 1;
|
||||
cache->max_memory = max_memory;
|
||||
cache->used_memory = 0;
|
||||
cache->live_entries = 0;
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->hits = 0;
|
||||
cache->misses = 0;
|
||||
cache->probes = 0;
|
||||
#endif
|
||||
|
||||
cache->backend = backend;
|
||||
cache->entries = calloc (sizeof(cairo_cache_entry_base_t *),
|
||||
cache->arrangement->size);
|
||||
if (cache->entries == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
_cache_sane_state (cache);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_cache_reference (cairo_cache_t *cache)
|
||||
{
|
||||
_cache_sane_state (cache);
|
||||
cache->refcount++;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_cache_destroy (cairo_cache_t *cache)
|
||||
{
|
||||
unsigned long i;
|
||||
if (cache != NULL) {
|
||||
|
||||
_cache_sane_state (cache);
|
||||
|
||||
if (cache->refcount-- > 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < cache->arrangement->size; ++i) {
|
||||
_entry_destroy (cache, i);
|
||||
}
|
||||
|
||||
free (cache->entries);
|
||||
cache->entries = NULL;
|
||||
cache->backend->destroy_cache (cache);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_cache_lookup (cairo_cache_t *cache,
|
||||
void *key,
|
||||
void **entry_return)
|
||||
{
|
||||
|
||||
unsigned long idx;
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_cache_entry_base_t **slot = NULL, *new_entry;
|
||||
|
||||
_cache_sane_state (cache);
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
if ((cache->hits + cache->misses) % 0xffff == 0)
|
||||
printf("cache %p stats: size %ld, live %ld, load %.2f\n"
|
||||
" mem %ld/%ld, hit %ld, miss %ld\n"
|
||||
" probe %ld, %.2f probe/access\n",
|
||||
cache,
|
||||
cache->arrangement->size,
|
||||
cache->live_entries,
|
||||
_load_factor (cache),
|
||||
cache->used_memory,
|
||||
cache->max_memory,
|
||||
cache->hits,
|
||||
cache->misses,
|
||||
cache->probes,
|
||||
((double) cache->probes)
|
||||
/ ((double) (cache->hits +
|
||||
cache->misses + 1)));
|
||||
#endif
|
||||
|
||||
/* See if we have an entry in the table already. */
|
||||
slot = _find_exact_live_entry_for (cache, key);
|
||||
if (slot != NULL) {
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->hits++;
|
||||
#endif
|
||||
*entry_return = *slot;
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->misses++;
|
||||
#endif
|
||||
|
||||
/* Build the new entry. */
|
||||
status = cache->backend->create_entry (cache, key,
|
||||
entry_return);
|
||||
if (status != CAIRO_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
new_entry = (cairo_cache_entry_base_t *) (*entry_return);
|
||||
|
||||
/* Store the hash value in case the backend forgot. */
|
||||
new_entry->hashcode = cache->backend->hash (cache, key);
|
||||
|
||||
/* Make some entries die if we're under memory pressure. */
|
||||
while (cache->live_entries > 0 &&
|
||||
((cache->max_memory - cache->used_memory) < new_entry->memory)) {
|
||||
idx = _random_live_entry (cache);
|
||||
assert (idx < cache->arrangement->size);
|
||||
_entry_destroy (cache, idx);
|
||||
}
|
||||
|
||||
assert(cache->max_memory >= (cache->used_memory + new_entry->memory));
|
||||
|
||||
/* Make room in the table for a new slot. */
|
||||
status = _resize_cache (cache, cache->live_entries + 1);
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
cache->backend->destroy_entry (cache, new_entry);
|
||||
*entry_return = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
slot = _find_available_entry_for (cache, key);
|
||||
assert(slot != NULL);
|
||||
|
||||
/* Store entry in slot and increment statistics. */
|
||||
*slot = new_entry;
|
||||
cache->live_entries++;
|
||||
cache->used_memory += new_entry->memory;
|
||||
|
||||
_cache_sane_state (cache);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
_cairo_hash_string (const char *c)
|
||||
{
|
||||
/* This is the djb2 hash. */
|
||||
unsigned long hash = 5381;
|
||||
while (*c)
|
||||
hash = ((hash << 5) + hash) + *c++;
|
||||
return hash;
|
||||
}
|
||||
|
||||
731
src/cairo-font.c
731
src/cairo-font.c
|
|
@ -36,20 +36,60 @@
|
|||
|
||||
#include "cairoint.h"
|
||||
|
||||
static cairo_glyph_cache_t *
|
||||
_cairo_glyph_cache_create (void);
|
||||
|
||||
static void
|
||||
_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache);
|
||||
/* First we implement a global font cache for named fonts. */
|
||||
|
||||
static void
|
||||
_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache);
|
||||
typedef struct {
|
||||
cairo_cache_entry_base_t base;
|
||||
const char *family;
|
||||
cairo_font_slant_t slant;
|
||||
cairo_font_weight_t weight;
|
||||
} cairo_font_cache_key_t;
|
||||
|
||||
cairo_font_t *
|
||||
_cairo_font_create (const char *family,
|
||||
cairo_font_slant_t slant,
|
||||
cairo_font_weight_t weight)
|
||||
typedef struct {
|
||||
cairo_font_cache_key_t key;
|
||||
cairo_unscaled_font_t *unscaled;
|
||||
} cairo_font_cache_entry_t;
|
||||
|
||||
static unsigned long
|
||||
_font_cache_hash (void *cache, void *key)
|
||||
{
|
||||
cairo_font_cache_key_t *in;
|
||||
in = (cairo_font_cache_key_t *) key;
|
||||
unsigned long hash;
|
||||
|
||||
/* 1607 and 1451 are just a couple random primes. */
|
||||
hash = _cairo_hash_string (in->family);
|
||||
hash += ((unsigned long) in->slant) * 1607;
|
||||
hash += ((unsigned long) in->weight) * 1451;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_font_cache_keys_equal (void *cache,
|
||||
void *k1,
|
||||
void *k2)
|
||||
{
|
||||
cairo_font_cache_key_t *a, *b;
|
||||
a = (cairo_font_cache_key_t *) k1;
|
||||
b = (cairo_font_cache_key_t *) k2;
|
||||
|
||||
return (strcmp (a->family, b->family) == 0)
|
||||
&& (a->weight == b->weight)
|
||||
&& (a->slant == b->slant);
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_font_cache_create_entry (void *cache,
|
||||
void *key,
|
||||
void **return_value)
|
||||
{
|
||||
cairo_font_cache_key_t *k;
|
||||
cairo_font_cache_entry_t *entry;
|
||||
k = (cairo_font_cache_key_t *) key;
|
||||
|
||||
const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT;
|
||||
|
||||
/* XXX: The current freetype backend may return NULL, (for example
|
||||
|
|
@ -58,336 +98,250 @@ _cairo_font_create (const char *family,
|
|||
* like to build in some sort fo font here, (even a really lame,
|
||||
* ugly one if necessary). */
|
||||
|
||||
return backend->create (family, slant, weight);
|
||||
entry = malloc (sizeof (cairo_font_cache_entry_t));
|
||||
if (entry == NULL)
|
||||
goto FAIL;
|
||||
|
||||
entry->key.slant = k->slant;
|
||||
entry->key.weight = k->weight;
|
||||
entry->key.family = strdup(k->family);
|
||||
if (entry->key.family == NULL)
|
||||
goto FREE_ENTRY;
|
||||
|
||||
entry->unscaled = backend->create (k->family, k->slant, k->weight);
|
||||
if (entry->unscaled == NULL)
|
||||
goto FREE_FAMILY;
|
||||
|
||||
/* Not sure how to measure backend font mem; use a simple count for now.*/
|
||||
entry->key.base.memory = 1;
|
||||
*return_value = entry;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
FREE_FAMILY:
|
||||
free ((void *) entry->key.family);
|
||||
|
||||
FREE_ENTRY:
|
||||
free (entry);
|
||||
|
||||
FAIL:
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
static void
|
||||
_font_cache_destroy_entry (void *cache,
|
||||
void *entry)
|
||||
{
|
||||
cairo_font_cache_entry_t *e;
|
||||
|
||||
e = (cairo_font_cache_entry_t *) entry;
|
||||
_cairo_unscaled_font_destroy (e->unscaled);
|
||||
free ((void *) e->key.family);
|
||||
free (e);
|
||||
}
|
||||
|
||||
static void
|
||||
_font_cache_destroy_cache (void *cache)
|
||||
{
|
||||
free (cache);
|
||||
}
|
||||
|
||||
const struct cairo_cache_backend cairo_font_cache_backend = {
|
||||
_font_cache_hash,
|
||||
_font_cache_keys_equal,
|
||||
_font_cache_create_entry,
|
||||
_font_cache_destroy_entry,
|
||||
_font_cache_destroy_cache
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
_lock_global_font_cache (void)
|
||||
{
|
||||
/* FIXME: implement locking. */
|
||||
}
|
||||
|
||||
static void
|
||||
_unlock_global_font_cache (void)
|
||||
{
|
||||
/* FIXME: implement locking. */
|
||||
}
|
||||
|
||||
static cairo_cache_t *
|
||||
_global_font_cache = NULL;
|
||||
|
||||
static cairo_cache_t *
|
||||
_get_global_font_cache (void)
|
||||
{
|
||||
if (_global_font_cache == NULL) {
|
||||
_global_font_cache = malloc (sizeof (cairo_cache_t));
|
||||
|
||||
if (_global_font_cache == NULL)
|
||||
goto FAIL;
|
||||
|
||||
if (_cairo_cache_init (_global_font_cache,
|
||||
&cairo_font_cache_backend,
|
||||
CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT))
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
return _global_font_cache;
|
||||
|
||||
FAIL:
|
||||
if (_global_font_cache)
|
||||
free (_global_font_cache);
|
||||
_global_font_cache = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Now the internal "unscaled + scale" font API */
|
||||
|
||||
cairo_unscaled_font_t *
|
||||
_cairo_unscaled_font_create (const char *family,
|
||||
cairo_font_slant_t slant,
|
||||
cairo_font_weight_t weight)
|
||||
{
|
||||
cairo_cache_t * cache;
|
||||
cairo_font_cache_key_t key;
|
||||
cairo_font_cache_entry_t *font;
|
||||
cairo_status_t status;
|
||||
|
||||
_lock_global_font_cache ();
|
||||
cache = _get_global_font_cache ();
|
||||
if (cache == NULL) {
|
||||
_unlock_global_font_cache ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key.family = family;
|
||||
key.slant = slant;
|
||||
key.weight = weight;
|
||||
|
||||
status = _cairo_cache_lookup (cache, &key, (void **) &font);
|
||||
if (status) {
|
||||
_unlock_global_font_cache ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_cairo_unscaled_font_reference (font->unscaled);
|
||||
_unlock_global_font_cache ();
|
||||
return font->unscaled;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_font_init (cairo_font_t *scaled,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_unscaled_font_t *unscaled)
|
||||
{
|
||||
scaled->scale = *scale;
|
||||
scaled->unscaled = unscaled;
|
||||
scaled->refcount = 1;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_init (cairo_font_t *font,
|
||||
const struct cairo_font_backend *backend)
|
||||
_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
|
||||
const struct cairo_font_backend *backend)
|
||||
{
|
||||
cairo_matrix_set_identity (&font->matrix);
|
||||
font->refcount = 1;
|
||||
font->backend = backend;
|
||||
font->glyph_cache = _cairo_glyph_cache_create ();
|
||||
if (font->glyph_cache == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_font_t *
|
||||
_cairo_font_copy (cairo_font_t *font)
|
||||
{
|
||||
cairo_font_t *newfont = NULL;
|
||||
char *tmp = NULL;
|
||||
|
||||
if (font == NULL || font->backend->copy == NULL)
|
||||
return NULL;
|
||||
|
||||
newfont = font->backend->copy (font);
|
||||
if (newfont == NULL) {
|
||||
free (tmp);
|
||||
return NULL;
|
||||
cairo_status_t
|
||||
_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
const unsigned char *utf8,
|
||||
cairo_glyph_t **glyphs,
|
||||
int *num_glyphs)
|
||||
{
|
||||
return font->backend->text_to_glyphs (font, scale, utf8, glyphs, num_glyphs);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_text_extents_t *extents)
|
||||
{
|
||||
return font->backend->glyph_extents(font, scale, glyphs, num_glyphs, extents);
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_box_t *bbox)
|
||||
{
|
||||
return font->backend->glyph_bbox (font, scale, glyphs, num_glyphs, bbox);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs)
|
||||
{
|
||||
cairo_status_t status;
|
||||
if (surface->backend->show_glyphs != NULL) {
|
||||
status = surface->backend->show_glyphs (font, scale, operator, source,
|
||||
surface, source_x, source_y,
|
||||
glyphs, num_glyphs);
|
||||
if (status == CAIRO_STATUS_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
newfont->refcount = 1;
|
||||
cairo_matrix_copy(&newfont->matrix, &font->matrix);
|
||||
newfont->backend = font->backend;
|
||||
|
||||
if (newfont->glyph_cache)
|
||||
_cairo_glyph_cache_destroy (newfont->glyph_cache);
|
||||
|
||||
newfont->glyph_cache = font->glyph_cache;
|
||||
_cairo_glyph_cache_reference (font->glyph_cache);
|
||||
|
||||
return newfont;
|
||||
/* Surface display routine either does not exist or failed. */
|
||||
return font->backend->show_glyphs (font, scale, operator, source,
|
||||
surface, source_x, source_y,
|
||||
glyphs, num_glyphs);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_scale (cairo_font_t *font, double scale)
|
||||
_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_path_t *path)
|
||||
{
|
||||
return cairo_matrix_scale (&font->matrix, scale, scale);
|
||||
return font->backend->glyph_path (font, scale, glyphs, num_glyphs, path);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_transform (cairo_font_t *font, cairo_matrix_t *matrix)
|
||||
_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_font_extents_t *extents)
|
||||
{
|
||||
return cairo_matrix_multiply (&font->matrix, matrix, &font->matrix);
|
||||
return font->backend->font_extents(font, scale, extents);
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_text_extents (cairo_font_t *font,
|
||||
const unsigned char *utf8,
|
||||
cairo_text_extents_t *extents)
|
||||
void
|
||||
_cairo_unscaled_font_reference (cairo_unscaled_font_t *font)
|
||||
{
|
||||
return font->backend->text_extents(font, utf8, extents);
|
||||
font->refcount++;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_glyph_extents (cairo_font_t *font,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_text_extents_t *extents)
|
||||
{
|
||||
return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_text_bbox (cairo_font_t *font,
|
||||
cairo_surface_t *surface,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8,
|
||||
cairo_box_t *bbox)
|
||||
{
|
||||
return font->backend->text_bbox (font, surface, x, y, utf8, bbox);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_glyph_bbox (cairo_font_t *font,
|
||||
cairo_surface_t *surface,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_box_t *bbox)
|
||||
{
|
||||
return font->backend->glyph_bbox (font, surface, glyphs, num_glyphs, bbox);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_show_text (cairo_font_t *font,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8)
|
||||
{
|
||||
return font->backend->show_text(font, operator, source,
|
||||
surface, source_x, source_y, x, y, utf8);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_show_glyphs (cairo_font_t *font,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs)
|
||||
{
|
||||
return font->backend->show_glyphs(font, operator, source,
|
||||
surface, source_x, source_y,
|
||||
glyphs, num_glyphs);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_text_path (cairo_font_t *font,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8,
|
||||
cairo_path_t *path)
|
||||
{
|
||||
return font->backend->text_path(font, x, y, utf8, path);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_glyph_path (cairo_font_t *font,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_path_t *path)
|
||||
{
|
||||
return font->backend->glyph_path(font, glyphs, num_glyphs, path);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_font_extents (cairo_font_t *font,
|
||||
cairo_font_extents_t *extents)
|
||||
{
|
||||
return font->backend->font_extents(font, extents);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_glyph_cache_pop_last (cairo_glyph_cache_t *glyph_cache)
|
||||
{
|
||||
if (glyph_cache->last) {
|
||||
cairo_glyph_surface_node_t *remove = glyph_cache->last;
|
||||
|
||||
cairo_surface_destroy (remove->s.surface);
|
||||
glyph_cache->last = remove->prev;
|
||||
if (glyph_cache->last)
|
||||
glyph_cache->last->next = NULL;
|
||||
|
||||
free (remove);
|
||||
glyph_cache->n_nodes--;
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_glyph_cache_t *
|
||||
_cairo_glyph_cache_create (void)
|
||||
{
|
||||
cairo_glyph_cache_t *glyph_cache;
|
||||
|
||||
glyph_cache = malloc (sizeof (cairo_glyph_cache_t));
|
||||
if (glyph_cache == NULL)
|
||||
return NULL;
|
||||
|
||||
glyph_cache->n_nodes = 0;
|
||||
glyph_cache->first = NULL;
|
||||
glyph_cache->last = NULL;
|
||||
glyph_cache->cache_size = CAIRO_FONT_CACHE_SIZE_DEFAULT;
|
||||
glyph_cache->ref_count = 1;
|
||||
|
||||
return glyph_cache;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache)
|
||||
{
|
||||
if (glyph_cache == NULL)
|
||||
void
|
||||
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font)
|
||||
{
|
||||
if (--(font->refcount) > 0)
|
||||
return;
|
||||
|
||||
glyph_cache->ref_count++;
|
||||
if (font->backend)
|
||||
font->backend->destroy (font);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache)
|
||||
{
|
||||
if (glyph_cache == NULL)
|
||||
return;
|
||||
|
||||
glyph_cache->ref_count--;
|
||||
if (glyph_cache->ref_count)
|
||||
return;
|
||||
|
||||
while (glyph_cache->last)
|
||||
_cairo_glyph_cache_pop_last (glyph_cache);
|
||||
|
||||
free (glyph_cache);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_glyph_surface_init (cairo_font_t *font,
|
||||
cairo_surface_t *surface,
|
||||
const cairo_glyph_t *glyph,
|
||||
cairo_glyph_surface_t *glyph_surface)
|
||||
{
|
||||
cairo_surface_t *image;
|
||||
|
||||
glyph_surface->surface = NULL;
|
||||
glyph_surface->index = glyph->index;
|
||||
glyph_surface->matrix[0][0] = font->matrix.m[0][0];
|
||||
glyph_surface->matrix[0][1] = font->matrix.m[0][1];
|
||||
glyph_surface->matrix[1][0] = font->matrix.m[1][0];
|
||||
glyph_surface->matrix[1][1] = font->matrix.m[1][1];
|
||||
|
||||
image = font->backend->create_glyph (font, glyph, &glyph_surface->size);
|
||||
if (image == NULL)
|
||||
return;
|
||||
|
||||
if (surface->backend != image->backend) {
|
||||
cairo_status_t status;
|
||||
|
||||
glyph_surface->surface =
|
||||
_cairo_surface_create_similar_scratch (surface,
|
||||
CAIRO_FORMAT_A8, 0,
|
||||
glyph_surface->size.width,
|
||||
glyph_surface->size.height);
|
||||
if (glyph_surface->surface == NULL) {
|
||||
glyph_surface->surface = image;
|
||||
return;
|
||||
}
|
||||
|
||||
status = _cairo_surface_set_image (glyph_surface->surface,
|
||||
(cairo_image_surface_t *) image);
|
||||
if (status) {
|
||||
cairo_surface_destroy (glyph_surface->surface);
|
||||
glyph_surface->surface = NULL;
|
||||
}
|
||||
cairo_surface_destroy (image);
|
||||
} else
|
||||
glyph_surface->surface = image;
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
_cairo_font_lookup_glyph (cairo_font_t *font,
|
||||
cairo_surface_t *surface,
|
||||
const cairo_glyph_t *glyph,
|
||||
cairo_glyph_size_t *return_size)
|
||||
{
|
||||
cairo_glyph_surface_t glyph_surface;
|
||||
cairo_glyph_cache_t *cache = font->glyph_cache;
|
||||
cairo_glyph_surface_node_t *node;
|
||||
|
||||
for (node = cache->first; node != NULL; node = node->next) {
|
||||
cairo_glyph_surface_t *s = &node->s;
|
||||
|
||||
if ((s->surface == NULL || s->surface->backend == surface->backend) &&
|
||||
s->index == glyph->index &&
|
||||
s->matrix[0][0] == font->matrix.m[0][0] &&
|
||||
s->matrix[0][1] == font->matrix.m[0][1] &&
|
||||
s->matrix[1][0] == font->matrix.m[1][0] &&
|
||||
s->matrix[1][1] == font->matrix.m[1][1]) {
|
||||
|
||||
/* move node first in cache */
|
||||
if (node->prev) {
|
||||
if (node->next == NULL) {
|
||||
cache->last = node->prev;
|
||||
node->prev->next = NULL;
|
||||
} else {
|
||||
node->prev->next = node->next;
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
|
||||
node->prev = NULL;
|
||||
node->next = cache->first;
|
||||
cache->first = node;
|
||||
if (node->next)
|
||||
node->next->prev = node;
|
||||
else
|
||||
cache->last = node;
|
||||
}
|
||||
|
||||
cairo_surface_reference (s->surface);
|
||||
*return_size = s->size;
|
||||
|
||||
return s->surface;
|
||||
}
|
||||
}
|
||||
|
||||
_cairo_glyph_surface_init (font, surface, glyph, &glyph_surface);
|
||||
|
||||
*return_size = glyph_surface.size;
|
||||
|
||||
if (cache->cache_size > 0) {
|
||||
if (cache->n_nodes == cache->cache_size)
|
||||
_cairo_glyph_cache_pop_last (cache);
|
||||
|
||||
node = malloc (sizeof (cairo_glyph_surface_node_t));
|
||||
if (node) {
|
||||
cairo_surface_reference (glyph_surface.surface);
|
||||
|
||||
/* insert node first in cache */
|
||||
node->s = glyph_surface;
|
||||
node->prev = NULL;
|
||||
node->next = cache->first;
|
||||
cache->first = node;
|
||||
if (node->next)
|
||||
node->next->prev = node;
|
||||
else
|
||||
cache->last = node;
|
||||
|
||||
cache->n_nodes++;
|
||||
}
|
||||
}
|
||||
|
||||
return glyph_surface.surface;
|
||||
}
|
||||
|
||||
/* public font interface follows */
|
||||
/* Public font API follows. */
|
||||
|
||||
void
|
||||
cairo_font_reference (cairo_font_t *font)
|
||||
|
|
@ -401,22 +355,171 @@ cairo_font_destroy (cairo_font_t *font)
|
|||
if (--(font->refcount) > 0)
|
||||
return;
|
||||
|
||||
_cairo_glyph_cache_destroy (font->glyph_cache);
|
||||
if (font->unscaled)
|
||||
_cairo_unscaled_font_destroy (font->unscaled);
|
||||
|
||||
if (font->backend->destroy)
|
||||
font->backend->destroy (font);
|
||||
free (font);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_font_set_transform (cairo_font_t *font,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_matrix_copy (&(font->matrix), matrix);
|
||||
double dummy;
|
||||
cairo_matrix_get_affine (matrix,
|
||||
&font->scale.matrix[0][0],
|
||||
&font->scale.matrix[0][1],
|
||||
&font->scale.matrix[1][0],
|
||||
&font->scale.matrix[1][1],
|
||||
&dummy, &dummy);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_font_current_transform (cairo_font_t *font,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_matrix_copy (matrix, &(font->matrix));
|
||||
cairo_matrix_set_affine (matrix,
|
||||
font->scale.matrix[0][0],
|
||||
font->scale.matrix[0][1],
|
||||
font->scale.matrix[1][0],
|
||||
font->scale.matrix[1][1],
|
||||
0, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Now we implement functions to access a default global image & metrics
|
||||
* cache.
|
||||
*/
|
||||
|
||||
unsigned long
|
||||
_cairo_glyph_cache_hash (void *cache, void *key)
|
||||
{
|
||||
cairo_glyph_cache_key_t *in;
|
||||
in = (cairo_glyph_cache_key_t *) key;
|
||||
return
|
||||
((unsigned long) in->unscaled)
|
||||
^ ((unsigned long) in->scale.matrix[0][0])
|
||||
^ ((unsigned long) in->scale.matrix[0][1])
|
||||
^ ((unsigned long) in->scale.matrix[1][0])
|
||||
^ ((unsigned long) in->scale.matrix[1][1])
|
||||
^ in->index;
|
||||
}
|
||||
|
||||
int
|
||||
_cairo_glyph_cache_keys_equal (void *cache,
|
||||
void *k1,
|
||||
void *k2)
|
||||
{
|
||||
cairo_glyph_cache_key_t *a, *b;
|
||||
a = (cairo_glyph_cache_key_t *) k1;
|
||||
b = (cairo_glyph_cache_key_t *) k2;
|
||||
return (a->index == b->index)
|
||||
&& (a->unscaled == b->unscaled)
|
||||
&& (a->scale.matrix[0][0] == b->scale.matrix[0][0])
|
||||
&& (a->scale.matrix[0][1] == b->scale.matrix[0][1])
|
||||
&& (a->scale.matrix[1][0] == b->scale.matrix[1][0])
|
||||
&& (a->scale.matrix[1][1] == b->scale.matrix[1][1]);
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_image_glyph_cache_create_entry (void *cache,
|
||||
void *key,
|
||||
void **return_value)
|
||||
{
|
||||
cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *) key;
|
||||
cairo_image_glyph_cache_entry_t *im;
|
||||
cairo_status_t status;
|
||||
|
||||
im = calloc (1, sizeof (cairo_image_glyph_cache_entry_t));
|
||||
if (im == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
im->key = *k;
|
||||
status = im->key.unscaled->backend->create_glyph (im);
|
||||
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
free (im);
|
||||
return status;
|
||||
}
|
||||
|
||||
_cairo_unscaled_font_reference (im->key.unscaled);
|
||||
|
||||
im->key.base.memory =
|
||||
sizeof (cairo_image_glyph_cache_entry_t)
|
||||
+ (im->image ?
|
||||
sizeof (cairo_image_surface_t)
|
||||
+ 28 * sizeof (int) /* rough guess at size of pixman image structure */
|
||||
+ (im->image->height * im->image->stride) : 0);
|
||||
|
||||
*return_value = im;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_image_glyph_cache_destroy_entry (void *cache,
|
||||
void *value)
|
||||
{
|
||||
cairo_image_glyph_cache_entry_t *im;
|
||||
|
||||
im = (cairo_image_glyph_cache_entry_t *) value;
|
||||
_cairo_unscaled_font_destroy (im->key.unscaled);
|
||||
cairo_surface_destroy (&(im->image->base));
|
||||
free (im);
|
||||
}
|
||||
|
||||
static void
|
||||
_image_glyph_cache_destroy_cache (void *cache)
|
||||
{
|
||||
free (cache);
|
||||
}
|
||||
|
||||
const cairo_cache_backend_t cairo_image_cache_backend = {
|
||||
_cairo_glyph_cache_hash,
|
||||
_cairo_glyph_cache_keys_equal,
|
||||
_image_glyph_cache_create_entry,
|
||||
_image_glyph_cache_destroy_entry,
|
||||
_image_glyph_cache_destroy_cache
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
_cairo_lock_global_image_glyph_cache()
|
||||
{
|
||||
/* FIXME: implement locking. */
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_unlock_global_image_glyph_cache()
|
||||
{
|
||||
/* FIXME: implement locking. */
|
||||
}
|
||||
|
||||
static cairo_cache_t *
|
||||
_global_image_glyph_cache = NULL;
|
||||
|
||||
cairo_cache_t *
|
||||
_cairo_get_global_image_glyph_cache ()
|
||||
{
|
||||
if (_global_image_glyph_cache == NULL) {
|
||||
_global_image_glyph_cache = malloc (sizeof (cairo_cache_t));
|
||||
|
||||
if (_global_image_glyph_cache == NULL)
|
||||
goto FAIL;
|
||||
|
||||
if (_cairo_cache_init (_global_image_glyph_cache,
|
||||
&cairo_image_cache_backend,
|
||||
CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT))
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
return _global_image_glyph_cache;
|
||||
|
||||
FAIL:
|
||||
if (_global_image_glyph_cache)
|
||||
free (_global_image_glyph_cache);
|
||||
_global_image_glyph_cache = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -900,7 +900,8 @@ static const struct cairo_surface_backend cairo_glitz_surface_backend = {
|
|||
_cairo_glitz_surface_copy_page,
|
||||
_cairo_glitz_surface_show_page,
|
||||
_cairo_glitz_surface_set_clip_region,
|
||||
_cairo_glitz_surface_create_pattern
|
||||
_cairo_glitz_surface_create_pattern,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
||||
cairo_surface_t *
|
||||
|
|
|
|||
|
|
@ -77,9 +77,9 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
|
|||
gstate->num_dashes = 0;
|
||||
gstate->dash_offset = 0.0;
|
||||
|
||||
gstate->font = _cairo_font_create (CAIRO_FONT_FAMILY_DEFAULT,
|
||||
CAIRO_FONT_SLANT_DEFAULT,
|
||||
CAIRO_FONT_WEIGHT_DEFAULT);
|
||||
gstate->font = _cairo_unscaled_font_create (CAIRO_FONT_FAMILY_DEFAULT,
|
||||
CAIRO_FONT_SLANT_DEFAULT,
|
||||
CAIRO_FONT_WEIGHT_DEFAULT);
|
||||
|
||||
gstate->surface = NULL;
|
||||
|
||||
|
|
@ -119,11 +119,8 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
|
|||
}
|
||||
|
||||
if (other->font) {
|
||||
gstate->font = _cairo_font_copy (other->font);
|
||||
if (!gstate->font) {
|
||||
status = CAIRO_STATUS_NO_MEMORY;
|
||||
goto CLEANUP_DASHES;
|
||||
}
|
||||
gstate->font = other->font;
|
||||
_cairo_unscaled_font_reference (gstate->font);
|
||||
}
|
||||
|
||||
if (other->clip.region)
|
||||
|
|
@ -149,9 +146,10 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
|
|||
|
||||
CLEANUP_PATH:
|
||||
_cairo_path_fini (&gstate->path);
|
||||
|
||||
CLEANUP_FONT:
|
||||
cairo_font_destroy (gstate->font);
|
||||
CLEANUP_DASHES:
|
||||
_cairo_unscaled_font_destroy (gstate->font);
|
||||
|
||||
free (gstate->dash);
|
||||
gstate->dash = NULL;
|
||||
|
||||
|
|
@ -161,7 +159,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
|
|||
void
|
||||
_cairo_gstate_fini (cairo_gstate_t *gstate)
|
||||
{
|
||||
cairo_font_destroy (gstate->font);
|
||||
_cairo_unscaled_font_destroy (gstate->font);
|
||||
|
||||
if (gstate->surface)
|
||||
cairo_surface_destroy (gstate->surface);
|
||||
|
|
@ -177,6 +175,8 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
|
|||
|
||||
cairo_pattern_destroy (gstate->pattern);
|
||||
|
||||
_cairo_matrix_fini (&gstate->font_matrix);
|
||||
|
||||
_cairo_matrix_fini (&gstate->ctm);
|
||||
_cairo_matrix_fini (&gstate->ctm_inverse);
|
||||
|
||||
|
|
@ -627,6 +627,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate)
|
|||
if (scale == 0)
|
||||
scale = 1;
|
||||
|
||||
cairo_matrix_set_identity (&gstate->font_matrix);
|
||||
|
||||
cairo_matrix_set_identity (&gstate->ctm);
|
||||
cairo_matrix_scale (&gstate->ctm, scale, scale);
|
||||
cairo_matrix_copy (&gstate->ctm_inverse, &gstate->ctm);
|
||||
|
|
@ -1676,15 +1678,6 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
|
|||
double a, b, c, d, tx, ty;
|
||||
cairo_status_t st;
|
||||
|
||||
/* XXX: Something in the rectangle-based clipping support is
|
||||
* broken. See cairo_snippets/xxx_clip_rectangle which
|
||||
* demonstrates no clipping at all.
|
||||
*
|
||||
* For now, I'm am disabling this optimization completely until it
|
||||
* can be fixed.
|
||||
*/
|
||||
return 0;
|
||||
|
||||
st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
|
||||
if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.))
|
||||
return 0;
|
||||
|
|
@ -1992,16 +1985,28 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_select_font (cairo_gstate_t *gstate,
|
||||
const char *family,
|
||||
cairo_font_slant_t slant,
|
||||
cairo_font_weight_t weight)
|
||||
{
|
||||
if (gstate->font != NULL)
|
||||
cairo_font_destroy (gstate->font);
|
||||
cairo_unscaled_font_t *tmp;
|
||||
|
||||
gstate->font = _cairo_font_create (family, slant, weight);
|
||||
tmp = _cairo_unscaled_font_create (family, slant, weight);
|
||||
|
||||
if (tmp == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
if (gstate->font != tmp)
|
||||
{
|
||||
if (gstate->font != NULL)
|
||||
_cairo_unscaled_font_destroy (gstate->font);
|
||||
|
||||
cairo_matrix_set_identity (&gstate->font_matrix);
|
||||
gstate->font = tmp;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -2010,82 +2015,250 @@ cairo_status_t
|
|||
_cairo_gstate_scale_font (cairo_gstate_t *gstate,
|
||||
double scale)
|
||||
{
|
||||
return _cairo_font_scale (gstate->font, scale);
|
||||
return cairo_matrix_scale (&gstate->font_matrix, scale, scale);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_transform_font (cairo_gstate_t *gstate,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
return _cairo_font_transform (gstate->font, matrix);
|
||||
cairo_matrix_t tmp;
|
||||
double a, b, c, d, tx, ty;
|
||||
cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty);
|
||||
cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0);
|
||||
return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp);
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_current_font (cairo_gstate_t *gstate,
|
||||
cairo_font_t **font)
|
||||
{
|
||||
*font = gstate->font;
|
||||
cairo_font_scale_t scale;
|
||||
cairo_font_t *scaled;
|
||||
double dummy;
|
||||
|
||||
scaled = malloc (sizeof (cairo_font_t));
|
||||
if (scaled == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
cairo_matrix_get_affine (&gstate->font_matrix,
|
||||
&scale.matrix[0][0],
|
||||
&scale.matrix[0][1],
|
||||
&scale.matrix[1][0],
|
||||
&scale.matrix[1][1],
|
||||
&dummy, &dummy);
|
||||
|
||||
_cairo_font_init (scaled, &scale, gstate->font);
|
||||
_cairo_unscaled_font_reference (gstate->font);
|
||||
|
||||
*font = scaled;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_matrix_copy (&gstate->font_matrix, matrix);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_matrix_copy (matrix, &gstate->font_matrix);
|
||||
}
|
||||
|
||||
/*
|
||||
* Like everything else in this file, fonts involve Too Many Coordinate Spaces;
|
||||
* it is easy to get confused about what's going on.
|
||||
*
|
||||
* The user's view
|
||||
* ---------------
|
||||
*
|
||||
* Users ask for things in user space. When cairo starts, a user space unit
|
||||
* is about 1/96 inch, which is similar to (but importantly different from)
|
||||
* the normal "point" units most users think in terms of. When a user
|
||||
* selects a font, its scale is set to "one user unit". The user can then
|
||||
* independently scale the user coordinate system *or* the font matrix, in
|
||||
* order to adjust the rendered size of the font.
|
||||
*
|
||||
* If the user asks for a permanent reference to "a font", they are given a
|
||||
* handle to a structure holding a scale matrix and an unscaled font. This
|
||||
* effectively decouples the font from further changes to user space. Even
|
||||
* if the user then "sets" the current cairo_t font to the handle they were
|
||||
* passed, further changes to the cairo_t CTM will not affect externally
|
||||
* held references to the font.
|
||||
*
|
||||
*
|
||||
* The font's view
|
||||
* ---------------
|
||||
*
|
||||
* Fonts are designed and stored (in say .ttf files) in "font space", which
|
||||
* describes an "EM Square" (a design tile) and has some abstract number
|
||||
* such as 1000, 1024, or 2048 units per "EM". This is basically an
|
||||
* uninteresting space for us, but we need to remember that it exists.
|
||||
*
|
||||
* Font resources (from libraries or operating systems) render themselves
|
||||
* to a particular device. Since they do not want to make most programmers
|
||||
* worry about the font design space, the scaling API is simplified to
|
||||
* involve just telling the font the required pixel size of the EM square
|
||||
* (that is, in device space).
|
||||
*
|
||||
*
|
||||
* Cairo's gstate view
|
||||
* -------------------
|
||||
*
|
||||
* In addition to the CTM and CTM inverse, we keep a matrix in the gstate
|
||||
* called the "font matrix" which describes the user's most recent
|
||||
* font-scaling or font-transforming request. This is kept in terms of an
|
||||
* abstract scale factor, composed with the CTM and used to set the font's
|
||||
* pixel size. So if the user asks to "scale the font by 12", the matrix
|
||||
* is:
|
||||
*
|
||||
* [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ]
|
||||
*
|
||||
* It is an affine matrix, like all cairo matrices, but its tx and ty
|
||||
* components are always set to zero; we don't permit "nudging" fonts
|
||||
* around.
|
||||
*
|
||||
* In order to perform any action on a font, we must build an object
|
||||
* called a cairo_font_scale_t; this contains the central 2x2 matrix
|
||||
* resulting from "font matrix * CTM".
|
||||
*
|
||||
* We pass this to the font when making requests of it, which causes it to
|
||||
* reply for a particular [user request, device] combination, under the CTM
|
||||
* (to accomodate the "zoom in" == "bigger fonts" issue above).
|
||||
*
|
||||
* The other terms in our communication with the font are therefore in
|
||||
* device space. When we ask it to perform text->glyph conversion, it will
|
||||
* produce a glyph string in device space. Glyph vectors we pass to it for
|
||||
* measuring or rendering should be in device space. The metrics which we
|
||||
* get back from the font will be in device space. The contents of the
|
||||
* global glyph image cache will be in device space.
|
||||
*
|
||||
*
|
||||
* Cairo's public view
|
||||
* -------------------
|
||||
*
|
||||
* Since the values entering and leaving via public API calls are in user
|
||||
* space, the gstate functions typically need to multiply argumens by the
|
||||
* CTM (for user-input glyph vectors), and return values by the CTM inverse
|
||||
* (for font responses such as metrics or glyph vectors).
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
_build_font_scale (cairo_gstate_t *gstate,
|
||||
cairo_font_scale_t *sc)
|
||||
{
|
||||
cairo_matrix_t tmp;
|
||||
double dummy;
|
||||
cairo_matrix_multiply (&tmp, &gstate->font_matrix, &gstate->ctm);
|
||||
cairo_matrix_get_affine (&tmp,
|
||||
&sc->matrix[0][0],
|
||||
&sc->matrix[0][1],
|
||||
&sc->matrix[1][0],
|
||||
&sc->matrix[1][1],
|
||||
&dummy, &dummy);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
|
||||
cairo_font_extents_t *extents)
|
||||
{
|
||||
cairo_int_status_t status;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
|
||||
|
||||
status = _cairo_font_font_extents (gstate->font, extents);
|
||||
cairo_font_scale_t sc;
|
||||
double dummy = 0.0;
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
_build_font_scale (gstate, &sc);
|
||||
|
||||
status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents);
|
||||
|
||||
/* The font responded in device space; convert to user space. */
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&dummy,
|
||||
&extents->ascent);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&dummy,
|
||||
&extents->descent);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&dummy,
|
||||
&extents->height);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&extents->max_x_advance,
|
||||
&extents->max_y_advance);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8,
|
||||
cairo_glyph_t **glyphs,
|
||||
int *nglyphs)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_font_scale_t sc;
|
||||
|
||||
cairo_point_t point;
|
||||
double dev_x, dev_y;
|
||||
int i;
|
||||
|
||||
_build_font_scale (gstate, &sc);
|
||||
|
||||
status = _cairo_path_current_point (&gstate->path, &point);
|
||||
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
|
||||
dev_x = 0.0;
|
||||
dev_y = 0.0;
|
||||
} else {
|
||||
dev_x = _cairo_fixed_to_double (point.x);
|
||||
dev_y = _cairo_fixed_to_double (point.y);
|
||||
}
|
||||
|
||||
status = _cairo_unscaled_font_text_to_glyphs (gstate->font,
|
||||
&sc, utf8, glyphs, nglyphs);
|
||||
|
||||
if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
|
||||
return status;
|
||||
|
||||
/* The font responded in device space, starting from (0,0); add any
|
||||
current point offset in device space, and convert to user space. */
|
||||
|
||||
for (i = 0; i < *nglyphs; ++i) {
|
||||
(*glyphs)[i].x += dev_x;
|
||||
(*glyphs)[i].y += dev_y;
|
||||
cairo_matrix_transform_point (&gstate->ctm_inverse,
|
||||
&((*glyphs)[i].x),
|
||||
&((*glyphs)[i].y));
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_font (cairo_gstate_t *gstate,
|
||||
cairo_font_t *font)
|
||||
{
|
||||
if (gstate->font != NULL)
|
||||
cairo_font_destroy (gstate->font);
|
||||
gstate->font = font;
|
||||
cairo_font_reference (gstate->font);
|
||||
_cairo_unscaled_font_destroy (gstate->font);
|
||||
gstate->font = font->unscaled;
|
||||
_cairo_unscaled_font_reference (gstate->font);
|
||||
cairo_matrix_set_affine (&gstate->font_matrix,
|
||||
font->scale.matrix[0][0],
|
||||
font->scale.matrix[0][1],
|
||||
font->scale.matrix[1][0],
|
||||
font->scale.matrix[1][1],
|
||||
0, 0);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_text_extents (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8,
|
||||
cairo_text_extents_t *extents)
|
||||
{
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
cairo_status_t status;
|
||||
double scale_x, scale_y;
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
_cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
|
||||
cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
|
||||
|
||||
status = _cairo_font_text_extents (gstate->font,
|
||||
utf8, extents);
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
|
||||
extents->x_bearing /= scale_x;
|
||||
extents->y_bearing /= scale_y;
|
||||
extents->width /= scale_x;
|
||||
extents->height /= scale_y;
|
||||
extents->x_advance /= scale_x;
|
||||
extents->y_advance /= scale_y;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
|
||||
cairo_glyph_t *glyphs,
|
||||
|
|
@ -2093,129 +2266,43 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
|
|||
cairo_text_extents_t *extents)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
double scale_x, scale_y;
|
||||
cairo_glyph_t *transformed_glyphs;
|
||||
cairo_font_scale_t sc;
|
||||
int i;
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
_cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
|
||||
cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
|
||||
_build_font_scale (gstate, &sc);
|
||||
|
||||
status = _cairo_font_glyph_extents (gstate->font,
|
||||
glyphs, num_glyphs,
|
||||
extents);
|
||||
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
|
||||
if (transformed_glyphs == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
|
||||
extents->x_bearing /= scale_x;
|
||||
extents->y_bearing /= scale_y;
|
||||
extents->width /= scale_x;
|
||||
extents->height /= scale_y;
|
||||
extents->x_advance /= scale_x;
|
||||
extents->y_advance /= scale_y;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_show_text (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_point_t point;
|
||||
double x, y;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
cairo_pattern_t pattern;
|
||||
cairo_box_t bbox;
|
||||
|
||||
status = _cairo_path_current_point (&gstate->path, &point);
|
||||
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
|
||||
x = 0;
|
||||
y = 0;
|
||||
cairo_matrix_transform_point (&gstate->ctm, &x, &y);
|
||||
} else {
|
||||
x = _cairo_fixed_to_double (point.x);
|
||||
y = _cairo_fixed_to_double (point.y);
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
|
||||
|
||||
_cairo_pattern_init_copy (&pattern, gstate->pattern);
|
||||
|
||||
status = _cairo_font_text_bbox (gstate->font, gstate->surface,
|
||||
x, y, utf8, &bbox);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (gstate->clip.surface)
|
||||
for (i = 0; i < num_glyphs; ++i)
|
||||
{
|
||||
cairo_surface_t *intermediate;
|
||||
cairo_color_t empty_color;
|
||||
|
||||
_cairo_color_init (&empty_color);
|
||||
_cairo_color_set_alpha (&empty_color, .0);
|
||||
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
|
||||
CAIRO_FORMAT_A8,
|
||||
gstate->clip.width,
|
||||
gstate->clip.height,
|
||||
&empty_color);
|
||||
|
||||
status = _cairo_font_show_text (gstate->font,
|
||||
CAIRO_OPERATOR_ADD, pattern.source,
|
||||
intermediate,
|
||||
gstate->clip.x - pattern.source_offset.x,
|
||||
gstate->clip.y - pattern.source_offset.y,
|
||||
x - gstate->clip.x,
|
||||
y - gstate->clip.y, utf8);
|
||||
|
||||
if (status)
|
||||
goto BAIL;
|
||||
|
||||
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
|
||||
gstate->clip.surface,
|
||||
NULL,
|
||||
intermediate,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
gstate->clip.width,
|
||||
gstate->clip.height);
|
||||
|
||||
if (status)
|
||||
goto BAIL;
|
||||
|
||||
status = _cairo_surface_composite (gstate->operator,
|
||||
pattern.source,
|
||||
intermediate,
|
||||
gstate->surface,
|
||||
0, 0,
|
||||
0, 0,
|
||||
gstate->clip.x,
|
||||
gstate->clip.y,
|
||||
gstate->clip.width,
|
||||
gstate->clip.height);
|
||||
|
||||
BAIL:
|
||||
cairo_surface_destroy (intermediate);
|
||||
|
||||
transformed_glyphs[i] = glyphs[i];
|
||||
cairo_matrix_transform_point (&gstate->ctm,
|
||||
&transformed_glyphs[i].x,
|
||||
&transformed_glyphs[i].y);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = _cairo_font_show_text (gstate->font,
|
||||
gstate->operator, pattern.source,
|
||||
gstate->surface,
|
||||
-pattern.source_offset.x,
|
||||
-pattern.source_offset.y,
|
||||
x, y, utf8);
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
|
||||
_cairo_pattern_fini (&pattern);
|
||||
status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc,
|
||||
transformed_glyphs, num_glyphs,
|
||||
extents);
|
||||
|
||||
/* The font responded in device space; convert to user space. */
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&extents->x_bearing,
|
||||
&extents->y_bearing);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&extents->width,
|
||||
&extents->height);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&extents->x_advance,
|
||||
&extents->y_advance);
|
||||
|
||||
free (transformed_glyphs);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -2226,12 +2313,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
int num_glyphs)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
int i;
|
||||
cairo_glyph_t *transformed_glyphs = NULL;
|
||||
cairo_font_scale_t sc;
|
||||
cairo_pattern_t pattern;
|
||||
cairo_box_t bbox;
|
||||
|
||||
_build_font_scale (gstate, &sc);
|
||||
|
||||
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
|
||||
if (transformed_glyphs == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
|
@ -2240,16 +2329,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
{
|
||||
transformed_glyphs[i] = glyphs[i];
|
||||
cairo_matrix_transform_point (&gstate->ctm,
|
||||
&(transformed_glyphs[i].x),
|
||||
&(transformed_glyphs[i].y));
|
||||
&transformed_glyphs[i].x,
|
||||
&transformed_glyphs[i].y);
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
|
||||
|
||||
_cairo_pattern_init_copy (&pattern, gstate->pattern);
|
||||
status = _cairo_font_glyph_bbox (gstate->font, gstate->surface,
|
||||
transformed_glyphs, num_glyphs, &bbox);
|
||||
status = _cairo_unscaled_font_glyph_bbox (gstate->font, &sc,
|
||||
transformed_glyphs, num_glyphs,
|
||||
&bbox);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
|
|
@ -2277,12 +2364,13 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
transformed_glyphs[i].y -= gstate->clip.y;
|
||||
}
|
||||
|
||||
status = _cairo_font_show_glyphs (gstate->font,
|
||||
CAIRO_OPERATOR_ADD,
|
||||
pattern.source, intermediate,
|
||||
gstate->clip.x - pattern.source_offset.x,
|
||||
gstate->clip.y - pattern.source_offset.y,
|
||||
transformed_glyphs, num_glyphs);
|
||||
status = _cairo_unscaled_font_show_glyphs (gstate->font,
|
||||
&sc,
|
||||
CAIRO_OPERATOR_ADD,
|
||||
pattern.source, intermediate,
|
||||
gstate->clip.x - pattern.source_offset.x,
|
||||
gstate->clip.y - pattern.source_offset.y,
|
||||
transformed_glyphs, num_glyphs);
|
||||
|
||||
if (status)
|
||||
goto BAIL;
|
||||
|
|
@ -2317,16 +2405,15 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
}
|
||||
else
|
||||
{
|
||||
status = _cairo_font_show_glyphs (gstate->font,
|
||||
gstate->operator, pattern.source,
|
||||
gstate->surface,
|
||||
-pattern.source_offset.x,
|
||||
-pattern.source_offset.y,
|
||||
transformed_glyphs, num_glyphs);
|
||||
status = _cairo_unscaled_font_show_glyphs (gstate->font,
|
||||
&sc,
|
||||
gstate->operator, pattern.source,
|
||||
gstate->surface,
|
||||
-pattern.source_offset.x,
|
||||
-pattern.source_offset.y,
|
||||
transformed_glyphs, num_glyphs);
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
|
||||
_cairo_pattern_fini (&pattern);
|
||||
|
||||
free (transformed_glyphs);
|
||||
|
|
@ -2334,40 +2421,6 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
return status;
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_text_path (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
cairo_point_t point;
|
||||
double x, y;
|
||||
|
||||
status = _cairo_path_current_point (&gstate->path, &point);
|
||||
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
|
||||
x = 0;
|
||||
y = 0;
|
||||
cairo_matrix_transform_point (&gstate->ctm, &x, &y);
|
||||
} else {
|
||||
x = _cairo_fixed_to_double (point.x);
|
||||
y = _cairo_fixed_to_double (point.y);
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
|
||||
|
||||
status = _cairo_font_text_path (gstate->font,
|
||||
x, y,
|
||||
utf8,
|
||||
&gstate->path);
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
|
||||
cairo_glyph_t *glyphs,
|
||||
|
|
@ -2376,7 +2429,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
|
|||
cairo_status_t status;
|
||||
int i;
|
||||
cairo_glyph_t *transformed_glyphs = NULL;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
cairo_font_scale_t sc;
|
||||
|
||||
_build_font_scale (gstate, &sc);
|
||||
|
||||
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
|
||||
if (transformed_glyphs == NULL)
|
||||
|
|
@ -2390,14 +2445,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
|
|||
&(transformed_glyphs[i].y));
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
|
||||
|
||||
status = _cairo_font_glyph_path (gstate->font,
|
||||
transformed_glyphs, num_glyphs,
|
||||
&gstate->path);
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
status = _cairo_unscaled_font_glyph_path (gstate->font, &sc,
|
||||
transformed_glyphs, num_glyphs,
|
||||
&gstate->path);
|
||||
|
||||
free (transformed_glyphs);
|
||||
return status;
|
||||
|
|
|
|||
454
src/cairo-hash.c
Normal file
454
src/cairo-hash.c
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* This file is Copyright © 2004 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it either under the terms of the GNU Lesser General Public
|
||||
* License version 2.1 as published by the Free Software Foundation
|
||||
* (the "LGPL") or, at your option, under the terms of the Mozilla
|
||||
* Public License Version 1.1 (the "MPL"). If you do not alter this
|
||||
* notice, a recipient may use your version of this file under either
|
||||
* the MPL or the LGPL.
|
||||
*
|
||||
* You should have received a copy of the LGPL along with this library
|
||||
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* You should have received a copy of the MPL along with this library
|
||||
* in the file COPYING-MPL-1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
||||
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
||||
* the specific language governing rights and limitations.
|
||||
*
|
||||
* The Original Code is the cairo graphics library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Red Hat, Inc.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Keith Packard
|
||||
* Graydon Hoare <graydon@redhat.com>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
/*
|
||||
* This structure, and accompanying table, is borrowed/modified from the
|
||||
* file xserver/render/glyph.c in the freedesktop.org x server, with
|
||||
* permission (and suggested modification of doubling sizes) by Keith
|
||||
* Packard.
|
||||
*/
|
||||
|
||||
static cairo_cache_arrangement_t cache_arrangements [] = {
|
||||
{ 16, 43, 41 },
|
||||
{ 32, 73, 71 },
|
||||
{ 64, 151, 149 },
|
||||
{ 128, 283, 281 },
|
||||
{ 256, 571, 569 },
|
||||
{ 512, 1153, 1151 },
|
||||
{ 1024, 2269, 2267 },
|
||||
{ 2048, 4519, 4517 },
|
||||
{ 4096, 9013, 9011 },
|
||||
{ 8192, 18043, 18041 },
|
||||
{ 16384, 36109, 36107 },
|
||||
{ 32768, 72091, 72089 },
|
||||
{ 65536, 144409, 144407 },
|
||||
{ 131072, 288361, 288359 },
|
||||
{ 262144, 576883, 576881 },
|
||||
{ 524288, 1153459, 1153457 },
|
||||
{ 1048576, 2307163, 2307161 },
|
||||
{ 2097152, 4613893, 4613891 },
|
||||
{ 4194304, 9227641, 9227639 },
|
||||
{ 8388608, 18455029, 18455027 },
|
||||
{ 16777216, 36911011, 36911009 },
|
||||
{ 33554432, 73819861, 73819859 },
|
||||
{ 67108864, 147639589, 147639587 },
|
||||
{ 134217728, 295279081, 295279079 },
|
||||
{ 268435456, 590559793, 590559791 }
|
||||
};
|
||||
|
||||
#define N_CACHE_SIZES (sizeof(cache_arrangements)/sizeof(cache_arrangements[0]))
|
||||
|
||||
/*
|
||||
* Entries 'e' are poiners, in one of 3 states:
|
||||
*
|
||||
* e == NULL: The entry has never had anything put in it
|
||||
* e != DEAD_ENTRY: The entry has an active value in it currently
|
||||
* e == DEAD_ENTRY: The entry *had* a value in it at some point, but the
|
||||
* entry has been killed. Lookups requesting free space can
|
||||
* reuse these entries; lookups requesting a precise match
|
||||
* should neither return these entries nor stop searching when
|
||||
* seeing these entries.
|
||||
*
|
||||
* We expect keys will not be destroyed frequently, so our table does not
|
||||
* contain any explicit shrinking code nor any chain-coalescing code for
|
||||
* entries randomly deleted by memory pressure (except during rehashing, of
|
||||
* course). These assumptions are potentially bad, but they make the
|
||||
* implementation straightforward.
|
||||
*
|
||||
* Revisit later if evidence appears that we're using excessive memory from
|
||||
* a mostly-dead table.
|
||||
*
|
||||
* Generally you do not need to worry about freeing cache entries; the
|
||||
* cache will expire entries randomly as it experiences memory pressure.
|
||||
* There is currently no explicit entry-removing call, though one can be
|
||||
* added easily.
|
||||
*
|
||||
* This table is open-addressed with double hashing. Each table size is a
|
||||
* prime chosen to be a little more than double the high water mark for a
|
||||
* given arrangement, so the tables should remain < 50% full. The table
|
||||
* size makes for the "first" hash modulus; a second prime (2 less than the
|
||||
* first prime) serves as the "second" hash modulus, which is co-prime and
|
||||
* thus guarantees a complete permutation of table indices.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DEAD_ENTRY ((cairo_cache_entry_base_t *) 1)
|
||||
#define NULL_ENTRY_P(cache, i) ((cache)->entries[i] == NULL)
|
||||
#define DEAD_ENTRY_P(cache, i) ((cache)->entries[i] == DEAD_ENTRY)
|
||||
#define LIVE_ENTRY_P(cache, i) \
|
||||
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
|
||||
|
||||
#ifdef CAIRO_DO_SANITY_CHECKING
|
||||
#include <assert.h>
|
||||
static void
|
||||
_cache_sane_state (cairo_cache_t *cache)
|
||||
{
|
||||
assert (cache != NULL);
|
||||
assert (cache->entries != NULL);
|
||||
assert (cache->backend != NULL);
|
||||
assert (cache->arrangement != NULL);
|
||||
assert (cache->refcount > 0);
|
||||
assert (cache->used_memory <= cache->max_memory);
|
||||
assert (cache->live_entries <= cache->arrangement->size);
|
||||
}
|
||||
#else
|
||||
#define _cache_sane_state(c)
|
||||
#define assert(x)
|
||||
#endif
|
||||
|
||||
static void
|
||||
_entry_destroy (cairo_cache_t *cache, unsigned long i)
|
||||
{
|
||||
_cache_sane_state (cache);
|
||||
|
||||
if (LIVE_ENTRY_P(cache, i))
|
||||
{
|
||||
cairo_cache_entry_base_t *entry = cache->entries[i];
|
||||
assert(cache->live_entries > 0);
|
||||
assert(cache->used_memory > entry->memory);
|
||||
|
||||
cache->live_entries--;
|
||||
cache->used_memory -= entry->memory;
|
||||
cache->backend->destroy_entry (cache, entry);
|
||||
cache->entries[i] = DEAD_ENTRY;
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_cache_entry_base_t **
|
||||
_cache_lookup (cairo_cache_t *cache,
|
||||
void *key,
|
||||
int (*predicate)(void*,void*,void*))
|
||||
{
|
||||
|
||||
cairo_cache_entry_base_t **probe;
|
||||
unsigned long hash;
|
||||
unsigned long table_size, i, idx, step;
|
||||
|
||||
_cache_sane_state (cache);
|
||||
assert (key != NULL);
|
||||
|
||||
table_size = cache->arrangement->size;
|
||||
hash = cache->backend->hash (cache, key);
|
||||
idx = hash % table_size;
|
||||
step = 0;
|
||||
|
||||
for (i = 0; i < table_size; ++i)
|
||||
{
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->probes++;
|
||||
#endif
|
||||
assert(idx < table_size);
|
||||
probe = cache->entries + idx;
|
||||
|
||||
/*
|
||||
* There are two lookup modes: searching for a free slot and searching
|
||||
* for an exact entry.
|
||||
*/
|
||||
|
||||
if (predicate != NULL)
|
||||
{
|
||||
/* We are looking up an exact entry. */
|
||||
if (*probe != NULL
|
||||
&& *probe != DEAD_ENTRY
|
||||
&& (*probe)->hashcode == hash
|
||||
&& predicate (cache, key, *probe))
|
||||
return probe;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We are just looking for a free slot. */
|
||||
if (*probe == NULL
|
||||
|| *probe == DEAD_ENTRY)
|
||||
return probe;
|
||||
}
|
||||
|
||||
if (step == 0) {
|
||||
step = hash % cache->arrangement->rehash;
|
||||
if (step == 0)
|
||||
step = 1;
|
||||
}
|
||||
|
||||
idx += step;
|
||||
if (idx >= table_size)
|
||||
idx -= table_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* The table should not have permitted you to get here if you were just
|
||||
* looking for a free slot: there should have been room.
|
||||
*/
|
||||
assert(predicate != NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static cairo_cache_entry_base_t **
|
||||
_find_available_entry_for (cairo_cache_t *cache,
|
||||
void *key)
|
||||
{
|
||||
return _cache_lookup (cache, key, NULL);
|
||||
}
|
||||
|
||||
static cairo_cache_entry_base_t **
|
||||
_find_exact_live_entry_for (cairo_cache_t *cache,
|
||||
void *key)
|
||||
{
|
||||
return _cache_lookup (cache, key, cache->backend->keys_equal);
|
||||
}
|
||||
|
||||
|
||||
static cairo_cache_arrangement_t *
|
||||
_find_cache_arrangement (unsigned long proposed_size)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
for (idx = 0; idx < N_CACHE_SIZES; ++idx)
|
||||
if (cache_arrangements[idx].high_water_mark >= proposed_size)
|
||||
return &cache_arrangements[idx];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_resize_cache (cairo_cache_t *cache, unsigned long proposed_size)
|
||||
{
|
||||
cairo_cache_t tmp;
|
||||
cairo_cache_entry_base_t **e;
|
||||
unsigned long new_size, i;
|
||||
|
||||
tmp = *cache;
|
||||
tmp.arrangement = _find_cache_arrangement (proposed_size);
|
||||
assert(tmp.arrangement != NULL);
|
||||
if (tmp.arrangement == cache->arrangement)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
new_size = tmp.arrangement->size;
|
||||
tmp.entries = calloc (new_size, sizeof (cairo_cache_entry_base_t *));
|
||||
if (tmp.entries == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
for (i = 0; i < cache->arrangement->size; ++i) {
|
||||
if (LIVE_ENTRY_P(cache, i)) {
|
||||
e = _find_available_entry_for (&tmp, cache->entries[i]);
|
||||
assert (e != NULL);
|
||||
*e = cache->entries[i];
|
||||
}
|
||||
}
|
||||
free (cache->entries);
|
||||
cache->entries = tmp.entries;
|
||||
cache->arrangement = tmp.arrangement;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
static double
|
||||
_load_factor (cairo_cache_t *cache)
|
||||
{
|
||||
return ((double) cache->live_entries)
|
||||
/ ((double) cache->arrangement->size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned long
|
||||
_random_live_entry (cairo_cache_t *cache)
|
||||
{
|
||||
unsigned long idx;
|
||||
assert(cache != NULL);
|
||||
do {
|
||||
idx = rand () % cache->arrangement->size;
|
||||
} while (! LIVE_ENTRY_P(cache, idx));
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
/* public API follows */
|
||||
|
||||
cairo_status_t
|
||||
_cairo_cache_init (cairo_cache_t *cache,
|
||||
const cairo_cache_backend_t *backend,
|
||||
unsigned long max_memory)
|
||||
{
|
||||
assert(backend != NULL);
|
||||
|
||||
if (cache != NULL){
|
||||
cache->arrangement = &cache_arrangements[0];
|
||||
cache->refcount = 1;
|
||||
cache->max_memory = max_memory;
|
||||
cache->used_memory = 0;
|
||||
cache->live_entries = 0;
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->hits = 0;
|
||||
cache->misses = 0;
|
||||
cache->probes = 0;
|
||||
#endif
|
||||
|
||||
cache->backend = backend;
|
||||
cache->entries = calloc (sizeof(cairo_cache_entry_base_t *),
|
||||
cache->arrangement->size);
|
||||
if (cache->entries == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
_cache_sane_state (cache);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_cache_reference (cairo_cache_t *cache)
|
||||
{
|
||||
_cache_sane_state (cache);
|
||||
cache->refcount++;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_cache_destroy (cairo_cache_t *cache)
|
||||
{
|
||||
unsigned long i;
|
||||
if (cache != NULL) {
|
||||
|
||||
_cache_sane_state (cache);
|
||||
|
||||
if (cache->refcount-- > 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < cache->arrangement->size; ++i) {
|
||||
_entry_destroy (cache, i);
|
||||
}
|
||||
|
||||
free (cache->entries);
|
||||
cache->entries = NULL;
|
||||
cache->backend->destroy_cache (cache);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_cache_lookup (cairo_cache_t *cache,
|
||||
void *key,
|
||||
void **entry_return)
|
||||
{
|
||||
|
||||
unsigned long idx;
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_cache_entry_base_t **slot = NULL, *new_entry;
|
||||
|
||||
_cache_sane_state (cache);
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
if ((cache->hits + cache->misses) % 0xffff == 0)
|
||||
printf("cache %p stats: size %ld, live %ld, load %.2f\n"
|
||||
" mem %ld/%ld, hit %ld, miss %ld\n"
|
||||
" probe %ld, %.2f probe/access\n",
|
||||
cache,
|
||||
cache->arrangement->size,
|
||||
cache->live_entries,
|
||||
_load_factor (cache),
|
||||
cache->used_memory,
|
||||
cache->max_memory,
|
||||
cache->hits,
|
||||
cache->misses,
|
||||
cache->probes,
|
||||
((double) cache->probes)
|
||||
/ ((double) (cache->hits +
|
||||
cache->misses + 1)));
|
||||
#endif
|
||||
|
||||
/* See if we have an entry in the table already. */
|
||||
slot = _find_exact_live_entry_for (cache, key);
|
||||
if (slot != NULL) {
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->hits++;
|
||||
#endif
|
||||
*entry_return = *slot;
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->misses++;
|
||||
#endif
|
||||
|
||||
/* Build the new entry. */
|
||||
status = cache->backend->create_entry (cache, key,
|
||||
entry_return);
|
||||
if (status != CAIRO_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
new_entry = (cairo_cache_entry_base_t *) (*entry_return);
|
||||
|
||||
/* Store the hash value in case the backend forgot. */
|
||||
new_entry->hashcode = cache->backend->hash (cache, key);
|
||||
|
||||
/* Make some entries die if we're under memory pressure. */
|
||||
while (cache->live_entries > 0 &&
|
||||
((cache->max_memory - cache->used_memory) < new_entry->memory)) {
|
||||
idx = _random_live_entry (cache);
|
||||
assert (idx < cache->arrangement->size);
|
||||
_entry_destroy (cache, idx);
|
||||
}
|
||||
|
||||
assert(cache->max_memory >= (cache->used_memory + new_entry->memory));
|
||||
|
||||
/* Make room in the table for a new slot. */
|
||||
status = _resize_cache (cache, cache->live_entries + 1);
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
cache->backend->destroy_entry (cache, new_entry);
|
||||
*entry_return = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
slot = _find_available_entry_for (cache, key);
|
||||
assert(slot != NULL);
|
||||
|
||||
/* Store entry in slot and increment statistics. */
|
||||
*slot = new_entry;
|
||||
cache->live_entries++;
|
||||
cache->used_memory += new_entry->memory;
|
||||
|
||||
_cache_sane_state (cache);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
_cairo_hash_string (const char *c)
|
||||
{
|
||||
/* This is the djb2 hash. */
|
||||
unsigned long hash = 5381;
|
||||
while (*c)
|
||||
hash = ((hash << 5) + hash) + *c++;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
|
@ -525,5 +525,6 @@ static const cairo_surface_backend_t cairo_image_surface_backend = {
|
|||
_cairo_image_surface_copy_page,
|
||||
_cairo_image_surface_show_page,
|
||||
_cairo_image_abstract_surface_set_clip_region,
|
||||
_cairo_image_abstract_surface_create_pattern
|
||||
_cairo_image_abstract_surface_create_pattern,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -436,5 +436,6 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
|
|||
_cairo_ps_surface_copy_page,
|
||||
_cairo_ps_surface_show_page,
|
||||
_cairo_ps_surface_set_clip_region,
|
||||
_cairo_ps_surface_create_pattern
|
||||
_cairo_ps_surface_create_pattern,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -745,7 +745,8 @@ static const struct cairo_surface_backend cairo_xcb_surface_backend = {
|
|||
_cairo_xcb_surface_copy_page,
|
||||
_cairo_xcb_surface_show_page,
|
||||
_cairo_xcb_surface_set_clip_region,
|
||||
_cairo_xcb_surface_create_pattern
|
||||
_cairo_xcb_surface_create_pattern,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -631,6 +631,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
|
|||
xr.height = surf->height;
|
||||
XUnionRectWithRegion (&xr, xregion, xregion);
|
||||
rects = malloc(sizeof(XRectangle));
|
||||
if (rects == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
rects[0] = xr;
|
||||
m = 1;
|
||||
|
||||
|
|
@ -641,6 +643,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
|
|||
if (n == 0)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
rects = malloc(sizeof(XRectangle) * n);
|
||||
if (rects == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
box = pixman_region_rects (region);
|
||||
xregion = XCreateRegion();
|
||||
|
||||
|
|
@ -661,7 +665,7 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
|
|||
XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
|
||||
free(rects);
|
||||
if (surf->picture)
|
||||
XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
|
||||
XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
|
||||
XDestroyRegion(xregion);
|
||||
XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
@ -675,6 +679,17 @@ _cairo_xlib_surface_create_pattern (void *abstract_surface,
|
|||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs);
|
||||
|
||||
static const struct cairo_surface_backend cairo_xlib_surface_backend = {
|
||||
_cairo_xlib_surface_create_similar,
|
||||
_cairo_xlib_surface_destroy,
|
||||
|
|
@ -690,7 +705,8 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = {
|
|||
_cairo_xlib_surface_copy_page,
|
||||
_cairo_xlib_surface_show_page,
|
||||
_cairo_xlib_surface_set_clip_region,
|
||||
_cairo_xlib_surface_create_pattern
|
||||
_cairo_xlib_surface_create_pattern,
|
||||
_cairo_xlib_surface_show_glyphs
|
||||
};
|
||||
|
||||
cairo_surface_t *
|
||||
|
|
@ -761,3 +777,512 @@ cairo_xlib_surface_create (Display *dpy,
|
|||
return (cairo_surface_t *) surface;
|
||||
}
|
||||
DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
|
||||
|
||||
|
||||
/* RENDER glyphset cache code */
|
||||
|
||||
typedef struct glyphset_cache {
|
||||
cairo_cache_t base;
|
||||
struct glyphset_cache *next;
|
||||
Display *display;
|
||||
XRenderPictFormat *a8_pict_format;
|
||||
GlyphSet glyphset;
|
||||
Glyph counter;
|
||||
} glyphset_cache_t;
|
||||
|
||||
typedef struct {
|
||||
cairo_glyph_cache_key_t key;
|
||||
Glyph glyph;
|
||||
XGlyphInfo info;
|
||||
} glyphset_cache_entry_t;
|
||||
|
||||
static Glyph
|
||||
_next_xlib_glyph (glyphset_cache_t *cache)
|
||||
{
|
||||
return ++(cache->counter);
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_xlib_glyphset_cache_create_entry (void *cache,
|
||||
void *key,
|
||||
void **return_entry)
|
||||
{
|
||||
glyphset_cache_t *g = (glyphset_cache_t *) cache;
|
||||
cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *)key;
|
||||
glyphset_cache_entry_t *v;
|
||||
|
||||
cairo_status_t status;
|
||||
|
||||
cairo_cache_t *im_cache;
|
||||
cairo_image_glyph_cache_entry_t *im;
|
||||
|
||||
v = malloc (sizeof (glyphset_cache_entry_t));
|
||||
_cairo_lock_global_image_glyph_cache ();
|
||||
im_cache = _cairo_get_global_image_glyph_cache ();
|
||||
|
||||
if (g == NULL || v == NULL ||g == NULL || im_cache == NULL) {
|
||||
_cairo_unlock_global_image_glyph_cache ();
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
status = _cairo_cache_lookup (im_cache, key, (void **) (&im));
|
||||
if (status != CAIRO_STATUS_SUCCESS || im == NULL) {
|
||||
_cairo_unlock_global_image_glyph_cache ();
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
v->key = *k;
|
||||
_cairo_unscaled_font_reference (v->key.unscaled);
|
||||
|
||||
v->glyph = _next_xlib_glyph (g);
|
||||
|
||||
v->info.width = im->image ? im->image->stride : im->size.width;
|
||||
v->info.height = im->size.height;
|
||||
v->info.x = - im->extents.x_bearing;
|
||||
v->info.y = im->extents.y_bearing;
|
||||
v->info.xOff = 0;
|
||||
v->info.yOff = 0;
|
||||
|
||||
XRenderAddGlyphs (g->display, g->glyphset,
|
||||
&(v->glyph), &(v->info), 1,
|
||||
im->image ? im->image->data : NULL,
|
||||
im->image ? v->info.height * v->info.width : 0);
|
||||
|
||||
v->key.base.memory = im->image ? im->image->width * im->image->stride : 0;
|
||||
*return_entry = v;
|
||||
_cairo_unlock_global_image_glyph_cache ();
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_xlib_glyphset_cache_destroy_cache (void *cache)
|
||||
{
|
||||
/* FIXME: will we ever release glyphset caches? */
|
||||
}
|
||||
|
||||
static void
|
||||
_xlib_glyphset_cache_destroy_entry (void *cache, void *entry)
|
||||
{
|
||||
glyphset_cache_t *g;
|
||||
glyphset_cache_entry_t *v;
|
||||
|
||||
g = (glyphset_cache_t *) cache;
|
||||
v = (glyphset_cache_entry_t *) entry;
|
||||
|
||||
_cairo_unscaled_font_destroy (v->key.unscaled);
|
||||
XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1);
|
||||
free (v);
|
||||
}
|
||||
|
||||
const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
|
||||
_cairo_glyph_cache_hash,
|
||||
_cairo_glyph_cache_keys_equal,
|
||||
_xlib_glyphset_cache_create_entry,
|
||||
_xlib_glyphset_cache_destroy_entry,
|
||||
_xlib_glyphset_cache_destroy_cache
|
||||
};
|
||||
|
||||
|
||||
static glyphset_cache_t *
|
||||
_xlib_glyphset_caches = NULL;
|
||||
|
||||
static void
|
||||
_lock_xlib_glyphset_caches (void)
|
||||
{
|
||||
/* FIXME: implement locking */
|
||||
}
|
||||
|
||||
static void
|
||||
_unlock_xlib_glyphset_caches (void)
|
||||
{
|
||||
/* FIXME: implement locking */
|
||||
}
|
||||
|
||||
static glyphset_cache_t *
|
||||
_get_glyphset_cache (Display *d)
|
||||
{
|
||||
/*
|
||||
* There should usually only be one, or a very small number, of
|
||||
* displays. So we just do a linear scan.
|
||||
*/
|
||||
|
||||
glyphset_cache_t *g;
|
||||
|
||||
for (g = _xlib_glyphset_caches; g != NULL; g = g->next) {
|
||||
if (g->display == d)
|
||||
return g;
|
||||
}
|
||||
|
||||
g = malloc (sizeof (glyphset_cache_t));
|
||||
if (g == NULL)
|
||||
goto ERR;
|
||||
|
||||
g->counter = 0;
|
||||
g->display = d;
|
||||
g->a8_pict_format = XRenderFindStandardFormat (d, PictStandardA8);
|
||||
if (g->a8_pict_format == NULL)
|
||||
goto ERR;
|
||||
|
||||
if (_cairo_cache_init (&g->base,
|
||||
&_xlib_glyphset_cache_backend,
|
||||
CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT))
|
||||
goto FREE_GLYPHSET_CACHE;
|
||||
|
||||
g->glyphset = XRenderCreateGlyphSet (d, g->a8_pict_format);
|
||||
g->next = _xlib_glyphset_caches;
|
||||
_xlib_glyphset_caches = g;
|
||||
return g;
|
||||
|
||||
FREE_GLYPHSET_CACHE:
|
||||
free (g);
|
||||
|
||||
ERR:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define N_STACK_BUF 1024
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
glyphset_cache_t *g,
|
||||
cairo_glyph_cache_key_t *key,
|
||||
cairo_xlib_surface_t *src,
|
||||
cairo_xlib_surface_t *self,
|
||||
int source_x,
|
||||
int source_y,
|
||||
const cairo_glyph_t *glyphs,
|
||||
glyphset_cache_entry_t **entries,
|
||||
int num_glyphs)
|
||||
{
|
||||
XGlyphElt32 *elts = NULL;
|
||||
XGlyphElt32 stack_elts [N_STACK_BUF];
|
||||
|
||||
unsigned int *chars = NULL;
|
||||
unsigned int stack_chars [N_STACK_BUF];
|
||||
|
||||
int i;
|
||||
int lastX = 0, lastY = 0;
|
||||
|
||||
/* Acquire arrays of suitable sizes. */
|
||||
if (num_glyphs < N_STACK_BUF) {
|
||||
elts = stack_elts;
|
||||
chars = stack_chars;
|
||||
|
||||
} else {
|
||||
elts = malloc (num_glyphs * sizeof (XGlyphElt32));
|
||||
if (elts == NULL)
|
||||
goto FAIL;
|
||||
|
||||
chars = malloc (num_glyphs * sizeof (unsigned int));
|
||||
if (chars == NULL)
|
||||
goto FREE_ELTS;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < num_glyphs; ++i) {
|
||||
chars[i] = entries[i]->glyph;
|
||||
elts[i].chars = &(chars[i]);
|
||||
elts[i].nchars = 1;
|
||||
elts[i].glyphset = g->glyphset;
|
||||
elts[i].xOff = glyphs[i].x - lastX;
|
||||
elts[i].yOff = glyphs[i].y - lastY;
|
||||
lastX = glyphs[i].x;
|
||||
lastY = glyphs[i].y;
|
||||
}
|
||||
|
||||
XRenderCompositeText32 (self->dpy,
|
||||
_render_operator (operator),
|
||||
src->picture,
|
||||
self->picture,
|
||||
g->a8_pict_format,
|
||||
source_x, source_y,
|
||||
0, 0,
|
||||
elts, num_glyphs);
|
||||
|
||||
if (num_glyphs >= N_STACK_BUF) {
|
||||
free (chars);
|
||||
free (elts);
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
FREE_ELTS:
|
||||
if (num_glyphs >= N_STACK_BUF)
|
||||
free (elts);
|
||||
|
||||
FAIL:
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
glyphset_cache_t *g,
|
||||
cairo_glyph_cache_key_t *key,
|
||||
cairo_xlib_surface_t *src,
|
||||
cairo_xlib_surface_t *self,
|
||||
int source_x,
|
||||
int source_y,
|
||||
const cairo_glyph_t *glyphs,
|
||||
glyphset_cache_entry_t **entries,
|
||||
int num_glyphs)
|
||||
{
|
||||
XGlyphElt16 *elts = NULL;
|
||||
XGlyphElt16 stack_elts [N_STACK_BUF];
|
||||
|
||||
unsigned short *chars = NULL;
|
||||
unsigned short stack_chars [N_STACK_BUF];
|
||||
|
||||
int i;
|
||||
int lastX = 0, lastY = 0;
|
||||
|
||||
/* Acquire arrays of suitable sizes. */
|
||||
if (num_glyphs < N_STACK_BUF) {
|
||||
elts = stack_elts;
|
||||
chars = stack_chars;
|
||||
|
||||
} else {
|
||||
elts = malloc (num_glyphs * sizeof (XGlyphElt16));
|
||||
if (elts == NULL)
|
||||
goto FAIL;
|
||||
|
||||
chars = malloc (num_glyphs * sizeof (unsigned short));
|
||||
if (chars == NULL)
|
||||
goto FREE_ELTS;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < num_glyphs; ++i) {
|
||||
chars[i] = entries[i]->glyph;
|
||||
elts[i].chars = &(chars[i]);
|
||||
elts[i].nchars = 1;
|
||||
elts[i].glyphset = g->glyphset;
|
||||
elts[i].xOff = glyphs[i].x - lastX;
|
||||
elts[i].yOff = glyphs[i].y - lastY;
|
||||
lastX = glyphs[i].x;
|
||||
lastY = glyphs[i].y;
|
||||
}
|
||||
|
||||
XRenderCompositeText16 (self->dpy,
|
||||
_render_operator (operator),
|
||||
src->picture,
|
||||
self->picture,
|
||||
g->a8_pict_format,
|
||||
source_x, source_y,
|
||||
0, 0,
|
||||
elts, num_glyphs);
|
||||
|
||||
if (num_glyphs >= N_STACK_BUF) {
|
||||
free (chars);
|
||||
free (elts);
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
FREE_ELTS:
|
||||
if (num_glyphs >= N_STACK_BUF)
|
||||
free (elts);
|
||||
|
||||
FAIL:
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
glyphset_cache_t *g,
|
||||
cairo_glyph_cache_key_t *key,
|
||||
cairo_xlib_surface_t *src,
|
||||
cairo_xlib_surface_t *self,
|
||||
int source_x,
|
||||
int source_y,
|
||||
const cairo_glyph_t *glyphs,
|
||||
glyphset_cache_entry_t **entries,
|
||||
int num_glyphs)
|
||||
{
|
||||
XGlyphElt8 *elts = NULL;
|
||||
XGlyphElt8 stack_elts [N_STACK_BUF];
|
||||
|
||||
char *chars = NULL;
|
||||
char stack_chars [N_STACK_BUF];
|
||||
|
||||
int i;
|
||||
int lastX = 0, lastY = 0;
|
||||
|
||||
/* Acquire arrays of suitable sizes. */
|
||||
if (num_glyphs < N_STACK_BUF) {
|
||||
elts = stack_elts;
|
||||
chars = stack_chars;
|
||||
|
||||
} else {
|
||||
elts = malloc (num_glyphs * sizeof (XGlyphElt8));
|
||||
if (elts == NULL)
|
||||
goto FAIL;
|
||||
|
||||
chars = malloc (num_glyphs * sizeof (char));
|
||||
if (chars == NULL)
|
||||
goto FREE_ELTS;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < num_glyphs; ++i) {
|
||||
chars[i] = entries[i]->glyph;
|
||||
elts[i].chars = &(chars[i]);
|
||||
elts[i].nchars = 1;
|
||||
elts[i].glyphset = g->glyphset;
|
||||
elts[i].xOff = glyphs[i].x - lastX;
|
||||
elts[i].yOff = glyphs[i].y - lastY;
|
||||
lastX = glyphs[i].x;
|
||||
lastY = glyphs[i].y;
|
||||
}
|
||||
|
||||
XRenderCompositeText8 (self->dpy,
|
||||
_render_operator (operator),
|
||||
src->picture,
|
||||
self->picture,
|
||||
g->a8_pict_format,
|
||||
source_x, source_y,
|
||||
0, 0,
|
||||
elts, num_glyphs);
|
||||
|
||||
if (num_glyphs >= N_STACK_BUF) {
|
||||
free (chars);
|
||||
free (elts);
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
FREE_ELTS:
|
||||
if (num_glyphs >= N_STACK_BUF)
|
||||
free (elts);
|
||||
|
||||
FAIL:
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs)
|
||||
{
|
||||
unsigned int elt_size;
|
||||
cairo_xlib_surface_t *self = (cairo_xlib_surface_t *) surface;
|
||||
cairo_image_surface_t *tmp = NULL;
|
||||
cairo_xlib_surface_t *src = NULL;
|
||||
glyphset_cache_t *g;
|
||||
cairo_status_t status;
|
||||
cairo_glyph_cache_key_t key;
|
||||
glyphset_cache_entry_t **entries;
|
||||
glyphset_cache_entry_t *stack_entries [N_STACK_BUF];
|
||||
int i;
|
||||
|
||||
/* Acquire an entry array of suitable size. */
|
||||
if (num_glyphs < N_STACK_BUF) {
|
||||
entries = stack_entries;
|
||||
|
||||
} else {
|
||||
entries = malloc (num_glyphs * sizeof (glyphset_cache_entry_t *));
|
||||
if (entries == NULL)
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
/* prep the source surface. */
|
||||
if (source->backend == surface->backend) {
|
||||
src = (cairo_xlib_surface_t *) source;
|
||||
|
||||
} else {
|
||||
tmp = _cairo_surface_get_image (source);
|
||||
if (tmp == NULL)
|
||||
goto FREE_ENTRIES;
|
||||
|
||||
src = (cairo_xlib_surface_t *)
|
||||
_cairo_surface_create_similar_scratch (surface, self->format, 1,
|
||||
tmp->width, tmp->height);
|
||||
|
||||
if (src == NULL)
|
||||
goto FREE_TMP;
|
||||
|
||||
if (_cairo_surface_set_image (&(src->base), tmp) != CAIRO_STATUS_SUCCESS)
|
||||
goto FREE_SRC;
|
||||
}
|
||||
|
||||
_lock_xlib_glyphset_caches ();
|
||||
g = _get_glyphset_cache (self->dpy);
|
||||
if (g == NULL)
|
||||
goto UNLOCK;
|
||||
|
||||
/* Work out the index size to use. */
|
||||
elt_size = 8;
|
||||
key.scale = *scale;
|
||||
key.unscaled = font;
|
||||
|
||||
for (i = 0; i < num_glyphs; ++i) {
|
||||
key.index = glyphs[i].index;
|
||||
status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]));
|
||||
if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL)
|
||||
goto UNLOCK;
|
||||
|
||||
if (elt_size == 8 && entries[i]->glyph > 0xff)
|
||||
elt_size = 16;
|
||||
if (elt_size == 16 && entries[i]->glyph > 0xffff) {
|
||||
elt_size = 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the appropriate sub-function. */
|
||||
|
||||
if (elt_size == 8)
|
||||
status = _cairo_xlib_surface_show_glyphs8 (font, scale, operator, g, &key, src, self,
|
||||
source_x, source_y,
|
||||
glyphs, entries, num_glyphs);
|
||||
else if (elt_size == 16)
|
||||
status = _cairo_xlib_surface_show_glyphs16 (font, scale, operator, g, &key, src, self,
|
||||
source_x, source_y,
|
||||
glyphs, entries, num_glyphs);
|
||||
else
|
||||
status = _cairo_xlib_surface_show_glyphs32 (font, scale, operator, g, &key, src, self,
|
||||
source_x, source_y,
|
||||
glyphs, entries, num_glyphs);
|
||||
|
||||
_unlock_xlib_glyphset_caches ();
|
||||
|
||||
if (tmp != NULL) {
|
||||
cairo_surface_destroy (&(src->base));
|
||||
cairo_surface_destroy (&(tmp->base));
|
||||
}
|
||||
|
||||
if (num_glyphs >= N_STACK_BUF)
|
||||
free (entries);
|
||||
|
||||
return status;
|
||||
|
||||
UNLOCK:
|
||||
_unlock_xlib_glyphset_caches ();
|
||||
|
||||
FREE_SRC:
|
||||
cairo_surface_destroy (&(src->base));
|
||||
|
||||
FREE_TMP:
|
||||
cairo_surface_destroy (&(tmp->base));
|
||||
|
||||
FREE_ENTRIES:
|
||||
if (num_glyphs >= N_STACK_BUF)
|
||||
free (entries);
|
||||
|
||||
FAIL:
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
|
|
|||
53
src/cairo.c
53
src/cairo.c
|
|
@ -900,12 +900,27 @@ cairo_text_extents (cairo_t *cr,
|
|||
const unsigned char *utf8,
|
||||
cairo_text_extents_t *extents)
|
||||
{
|
||||
cairo_glyph_t *glyphs = NULL;
|
||||
int nglyphs;
|
||||
|
||||
CAIRO_CHECK_SANITY (cr);
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_text_extents (cr->gstate, utf8, extents);
|
||||
|
||||
cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
|
||||
CAIRO_CHECK_SANITY (cr);
|
||||
|
||||
if (cr->status) {
|
||||
if (glyphs)
|
||||
free (glyphs);
|
||||
return;
|
||||
}
|
||||
|
||||
cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, nglyphs, extents);
|
||||
CAIRO_CHECK_SANITY (cr);
|
||||
|
||||
if (glyphs)
|
||||
free (glyphs);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -926,6 +941,9 @@ cairo_glyph_extents (cairo_t *cr,
|
|||
void
|
||||
cairo_show_text (cairo_t *cr, const unsigned char *utf8)
|
||||
{
|
||||
cairo_glyph_t *glyphs = NULL;
|
||||
int nglyphs;
|
||||
|
||||
CAIRO_CHECK_SANITY (cr);
|
||||
if (cr->status)
|
||||
return;
|
||||
|
|
@ -933,8 +951,20 @@ cairo_show_text (cairo_t *cr, const unsigned char *utf8)
|
|||
if (utf8 == NULL)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_show_text (cr->gstate, utf8);
|
||||
cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
|
||||
CAIRO_CHECK_SANITY (cr);
|
||||
|
||||
if (cr->status) {
|
||||
if (glyphs)
|
||||
free (glyphs);
|
||||
return;
|
||||
}
|
||||
|
||||
cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, nglyphs);
|
||||
CAIRO_CHECK_SANITY (cr);
|
||||
|
||||
if (glyphs)
|
||||
free (glyphs);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -951,12 +981,27 @@ cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
|
|||
void
|
||||
cairo_text_path (cairo_t *cr, const unsigned char *utf8)
|
||||
{
|
||||
cairo_glyph_t *glyphs = NULL;
|
||||
int nglyphs;
|
||||
|
||||
CAIRO_CHECK_SANITY (cr);
|
||||
if (cr->status)
|
||||
return;
|
||||
|
||||
cr->status = _cairo_gstate_text_path (cr->gstate, utf8);
|
||||
cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
|
||||
CAIRO_CHECK_SANITY (cr);
|
||||
|
||||
if (cr->status) {
|
||||
if (glyphs)
|
||||
free (glyphs);
|
||||
return;
|
||||
}
|
||||
|
||||
cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, nglyphs);
|
||||
CAIRO_CHECK_SANITY (cr);
|
||||
|
||||
if (glyphs)
|
||||
free (glyphs);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
454
src/cairo_cache.c
Normal file
454
src/cairo_cache.c
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* This file is Copyright © 2004 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it either under the terms of the GNU Lesser General Public
|
||||
* License version 2.1 as published by the Free Software Foundation
|
||||
* (the "LGPL") or, at your option, under the terms of the Mozilla
|
||||
* Public License Version 1.1 (the "MPL"). If you do not alter this
|
||||
* notice, a recipient may use your version of this file under either
|
||||
* the MPL or the LGPL.
|
||||
*
|
||||
* You should have received a copy of the LGPL along with this library
|
||||
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* You should have received a copy of the MPL along with this library
|
||||
* in the file COPYING-MPL-1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
||||
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
||||
* the specific language governing rights and limitations.
|
||||
*
|
||||
* The Original Code is the cairo graphics library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Red Hat, Inc.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Keith Packard
|
||||
* Graydon Hoare <graydon@redhat.com>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
/*
|
||||
* This structure, and accompanying table, is borrowed/modified from the
|
||||
* file xserver/render/glyph.c in the freedesktop.org x server, with
|
||||
* permission (and suggested modification of doubling sizes) by Keith
|
||||
* Packard.
|
||||
*/
|
||||
|
||||
static cairo_cache_arrangement_t cache_arrangements [] = {
|
||||
{ 16, 43, 41 },
|
||||
{ 32, 73, 71 },
|
||||
{ 64, 151, 149 },
|
||||
{ 128, 283, 281 },
|
||||
{ 256, 571, 569 },
|
||||
{ 512, 1153, 1151 },
|
||||
{ 1024, 2269, 2267 },
|
||||
{ 2048, 4519, 4517 },
|
||||
{ 4096, 9013, 9011 },
|
||||
{ 8192, 18043, 18041 },
|
||||
{ 16384, 36109, 36107 },
|
||||
{ 32768, 72091, 72089 },
|
||||
{ 65536, 144409, 144407 },
|
||||
{ 131072, 288361, 288359 },
|
||||
{ 262144, 576883, 576881 },
|
||||
{ 524288, 1153459, 1153457 },
|
||||
{ 1048576, 2307163, 2307161 },
|
||||
{ 2097152, 4613893, 4613891 },
|
||||
{ 4194304, 9227641, 9227639 },
|
||||
{ 8388608, 18455029, 18455027 },
|
||||
{ 16777216, 36911011, 36911009 },
|
||||
{ 33554432, 73819861, 73819859 },
|
||||
{ 67108864, 147639589, 147639587 },
|
||||
{ 134217728, 295279081, 295279079 },
|
||||
{ 268435456, 590559793, 590559791 }
|
||||
};
|
||||
|
||||
#define N_CACHE_SIZES (sizeof(cache_arrangements)/sizeof(cache_arrangements[0]))
|
||||
|
||||
/*
|
||||
* Entries 'e' are poiners, in one of 3 states:
|
||||
*
|
||||
* e == NULL: The entry has never had anything put in it
|
||||
* e != DEAD_ENTRY: The entry has an active value in it currently
|
||||
* e == DEAD_ENTRY: The entry *had* a value in it at some point, but the
|
||||
* entry has been killed. Lookups requesting free space can
|
||||
* reuse these entries; lookups requesting a precise match
|
||||
* should neither return these entries nor stop searching when
|
||||
* seeing these entries.
|
||||
*
|
||||
* We expect keys will not be destroyed frequently, so our table does not
|
||||
* contain any explicit shrinking code nor any chain-coalescing code for
|
||||
* entries randomly deleted by memory pressure (except during rehashing, of
|
||||
* course). These assumptions are potentially bad, but they make the
|
||||
* implementation straightforward.
|
||||
*
|
||||
* Revisit later if evidence appears that we're using excessive memory from
|
||||
* a mostly-dead table.
|
||||
*
|
||||
* Generally you do not need to worry about freeing cache entries; the
|
||||
* cache will expire entries randomly as it experiences memory pressure.
|
||||
* There is currently no explicit entry-removing call, though one can be
|
||||
* added easily.
|
||||
*
|
||||
* This table is open-addressed with double hashing. Each table size is a
|
||||
* prime chosen to be a little more than double the high water mark for a
|
||||
* given arrangement, so the tables should remain < 50% full. The table
|
||||
* size makes for the "first" hash modulus; a second prime (2 less than the
|
||||
* first prime) serves as the "second" hash modulus, which is co-prime and
|
||||
* thus guarantees a complete permutation of table indices.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DEAD_ENTRY ((cairo_cache_entry_base_t *) 1)
|
||||
#define NULL_ENTRY_P(cache, i) ((cache)->entries[i] == NULL)
|
||||
#define DEAD_ENTRY_P(cache, i) ((cache)->entries[i] == DEAD_ENTRY)
|
||||
#define LIVE_ENTRY_P(cache, i) \
|
||||
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
|
||||
|
||||
#ifdef CAIRO_DO_SANITY_CHECKING
|
||||
#include <assert.h>
|
||||
static void
|
||||
_cache_sane_state (cairo_cache_t *cache)
|
||||
{
|
||||
assert (cache != NULL);
|
||||
assert (cache->entries != NULL);
|
||||
assert (cache->backend != NULL);
|
||||
assert (cache->arrangement != NULL);
|
||||
assert (cache->refcount > 0);
|
||||
assert (cache->used_memory <= cache->max_memory);
|
||||
assert (cache->live_entries <= cache->arrangement->size);
|
||||
}
|
||||
#else
|
||||
#define _cache_sane_state(c)
|
||||
#define assert(x)
|
||||
#endif
|
||||
|
||||
static void
|
||||
_entry_destroy (cairo_cache_t *cache, unsigned long i)
|
||||
{
|
||||
_cache_sane_state (cache);
|
||||
|
||||
if (LIVE_ENTRY_P(cache, i))
|
||||
{
|
||||
cairo_cache_entry_base_t *entry = cache->entries[i];
|
||||
assert(cache->live_entries > 0);
|
||||
assert(cache->used_memory > entry->memory);
|
||||
|
||||
cache->live_entries--;
|
||||
cache->used_memory -= entry->memory;
|
||||
cache->backend->destroy_entry (cache, entry);
|
||||
cache->entries[i] = DEAD_ENTRY;
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_cache_entry_base_t **
|
||||
_cache_lookup (cairo_cache_t *cache,
|
||||
void *key,
|
||||
int (*predicate)(void*,void*,void*))
|
||||
{
|
||||
|
||||
cairo_cache_entry_base_t **probe;
|
||||
unsigned long hash;
|
||||
unsigned long table_size, i, idx, step;
|
||||
|
||||
_cache_sane_state (cache);
|
||||
assert (key != NULL);
|
||||
|
||||
table_size = cache->arrangement->size;
|
||||
hash = cache->backend->hash (cache, key);
|
||||
idx = hash % table_size;
|
||||
step = 0;
|
||||
|
||||
for (i = 0; i < table_size; ++i)
|
||||
{
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->probes++;
|
||||
#endif
|
||||
assert(idx < table_size);
|
||||
probe = cache->entries + idx;
|
||||
|
||||
/*
|
||||
* There are two lookup modes: searching for a free slot and searching
|
||||
* for an exact entry.
|
||||
*/
|
||||
|
||||
if (predicate != NULL)
|
||||
{
|
||||
/* We are looking up an exact entry. */
|
||||
if (*probe != NULL
|
||||
&& *probe != DEAD_ENTRY
|
||||
&& (*probe)->hashcode == hash
|
||||
&& predicate (cache, key, *probe))
|
||||
return probe;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We are just looking for a free slot. */
|
||||
if (*probe == NULL
|
||||
|| *probe == DEAD_ENTRY)
|
||||
return probe;
|
||||
}
|
||||
|
||||
if (step == 0) {
|
||||
step = hash % cache->arrangement->rehash;
|
||||
if (step == 0)
|
||||
step = 1;
|
||||
}
|
||||
|
||||
idx += step;
|
||||
if (idx >= table_size)
|
||||
idx -= table_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* The table should not have permitted you to get here if you were just
|
||||
* looking for a free slot: there should have been room.
|
||||
*/
|
||||
assert(predicate != NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static cairo_cache_entry_base_t **
|
||||
_find_available_entry_for (cairo_cache_t *cache,
|
||||
void *key)
|
||||
{
|
||||
return _cache_lookup (cache, key, NULL);
|
||||
}
|
||||
|
||||
static cairo_cache_entry_base_t **
|
||||
_find_exact_live_entry_for (cairo_cache_t *cache,
|
||||
void *key)
|
||||
{
|
||||
return _cache_lookup (cache, key, cache->backend->keys_equal);
|
||||
}
|
||||
|
||||
|
||||
static cairo_cache_arrangement_t *
|
||||
_find_cache_arrangement (unsigned long proposed_size)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
for (idx = 0; idx < N_CACHE_SIZES; ++idx)
|
||||
if (cache_arrangements[idx].high_water_mark >= proposed_size)
|
||||
return &cache_arrangements[idx];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_resize_cache (cairo_cache_t *cache, unsigned long proposed_size)
|
||||
{
|
||||
cairo_cache_t tmp;
|
||||
cairo_cache_entry_base_t **e;
|
||||
unsigned long new_size, i;
|
||||
|
||||
tmp = *cache;
|
||||
tmp.arrangement = _find_cache_arrangement (proposed_size);
|
||||
assert(tmp.arrangement != NULL);
|
||||
if (tmp.arrangement == cache->arrangement)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
new_size = tmp.arrangement->size;
|
||||
tmp.entries = calloc (new_size, sizeof (cairo_cache_entry_base_t *));
|
||||
if (tmp.entries == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
for (i = 0; i < cache->arrangement->size; ++i) {
|
||||
if (LIVE_ENTRY_P(cache, i)) {
|
||||
e = _find_available_entry_for (&tmp, cache->entries[i]);
|
||||
assert (e != NULL);
|
||||
*e = cache->entries[i];
|
||||
}
|
||||
}
|
||||
free (cache->entries);
|
||||
cache->entries = tmp.entries;
|
||||
cache->arrangement = tmp.arrangement;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
static double
|
||||
_load_factor (cairo_cache_t *cache)
|
||||
{
|
||||
return ((double) cache->live_entries)
|
||||
/ ((double) cache->arrangement->size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned long
|
||||
_random_live_entry (cairo_cache_t *cache)
|
||||
{
|
||||
unsigned long idx;
|
||||
assert(cache != NULL);
|
||||
do {
|
||||
idx = rand () % cache->arrangement->size;
|
||||
} while (! LIVE_ENTRY_P(cache, idx));
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
/* public API follows */
|
||||
|
||||
cairo_status_t
|
||||
_cairo_cache_init (cairo_cache_t *cache,
|
||||
const cairo_cache_backend_t *backend,
|
||||
unsigned long max_memory)
|
||||
{
|
||||
assert(backend != NULL);
|
||||
|
||||
if (cache != NULL){
|
||||
cache->arrangement = &cache_arrangements[0];
|
||||
cache->refcount = 1;
|
||||
cache->max_memory = max_memory;
|
||||
cache->used_memory = 0;
|
||||
cache->live_entries = 0;
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->hits = 0;
|
||||
cache->misses = 0;
|
||||
cache->probes = 0;
|
||||
#endif
|
||||
|
||||
cache->backend = backend;
|
||||
cache->entries = calloc (sizeof(cairo_cache_entry_base_t *),
|
||||
cache->arrangement->size);
|
||||
if (cache->entries == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
_cache_sane_state (cache);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_cache_reference (cairo_cache_t *cache)
|
||||
{
|
||||
_cache_sane_state (cache);
|
||||
cache->refcount++;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_cache_destroy (cairo_cache_t *cache)
|
||||
{
|
||||
unsigned long i;
|
||||
if (cache != NULL) {
|
||||
|
||||
_cache_sane_state (cache);
|
||||
|
||||
if (cache->refcount-- > 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < cache->arrangement->size; ++i) {
|
||||
_entry_destroy (cache, i);
|
||||
}
|
||||
|
||||
free (cache->entries);
|
||||
cache->entries = NULL;
|
||||
cache->backend->destroy_cache (cache);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_cache_lookup (cairo_cache_t *cache,
|
||||
void *key,
|
||||
void **entry_return)
|
||||
{
|
||||
|
||||
unsigned long idx;
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
cairo_cache_entry_base_t **slot = NULL, *new_entry;
|
||||
|
||||
_cache_sane_state (cache);
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
if ((cache->hits + cache->misses) % 0xffff == 0)
|
||||
printf("cache %p stats: size %ld, live %ld, load %.2f\n"
|
||||
" mem %ld/%ld, hit %ld, miss %ld\n"
|
||||
" probe %ld, %.2f probe/access\n",
|
||||
cache,
|
||||
cache->arrangement->size,
|
||||
cache->live_entries,
|
||||
_load_factor (cache),
|
||||
cache->used_memory,
|
||||
cache->max_memory,
|
||||
cache->hits,
|
||||
cache->misses,
|
||||
cache->probes,
|
||||
((double) cache->probes)
|
||||
/ ((double) (cache->hits +
|
||||
cache->misses + 1)));
|
||||
#endif
|
||||
|
||||
/* See if we have an entry in the table already. */
|
||||
slot = _find_exact_live_entry_for (cache, key);
|
||||
if (slot != NULL) {
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->hits++;
|
||||
#endif
|
||||
*entry_return = *slot;
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
cache->misses++;
|
||||
#endif
|
||||
|
||||
/* Build the new entry. */
|
||||
status = cache->backend->create_entry (cache, key,
|
||||
entry_return);
|
||||
if (status != CAIRO_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
new_entry = (cairo_cache_entry_base_t *) (*entry_return);
|
||||
|
||||
/* Store the hash value in case the backend forgot. */
|
||||
new_entry->hashcode = cache->backend->hash (cache, key);
|
||||
|
||||
/* Make some entries die if we're under memory pressure. */
|
||||
while (cache->live_entries > 0 &&
|
||||
((cache->max_memory - cache->used_memory) < new_entry->memory)) {
|
||||
idx = _random_live_entry (cache);
|
||||
assert (idx < cache->arrangement->size);
|
||||
_entry_destroy (cache, idx);
|
||||
}
|
||||
|
||||
assert(cache->max_memory >= (cache->used_memory + new_entry->memory));
|
||||
|
||||
/* Make room in the table for a new slot. */
|
||||
status = _resize_cache (cache, cache->live_entries + 1);
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
cache->backend->destroy_entry (cache, new_entry);
|
||||
*entry_return = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
slot = _find_available_entry_for (cache, key);
|
||||
assert(slot != NULL);
|
||||
|
||||
/* Store entry in slot and increment statistics. */
|
||||
*slot = new_entry;
|
||||
cache->live_entries++;
|
||||
cache->used_memory += new_entry->memory;
|
||||
|
||||
_cache_sane_state (cache);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
_cairo_hash_string (const char *c)
|
||||
{
|
||||
/* This is the djb2 hash. */
|
||||
unsigned long hash = 5381;
|
||||
while (*c)
|
||||
hash = ((hash << 5) + hash) + *c++;
|
||||
return hash;
|
||||
}
|
||||
|
||||
731
src/cairo_font.c
731
src/cairo_font.c
|
|
@ -36,20 +36,60 @@
|
|||
|
||||
#include "cairoint.h"
|
||||
|
||||
static cairo_glyph_cache_t *
|
||||
_cairo_glyph_cache_create (void);
|
||||
|
||||
static void
|
||||
_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache);
|
||||
/* First we implement a global font cache for named fonts. */
|
||||
|
||||
static void
|
||||
_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache);
|
||||
typedef struct {
|
||||
cairo_cache_entry_base_t base;
|
||||
const char *family;
|
||||
cairo_font_slant_t slant;
|
||||
cairo_font_weight_t weight;
|
||||
} cairo_font_cache_key_t;
|
||||
|
||||
cairo_font_t *
|
||||
_cairo_font_create (const char *family,
|
||||
cairo_font_slant_t slant,
|
||||
cairo_font_weight_t weight)
|
||||
typedef struct {
|
||||
cairo_font_cache_key_t key;
|
||||
cairo_unscaled_font_t *unscaled;
|
||||
} cairo_font_cache_entry_t;
|
||||
|
||||
static unsigned long
|
||||
_font_cache_hash (void *cache, void *key)
|
||||
{
|
||||
cairo_font_cache_key_t *in;
|
||||
in = (cairo_font_cache_key_t *) key;
|
||||
unsigned long hash;
|
||||
|
||||
/* 1607 and 1451 are just a couple random primes. */
|
||||
hash = _cairo_hash_string (in->family);
|
||||
hash += ((unsigned long) in->slant) * 1607;
|
||||
hash += ((unsigned long) in->weight) * 1451;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_font_cache_keys_equal (void *cache,
|
||||
void *k1,
|
||||
void *k2)
|
||||
{
|
||||
cairo_font_cache_key_t *a, *b;
|
||||
a = (cairo_font_cache_key_t *) k1;
|
||||
b = (cairo_font_cache_key_t *) k2;
|
||||
|
||||
return (strcmp (a->family, b->family) == 0)
|
||||
&& (a->weight == b->weight)
|
||||
&& (a->slant == b->slant);
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_font_cache_create_entry (void *cache,
|
||||
void *key,
|
||||
void **return_value)
|
||||
{
|
||||
cairo_font_cache_key_t *k;
|
||||
cairo_font_cache_entry_t *entry;
|
||||
k = (cairo_font_cache_key_t *) key;
|
||||
|
||||
const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT;
|
||||
|
||||
/* XXX: The current freetype backend may return NULL, (for example
|
||||
|
|
@ -58,336 +98,250 @@ _cairo_font_create (const char *family,
|
|||
* like to build in some sort fo font here, (even a really lame,
|
||||
* ugly one if necessary). */
|
||||
|
||||
return backend->create (family, slant, weight);
|
||||
entry = malloc (sizeof (cairo_font_cache_entry_t));
|
||||
if (entry == NULL)
|
||||
goto FAIL;
|
||||
|
||||
entry->key.slant = k->slant;
|
||||
entry->key.weight = k->weight;
|
||||
entry->key.family = strdup(k->family);
|
||||
if (entry->key.family == NULL)
|
||||
goto FREE_ENTRY;
|
||||
|
||||
entry->unscaled = backend->create (k->family, k->slant, k->weight);
|
||||
if (entry->unscaled == NULL)
|
||||
goto FREE_FAMILY;
|
||||
|
||||
/* Not sure how to measure backend font mem; use a simple count for now.*/
|
||||
entry->key.base.memory = 1;
|
||||
*return_value = entry;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
FREE_FAMILY:
|
||||
free ((void *) entry->key.family);
|
||||
|
||||
FREE_ENTRY:
|
||||
free (entry);
|
||||
|
||||
FAIL:
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
static void
|
||||
_font_cache_destroy_entry (void *cache,
|
||||
void *entry)
|
||||
{
|
||||
cairo_font_cache_entry_t *e;
|
||||
|
||||
e = (cairo_font_cache_entry_t *) entry;
|
||||
_cairo_unscaled_font_destroy (e->unscaled);
|
||||
free ((void *) e->key.family);
|
||||
free (e);
|
||||
}
|
||||
|
||||
static void
|
||||
_font_cache_destroy_cache (void *cache)
|
||||
{
|
||||
free (cache);
|
||||
}
|
||||
|
||||
const struct cairo_cache_backend cairo_font_cache_backend = {
|
||||
_font_cache_hash,
|
||||
_font_cache_keys_equal,
|
||||
_font_cache_create_entry,
|
||||
_font_cache_destroy_entry,
|
||||
_font_cache_destroy_cache
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
_lock_global_font_cache (void)
|
||||
{
|
||||
/* FIXME: implement locking. */
|
||||
}
|
||||
|
||||
static void
|
||||
_unlock_global_font_cache (void)
|
||||
{
|
||||
/* FIXME: implement locking. */
|
||||
}
|
||||
|
||||
static cairo_cache_t *
|
||||
_global_font_cache = NULL;
|
||||
|
||||
static cairo_cache_t *
|
||||
_get_global_font_cache (void)
|
||||
{
|
||||
if (_global_font_cache == NULL) {
|
||||
_global_font_cache = malloc (sizeof (cairo_cache_t));
|
||||
|
||||
if (_global_font_cache == NULL)
|
||||
goto FAIL;
|
||||
|
||||
if (_cairo_cache_init (_global_font_cache,
|
||||
&cairo_font_cache_backend,
|
||||
CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT))
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
return _global_font_cache;
|
||||
|
||||
FAIL:
|
||||
if (_global_font_cache)
|
||||
free (_global_font_cache);
|
||||
_global_font_cache = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Now the internal "unscaled + scale" font API */
|
||||
|
||||
cairo_unscaled_font_t *
|
||||
_cairo_unscaled_font_create (const char *family,
|
||||
cairo_font_slant_t slant,
|
||||
cairo_font_weight_t weight)
|
||||
{
|
||||
cairo_cache_t * cache;
|
||||
cairo_font_cache_key_t key;
|
||||
cairo_font_cache_entry_t *font;
|
||||
cairo_status_t status;
|
||||
|
||||
_lock_global_font_cache ();
|
||||
cache = _get_global_font_cache ();
|
||||
if (cache == NULL) {
|
||||
_unlock_global_font_cache ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key.family = family;
|
||||
key.slant = slant;
|
||||
key.weight = weight;
|
||||
|
||||
status = _cairo_cache_lookup (cache, &key, (void **) &font);
|
||||
if (status) {
|
||||
_unlock_global_font_cache ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_cairo_unscaled_font_reference (font->unscaled);
|
||||
_unlock_global_font_cache ();
|
||||
return font->unscaled;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_font_init (cairo_font_t *scaled,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_unscaled_font_t *unscaled)
|
||||
{
|
||||
scaled->scale = *scale;
|
||||
scaled->unscaled = unscaled;
|
||||
scaled->refcount = 1;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_init (cairo_font_t *font,
|
||||
const struct cairo_font_backend *backend)
|
||||
_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
|
||||
const struct cairo_font_backend *backend)
|
||||
{
|
||||
cairo_matrix_set_identity (&font->matrix);
|
||||
font->refcount = 1;
|
||||
font->backend = backend;
|
||||
font->glyph_cache = _cairo_glyph_cache_create ();
|
||||
if (font->glyph_cache == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_font_t *
|
||||
_cairo_font_copy (cairo_font_t *font)
|
||||
{
|
||||
cairo_font_t *newfont = NULL;
|
||||
char *tmp = NULL;
|
||||
|
||||
if (font == NULL || font->backend->copy == NULL)
|
||||
return NULL;
|
||||
|
||||
newfont = font->backend->copy (font);
|
||||
if (newfont == NULL) {
|
||||
free (tmp);
|
||||
return NULL;
|
||||
cairo_status_t
|
||||
_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
const unsigned char *utf8,
|
||||
cairo_glyph_t **glyphs,
|
||||
int *num_glyphs)
|
||||
{
|
||||
return font->backend->text_to_glyphs (font, scale, utf8, glyphs, num_glyphs);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_text_extents_t *extents)
|
||||
{
|
||||
return font->backend->glyph_extents(font, scale, glyphs, num_glyphs, extents);
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_box_t *bbox)
|
||||
{
|
||||
return font->backend->glyph_bbox (font, scale, glyphs, num_glyphs, bbox);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs)
|
||||
{
|
||||
cairo_status_t status;
|
||||
if (surface->backend->show_glyphs != NULL) {
|
||||
status = surface->backend->show_glyphs (font, scale, operator, source,
|
||||
surface, source_x, source_y,
|
||||
glyphs, num_glyphs);
|
||||
if (status == CAIRO_STATUS_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
newfont->refcount = 1;
|
||||
cairo_matrix_copy(&newfont->matrix, &font->matrix);
|
||||
newfont->backend = font->backend;
|
||||
|
||||
if (newfont->glyph_cache)
|
||||
_cairo_glyph_cache_destroy (newfont->glyph_cache);
|
||||
|
||||
newfont->glyph_cache = font->glyph_cache;
|
||||
_cairo_glyph_cache_reference (font->glyph_cache);
|
||||
|
||||
return newfont;
|
||||
/* Surface display routine either does not exist or failed. */
|
||||
return font->backend->show_glyphs (font, scale, operator, source,
|
||||
surface, source_x, source_y,
|
||||
glyphs, num_glyphs);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_scale (cairo_font_t *font, double scale)
|
||||
_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_path_t *path)
|
||||
{
|
||||
return cairo_matrix_scale (&font->matrix, scale, scale);
|
||||
return font->backend->glyph_path (font, scale, glyphs, num_glyphs, path);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_transform (cairo_font_t *font, cairo_matrix_t *matrix)
|
||||
_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_font_extents_t *extents)
|
||||
{
|
||||
return cairo_matrix_multiply (&font->matrix, matrix, &font->matrix);
|
||||
return font->backend->font_extents(font, scale, extents);
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_text_extents (cairo_font_t *font,
|
||||
const unsigned char *utf8,
|
||||
cairo_text_extents_t *extents)
|
||||
void
|
||||
_cairo_unscaled_font_reference (cairo_unscaled_font_t *font)
|
||||
{
|
||||
return font->backend->text_extents(font, utf8, extents);
|
||||
font->refcount++;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_glyph_extents (cairo_font_t *font,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_text_extents_t *extents)
|
||||
{
|
||||
return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_text_bbox (cairo_font_t *font,
|
||||
cairo_surface_t *surface,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8,
|
||||
cairo_box_t *bbox)
|
||||
{
|
||||
return font->backend->text_bbox (font, surface, x, y, utf8, bbox);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_glyph_bbox (cairo_font_t *font,
|
||||
cairo_surface_t *surface,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_box_t *bbox)
|
||||
{
|
||||
return font->backend->glyph_bbox (font, surface, glyphs, num_glyphs, bbox);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_show_text (cairo_font_t *font,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8)
|
||||
{
|
||||
return font->backend->show_text(font, operator, source,
|
||||
surface, source_x, source_y, x, y, utf8);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_show_glyphs (cairo_font_t *font,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs)
|
||||
{
|
||||
return font->backend->show_glyphs(font, operator, source,
|
||||
surface, source_x, source_y,
|
||||
glyphs, num_glyphs);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_text_path (cairo_font_t *font,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8,
|
||||
cairo_path_t *path)
|
||||
{
|
||||
return font->backend->text_path(font, x, y, utf8, path);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_glyph_path (cairo_font_t *font,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_path_t *path)
|
||||
{
|
||||
return font->backend->glyph_path(font, glyphs, num_glyphs, path);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_font_font_extents (cairo_font_t *font,
|
||||
cairo_font_extents_t *extents)
|
||||
{
|
||||
return font->backend->font_extents(font, extents);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_glyph_cache_pop_last (cairo_glyph_cache_t *glyph_cache)
|
||||
{
|
||||
if (glyph_cache->last) {
|
||||
cairo_glyph_surface_node_t *remove = glyph_cache->last;
|
||||
|
||||
cairo_surface_destroy (remove->s.surface);
|
||||
glyph_cache->last = remove->prev;
|
||||
if (glyph_cache->last)
|
||||
glyph_cache->last->next = NULL;
|
||||
|
||||
free (remove);
|
||||
glyph_cache->n_nodes--;
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_glyph_cache_t *
|
||||
_cairo_glyph_cache_create (void)
|
||||
{
|
||||
cairo_glyph_cache_t *glyph_cache;
|
||||
|
||||
glyph_cache = malloc (sizeof (cairo_glyph_cache_t));
|
||||
if (glyph_cache == NULL)
|
||||
return NULL;
|
||||
|
||||
glyph_cache->n_nodes = 0;
|
||||
glyph_cache->first = NULL;
|
||||
glyph_cache->last = NULL;
|
||||
glyph_cache->cache_size = CAIRO_FONT_CACHE_SIZE_DEFAULT;
|
||||
glyph_cache->ref_count = 1;
|
||||
|
||||
return glyph_cache;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache)
|
||||
{
|
||||
if (glyph_cache == NULL)
|
||||
void
|
||||
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font)
|
||||
{
|
||||
if (--(font->refcount) > 0)
|
||||
return;
|
||||
|
||||
glyph_cache->ref_count++;
|
||||
if (font->backend)
|
||||
font->backend->destroy (font);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache)
|
||||
{
|
||||
if (glyph_cache == NULL)
|
||||
return;
|
||||
|
||||
glyph_cache->ref_count--;
|
||||
if (glyph_cache->ref_count)
|
||||
return;
|
||||
|
||||
while (glyph_cache->last)
|
||||
_cairo_glyph_cache_pop_last (glyph_cache);
|
||||
|
||||
free (glyph_cache);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_glyph_surface_init (cairo_font_t *font,
|
||||
cairo_surface_t *surface,
|
||||
const cairo_glyph_t *glyph,
|
||||
cairo_glyph_surface_t *glyph_surface)
|
||||
{
|
||||
cairo_surface_t *image;
|
||||
|
||||
glyph_surface->surface = NULL;
|
||||
glyph_surface->index = glyph->index;
|
||||
glyph_surface->matrix[0][0] = font->matrix.m[0][0];
|
||||
glyph_surface->matrix[0][1] = font->matrix.m[0][1];
|
||||
glyph_surface->matrix[1][0] = font->matrix.m[1][0];
|
||||
glyph_surface->matrix[1][1] = font->matrix.m[1][1];
|
||||
|
||||
image = font->backend->create_glyph (font, glyph, &glyph_surface->size);
|
||||
if (image == NULL)
|
||||
return;
|
||||
|
||||
if (surface->backend != image->backend) {
|
||||
cairo_status_t status;
|
||||
|
||||
glyph_surface->surface =
|
||||
_cairo_surface_create_similar_scratch (surface,
|
||||
CAIRO_FORMAT_A8, 0,
|
||||
glyph_surface->size.width,
|
||||
glyph_surface->size.height);
|
||||
if (glyph_surface->surface == NULL) {
|
||||
glyph_surface->surface = image;
|
||||
return;
|
||||
}
|
||||
|
||||
status = _cairo_surface_set_image (glyph_surface->surface,
|
||||
(cairo_image_surface_t *) image);
|
||||
if (status) {
|
||||
cairo_surface_destroy (glyph_surface->surface);
|
||||
glyph_surface->surface = NULL;
|
||||
}
|
||||
cairo_surface_destroy (image);
|
||||
} else
|
||||
glyph_surface->surface = image;
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
_cairo_font_lookup_glyph (cairo_font_t *font,
|
||||
cairo_surface_t *surface,
|
||||
const cairo_glyph_t *glyph,
|
||||
cairo_glyph_size_t *return_size)
|
||||
{
|
||||
cairo_glyph_surface_t glyph_surface;
|
||||
cairo_glyph_cache_t *cache = font->glyph_cache;
|
||||
cairo_glyph_surface_node_t *node;
|
||||
|
||||
for (node = cache->first; node != NULL; node = node->next) {
|
||||
cairo_glyph_surface_t *s = &node->s;
|
||||
|
||||
if ((s->surface == NULL || s->surface->backend == surface->backend) &&
|
||||
s->index == glyph->index &&
|
||||
s->matrix[0][0] == font->matrix.m[0][0] &&
|
||||
s->matrix[0][1] == font->matrix.m[0][1] &&
|
||||
s->matrix[1][0] == font->matrix.m[1][0] &&
|
||||
s->matrix[1][1] == font->matrix.m[1][1]) {
|
||||
|
||||
/* move node first in cache */
|
||||
if (node->prev) {
|
||||
if (node->next == NULL) {
|
||||
cache->last = node->prev;
|
||||
node->prev->next = NULL;
|
||||
} else {
|
||||
node->prev->next = node->next;
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
|
||||
node->prev = NULL;
|
||||
node->next = cache->first;
|
||||
cache->first = node;
|
||||
if (node->next)
|
||||
node->next->prev = node;
|
||||
else
|
||||
cache->last = node;
|
||||
}
|
||||
|
||||
cairo_surface_reference (s->surface);
|
||||
*return_size = s->size;
|
||||
|
||||
return s->surface;
|
||||
}
|
||||
}
|
||||
|
||||
_cairo_glyph_surface_init (font, surface, glyph, &glyph_surface);
|
||||
|
||||
*return_size = glyph_surface.size;
|
||||
|
||||
if (cache->cache_size > 0) {
|
||||
if (cache->n_nodes == cache->cache_size)
|
||||
_cairo_glyph_cache_pop_last (cache);
|
||||
|
||||
node = malloc (sizeof (cairo_glyph_surface_node_t));
|
||||
if (node) {
|
||||
cairo_surface_reference (glyph_surface.surface);
|
||||
|
||||
/* insert node first in cache */
|
||||
node->s = glyph_surface;
|
||||
node->prev = NULL;
|
||||
node->next = cache->first;
|
||||
cache->first = node;
|
||||
if (node->next)
|
||||
node->next->prev = node;
|
||||
else
|
||||
cache->last = node;
|
||||
|
||||
cache->n_nodes++;
|
||||
}
|
||||
}
|
||||
|
||||
return glyph_surface.surface;
|
||||
}
|
||||
|
||||
/* public font interface follows */
|
||||
/* Public font API follows. */
|
||||
|
||||
void
|
||||
cairo_font_reference (cairo_font_t *font)
|
||||
|
|
@ -401,22 +355,171 @@ cairo_font_destroy (cairo_font_t *font)
|
|||
if (--(font->refcount) > 0)
|
||||
return;
|
||||
|
||||
_cairo_glyph_cache_destroy (font->glyph_cache);
|
||||
if (font->unscaled)
|
||||
_cairo_unscaled_font_destroy (font->unscaled);
|
||||
|
||||
if (font->backend->destroy)
|
||||
font->backend->destroy (font);
|
||||
free (font);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_font_set_transform (cairo_font_t *font,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_matrix_copy (&(font->matrix), matrix);
|
||||
double dummy;
|
||||
cairo_matrix_get_affine (matrix,
|
||||
&font->scale.matrix[0][0],
|
||||
&font->scale.matrix[0][1],
|
||||
&font->scale.matrix[1][0],
|
||||
&font->scale.matrix[1][1],
|
||||
&dummy, &dummy);
|
||||
}
|
||||
|
||||
void
|
||||
cairo_font_current_transform (cairo_font_t *font,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_matrix_copy (matrix, &(font->matrix));
|
||||
cairo_matrix_set_affine (matrix,
|
||||
font->scale.matrix[0][0],
|
||||
font->scale.matrix[0][1],
|
||||
font->scale.matrix[1][0],
|
||||
font->scale.matrix[1][1],
|
||||
0, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Now we implement functions to access a default global image & metrics
|
||||
* cache.
|
||||
*/
|
||||
|
||||
unsigned long
|
||||
_cairo_glyph_cache_hash (void *cache, void *key)
|
||||
{
|
||||
cairo_glyph_cache_key_t *in;
|
||||
in = (cairo_glyph_cache_key_t *) key;
|
||||
return
|
||||
((unsigned long) in->unscaled)
|
||||
^ ((unsigned long) in->scale.matrix[0][0])
|
||||
^ ((unsigned long) in->scale.matrix[0][1])
|
||||
^ ((unsigned long) in->scale.matrix[1][0])
|
||||
^ ((unsigned long) in->scale.matrix[1][1])
|
||||
^ in->index;
|
||||
}
|
||||
|
||||
int
|
||||
_cairo_glyph_cache_keys_equal (void *cache,
|
||||
void *k1,
|
||||
void *k2)
|
||||
{
|
||||
cairo_glyph_cache_key_t *a, *b;
|
||||
a = (cairo_glyph_cache_key_t *) k1;
|
||||
b = (cairo_glyph_cache_key_t *) k2;
|
||||
return (a->index == b->index)
|
||||
&& (a->unscaled == b->unscaled)
|
||||
&& (a->scale.matrix[0][0] == b->scale.matrix[0][0])
|
||||
&& (a->scale.matrix[0][1] == b->scale.matrix[0][1])
|
||||
&& (a->scale.matrix[1][0] == b->scale.matrix[1][0])
|
||||
&& (a->scale.matrix[1][1] == b->scale.matrix[1][1]);
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_image_glyph_cache_create_entry (void *cache,
|
||||
void *key,
|
||||
void **return_value)
|
||||
{
|
||||
cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *) key;
|
||||
cairo_image_glyph_cache_entry_t *im;
|
||||
cairo_status_t status;
|
||||
|
||||
im = calloc (1, sizeof (cairo_image_glyph_cache_entry_t));
|
||||
if (im == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
im->key = *k;
|
||||
status = im->key.unscaled->backend->create_glyph (im);
|
||||
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
free (im);
|
||||
return status;
|
||||
}
|
||||
|
||||
_cairo_unscaled_font_reference (im->key.unscaled);
|
||||
|
||||
im->key.base.memory =
|
||||
sizeof (cairo_image_glyph_cache_entry_t)
|
||||
+ (im->image ?
|
||||
sizeof (cairo_image_surface_t)
|
||||
+ 28 * sizeof (int) /* rough guess at size of pixman image structure */
|
||||
+ (im->image->height * im->image->stride) : 0);
|
||||
|
||||
*return_value = im;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_image_glyph_cache_destroy_entry (void *cache,
|
||||
void *value)
|
||||
{
|
||||
cairo_image_glyph_cache_entry_t *im;
|
||||
|
||||
im = (cairo_image_glyph_cache_entry_t *) value;
|
||||
_cairo_unscaled_font_destroy (im->key.unscaled);
|
||||
cairo_surface_destroy (&(im->image->base));
|
||||
free (im);
|
||||
}
|
||||
|
||||
static void
|
||||
_image_glyph_cache_destroy_cache (void *cache)
|
||||
{
|
||||
free (cache);
|
||||
}
|
||||
|
||||
const cairo_cache_backend_t cairo_image_cache_backend = {
|
||||
_cairo_glyph_cache_hash,
|
||||
_cairo_glyph_cache_keys_equal,
|
||||
_image_glyph_cache_create_entry,
|
||||
_image_glyph_cache_destroy_entry,
|
||||
_image_glyph_cache_destroy_cache
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
_cairo_lock_global_image_glyph_cache()
|
||||
{
|
||||
/* FIXME: implement locking. */
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_unlock_global_image_glyph_cache()
|
||||
{
|
||||
/* FIXME: implement locking. */
|
||||
}
|
||||
|
||||
static cairo_cache_t *
|
||||
_global_image_glyph_cache = NULL;
|
||||
|
||||
cairo_cache_t *
|
||||
_cairo_get_global_image_glyph_cache ()
|
||||
{
|
||||
if (_global_image_glyph_cache == NULL) {
|
||||
_global_image_glyph_cache = malloc (sizeof (cairo_cache_t));
|
||||
|
||||
if (_global_image_glyph_cache == NULL)
|
||||
goto FAIL;
|
||||
|
||||
if (_cairo_cache_init (_global_image_glyph_cache,
|
||||
&cairo_image_cache_backend,
|
||||
CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT))
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
return _global_image_glyph_cache;
|
||||
|
||||
FAIL:
|
||||
if (_global_image_glyph_cache)
|
||||
free (_global_image_glyph_cache);
|
||||
_global_image_glyph_cache = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -900,7 +900,8 @@ static const struct cairo_surface_backend cairo_glitz_surface_backend = {
|
|||
_cairo_glitz_surface_copy_page,
|
||||
_cairo_glitz_surface_show_page,
|
||||
_cairo_glitz_surface_set_clip_region,
|
||||
_cairo_glitz_surface_create_pattern
|
||||
_cairo_glitz_surface_create_pattern,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
||||
cairo_surface_t *
|
||||
|
|
|
|||
|
|
@ -77,9 +77,9 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
|
|||
gstate->num_dashes = 0;
|
||||
gstate->dash_offset = 0.0;
|
||||
|
||||
gstate->font = _cairo_font_create (CAIRO_FONT_FAMILY_DEFAULT,
|
||||
CAIRO_FONT_SLANT_DEFAULT,
|
||||
CAIRO_FONT_WEIGHT_DEFAULT);
|
||||
gstate->font = _cairo_unscaled_font_create (CAIRO_FONT_FAMILY_DEFAULT,
|
||||
CAIRO_FONT_SLANT_DEFAULT,
|
||||
CAIRO_FONT_WEIGHT_DEFAULT);
|
||||
|
||||
gstate->surface = NULL;
|
||||
|
||||
|
|
@ -119,11 +119,8 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
|
|||
}
|
||||
|
||||
if (other->font) {
|
||||
gstate->font = _cairo_font_copy (other->font);
|
||||
if (!gstate->font) {
|
||||
status = CAIRO_STATUS_NO_MEMORY;
|
||||
goto CLEANUP_DASHES;
|
||||
}
|
||||
gstate->font = other->font;
|
||||
_cairo_unscaled_font_reference (gstate->font);
|
||||
}
|
||||
|
||||
if (other->clip.region)
|
||||
|
|
@ -149,9 +146,10 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
|
|||
|
||||
CLEANUP_PATH:
|
||||
_cairo_path_fini (&gstate->path);
|
||||
|
||||
CLEANUP_FONT:
|
||||
cairo_font_destroy (gstate->font);
|
||||
CLEANUP_DASHES:
|
||||
_cairo_unscaled_font_destroy (gstate->font);
|
||||
|
||||
free (gstate->dash);
|
||||
gstate->dash = NULL;
|
||||
|
||||
|
|
@ -161,7 +159,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
|
|||
void
|
||||
_cairo_gstate_fini (cairo_gstate_t *gstate)
|
||||
{
|
||||
cairo_font_destroy (gstate->font);
|
||||
_cairo_unscaled_font_destroy (gstate->font);
|
||||
|
||||
if (gstate->surface)
|
||||
cairo_surface_destroy (gstate->surface);
|
||||
|
|
@ -177,6 +175,8 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
|
|||
|
||||
cairo_pattern_destroy (gstate->pattern);
|
||||
|
||||
_cairo_matrix_fini (&gstate->font_matrix);
|
||||
|
||||
_cairo_matrix_fini (&gstate->ctm);
|
||||
_cairo_matrix_fini (&gstate->ctm_inverse);
|
||||
|
||||
|
|
@ -627,6 +627,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate)
|
|||
if (scale == 0)
|
||||
scale = 1;
|
||||
|
||||
cairo_matrix_set_identity (&gstate->font_matrix);
|
||||
|
||||
cairo_matrix_set_identity (&gstate->ctm);
|
||||
cairo_matrix_scale (&gstate->ctm, scale, scale);
|
||||
cairo_matrix_copy (&gstate->ctm_inverse, &gstate->ctm);
|
||||
|
|
@ -1676,15 +1678,6 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
|
|||
double a, b, c, d, tx, ty;
|
||||
cairo_status_t st;
|
||||
|
||||
/* XXX: Something in the rectangle-based clipping support is
|
||||
* broken. See cairo_snippets/xxx_clip_rectangle which
|
||||
* demonstrates no clipping at all.
|
||||
*
|
||||
* For now, I'm am disabling this optimization completely until it
|
||||
* can be fixed.
|
||||
*/
|
||||
return 0;
|
||||
|
||||
st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
|
||||
if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.))
|
||||
return 0;
|
||||
|
|
@ -1992,16 +1985,28 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_select_font (cairo_gstate_t *gstate,
|
||||
const char *family,
|
||||
cairo_font_slant_t slant,
|
||||
cairo_font_weight_t weight)
|
||||
{
|
||||
if (gstate->font != NULL)
|
||||
cairo_font_destroy (gstate->font);
|
||||
cairo_unscaled_font_t *tmp;
|
||||
|
||||
gstate->font = _cairo_font_create (family, slant, weight);
|
||||
tmp = _cairo_unscaled_font_create (family, slant, weight);
|
||||
|
||||
if (tmp == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
if (gstate->font != tmp)
|
||||
{
|
||||
if (gstate->font != NULL)
|
||||
_cairo_unscaled_font_destroy (gstate->font);
|
||||
|
||||
cairo_matrix_set_identity (&gstate->font_matrix);
|
||||
gstate->font = tmp;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -2010,82 +2015,250 @@ cairo_status_t
|
|||
_cairo_gstate_scale_font (cairo_gstate_t *gstate,
|
||||
double scale)
|
||||
{
|
||||
return _cairo_font_scale (gstate->font, scale);
|
||||
return cairo_matrix_scale (&gstate->font_matrix, scale, scale);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_transform_font (cairo_gstate_t *gstate,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
return _cairo_font_transform (gstate->font, matrix);
|
||||
cairo_matrix_t tmp;
|
||||
double a, b, c, d, tx, ty;
|
||||
cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty);
|
||||
cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0);
|
||||
return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp);
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_current_font (cairo_gstate_t *gstate,
|
||||
cairo_font_t **font)
|
||||
{
|
||||
*font = gstate->font;
|
||||
cairo_font_scale_t scale;
|
||||
cairo_font_t *scaled;
|
||||
double dummy;
|
||||
|
||||
scaled = malloc (sizeof (cairo_font_t));
|
||||
if (scaled == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
cairo_matrix_get_affine (&gstate->font_matrix,
|
||||
&scale.matrix[0][0],
|
||||
&scale.matrix[0][1],
|
||||
&scale.matrix[1][0],
|
||||
&scale.matrix[1][1],
|
||||
&dummy, &dummy);
|
||||
|
||||
_cairo_font_init (scaled, &scale, gstate->font);
|
||||
_cairo_unscaled_font_reference (gstate->font);
|
||||
|
||||
*font = scaled;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_matrix_copy (&gstate->font_matrix, matrix);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
|
||||
cairo_matrix_t *matrix)
|
||||
{
|
||||
cairo_matrix_copy (matrix, &gstate->font_matrix);
|
||||
}
|
||||
|
||||
/*
|
||||
* Like everything else in this file, fonts involve Too Many Coordinate Spaces;
|
||||
* it is easy to get confused about what's going on.
|
||||
*
|
||||
* The user's view
|
||||
* ---------------
|
||||
*
|
||||
* Users ask for things in user space. When cairo starts, a user space unit
|
||||
* is about 1/96 inch, which is similar to (but importantly different from)
|
||||
* the normal "point" units most users think in terms of. When a user
|
||||
* selects a font, its scale is set to "one user unit". The user can then
|
||||
* independently scale the user coordinate system *or* the font matrix, in
|
||||
* order to adjust the rendered size of the font.
|
||||
*
|
||||
* If the user asks for a permanent reference to "a font", they are given a
|
||||
* handle to a structure holding a scale matrix and an unscaled font. This
|
||||
* effectively decouples the font from further changes to user space. Even
|
||||
* if the user then "sets" the current cairo_t font to the handle they were
|
||||
* passed, further changes to the cairo_t CTM will not affect externally
|
||||
* held references to the font.
|
||||
*
|
||||
*
|
||||
* The font's view
|
||||
* ---------------
|
||||
*
|
||||
* Fonts are designed and stored (in say .ttf files) in "font space", which
|
||||
* describes an "EM Square" (a design tile) and has some abstract number
|
||||
* such as 1000, 1024, or 2048 units per "EM". This is basically an
|
||||
* uninteresting space for us, but we need to remember that it exists.
|
||||
*
|
||||
* Font resources (from libraries or operating systems) render themselves
|
||||
* to a particular device. Since they do not want to make most programmers
|
||||
* worry about the font design space, the scaling API is simplified to
|
||||
* involve just telling the font the required pixel size of the EM square
|
||||
* (that is, in device space).
|
||||
*
|
||||
*
|
||||
* Cairo's gstate view
|
||||
* -------------------
|
||||
*
|
||||
* In addition to the CTM and CTM inverse, we keep a matrix in the gstate
|
||||
* called the "font matrix" which describes the user's most recent
|
||||
* font-scaling or font-transforming request. This is kept in terms of an
|
||||
* abstract scale factor, composed with the CTM and used to set the font's
|
||||
* pixel size. So if the user asks to "scale the font by 12", the matrix
|
||||
* is:
|
||||
*
|
||||
* [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ]
|
||||
*
|
||||
* It is an affine matrix, like all cairo matrices, but its tx and ty
|
||||
* components are always set to zero; we don't permit "nudging" fonts
|
||||
* around.
|
||||
*
|
||||
* In order to perform any action on a font, we must build an object
|
||||
* called a cairo_font_scale_t; this contains the central 2x2 matrix
|
||||
* resulting from "font matrix * CTM".
|
||||
*
|
||||
* We pass this to the font when making requests of it, which causes it to
|
||||
* reply for a particular [user request, device] combination, under the CTM
|
||||
* (to accomodate the "zoom in" == "bigger fonts" issue above).
|
||||
*
|
||||
* The other terms in our communication with the font are therefore in
|
||||
* device space. When we ask it to perform text->glyph conversion, it will
|
||||
* produce a glyph string in device space. Glyph vectors we pass to it for
|
||||
* measuring or rendering should be in device space. The metrics which we
|
||||
* get back from the font will be in device space. The contents of the
|
||||
* global glyph image cache will be in device space.
|
||||
*
|
||||
*
|
||||
* Cairo's public view
|
||||
* -------------------
|
||||
*
|
||||
* Since the values entering and leaving via public API calls are in user
|
||||
* space, the gstate functions typically need to multiply argumens by the
|
||||
* CTM (for user-input glyph vectors), and return values by the CTM inverse
|
||||
* (for font responses such as metrics or glyph vectors).
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
_build_font_scale (cairo_gstate_t *gstate,
|
||||
cairo_font_scale_t *sc)
|
||||
{
|
||||
cairo_matrix_t tmp;
|
||||
double dummy;
|
||||
cairo_matrix_multiply (&tmp, &gstate->font_matrix, &gstate->ctm);
|
||||
cairo_matrix_get_affine (&tmp,
|
||||
&sc->matrix[0][0],
|
||||
&sc->matrix[0][1],
|
||||
&sc->matrix[1][0],
|
||||
&sc->matrix[1][1],
|
||||
&dummy, &dummy);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
|
||||
cairo_font_extents_t *extents)
|
||||
{
|
||||
cairo_int_status_t status;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
|
||||
|
||||
status = _cairo_font_font_extents (gstate->font, extents);
|
||||
cairo_font_scale_t sc;
|
||||
double dummy = 0.0;
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
_build_font_scale (gstate, &sc);
|
||||
|
||||
status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents);
|
||||
|
||||
/* The font responded in device space; convert to user space. */
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&dummy,
|
||||
&extents->ascent);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&dummy,
|
||||
&extents->descent);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&dummy,
|
||||
&extents->height);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&extents->max_x_advance,
|
||||
&extents->max_y_advance);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8,
|
||||
cairo_glyph_t **glyphs,
|
||||
int *nglyphs)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_font_scale_t sc;
|
||||
|
||||
cairo_point_t point;
|
||||
double dev_x, dev_y;
|
||||
int i;
|
||||
|
||||
_build_font_scale (gstate, &sc);
|
||||
|
||||
status = _cairo_path_current_point (&gstate->path, &point);
|
||||
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
|
||||
dev_x = 0.0;
|
||||
dev_y = 0.0;
|
||||
} else {
|
||||
dev_x = _cairo_fixed_to_double (point.x);
|
||||
dev_y = _cairo_fixed_to_double (point.y);
|
||||
}
|
||||
|
||||
status = _cairo_unscaled_font_text_to_glyphs (gstate->font,
|
||||
&sc, utf8, glyphs, nglyphs);
|
||||
|
||||
if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
|
||||
return status;
|
||||
|
||||
/* The font responded in device space, starting from (0,0); add any
|
||||
current point offset in device space, and convert to user space. */
|
||||
|
||||
for (i = 0; i < *nglyphs; ++i) {
|
||||
(*glyphs)[i].x += dev_x;
|
||||
(*glyphs)[i].y += dev_y;
|
||||
cairo_matrix_transform_point (&gstate->ctm_inverse,
|
||||
&((*glyphs)[i].x),
|
||||
&((*glyphs)[i].y));
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_set_font (cairo_gstate_t *gstate,
|
||||
cairo_font_t *font)
|
||||
{
|
||||
if (gstate->font != NULL)
|
||||
cairo_font_destroy (gstate->font);
|
||||
gstate->font = font;
|
||||
cairo_font_reference (gstate->font);
|
||||
_cairo_unscaled_font_destroy (gstate->font);
|
||||
gstate->font = font->unscaled;
|
||||
_cairo_unscaled_font_reference (gstate->font);
|
||||
cairo_matrix_set_affine (&gstate->font_matrix,
|
||||
font->scale.matrix[0][0],
|
||||
font->scale.matrix[0][1],
|
||||
font->scale.matrix[1][0],
|
||||
font->scale.matrix[1][1],
|
||||
0, 0);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_text_extents (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8,
|
||||
cairo_text_extents_t *extents)
|
||||
{
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
cairo_status_t status;
|
||||
double scale_x, scale_y;
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
_cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
|
||||
cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
|
||||
|
||||
status = _cairo_font_text_extents (gstate->font,
|
||||
utf8, extents);
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
|
||||
extents->x_bearing /= scale_x;
|
||||
extents->y_bearing /= scale_y;
|
||||
extents->width /= scale_x;
|
||||
extents->height /= scale_y;
|
||||
extents->x_advance /= scale_x;
|
||||
extents->y_advance /= scale_y;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
|
||||
cairo_glyph_t *glyphs,
|
||||
|
|
@ -2093,129 +2266,43 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
|
|||
cairo_text_extents_t *extents)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
double scale_x, scale_y;
|
||||
cairo_glyph_t *transformed_glyphs;
|
||||
cairo_font_scale_t sc;
|
||||
int i;
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
_cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
|
||||
cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
|
||||
_build_font_scale (gstate, &sc);
|
||||
|
||||
status = _cairo_font_glyph_extents (gstate->font,
|
||||
glyphs, num_glyphs,
|
||||
extents);
|
||||
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
|
||||
if (transformed_glyphs == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
|
||||
extents->x_bearing /= scale_x;
|
||||
extents->y_bearing /= scale_y;
|
||||
extents->width /= scale_x;
|
||||
extents->height /= scale_y;
|
||||
extents->x_advance /= scale_x;
|
||||
extents->y_advance /= scale_y;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_show_text (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_point_t point;
|
||||
double x, y;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
cairo_pattern_t pattern;
|
||||
cairo_box_t bbox;
|
||||
|
||||
status = _cairo_path_current_point (&gstate->path, &point);
|
||||
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
|
||||
x = 0;
|
||||
y = 0;
|
||||
cairo_matrix_transform_point (&gstate->ctm, &x, &y);
|
||||
} else {
|
||||
x = _cairo_fixed_to_double (point.x);
|
||||
y = _cairo_fixed_to_double (point.y);
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
|
||||
|
||||
_cairo_pattern_init_copy (&pattern, gstate->pattern);
|
||||
|
||||
status = _cairo_font_text_bbox (gstate->font, gstate->surface,
|
||||
x, y, utf8, &bbox);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (gstate->clip.surface)
|
||||
for (i = 0; i < num_glyphs; ++i)
|
||||
{
|
||||
cairo_surface_t *intermediate;
|
||||
cairo_color_t empty_color;
|
||||
|
||||
_cairo_color_init (&empty_color);
|
||||
_cairo_color_set_alpha (&empty_color, .0);
|
||||
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
|
||||
CAIRO_FORMAT_A8,
|
||||
gstate->clip.width,
|
||||
gstate->clip.height,
|
||||
&empty_color);
|
||||
|
||||
status = _cairo_font_show_text (gstate->font,
|
||||
CAIRO_OPERATOR_ADD, pattern.source,
|
||||
intermediate,
|
||||
gstate->clip.x - pattern.source_offset.x,
|
||||
gstate->clip.y - pattern.source_offset.y,
|
||||
x - gstate->clip.x,
|
||||
y - gstate->clip.y, utf8);
|
||||
|
||||
if (status)
|
||||
goto BAIL;
|
||||
|
||||
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
|
||||
gstate->clip.surface,
|
||||
NULL,
|
||||
intermediate,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
gstate->clip.width,
|
||||
gstate->clip.height);
|
||||
|
||||
if (status)
|
||||
goto BAIL;
|
||||
|
||||
status = _cairo_surface_composite (gstate->operator,
|
||||
pattern.source,
|
||||
intermediate,
|
||||
gstate->surface,
|
||||
0, 0,
|
||||
0, 0,
|
||||
gstate->clip.x,
|
||||
gstate->clip.y,
|
||||
gstate->clip.width,
|
||||
gstate->clip.height);
|
||||
|
||||
BAIL:
|
||||
cairo_surface_destroy (intermediate);
|
||||
|
||||
transformed_glyphs[i] = glyphs[i];
|
||||
cairo_matrix_transform_point (&gstate->ctm,
|
||||
&transformed_glyphs[i].x,
|
||||
&transformed_glyphs[i].y);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = _cairo_font_show_text (gstate->font,
|
||||
gstate->operator, pattern.source,
|
||||
gstate->surface,
|
||||
-pattern.source_offset.x,
|
||||
-pattern.source_offset.y,
|
||||
x, y, utf8);
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
|
||||
_cairo_pattern_fini (&pattern);
|
||||
status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc,
|
||||
transformed_glyphs, num_glyphs,
|
||||
extents);
|
||||
|
||||
/* The font responded in device space; convert to user space. */
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&extents->x_bearing,
|
||||
&extents->y_bearing);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&extents->width,
|
||||
&extents->height);
|
||||
|
||||
cairo_matrix_transform_distance (&gstate->ctm_inverse,
|
||||
&extents->x_advance,
|
||||
&extents->y_advance);
|
||||
|
||||
free (transformed_glyphs);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -2226,12 +2313,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
int num_glyphs)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
int i;
|
||||
cairo_glyph_t *transformed_glyphs = NULL;
|
||||
cairo_font_scale_t sc;
|
||||
cairo_pattern_t pattern;
|
||||
cairo_box_t bbox;
|
||||
|
||||
_build_font_scale (gstate, &sc);
|
||||
|
||||
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
|
||||
if (transformed_glyphs == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
|
@ -2240,16 +2329,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
{
|
||||
transformed_glyphs[i] = glyphs[i];
|
||||
cairo_matrix_transform_point (&gstate->ctm,
|
||||
&(transformed_glyphs[i].x),
|
||||
&(transformed_glyphs[i].y));
|
||||
&transformed_glyphs[i].x,
|
||||
&transformed_glyphs[i].y);
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
|
||||
|
||||
_cairo_pattern_init_copy (&pattern, gstate->pattern);
|
||||
status = _cairo_font_glyph_bbox (gstate->font, gstate->surface,
|
||||
transformed_glyphs, num_glyphs, &bbox);
|
||||
status = _cairo_unscaled_font_glyph_bbox (gstate->font, &sc,
|
||||
transformed_glyphs, num_glyphs,
|
||||
&bbox);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
|
|
@ -2277,12 +2364,13 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
transformed_glyphs[i].y -= gstate->clip.y;
|
||||
}
|
||||
|
||||
status = _cairo_font_show_glyphs (gstate->font,
|
||||
CAIRO_OPERATOR_ADD,
|
||||
pattern.source, intermediate,
|
||||
gstate->clip.x - pattern.source_offset.x,
|
||||
gstate->clip.y - pattern.source_offset.y,
|
||||
transformed_glyphs, num_glyphs);
|
||||
status = _cairo_unscaled_font_show_glyphs (gstate->font,
|
||||
&sc,
|
||||
CAIRO_OPERATOR_ADD,
|
||||
pattern.source, intermediate,
|
||||
gstate->clip.x - pattern.source_offset.x,
|
||||
gstate->clip.y - pattern.source_offset.y,
|
||||
transformed_glyphs, num_glyphs);
|
||||
|
||||
if (status)
|
||||
goto BAIL;
|
||||
|
|
@ -2317,16 +2405,15 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
}
|
||||
else
|
||||
{
|
||||
status = _cairo_font_show_glyphs (gstate->font,
|
||||
gstate->operator, pattern.source,
|
||||
gstate->surface,
|
||||
-pattern.source_offset.x,
|
||||
-pattern.source_offset.y,
|
||||
transformed_glyphs, num_glyphs);
|
||||
status = _cairo_unscaled_font_show_glyphs (gstate->font,
|
||||
&sc,
|
||||
gstate->operator, pattern.source,
|
||||
gstate->surface,
|
||||
-pattern.source_offset.x,
|
||||
-pattern.source_offset.y,
|
||||
transformed_glyphs, num_glyphs);
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
|
||||
_cairo_pattern_fini (&pattern);
|
||||
|
||||
free (transformed_glyphs);
|
||||
|
|
@ -2334,40 +2421,6 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
|||
return status;
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_text_path (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
cairo_point_t point;
|
||||
double x, y;
|
||||
|
||||
status = _cairo_path_current_point (&gstate->path, &point);
|
||||
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
|
||||
x = 0;
|
||||
y = 0;
|
||||
cairo_matrix_transform_point (&gstate->ctm, &x, &y);
|
||||
} else {
|
||||
x = _cairo_fixed_to_double (point.x);
|
||||
y = _cairo_fixed_to_double (point.y);
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
|
||||
|
||||
status = _cairo_font_text_path (gstate->font,
|
||||
x, y,
|
||||
utf8,
|
||||
&gstate->path);
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
|
||||
cairo_glyph_t *glyphs,
|
||||
|
|
@ -2376,7 +2429,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
|
|||
cairo_status_t status;
|
||||
int i;
|
||||
cairo_glyph_t *transformed_glyphs = NULL;
|
||||
cairo_matrix_t saved_font_matrix;
|
||||
cairo_font_scale_t sc;
|
||||
|
||||
_build_font_scale (gstate, &sc);
|
||||
|
||||
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
|
||||
if (transformed_glyphs == NULL)
|
||||
|
|
@ -2390,14 +2445,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
|
|||
&(transformed_glyphs[i].y));
|
||||
}
|
||||
|
||||
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
|
||||
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
|
||||
|
||||
status = _cairo_font_glyph_path (gstate->font,
|
||||
transformed_glyphs, num_glyphs,
|
||||
&gstate->path);
|
||||
|
||||
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
|
||||
status = _cairo_unscaled_font_glyph_path (gstate->font, &sc,
|
||||
transformed_glyphs, num_glyphs,
|
||||
&gstate->path);
|
||||
|
||||
free (transformed_glyphs);
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -525,5 +525,6 @@ static const cairo_surface_backend_t cairo_image_surface_backend = {
|
|||
_cairo_image_surface_copy_page,
|
||||
_cairo_image_surface_show_page,
|
||||
_cairo_image_abstract_surface_set_clip_region,
|
||||
_cairo_image_abstract_surface_create_pattern
|
||||
_cairo_image_abstract_surface_create_pattern,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -382,5 +382,6 @@ static const cairo_surface_backend_t cairo_png_surface_backend = {
|
|||
_cairo_png_surface_copy_page,
|
||||
_cairo_png_surface_show_page,
|
||||
_cairo_png_surface_set_clip_region,
|
||||
_cairo_png_surface_create_pattern
|
||||
_cairo_png_surface_create_pattern,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -436,5 +436,6 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
|
|||
_cairo_ps_surface_copy_page,
|
||||
_cairo_ps_surface_show_page,
|
||||
_cairo_ps_surface_set_clip_region,
|
||||
_cairo_ps_surface_create_pattern
|
||||
_cairo_ps_surface_create_pattern,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -745,7 +745,8 @@ static const struct cairo_surface_backend cairo_xcb_surface_backend = {
|
|||
_cairo_xcb_surface_copy_page,
|
||||
_cairo_xcb_surface_show_page,
|
||||
_cairo_xcb_surface_set_clip_region,
|
||||
_cairo_xcb_surface_create_pattern
|
||||
_cairo_xcb_surface_create_pattern,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -631,6 +631,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
|
|||
xr.height = surf->height;
|
||||
XUnionRectWithRegion (&xr, xregion, xregion);
|
||||
rects = malloc(sizeof(XRectangle));
|
||||
if (rects == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
rects[0] = xr;
|
||||
m = 1;
|
||||
|
||||
|
|
@ -641,6 +643,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
|
|||
if (n == 0)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
rects = malloc(sizeof(XRectangle) * n);
|
||||
if (rects == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
box = pixman_region_rects (region);
|
||||
xregion = XCreateRegion();
|
||||
|
||||
|
|
@ -661,7 +665,7 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
|
|||
XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
|
||||
free(rects);
|
||||
if (surf->picture)
|
||||
XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
|
||||
XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
|
||||
XDestroyRegion(xregion);
|
||||
XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
@ -675,6 +679,17 @@ _cairo_xlib_surface_create_pattern (void *abstract_surface,
|
|||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs);
|
||||
|
||||
static const struct cairo_surface_backend cairo_xlib_surface_backend = {
|
||||
_cairo_xlib_surface_create_similar,
|
||||
_cairo_xlib_surface_destroy,
|
||||
|
|
@ -690,7 +705,8 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = {
|
|||
_cairo_xlib_surface_copy_page,
|
||||
_cairo_xlib_surface_show_page,
|
||||
_cairo_xlib_surface_set_clip_region,
|
||||
_cairo_xlib_surface_create_pattern
|
||||
_cairo_xlib_surface_create_pattern,
|
||||
_cairo_xlib_surface_show_glyphs
|
||||
};
|
||||
|
||||
cairo_surface_t *
|
||||
|
|
@ -761,3 +777,512 @@ cairo_xlib_surface_create (Display *dpy,
|
|||
return (cairo_surface_t *) surface;
|
||||
}
|
||||
DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
|
||||
|
||||
|
||||
/* RENDER glyphset cache code */
|
||||
|
||||
typedef struct glyphset_cache {
|
||||
cairo_cache_t base;
|
||||
struct glyphset_cache *next;
|
||||
Display *display;
|
||||
XRenderPictFormat *a8_pict_format;
|
||||
GlyphSet glyphset;
|
||||
Glyph counter;
|
||||
} glyphset_cache_t;
|
||||
|
||||
typedef struct {
|
||||
cairo_glyph_cache_key_t key;
|
||||
Glyph glyph;
|
||||
XGlyphInfo info;
|
||||
} glyphset_cache_entry_t;
|
||||
|
||||
static Glyph
|
||||
_next_xlib_glyph (glyphset_cache_t *cache)
|
||||
{
|
||||
return ++(cache->counter);
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_xlib_glyphset_cache_create_entry (void *cache,
|
||||
void *key,
|
||||
void **return_entry)
|
||||
{
|
||||
glyphset_cache_t *g = (glyphset_cache_t *) cache;
|
||||
cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *)key;
|
||||
glyphset_cache_entry_t *v;
|
||||
|
||||
cairo_status_t status;
|
||||
|
||||
cairo_cache_t *im_cache;
|
||||
cairo_image_glyph_cache_entry_t *im;
|
||||
|
||||
v = malloc (sizeof (glyphset_cache_entry_t));
|
||||
_cairo_lock_global_image_glyph_cache ();
|
||||
im_cache = _cairo_get_global_image_glyph_cache ();
|
||||
|
||||
if (g == NULL || v == NULL ||g == NULL || im_cache == NULL) {
|
||||
_cairo_unlock_global_image_glyph_cache ();
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
status = _cairo_cache_lookup (im_cache, key, (void **) (&im));
|
||||
if (status != CAIRO_STATUS_SUCCESS || im == NULL) {
|
||||
_cairo_unlock_global_image_glyph_cache ();
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
v->key = *k;
|
||||
_cairo_unscaled_font_reference (v->key.unscaled);
|
||||
|
||||
v->glyph = _next_xlib_glyph (g);
|
||||
|
||||
v->info.width = im->image ? im->image->stride : im->size.width;
|
||||
v->info.height = im->size.height;
|
||||
v->info.x = - im->extents.x_bearing;
|
||||
v->info.y = im->extents.y_bearing;
|
||||
v->info.xOff = 0;
|
||||
v->info.yOff = 0;
|
||||
|
||||
XRenderAddGlyphs (g->display, g->glyphset,
|
||||
&(v->glyph), &(v->info), 1,
|
||||
im->image ? im->image->data : NULL,
|
||||
im->image ? v->info.height * v->info.width : 0);
|
||||
|
||||
v->key.base.memory = im->image ? im->image->width * im->image->stride : 0;
|
||||
*return_entry = v;
|
||||
_cairo_unlock_global_image_glyph_cache ();
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_xlib_glyphset_cache_destroy_cache (void *cache)
|
||||
{
|
||||
/* FIXME: will we ever release glyphset caches? */
|
||||
}
|
||||
|
||||
static void
|
||||
_xlib_glyphset_cache_destroy_entry (void *cache, void *entry)
|
||||
{
|
||||
glyphset_cache_t *g;
|
||||
glyphset_cache_entry_t *v;
|
||||
|
||||
g = (glyphset_cache_t *) cache;
|
||||
v = (glyphset_cache_entry_t *) entry;
|
||||
|
||||
_cairo_unscaled_font_destroy (v->key.unscaled);
|
||||
XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1);
|
||||
free (v);
|
||||
}
|
||||
|
||||
const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
|
||||
_cairo_glyph_cache_hash,
|
||||
_cairo_glyph_cache_keys_equal,
|
||||
_xlib_glyphset_cache_create_entry,
|
||||
_xlib_glyphset_cache_destroy_entry,
|
||||
_xlib_glyphset_cache_destroy_cache
|
||||
};
|
||||
|
||||
|
||||
static glyphset_cache_t *
|
||||
_xlib_glyphset_caches = NULL;
|
||||
|
||||
static void
|
||||
_lock_xlib_glyphset_caches (void)
|
||||
{
|
||||
/* FIXME: implement locking */
|
||||
}
|
||||
|
||||
static void
|
||||
_unlock_xlib_glyphset_caches (void)
|
||||
{
|
||||
/* FIXME: implement locking */
|
||||
}
|
||||
|
||||
static glyphset_cache_t *
|
||||
_get_glyphset_cache (Display *d)
|
||||
{
|
||||
/*
|
||||
* There should usually only be one, or a very small number, of
|
||||
* displays. So we just do a linear scan.
|
||||
*/
|
||||
|
||||
glyphset_cache_t *g;
|
||||
|
||||
for (g = _xlib_glyphset_caches; g != NULL; g = g->next) {
|
||||
if (g->display == d)
|
||||
return g;
|
||||
}
|
||||
|
||||
g = malloc (sizeof (glyphset_cache_t));
|
||||
if (g == NULL)
|
||||
goto ERR;
|
||||
|
||||
g->counter = 0;
|
||||
g->display = d;
|
||||
g->a8_pict_format = XRenderFindStandardFormat (d, PictStandardA8);
|
||||
if (g->a8_pict_format == NULL)
|
||||
goto ERR;
|
||||
|
||||
if (_cairo_cache_init (&g->base,
|
||||
&_xlib_glyphset_cache_backend,
|
||||
CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT))
|
||||
goto FREE_GLYPHSET_CACHE;
|
||||
|
||||
g->glyphset = XRenderCreateGlyphSet (d, g->a8_pict_format);
|
||||
g->next = _xlib_glyphset_caches;
|
||||
_xlib_glyphset_caches = g;
|
||||
return g;
|
||||
|
||||
FREE_GLYPHSET_CACHE:
|
||||
free (g);
|
||||
|
||||
ERR:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define N_STACK_BUF 1024
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
glyphset_cache_t *g,
|
||||
cairo_glyph_cache_key_t *key,
|
||||
cairo_xlib_surface_t *src,
|
||||
cairo_xlib_surface_t *self,
|
||||
int source_x,
|
||||
int source_y,
|
||||
const cairo_glyph_t *glyphs,
|
||||
glyphset_cache_entry_t **entries,
|
||||
int num_glyphs)
|
||||
{
|
||||
XGlyphElt32 *elts = NULL;
|
||||
XGlyphElt32 stack_elts [N_STACK_BUF];
|
||||
|
||||
unsigned int *chars = NULL;
|
||||
unsigned int stack_chars [N_STACK_BUF];
|
||||
|
||||
int i;
|
||||
int lastX = 0, lastY = 0;
|
||||
|
||||
/* Acquire arrays of suitable sizes. */
|
||||
if (num_glyphs < N_STACK_BUF) {
|
||||
elts = stack_elts;
|
||||
chars = stack_chars;
|
||||
|
||||
} else {
|
||||
elts = malloc (num_glyphs * sizeof (XGlyphElt32));
|
||||
if (elts == NULL)
|
||||
goto FAIL;
|
||||
|
||||
chars = malloc (num_glyphs * sizeof (unsigned int));
|
||||
if (chars == NULL)
|
||||
goto FREE_ELTS;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < num_glyphs; ++i) {
|
||||
chars[i] = entries[i]->glyph;
|
||||
elts[i].chars = &(chars[i]);
|
||||
elts[i].nchars = 1;
|
||||
elts[i].glyphset = g->glyphset;
|
||||
elts[i].xOff = glyphs[i].x - lastX;
|
||||
elts[i].yOff = glyphs[i].y - lastY;
|
||||
lastX = glyphs[i].x;
|
||||
lastY = glyphs[i].y;
|
||||
}
|
||||
|
||||
XRenderCompositeText32 (self->dpy,
|
||||
_render_operator (operator),
|
||||
src->picture,
|
||||
self->picture,
|
||||
g->a8_pict_format,
|
||||
source_x, source_y,
|
||||
0, 0,
|
||||
elts, num_glyphs);
|
||||
|
||||
if (num_glyphs >= N_STACK_BUF) {
|
||||
free (chars);
|
||||
free (elts);
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
FREE_ELTS:
|
||||
if (num_glyphs >= N_STACK_BUF)
|
||||
free (elts);
|
||||
|
||||
FAIL:
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
glyphset_cache_t *g,
|
||||
cairo_glyph_cache_key_t *key,
|
||||
cairo_xlib_surface_t *src,
|
||||
cairo_xlib_surface_t *self,
|
||||
int source_x,
|
||||
int source_y,
|
||||
const cairo_glyph_t *glyphs,
|
||||
glyphset_cache_entry_t **entries,
|
||||
int num_glyphs)
|
||||
{
|
||||
XGlyphElt16 *elts = NULL;
|
||||
XGlyphElt16 stack_elts [N_STACK_BUF];
|
||||
|
||||
unsigned short *chars = NULL;
|
||||
unsigned short stack_chars [N_STACK_BUF];
|
||||
|
||||
int i;
|
||||
int lastX = 0, lastY = 0;
|
||||
|
||||
/* Acquire arrays of suitable sizes. */
|
||||
if (num_glyphs < N_STACK_BUF) {
|
||||
elts = stack_elts;
|
||||
chars = stack_chars;
|
||||
|
||||
} else {
|
||||
elts = malloc (num_glyphs * sizeof (XGlyphElt16));
|
||||
if (elts == NULL)
|
||||
goto FAIL;
|
||||
|
||||
chars = malloc (num_glyphs * sizeof (unsigned short));
|
||||
if (chars == NULL)
|
||||
goto FREE_ELTS;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < num_glyphs; ++i) {
|
||||
chars[i] = entries[i]->glyph;
|
||||
elts[i].chars = &(chars[i]);
|
||||
elts[i].nchars = 1;
|
||||
elts[i].glyphset = g->glyphset;
|
||||
elts[i].xOff = glyphs[i].x - lastX;
|
||||
elts[i].yOff = glyphs[i].y - lastY;
|
||||
lastX = glyphs[i].x;
|
||||
lastY = glyphs[i].y;
|
||||
}
|
||||
|
||||
XRenderCompositeText16 (self->dpy,
|
||||
_render_operator (operator),
|
||||
src->picture,
|
||||
self->picture,
|
||||
g->a8_pict_format,
|
||||
source_x, source_y,
|
||||
0, 0,
|
||||
elts, num_glyphs);
|
||||
|
||||
if (num_glyphs >= N_STACK_BUF) {
|
||||
free (chars);
|
||||
free (elts);
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
FREE_ELTS:
|
||||
if (num_glyphs >= N_STACK_BUF)
|
||||
free (elts);
|
||||
|
||||
FAIL:
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
glyphset_cache_t *g,
|
||||
cairo_glyph_cache_key_t *key,
|
||||
cairo_xlib_surface_t *src,
|
||||
cairo_xlib_surface_t *self,
|
||||
int source_x,
|
||||
int source_y,
|
||||
const cairo_glyph_t *glyphs,
|
||||
glyphset_cache_entry_t **entries,
|
||||
int num_glyphs)
|
||||
{
|
||||
XGlyphElt8 *elts = NULL;
|
||||
XGlyphElt8 stack_elts [N_STACK_BUF];
|
||||
|
||||
char *chars = NULL;
|
||||
char stack_chars [N_STACK_BUF];
|
||||
|
||||
int i;
|
||||
int lastX = 0, lastY = 0;
|
||||
|
||||
/* Acquire arrays of suitable sizes. */
|
||||
if (num_glyphs < N_STACK_BUF) {
|
||||
elts = stack_elts;
|
||||
chars = stack_chars;
|
||||
|
||||
} else {
|
||||
elts = malloc (num_glyphs * sizeof (XGlyphElt8));
|
||||
if (elts == NULL)
|
||||
goto FAIL;
|
||||
|
||||
chars = malloc (num_glyphs * sizeof (char));
|
||||
if (chars == NULL)
|
||||
goto FREE_ELTS;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < num_glyphs; ++i) {
|
||||
chars[i] = entries[i]->glyph;
|
||||
elts[i].chars = &(chars[i]);
|
||||
elts[i].nchars = 1;
|
||||
elts[i].glyphset = g->glyphset;
|
||||
elts[i].xOff = glyphs[i].x - lastX;
|
||||
elts[i].yOff = glyphs[i].y - lastY;
|
||||
lastX = glyphs[i].x;
|
||||
lastY = glyphs[i].y;
|
||||
}
|
||||
|
||||
XRenderCompositeText8 (self->dpy,
|
||||
_render_operator (operator),
|
||||
src->picture,
|
||||
self->picture,
|
||||
g->a8_pict_format,
|
||||
source_x, source_y,
|
||||
0, 0,
|
||||
elts, num_glyphs);
|
||||
|
||||
if (num_glyphs >= N_STACK_BUF) {
|
||||
free (chars);
|
||||
free (elts);
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
FREE_ELTS:
|
||||
if (num_glyphs >= N_STACK_BUF)
|
||||
free (elts);
|
||||
|
||||
FAIL:
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs)
|
||||
{
|
||||
unsigned int elt_size;
|
||||
cairo_xlib_surface_t *self = (cairo_xlib_surface_t *) surface;
|
||||
cairo_image_surface_t *tmp = NULL;
|
||||
cairo_xlib_surface_t *src = NULL;
|
||||
glyphset_cache_t *g;
|
||||
cairo_status_t status;
|
||||
cairo_glyph_cache_key_t key;
|
||||
glyphset_cache_entry_t **entries;
|
||||
glyphset_cache_entry_t *stack_entries [N_STACK_BUF];
|
||||
int i;
|
||||
|
||||
/* Acquire an entry array of suitable size. */
|
||||
if (num_glyphs < N_STACK_BUF) {
|
||||
entries = stack_entries;
|
||||
|
||||
} else {
|
||||
entries = malloc (num_glyphs * sizeof (glyphset_cache_entry_t *));
|
||||
if (entries == NULL)
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
/* prep the source surface. */
|
||||
if (source->backend == surface->backend) {
|
||||
src = (cairo_xlib_surface_t *) source;
|
||||
|
||||
} else {
|
||||
tmp = _cairo_surface_get_image (source);
|
||||
if (tmp == NULL)
|
||||
goto FREE_ENTRIES;
|
||||
|
||||
src = (cairo_xlib_surface_t *)
|
||||
_cairo_surface_create_similar_scratch (surface, self->format, 1,
|
||||
tmp->width, tmp->height);
|
||||
|
||||
if (src == NULL)
|
||||
goto FREE_TMP;
|
||||
|
||||
if (_cairo_surface_set_image (&(src->base), tmp) != CAIRO_STATUS_SUCCESS)
|
||||
goto FREE_SRC;
|
||||
}
|
||||
|
||||
_lock_xlib_glyphset_caches ();
|
||||
g = _get_glyphset_cache (self->dpy);
|
||||
if (g == NULL)
|
||||
goto UNLOCK;
|
||||
|
||||
/* Work out the index size to use. */
|
||||
elt_size = 8;
|
||||
key.scale = *scale;
|
||||
key.unscaled = font;
|
||||
|
||||
for (i = 0; i < num_glyphs; ++i) {
|
||||
key.index = glyphs[i].index;
|
||||
status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]));
|
||||
if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL)
|
||||
goto UNLOCK;
|
||||
|
||||
if (elt_size == 8 && entries[i]->glyph > 0xff)
|
||||
elt_size = 16;
|
||||
if (elt_size == 16 && entries[i]->glyph > 0xffff) {
|
||||
elt_size = 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the appropriate sub-function. */
|
||||
|
||||
if (elt_size == 8)
|
||||
status = _cairo_xlib_surface_show_glyphs8 (font, scale, operator, g, &key, src, self,
|
||||
source_x, source_y,
|
||||
glyphs, entries, num_glyphs);
|
||||
else if (elt_size == 16)
|
||||
status = _cairo_xlib_surface_show_glyphs16 (font, scale, operator, g, &key, src, self,
|
||||
source_x, source_y,
|
||||
glyphs, entries, num_glyphs);
|
||||
else
|
||||
status = _cairo_xlib_surface_show_glyphs32 (font, scale, operator, g, &key, src, self,
|
||||
source_x, source_y,
|
||||
glyphs, entries, num_glyphs);
|
||||
|
||||
_unlock_xlib_glyphset_caches ();
|
||||
|
||||
if (tmp != NULL) {
|
||||
cairo_surface_destroy (&(src->base));
|
||||
cairo_surface_destroy (&(tmp->base));
|
||||
}
|
||||
|
||||
if (num_glyphs >= N_STACK_BUF)
|
||||
free (entries);
|
||||
|
||||
return status;
|
||||
|
||||
UNLOCK:
|
||||
_unlock_xlib_glyphset_caches ();
|
||||
|
||||
FREE_SRC:
|
||||
cairo_surface_destroy (&(src->base));
|
||||
|
||||
FREE_TMP:
|
||||
cairo_surface_destroy (&(tmp->base));
|
||||
|
||||
FREE_ENTRIES:
|
||||
if (num_glyphs >= N_STACK_BUF)
|
||||
free (entries);
|
||||
|
||||
FAIL:
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
|
|
|||
417
src/cairoint.h
417
src/cairoint.h
|
|
@ -49,7 +49,6 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
|
@ -253,52 +252,204 @@ typedef struct cairo_pen {
|
|||
} cairo_pen_t;
|
||||
|
||||
typedef struct cairo_color cairo_color_t;
|
||||
typedef struct cairo_image_surface cairo_image_surface_t;
|
||||
|
||||
/* cairo_cache.c structures and functions */
|
||||
|
||||
typedef struct cairo_cache_backend {
|
||||
|
||||
unsigned long (*hash) (void *cache,
|
||||
void *key);
|
||||
|
||||
int (*keys_equal) (void *cache,
|
||||
void *k1,
|
||||
void *k2);
|
||||
|
||||
cairo_status_t (*create_entry) (void *cache,
|
||||
void *key,
|
||||
void **entry_return);
|
||||
|
||||
void (*destroy_entry) (void *cache,
|
||||
void *entry);
|
||||
|
||||
void (*destroy_cache) (void *cache);
|
||||
|
||||
} cairo_cache_backend_t;
|
||||
|
||||
|
||||
/*
|
||||
* The cairo_cache system makes the following assumptions about
|
||||
* entries in its cache:
|
||||
*
|
||||
* - a pointer to an entry can be cast to a cairo_cache_entry_base_t.
|
||||
* - a pointer to an entry can also be cast to the "key type".
|
||||
*
|
||||
* The practical effect of this is that your entries must be laid
|
||||
* out this way:
|
||||
*
|
||||
* struct my_entry {
|
||||
* cairo_cache_entry_base_t;
|
||||
* my_key_value_1;
|
||||
* my_key_value_2;
|
||||
* ...
|
||||
* my_value;
|
||||
* };
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
unsigned long memory;
|
||||
unsigned long hashcode;
|
||||
} cairo_cache_entry_base_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned long high_water_mark;
|
||||
unsigned long size;
|
||||
unsigned long rehash;
|
||||
} cairo_cache_arrangement_t;
|
||||
|
||||
#undef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
|
||||
typedef struct {
|
||||
unsigned long refcount;
|
||||
const cairo_cache_backend_t *backend;
|
||||
cairo_cache_arrangement_t *arrangement;
|
||||
cairo_cache_entry_base_t **entries;
|
||||
|
||||
unsigned long max_memory;
|
||||
unsigned long used_memory;
|
||||
unsigned long live_entries;
|
||||
|
||||
#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
|
||||
unsigned long hits;
|
||||
unsigned long misses;
|
||||
unsigned long probes;
|
||||
#endif
|
||||
} cairo_cache_t;
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_cache_init (cairo_cache_t *cache,
|
||||
const cairo_cache_backend_t *backend,
|
||||
unsigned long max_memory);
|
||||
|
||||
extern void __internal_linkage
|
||||
_cairo_cache_reference (cairo_cache_t *cache);
|
||||
|
||||
extern void __internal_linkage
|
||||
_cairo_cache_destroy (cairo_cache_t *cache);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_cache_lookup (cairo_cache_t *cache,
|
||||
void *key,
|
||||
void **entry_return);
|
||||
|
||||
extern unsigned long __internal_linkage
|
||||
_cairo_hash_string (const char *c);
|
||||
|
||||
#define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
|
||||
#define CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
|
||||
#define CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT 20
|
||||
#define CAIRO_FT_CACHE_NUM_FONTS_DEFAULT 20
|
||||
|
||||
typedef struct {
|
||||
double matrix[2][2];
|
||||
} cairo_font_scale_t;
|
||||
|
||||
struct cairo_font_backend;
|
||||
|
||||
typedef struct {
|
||||
int refcount;
|
||||
const struct cairo_font_backend *backend;
|
||||
} cairo_unscaled_font_t;
|
||||
|
||||
/*
|
||||
* A cairo_font contains a pointer to a cairo_sizeless_font_t and a scale
|
||||
* matrix. These are the things the user holds references to.
|
||||
*/
|
||||
|
||||
struct cairo_font {
|
||||
int refcount;
|
||||
cairo_font_scale_t scale;
|
||||
cairo_unscaled_font_t *unscaled;
|
||||
};
|
||||
|
||||
|
||||
/* cairo_font.c is responsible for two global caches:
|
||||
*
|
||||
* - font entries: [[[base], name, weight, slant], cairo_unscaled_font_t ]
|
||||
* - glyph entries: [[[base], cairo_font_t, index], image, size, extents ]
|
||||
*
|
||||
* Surfaces may build their own glyph caches if they have surface-specific
|
||||
* glyph resources to maintain; those caches can feed off of the global
|
||||
* caches if need be (eg. cairo_xlib_surface.c does this).
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
cairo_cache_entry_base_t base;
|
||||
cairo_unscaled_font_t *unscaled;
|
||||
cairo_font_scale_t scale;
|
||||
unsigned long index;
|
||||
} cairo_glyph_cache_key_t;
|
||||
|
||||
typedef struct {
|
||||
cairo_glyph_cache_key_t key;
|
||||
cairo_image_surface_t *image;
|
||||
cairo_glyph_size_t size;
|
||||
cairo_text_extents_t extents;
|
||||
} cairo_image_glyph_cache_entry_t;
|
||||
|
||||
extern void __internal_linkage
|
||||
_cairo_lock_global_image_glyph_cache (void);
|
||||
|
||||
extern void __internal_linkage
|
||||
_cairo_unlock_global_image_glyph_cache (void);
|
||||
|
||||
extern cairo_cache_t * __internal_linkage
|
||||
_cairo_get_global_image_glyph_cache (void);
|
||||
|
||||
/* Some glyph cache functions you can reuse. */
|
||||
|
||||
extern unsigned long __internal_linkage
|
||||
_cairo_glyph_cache_hash (void *cache, void *key);
|
||||
|
||||
extern int __internal_linkage
|
||||
_cairo_glyph_cache_keys_equal (void *cache,
|
||||
void *k1,
|
||||
void *k2);
|
||||
|
||||
|
||||
/* the font backend interface */
|
||||
|
||||
typedef struct cairo_font_backend {
|
||||
cairo_font_t *(*create) (const char *family,
|
||||
cairo_unscaled_font_t *(*create) (const char *family,
|
||||
cairo_font_slant_t slant,
|
||||
cairo_font_weight_t weight);
|
||||
|
||||
cairo_font_t *(*copy) (void *font);
|
||||
|
||||
void (*destroy) (void *font);
|
||||
|
||||
cairo_status_t (*font_extents) (void *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_font_extents_t *extents);
|
||||
|
||||
cairo_status_t (*text_extents) (void *font,
|
||||
cairo_status_t (*text_to_glyphs) (void *font,
|
||||
cairo_font_scale_t *scale,
|
||||
const unsigned char *utf8,
|
||||
cairo_text_extents_t *extents);
|
||||
|
||||
cairo_glyph_t **glyphs,
|
||||
int *num_glyphs);
|
||||
|
||||
cairo_status_t (*glyph_extents) (void *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_text_extents_t *extents);
|
||||
|
||||
cairo_status_t (*text_bbox) (void *font,
|
||||
cairo_surface_t *surface,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8,
|
||||
cairo_box_t *bbox);
|
||||
|
||||
cairo_status_t (*glyph_bbox) (void *font,
|
||||
cairo_surface_t *surface,
|
||||
cairo_font_scale_t *scale,
|
||||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_box_t *bbox);
|
||||
|
||||
cairo_status_t (*show_text) (void *font,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8);
|
||||
|
||||
cairo_status_t (*show_glyphs) (void *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
|
|
@ -307,25 +458,19 @@ typedef struct cairo_font_backend {
|
|||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs);
|
||||
|
||||
cairo_status_t (*text_path) (void *font,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8,
|
||||
cairo_path_t *path);
|
||||
|
||||
cairo_status_t (*glyph_path) (void *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_path_t *path);
|
||||
cairo_surface_t *(*create_glyph) (void *font,
|
||||
const cairo_glyph_t *glyph,
|
||||
cairo_glyph_size_t *return_size);
|
||||
|
||||
cairo_status_t (*create_glyph) (cairo_image_glyph_cache_entry_t *entry);
|
||||
|
||||
} cairo_font_backend_t;
|
||||
|
||||
/* concrete font backends */
|
||||
extern const struct cairo_font_backend cairo_ft_font_backend;
|
||||
|
||||
typedef struct cairo_image_surface cairo_image_surface_t;
|
||||
|
||||
typedef struct cairo_surface_backend {
|
||||
cairo_surface_t *
|
||||
|
|
@ -410,6 +555,23 @@ typedef struct cairo_surface_backend {
|
|||
(*create_pattern) (void *surface,
|
||||
cairo_pattern_t *pattern,
|
||||
cairo_box_t *extents);
|
||||
|
||||
/*
|
||||
* This is an optional entry to let the surface manage its own glyph
|
||||
* resources. If null, the font will be asked to render against this
|
||||
* surface, using image surfaces as glyphs.
|
||||
*/
|
||||
cairo_status_t
|
||||
(*show_glyphs) (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
const cairo_glyph_t *glyphs,
|
||||
int num_glyphs);
|
||||
|
||||
} cairo_surface_backend_t;
|
||||
|
||||
struct cairo_matrix {
|
||||
|
|
@ -547,40 +709,6 @@ typedef struct cairo_traps {
|
|||
/* XXX: Platform-specific. Other platforms may want a different default */
|
||||
#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend
|
||||
|
||||
#define CAIRO_FONT_CACHE_SIZE_DEFAULT 256
|
||||
|
||||
typedef struct {
|
||||
unsigned long index;
|
||||
double matrix[2][2];
|
||||
|
||||
unsigned int time;
|
||||
|
||||
cairo_surface_t *surface;
|
||||
cairo_glyph_size_t size;
|
||||
} cairo_glyph_surface_t;
|
||||
|
||||
typedef struct cairo_glyph_surface_node {
|
||||
struct cairo_glyph_surface_node *next;
|
||||
struct cairo_glyph_surface_node *prev;
|
||||
|
||||
cairo_glyph_surface_t s;
|
||||
} cairo_glyph_surface_node_t;
|
||||
|
||||
typedef struct {
|
||||
cairo_glyph_surface_node_t *first;
|
||||
cairo_glyph_surface_node_t *last;
|
||||
unsigned int n_nodes;
|
||||
|
||||
unsigned int ref_count;
|
||||
unsigned int cache_size;
|
||||
} cairo_glyph_cache_t;
|
||||
|
||||
struct cairo_font {
|
||||
int refcount;
|
||||
cairo_matrix_t matrix;
|
||||
cairo_glyph_cache_t *glyph_cache;
|
||||
const struct cairo_font_backend *backend;
|
||||
};
|
||||
|
||||
#define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER
|
||||
#define CAIRO_GSTATE_TOLERANCE_DEFAULT 0.1
|
||||
|
|
@ -618,7 +746,7 @@ typedef struct cairo_gstate {
|
|||
int num_dashes;
|
||||
double dash_offset;
|
||||
|
||||
cairo_font_t *font;
|
||||
cairo_unscaled_font_t *font;
|
||||
|
||||
cairo_surface_t *surface;
|
||||
|
||||
|
|
@ -628,6 +756,9 @@ typedef struct cairo_gstate {
|
|||
cairo_clip_rec_t clip;
|
||||
|
||||
double pixels_per_inch;
|
||||
|
||||
cairo_matrix_t font_matrix;
|
||||
|
||||
cairo_matrix_t ctm;
|
||||
cairo_matrix_t ctm_inverse;
|
||||
|
||||
|
|
@ -935,6 +1066,14 @@ extern cairo_status_t __internal_linkage
|
|||
_cairo_gstate_current_font (cairo_gstate_t *gstate,
|
||||
cairo_font_t **font);
|
||||
|
||||
extern void __internal_linkage
|
||||
_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
|
||||
cairo_matrix_t *matrix);
|
||||
|
||||
extern void __internal_linkage
|
||||
_cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
|
||||
cairo_matrix_t *matrix);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
|
||||
cairo_font_extents_t *extents);
|
||||
|
|
@ -943,11 +1082,11 @@ extern cairo_status_t __internal_linkage
|
|||
_cairo_gstate_set_font (cairo_gstate_t *gstate,
|
||||
cairo_font_t *font);
|
||||
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_gstate_text_extents (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8,
|
||||
cairo_text_extents_t *extents);
|
||||
_cairo_gstate_text_to_glyphs (cairo_gstate_t *font,
|
||||
const unsigned char *utf8,
|
||||
cairo_glyph_t **glyphs,
|
||||
int *num_glyphs);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
|
||||
|
|
@ -955,19 +1094,11 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
|
|||
int num_glyphs,
|
||||
cairo_text_extents_t *extents);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_gstate_show_text (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_gstate_text_path (cairo_gstate_t *gstate,
|
||||
const unsigned char *utf8);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
|
||||
cairo_glyph_t *glyphs,
|
||||
|
|
@ -992,95 +1123,69 @@ _cairo_color_set_alpha (cairo_color_t *color, double alpha);
|
|||
|
||||
/* cairo_font.c */
|
||||
|
||||
extern cairo_font_t * __internal_linkage
|
||||
_cairo_font_create (const char *family,
|
||||
cairo_font_slant_t slant,
|
||||
cairo_font_weight_t weight);
|
||||
extern cairo_unscaled_font_t * __internal_linkage
|
||||
_cairo_unscaled_font_create (const char *family,
|
||||
cairo_font_slant_t slant,
|
||||
cairo_font_weight_t weight);
|
||||
|
||||
extern void __internal_linkage
|
||||
_cairo_font_init (cairo_font_t *scaled,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_unscaled_font_t *unscaled);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_init (cairo_font_t *font,
|
||||
const struct cairo_font_backend *backend);
|
||||
_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
|
||||
const struct cairo_font_backend *backend);
|
||||
|
||||
extern cairo_font_t * __internal_linkage
|
||||
_cairo_font_copy (cairo_font_t *font);
|
||||
extern void __internal_linkage
|
||||
_cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
|
||||
|
||||
extern void __internal_linkage
|
||||
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_scale (cairo_font_t *font, double scale);
|
||||
_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_font_extents_t *extents);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_transform (cairo_font_t *font, cairo_matrix_t *matrix);
|
||||
_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
const unsigned char *utf8,
|
||||
cairo_glyph_t **glyphs,
|
||||
int *num_glyphs);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_font_extents (cairo_font_t *font,
|
||||
cairo_font_extents_t *extents);
|
||||
_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *scale,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_text_extents_t *extents);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_text_extents (cairo_font_t *font,
|
||||
const unsigned char *utf8,
|
||||
cairo_text_extents_t *extents);
|
||||
_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *size,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_box_t *bbox);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_glyph_extents (cairo_font_t *font,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_text_extents_t *extents);
|
||||
_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *size,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_text_bbox (cairo_font_t *font,
|
||||
cairo_surface_t *surface,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8,
|
||||
cairo_box_t *bbox);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_glyph_bbox (cairo_font_t *font,
|
||||
cairo_surface_t *surface,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_box_t *bbox);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_show_text (cairo_font_t *font,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8);
|
||||
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_show_glyphs (cairo_font_t *font,
|
||||
cairo_operator_t operator,
|
||||
cairo_surface_t *source,
|
||||
cairo_surface_t *surface,
|
||||
int source_x,
|
||||
int source_y,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs);
|
||||
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_text_path (cairo_font_t *font,
|
||||
double x,
|
||||
double y,
|
||||
const unsigned char *utf8,
|
||||
cairo_path_t *path);
|
||||
|
||||
extern cairo_status_t __internal_linkage
|
||||
_cairo_font_glyph_path (cairo_font_t *font,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_path_t *path);
|
||||
|
||||
extern cairo_surface_t *__internal_linkage
|
||||
_cairo_font_lookup_glyph (cairo_font_t *font,
|
||||
cairo_surface_t *surface,
|
||||
const cairo_glyph_t *glyph,
|
||||
cairo_glyph_size_t *return_size);
|
||||
_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font,
|
||||
cairo_font_scale_t *size,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_path_t *path);
|
||||
|
||||
/* cairo_hull.c */
|
||||
extern cairo_status_t
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue