summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am81
-rw-r--r--src/cairo-atsui-font.c2
-rw-r--r--src/cairo-atsui.h11
-rw-r--r--src/cairo-cache.c104
-rw-r--r--src/cairo-color.c5
-rw-r--r--src/cairo-features.h.in6
-rw-r--r--src/cairo-fixed.c2
-rw-r--r--src/cairo-font.c479
-rw-r--r--src/cairo-ft-font.c1257
-rw-r--r--src/cairo-ft-private.h63
-rw-r--r--src/cairo-ft.h31
-rw-r--r--src/cairo-glitz-surface.c1484
-rw-r--r--src/cairo-glitz.h11
-rw-r--r--src/cairo-gstate.c1042
-rw-r--r--src/cairo-hash.c104
-rw-r--r--src/cairo-hull.c2
-rw-r--r--src/cairo-image-surface.c321
-rw-r--r--src/cairo-matrix.c170
-rw-r--r--src/cairo-path-bounds.c2
-rw-r--r--src/cairo-path-fill.c2
-rw-r--r--src/cairo-path-stroke.c2
-rw-r--r--src/cairo-path.c4
-rw-r--r--src/cairo-pattern.c1228
-rw-r--r--src/cairo-pdf-surface.c402
-rw-r--r--src/cairo-pdf.h11
-rw-r--r--src/cairo-pen.c2
-rw-r--r--src/cairo-png.h13
-rw-r--r--src/cairo-polygon.c2
-rw-r--r--src/cairo-ps-surface.c135
-rw-r--r--src/cairo-ps.h11
-rw-r--r--src/cairo-quartz-surface.c2
-rw-r--r--src/cairo-quartz.h11
-rw-r--r--src/cairo-slope.c2
-rw-r--r--src/cairo-spline.c2
-rw-r--r--src/cairo-surface.c540
-rw-r--r--src/cairo-traps.c269
-rw-r--r--src/cairo-unicode.c340
-rw-r--r--src/cairo-win32-font.c1252
-rw-r--r--src/cairo-win32-private.h87
-rw-r--r--src/cairo-win32-surface.c931
-rw-r--r--src/cairo-win32.h71
-rw-r--r--src/cairo-xcb-surface.c460
-rw-r--r--src/cairo-xcb.h11
-rw-r--r--src/cairo-xlib-surface.c619
-rw-r--r--src/cairo-xlib.h11
-rw-r--r--src/cairo.c225
-rw-r--r--src/cairo.h217
-rw-r--r--src/cairo_atsui_font.c2
-rw-r--r--src/cairo_cache.c104
-rw-r--r--src/cairo_color.c5
-rw-r--r--src/cairo_fixed.c2
-rw-r--r--src/cairo_font.c479
-rw-r--r--src/cairo_ft_font.c1257
-rw-r--r--src/cairo_gdip_font.cpp665
-rw-r--r--src/cairo_gdip_surface.cpp727
-rw-r--r--src/cairo_glitz_surface.c1484
-rw-r--r--src/cairo_gstate.c1042
-rw-r--r--src/cairo_hull.c2
-rw-r--r--src/cairo_image_surface.c321
-rw-r--r--src/cairo_matrix.c170
-rw-r--r--src/cairo_path.c4
-rw-r--r--src/cairo_path_bounds.c2
-rw-r--r--src/cairo_path_fill.c2
-rw-r--r--src/cairo_path_stroke.c2
-rw-r--r--src/cairo_pattern.c1228
-rw-r--r--src/cairo_pdf_surface.c402
-rw-r--r--src/cairo_pen.c2
-rw-r--r--src/cairo_png_surface.c118
-rw-r--r--src/cairo_polygon.c2
-rw-r--r--src/cairo_ps_surface.c135
-rw-r--r--src/cairo_quartz_surface.c2
-rw-r--r--src/cairo_slope.c2
-rw-r--r--src/cairo_spline.c2
-rw-r--r--src/cairo_surface.c540
-rw-r--r--src/cairo_traps.c269
-rw-r--r--src/cairo_unicode.c340
-rw-r--r--src/cairo_win32_font.c1252
-rw-r--r--src/cairo_win32_surface.c931
-rw-r--r--src/cairo_xcb_surface.c460
-rw-r--r--src/cairo_xlib_surface.c619
-rw-r--r--src/cairoint.h528
81 files changed, 16912 insertions, 8229 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d4155e817..3f76d2726 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,53 +1,56 @@
-cairoincludedir = $(includedir)/cairo
-cairoinclude_HEADERS = \
- cairo.h \
- cairo-atsui.h \
- cairo-features.h\
- cairo-ft.h \
- cairo-glitz.h \
- cairo-pdf.h \
- cairo-png.h \
- cairo-ps.h \
- cairo-quartz.h \
- cairo-xcb.h \
- cairo-xlib.h
-
-lib_LTLIBRARIES = libcairo.la
if CAIRO_HAS_PS_SURFACE
-libcairo_ps_sources = cairo_ps_surface.c cairo-ps.h
+libcairo_ps_headers = cairo-ps.h
+libcairo_ps_sources = cairo_ps_surface.c
endif
if CAIRO_HAS_PDF_SURFACE
-libcairo_pdf_sources = cairo_pdf_surface.c cairo-pdf.h
+libcairo_pdf_headers = cairo-pdf.h
+libcairo_pdf_sources = cairo_pdf_surface.c
endif
if CAIRO_HAS_PNG_SURFACE
-libcairo_png_sources = cairo_png_surface.c cairo-png.h
+libcairo_png_headers = cairo-png.h
+libcairo_png_sources = cairo_png_surface.c
endif
if CAIRO_HAS_XLIB_SURFACE
-libcairo_xlib_sources = cairo_xlib_surface.c cairo-xlib.h
+libcairo_xlib_headers = cairo-xlib.h
+libcairo_xlib_sources = cairo_xlib_surface.c
endif
if CAIRO_HAS_QUARTZ_SURFACE
-libcairo_quartz_sources = cairo_quartz_surface.c cairo-quartz.h
+libcairo_quartz_headers = cairo-quartz.h
+libcairo_quartz_sources = cairo_quartz_surface.c
endif
if CAIRO_HAS_XCB_SURFACE
-libcairo_xcb_sources = cairo_xcb_surface.c cairo-xcb.h
+libcairo_xcb_headers = cairo-xcb.h
+libcairo_xcb_sources = cairo_xcb_surface.c
+endif
+
+libcairo_win32_sources =
+if CAIRO_HAS_WIN32_SURFACE
+libcairo_win32_headers = cairo-win32.h
+libcairo_win32_sources += cairo_win32_surface.c cairo-win32-private.h
+endif
+if CAIRO_HAS_WIN32_FONT
+libcairo_win32_sources += cairo_win32_font.c
endif
if CAIRO_HAS_GLITZ_SURFACE
-libcairo_glitz_sources = cairo_glitz_surface.c cairo-glitz.h
+libcairo_glitz_headers = cairo-glitz.h
+libcairo_glitz_sources = cairo_glitz_surface.c
endif
if CAIRO_HAS_ATSUI_FONT
-libcairo_atsui_sources = cairo_atsui_font.c cairo-atsui.h
+libcairo_atsui_headers = cairo-atsui.h
+libcairo_atsui_sources = cairo_atsui_font.c
endif
if CAIRO_HAS_FT_FONT
-libcairo_ft_sources = cairo_ft_font.c cairo-ft.h
+libcairo_ft_headers = cairo-ft.h
+libcairo_ft_sources = cairo_ft_font.c cairo-ft-private.h
endif
# These names match automake style variable definition conventions so
@@ -57,6 +60,23 @@ endif
FONTCONFIG_LIBS=@FONTCONFIG_LIBS@
XRENDER_LIBS=@XRENDER_LIBS@
+cairoincludedir = $(includedir)/cairo
+cairoinclude_HEADERS = \
+ cairo.h \
+ cairo-features.h \
+ $(libcairo_atsui_headers) \
+ $(libcairo_ft_headers) \
+ $(libcairo_glitz_headers) \
+ $(libcairo_pdf_headers) \
+ $(libcairo_png_headers) \
+ $(libcairo_ps_headers) \
+ $(libcairo_quartz_headers) \
+ $(libcairo_win32_headers) \
+ $(libcairo_xcb_headers) \
+ $(libcairo_xlib_headers)
+
+lib_LTLIBRARIES = libcairo.la
+
libcairo_la_SOURCES = \
cairo.c \
cairo.h \
@@ -80,6 +100,7 @@ libcairo_la_SOURCES = \
cairo_surface.c \
cairo_traps.c \
cairo_pattern.c \
+ cairo_unicode.c \
cairo_wideint.c \
cairo-wideint.h \
$(libcairo_atsui_sources)\
@@ -91,6 +112,8 @@ libcairo_la_SOURCES = \
$(libcairo_quartz_sources)\
$(libcairo_xcb_sources) \
$(libcairo_glitz_sources)\
+ $(libcairo_win32_sources)\
+ $(libcairo_freetype_sources) \
cairoint.h
libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined
@@ -98,3 +121,13 @@ libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined
INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS)
libcairo_la_LIBADD = $(CAIRO_LIBS)
+
+install-data-local:
+ @if test -f $(includedir)/cairo.h || test -f $(includedir)/cairo-features.h ; then \
+ echo "****************************************************************" ; \
+ echo "*** Error: Old headers found. You should remove the following" ; \
+ echo "*** files and then type 'make install' again." ; \
+ ls $(includedir)/cairo*.h ; \
+ echo "****************************************************************" ; \
+ false ; \
+ fi
diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c
index 52cfc6bd8..cb4b1c5d7 100644
--- a/src/cairo-atsui-font.c
+++ b/src/cairo-atsui-font.c
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2004 Calum Robinson
+ * Copyright © 2004 Calum Robinson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
diff --git a/src/cairo-atsui.h b/src/cairo-atsui.h
index 94b30432a..a5b7308f8 100644
--- a/src/cairo-atsui.h
+++ b/src/cairo-atsui.h
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2004 Calum Robinson
+ * Copyright © 2004 Calum Robinson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -33,18 +33,23 @@
* Calum Robinson <calumr@mac.com>
*/
-#include <cairo.h>
-
#ifndef CAIRO_ATSUI_H
#define CAIRO_ATSUI_H
+
+#include <cairo.h>
+
#ifdef CAIRO_HAS_ATSUI_FONT
/* ATSUI platform-specific font interface */
#include <Carbon/Carbon.h>
+CAIRO_BEGIN_DECLS
+
cairo_font_t *
cairo_atsui_font_create(ATSUStyle style);
+CAIRO_END_DECLS
+
#endif /* CAIRO_HAS_ATSUI_FONT */
#endif /* CAIRO_ATSUI_H */
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index b097b609b..d1ad5a4e2 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -94,9 +94,9 @@ static const cairo_cache_arrangement_t cache_arrangements [] = {
* 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.
+ * cache will expire entries randomly as it experiences memory pressure.
+ * If max_memory is set, entries are not expired, and must be explicitely
+ * removed.
*
* 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
@@ -282,17 +282,51 @@ _load_factor (cairo_cache_t *cache)
}
#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;
-}
+/* Find a random in the cache matching the given predicate. We use the
+ * same algorithm as the probing algorithm to walk over the entries in
+ * the hash table in a pseudo-random order. Walking linearly would
+ * favor entries following gaps in the hash table. We could also
+ * call rand() repeatedly, which works well for almost-full tables,
+ * but degrades when the table is almost empty, or predicate
+ * returns false for most entries.
+ */
+static cairo_cache_entry_base_t **
+_random_entry (cairo_cache_t *cache,
+ int (*predicate)(void*))
+{
+ cairo_cache_entry_base_t **probe;
+ unsigned long hash;
+ unsigned long table_size, i, idx, step;
+
+ _cache_sane_state (cache);
+
+ table_size = cache->arrangement->size;
+ hash = rand ();
+ idx = hash % table_size;
+ step = 0;
+
+ for (i = 0; i < table_size; ++i)
+ {
+ assert(idx < table_size);
+ probe = cache->entries + idx;
+ if (LIVE_ENTRY_P(cache, idx)
+ && (!predicate || predicate (*probe)))
+ return probe;
+
+ if (step == 0) {
+ step = hash % cache->arrangement->rehash;
+ if (step == 0)
+ step = 1;
+ }
+
+ idx += step;
+ if (idx >= table_size)
+ idx -= table_size;
+ }
+
+ return NULL;
+}
/* public API follows */
@@ -356,8 +390,9 @@ _cairo_cache_destroy (cairo_cache_t *cache)
cairo_status_t
_cairo_cache_lookup (cairo_cache_t *cache,
- void *key,
- void **entry_return)
+ void *key,
+ void **entry_return,
+ int *created_entry)
{
unsigned long idx;
@@ -392,6 +427,8 @@ _cairo_cache_lookup (cairo_cache_t *cache,
cache->hits++;
#endif
*entry_return = *slot;
+ if (created_entry)
+ *created_entry = 0;
return status;
}
@@ -401,19 +438,18 @@ _cairo_cache_lookup (cairo_cache_t *cache,
/* Build the new entry. */
status = cache->backend->create_entry (cache, key,
- entry_return);
+ (void **)&new_entry);
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 > 0 &&
((cache->max_memory - cache->used_memory) < new_entry->memory)) {
- idx = _random_live_entry (cache);
+ idx = _random_entry (cache, NULL) - cache->entries;
assert (idx < cache->arrangement->size);
_entry_destroy (cache, idx);
}
@@ -425,7 +461,6 @@ _cairo_cache_lookup (cairo_cache_t *cache,
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;
}
@@ -439,9 +474,38 @@ _cairo_cache_lookup (cairo_cache_t *cache,
_cache_sane_state (cache);
+ *entry_return = new_entry;
+ if (created_entry)
+ *created_entry = 1;
+
return status;
}
+cairo_status_t
+_cairo_cache_remove (cairo_cache_t *cache,
+ void *key)
+{
+ cairo_cache_entry_base_t **slot;
+
+ _cache_sane_state (cache);
+
+ /* See if we have an entry in the table already. */
+ slot = _find_exact_live_entry_for (cache, key);
+ if (slot != NULL)
+ _entry_destroy (cache, slot - cache->entries);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void *
+_cairo_cache_random_entry (cairo_cache_t *cache,
+ int (*predicate)(void*))
+{
+ cairo_cache_entry_base_t **slot = _random_entry (cache, predicate);
+
+ return slot ? *slot : NULL;
+}
+
unsigned long
_cairo_hash_string (const char *c)
{
diff --git a/src/cairo-color.c b/src/cairo-color.c
index 899b1e3d5..f203d96cc 100644
--- a/src/cairo-color.c
+++ b/src/cairo-color.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
@@ -67,7 +67,8 @@ _cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blu
}
void
-_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue)
+_cairo_color_get_rgb (const cairo_color_t *color,
+ double *red, double *green, double *blue)
{
if (red)
*red = color->red;
diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in
index e2a62ba66..a13250d97 100644
--- a/src/cairo-features.h.in
+++ b/src/cairo-features.h.in
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl Worth <cworth@east.isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#ifndef CAIRO_FEATURES_H
@@ -49,10 +49,14 @@
#define @XCB_SURFACE_FEATURE@
+#define @WIN32_SURFACE_FEATURE@
+
#define @GLITZ_SURFACE_FEATURE@
#define @FT_FONT_FEATURE@
+#define @WIN32_FONT_FEATURE@
+
#define @ATSUI_FONT_FEATURE@
#define @SANITY_CHECKING_FEATURE@
diff --git a/src/cairo-fixed.c b/src/cairo-fixed.c
index ee31718ef..a4faa1708 100644
--- a/src/cairo-fixed.c
+++ b/src/cairo-fixed.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo-font.c b/src/cairo-font.c
index f5fc0e981..529c1c7c3 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 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
@@ -31,293 +32,129 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
+ * Graydon Hoare <graydon@redhat.com>
+ * Owen Taylor <otaylor@redhat.com>
*/
#include "cairoint.h"
-/* First we implement a global font cache for named fonts. */
-
-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;
-
-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)
-{
- unsigned long hash;
- cairo_font_cache_key_t *in;
- in = (cairo_font_cache_key_t *) key;
-
- /* 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)
-{
- const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
- cairo_font_cache_key_t *k;
- cairo_font_cache_entry_t *entry;
- k = (cairo_font_cache_key_t *) key;
-
- /* XXX: The current freetype backend may return NULL, (for example
- * if no fonts are installed), but I would like to guarantee that
- * the toy API always returns at least *some* font, so I would
- * like to build in some sort fo font here, (even a really lame,
- * ugly one if necessary). */
-
- 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);
-}
-
-static const cairo_cache_backend_t 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_private cairo_status_t
+_cairo_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ cairo_font_scale_t *sc,
+ cairo_font_t **font)
{
- 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;
- }
+ const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
- _cairo_unscaled_font_reference (font->unscaled);
- _unlock_global_font_cache ();
- return font->unscaled;
+ return backend->create (family, slant, weight, sc, font);
}
void
-_cairo_font_init (cairo_font_t *scaled,
- cairo_font_scale_t *scale,
- cairo_unscaled_font_t *unscaled)
+_cairo_font_init (cairo_font_t *font,
+ cairo_font_scale_t *scale,
+ const cairo_font_backend_t *backend)
{
- scaled->scale = *scale;
- scaled->unscaled = unscaled;
- scaled->refcount = 1;
+ font->scale = *scale;
+ font->refcount = 1;
+ font->backend = backend;
}
-cairo_status_t
-_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const cairo_font_backend_t *backend)
+void
+_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
+ const cairo_font_backend_t *backend)
{
font->refcount = 1;
font->backend = backend;
- return CAIRO_STATUS_SUCCESS;
}
-
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)
+_cairo_font_text_to_glyphs (cairo_font_t *font,
+ const unsigned char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
{
- return font->backend->text_to_glyphs (font, scale, utf8, glyphs, num_glyphs);
+ return font->backend->text_to_glyphs (font, 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)
+_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, scale, glyphs, num_glyphs, extents);
+ return font->backend->glyph_extents(font, 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)
+_cairo_font_glyph_bbox (cairo_font_t *font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
{
- return font->backend->glyph_bbox (font, scale, glyphs, num_glyphs, bbox);
+ return font->backend->glyph_bbox (font, 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_font_show_glyphs (cairo_font_t *font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glyph_t *glyphs,
+ int num_glyphs)
{
cairo_status_t status;
if (surface->backend->show_glyphs != NULL) {
- status = surface->backend->show_glyphs (font, scale, operator, source,
- surface, source_x, source_y,
+ status = surface->backend->show_glyphs (font, operator, pattern,
+ surface,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
glyphs, num_glyphs);
if (status == CAIRO_STATUS_SUCCESS)
return status;
}
/* Surface display routine either does not exist or failed. */
- return font->backend->show_glyphs (font, scale, operator, source,
- surface, source_x, source_y,
+ return font->backend->show_glyphs (font, operator, pattern,
+ surface,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
glyphs, num_glyphs);
}
cairo_status_t
-_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)
+_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);
+}
+
+void
+_cairo_font_get_glyph_cache_key (cairo_font_t *font,
+ cairo_glyph_cache_key_t *key)
{
- return font->backend->glyph_path (font, scale, glyphs, num_glyphs, path);
+ font->backend->get_glyph_cache_key (font, key);
}
cairo_status_t
-_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
- cairo_font_extents_t *extents)
+_cairo_font_font_extents (cairo_font_t *font,
+ cairo_font_extents_t *extents)
{
- return font->backend->font_extents(font, scale, extents);
+ return font->backend->font_extents (font, extents);
}
void
@@ -332,8 +169,7 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font)
if (--(font->refcount) > 0)
return;
- if (font->backend)
- font->backend->destroy (font);
+ font->backend->destroy_unscaled_font (font);
}
@@ -352,37 +188,154 @@ cairo_font_destroy (cairo_font_t *font)
if (--(font->refcount) > 0)
return;
- if (font->unscaled)
- _cairo_unscaled_font_destroy (font->unscaled);
-
- free (font);
+ font->backend->destroy_font (font);
}
-void
-cairo_font_set_transform (cairo_font_t *font,
- cairo_matrix_t *matrix)
+/**
+ * cairo_font_extents:
+ * @font: a #cairo_font_t
+ * @font_matrix: the font transformation for which this font was
+ * created. (See cairo_transform_font()). This is needed
+ * properly convert the metrics from the font into user space.
+ * @extents: a #cairo_font_extents_t which to store the retrieved extents.
+ *
+ * Gets the metrics for a #cairo_font_t.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an
+ * error such as %CAIRO_STATUS_NO_MEMORY.
+ **/
+cairo_status_t
+cairo_font_extents (cairo_font_t *font,
+ cairo_matrix_t *font_matrix,
+ cairo_font_extents_t *extents)
{
- 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);
+ cairo_int_status_t status;
+ double font_scale_x, font_scale_y;
+
+ status = _cairo_font_font_extents (font, extents);
+
+ if (!CAIRO_OK (status))
+ return status;
+
+ _cairo_matrix_compute_scale_factors (font_matrix,
+ &font_scale_x, &font_scale_y,
+ /* XXX */ 1);
+
+ /*
+ * The font responded in unscaled units, scale by the font
+ * matrix scale factors to get to user space
+ */
+
+ extents->ascent *= font_scale_y;
+ extents->descent *= font_scale_y;
+ extents->height *= font_scale_y;
+ extents->max_x_advance *= font_scale_x;
+ extents->max_y_advance *= font_scale_y;
+
+ return status;
}
+/**
+ * cairo_font_glyph_extents:
+ * @font: a #cairo_font_t
+ * @font_matrix: the font transformation for which this font was
+ * created. (See cairo_transform_font()). This is needed
+ * properly convert the metrics from the font into user space.
+ * @glyphs: an array of glyph IDs with X and Y offsets.
+ * @num_glyphs: the number of glyphs in the @glyphs array
+ * @extents: a #cairo_text_extents_t which to store the retrieved extents.
+ *
+ * cairo_font_glyph_extents() gets the overall metrics for a string of
+ * glyphs. The X and Y offsets in @glyphs are taken from an origin of 0,0.
+ **/
void
-cairo_font_current_transform (cairo_font_t *font,
- cairo_matrix_t *matrix)
+cairo_font_glyph_extents (cairo_font_t *font,
+ cairo_matrix_t *font_matrix,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
- 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);
-}
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_glyph_t origin_glyph;
+ cairo_text_extents_t origin_extents;
+ int i;
+ double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
+ double x_pos = 0.0, y_pos = 0.0;
+ int set = 0;
+
+ if (!num_glyphs)
+ {
+ extents->x_bearing = 0.0;
+ extents->y_bearing = 0.0;
+ extents->width = 0.0;
+ extents->height = 0.0;
+ extents->x_advance = 0.0;
+ extents->y_advance = 0.0;
+
+ return;
+ }
+ for (i = 0; i < num_glyphs; i++)
+ {
+ double x, y;
+ double wm, hm;
+
+ origin_glyph = glyphs[i];
+ origin_glyph.x = 0.0;
+ origin_glyph.y = 0.0;
+ status = _cairo_font_glyph_extents (font,
+ &origin_glyph, 1,
+ &origin_extents);
+
+ /*
+ * Transform font space metrics into user space metrics
+ * by running the corners through the font matrix and
+ * expanding the bounding box as necessary
+ */
+ x = origin_extents.x_bearing;
+ y = origin_extents.y_bearing;
+ cairo_matrix_transform_point (font_matrix,
+ &x, &y);
+
+ for (hm = 0.0; hm <= 1.0; hm += 1.0)
+ for (wm = 0.0; wm <= 1.0; wm += 1.0)
+ {
+ x = origin_extents.x_bearing + origin_extents.width * wm;
+ y = origin_extents.y_bearing + origin_extents.height * hm;
+ cairo_matrix_transform_point (font_matrix,
+ &x, &y);
+ x += glyphs[i].x;
+ y += glyphs[i].y;
+ if (!set)
+ {
+ min_x = max_x = x;
+ min_y = max_y = y;
+ set = 1;
+ }
+ else
+ {
+ if (x < min_x) min_x = x;
+ if (x > max_x) max_x = x;
+ if (y < min_y) min_y = y;
+ if (y > max_y) max_y = y;
+ }
+ }
+
+ x = origin_extents.x_advance;
+ y = origin_extents.y_advance;
+ cairo_matrix_transform_point (font_matrix,
+ &x, &y);
+ x_pos = glyphs[i].x + x;
+ y_pos = glyphs[i].y + y;
+ }
+
+ extents->x_bearing = min_x - glyphs[0].x;
+ extents->y_bearing = min_y - glyphs[0].y;
+ extents->width = max_x - min_x;
+ extents->height = max_y - min_y;
+ extents->x_advance = x_pos - glyphs[0].x;
+ extents->y_advance = y_pos - glyphs[0].y;
+}
/* Now we implement functions to access a default global image & metrics
* cache.
@@ -398,7 +351,8 @@ _cairo_glyph_cache_hash (void *cache, void *key)
^ ((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])
+ ^ ((unsigned long) in->scale.matrix[1][1])
+ ^ (in->flags * 1451) /* 1451 is just an abitrary prime */
^ in->index;
}
@@ -412,6 +366,7 @@ _cairo_glyph_cache_keys_equal (void *cache,
b = (cairo_glyph_cache_key_t *) k2;
return (a->index == b->index)
&& (a->unscaled == b->unscaled)
+ && (a->flags == b->flags)
&& (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])
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index b928b04fc..44e1b0e84 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -1,29 +1,40 @@
-/*
- * Copyright © 2003 Red Hat Inc.
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 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
*
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee,
- * provided that the above copyright notice appear in all copies and that
- * both that copyright notice and this permission notice appear in
- * supporting documentation, and that the name of Red Hat Inc. not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. Red Hat Inc. makes no
- * representations about the suitability of this software for any purpose.
- * It is provided "as is" without express or implied warranty.
+ * 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/
*
- * RED HAT INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL RED HAT INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
- * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * 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.
*
- * Author: Graydon Hoare <graydon@redhat.com>
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Graydon Hoare <graydon@redhat.com>
+ * Owen Taylor <otaylor@redhat.com>
*/
-#include "cairoint.h"
-#include "cairo-ft.h"
+#include "cairo-ft-private.h"
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
@@ -38,19 +49,9 @@
#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))
#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0)
-/*
- * First we make a private, sharable implementation object which can be
- * stored both in a private cache and in public font objects (including
- * those connected to fonts we don't own)
+/* This is the max number of FT_face objects we keep open at once
*/
-
-typedef struct {
- int refcount;
-
- FT_Face face;
- int owns_face;
-
-} ft_font_val_t;
+#define MAX_OPEN_FACES 10
/*
* The simple 2x2 matrix is converted into separate scale and shape
@@ -62,141 +63,126 @@ typedef struct {
double shape[2][2];
} ft_font_transform_t;
-static ft_font_val_t *
-_create_from_face (FT_Face face, int owns_face)
-{
- ft_font_val_t *tmp = malloc (sizeof(ft_font_val_t));
- if (tmp) {
- tmp->refcount = 1;
- tmp->face = face;
- tmp->owns_face = owns_face;
- FT_Set_Char_Size (face,
- DOUBLE_TO_26_6 (1.0),
- DOUBLE_TO_26_6 (1.0),
- 0, 0);
- }
- return tmp;
-}
+/*
+ * We create an object that corresponds to a single font on the disk;
+ * (identified by a filename/id pair) these are shared between all
+ * fonts using that file. For cairo_ft_font_create_for_ft_face(), we
+ * just create a one-off version with a permanent face value.
+ */
-static void
-_reference_font_val (ft_font_val_t *f)
-{
- f->refcount++;
-}
+typedef struct {
+ cairo_unscaled_font_t base;
-static void
-_destroy_font_val (ft_font_val_t *f)
-{
- if (--(f->refcount) > 0)
- return;
+ int from_face; /* from cairo_ft_font_create_for_ft_face()? */
+ FT_Face face; /* provided or cached face */
- if (f->owns_face)
- FT_Done_Face (f->face);
+ /* only set if from_face is false */
+ FT_Library library;
+ char *filename;
+ int id;
- free (f);
-}
+ /* We temporarily scale the unscaled font as neede */
+ int have_scale;
+ cairo_font_scale_t current_scale;
+ double x_scale; /* Extracted X scale factor */
+ double y_scale; /* Extracted Y scale factor */
+
+ int lock; /* count of how many times this font has been locked */
+} ft_unscaled_font_t;
-static ft_font_val_t *
-_create_from_library_and_pattern (FT_Library ft_library, FcPattern *pattern)
-{
- ft_font_val_t *f = NULL;
- char *filename = NULL;
- int owns_face = 0;
- FT_Face face = NULL;
- FcPattern *resolved = NULL;
- FcResult result = FcResultMatch;
+const cairo_font_backend_t cairo_ft_font_backend;
- if (pattern == NULL)
- goto FAIL;
+static ft_unscaled_font_t *
+_ft_unscaled_font_create_from_face (FT_Face face)
+{
+ ft_unscaled_font_t *unscaled = malloc (sizeof(ft_unscaled_font_t));
+ if (!unscaled)
+ return NULL;
+
+ unscaled->from_face = 1;
+ unscaled->face = face;
- FcConfigSubstitute (0, pattern, FcMatchPattern);
- FcDefaultSubstitute (pattern);
+ unscaled->library = NULL;
+ unscaled->filename = NULL;
+ unscaled->id = 0;
- resolved = FcFontMatch (0, pattern, &result);
- if (!resolved)
- goto FAIL;
+ unscaled->have_scale = 0;
+ unscaled->lock = 0;
- if (result != FcResultMatch)
- goto FREE_RESOLVED;
+ _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
+ &cairo_ft_font_backend);
+ return unscaled;
+}
+
+static ft_unscaled_font_t *
+_ft_unscaled_font_create_from_filename (FT_Library library,
+ const char *filename,
+ int id)
+{
+ ft_unscaled_font_t *unscaled;
+ char *new_filename;
- /* If the pattern has an FT_Face object, use that. */
- if (FcPatternGetFTFace (resolved, FC_FT_FACE, 0, &face) != FcResultMatch
- || face == NULL)
- {
- /* otherwise it had better have a filename */
- result = FcPatternGetString (resolved, FC_FILE, 0, (FcChar8 **)(&filename));
-
- if (result == FcResultMatch)
- if (FT_New_Face (ft_library, filename, 0, &face))
- goto FREE_RESOLVED;
-
- if (face == NULL)
- goto FREE_RESOLVED;
-
- owns_face = 1;
+ new_filename = strdup (filename);
+ if (!new_filename)
+ return NULL;
+
+ unscaled = malloc (sizeof (ft_unscaled_font_t));
+ if (!unscaled) {
+ free (new_filename);
+ return NULL;
}
+
+ unscaled->from_face = 0;
+ unscaled->face = NULL;
- f = _create_from_face (face, owns_face);
-
- FcPatternDestroy (resolved);
- return f;
+ unscaled->library = library;
+ unscaled->filename = new_filename;
+ unscaled->id = id;
- FREE_RESOLVED:
- if (resolved)
- FcPatternDestroy (resolved);
-
- FAIL:
- return NULL;
+ unscaled->have_scale = 0;
+ unscaled->lock = 0;
+
+ _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
+ &cairo_ft_font_backend);
+ return unscaled;
}
-
-/*
- * We then make the user-exposed structure out of one of these impls, such
- * that it is reasonably cheap to copy and/or destroy. Unfortunately this
- * duplicates a certain amount of the caching machinery in the font cache,
- * but that's unavoidable as we also provide an FcPattern resolution API,
- * which is not part of cairo's generic font finding system.
- */
-
-typedef struct {
- cairo_unscaled_font_t base;
- FcPattern *pattern;
- ft_font_val_t *val;
-} cairo_ft_font_t;
-
-/*
- * We then make a key and entry type which are compatible with the generic
- * cache system. This cache serves to share single ft_font_val_t instances
- * between fonts (or between font lifecycles).
+/*
+ * We keep a global cache from [file/id] => [ft_unscaled_font_t]. This
+ * hash isn't limited in size. However, we limit the number of
+ * FT_Face objects we keep around; when we've exceeeded that
+ * limit and need to create a new FT_Face, we dump the FT_Face from
+ * a random ft_unscaled_font_t.
*/
typedef struct {
cairo_cache_entry_base_t base;
- FcPattern *pattern;
+ char *filename;
+ int id;
} cairo_ft_cache_key_t;
typedef struct {
cairo_ft_cache_key_t key;
- ft_font_val_t *val;
+ ft_unscaled_font_t *unscaled;
} cairo_ft_cache_entry_t;
-/*
- * Then we create a cache which maps FcPattern keys to the refcounted
- * ft_font_val_t values.
- */
-
typedef struct {
cairo_cache_t base;
FT_Library lib;
+ int n_faces; /* Number of open FT_Face objects */
} ft_cache_t;
-
static unsigned long
_ft_font_cache_hash (void *cache, void *key)
{
- cairo_ft_cache_key_t *in;
- in = (cairo_ft_cache_key_t *) key;
- return FcPatternHash (in->pattern);
+ cairo_ft_cache_key_t *in = (cairo_ft_cache_key_t *) key;
+ unsigned long hash;
+
+ /* 1607 is just a random prime. */
+ hash = _cairo_hash_string (in->filename);
+ hash += ((unsigned long) in->id) * 1607;
+
+ return hash;
}
static int
@@ -208,10 +194,10 @@ _ft_font_cache_keys_equal (void *cache,
cairo_ft_cache_key_t *b;
a = (cairo_ft_cache_key_t *) k1;
b = (cairo_ft_cache_key_t *) k2;
-
- return FcPatternEqual (a->pattern, b->pattern);
-}
+ return strcmp (a->filename, b->filename) == 0 &&
+ a->id == b->id;
+}
static cairo_status_t
_ft_font_cache_create_entry (void *cache,
@@ -226,27 +212,33 @@ _ft_font_cache_create_entry (void *cache,
if (entry == NULL)
return CAIRO_STATUS_NO_MEMORY;
- entry->key.pattern = FcPatternDuplicate (k->pattern);
- if (!entry->key.pattern) {
+ entry->unscaled = _ft_unscaled_font_create_from_filename (ftcache->lib,
+ k->filename,
+ k->id);
+ if (!entry->unscaled) {
free (entry);
return CAIRO_STATUS_NO_MEMORY;
}
-
- entry->val = _create_from_library_and_pattern (ftcache->lib, entry->key.pattern);
- entry->key.base.memory = 1;
-
+
+ entry->key.base.memory = 0;
+ entry->key.filename = entry->unscaled->filename;
+ entry->key.id = entry->unscaled->id;
+
*return_entry = entry;
return CAIRO_STATUS_SUCCESS;
}
+/* Entries are never spontaneously destroyed; but only when
+ * we remove them from the cache specifically. We free entry->unscaled
+ * in the code that removes the entry from the cache
+ */
static void
_ft_font_cache_destroy_entry (void *cache,
void *entry)
{
cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry;
- FcPatternDestroy (e->key.pattern);
- _destroy_font_val (e->val);
+
free (e);
}
@@ -291,11 +283,12 @@ _get_global_ft_cache (void)
if (_cairo_cache_init (&_global_ft_cache->base,
&_ft_font_cache_backend,
- CAIRO_FT_CACHE_NUM_FONTS_DEFAULT))
+ 0)) /* No memory limit */
goto FAIL;
if (FT_Init_FreeType (&_global_ft_cache->lib))
goto FAIL;
+ _global_ft_cache->n_faces = 0;
}
return &_global_ft_cache->base;
@@ -306,30 +299,304 @@ _get_global_ft_cache (void)
return NULL;
}
-/* implement the backend interface */
+/* Finds or creates a ft_unscaled_font for the filename/id from pattern.
+ * Returns a new reference to the unscaled font.
+ */
+static ft_unscaled_font_t *
+_ft_unscaled_font_get_for_pattern (FcPattern *pattern)
+{
+ cairo_ft_cache_entry_t *entry;
+ cairo_ft_cache_key_t key;
+ cairo_cache_t *cache;
+ cairo_status_t status;
+ FcChar8 *filename;
+ int created_entry;
+
+ if (FcPatternGetString (pattern, FC_FILE, 0, &filename) != FcResultMatch)
+ return NULL;
+ key.filename = (char *)filename;
+
+ if (FcPatternGetInteger (pattern, FC_INDEX, 0, &key.id) != FcResultMatch)
+ return NULL;
+
+ _lock_global_ft_cache ();
+ cache = _get_global_ft_cache ();
+ if (cache == NULL) {
+ _unlock_global_ft_cache ();
+ return NULL;
+ }
+
+ status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry);
+ _unlock_global_ft_cache ();
+ if (status)
+ return NULL;
+
+ if (!created_entry)
+ _cairo_unscaled_font_reference ((cairo_unscaled_font_t *)entry->unscaled);
+
+ return entry->unscaled;
+}
+
+static int
+_has_unlocked_face (void *entry)
+{
+ cairo_ft_cache_entry_t *e = entry;
-const cairo_font_backend_t cairo_ft_font_backend;
+ return (e->unscaled->lock == 0 && e->unscaled->face);
+}
+
+/* Ensures that an unscaled font has a face object. If we exceed
+ * MAX_OPEN_FACES, try to close some.
+ */
+static FT_Face
+_ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled)
+{
+ ft_cache_t *ftcache;
+ FT_Face face = NULL;
+
+ if (unscaled->face) {
+ unscaled->lock++;
+ return unscaled->face;
+ }
-static cairo_unscaled_font_t *
-_cairo_ft_font_create (const char *family,
+ assert (!unscaled->from_face);
+
+ _lock_global_ft_cache ();
+ ftcache = (ft_cache_t *) _get_global_ft_cache ();
+ assert (ftcache != NULL);
+
+ while (ftcache->n_faces >= MAX_OPEN_FACES) {
+ cairo_ft_cache_entry_t *entry;
+
+ entry = _cairo_cache_random_entry ((cairo_cache_t *)ftcache, _has_unlocked_face);
+ if (entry) {
+ FT_Done_Face (entry->unscaled->face);
+ entry->unscaled->face = NULL;
+ entry->unscaled->have_scale = 0;
+ ftcache->n_faces--;
+ } else {
+ break;
+ }
+ }
+
+ if (FT_New_Face (ftcache->lib,
+ unscaled->filename,
+ unscaled->id,
+ &face) != FT_Err_Ok)
+ goto FAIL;
+
+ unscaled->face = face;
+ unscaled->lock++;
+ ftcache->n_faces++;
+
+ FAIL:
+ _unlock_global_ft_cache ();
+ return face;
+}
+
+/* Unlock unscaled font locked with _ft_unscaled_font_lock_face
+ */
+static void
+_ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled)
+{
+ assert (unscaled->lock > 0);
+
+ unscaled->lock--;
+}
+
+static void
+_compute_transform (ft_font_transform_t *sf,
+ cairo_font_scale_t *sc)
+{
+ cairo_matrix_t normalized;
+ double tx, ty;
+
+ /* The font matrix has x and y "scale" components which we extract and
+ * use as character scale values. These influence the way freetype
+ * chooses hints, as well as selecting different bitmaps in
+ * hand-rendered fonts. We also copy the normalized matrix to
+ * freetype's transformation.
+ */
+
+ cairo_matrix_set_affine (&normalized,
+ sc->matrix[0][0],
+ sc->matrix[0][1],
+ sc->matrix[1][0],
+ sc->matrix[1][1],
+ 0, 0);
+
+ _cairo_matrix_compute_scale_factors (&normalized,
+ &sf->x_scale, &sf->y_scale,
+ /* XXX */ 1);
+ cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
+ cairo_matrix_get_affine (&normalized,
+ &sf->shape[0][0], &sf->shape[0][1],
+ &sf->shape[1][0], &sf->shape[1][1],
+ &tx, &ty);
+}
+
+/* Temporarily scales an unscaled font to the give scale. We catch
+ * scaling to the same size, since changing a FT_Face is expensive.
+ */
+static void
+_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
+ cairo_font_scale_t *scale)
+{
+ ft_font_transform_t sf;
+ FT_Matrix mat;
+
+ assert (unscaled->face != NULL);
+
+ if (unscaled->have_scale &&
+ scale->matrix[0][0] == unscaled->current_scale.matrix[0][0] &&
+ scale->matrix[0][1] == unscaled->current_scale.matrix[0][1] &&
+ scale->matrix[1][0] == unscaled->current_scale.matrix[1][0] &&
+ scale->matrix[1][1] == unscaled->current_scale.matrix[1][1])
+ return;
+
+ unscaled->have_scale = 1;
+ unscaled->current_scale = *scale;
+
+ _compute_transform (&sf, scale);
+
+ unscaled->x_scale = sf.x_scale;
+ unscaled->y_scale = sf.y_scale;
+
+ mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]);
+ mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]);
+ mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]);
+ mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]);
+
+ FT_Set_Transform(unscaled->face, &mat, NULL);
+
+ FT_Set_Pixel_Sizes(unscaled->face,
+ (FT_UInt) sf.x_scale,
+ (FT_UInt) sf.y_scale);
+}
+
+/* implement the font backend interface */
+
+typedef struct {
+ cairo_font_t base;
+ FcPattern *pattern;
+ int load_flags;
+ ft_unscaled_font_t *unscaled;
+} cairo_ft_font_t;
+
+/* for compatibility with older freetype versions */
+#ifndef FT_LOAD_TARGET_MONO
+#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME
+#endif
+
+/* The load flags passed to FT_Load_Glyph control aspects like hinting and
+ * antialiasing. Here we compute them from the fields of a FcPattern.
+ */
+static int
+_get_load_flags (FcPattern *pattern)
+{
+ FcBool antialias, hinting, autohint;
+#ifdef FC_HINT_STYLE
+ int hintstyle;
+#endif
+ int load_flags = 0;
+
+ /* disable antialiasing if requested */
+ if (FcPatternGetBool (pattern,
+ FC_ANTIALIAS, 0, &antialias) != FcResultMatch)
+ antialias = FcTrue;
+
+ if (antialias)
+ load_flags |= FT_LOAD_NO_BITMAP;
+ else
+ load_flags |= FT_LOAD_TARGET_MONO;
+
+ /* disable hinting if requested */
+ if (FcPatternGetBool (pattern,
+ FC_HINTING, 0, &hinting) != FcResultMatch)
+ hinting = FcTrue;
+
+#ifdef FC_HINT_STYLE
+ if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch)
+ hintstyle = FC_HINT_FULL;
+
+ if (!hinting || hintstyle == FC_HINT_NONE)
+ load_flags |= FT_LOAD_NO_HINTING;
+
+ switch (hintstyle) {
+ case FC_HINT_SLIGHT:
+ case FC_HINT_MEDIUM:
+ load_flags |= FT_LOAD_TARGET_LIGHT;
+ break;
+ default:
+ load_flags |= FT_LOAD_TARGET_NORMAL;
+ break;
+ }
+#else /* !FC_HINT_STYLE */
+ if (!hinting)
+ load_flags |= FT_LOAD_NO_HINTING;
+#endif /* FC_FHINT_STYLE */
+
+ /* force autohinting if requested */
+ if (FcPatternGetBool (pattern,
+ FC_AUTOHINT, 0, &autohint) != FcResultMatch)
+ autohint = FcFalse;
+
+ if (autohint)
+ load_flags |= FT_LOAD_FORCE_AUTOHINT;
+
+ return load_flags;
+}
+
+/* Like the public cairo_ft_font_create, but takes a cairo_font_scale_t,
+ * rather than a cairo_font_t
+ */
+static cairo_font_t *
+_ft_font_create (FcPattern *pattern,
+ cairo_font_scale_t *scale)
+{
+ cairo_ft_font_t *f = NULL;
+ ft_unscaled_font_t *unscaled = NULL;
+
+ unscaled = _ft_unscaled_font_get_for_pattern (pattern);
+ if (unscaled == NULL)
+ return NULL;
+
+ f = malloc (sizeof(cairo_ft_font_t));
+ if (f == NULL)
+ goto FREE_UNSCALED;
+
+ f->unscaled = unscaled;
+ f->pattern = pattern;
+ FcPatternReference (pattern);
+ f->load_flags = _get_load_flags (pattern);
+
+ _cairo_font_init ((cairo_font_t *)f, scale, &cairo_ft_font_backend);
+
+ return (cairo_font_t *)f;
+
+ FREE_UNSCALED:
+ _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
+
+ return NULL;
+}
+
+static cairo_status_t
+_cairo_ft_font_create (const char *family,
cairo_font_slant_t slant,
- cairo_font_weight_t weight)
+ cairo_font_weight_t weight,
+ cairo_font_scale_t *scale,
+ cairo_font_t **font)
{
- cairo_status_t status;
- cairo_ft_font_t *font = NULL;
+ FcPattern *pattern, *resolved;
+ cairo_font_t *new_font;
+ FcResult result;
int fcslant;
int fcweight;
- cairo_cache_t *cache;
- cairo_ft_cache_entry_t *entry;
- cairo_ft_cache_key_t key;
-
- key.pattern = FcPatternCreate ();
- if (key.pattern == NULL)
- goto FAIL;
+ ft_font_transform_t sf;
- font = malloc (sizeof (cairo_ft_font_t));
- if (font == NULL)
- goto FREE_PATTERN;
+ pattern = FcPatternCreate ();
+ if (!pattern)
+ return CAIRO_STATUS_NO_MEMORY;
switch (weight)
{
@@ -356,46 +623,44 @@ _cairo_ft_font_create (const char *family,
break;
}
- FcPatternAddString (key.pattern, FC_FAMILY, family);
- FcPatternAddInteger (key.pattern, FC_SLANT, fcslant);
- FcPatternAddInteger (key.pattern, FC_WEIGHT, fcweight);
-
- if (_cairo_unscaled_font_init (&font->base, &cairo_ft_font_backend))
+ if (!FcPatternAddString (pattern, FC_FAMILY, family))
goto FREE_PATTERN;
-
- _lock_global_ft_cache ();
- cache = _get_global_ft_cache ();
- if (cache == NULL) {
- _unlock_global_ft_cache ();
+ if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant))
+ goto FREE_PATTERN;
+ if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight))
goto FREE_PATTERN;
- }
- status = _cairo_cache_lookup (cache, &key, (void **) &entry);
- _unlock_global_ft_cache ();
+ _compute_transform (&sf, scale);
- if (status)
- goto FREE_PATTERN;
+ FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale);
- font->pattern = FcPatternDuplicate (entry->key.pattern);
- if (font->pattern == NULL)
+ FcConfigSubstitute (NULL, pattern, FcMatchPattern);
+ FcDefaultSubstitute (pattern);
+
+ resolved = FcFontMatch (NULL, pattern, &result);
+ if (!resolved)
goto FREE_PATTERN;
- font->val = entry->val;
- _reference_font_val (font->val);
-
- return &font->base;
+ new_font = _ft_font_create (resolved, scale);
- FREE_PATTERN:
- FcPatternDestroy (key.pattern);
+ FcPatternDestroy (resolved);
+ FcPatternDestroy (pattern);
- FAIL:
- return NULL;
+ if (new_font) {
+ *font = new_font;
+ return CAIRO_STATUS_SUCCESS;
+ } else {
+ return CAIRO_STATUS_NO_MEMORY; /* A guess */
+ }
-}
+ FREE_PATTERN:
+ FcPatternDestroy (pattern);
+ return CAIRO_STATUS_NO_MEMORY;
+}
static void
-_cairo_ft_font_destroy (void *abstract_font)
+_cairo_ft_font_destroy_font (void *abstract_font)
{
cairo_ft_font_t * font = abstract_font;
@@ -405,179 +670,94 @@ _cairo_ft_font_destroy (void *abstract_font)
if (font->pattern != NULL)
FcPatternDestroy (font->pattern);
- _destroy_font_val (font->val);
+ _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)font->unscaled);
free (font);
}
static void
-_utf8_to_ucs4 (char const *utf8,
- FT_ULong **ucs4,
- int *nchars)
+_cairo_ft_font_destroy_unscaled_font (void *abstract_font)
{
- int len = 0, step = 0;
- int n = 0, alloc = 0;
- FcChar32 u = 0;
+ ft_unscaled_font_t *unscaled = abstract_font;
- if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
- return;
+ if (!unscaled->from_face) {
+ cairo_cache_t *cache;
+ cairo_ft_cache_key_t key;
+
+ _lock_global_ft_cache ();
+ cache = _get_global_ft_cache ();
+ assert (cache);
- len = strlen (utf8);
- alloc = len;
- *ucs4 = malloc (sizeof (FT_ULong) * alloc);
- if (*ucs4 == NULL)
- return;
-
- while (len && (step = FcUtf8ToUcs4(utf8, &u, len)) > 0)
- {
- if (n == alloc)
- {
- alloc *= 2;
- *ucs4 = realloc (*ucs4, sizeof (FT_ULong) * alloc);
- if (*ucs4 == NULL)
- return;
- }
- (*ucs4)[n++] = u;
- len -= step;
- utf8 += step;
+ key.filename = unscaled->filename;
+ key.id = unscaled->id;
+
+ _cairo_cache_remove (cache, &key);
+
+ _unlock_global_ft_cache ();
}
- *nchars = n;
-}
-
-/*
- * Split a matrix into the component pieces of scale and shape
- */
-
-static void
-_cairo_ft_font_compute_transform (ft_font_transform_t *sf, cairo_font_scale_t *sc)
-{
- cairo_matrix_t normalized;
- double tx, ty;
- /* The font matrix has x and y "scale" components which we extract and
- * use as character scale values. These influence the way freetype
- * chooses hints, as well as selecting different bitmaps in
- * hand-rendered fonts. We also copy the normalized matrix to
- * freetype's transformation.
- */
-
- cairo_matrix_set_affine (&normalized,
- sc->matrix[0][0],
- sc->matrix[0][1],
- sc->matrix[1][0],
- sc->matrix[1][1],
- 0, 0);
-
- _cairo_matrix_compute_scale_factors (&normalized,
- &sf->x_scale, &sf->y_scale,
- /* XXX */ 1);
- cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
- cairo_matrix_get_affine (&normalized,
- &sf->shape[0][0], &sf->shape[0][1],
- &sf->shape[1][0], &sf->shape[1][1],
- &tx, &ty);
-}
-
-/*
- * Set the font transformation
- */
-
-static void
-_cairo_ft_font_install_transform (ft_font_transform_t *sf, FT_Face face)
-{
- FT_Matrix mat;
-
- mat.xx = DOUBLE_TO_16_16(sf->shape[0][0]);
- mat.yx = -DOUBLE_TO_16_16(sf->shape[0][1]);
- mat.xy = -DOUBLE_TO_16_16(sf->shape[1][0]);
- mat.yy = DOUBLE_TO_16_16(sf->shape[1][1]);
+ if (unscaled == NULL)
+ return;
- FT_Set_Transform(face, &mat, NULL);
+ if (!unscaled->from_face && unscaled->face)
+ FT_Done_Face (unscaled->face);
- FT_Set_Char_Size(face,
- (FT_F26Dot6) (sf->x_scale * 64.0),
- (FT_F26Dot6) (sf->y_scale * 64.0),
- 0, 0);
+ if (unscaled->filename)
+ free (unscaled->filename);
+
+ free (unscaled);
}
static void
-_install_font_scale (cairo_font_scale_t *sc, FT_Face face)
+_cairo_ft_font_get_glyph_cache_key (void *abstract_font,
+ cairo_glyph_cache_key_t *key)
{
- cairo_matrix_t normalized;
- double x_scale, y_scale;
- double xx, xy, yx, yy, tx, ty;
- FT_Matrix mat;
-
- /* The font matrix has x and y "scale" components which we extract and
- * use as character scale values. These influence the way freetype
- * chooses hints, as well as selecting different bitmaps in
- * hand-rendered fonts. We also copy the normalized matrix to
- * freetype's transformation.
- */
-
- cairo_matrix_set_affine (&normalized,
- sc->matrix[0][0],
- sc->matrix[0][1],
- sc->matrix[1][0],
- sc->matrix[1][1],
- 0, 0);
-
- _cairo_matrix_compute_scale_factors (&normalized, &x_scale, &y_scale,
- /* XXX */ 1);
- cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale);
- cairo_matrix_get_affine (&normalized,
- &xx /* 00 */ , &yx /* 01 */,
- &xy /* 10 */, &yy /* 11 */,
- &tx, &ty);
-
- mat.xx = DOUBLE_TO_16_16(xx);
- mat.xy = -DOUBLE_TO_16_16(xy);
- mat.yx = -DOUBLE_TO_16_16(yx);
- mat.yy = DOUBLE_TO_16_16(yy);
-
- FT_Set_Transform(face, &mat, NULL);
+ cairo_ft_font_t *font = abstract_font;
- FT_Set_Pixel_Sizes(face,
- (FT_UInt) x_scale,
- (FT_UInt) y_scale);
+ key->unscaled = (cairo_unscaled_font_t *)font->unscaled;
+ key->scale = font->base.scale;
+ key->flags = font->load_flags;
}
static cairo_status_t
_cairo_ft_font_text_to_glyphs (void *abstract_font,
- cairo_font_scale_t *sc,
const unsigned char *utf8,
cairo_glyph_t **glyphs,
int *nglyphs)
{
double x = 0., y = 0.;
size_t i;
- FT_ULong *ucs4 = NULL;
+ uint32_t *ucs4 = NULL;
cairo_ft_font_t *font = abstract_font;
- FT_Face face = font->val->face;
+ FT_Face face;
cairo_glyph_cache_key_t key;
cairo_image_glyph_cache_entry_t *val;
- cairo_cache_t *cache;
+ cairo_cache_t *cache = NULL;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
- key.unscaled = &font->base;
- key.scale = *sc;
+ _cairo_ft_font_get_glyph_cache_key (font, &key);
- _utf8_to_ucs4 (utf8, &ucs4, nglyphs);
-
- if (ucs4 == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, nglyphs);
+ if (!CAIRO_OK (status))
+ return status;
- *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t)));
- if (*glyphs == NULL)
- {
- free (ucs4);
- return CAIRO_STATUS_NO_MEMORY;
+ face = cairo_ft_font_lock_face ((cairo_font_t *)font);
+ if (!face) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL1;
}
_cairo_lock_global_image_glyph_cache ();
cache = _cairo_get_global_image_glyph_cache ();
if (cache == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL2;
+ }
+
+ *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t)));
+ if (*glyphs == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL2;
}
for (i = 0; i < *nglyphs; i++)
@@ -589,51 +769,62 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
val = NULL;
key.index = (*glyphs)[i].index;
- if (_cairo_cache_lookup (cache, &key, (void **) &val)
+ if (_cairo_cache_lookup (cache, &key, (void **) &val, NULL)
!= CAIRO_STATUS_SUCCESS || val == NULL)
continue;
x += val->extents.x_advance;
y += val->extents.y_advance;
}
- _cairo_unlock_global_image_glyph_cache ();
+ FAIL2:
+ if (cache)
+ _cairo_unlock_global_image_glyph_cache ();
+
+ cairo_ft_font_unlock_face ((cairo_font_t *)font);
+
+ FAIL1:
free (ucs4);
- return CAIRO_STATUS_SUCCESS;
+
+ return status;
}
static cairo_status_t
_cairo_ft_font_font_extents (void *abstract_font,
- cairo_font_scale_t *sc,
cairo_font_extents_t *extents)
{
cairo_ft_font_t *font = abstract_font;
- FT_Face face = font->val->face;
- FT_Size_Metrics *metrics = &face->size->metrics;
- ft_font_transform_t sf;
+ FT_Face face;
+ FT_Size_Metrics *metrics;
+
+ face = _ft_unscaled_font_lock_face (font->unscaled);
+ if (!face)
+ return CAIRO_STATUS_NO_MEMORY;
- _cairo_ft_font_compute_transform (&sf, sc);
- _cairo_ft_font_install_transform (&sf, face);
+ metrics = &face->size->metrics;
+ _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
+
/*
* Get to unscaled metrics so that the upper level can get back to
* user space
*/
- extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / sf.y_scale;
- extents->descent = DOUBLE_FROM_26_6(metrics->descender) / sf.y_scale;
- extents->height = DOUBLE_FROM_26_6(metrics->height) / sf.y_scale;
- extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / sf.x_scale;
+ extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / font->unscaled->y_scale;
+ extents->descent = DOUBLE_FROM_26_6(metrics->descender) / font->unscaled->y_scale;
+ extents->height = DOUBLE_FROM_26_6(metrics->height) / font->unscaled->y_scale;
+ extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / font->unscaled->x_scale;
/* FIXME: this doesn't do vertical layout atm. */
extents->max_y_advance = 0.0;
+ _ft_unscaled_font_unlock_face (font->unscaled);
+
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ft_font_glyph_extents (void *abstract_font,
- cairo_font_scale_t *sc,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents)
@@ -670,14 +861,13 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
return CAIRO_STATUS_NO_MEMORY;
}
- key.unscaled = &font->base;
- key.scale = *sc;
+ _cairo_ft_font_get_glyph_cache_key (font, &key);
for (i = 0; i < num_glyphs; i++)
{
img = NULL;
key.index = glyphs[i].index;
- if (_cairo_cache_lookup (cache, &key, (void **) &img)
+ if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
!= CAIRO_STATUS_SUCCESS || img == NULL)
continue;
@@ -721,7 +911,6 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
static cairo_status_t
_cairo_ft_font_glyph_bbox (void *abstract_font,
- cairo_font_scale_t *sc,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_box_t *bbox)
@@ -747,16 +936,15 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
return CAIRO_STATUS_NO_MEMORY;
}
- key.unscaled = &font->base;
- key.scale = *sc;
-
+ _cairo_ft_font_get_glyph_cache_key (font, &key);
+
for (i = 0; i < num_glyphs; i++)
{
img = NULL;
key.index = glyphs[i].index;
- if (_cairo_cache_lookup (cache, &key, (void **) &img)
+ if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
!= CAIRO_STATUS_SUCCESS || img == NULL)
continue;
@@ -785,12 +973,15 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
static cairo_status_t
_cairo_ft_font_show_glyphs (void *abstract_font,
- cairo_font_scale_t *sc,
cairo_operator_t operator,
- cairo_surface_t *source,
+ cairo_pattern_t *pattern,
cairo_surface_t *surface,
int source_x,
int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
@@ -798,9 +989,9 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
cairo_cache_t *cache;
cairo_glyph_cache_key_t key;
cairo_ft_font_t *font = abstract_font;
+ cairo_surface_pattern_t glyph_pattern;
cairo_status_t status;
-
- double x, y;
+ int x, y;
int i;
_cairo_lock_global_image_glyph_cache ();
@@ -808,47 +999,54 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
if (cache == NULL
|| font == NULL
- || source == NULL
+ || pattern == NULL
|| surface == NULL
|| glyphs == NULL) {
_cairo_unlock_global_image_glyph_cache ();
return CAIRO_STATUS_NO_MEMORY;
}
- key.unscaled = &font->base;
- key.scale = *sc;
+ key.unscaled = (cairo_unscaled_font_t *)font->unscaled;
+ key.scale = font->base.scale;
+ key.flags = font->load_flags;
for (i = 0; i < num_glyphs; i++)
{
img = NULL;
key.index = glyphs[i].index;
- if (_cairo_cache_lookup (cache, &key, (void **) &img)
+ if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
!= CAIRO_STATUS_SUCCESS
|| img == NULL
|| img->image == NULL)
continue;
- x = glyphs[i].x;
- y = glyphs[i].y;
+ x = (int) floor (glyphs[i].x + 0.5);
+ y = (int) floor (glyphs[i].y + 0.5);
+
+ _cairo_pattern_init_for_surface (&glyph_pattern, &(img->image->base));
- status = _cairo_surface_composite (operator, source,
- &(img->image->base),
+ status = _cairo_surface_composite (operator, pattern,
+ &glyph_pattern.base,
surface,
- source_x + x + img->size.x,
- source_y + y + img->size.y,
+ x + img->size.x,
+ y + img->size.y,
0, 0,
x + img->size.x,
y + img->size.y,
(double) img->size.width,
(double) img->size.height);
+ _cairo_pattern_fini (&glyph_pattern.base);
+
if (status) {
- _cairo_unlock_global_image_glyph_cache ();
+ _cairo_unlock_global_image_glyph_cache ();
return status;
}
}
+
_cairo_unlock_global_image_glyph_cache ();
+
return CAIRO_STATUS_SUCCESS;
}
@@ -932,7 +1130,6 @@ _cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closur
static cairo_status_t
_cairo_ft_font_glyph_path (void *abstract_font,
- cairo_font_scale_t *sc,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_t *path)
@@ -940,6 +1137,7 @@ _cairo_ft_font_glyph_path (void *abstract_font,
int i;
cairo_ft_font_t *font = abstract_font;
FT_GlyphSlot glyph;
+ FT_Face face;
FT_Error error;
FT_Outline_Funcs outline_funcs = {
_move_to,
@@ -949,10 +1147,12 @@ _cairo_ft_font_glyph_path (void *abstract_font,
0, /* shift */
0, /* delta */
};
+
+ face = cairo_ft_font_lock_face (abstract_font);
+ if (!face)
+ return CAIRO_STATUS_NO_MEMORY;
- glyph = font->val->face->glyph;
-
- _install_font_scale (sc, font->val->face);
+ glyph = face->glyph;
for (i = 0; i < num_glyphs; i++)
{
@@ -961,7 +1161,7 @@ _cairo_ft_font_glyph_path (void *abstract_font,
0, DOUBLE_TO_16_16 (-1.0),
};
- error = FT_Load_Glyph (font->val->face, glyphs[i].index, FT_LOAD_DEFAULT);
+ error = FT_Load_Glyph (font->unscaled->face, glyphs[i].index, font->load_flags | FT_LOAD_NO_BITMAP);
/* XXX: What to do in this error case? */
if (error)
continue;
@@ -977,32 +1177,39 @@ _cairo_ft_font_glyph_path (void *abstract_font,
FT_Outline_Decompose (&glyph->outline, &outline_funcs, path);
}
_cairo_path_close_path (path);
+
+ cairo_ft_font_unlock_face (abstract_font);
return CAIRO_STATUS_SUCCESS;
}
-
static cairo_status_t
-_cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
+_cairo_ft_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *)val->key.unscaled;
+ ft_unscaled_font_t *unscaled = (ft_unscaled_font_t *)val->key.unscaled;
FT_GlyphSlot glyphslot;
unsigned int width, height, stride;
+ FT_Face face;
FT_Outline *outline;
FT_BBox cbox;
FT_Bitmap bitmap;
FT_Glyph_Metrics *metrics;
- ft_font_transform_t sf;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
- glyphslot = font->val->face->glyph;
+ glyphslot = unscaled->face->glyph;
metrics = &glyphslot->metrics;
- _cairo_ft_font_compute_transform (&sf, &val->key.scale);
- _cairo_ft_font_install_transform (&sf, font->val->face);
-
- if (FT_Load_Glyph (font->val->face, val->key.index, FT_LOAD_DEFAULT) != 0)
+ face = _ft_unscaled_font_lock_face (unscaled);
+ if (!face)
return CAIRO_STATUS_NO_MEMORY;
+ _ft_unscaled_font_set_scale (unscaled, &val->key.scale);
+
+ if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
/*
* Note: the font's coordinate system is upside down from ours, so the
* Y coordinates of the bearing and advance need to be negated.
@@ -1011,11 +1218,11 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
* by FreeType
*/
- val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / sf.x_scale;
- val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / sf.y_scale;
+ val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale;
+ val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale;
- val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / sf.x_scale;
- val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / sf.y_scale;
+ val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale;
+ val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale;
/*
* use untransformed advance values
@@ -1023,8 +1230,8 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
should provide FT_LOAD_VERTICAL_LAYOUT
*/
- val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->metrics.horiAdvance) / sf.x_scale;
- val->extents.y_advance = 0 / sf.y_scale;
+ val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale;
+ val->extents.y_advance = 0 / unscaled->y_scale;
outline = &glyphslot->outline;
@@ -1052,14 +1259,16 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
bitmap.buffer = calloc (1, stride * height);
if (bitmap.buffer == NULL) {
- return CAIRO_STATUS_NO_MEMORY;
- };
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
free (bitmap.buffer);
- return CAIRO_STATUS_NO_MEMORY;
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
}
val->image = (cairo_image_surface_t *)
@@ -1068,7 +1277,8 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
width, height, stride);
if (val->image == NULL) {
free (bitmap.buffer);
- return CAIRO_STATUS_NO_MEMORY;
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
}
_cairo_image_surface_assume_ownership_of_data (val->image);
@@ -1084,138 +1294,245 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
val->size.x = (short) (cbox.xMin >> 6);
val->size.y = - (short) (cbox.yMax >> 6);
- return CAIRO_STATUS_SUCCESS;
+ FAIL:
+ _ft_unscaled_font_unlock_face (unscaled);
+
+ return status;
}
const cairo_font_backend_t cairo_ft_font_backend = {
_cairo_ft_font_create,
- _cairo_ft_font_destroy,
+ _cairo_ft_font_destroy_font,
+ _cairo_ft_font_destroy_unscaled_font,
_cairo_ft_font_font_extents,
_cairo_ft_font_text_to_glyphs,
_cairo_ft_font_glyph_extents,
_cairo_ft_font_glyph_bbox,
_cairo_ft_font_show_glyphs,
_cairo_ft_font_glyph_path,
+ _cairo_ft_font_get_glyph_cache_key,
_cairo_ft_font_create_glyph
};
-
/* implement the platform-specific interface */
+/**
+ * cairo_ft_font_create:
+ * @pattern: A fully resolved fontconfig
+ * pattern. A pattern can be resolved, by, among other things, calling
+ * FcConfigSubstitute(), FcDefaultSubstitute(), then
+ * FcFontMatch(). Cairo will call FcPatternReference() on this
+ * pattern, so you should not further modify the pattern, but you can
+ * release your reference to the pattern with FcPatternDestroy() if
+ * you no longer need to access it.
+ * @scale: The scale at which this font will be used. The
+ * scale is given by multiplying the font matrix (see
+ * cairo_transform_font()) by the current transformation matrix.
+ * The translation elements of the resulting matrix are ignored.
+ *
+ * Creates a new font for the FreeType font backend based on a
+ * fontconfig pattern. This font can then be used with
+ * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
+ * specific functions like cairo_ft_font_lock_face().
+ *
+ * Return value: a newly created #cairo_font_t. Free with
+ * cairo_font_destroy() when you are done using it.
+ **/
cairo_font_t *
-cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern)
+cairo_ft_font_create (FcPattern *pattern,
+ cairo_matrix_t *scale)
{
- cairo_font_scale_t scale;
- cairo_font_t *scaled;
- cairo_ft_font_t *f = NULL;
- ft_font_val_t *v = NULL;
- FcPattern *dup;
-
- scale.matrix[0][0] = 1.;
- scale.matrix[0][1] = 0.;
- scale.matrix[1][0] = 0.;
- scale.matrix[1][1] = 1.;
-
- scaled = malloc (sizeof (cairo_font_t));
- if (scaled == NULL)
- goto FAIL;
-
- dup = FcPatternDuplicate(pattern);
- if (dup == NULL)
- goto FREE_SCALED;
-
- v = _create_from_library_and_pattern (ft_library, pattern);
- if (v == NULL)
- goto FREE_PATTERN;
-
- f = malloc (sizeof(cairo_ft_font_t));
- if (f == NULL)
- goto FREE_VAL;
-
- if (_cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend))
- goto FREE_VAL;
-
- f->pattern = dup;
- f->val = v;
-
- _cairo_font_init (scaled, &scale, &f->base);
-
- return scaled;
-
- FREE_VAL:
- _destroy_font_val (v);
-
- FREE_PATTERN:
- FcPatternDestroy (dup);
+ cairo_font_scale_t sc;
+ double tx, ty;
- FREE_SCALED:
- free (scaled);
+ cairo_matrix_get_affine (scale,
+ &sc.matrix[0][0], &sc.matrix[0][1],
+ &sc.matrix[1][0], &sc.matrix[1][1],
+ &tx, &ty);
- FAIL:
- return NULL;
+ return _ft_font_create (pattern, &sc);
}
+/**
+ * cairo_ft_font_create_for_ft_face:
+ * @face: A FreeType face object, already opened. This must
+ * be kept around until the font object's refcount drops to
+ * zero and it is freed. The font object can be kept alive by
+ * internal caching, so it's safest to keep the face object
+ * around forever.
+ * @load_flags: The flags to pass to FT_Load_Glyph when loading
+ * glyphs from the font. These flags control aspects of
+ * rendering such as hinting and antialiasing. See the FreeType
+ * docs for full information.
+ * @scale: The scale at which this font will be used. The
+ * scale is given by multiplying the font matrix (see
+ * cairo_transform_font()) by the current transformation matrix.
+ * The translation elements of the resulting matrix are ignored.
+ *
+ * Creates a new font forthe FreeType font backend from a pre-opened
+ * FreeType face. This font can then be used with cairo_set_font(),
+ * cairo_font_glyph_extents(), or FreeType backend specific
+ * functions like cairo_ft_font_lock_face() Cairo will determine the
+ * pixel size and transformation from the @scale parameter and call
+ * FT_Set_Transform() and FT_Set_Pixel_Sizes().
+ *
+ * Return value: a newly created #cairo_font_t. Free with
+ * cairo_font_destroy() when you are done using it.
+ **/
cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face)
+cairo_ft_font_create_for_ft_face (FT_Face face,
+ int load_flags,
+ cairo_matrix_t *scale)
{
- cairo_font_scale_t scale;
- cairo_font_t *scaled;
cairo_ft_font_t *f = NULL;
- ft_font_val_t *v = NULL;
-
- scale.matrix[0][0] = 1.;
- scale.matrix[0][1] = 0.;
- scale.matrix[1][0] = 0.;
- scale.matrix[1][1] = 1.;
-
- scaled = malloc (sizeof (cairo_font_t));
- if (scaled == NULL)
- goto FAIL;
+ ft_unscaled_font_t *unscaled = NULL;
+ cairo_font_scale_t sc;
+ double tx, ty;
- v = _create_from_face (face, 0);
- if (v == NULL)
- goto FREE_SCALED;
+ unscaled = _ft_unscaled_font_create_from_face (face);
+ if (unscaled == NULL)
+ return NULL;
f = malloc (sizeof(cairo_ft_font_t));
if (f == NULL)
- goto FREE_VAL;
+ goto FREE_UNSCALED;
- _cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend);
+ f->unscaled = unscaled;
f->pattern = NULL;
- f->val = v;
+ f->load_flags = load_flags;
- _cairo_font_init (scaled, &scale, &f->base);
+ cairo_matrix_get_affine (scale,
+ &sc.matrix[0][0], &sc.matrix[0][1],
+ &sc.matrix[1][0], &sc.matrix[1][1],
+ &tx, &ty);
- return scaled;
+ _cairo_font_init ((cairo_font_t *)f, &sc, &cairo_ft_font_backend);
- FREE_VAL:
- _destroy_font_val (v);
+ return (cairo_font_t *)f;
- FREE_SCALED:
- free (scaled);
+ FREE_UNSCALED:
+ _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
- FAIL:
return NULL;
}
+
+/**
+ * cairo_ft_font_lock_face:
+ * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
+ * object can be created with cairo_ft_font_create() or
+ * cairo_ft_font_create_for_ft_face(). On some platforms the font from
+ * cairo_current_font() will also be a FreeType font, but using this
+ * functionality with fonts you don't create yourself is not
+ * recommended.
+ *
+ * cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType
+ * backend font and scales it appropriately for the font. You must
+ * release the face with cairo_ft_font_unlock_face()
+ * when you are done using it. Since the #FT_Face object can be
+ * shared between multiple #cairo_font_t objects, you must not
+ * lock any other font objects until you unlock this one. A count is
+ * kept of the number of times cairo_ft_font_lock_face() is
+ * called. cairo_ft_font_unlock_face() must be called the same number
+ * of times.
+ *
+ * You must be careful when using this function in a library or in a
+ * threaded application, because other threads may lock faces that
+ * share the same #FT_Face object. For this reason, you must call
+ * cairo_ft_lock() before locking any face objects, and
+ * cairo_ft_unlock() after you are done. (These functions are not yet
+ * implemented, so this function cannot be currently safely used in a
+ * threaded application.)
+
+ * Return value: The #FT_Face object for @font, scaled appropriately.
+ **/
FT_Face
-cairo_ft_font_face (cairo_font_t *abstract_font)
+cairo_ft_font_lock_face (cairo_font_t *abstract_font)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled;
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+ FT_Face face;
- if (font == NULL || font->val == NULL)
- return NULL;
+ face = _ft_unscaled_font_lock_face (font->unscaled);
+ if (!face)
+ return NULL;
+
+ _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
+
+ return face;
+}
- return font->val->face;
+/**
+ * cairo_ft_font_unlock_face:
+ * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
+ * object can be created with cairo_ft_font_create() or
+ * cairo_ft_font_create_for_ft_face(). On some platforms the font from
+ * cairo_current_font() will also be a FreeType font, but using this
+ * functionality with fonts you don't create yourself is not
+ * recommended.
+ *
+ * Releases a face obtained with cairo_ft_font_lock_face(). See the
+ * documentation for that function for full details.
+ **/
+void
+cairo_ft_font_unlock_face (cairo_font_t *abstract_font)
+{
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+
+ _ft_unscaled_font_unlock_face (font->unscaled);
}
+/**
+ * cairo_ft_font_get_pattern:
+ * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
+ * object can be created with cairo_ft_font_create() or
+ * cairo_ft_font_create_for_ft_face(). On some platforms the font from
+ * cairo_current_font() will also be a FreeType font, but using this
+ * functionality with fonts you don't create yourself is not
+ * recommended.
+ *
+ * cairo_ft_font_get_pattern() gets the #FcPattern for a FreeType
+ * backend font.
+
+ * Return value: The #FcPattenr for @font. The return value is owned
+ * by the font, so you must not modify it, and must call
+ * FcPatternReference() to keep a persistant reference to the
+ * pattern. If the font was created with cairo_ft_font_create_for_ft_face()
+ * returns %NULL.
+ **/
FcPattern *
-cairo_ft_font_pattern (cairo_font_t *abstract_font)
+cairo_ft_font_get_pattern (cairo_font_t *abstract_font)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled;
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
if (font == NULL)
return NULL;
return font->pattern;
}
+
+/* We expose our unscaled font implementation internally for the the
+ * PDF backend, which needs to keep track of the the different
+ * fonts-on-disk used by a document, so it can embed them.
+ */
+cairo_unscaled_font_t *
+_cairo_ft_font_get_unscaled_font (cairo_font_t *abstract_font)
+{
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+
+ return (cairo_unscaled_font_t *)font->unscaled;
+}
+
+/* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't
+ * set the scale on the face, but just returns it at the last scale.
+ */
+FT_Face
+_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font)
+{
+ return _ft_unscaled_font_lock_face ((ft_unscaled_font_t *)unscaled_font);
+}
+
+void
+_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font)
+{
+ _ft_unscaled_font_unlock_face ((ft_unscaled_font_t *)unscaled_font);
+}
diff --git a/src/cairo-ft-private.h b/src/cairo-ft-private.h
new file mode 100644
index 000000000..37a6feecc
--- /dev/null
+++ b/src/cairo-ft-private.h
@@ -0,0 +1,63 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 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):
+ * Graydon Hoare <graydon@redhat.com>
+ * Owen Taylor <otaylor@redhat.com>
+ */
+
+#ifndef CAIRO_FT_PRIVATE_H
+#define CAIRO_FT_PRIVATE_H
+
+#include <cairo-ft.h>
+#include <cairoint.h>
+
+#ifdef CAIRO_HAS_FT_FONT
+
+CAIRO_BEGIN_DECLS
+
+/* These functions are needed by the PDF backend, which needs to keep track of the
+ * the different fonts-on-disk used by a document, so it can embed them
+ */
+cairo_private cairo_unscaled_font_t *
+_cairo_ft_font_get_unscaled_font (cairo_font_t *font);
+
+cairo_private FT_Face
+_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font);
+
+cairo_private void
+_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_HAS_FT_FONT */
+
+#endif /* CAIRO_FT_PRIVATE_H */
diff --git a/src/cairo-ft.h b/src/cairo-ft.h
index 57d439ab2..f10c67d80 100644
--- a/src/cairo-ft.h
+++ b/src/cairo-ft.h
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2002 University of Southern California
+ * Copyright © 2005 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
@@ -27,17 +27,18 @@
*
* The Original Code is the cairo graphics library.
*
- * The Initial Developer of the Original Code is University of Southern
- * California.
+ * The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Graydon Hoare <graydon@redhat.com>
+ * Owen Taylor <otaylor@redhat.com>
*/
-#include <cairo.h>
-
#ifndef CAIRO_FT_H
#define CAIRO_FT_H
+
+#include <cairo.h>
+
#ifdef CAIRO_HAS_FT_FONT
/* Fontconfig/Freetype platform-specific font interface */
@@ -46,17 +47,27 @@
#include <ft2build.h>
#include FT_FREETYPE_H
+CAIRO_BEGIN_DECLS
+
cairo_font_t *
-cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern);
+cairo_ft_font_create (FcPattern *pattern,
+ cairo_matrix_t *scale);
cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face);
+cairo_ft_font_create_for_ft_face (FT_Face face,
+ int load_flags,
+ cairo_matrix_t *scale);
FT_Face
-cairo_ft_font_face (cairo_font_t *ft_font);
+cairo_ft_font_lock_face (cairo_font_t *ft_font);
+
+void
+cairo_ft_font_unlock_face (cairo_font_t *ft_font);
FcPattern *
-cairo_ft_font_pattern (cairo_font_t *ft_font);
+cairo_ft_font_get_pattern (cairo_font_t *ft_font);
+
+CAIRO_END_DECLS
#endif /* CAIRO_HAS_FT_FONT */
#endif /* CAIRO_FT_H */
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 69fc82f2e..ee664e1cc 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -21,30 +21,12 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * Author: David Reveman <c99drn@cs.umu.se>
+ * Author: David Reveman <davidr@novell.com>
*/
#include "cairoint.h"
#include "cairo-glitz.h"
-#define GLITZ_FIXED_TO_FLOAT(f) \
- (((glitz_float_t) (f)) / 65536)
-
-#define GLITZ_FIXED_LINE_X_TO_FLOAT(line, v) \
- (((glitz_float_t) \
- ((line).p1.x + (cairo_fixed_16_16_t) \
- (((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \
- ((line).p2.x - (line).p1.x)) / \
- ((line).p2.y - (line).p1.y)))) / 65536)
-
-#define GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \
- (((glitz_float_t) \
- ((line).p1.x + (cairo_fixed_16_16_t) \
- (((((line).p2.y - (line).p1.y) - 1) + \
- ((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \
- ((line).p2.x - (line).p1.x))) / \
- ((line).p2.y - (line).p1.y)))) / 65536)
-
void
cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
{
@@ -65,13 +47,11 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
}
typedef struct _cairo_glitz_surface {
- cairo_surface_t base;
-
- glitz_surface_t *surface;
- glitz_format_t *format;
+ cairo_surface_t base;
- cairo_pattern_t pattern;
- cairo_box_t pattern_box;
+ glitz_surface_t *surface;
+ glitz_format_t *format;
+ pixman_region16_t *clip;
} cairo_glitz_surface_t;
static void
@@ -79,11 +59,60 @@ _cairo_glitz_surface_destroy (void *abstract_surface)
{
cairo_glitz_surface_t *surface = abstract_surface;
+ if (surface->clip)
+ {
+ glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
+ pixman_region_destroy (surface->clip);
+ }
+
glitz_surface_destroy (surface->surface);
+ free (surface);
+}
- _cairo_pattern_fini (&surface->pattern);
+static glitz_format_name_t
+_glitz_format (cairo_format_t format)
+{
+ switch (format) {
+ default:
+ case CAIRO_FORMAT_ARGB32:
+ return GLITZ_STANDARD_ARGB32;
+ case CAIRO_FORMAT_RGB24:
+ return GLITZ_STANDARD_RGB24;
+ case CAIRO_FORMAT_A8:
+ return GLITZ_STANDARD_A8;
+ case CAIRO_FORMAT_A1:
+ return GLITZ_STANDARD_A1;
+ }
+}
- free (surface);
+static cairo_surface_t *
+_cairo_glitz_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int draw,
+ int width,
+ int height)
+{
+ cairo_glitz_surface_t *src = abstract_src;
+ cairo_surface_t *crsurface;
+ glitz_drawable_t *drawable;
+ glitz_surface_t *surface;
+ glitz_format_t *gformat;
+
+ drawable = glitz_surface_get_drawable (src->surface);
+
+ gformat = glitz_find_standard_format (drawable, _glitz_format (format));
+ if (!gformat)
+ return NULL;
+
+ surface = glitz_surface_create (drawable, gformat, width, height, 0, NULL);
+ if (!surface)
+ return NULL;
+
+ crsurface = cairo_glitz_surface_create (surface);
+
+ glitz_surface_destroy (surface);
+
+ return crsurface;
}
static double
@@ -92,31 +121,54 @@ _cairo_glitz_surface_pixels_per_inch (void *abstract_surface)
return 96.0;
}
-static cairo_image_surface_t *
-_cairo_glitz_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
+ cairo_rectangle_t *interest,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *rect_out)
{
- cairo_glitz_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
- char *pixels;
- int width, height;
- cairo_format_masks_t format;
- glitz_buffer_t *buffer;
- glitz_pixel_format_t pf;
-
- if (surface->pattern.type != CAIRO_PATTERN_SURFACE) {
- cairo_box_t box;
-
- box.p1.x = box.p1.y = 0;
- box.p2.x = surface->pattern_box.p2.x;
- box.p2.y = surface->pattern_box.p2.y;
-
- return _cairo_pattern_get_image (&surface->pattern, &box);
+ int x1, y1, x2, y2;
+ int width, height;
+ char *pixels;
+ cairo_format_masks_t format;
+ glitz_buffer_t *buffer;
+ glitz_pixel_format_t pf;
+
+ x1 = 0;
+ y1 = 0;
+ x2 = glitz_surface_get_width (surface->surface);
+ y2 = glitz_surface_get_height (surface->surface);
+
+ if (interest)
+ {
+ if (interest->x > x1)
+ x1 = interest->x;
+ if (interest->y > y1)
+ y1 = interest->y;
+ if (interest->x + interest->width < x2)
+ x2 = interest->x + interest->width;
+ if (interest->y + interest->height < y2)
+ y2 = interest->y + interest->height;
+
+ if (x1 >= x2 || y1 >= y2)
+ {
+ *image_out = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
}
+ width = x2 - x1;
+ height = y2 - y1;
- width = glitz_surface_get_width (surface->surface);
- height = glitz_surface_get_height (surface->surface);
-
+ if (rect_out)
+ {
+ rect_out->x = x1;
+ rect_out->y = y1;
+ rect_out->width = width;
+ rect_out->height = height;
+ }
+
if (surface->format->type == GLITZ_FORMAT_TYPE_COLOR) {
if (surface->format->color.red_size > 0) {
format.bpp = 32;
@@ -149,21 +201,24 @@ _cairo_glitz_surface_get_image (void *abstract_surface)
pf.masks.blue_mask = format.blue_mask;
pf.xoffset = 0;
pf.skip_lines = 0;
+
+ /* XXX: we should eventually return images with negative stride,
+ need to verify that libpixman have no problem with this first. */
pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4;
pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
pixels = malloc (height * pf.bytes_per_line);
if (!pixels)
- return NULL;
+ return CAIRO_STATUS_NO_MEMORY;
buffer = glitz_buffer_create_for_data (pixels);
if (!buffer) {
free (pixels);
- return NULL;
+ return CAIRO_STATUS_NO_MEMORY;
}
glitz_get_pixels (surface->surface,
- 0, 0,
+ x1, y1,
width, height,
&pf,
buffer);
@@ -175,27 +230,38 @@ _cairo_glitz_surface_get_image (void *abstract_surface)
&format,
width, height,
pf.bytes_per_line);
-
+
+ if (!image)
+ {
+ free (pixels);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
_cairo_image_surface_assume_ownership_of_data (image);
_cairo_image_surface_set_repeat (image, surface->base.repeat);
_cairo_image_surface_set_matrix (image, &(surface->base.matrix));
- return image;
+ *image_out = image;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_glitz_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+_cairo_glitz_surface_set_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ int x_dst,
+ int y_dst)
{
cairo_glitz_surface_t *surface = abstract_surface;
- glitz_buffer_t *buffer;
- glitz_pixel_format_t pf;
- pixman_format_t *format;
- int am, rm, gm, bm;
+ glitz_buffer_t *buffer;
+ glitz_pixel_format_t pf;
+ pixman_format_t *format;
+ int am, rm, gm, bm;
+ char *data;
format = pixman_image_get_format (image->pixman_image);
- if (format == NULL)
+ if (!format)
return CAIRO_STATUS_NO_MEMORY;
pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm);
@@ -206,15 +272,27 @@ _cairo_glitz_surface_set_image (void *abstract_surface,
pf.masks.blue_mask = bm;
pf.xoffset = 0;
pf.skip_lines = 0;
- pf.bytes_per_line = image->stride;
- pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
- buffer = glitz_buffer_create_for_data (image->data);
+ /* check for negative stride */
+ if (image->stride < 0)
+ {
+ pf.bytes_per_line = -image->stride;
+ pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
+ data = (char *) image->data + image->stride * (image->height - 1);
+ }
+ else
+ {
+ pf.bytes_per_line = image->stride;
+ pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
+ data = (char *) image->data;
+ }
+
+ buffer = glitz_buffer_create_for_data (data);
if (!buffer)
return CAIRO_STATUS_NO_MEMORY;
glitz_set_pixels (surface->surface,
- 0, 0,
+ x_dst, y_dst,
image->width, image->height,
&pf,
buffer);
@@ -225,63 +303,118 @@ _cairo_glitz_surface_set_image (void *abstract_surface,
}
static cairo_status_t
-_cairo_glitz_surface_set_matrix (void *abstract_surface,
- cairo_matrix_t *matrix)
+_cairo_glitz_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
cairo_glitz_surface_t *surface = abstract_surface;
- glitz_transform_t transform;
- transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
+ *image_extra = NULL;
+
+ return _cairo_glitz_surface_get_image (surface, NULL, image_out, NULL);
+}
- transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
+static void
+_cairo_glitz_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ cairo_surface_destroy (&image->base);
+}
- transform.matrix[2][0] = 0;
- transform.matrix[2][1] = 0;
- transform.matrix[2][2] = 1 << 16;
+static cairo_status_t
+_cairo_glitz_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect_out,
+ void **image_extra)
+{
+ cairo_glitz_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
- glitz_surface_set_transform (surface->surface, &transform);
+ status = _cairo_glitz_surface_get_image (surface, interest_rect, &image,
+ image_rect_out);
+ if (status)
+ return status;
- return CAIRO_STATUS_SUCCESS;
+ *image_out = image;
+ *image_extra = NULL;
+
+ return status;
}
+static void
+_cairo_glitz_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+ cairo_glitz_surface_t *surface = abstract_surface;
+
+ _cairo_glitz_surface_set_image (surface, image,
+ image_rect->x, image_rect->y);
+
+ cairo_surface_destroy (&image->base);
+}
+
+
static cairo_status_t
-_cairo_glitz_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
+_cairo_glitz_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
cairo_glitz_surface_t *surface = abstract_surface;
- glitz_filter_t glitz_filter;
+ cairo_glitz_surface_t *clone;
- switch (filter) {
- case CAIRO_FILTER_FAST:
- case CAIRO_FILTER_NEAREST:
- glitz_filter = GLITZ_FILTER_NEAREST;
- break;
- case CAIRO_FILTER_GOOD:
- case CAIRO_FILTER_BEST:
- case CAIRO_FILTER_BILINEAR:
- default:
- glitz_filter = GLITZ_FILTER_BILINEAR;
- break;
+ if (src->backend == surface->base.backend)
+ {
+ *clone_out = src;
+ cairo_surface_reference (src);
+
+ return CAIRO_STATUS_SUCCESS;
}
+ else if (_cairo_surface_is_image (src))
+ {
+ cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
+
+ clone = (cairo_glitz_surface_t *)
+ _cairo_glitz_surface_create_similar (surface, image_src->format, 0,
+ image_src->width,
+ image_src->height);
+ if (!clone)
+ return CAIRO_STATUS_NO_MEMORY;
- glitz_surface_set_filter (surface->surface, glitz_filter, NULL, 0);
+ _cairo_glitz_surface_set_image (clone, image_src, 0, 0);
+
+ *clone_out = &clone->base;
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_status_t
-_cairo_glitz_surface_set_repeat (void *abstract_surface, int repeat)
+static void
+_cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface,
+ cairo_matrix_t *matrix)
{
- cairo_glitz_surface_t *surface = abstract_surface;
+ glitz_transform_t transform;
+
+ transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
+ transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
+ transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
- glitz_surface_set_fill (surface->surface,
- (repeat)? GLITZ_FILL_REPEAT:
- GLITZ_FILL_TRANSPARENT);
+ transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
+ transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
+ transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
- return CAIRO_STATUS_SUCCESS;
+ transform.matrix[2][0] = 0;
+ transform.matrix[2][1] = 0;
+ transform.matrix[2][2] = 1 << 16;
+
+ glitz_surface_set_transform (surface->surface, &transform);
}
static glitz_operator_t
@@ -318,32 +451,6 @@ _glitz_operator (cairo_operator_t op)
}
}
-static glitz_surface_t *
-_glitz_surface_create_solid (glitz_surface_t *other,
- glitz_format_name_t format_name,
- glitz_color_t *color)
-{
- glitz_drawable_t *drawable;
- glitz_format_t *format;
- glitz_surface_t *surface;
-
- drawable = glitz_surface_get_drawable (other);
-
- format = glitz_find_standard_format (drawable, format_name);
- if (format == NULL)
- return NULL;
-
- surface = glitz_surface_create (drawable, format, 1, 1);
- if (surface == NULL)
- return NULL;
-
- glitz_set_rectangle (surface, color, 0, 0, 1, 1);
-
- glitz_surface_set_fill (surface, GLITZ_FILL_REPEAT);
-
- return surface;
-}
-
static glitz_status_t
_glitz_ensure_target (glitz_surface_t *surface)
{
@@ -355,7 +462,6 @@ _glitz_ensure_target (glitz_surface_t *surface)
glitz_drawable_format_t templ;
glitz_format_t *format;
glitz_drawable_t *pbuffer;
- glitz_pbuffer_attributes_t attributes;
unsigned long mask;
int i;
@@ -397,21 +503,13 @@ _glitz_ensure_target (glitz_surface_t *surface)
if (!dformat)
return CAIRO_INT_STATUS_UNSUPPORTED;
- attributes.width = glitz_surface_get_width (surface);
- attributes.height = glitz_surface_get_height (surface);
- mask = GLITZ_PBUFFER_WIDTH_MASK | GLITZ_PBUFFER_HEIGHT_MASK;
-
- pbuffer = glitz_create_pbuffer_drawable (drawable, dformat,
- &attributes, mask);
+ pbuffer =
+ glitz_create_pbuffer_drawable (drawable, dformat,
+ glitz_surface_get_width (surface),
+ glitz_surface_get_height (surface));
if (!pbuffer)
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (glitz_drawable_get_width (pbuffer) < attributes.width ||
- glitz_drawable_get_height (pbuffer) < attributes.height) {
- glitz_drawable_destroy (pbuffer);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
glitz_surface_attach (surface, pbuffer,
GLITZ_DRAWABLE_BUFFER_FRONT_COLOR,
0, 0);
@@ -422,388 +520,711 @@ _glitz_ensure_target (glitz_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
}
-static glitz_format_name_t
-_glitz_format (cairo_format_t format)
+typedef struct _cairo_glitz_surface_attributes {
+ cairo_surface_attributes_t base;
+
+ glitz_fill_t fill;
+ glitz_filter_t filter;
+ glitz_fixed16_16_t *params;
+ int n_params;
+ cairo_bool_t acquired;
+} cairo_glitz_surface_attributes_t;
+
+static cairo_int_status_t
+_cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
+ cairo_glitz_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glitz_surface_t **surface_out,
+ cairo_glitz_surface_attributes_t *attr)
{
- switch (format) {
+ cairo_glitz_surface_t *src = NULL;
+
+ attr->acquired = FALSE;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ cairo_gradient_pattern_t *gradient =
+ (cairo_gradient_pattern_t *) pattern;
+ glitz_drawable_t *drawable;
+ glitz_fixed16_16_t *params;
+ int n_params;
+ int i;
+ unsigned short alpha;
+
+ /* XXX: the current color gradient acceleration provided by glitz is
+ * experimental, it's been proven inappropriate in a number of ways,
+ * most importantly, it's currently implemented as filters and
+ * gradients are not filters. eventually, it will be replaced with
+ * something more appropriate.
+ */
+
+ if (gradient->n_stops < 2)
+ break;
+
+ /* glitz doesn't support inner and outer circle with different
+ center points. */
+ if (pattern->type == CAIRO_PATTERN_RADIAL)
+ {
+ cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
+
+ if (grad->center0.x != grad->center1.x ||
+ grad->center0.y != grad->center1.y)
+ break;
+ }
+
+ drawable = glitz_surface_get_drawable (dst->surface);
+ if (!(glitz_drawable_get_features (drawable) &
+ GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
+ break;
+
+ if (pattern->filter != CAIRO_FILTER_BILINEAR &&
+ pattern->filter != CAIRO_FILTER_GOOD &&
+ pattern->filter != CAIRO_FILTER_BEST)
+ break;
+
+ alpha = (gradient->stops[0].color.alpha * pattern->alpha) * 0xffff;
+ for (i = 1; i < gradient->n_stops; i++)
+ {
+ unsigned short a;
+
+ a = (gradient->stops[i].color.alpha * pattern->alpha) * 0xffff;
+ if (a != alpha)
+ break;
+ }
+
+ /* we can't have color stops with different alpha as gradient color
+ interpolation should be done to unpremultiplied colors. */
+ if (i < gradient->n_stops)
+ break;
+
+ n_params = gradient->n_stops * 3 + 4;
+
+ params = malloc (sizeof (glitz_fixed16_16_t) * n_params);
+ if (!params)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ src = (cairo_glitz_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ CAIRO_FORMAT_ARGB32, 0,
+ gradient->n_stops, 1);
+ if (!src)
+ {
+ free (params);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < gradient->n_stops; i++) {
+ glitz_color_t color;
+
+ color.red = gradient->stops[i].color.red * alpha;
+ color.green = gradient->stops[i].color.green * alpha;
+ color.blue = gradient->stops[i].color.blue * alpha;
+ color.alpha = alpha;
+
+ glitz_set_rectangle (src->surface, &color, i, 0, 1, 1);
+
+ params[4 + 3 * i] = gradient->stops[i].offset;
+ params[5 + 3 * i] = i << 16;
+ params[6 + 3 * i] = 0;
+ }
+
+ if (pattern->type == CAIRO_PATTERN_LINEAR)
+ {
+ cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern;
+
+ params[0] = _cairo_fixed_from_double (grad->point0.x);
+ params[1] = _cairo_fixed_from_double (grad->point0.y);
+ params[2] = _cairo_fixed_from_double (grad->point1.x);
+ params[3] = _cairo_fixed_from_double (grad->point1.y);
+ attr->filter = GLITZ_FILTER_LINEAR_GRADIENT;
+ }
+ else
+ {
+ cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
+
+ params[0] = _cairo_fixed_from_double (grad->center0.x);
+ params[1] = _cairo_fixed_from_double (grad->center0.y);
+ params[2] = _cairo_fixed_from_double (grad->radius0);
+ params[3] = _cairo_fixed_from_double (grad->radius1);
+ attr->filter = GLITZ_FILTER_RADIAL_GRADIENT;
+ }
+
+ switch (pattern->extend) {
+ case CAIRO_EXTEND_NONE:
+ attr->fill = GLITZ_FILL_NEAREST;
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ attr->fill = GLITZ_FILL_REPEAT;
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ attr->fill = GLITZ_FILL_REFLECT;
+ break;
+ }
+
+ attr->params = params;
+ attr->n_params = n_params;
+ attr->base.matrix = pattern->matrix;
+ attr->base.x_offset = 0;
+ attr->base.y_offset = 0;
+ } break;
default:
- case CAIRO_FORMAT_ARGB32:
- return GLITZ_STANDARD_ARGB32;
- case CAIRO_FORMAT_RGB24:
- return GLITZ_STANDARD_RGB24;
- case CAIRO_FORMAT_A8:
- return GLITZ_STANDARD_A8;
- case CAIRO_FORMAT_A1:
- return GLITZ_STANDARD_A1;
+ break;
}
-}
-static cairo_surface_t *
-_cairo_glitz_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int draw,
- int width,
- int height)
-{
- cairo_glitz_surface_t *src = abstract_src;
- cairo_surface_t *crsurface;
- glitz_drawable_t *drawable;
- glitz_surface_t *surface;
- glitz_format_t *gformat;
+ if (!src)
+ {
+ cairo_int_status_t status;
- drawable = glitz_surface_get_drawable (src->surface);
-
- gformat = glitz_find_standard_format (drawable, _glitz_format (format));
- if (gformat == NULL)
- return NULL;
-
- surface = glitz_surface_create (drawable, gformat, width, height);
- if (surface == NULL)
- return NULL;
+ status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ x, y, width, height,
+ (cairo_surface_t **) &src,
+ &attr->base);
+ if (status)
+ return status;
+
+ if (src)
+ {
+ switch (attr->base.extend) {
+ case CAIRO_EXTEND_NONE:
+ attr->fill = GLITZ_FILL_TRANSPARENT;
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ attr->fill = GLITZ_FILL_REPEAT;
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ attr->fill = GLITZ_FILL_REFLECT;
+ break;
+ }
- crsurface = cairo_glitz_surface_create (surface);
-
- glitz_surface_destroy (surface);
+ switch (attr->base.filter) {
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ attr->filter = GLITZ_FILTER_NEAREST;
+ break;
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_BILINEAR:
+ default:
+ attr->filter = GLITZ_FILTER_BILINEAR;
+ break;
+ }
+
+ attr->params = NULL;
+ attr->n_params = 0;
+ attr->acquired = TRUE;
+ }
+ }
- return crsurface;
+ *surface_out = src;
+
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_glitz_surface_t *
-_cairo_glitz_surface_clone_similar (cairo_glitz_surface_t *templ,
- cairo_surface_t *src,
- cairo_format_t format)
+static void
+_cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst,
+ cairo_glitz_surface_t *surface,
+ cairo_glitz_surface_attributes_t *attr)
{
- cairo_glitz_surface_t *clone;
- cairo_image_surface_t *src_image;
+ if (attr->acquired)
+ _cairo_pattern_release_surface (&dst->base, &surface->base,
+ &attr->base);
+ else
+ _cairo_glitz_surface_destroy (surface);
+}
- src_image = _cairo_surface_get_image (src);
+static cairo_int_status_t
+_cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
+ cairo_pattern_t *mask,
+ cairo_glitz_surface_t *dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glitz_surface_t **src_out,
+ cairo_glitz_surface_t **mask_out,
+ cairo_glitz_surface_attributes_t *sattr,
+ cairo_glitz_surface_attributes_t *mattr)
+{
+ cairo_int_status_t status;
+ cairo_pattern_union_t tmp;
+ cairo_bool_t src_opaque, mask_opaque;
+ double src_alpha, mask_alpha;
- clone = (cairo_glitz_surface_t *)
- _cairo_glitz_surface_create_similar (templ, format, 0,
- src_image->width,
- src_image->height);
- if (clone == NULL)
- return NULL;
-
- _cairo_glitz_surface_set_filter (clone, cairo_surface_get_filter (src));
+ src_opaque = _cairo_pattern_is_opaque (src);
+ mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
- _cairo_glitz_surface_set_image (clone, src_image);
-
- _cairo_glitz_surface_set_matrix (clone, &(src_image->base.matrix));
+ /* For surface patterns, we move any translucency from src->alpha
+ * to mask->alpha so we can use the source unchanged. Otherwise we
+ * move the translucency from mask->alpha to src->alpha so that
+ * we can drop the mask if possible.
+ */
+ if (src->type == CAIRO_PATTERN_SURFACE)
+ {
+ if (mask) {
+ mask_opaque = mask_opaque && src_opaque;
+ mask_alpha = mask->alpha * src->alpha;
+ } else {
+ mask_opaque = src_opaque;
+ mask_alpha = src->alpha;
+ }
+
+ src_alpha = 1.0;
+ src_opaque = TRUE;
+ }
+ else
+ {
+ if (mask)
+ {
+ src_opaque = mask_opaque && src_opaque;
+ src_alpha = mask->alpha * src->alpha;
+ /* FIXME: This needs changing when we support RENDER
+ * style 4-channel masks.
+ */
+ if (mask->type == CAIRO_PATTERN_SOLID)
+ mask = NULL;
+ } else
+ src_alpha = src->alpha;
+
+ mask_alpha = 1.0;
+ mask_opaque = TRUE;
+ }
+
+ _cairo_pattern_init_copy (&tmp.base, src);
+ _cairo_pattern_set_alpha (&tmp.base, src_alpha);
+
+ status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
+ src_x, src_y,
+ width, height,
+ src_out, sattr);
- cairo_surface_destroy (&src_image->base);
+ _cairo_pattern_fini (&tmp.base);
- return clone;
-}
+ if (status)
+ return status;
-static cairo_int_status_t
-_glitz_composite (glitz_operator_t op,
- glitz_surface_t *src,
- glitz_surface_t *mask,
- glitz_surface_t *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- int width,
- int height,
- glitz_buffer_t *geometry,
- glitz_geometry_format_t *format)
-{
- if (_glitz_ensure_target (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (mask || !mask_opaque)
+ {
+ if (mask)
+ _cairo_pattern_init_copy (&tmp.base, mask);
+ else
+ _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
- if (glitz_surface_get_status (dst))
- return CAIRO_STATUS_NO_TARGET_SURFACE;
-
- glitz_set_geometry (dst,
- 0, 0,
- format, geometry);
-
- glitz_composite (op,
- src,
- mask,
- dst,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
-
- glitz_set_geometry (dst, 0, 0, NULL, NULL);
+ _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
+
+ status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
+ mask_x, mask_y,
+ width, height,
+ mask_out, mattr);
+
+ _cairo_pattern_fini (&tmp.base);
- if (glitz_surface_get_status (dst) == GLITZ_STATUS_NOT_SUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (status)
+ {
+ _cairo_glitz_pattern_release_surface (dst, *src_out, sattr);
+ return status;
+ }
+ }
+ else
+ {
+ *mask_out = NULL;
+ }
return CAIRO_STATUS_SUCCESS;
}
+static void
+_cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface,
+ cairo_glitz_surface_attributes_t *a)
+{
+ _cairo_glitz_surface_set_matrix (surface, &a->base.matrix);
+ glitz_surface_set_fill (surface->surface, a->fill);
+ glitz_surface_set_filter (surface->surface, a->filter,
+ a->params, a->n_params);
+}
+
static cairo_int_status_t
_cairo_glitz_surface_composite (cairo_operator_t op,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
+ cairo_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
{
- cairo_glitz_surface_t *dst = abstract_dst;
- cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src;
- cairo_glitz_surface_t *mask = (cairo_glitz_surface_t *) generic_mask;
- cairo_glitz_surface_t *src_clone = NULL;
- cairo_glitz_surface_t *mask_clone = NULL;
- cairo_int_status_t status;
+ cairo_glitz_surface_attributes_t src_attr, mask_attr;
+ cairo_glitz_surface_t *dst = abstract_dst;
+ cairo_glitz_surface_t *src;
+ cairo_glitz_surface_t *mask;
+ cairo_int_status_t status;
if (op == CAIRO_OPERATOR_SATURATE)
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (generic_src->backend != dst->base.backend) {
- src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src,
- CAIRO_FORMAT_ARGB32);
- if (!src_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern,
+ dst,
+ src_x, src_y,
+ mask_x, mask_y,
+ width, height,
+ &src, &mask,
+ &src_attr, &mask_attr);
+ if (status)
+ return status;
+
+ _cairo_glitz_surface_set_attributes (src, &src_attr);
+ if (mask)
+ {
+ _cairo_glitz_surface_set_attributes (mask, &mask_attr);
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ mask->surface,
+ dst->surface,
+ src_x + src_attr.base.x_offset,
+ src_y + src_attr.base.y_offset,
+ mask_x + mask_attr.base.x_offset,
+ mask_y + mask_attr.base.y_offset,
+ dst_x, dst_y,
+ width, height);
- src = src_clone;
- }
-
- if (generic_mask && (generic_mask->backend != dst->base.backend)) {
- mask_clone = _cairo_glitz_surface_clone_similar (dst, generic_mask,
- CAIRO_FORMAT_A8);
- if (!mask_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (mask_attr.n_params)
+ free (mask_attr.params);
- mask = mask_clone;
+ _cairo_glitz_pattern_release_surface (dst, mask, &mask_attr);
+ }
+ else
+ {
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ NULL,
+ dst->surface,
+ src_x + src_attr.base.x_offset,
+ src_y + src_attr.base.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
}
- status = _glitz_composite (_glitz_operator (op),
- src->surface,
- (mask)? mask->surface: NULL,
- dst->surface,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height,
- NULL, NULL);
-
- if (src_clone)
- cairo_surface_destroy (&src_clone->base);
-
- if (mask_clone)
- cairo_surface_destroy (&mask_clone->base);
+ if (src_attr.n_params)
+ free (src_attr.params);
- return status;
+ _cairo_glitz_pattern_release_surface (dst, src, &src_attr);
+
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
-_cairo_glitz_surface_fill_rectangles (void *abstract_dst,
- cairo_operator_t op,
+_cairo_glitz_surface_fill_rectangles (void *abstract_dst,
+ cairo_operator_t op,
const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int n_rects)
+ cairo_rectangle_t *rects,
+ int n_rects)
{
cairo_glitz_surface_t *dst = abstract_dst;
- glitz_color_t glitz_color;
- if (op == CAIRO_OPERATOR_SATURATE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- glitz_color.red = color->red_short;
- glitz_color.green = color->green_short;
- glitz_color.blue = color->blue_short;
- glitz_color.alpha = color->alpha_short;
+ if (op == CAIRO_OPERATOR_SRC)
+ {
+ glitz_color_t glitz_color;
+
+ glitz_color.red = color->red_short;
+ glitz_color.green = color->green_short;
+ glitz_color.blue = color->blue_short;
+ glitz_color.alpha = color->alpha_short;
+
+ if (glitz_surface_get_width (dst->surface) != 1 ||
+ glitz_surface_get_height (dst->surface) != 1)
+ _glitz_ensure_target (dst->surface);
- if (op != CAIRO_OPERATOR_SRC) {
- glitz_surface_t *solid;
- glitz_float_t *vertices;
- glitz_buffer_t *buffer;
- glitz_geometry_format_t gf;
- cairo_int_status_t status;
- int width, height;
- void *data;
+ glitz_set_rectangles (dst->surface, &glitz_color,
+ (glitz_rectangle_t *) rects, n_rects);
+ }
+ else
+ {
+ cairo_glitz_surface_t *src;
- gf.mode = GLITZ_GEOMETRY_MODE_DIRECT;
- gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_SHARP;
- gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS;
- gf.type = GLITZ_DATA_TYPE_FLOAT;
- gf.first = 0;
- gf.count = n_rects * 4;
-
- data = malloc (n_rects * 8 * sizeof (glitz_float_t));
- if (!data)
- return CAIRO_STATUS_NO_MEMORY;
-
- buffer = glitz_buffer_create_for_data (data);
- if (buffer == NULL) {
- free (data);
- return CAIRO_STATUS_NO_MEMORY;
- }
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- width = height = 0;
- vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY);
- for (; n_rects; rects++, n_rects--) {
- *vertices++ = (glitz_float_t) rects->x;
- *vertices++ = (glitz_float_t) rects->y;
- *vertices++ = (glitz_float_t) (rects->x + rects->width);
- *vertices++ = (glitz_float_t) rects->y;
- *vertices++ = (glitz_float_t) (rects->x + rects->width);
- *vertices++ = (glitz_float_t) (rects->y + rects->height);
- *vertices++ = (glitz_float_t) rects->x;
- *vertices++ = (glitz_float_t) (rects->y + rects->height);
-
- if ((rects->x + rects->width) > width)
- width = rects->x + rects->width;
-
- if ((rects->y + rects->height) > height)
- height = rects->y + rects->height;
- }
- glitz_buffer_unmap (buffer);
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- solid = _glitz_surface_create_solid (dst->surface,
- GLITZ_STANDARD_ARGB32,
- &glitz_color);
- if (solid == NULL)
+ src = (cairo_glitz_surface_t *)
+ _cairo_surface_create_similar_solid (&dst->base,
+ CAIRO_FORMAT_ARGB32, 1, 1,
+ (cairo_color_t *) color);
+ if (!src)
return CAIRO_STATUS_NO_MEMORY;
-
- status = _glitz_composite (_glitz_operator (op),
- solid,
- NULL,
- dst->surface,
- 0, 0,
- 0, 0,
- 0, 0,
- width, height,
- buffer, &gf);
-
- glitz_surface_destroy (solid);
- glitz_buffer_destroy (buffer);
- free (data);
-
- return status;
- } else {
- if (glitz_surface_get_width (dst->surface) != 1 ||
- glitz_surface_get_height (dst->surface) != 1) {
- if (_glitz_ensure_target (dst->surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ while (n_rects--)
+ {
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ NULL,
+ dst->surface,
+ 0, 0,
+ 0, 0,
+ rects->x, rects->y,
+ rects->width, rects->height);
+ rects++;
}
- glitz_set_rectangles (dst->surface, &glitz_color,
- (glitz_rectangle_t *) rects, n_rects);
+ cairo_surface_destroy (&src->base);
}
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
-_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
- cairo_surface_t *generic_src,
- void *abstract_dst,
- int x_src,
- int y_src,
+_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
+ cairo_pattern_t *pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
- int n_traps)
+ int n_traps)
{
- cairo_glitz_surface_t *dst = abstract_dst;
- cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src;
- glitz_surface_t *mask = NULL;
- glitz_float_t *vertices;
- glitz_buffer_t *buffer;
- glitz_geometry_format_t gf;
- cairo_int_status_t status;
- int x_dst, y_dst, x_rel, y_rel, width, height;
- void *data;
+ cairo_glitz_surface_attributes_t attributes;
+ cairo_glitz_surface_t *dst = abstract_dst;
+ cairo_glitz_surface_t *src;
+ cairo_glitz_surface_t *mask = NULL;
+ glitz_buffer_t *buffer = NULL;
+ void *data = NULL;
+ cairo_int_status_t status;
+ unsigned short alpha;
if (op == CAIRO_OPERATOR_SATURATE)
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (generic_src->backend != dst->base.backend)
+ if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
- gf.mode = GLITZ_GEOMETRY_MODE_DIRECT;
- gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_GOOD_SMOOTH;
- gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS;
- gf.type = GLITZ_DATA_TYPE_FLOAT;
- gf.first = 0;
- gf.count = n_traps * 4;
+ if (pattern->type == CAIRO_PATTERN_SURFACE)
+ {
+ cairo_pattern_union_t tmp;
- data = malloc (n_traps * 8 * sizeof (glitz_float_t));
- if (!data)
- return CAIRO_STATUS_NO_MEMORY;
-
- buffer = glitz_buffer_create_for_data (data);
- if (buffer == NULL) {
- free (data);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- x_dst = traps[0].left.p1.x >> 16;
- y_dst = traps[0].left.p1.y >> 16;
+ _cairo_pattern_init_copy (&tmp.base, pattern);
+ _cairo_pattern_set_alpha (&tmp.base, 1.0);
- vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY);
- for (; n_traps; traps++, n_traps--) {
- glitz_float_t top, bottom;
+ status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
+ src_x, src_y,
+ width, height,
+ &src, &attributes);
- top = GLITZ_FIXED_TO_FLOAT (traps->top);
- bottom = GLITZ_FIXED_TO_FLOAT (traps->bottom);
+ _cairo_pattern_fini (&tmp.base);
- *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->top);
- *vertices++ = top;
- *vertices++ =
- GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->top);
- *vertices++ = top;
- *vertices++ =
- GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->bottom);
- *vertices++ = bottom;
- *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->bottom);
- *vertices++ = bottom;
+ alpha = pattern->alpha * 0xffff;
}
- glitz_buffer_unmap (buffer);
+ else
+ {
+ status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
+ src_x, src_y,
+ width, height,
+ &src, &attributes);
+ alpha = 0xffff;
+ }
+
+ if (status)
+ return status;
+
+ if (op == CAIRO_OPERATOR_ADD || n_traps <= 1)
+ {
+ static glitz_color_t clear_black = { 0, 0, 0, 0 };
+ glitz_color_t color;
+ glitz_geometry_format_t format;
+ int n_trap_added;
+ int offset = 0;
+ int data_size = 0;
+ int size = 30 * n_traps; /* just a guess */
+
+ format.vertex.primitive = GLITZ_PRIMITIVE_QUADS;
+ format.vertex.type = GLITZ_DATA_TYPE_FLOAT;
+ format.vertex.bytes_per_vertex = 3 * sizeof (glitz_float_t);
+ format.vertex.attributes = GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK;
+ format.vertex.mask.type = GLITZ_DATA_TYPE_FLOAT;
+ format.vertex.mask.size = GLITZ_COORDINATE_SIZE_X;
+ format.vertex.mask.offset = 2 * sizeof (glitz_float_t);
+
+ mask = (cairo_glitz_surface_t *)
+ _cairo_glitz_surface_create_similar (&dst->base,
+ CAIRO_FORMAT_A8, 0,
+ 2, 1);
+ if (!mask)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ color.red = color.green = color.blue = color.alpha = alpha;
- if ((src->pattern.type == CAIRO_PATTERN_SURFACE) &&
- (src->pattern.color.alpha != 1.0)) {
- glitz_color_t color;
+ glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1);
+ glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1);
+
+ glitz_surface_set_fill (mask->surface, GLITZ_FILL_NEAREST);
+ glitz_surface_set_filter (mask->surface,
+ GLITZ_FILTER_BILINEAR,
+ NULL, 0);
+
+ size *= format.vertex.bytes_per_vertex;
- color.red = color.green = color.blue = 0;
- color.alpha = src->pattern.color.alpha_short;
+ while (n_traps)
+ {
+ if (data_size < size)
+ {
+ data_size = size;
+ data = realloc (data, data_size);
+ if (!data)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src,
+ &attributes);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ if (buffer)
+ glitz_buffer_destroy (buffer);
+
+ buffer = glitz_buffer_create_for_data (data);
+ if (!buffer) {
+ free (data);
+ _cairo_glitz_pattern_release_surface (dst, src,
+ &attributes);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+ }
- mask = _glitz_surface_create_solid (dst->surface,
- GLITZ_STANDARD_A8,
- &color);
+ offset +=
+ glitz_add_trapezoids (buffer,
+ offset, size - offset,
+ format.vertex.type, mask->surface,
+ (glitz_trapezoid_t *) traps, n_traps,
+ &n_trap_added);
+
+ n_traps -= n_trap_added;
+ traps += n_trap_added;
+ size *= 2;
+ }
+
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_VERTEX,
+ &format, buffer);
+ glitz_set_array (dst->surface, 0, 3,
+ offset / format.vertex.bytes_per_vertex,
+ 0, 0);
}
+ else
+ {
+ cairo_image_surface_t *image;
+ char *ptr;
+ int stride;
+
+ stride = (width + 3) & -4;
+ data = malloc (stride * height);
+ if (!data)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ memset (data, 0, stride * height);
- x_rel = (src->pattern_box.p1.x >> 16) + x_src - x_dst;
- y_rel = (src->pattern_box.p1.y >> 16) + y_src - y_dst;
+ /* using negative stride */
+ ptr = (char *) data + stride * (height - 1);
+
+ image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (ptr,
+ CAIRO_FORMAT_A8,
+ width, height,
+ -stride);
+ if (!image)
+ {
+ cairo_surface_destroy (&src->base);
+ free (data);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
- x_dst = src->pattern_box.p1.x >> 16;
- y_dst = src->pattern_box.p1.y >> 16;
+ pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
+ (pixman_trapezoid_t *) traps, n_traps);
+
+ if (alpha != 0xffff)
+ {
+ pixman_color_t color;
+
+ color.red = color.green = color.blue = color.alpha = alpha;
+
+ pixman_fill_rectangle (PIXMAN_OPERATOR_IN,
+ image->pixman_image,
+ &color,
+ 0, 0, width, height);
+ }
+
+ mask = (cairo_glitz_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ CAIRO_FORMAT_A8, 0,
+ width, height);
+ if (!mask)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+ free (data);
+ cairo_surface_destroy (&image->base);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ _cairo_glitz_surface_set_image (mask, image, 0, 0);
+ }
+
+ _cairo_glitz_surface_set_attributes (src, &attributes);
- width = ((src->pattern_box.p2.x + 65535) >> 16) -
- (src->pattern_box.p1.x >> 16);
- height = ((src->pattern_box.p2.y + 65535) >> 16) -
- (src->pattern_box.p1.y >> 16);
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ mask->surface,
+ dst->surface,
+ src_x + attributes.base.x_offset,
+ src_y + attributes.base.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+
+ if (attributes.n_params)
+ free (attributes.params);
+
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_NONE,
+ NULL, NULL);
+
+ if (buffer)
+ glitz_buffer_destroy (buffer);
- status = _glitz_composite (_glitz_operator (op),
- src->surface,
- mask,
- dst->surface,
- x_rel, y_rel,
- 0, 0,
- x_dst, y_dst,
- width, height,
- buffer, &gf);
+ free (data);
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
if (mask)
- glitz_surface_destroy (mask);
+ cairo_surface_destroy (&mask->base);
- glitz_buffer_destroy (buffer);
- free (data);
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@@ -819,173 +1240,56 @@ _cairo_glitz_surface_show_page (void *abstract_surface)
}
static cairo_int_status_t
-_cairo_glitz_surface_create_pattern (void *abstract_dst,
- cairo_pattern_t *pattern,
- cairo_box_t *box)
+_cairo_glitz_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
{
- cairo_glitz_surface_t *dst = abstract_dst;
- cairo_surface_t *generic_src = NULL;
- cairo_image_surface_t *image = NULL;
- cairo_glitz_surface_t *src;
-
- switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
- generic_src =
- _cairo_surface_create_similar_solid (abstract_dst,
- CAIRO_FORMAT_ARGB32,
- 1, 1,
- &pattern->color);
- if (generic_src)
- cairo_surface_set_repeat (generic_src, 1);
- break;
- case CAIRO_PATTERN_RADIAL:
- /* glitz doesn't support inner and outer circle with different
- center points. */
- if (pattern->u.radial.center0.x != pattern->u.radial.center1.x ||
- pattern->u.radial.center0.y != pattern->u.radial.center1.y)
- break;
- /* fall-through */
- case CAIRO_PATTERN_LINEAR: {
- glitz_drawable_t *drawable;
- glitz_fixed16_16_t *params;
- int i, n_params;
-
- drawable = glitz_surface_get_drawable (dst->surface);
- if (!(glitz_drawable_get_features (drawable) &
- GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
- break;
-
- if (pattern->filter != CAIRO_FILTER_BILINEAR)
- break;
-
- n_params = pattern->n_stops * 3 + 4;
-
- params = malloc (sizeof (glitz_fixed16_16_t) * n_params);
- if (params == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- generic_src =
- _cairo_glitz_surface_create_similar (abstract_dst,
- CAIRO_FORMAT_ARGB32, 0,
- pattern->n_stops, 1);
- if (generic_src == NULL) {
- free (params);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- src = (cairo_glitz_surface_t *) generic_src;
-
- for (i = 0; i < pattern->n_stops; i++) {
- glitz_color_t color;
+ cairo_glitz_surface_t *surface = abstract_surface;
- color.alpha = pattern->stops[i].color_char[3];
- color.red = pattern->stops[i].color_char[0] * color.alpha;
- color.green = pattern->stops[i].color_char[1] * color.alpha;
- color.blue = pattern->stops[i].color_char[2] * color.alpha;
- color.alpha *= 256;
+ if (region)
+ {
+ glitz_box_t *box;
+ int n;
- glitz_set_rectangle (src->surface, &color, i, 0, 1, 1);
-
- params[4 + 3 * i] = pattern->stops[i].offset;
- params[5 + 3 * i] = i << 16;
- params[6 + 3 * i] = 0;
- }
-
- if (pattern->type == CAIRO_PATTERN_LINEAR) {
- params[0] = _cairo_fixed_from_double (pattern->u.linear.point0.x);
- params[1] = _cairo_fixed_from_double (pattern->u.linear.point0.y);
- params[2] = _cairo_fixed_from_double (pattern->u.linear.point1.x);
- params[3] = _cairo_fixed_from_double (pattern->u.linear.point1.y);
-
- glitz_surface_set_filter (src->surface,
- GLITZ_FILTER_LINEAR_GRADIENT,
- params, n_params);
- } else {
- params[0] = _cairo_fixed_from_double (pattern->u.radial.center0.x);
- params[1] = _cairo_fixed_from_double (pattern->u.radial.center0.y);
- params[2] = _cairo_fixed_from_double (pattern->u.radial.radius0);
- params[3] = _cairo_fixed_from_double (pattern->u.radial.radius1);
-
- glitz_surface_set_filter (src->surface,
- GLITZ_FILTER_RADIAL_GRADIENT,
- params, n_params);
- }
-
- switch (pattern->extend) {
- case CAIRO_EXTEND_REPEAT:
- glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
- break;
- case CAIRO_EXTEND_REFLECT:
- glitz_surface_set_fill (src->surface, GLITZ_FILL_REFLECT);
- break;
- case CAIRO_EXTEND_NONE:
- default:
- glitz_surface_set_fill (src->surface, GLITZ_FILL_NEAREST);
- break;
+ if (!surface->clip)
+ {
+ surface->clip = pixman_region_create ();
+ if (!surface->clip)
+ return CAIRO_STATUS_NO_MEMORY;
}
+ pixman_region_copy (surface->clip, region);
- cairo_surface_set_matrix (&src->base, &pattern->matrix);
-
- free (params);
- } break;
- case CAIRO_PATTERN_SURFACE:
- generic_src = pattern->u.surface.surface;
- cairo_surface_reference (generic_src);
- break;
- }
-
- if (generic_src == NULL) {
- image = _cairo_pattern_get_image (pattern, box);
- if (image == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- generic_src = &image->base;
+ box = (glitz_box_t *) pixman_region_rects (surface->clip);
+ n = pixman_region_num_rects (surface->clip);
+ glitz_surface_set_clip_region (surface->surface, 0, 0, box, n);
}
+ else
+ {
+ glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
- if (generic_src->backend != dst->base.backend) {
- src = _cairo_glitz_surface_clone_similar (dst, generic_src,
- CAIRO_FORMAT_ARGB32);
- if (src == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- cairo_surface_set_repeat (&src->base, generic_src->repeat);
- } else
- src = (cairo_glitz_surface_t *) generic_src;
+ if (surface->clip)
+ pixman_region_destroy (surface->clip);
- if (image)
- cairo_surface_destroy (&image->base);
-
- _cairo_pattern_init_copy (&src->pattern, pattern);
- src->pattern_box = *box;
-
- pattern->source = &src->base;
+ surface->clip = NULL;
+ }
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_glitz_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_create_similar,
_cairo_glitz_surface_destroy,
_cairo_glitz_surface_pixels_per_inch,
- _cairo_glitz_surface_get_image,
- _cairo_glitz_surface_set_image,
- _cairo_glitz_surface_set_matrix,
- _cairo_glitz_surface_set_filter,
- _cairo_glitz_surface_set_repeat,
+ _cairo_glitz_surface_acquire_source_image,
+ _cairo_glitz_surface_release_source_image,
+ _cairo_glitz_surface_acquire_dest_image,
+ _cairo_glitz_surface_release_dest_image,
+ _cairo_glitz_surface_clone_similar,
_cairo_glitz_surface_composite,
_cairo_glitz_surface_fill_rectangles,
_cairo_glitz_surface_composite_trapezoids,
_cairo_glitz_surface_copy_page,
_cairo_glitz_surface_show_page,
_cairo_glitz_surface_set_clip_region,
- _cairo_glitz_surface_create_pattern,
NULL /* show_glyphs */
};
@@ -1004,12 +1308,10 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
_cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend);
glitz_surface_reference (surface);
- crsurface->surface = surface;
- crsurface->format = glitz_surface_get_format (surface);
- _cairo_pattern_init (&crsurface->pattern);
- crsurface->pattern.type = CAIRO_PATTERN_SURFACE;
- crsurface->pattern.u.surface.surface = NULL;
+ crsurface->surface = surface;
+ crsurface->format = glitz_surface_get_format (surface);
+ crsurface->clip = NULL;
return (cairo_surface_t *) crsurface;
}
diff --git a/src/cairo-glitz.h b/src/cairo-glitz.h
index 350d10233..f1917eb28 100644
--- a/src/cairo-glitz.h
+++ b/src/cairo-glitz.h
@@ -31,17 +31,20 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
-#include <cairo.h>
-
#ifndef CAIRO_GLITZ_H
#define CAIRO_GLITZ_H
+
+#include <cairo.h>
+
#ifdef CAIRO_HAS_GLITZ_SURFACE
#include <glitz.h>
+CAIRO_BEGIN_DECLS
+
void
cairo_set_target_glitz (cairo_t *cr,
glitz_surface_t *surface);
@@ -49,5 +52,7 @@ cairo_set_target_glitz (cairo_t *cr,
cairo_surface_t *
cairo_glitz_surface_create (glitz_surface_t *surface);
+CAIRO_END_DECLS
+
#endif /* CAIRO_HAS_GLITZ_SURFACE */
#endif /* CAIRO_GLITZ_H */
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index e855a7a66..d6db560a3 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include <stdlib.h>
@@ -46,20 +46,33 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
cairo_surface_t *dst,
cairo_traps_t *traps);
+static cairo_status_t
+_cairo_gstate_ensure_font (cairo_gstate_t *gstate);
+
+static void
+_cairo_gstate_unset_font (cairo_gstate_t *gstate);
+
cairo_gstate_t *
_cairo_gstate_create ()
{
+ cairo_status_t status;
cairo_gstate_t *gstate;
gstate = malloc (sizeof (cairo_gstate_t));
if (gstate)
- _cairo_gstate_init (gstate);
+ {
+ status = _cairo_gstate_init (gstate);
+ if (status) {
+ free (gstate);
+ return NULL;
+ }
+ }
return gstate;
}
-void
+cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate)
{
gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
@@ -77,9 +90,11 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->num_dashes = 0;
gstate->dash_offset = 0.0;
- gstate->font = _cairo_unscaled_font_create (CAIRO_FONT_FAMILY_DEFAULT,
- CAIRO_FONT_SLANT_DEFAULT,
- CAIRO_FONT_WEIGHT_DEFAULT);
+ gstate->font_family = NULL;
+ gstate->font_slant = CAIRO_FONT_SLANT_DEFAULT;
+ gstate->font_weight = CAIRO_FONT_WEIGHT_DEFAULT;
+
+ gstate->font = NULL;
gstate->surface = NULL;
@@ -87,6 +102,9 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->clip.surface = NULL;
gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0);
+ if (!gstate->pattern)
+ return CAIRO_STATUS_NO_MEMORY;
+
gstate->alpha = 1.0;
gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
@@ -97,6 +115,8 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
_cairo_pen_init_empty (&gstate->pen_regular);
gstate->next = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@@ -118,9 +138,15 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
}
+ if (other->font_family) {
+ gstate->font_family = strdup (other->font_family);
+ if (!gstate->font_family)
+ goto CLEANUP_DASH;
+ }
+
if (other->font) {
gstate->font = other->font;
- _cairo_unscaled_font_reference (gstate->font);
+ cairo_font_reference (gstate->font);
}
if (other->clip.region)
@@ -148,18 +174,29 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
_cairo_path_fini (&gstate->path);
CLEANUP_FONT:
- _cairo_unscaled_font_destroy (gstate->font);
+ cairo_font_destroy (gstate->font);
+ gstate->font = NULL;
+
+ if (gstate->font_family) {
+ free (gstate->font_family);
+ gstate->font_family = NULL;
+ }
+ CLEANUP_DASH:
free (gstate->dash);
gstate->dash = NULL;
- return status;
+ return CAIRO_STATUS_NO_MEMORY;
}
void
_cairo_gstate_fini (cairo_gstate_t *gstate)
{
- _cairo_unscaled_font_destroy (gstate->font);
+ if (gstate->font_family)
+ free (gstate->font_family);
+
+ if (gstate->font)
+ cairo_font_destroy (gstate->font);
if (gstate->surface)
cairo_surface_destroy (gstate->surface);
@@ -323,6 +360,8 @@ _cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surfa
{
double scale;
+ _cairo_gstate_unset_font (gstate);
+
if (gstate->surface)
cairo_surface_destroy (gstate->surface);
@@ -365,11 +404,9 @@ _cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern)
if (pattern == NULL)
return CAIRO_STATUS_NULL_POINTER;
- if (gstate->pattern)
- cairo_pattern_destroy (gstate->pattern);
-
- gstate->pattern = pattern;
cairo_pattern_reference (pattern);
+ cairo_pattern_destroy (gstate->pattern);
+ gstate->pattern = pattern;
return CAIRO_STATUS_SUCCESS;
}
@@ -407,6 +444,8 @@ _cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, d
cairo_pattern_destroy (gstate->pattern);
gstate->pattern = _cairo_pattern_create_solid (red, green, blue);
+ if (!gstate->pattern)
+ return CAIRO_STATUS_NO_MEMORY;
return CAIRO_STATUS_SUCCESS;
}
@@ -549,6 +588,8 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
{
cairo_matrix_t tmp;
+ _cairo_gstate_unset_font (gstate);
+
_cairo_matrix_set_translate (&tmp, tx, ty);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -566,6 +607,8 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
if (sx == 0 || sy == 0)
return CAIRO_STATUS_INVALID_MATRIX;
+ _cairo_gstate_unset_font (gstate);
+
_cairo_matrix_set_scale (&tmp, sx, sy);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -580,6 +623,8 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
{
cairo_matrix_t tmp;
+ _cairo_gstate_unset_font (gstate);
+
_cairo_matrix_set_rotate (&tmp, angle);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -595,6 +640,8 @@ _cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
{
cairo_matrix_t tmp;
+ _cairo_gstate_unset_font (gstate);
+
cairo_matrix_copy (&tmp, matrix);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -610,6 +657,8 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate,
{
cairo_status_t status;
+ _cairo_gstate_unset_font (gstate);
+
cairo_matrix_copy (&gstate->ctm, matrix);
cairo_matrix_copy (&gstate->ctm_inverse, matrix);
@@ -627,6 +676,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate)
if (scale == 0)
scale = 1;
+ _cairo_gstate_unset_font (gstate);
+
cairo_matrix_set_identity (&gstate->font_matrix);
cairo_matrix_set_identity (&gstate->ctm);
@@ -640,6 +691,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate)
cairo_status_t
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
{
+ _cairo_gstate_unset_font (gstate);
+
cairo_matrix_set_identity (&gstate->ctm);
cairo_matrix_set_identity (&gstate->ctm_inverse);
@@ -1256,54 +1309,17 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate,
&gpi);
}
-/* This function modifies the pattern and the state of the pattern surface it
- may contain. The pattern surface will be restored to its orignal state
- when the pattern is destroyed. The appropriate way is to pass a copy of
- the original pattern to this function just before the pattern should be
- used and destroy the copy when done. */
-static cairo_status_t
-_cairo_gstate_create_pattern (cairo_gstate_t *gstate,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
+/* XXX: gstate->alpha will be going away before too long, and when it
+ * does, it may make sense for this function to just disappear.
+ */
+static void
+_cairo_gstate_pattern_init_copy (cairo_gstate_t *gstate,
+ cairo_pattern_union_t *pattern,
+ cairo_pattern_t *src)
{
- cairo_int_status_t status;
-
- if (gstate->surface == NULL) {
- _cairo_pattern_fini (pattern);
- return CAIRO_STATUS_NO_TARGET_SURFACE;
- }
-
- if (pattern->type == CAIRO_PATTERN_LINEAR ||
- pattern->type == CAIRO_PATTERN_RADIAL) {
- if (pattern->n_stops < 2) {
- pattern->type = CAIRO_PATTERN_SOLID;
-
- if (pattern->n_stops) {
- cairo_color_stop_t *stop = pattern->stops;
-
- _cairo_color_set_rgb (&pattern->color,
- (double) stop->color_char[0] / 0xff,
- (double) stop->color_char[1] / 0xff,
- (double) stop->color_char[2] / 0xff);
- _cairo_color_set_alpha (&pattern->color,
- (double) stop->color_char[3] / 0xff);
- }
- }
- }
-
- _cairo_pattern_set_alpha (pattern, gstate->alpha);
- _cairo_pattern_transform (pattern, &gstate->ctm_inverse);
-
- status = _cairo_surface_create_pattern (gstate->surface, pattern, extents);
- if (status) {
- _cairo_pattern_fini (pattern);
- return status;
- }
-
- if (pattern->type == CAIRO_PATTERN_SURFACE)
- _cairo_pattern_prepare_surface (pattern);
-
- return CAIRO_STATUS_SUCCESS;
+ _cairo_pattern_init_copy (&pattern->base, src);
+ _cairo_pattern_transform (&pattern->base, &gstate->ctm_inverse);
+ _cairo_pattern_set_alpha (&pattern->base, gstate->alpha);
}
cairo_status_t
@@ -1342,7 +1358,7 @@ cairo_status_t
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double x,
double y,
- int *inside_ret)
+ cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;
@@ -1365,51 +1381,85 @@ BAIL:
return status;
}
-static cairo_status_t
-_calculate_region_for_intermediate_clip_surface (pixman_region16_t *out,
- cairo_box_t *extents,
- cairo_clip_rec_t *clip_rect)
+/* XXX We currently have a confusing mix of boxes and rectangles as
+ * exemplified by this function. A cairo_box_t is a rectangular area
+ * represented by the coordinates of the upper left and lower right
+ * corners, expressed in fixed point numbers. A cairo_rectangle_t is
+ * also a rectangular area, but represented by the upper left corner
+ * and the width and the height, as integer numbers.
+ *
+ * This function converts a cairo_box_t to a cairo_rectangle_t by
+ * increasing the area to the nearest integer coordinates. We should
+ * standardize on cairo_rectangle_t and cairo_rectangle_fixed_t, and
+ * this function could be renamed to the more reasonable
+ * _cairo_rectangle_fixed_round.
+ */
+
+static void
+_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle)
{
- cairo_status_t status;
- pixman_region16_t *extents_region, *clip_region;
- pixman_box16_t clip_box, pixman_extents;
-
- pixman_extents.x1 = _cairo_fixed_integer_floor (extents->p1.x);
- pixman_extents.y1 = _cairo_fixed_integer_floor (extents->p1.y);
- pixman_extents.x2 = _cairo_fixed_integer_ceil (extents->p2.x);
- pixman_extents.y2 = _cairo_fixed_integer_ceil (extents->p2.y);
- extents_region = pixman_region_create_simple (&pixman_extents);
- if (extents_region == NULL)
- {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL0;
- }
+ rectangle->x = _cairo_fixed_integer_floor (box->p1.x);
+ rectangle->y = _cairo_fixed_integer_floor (box->p1.y);
+ rectangle->width = _cairo_fixed_integer_ceil (box->p2.x) - rectangle->x;
+ rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y;
+}
- clip_box.x1 = clip_rect->x;
- clip_box.y1 = clip_rect->y;
- clip_box.x2 = clip_rect->x + clip_rect->width;
- clip_box.y2 = clip_rect->y + clip_rect->height;
- clip_region = pixman_region_create_simple (&clip_box);
- if (clip_region == NULL)
- {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
+static void
+_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src)
+{
+ int x1, y1, x2, y2;
- if (pixman_region_intersect (out,
- extents_region,
- clip_region)
- == PIXMAN_REGION_STATUS_FAILURE)
- status = CAIRO_STATUS_NO_MEMORY;
- else
- status = CAIRO_STATUS_SUCCESS;
-
- pixman_region_destroy (extents_region);
- BAIL1:
- pixman_region_destroy (clip_region);
-
- BAIL0:
- return status;
+ x1 = MAX (dest->x, src->x);
+ y1 = MAX (dest->y, src->y);
+ x2 = MIN (dest->x + dest->width, src->x + src->width);
+ y2 = MIN (dest->y + dest->height, src->y + src->height);
+
+ if (x1 >= x2 || y1 >= y2) {
+ dest->x = 0;
+ dest->y = 0;
+ dest->width = 0;
+ dest->height = 0;
+ } else {
+ dest->x = x1;
+ dest->y = y1;
+ dest->width = x2 - x1;
+ dest->height = y2 - y1;
+ }
+}
+
+static int
+_cairo_rectangle_empty (cairo_rectangle_t *rect)
+{
+ return rect->width == 0 || rect->height == 0;
+}
+
+static void
+translate_traps (cairo_traps_t *traps, int x, int y)
+{
+ cairo_fixed_t xoff, yoff;
+ cairo_trapezoid_t *t;
+ int i;
+
+ /* Ugh. The cairo_composite/(Render) interface doesn't allow
+ an offset for the trapezoids. Need to manually shift all
+ the coordinates to align with the offset origin of the
+ intermediate surface. */
+
+ xoff = _cairo_fixed_from_int (x);
+ yoff = _cairo_fixed_from_int (y);
+
+ for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
+ t->top += yoff;
+ t->bottom += yoff;
+ t->left.p1.x += xoff;
+ t->left.p1.y += yoff;
+ t->left.p2.x += xoff;
+ t->left.p2.y += yoff;
+ t->right.p1.x += xoff;
+ t->right.p1.y += yoff;
+ t->right.p2.x += xoff;
+ t->right.p2.y += yoff;
+ }
}
@@ -1422,173 +1472,148 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
cairo_traps_t *traps)
{
cairo_status_t status;
- cairo_pattern_t pattern;
- cairo_box_t extents;
- int x_src, y_src;
+ cairo_pattern_union_t pattern;
+ cairo_rectangle_t extents;
+ cairo_box_t trap_extents;
if (traps->num_traps == 0)
return CAIRO_STATUS_SUCCESS;
+ if (gstate->surface == NULL)
+ return CAIRO_STATUS_NO_TARGET_SURFACE;
+
+ _cairo_traps_extents (traps, &trap_extents);
+ _cairo_box_round_to_rectangle (&trap_extents, &extents);
+
if (gstate->clip.surface) {
- cairo_fixed_t xoff, yoff;
- cairo_trapezoid_t *t;
- int i;
cairo_surface_t *intermediate;
+ cairo_surface_pattern_t intermediate_pattern;
cairo_color_t empty_color;
- pixman_box16_t *draw_extents;
- pixman_region16_t *draw_region;
- draw_region = pixman_region_create ();
- if (draw_region == NULL)
- {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL0;
- }
-
- _cairo_traps_extents (traps, &extents);
-
- status = _calculate_region_for_intermediate_clip_surface (draw_region,
- &extents,
- &gstate->clip);
- if (status)
- goto BAIL1;
+ _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
- /* Shortcut if empty */
- if (!pixman_region_not_empty (draw_region)) {
+ if (_cairo_rectangle_empty (&extents)) {
status = CAIRO_STATUS_SUCCESS;
goto BAIL1;
}
- draw_extents = pixman_region_extents (draw_region);
-
- /* Ugh. The cairo_composite/(Render) interface doesn't allow
- an offset for the trapezoids. Need to manually shift all
- the coordinates to align with the offset origin of the
- intermediate surface. */
- xoff = _cairo_fixed_from_int (draw_extents->x1);
- yoff = _cairo_fixed_from_int (draw_extents->y1);
- for (i=0, t=traps->traps; i < traps->num_traps; i++, t++) {
- t->top -= yoff;
- t->bottom -= yoff;
- t->left.p1.x -= xoff;
- t->left.p1.y -= yoff;
- t->left.p2.x -= xoff;
- t->left.p2.y -= yoff;
- t->right.p1.x -= xoff;
- t->right.p1.y -= yoff;
- t->right.p2.x -= xoff;
- t->right.p2.y -= yoff;
- }
-
- if (traps->traps[0].left.p1.y < traps->traps[0].left.p2.y) {
- x_src = _cairo_fixed_to_double (traps->traps[0].left.p1.x);
- y_src = _cairo_fixed_to_double (traps->traps[0].left.p1.y);
- } else {
- x_src = _cairo_fixed_to_double (traps->traps[0].left.p2.x);
- y_src = _cairo_fixed_to_double (traps->traps[0].left.p2.y);
- }
-
- _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0);
- _cairo_pattern_set_alpha (&pattern, 1.0);
-
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
- if (status)
- goto BAIL1;
+ translate_traps (traps, -extents.x, -extents.y);
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, 0.);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1,
+ extents.width,
+ extents.height,
&empty_color);
if (intermediate == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL2;
+ goto BAIL1;
}
+ _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
+
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
- pattern.source, intermediate,
- x_src,
- y_src,
+ &pattern.base,
+ intermediate,
+ extents.x, extents.y,
+ 0, 0,
+ extents.width,
+ extents.height,
traps->traps,
traps->num_traps);
+ _cairo_pattern_fini (&pattern.base);
+
if (status)
- goto BAIL3;
+ goto BAIL2;
+
+
+ _cairo_pattern_init_for_surface (&pattern.surface,
+ gstate->clip.surface);
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- gstate->clip.surface,
+ &pattern.base,
NULL,
intermediate,
- draw_extents->x1 - gstate->clip.x,
- draw_extents->y1 - gstate->clip.y,
+ extents.x - gstate->clip.rect.x,
+ extents.y - gstate->clip.rect.y,
0, 0,
0, 0,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
- if (status)
- goto BAIL3;
-
- _cairo_pattern_fini (&pattern);
+ extents.width, extents.height);
+ _cairo_pattern_fini (&pattern.base);
- _cairo_pattern_init_copy (&pattern, src);
-
- extents.p1.x = _cairo_fixed_from_int (draw_extents->x1);
- extents.p1.y = _cairo_fixed_from_int (draw_extents->y1);
- extents.p2.x = _cairo_fixed_from_int (draw_extents->x2);
- extents.p2.y = _cairo_fixed_from_int (draw_extents->y2);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
- goto BAIL3;
+ goto BAIL2;
- if (dst == gstate->clip.surface)
- xoff = yoff = 0;
+ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+ _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
status = _cairo_surface_composite (operator,
- pattern.source, intermediate, dst,
- 0, 0,
+ &pattern.base,
+ &intermediate_pattern.base,
+ dst,
+ extents.x, extents.y,
0, 0,
- xoff >> 16,
- yoff >> 16,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
+ extents.x, extents.y,
+ extents.width, extents.height);
+ _cairo_pattern_fini (&pattern.base);
+ _cairo_pattern_fini (&intermediate_pattern.base);
- BAIL3:
- cairo_surface_destroy (intermediate);
BAIL2:
- _cairo_pattern_fini (&pattern);
+ cairo_surface_destroy (intermediate);
BAIL1:
- pixman_region_destroy (draw_region);
- BAIL0:
if (status)
return status;
} else {
- if (traps->traps[0].left.p1.y < traps->traps[0].left.p2.y) {
- x_src = _cairo_fixed_to_double (traps->traps[0].left.p1.x);
- y_src = _cairo_fixed_to_double (traps->traps[0].left.p1.y);
- } else {
- x_src = _cairo_fixed_to_double (traps->traps[0].left.p2.x);
- y_src = _cairo_fixed_to_double (traps->traps[0].left.p2.y);
+ if (gstate->clip.region) {
+ pixman_box16_t box;
+ pixman_box16_t *intersection_extents;
+ pixman_region16_t *rect, *intersection;
+
+ box.x1 = _cairo_fixed_integer_floor (trap_extents.p1.x);
+ box.y1 = _cairo_fixed_integer_floor (trap_extents.p1.y);
+ box.x2 = _cairo_fixed_integer_ceil (trap_extents.p2.x);
+ box.y2 = _cairo_fixed_integer_ceil (trap_extents.p2.y);
+
+ rect = pixman_region_create_simple (&box);
+ if (rect == NULL)
+ goto bail1;
+ intersection = pixman_region_create();
+ if (intersection == NULL)
+ goto bail2;
+
+ if (pixman_region_intersect (intersection, gstate->clip.region,
+ rect) != PIXMAN_REGION_STATUS_SUCCESS)
+ goto bail3;
+ intersection_extents = pixman_region_extents (intersection);
+
+ extents.x = intersection_extents->x1;
+ extents.y = intersection_extents->y1;
+ extents.width = intersection_extents->x2 - intersection_extents->x1;
+ extents.height = intersection_extents->y2 - intersection_extents->y1;
+ bail3:
+ pixman_region_destroy (intersection);
+ bail2:
+ pixman_region_destroy (rect);
+ bail1:
+ ;
}
- _cairo_pattern_init_copy (&pattern, src);
+ _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
- _cairo_traps_extents (traps, &extents);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
- if (status)
- return status;
-
status = _cairo_surface_composite_trapezoids (gstate->operator,
- pattern.source, dst,
- x_src - pattern.source_offset.x,
- y_src - pattern.source_offset.y,
+ &pattern.base, dst,
+ extents.x, extents.y,
+ extents.x, extents.y,
+ extents.width,
+ extents.height,
traps->traps,
traps->num_traps);
- _cairo_pattern_fini (&pattern);
+ _cairo_pattern_fini (&pattern.base);
if (status)
return status;
@@ -1628,7 +1653,7 @@ cairo_status_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
double x,
double y,
- int *inside_ret)
+ cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;
@@ -1807,9 +1832,10 @@ cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate)
{
cairo_status_t status;
- cairo_pattern_t pattern;
+ cairo_pattern_union_t pattern;
cairo_traps_t traps;
cairo_color_t white_color;
+ cairo_box_t extents;
pixman_box16_t box;
/* Fill the clip region as traps. */
@@ -1871,33 +1897,32 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_color_init (&white_color);
if (gstate->clip.surface == NULL) {
- cairo_box_t extents;
-
_cairo_traps_extents (&traps, &extents);
- gstate->clip.x = extents.p1.x >> 16;
- gstate->clip.y = extents.p1.y >> 16;
- gstate->clip.width = ((extents.p2.x + 65535) >> 16) - gstate->clip.x;
- gstate->clip.height = ((extents.p2.y + 65535) >> 16) - gstate->clip.y;
+ _cairo_box_round_to_rectangle (&extents, &gstate->clip.rect);
gstate->clip.surface =
_cairo_surface_create_similar_solid (gstate->surface,
CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
+ gstate->clip.rect.width,
+ gstate->clip.rect.height,
&white_color);
if (gstate->clip.surface == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
- _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0);
- _cairo_pattern_set_alpha (&pattern, 1.0);
-
- _cairo_gstate_clip_and_composite_trapezoids (gstate,
- &pattern,
- CAIRO_OPERATOR_IN,
- gstate->clip.surface,
- &traps);
+ translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y);
+ _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
- _cairo_pattern_fini (&pattern);
+ status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
+ &pattern.base,
+ gstate->clip.surface,
+ 0, 0,
+ 0, 0,
+ gstate->clip.rect.width,
+ gstate->clip.rect.height,
+ traps.traps,
+ traps.num_traps);
+
+ _cairo_pattern_fini (&pattern.base);
_cairo_traps_fini (&traps);
@@ -1978,19 +2003,15 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
*
*/
- cairo_status_t status;
- cairo_matrix_t user_to_image, image_to_user;
- cairo_matrix_t image_to_device, device_to_image;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_matrix_t image_to_user, image_to_device;
double device_x, device_y;
double device_width, device_height;
- cairo_pattern_t pattern;
+ cairo_surface_pattern_t pattern;
cairo_box_t pattern_extents;
+ cairo_rectangle_t extents;
- cairo_surface_get_matrix (surface, &user_to_image);
- cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image);
- cairo_surface_set_matrix (surface, &device_to_image);
-
- image_to_user = user_to_image;
+ cairo_surface_get_matrix (surface, &image_to_user);
cairo_matrix_invert (&image_to_user);
cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm);
@@ -2001,126 +2022,82 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
&device_x, &device_y,
&device_width, &device_height);
- _cairo_pattern_init (&pattern);
+ _cairo_pattern_init_for_surface (&pattern, surface);
+
+ /* inherit surface attributes while surface attribute functions still
+ exist */
+ pattern.base.matrix = surface->matrix;
+ pattern.base.filter = surface->filter;
+ if (surface->repeat)
+ pattern.base.extend = CAIRO_EXTEND_REPEAT;
+ else
+ pattern.base.extend = CAIRO_EXTEND_NONE;
+
+ _cairo_pattern_transform (&pattern.base, &gstate->ctm_inverse);
+ _cairo_pattern_set_alpha (&pattern.base, gstate->alpha);
pattern_extents.p1.x = _cairo_fixed_from_double (device_x);
pattern_extents.p1.y = _cairo_fixed_from_double (device_y);
pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
-
- if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) ||
- (gstate->alpha != 1.0)) {
- /* I'm allowing any type of pattern for the mask right now.
- Maybe this is bad. Will allow for some cool effects though. */
- _cairo_pattern_init_copy (&pattern, gstate->pattern);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &pattern_extents);
- if (status)
- return status;
- }
-
+ _cairo_box_round_to_rectangle (&pattern_extents, &extents);
+
if (gstate->clip.surface)
{
- cairo_surface_t *intermediate;
- cairo_color_t empty_color;
- pixman_box16_t *draw_extents;
- pixman_region16_t *draw_region;
-
- draw_region = pixman_region_create ();
- if (draw_region == NULL)
- {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL0;
+ _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
+
+ /* We only need to composite if the rectangle is not empty. */
+ if (!_cairo_rectangle_empty (&extents)) {
+ cairo_surface_pattern_t clip_pattern;
+
+ _cairo_pattern_init_for_surface (&clip_pattern,
+ gstate->clip.surface);
+
+ status = _cairo_surface_composite (gstate->operator,
+ &pattern.base,
+ &clip_pattern.base,
+ gstate->surface,
+ extents.x, extents.y,
+ 0, 0,
+ extents.x, extents.y,
+ extents.width, extents.height);
+
+ _cairo_pattern_fini (&clip_pattern.base);
}
-
- status = _calculate_region_for_intermediate_clip_surface (draw_region,
- &pattern_extents,
- &gstate->clip);
- if (status)
- goto BAIL1;
-
- /* Shortcut if empty */
- if (!pixman_region_not_empty (draw_region)) {
- status = CAIRO_STATUS_SUCCESS;
- goto BAIL1;
- }
-
- draw_extents = pixman_region_extents (draw_region);
-
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, .0);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_FORMAT_A8,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1,
- &empty_color);
-
- /* it is not completely clear what the "right" way to combine the
- pattern and mask surface is. I will use the the clip as a source
- and the pattern as a mask in building up my temporary, because
- this is not *totally* bogus and accomodates the case where
- pattern's source image is NULL reasonably well. feel free to
- correct this if you see a reason. */
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_SRC,
- gstate->clip.surface,
- pattern.source,
- intermediate,
- draw_extents->x1 - gstate->clip.x,
- draw_extents->y1 - gstate->clip.y,
- 0, 0,
- 0, 0,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
-
-
- if (status)
- goto BAIL2;
-
- status = _cairo_surface_composite (gstate->operator,
- surface,
- intermediate,
- gstate->surface,
- draw_extents->x1, draw_extents->y1,
- 0, 0,
- draw_extents->x1, draw_extents->y1,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
-
- BAIL2:
- cairo_surface_destroy (intermediate);
- BAIL1:
- pixman_region_destroy (draw_region);
- BAIL0:
- ;
}
else
{
-
- /* XXX: The rendered size is sometimes 1 or 2 pixels short from
- what I expect. Need to fix this. */
+ /* XXX: The rendered size is sometimes 1 or 2 pixels short
+ * from what I expect. Need to fix this.
+ * KRH: I'm guessing this was due to rounding error when
+ * passing double coordinates for integer arguments. Using
+ * the extents rectangle should fix this, since it's properly
+ * rounded. Is this still the case?
+ */
status = _cairo_surface_composite (gstate->operator,
- surface,
- pattern.source,
+ &pattern.base,
+ NULL,
gstate->surface,
- device_x, device_y,
+ extents.x, extents.y,
0, 0,
- device_x, device_y,
- device_width,
- device_height);
+ extents.x, extents.y,
+ extents.width, extents.height);
}
- _cairo_pattern_fini (&pattern);
+ _cairo_pattern_fini (&pattern.base);
- /* restore the matrix originally in the surface */
- cairo_surface_set_matrix (surface, &user_to_image);
-
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
+static void
+_cairo_gstate_unset_font (cairo_gstate_t *gstate)
+{
+ if (gstate->font) {
+ cairo_font_destroy (gstate->font);
+ gstate->font = NULL;
+ }
+}
cairo_status_t
_cairo_gstate_select_font (cairo_gstate_t *gstate,
@@ -2128,12 +2105,17 @@ _cairo_gstate_select_font (cairo_gstate_t *gstate,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
- if (gstate->font)
- _cairo_unscaled_font_destroy (gstate->font);
+ char *new_family;
- gstate->font = _cairo_unscaled_font_create (family, slant, weight);
- if (gstate->font == NULL)
+ new_family = strdup (family);
+ if (!new_family)
return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_gstate_unset_font (gstate);
+
+ gstate->font_family = new_family;
+ gstate->font_slant = slant;
+ gstate->font_weight = weight;
cairo_matrix_set_identity (&gstate->font_matrix);
@@ -2144,6 +2126,8 @@ cairo_status_t
_cairo_gstate_scale_font (cairo_gstate_t *gstate,
double scale)
{
+ _cairo_gstate_unset_font (gstate);
+
return cairo_matrix_scale (&gstate->font_matrix, scale, scale);
}
@@ -2153,6 +2137,9 @@ _cairo_gstate_transform_font (cairo_gstate_t *gstate,
{
cairo_matrix_t tmp;
double a, b, c, d, tx, ty;
+
+ _cairo_gstate_unset_font (gstate);
+
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);
@@ -2160,28 +2147,16 @@ _cairo_gstate_transform_font (cairo_gstate_t *gstate,
cairo_status_t
-_cairo_gstate_current_font (cairo_gstate_t *gstate,
- cairo_font_t **font)
+_cairo_gstate_current_font (cairo_gstate_t *gstate,
+ cairo_font_t **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);
+ cairo_status_t status;
- *font = scaled;
+ status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
+
+ *font = gstate->font;
return CAIRO_STATUS_SUCCESS;
}
@@ -2190,6 +2165,8 @@ void
_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
cairo_matrix_t *matrix)
{
+ _cairo_gstate_unset_font (gstate);
+
cairo_matrix_copy (&gstate->font_matrix, matrix);
}
@@ -2214,12 +2191,10 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
* 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 only font type exposed to the user is cairo_font_t which is a
+ * a font specialized to a particular scale matrix, CTM, and target
+ * surface. The user is responsible for not using a cairo_font_t
+ * after changing the parameters; doing so will produce garbled metrics.
*
*
* The font's view
@@ -2279,9 +2254,9 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
*
*/
-static void
-_build_font_scale (cairo_gstate_t *gstate,
- cairo_font_scale_t *sc)
+void
+_cairo_gstate_current_font_scale (cairo_gstate_t *gstate,
+ cairo_font_scale_t *sc)
{
cairo_matrix_t tmp;
double dummy;
@@ -2294,34 +2269,46 @@ _build_font_scale (cairo_gstate_t *gstate,
&dummy, &dummy);
}
-cairo_status_t
-_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
- cairo_font_extents_t *extents)
+static cairo_status_t
+_cairo_gstate_ensure_font (cairo_gstate_t *gstate)
{
- cairo_int_status_t status;
cairo_font_scale_t sc;
- double font_scale_x, font_scale_y;
+ cairo_status_t status;
+ const char *family;
+
+ if (gstate->font)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_gstate_current_font_scale (gstate, &sc);
- _build_font_scale (gstate, &sc);
+ if (gstate->font_family)
+ family = gstate->font_family;
+ else
+ family = CAIRO_FONT_FAMILY_DEFAULT;
+
+ status = _cairo_font_create (family,
+ gstate->font_slant,
+ gstate->font_weight,
+ &sc,
+ &gstate->font);
- status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents);
+ if (status)
+ return status;
- _cairo_matrix_compute_scale_factors (&gstate->font_matrix,
- &font_scale_x, &font_scale_y,
- /* XXX */ 1);
-
- /*
- * The font responded in unscaled units, scale by the font
- * matrix scale factors to get to user space
- */
-
- extents->ascent *= font_scale_y;
- extents->descent *= font_scale_y;
- extents->height *= font_scale_y;
- extents->max_x_advance *= font_scale_x;
- extents->max_y_advance *= font_scale_y;
-
- return status;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
+ cairo_font_extents_t *extents)
+{
+ cairo_status_t status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
+
+ return cairo_font_extents (gstate->font,
+ &gstate->font_matrix,
+ extents);
}
cairo_status_t
@@ -2331,14 +2318,15 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
int *nglyphs)
{
cairo_status_t status;
- cairo_font_scale_t sc;
cairo_point_t point;
double origin_x, origin_y;
int i;
- _build_font_scale (gstate, &sc);
-
+ status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
+
status = _cairo_path_current_point (&gstate->path, &point);
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
origin_x = 0.0;
@@ -2350,8 +2338,8 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
&origin_x, &origin_y);
}
- status = _cairo_unscaled_font_text_to_glyphs (gstate->font,
- &sc, utf8, glyphs, nglyphs);
+ status = _cairo_font_text_to_glyphs (gstate->font,
+ utf8, glyphs, nglyphs);
if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
return status;
@@ -2373,18 +2361,16 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
cairo_status_t
_cairo_gstate_set_font (cairo_gstate_t *gstate,
- cairo_font_t *font)
-{
- if (gstate->font != NULL)
- _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);
+ cairo_font_t *font)
+{
+ if (font != gstate->font) {
+ if (gstate->font)
+ cairo_font_destroy (gstate->font);
+ gstate->font = font;
+ if (gstate->font)
+ cairo_font_reference (gstate->font);
+ }
+
return CAIRO_STATUS_SUCCESS;
}
@@ -2394,90 +2380,18 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
int num_glyphs,
cairo_text_extents_t *extents)
{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_glyph_t origin_glyph;
- cairo_text_extents_t origin_extents;
- cairo_font_scale_t sc;
- int i;
- double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
- double x_pos = 0.0, y_pos = 0.0;
- int set = 0;
-
- if (!num_glyphs)
- {
- extents->x_bearing = 0.0;
- extents->y_bearing = 0.0;
- extents->width = 0.0;
- extents->height = 0.0;
- extents->x_advance = 0.0;
- extents->y_advance = 0.0;
- return CAIRO_STATUS_SUCCESS;
- }
-
- _build_font_scale (gstate, &sc);
-
- for (i = 0; i < num_glyphs; i++)
- {
- double x, y;
- double wm, hm;
-
- origin_glyph = glyphs[i];
- origin_glyph.x = 0.0;
- origin_glyph.y = 0.0;
- status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc,
- &origin_glyph, 1,
- &origin_extents);
-
- /*
- * Transform font space metrics into user space metrics
- * by running the corners through the font matrix and
- * expanding the bounding box as necessary
- */
- x = origin_extents.x_bearing;
- y = origin_extents.y_bearing;
- cairo_matrix_transform_point (&gstate->font_matrix,
- &x, &y);
-
- for (hm = 0.0; hm <= 1.0; hm += 1.0)
- for (wm = 0.0; wm <= 1.0; wm += 1.0)
- {
- x = origin_extents.x_bearing + origin_extents.width * wm;
- y = origin_extents.y_bearing + origin_extents.height * hm;
- cairo_matrix_transform_point (&gstate->font_matrix,
- &x, &y);
- x += glyphs[i].x;
- y += glyphs[i].y;
- if (!set)
- {
- min_x = max_x = x;
- min_y = max_y = y;
- set = 1;
- }
- else
- {
- if (x < min_x) min_x = x;
- if (x > max_x) max_x = x;
- if (y < min_y) min_y = y;
- if (y > max_y) max_y = y;
- }
- }
+ cairo_status_t status;
- x = origin_extents.x_advance;
- y = origin_extents.y_advance;
- cairo_matrix_transform_point (&gstate->font_matrix,
- &x, &y);
- x_pos = glyphs[i].x + x;
- y_pos = glyphs[i].y + y;
- }
+ status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
- extents->x_bearing = min_x - glyphs[0].x;
- extents->y_bearing = min_y - glyphs[0].y;
- extents->width = max_x - min_x;
- extents->height = max_y - min_y;
- extents->x_advance = x_pos - glyphs[0].x;
- extents->y_advance = y_pos - glyphs[0].y;
+ cairo_font_glyph_extents (gstate->font,
+ &gstate->font_matrix,
+ glyphs, num_glyphs,
+ extents);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@@ -2488,12 +2402,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_status_t status;
int i;
cairo_glyph_t *transformed_glyphs = NULL;
- cairo_font_scale_t sc;
- cairo_pattern_t pattern;
+ cairo_pattern_union_t pattern;
cairo_box_t bbox;
+ cairo_rectangle_t extents;
- _build_font_scale (gstate, &sc);
-
+ status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
+
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
if (transformed_glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY;
@@ -2506,52 +2422,34 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
&transformed_glyphs[i].y);
}
- _cairo_pattern_init_copy (&pattern, gstate->pattern);
- status = _cairo_unscaled_font_glyph_bbox (gstate->font, &sc,
- transformed_glyphs, num_glyphs,
- &bbox);
- if (status)
- goto CLEANUP_GLYPHS;
+ status = _cairo_font_glyph_bbox (gstate->font,
+ transformed_glyphs, num_glyphs,
+ &bbox);
+ _cairo_box_round_to_rectangle (&bbox, &extents);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
if (status)
goto CLEANUP_GLYPHS;
-
+
if (gstate->clip.surface)
{
cairo_surface_t *intermediate;
+ cairo_surface_pattern_t intermediate_pattern;
cairo_color_t empty_color;
- pixman_box16_t *draw_extents;
- pixman_region16_t *draw_region;
-
- draw_region = pixman_region_create ();
- if (draw_region == NULL)
- {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL0;
- }
- status = _calculate_region_for_intermediate_clip_surface (draw_region,
- &bbox,
- &gstate->clip);
- if (status) {
- goto BAIL1;
- }
+ _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
/* Shortcut if empty */
- if (!pixman_region_not_empty (draw_region)) {
+ if (_cairo_rectangle_empty (&extents)) {
status = CAIRO_STATUS_SUCCESS;
goto BAIL1;
}
- draw_extents = pixman_region_extents (draw_region);
-
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, .0);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1,
+ extents.width,
+ extents.height,
&empty_color);
if (intermediate == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
@@ -2561,66 +2459,77 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
/* move the glyphs again, from dev space to intermediate space */
for (i = 0; i < num_glyphs; ++i)
{
- transformed_glyphs[i].x -= draw_extents->x1;
- transformed_glyphs[i].y -= draw_extents->y1;
+ transformed_glyphs[i].x -= extents.x;
+ transformed_glyphs[i].y -= extents.y;
}
- status = _cairo_unscaled_font_show_glyphs (gstate->font,
- &sc,
- CAIRO_OPERATOR_ADD,
- pattern.source, intermediate,
- draw_extents->x1 - pattern.source_offset.x,
- draw_extents->y1 - pattern.source_offset.y,
- transformed_glyphs, num_glyphs);
+ _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
+
+ status = _cairo_font_show_glyphs (gstate->font,
+ CAIRO_OPERATOR_ADD,
+ &pattern.base, intermediate,
+ extents.x, extents.y,
+ 0, 0,
+ extents.width, extents.height,
+ transformed_glyphs, num_glyphs);
+
+ _cairo_pattern_fini (&pattern.base);
if (status)
goto BAIL2;
+ _cairo_pattern_init_for_surface (&pattern.surface,
+ gstate->clip.surface);
+
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- gstate->clip.surface,
+ &pattern.base,
NULL,
intermediate,
- draw_extents->x1 - gstate->clip.x,
- draw_extents->y1 - gstate->clip.y,
+ extents.x - gstate->clip.rect.x,
+ extents.y - gstate->clip.rect.y,
0, 0,
0, 0,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
+ extents.width, extents.height);
+
+ _cairo_pattern_fini (&pattern.base);
if (status)
goto BAIL2;
+ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+ _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
+
status = _cairo_surface_composite (gstate->operator,
- pattern.source,
- intermediate,
+ &pattern.base,
+ &intermediate_pattern.base,
gstate->surface,
- 0, 0,
+ extents.x, extents.y,
0, 0,
- draw_extents->x1,
- draw_extents->y1,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
+ extents.x, extents.y,
+ extents.width, extents.height);
+ _cairo_pattern_fini (&pattern.base);
+ _cairo_pattern_fini (&intermediate_pattern.base);
BAIL2:
cairo_surface_destroy (intermediate);
BAIL1:
- pixman_region_destroy (draw_region);
- BAIL0:
;
}
else
{
- 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_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
+
+ status = _cairo_font_show_glyphs (gstate->font,
+ gstate->operator, &pattern.base,
+ gstate->surface,
+ extents.x, extents.y,
+ extents.x, extents.y,
+ extents.width, extents.height,
+ transformed_glyphs, num_glyphs);
+
+ _cairo_pattern_fini (&pattern.base);
}
- _cairo_pattern_fini (&pattern);
-
CLEANUP_GLYPHS:
free (transformed_glyphs);
@@ -2635,9 +2544,6 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
cairo_status_t status;
int i;
cairo_glyph_t *transformed_glyphs = NULL;
- cairo_font_scale_t sc;
-
- _build_font_scale (gstate, &sc);
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
if (transformed_glyphs == NULL)
@@ -2651,9 +2557,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
&(transformed_glyphs[i].y));
}
- status = _cairo_unscaled_font_glyph_path (gstate->font, &sc,
- transformed_glyphs, num_glyphs,
- &gstate->path);
+ status = _cairo_font_glyph_path (gstate->font,
+ transformed_glyphs, num_glyphs,
+ &gstate->path);
free (transformed_glyphs);
return status;
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index b097b609b..d1ad5a4e2 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -94,9 +94,9 @@ static const cairo_cache_arrangement_t cache_arrangements [] = {
* 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.
+ * cache will expire entries randomly as it experiences memory pressure.
+ * If max_memory is set, entries are not expired, and must be explicitely
+ * removed.
*
* 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
@@ -282,17 +282,51 @@ _load_factor (cairo_cache_t *cache)
}
#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;
-}
+/* Find a random in the cache matching the given predicate. We use the
+ * same algorithm as the probing algorithm to walk over the entries in
+ * the hash table in a pseudo-random order. Walking linearly would
+ * favor entries following gaps in the hash table. We could also
+ * call rand() repeatedly, which works well for almost-full tables,
+ * but degrades when the table is almost empty, or predicate
+ * returns false for most entries.
+ */
+static cairo_cache_entry_base_t **
+_random_entry (cairo_cache_t *cache,
+ int (*predicate)(void*))
+{
+ cairo_cache_entry_base_t **probe;
+ unsigned long hash;
+ unsigned long table_size, i, idx, step;
+
+ _cache_sane_state (cache);
+
+ table_size = cache->arrangement->size;
+ hash = rand ();
+ idx = hash % table_size;
+ step = 0;
+
+ for (i = 0; i < table_size; ++i)
+ {
+ assert(idx < table_size);
+ probe = cache->entries + idx;
+ if (LIVE_ENTRY_P(cache, idx)
+ && (!predicate || predicate (*probe)))
+ return probe;
+
+ if (step == 0) {
+ step = hash % cache->arrangement->rehash;
+ if (step == 0)
+ step = 1;
+ }
+
+ idx += step;
+ if (idx >= table_size)
+ idx -= table_size;
+ }
+
+ return NULL;
+}
/* public API follows */
@@ -356,8 +390,9 @@ _cairo_cache_destroy (cairo_cache_t *cache)
cairo_status_t
_cairo_cache_lookup (cairo_cache_t *cache,
- void *key,
- void **entry_return)
+ void *key,
+ void **entry_return,
+ int *created_entry)
{
unsigned long idx;
@@ -392,6 +427,8 @@ _cairo_cache_lookup (cairo_cache_t *cache,
cache->hits++;
#endif
*entry_return = *slot;
+ if (created_entry)
+ *created_entry = 0;
return status;
}
@@ -401,19 +438,18 @@ _cairo_cache_lookup (cairo_cache_t *cache,
/* Build the new entry. */
status = cache->backend->create_entry (cache, key,
- entry_return);
+ (void **)&new_entry);
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 > 0 &&
((cache->max_memory - cache->used_memory) < new_entry->memory)) {
- idx = _random_live_entry (cache);
+ idx = _random_entry (cache, NULL) - cache->entries;
assert (idx < cache->arrangement->size);
_entry_destroy (cache, idx);
}
@@ -425,7 +461,6 @@ _cairo_cache_lookup (cairo_cache_t *cache,
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;
}
@@ -439,9 +474,38 @@ _cairo_cache_lookup (cairo_cache_t *cache,
_cache_sane_state (cache);
+ *entry_return = new_entry;
+ if (created_entry)
+ *created_entry = 1;
+
return status;
}
+cairo_status_t
+_cairo_cache_remove (cairo_cache_t *cache,
+ void *key)
+{
+ cairo_cache_entry_base_t **slot;
+
+ _cache_sane_state (cache);
+
+ /* See if we have an entry in the table already. */
+ slot = _find_exact_live_entry_for (cache, key);
+ if (slot != NULL)
+ _entry_destroy (cache, slot - cache->entries);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void *
+_cairo_cache_random_entry (cairo_cache_t *cache,
+ int (*predicate)(void*))
+{
+ cairo_cache_entry_base_t **slot = _random_entry (cache, predicate);
+
+ return slot ? *slot : NULL;
+}
+
unsigned long
_cairo_hash_string (const char *c)
{
diff --git a/src/cairo-hull.c b/src/cairo-hull.c
index 99b16d1ae..c93d70625 100644
--- a/src/cairo-hull.c
+++ b/src/cairo-hull.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 14e30f695..9745b3150 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
@@ -54,7 +54,8 @@ _cairo_format_bpp (cairo_format_t format)
}
static cairo_image_surface_t *
-_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image)
+_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
+ cairo_format_t format)
{
cairo_image_surface_t *surface;
@@ -66,6 +67,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image)
surface->pixman_image = pixman_image;
+ surface->format = format;
surface->data = (char *) pixman_image_get_data (pixman_image);
surface->owns_data = 0;
@@ -105,7 +107,8 @@ _cairo_image_surface_create_with_masks (char *data,
if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
+ (cairo_format_t)-1);
return surface;
}
@@ -130,6 +133,20 @@ _create_pixman_format (cairo_format_t format)
}
}
+/**
+ * cairo_image_surface_create:
+ * @format: format of pixels in the surface to create
+ * @width: width of the surface, in pixels
+ * @height: height of the surface, in pixels
+ *
+ * Creates an image surface of the specified format and
+ * dimensions. The initial contents of the surface is undefined; you
+ * must explicitely clear the buffer, using, for example,
+ * cairo_rectangle() and cairo_fill() if you want it cleared.
+ *
+ * Return value: the newly created surface, or %NULL if it couldn't
+ * be created because of lack of memory
+ **/
cairo_surface_t *
cairo_image_surface_create (cairo_format_t format,
int width,
@@ -150,11 +167,33 @@ cairo_image_surface_create (cairo_format_t format,
if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
return &surface->base;
}
+/**
+ * cairo_image_surface_create_for_data:
+ * @data: a pointer to a buffer supplied by the application
+ * in which to write contents.
+ * @format: the format of pixels in the buffer
+ * @width: the width of the image to be stored in the buffer
+ * @height: the height of the image to be stored in the buffer
+ * @stride: the number of bytes between the start of rows
+ * in the buffer. Having this be specified separate from @width
+ * allows for padding at the end of rows, or for writing
+ * to a subportion of a larger image.
+ *
+ * Creates an image surface for the provided pixel data. The output
+ * buffer must be kept around until the #cairo_surface_t is destroyed
+ * or cairo_surface_finish() is called on the surface. The initial
+ * contents of @buffer will be used as the inital image contents; you
+ * must explicitely clear the buffer, using, for example,
+ * cairo_rectangle() and cairo_fill() if you want it cleared.
+ *
+ * Return value: the newly created surface, or %NULL if it couldn't
+ * be created because of lack of memory
+ **/
cairo_surface_t *
cairo_image_surface_create_for_data (char *data,
cairo_format_t format,
@@ -180,7 +219,7 @@ cairo_image_surface_create_for_data (char *data,
if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
return &surface->base;
}
@@ -224,33 +263,66 @@ _cairo_image_surface_pixels_per_inch (void *abstract_surface)
return 96.0;
}
-static cairo_image_surface_t *
-_cairo_image_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_cairo_image_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
- cairo_image_surface_t *surface = abstract_surface;
-
- cairo_surface_reference (&surface->base);
+ *image_out = abstract_surface;
+
+ return CAIRO_STATUS_SUCCESS;
+}
- return surface;
+static void
+_cairo_image_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
}
static cairo_status_t
-_cairo_image_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+_cairo_image_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect_out,
+ void **image_extra)
{
- if (image == abstract_surface)
- return CAIRO_STATUS_SUCCESS;
+ cairo_image_surface_t *surface = abstract_surface;
+
+ image_rect_out->x = 0;
+ image_rect_out->y = 0;
+ image_rect_out->width = surface->width;
+ image_rect_out->height = surface->height;
+
+ *image_out = surface;
- /* XXX: This case has not yet been implemented. We'll lie for now. */
return CAIRO_STATUS_SUCCESS;
}
+static void
+_cairo_image_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+}
+
static cairo_status_t
-_cairo_image_abstract_surface_set_matrix (void *abstract_surface,
- cairo_matrix_t *matrix)
+_cairo_image_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
cairo_image_surface_t *surface = abstract_surface;
- return _cairo_image_surface_set_matrix (surface, matrix);
+
+ if (src->backend == surface->base.backend) {
+ *clone_out = src;
+ cairo_surface_reference (src);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
cairo_status_t
@@ -276,14 +348,6 @@ _cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_image_abstract_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_filter (surface, filter);
-}
-
cairo_status_t
_cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter)
{
@@ -314,13 +378,6 @@ _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_image_abstract_surface_set_repeat (void *abstract_surface, int repeat)
-{
- cairo_image_surface_t *surface = abstract_surface;
- return _cairo_image_surface_set_repeat (surface, repeat);
-}
-
cairo_status_t
_cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat)
{
@@ -329,6 +386,34 @@ _cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat)
return CAIRO_STATUS_SUCCESS;
}
+static cairo_int_status_t
+_cairo_image_surface_set_attributes (cairo_image_surface_t *surface,
+ cairo_surface_attributes_t *attributes)
+{
+ cairo_int_status_t status;
+
+ status = _cairo_image_surface_set_matrix (surface, &attributes->matrix);
+ if (status)
+ return status;
+
+ switch (attributes->extend) {
+ case CAIRO_EXTEND_NONE:
+ _cairo_image_surface_set_repeat (surface, 0);
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ _cairo_image_surface_set_repeat (surface, 1);
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ /* XXX: Obviously wrong. */
+ _cairo_image_surface_set_repeat (surface, 1);
+ break;
+ }
+
+ status = _cairo_image_surface_set_filter (surface, attributes->filter);
+
+ return status;
+}
+
static pixman_operator_t
_pixman_operator (cairo_operator_t operator)
{
@@ -368,8 +453,8 @@ _pixman_operator (cairo_operator_t operator)
static cairo_int_status_t
_cairo_image_surface_composite (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
+ cairo_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
void *abstract_dst,
int src_x,
int src_y,
@@ -380,26 +465,61 @@ _cairo_image_surface_composite (cairo_operator_t operator,
unsigned int width,
unsigned int height)
{
- cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_t *src = (cairo_image_surface_t *) generic_src;
- cairo_image_surface_t *mask = (cairo_image_surface_t *) generic_mask;
-
- if (generic_src->backend != dst->base.backend ||
- (generic_mask && (generic_mask->backend != dst->base.backend)))
+ cairo_surface_attributes_t src_attr, mask_attr;
+ cairo_image_surface_t *dst = abstract_dst;
+ cairo_image_surface_t *src;
+ cairo_image_surface_t *mask;
+ cairo_int_status_t status;
+
+ status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
+ &dst->base,
+ src_x, src_y,
+ mask_x, mask_y,
+ width, height,
+ (cairo_surface_t **) &src,
+ (cairo_surface_t **) &mask,
+ &src_attr, &mask_attr);
+ if (status)
+ return status;
+
+ status = _cairo_image_surface_set_attributes (src, &src_attr);
+ if (CAIRO_OK (status))
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (mask)
+ {
+ status = _cairo_image_surface_set_attributes (mask, &mask_attr);
+ if (CAIRO_OK (status))
+ pixman_composite (_pixman_operator (operator),
+ src->pixman_image,
+ mask->pixman_image,
+ dst->pixman_image,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ mask_x + mask_attr.x_offset,
+ mask_y + mask_attr.y_offset,
+ dst_x, dst_y,
+ width, height);
+ }
+ else
+ {
+ pixman_composite (_pixman_operator (operator),
+ src->pixman_image,
+ NULL,
+ dst->pixman_image,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ }
}
- pixman_composite (_pixman_operator (operator),
- src->pixman_image,
- mask ? mask->pixman_image : NULL,
- dst->pixman_image,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
-
- return CAIRO_STATUS_SUCCESS;
+ if (mask)
+ _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
+
+ _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
+
+ return status;
}
static cairo_int_status_t
@@ -427,24 +547,56 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
static cairo_int_status_t
_cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *generic_src,
+ cairo_pattern_t *pattern,
void *abstract_dst,
- int x_src,
- int y_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
- cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_t *src = (cairo_image_surface_t *) generic_src;
+ cairo_surface_attributes_t attributes;
+ cairo_image_surface_t *dst = abstract_dst;
+ cairo_image_surface_t *src;
+ cairo_int_status_t status;
+ int render_reference_x, render_reference_y;
+ int render_src_x, render_src_y;
+
+ status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ src_x, src_y, width, height,
+ (cairo_surface_t **) &src,
+ &attributes);
+ if (status)
+ return status;
+
+ if (traps[0].left.p1.y < traps[0].left.p2.y) {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
+ } else {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
+ }
- if (generic_src->backend != dst->base.backend)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ render_src_x = src_x + render_reference_x - dst_x;
+ render_src_y = src_y + render_reference_y - dst_y;
- /* XXX: The pixman_trapezoid_t cast is evil and needs to go away somehow. */
- pixman_composite_trapezoids (operator, src->pixman_image, dst->pixman_image,
- x_src, y_src, (pixman_trapezoid_t *) traps, num_traps);
+ /* XXX: The pixman_trapezoid_t cast is evil and needs to go away
+ * somehow. */
+ status = _cairo_image_surface_set_attributes (src, &attributes);
+ if (CAIRO_OK (status))
+ pixman_composite_trapezoids (operator,
+ src->pixman_image,
+ dst->pixman_image,
+ render_src_x + attributes.x_offset,
+ render_src_y + attributes.y_offset,
+ (pixman_trapezoid_t *) traps, num_traps);
- return CAIRO_STATUS_SUCCESS;
+ _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
+
+ return status;
}
static cairo_int_status_t
@@ -490,41 +642,34 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_image_abstract_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *box)
+/**
+ * _cairo_surface_is_image:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is an #cairo_image_surface_t
+ *
+ * Return value: True if the surface is an image surface
+ **/
+int
+_cairo_surface_is_image (cairo_surface_t *surface)
{
- cairo_image_surface_t *image;
-
- /* Fall back to general pattern creation for surface patterns. */
- if (pattern->type == CAIRO_PATTERN_SURFACE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- image = _cairo_pattern_get_image (pattern, box);
- if (image) {
- pattern->source = &image->base;
-
- return CAIRO_STATUS_SUCCESS;
- } else
- return CAIRO_STATUS_NO_MEMORY;
+ return surface->backend == &cairo_image_surface_backend;
}
-
+
static const cairo_surface_backend_t cairo_image_surface_backend = {
_cairo_image_surface_create_similar,
_cairo_image_abstract_surface_destroy,
_cairo_image_surface_pixels_per_inch,
- _cairo_image_surface_get_image,
- _cairo_image_surface_set_image,
- _cairo_image_abstract_surface_set_matrix,
- _cairo_image_abstract_surface_set_filter,
- _cairo_image_abstract_surface_set_repeat,
+ _cairo_image_surface_acquire_source_image,
+ _cairo_image_surface_release_source_image,
+ _cairo_image_surface_acquire_dest_image,
+ _cairo_image_surface_release_dest_image,
+ _cairo_image_surface_clone_similar,
_cairo_image_surface_composite,
_cairo_image_surface_fill_rectangles,
_cairo_image_surface_composite_trapezoids,
_cairo_image_surface_copy_page,
_cairo_image_surface_show_page,
_cairo_image_abstract_surface_set_clip_region,
- _cairo_image_abstract_surface_create_pattern,
NULL /* show_glyphs */
};
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index b964b688c..88e536e8a 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#define _GNU_SOURCE
@@ -54,6 +54,14 @@ _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
+/**
+ * cairo_matrix_create:
+ *
+ * Creates a new identity matrix.
+ *
+ * Return value: a newly created matrix; free with cairo_matrix_destroy(),
+ * or %NULL if memory couldn't be allocated.
+ **/
cairo_matrix_t *
cairo_matrix_create (void)
{
@@ -80,6 +88,12 @@ _cairo_matrix_fini (cairo_matrix_t *matrix)
/* nothing to do here */
}
+/**
+ * cairo_matrix_destroy:
+ * @matrix: a #cairo_matrix_t
+ *
+ * Frees a matrix created with cairo_matrix_create.
+ **/
void
cairo_matrix_destroy (cairo_matrix_t *matrix)
{
@@ -87,6 +101,15 @@ cairo_matrix_destroy (cairo_matrix_t *matrix)
free (matrix);
}
+/**
+ * cairo_matrix_copy:
+ * @matrix: a #cairo_matrix_t
+ * @other: another #cairo_
+ *
+ * Modifies @matrix to be identical to @other.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
{
@@ -96,6 +119,14 @@ cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
}
slim_hidden_def(cairo_matrix_copy);
+/**
+ * cairo_matrix_set_identity:
+ * @matrix: a #cairo_matrix_t
+ *
+ * Modifies @matrix to be an identity transformation.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_set_identity (cairo_matrix_t *matrix)
{
@@ -105,6 +136,26 @@ cairo_matrix_set_identity (cairo_matrix_t *matrix)
}
slim_hidden_def(cairo_matrix_set_identity);
+/**
+ * cairo_matrix_set_affine:
+ * @matrix: a cairo_matrix_t
+ * @a: a component of the affine transformation
+ * @b: b component of the affine transformation
+ * @c: c component of the affine transformation
+ * @d: d component of the affine transformation
+ * @tx: X translation component of the affine transformation
+ * @ty: Y translation component of the affine transformation
+ *
+ * Sets @matrix to be the affine transformation given by
+ * @a, b, @c, @d, @tx, @ty. The transformation is given
+ * by:
+ * <programlisting>
+ * x_new = x * a + y * c + tx;
+ * y_new = x * b + y * d + ty;
+ * </programlisting>
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_set_affine (cairo_matrix_t *matrix,
double a, double b,
@@ -119,6 +170,21 @@ cairo_matrix_set_affine (cairo_matrix_t *matrix,
}
slim_hidden_def(cairo_matrix_set_affine);
+/**
+ * cairo_matrix_get_affine:
+ * @matrix: a @cairo_matrix_t
+ * @a: location to store a component of affine transformation, or %NULL
+ * @b: location to store b component of affine transformation, or %NULL
+ * @c: location to store c component of affine transformation, or %NULL
+ * @d: location to store d component of affine transformation, or %NULL
+ * @tx: location to store X-translation component of affine transformation, or %NULL
+ * @ty: location to store Y-translation component of affine transformation, or %NULL
+ *
+ * Gets the matrix values for the affine tranformation that @matrix represents.
+ * See cairo_matrix_set_affine().
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_get_affine (cairo_matrix_t *matrix,
double *a, double *b,
@@ -153,6 +219,18 @@ _cairo_matrix_set_translate (cairo_matrix_t *matrix,
tx, ty);
}
+/**
+ * cairo_matrix_translate:
+ * @matrix: a cairo_matrix_t
+ * @tx: amount to rotate in the X direction
+ * @ty: amount to rotate in the Y direction
+ *
+ * Applies a translation by @tx, @ty to the transformation in
+ * @matrix. The new transformation is given by first translating by
+ * @tx, @ty then applying the original transformation
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
{
@@ -173,6 +251,18 @@ _cairo_matrix_set_scale (cairo_matrix_t *matrix,
0, 0);
}
+/**
+ * cairo_matrix_scale:
+ * @matrix: a #cairo_matrix_t
+ * @sx: Scale factor in the X direction
+ * @sy: Scale factor in the Y direction
+ *
+ * Applies scaling by @tx, @ty to the transformation in
+ * @matrix. The new transformation is given by first scaling by @sx
+ * and @sy then applying the original transformation
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
{
@@ -202,6 +292,21 @@ _cairo_matrix_set_rotate (cairo_matrix_t *matrix,
0, 0);
}
+/**
+ * cairo_matrix_rotate:
+ * @matrix: a @cairo_matrix_t
+ * @radians: angle of rotation, in radians. Angles are defined
+ * so that an angle of 90 degrees (%M_PI radians) rotates the
+ * positive X axis into the positive Y axis. With the default
+ * Cairo choice of axis orientation, positive rotations are
+ * clockwise.
+ *
+ * Applies rotation by @radians to the transformation in
+ * @matrix. The new transformation is given by first rotating by
+ * @radians then applying the original transformation
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
{
@@ -212,6 +317,19 @@ cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
return cairo_matrix_multiply (matrix, &tmp, matrix);
}
+/**
+ * cairo_matrix_multiply:
+ * @result: a @cairo_matrix_t in which to store the result
+ * @a: a @cairo_matrix_t
+ * @b: a @cairo_matrix_t
+ *
+ * Multiplies the affine transformations in @a and @b together
+ * and stores the result in @result. The resulting transformation
+ * is given by first applying the transformation in @b then
+ * applying the transformation in @a.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
{
@@ -238,6 +356,27 @@ cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const ca
}
slim_hidden_def(cairo_matrix_multiply);
+/**
+ * cairo_matrix_transform_distance:
+ * @matrix: a @cairo_matrix_t
+ * @dx: a distance in the X direction. An in/out parameter
+ * @dy: a distance in the Y direction. An in/out parameter
+ *
+ * Transforms the vector (@dx,@dy) by @matrix. Translation is
+ * ignored. In terms of the components of the affine transformation:
+ *
+ * <programlisting>
+ * dx2 = dx1 * a + dy1 * c;
+ * dy2 = dx1 * b + dy1 * d;
+ * </programlisting>
+ *
+ * Affine transformations are position invariant, so the same vector
+ * always transforms to the same vector. If (@x1,@y1) transforms
+ * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
+ * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
{
@@ -255,6 +394,16 @@ cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
}
slim_hidden_def(cairo_matrix_transform_distance);
+/**
+ * cairo_matrix_transform_point:
+ * @matrix: a @cairo_matrix_t
+ * @x: X position. An in/out parameter
+ * @y: Y position. An in/out parameter
+ *
+ * Transforms the point (@x, @y) by @matrix.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y)
{
@@ -351,6 +500,19 @@ _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
c*ty - d*tx, b*tx - a*ty);
}
+/**
+ * cairo_matrix_invert:
+ * @matrix: a @cairo_matrix_t
+ *
+ * Changes @matrix to be the inverse of it's original value. Not
+ * all transformation matrices have inverses; if the matrix
+ * collapses points together (it is <firstterm>degenerate</firstterm>),
+ * then it has no inverse and this function will fail.
+ *
+ * Returns: If @matrix has an inverse, modifies @matrix to
+ * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise,
+ * returns %CAIRO_STATUS_INVALID_MATRIX.
+ **/
cairo_status_t
cairo_matrix_invert (cairo_matrix_t *matrix)
{
@@ -458,7 +620,7 @@ _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double
return CAIRO_STATUS_SUCCESS;
}
-int
+cairo_bool_t
_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
int *itx, int *ity)
{
@@ -477,7 +639,7 @@ _cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
if (ok) {
*itx = _cairo_fixed_integer_part(ttx);
*ity = _cairo_fixed_integer_part(tty);
- return 1;
+ return TRUE;
}
- return 0;
+ return FALSE;
}
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index cfcdd97ee..7c5772a82 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index 6c6ebd976..dc79b6b96 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index ad0220370..08b380902 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo-path.c b/src/cairo-path.c
index 36c25d637..8314f601c 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include <stdlib.h>
@@ -100,6 +100,7 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
for (other_op = other->op_head; other_op; other_op = other_op->next) {
op = _cairo_path_op_buf_create ();
if (op == NULL) {
+ _cairo_path_fini(path);
return CAIRO_STATUS_NO_MEMORY;
}
*op = *other_op;
@@ -109,6 +110,7 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) {
arg = _cairo_path_arg_buf_create ();
if (arg == NULL) {
+ _cairo_path_fini(path);
return CAIRO_STATUS_NO_MEMORY;
}
*arg = *other_arg;
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 6cb981458..283c36dbd 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -21,58 +21,108 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * Author: David Reveman <c99drn@cs.umu.se>
+ * Author: David Reveman <davidr@novell.com>
*/
#include "cairoint.h"
+typedef void (*cairo_shader_function_t) (unsigned char *color0,
+ unsigned char *color1,
+ cairo_fixed_t factor,
+ uint32_t *pixel);
+
+typedef struct _cairo_shader_color_stop {
+ cairo_fixed_t offset;
+ cairo_fixed_48_16_t scale;
+ int id;
+ unsigned char color_char[4];
+} cairo_shader_color_stop_t;
+
+typedef struct _cairo_shader_op {
+ cairo_shader_color_stop_t *stops;
+ int n_stops;
+ cairo_extend_t extend;
+ cairo_shader_function_t shader_function;
+} cairo_shader_op_t;
+
#define MULTIPLY_COLORCOMP(c1, c2) \
((unsigned char) \
((((unsigned char) (c1)) * (int) ((unsigned char) (c2))) / 0xff))
-void
-_cairo_pattern_init (cairo_pattern_t *pattern)
+static void
+_cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
{
+ pattern->type = type;
pattern->ref_count = 1;
-
- pattern->extend = CAIRO_EXTEND_DEFAULT;
- pattern->filter = CAIRO_FILTER_DEFAULT;
-
- _cairo_color_init (&pattern->color);
+ pattern->extend = CAIRO_EXTEND_DEFAULT;
+ pattern->filter = CAIRO_FILTER_DEFAULT;
+ pattern->alpha = 1.0;
_cairo_matrix_init (&pattern->matrix);
+}
- pattern->stops = NULL;
- pattern->n_stops = 0;
+static cairo_status_t
+_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
+ cairo_gradient_pattern_t *other)
+{
+ if (other->base.type == CAIRO_PATTERN_LINEAR)
+ {
+ cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern;
+ cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other;
+
+ *dst = *src;
+ }
+ else
+ {
+ cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern;
+ cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other;
+
+ *dst = *src;
+ }
- pattern->type = CAIRO_PATTERN_SOLID;
+ if (other->n_stops)
+ {
+ pattern->stops = malloc (other->n_stops * sizeof (cairo_color_stop_t));
+ if (!pattern->stops)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ memcpy (pattern->stops, other->stops,
+ other->n_stops * sizeof (cairo_color_stop_t));
+ }
- pattern->source = NULL;
- pattern->source_offset.x = 0.0;
- pattern->source_offset.y = 0.0;
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other)
{
- *pattern = *other;
-
- pattern->ref_count = 1;
+ switch (other->type) {
+ case CAIRO_PATTERN_SOLID: {
+ cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern;
+ cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other;
- if (pattern->n_stops) {
- pattern->stops =
- malloc (sizeof (cairo_color_stop_t) * pattern->n_stops);
- if (pattern->stops == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- memcpy (pattern->stops, other->stops,
- sizeof (cairo_color_stop_t) * other->n_stops);
+ *dst = *src;
+ } break;
+ case CAIRO_PATTERN_SURFACE: {
+ cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern;
+ cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other;
+
+ *dst = *src;
+ cairo_surface_reference (dst->surface);
+ } break;
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern;
+ cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other;
+ cairo_status_t status;
+
+ status = _cairo_gradient_pattern_init_copy (dst, src);
+ if (status)
+ return status;
+ } break;
}
-
- if (pattern->source)
- cairo_surface_reference (other->source);
-
- if (pattern->type == CAIRO_PATTERN_SURFACE)
- cairo_surface_reference (other->u.surface.surface);
+
+ pattern->ref_count = 1;
return CAIRO_STATUS_SUCCESS;
}
@@ -80,110 +130,145 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other)
void
_cairo_pattern_fini (cairo_pattern_t *pattern)
{
- if (pattern->n_stops)
- free (pattern->stops);
-
- if (pattern->type == CAIRO_PATTERN_SURFACE) {
- /* show_surface require us to restore surface matrix, repeat
- attribute, filter type */
- if (pattern->source) {
- cairo_surface_set_matrix (pattern->source,
- &pattern->u.surface.save_matrix);
- cairo_surface_set_repeat (pattern->source,
- pattern->u.surface.save_repeat);
- cairo_surface_set_filter (pattern->source,
- pattern->u.surface.save_filter);
- }
- cairo_surface_destroy (pattern->u.surface.surface);
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SOLID:
+ break;
+ case CAIRO_PATTERN_SURFACE: {
+ cairo_surface_pattern_t *fini = (cairo_surface_pattern_t *) pattern;
+
+ cairo_surface_destroy (fini->surface);
+ } break;
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ cairo_gradient_pattern_t *fini = (cairo_gradient_pattern_t *) pattern;
+
+ if (fini->n_stops)
+ free (fini->stops);
+ } break;
}
+}
+
+void
+_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
+ double red,
+ double green,
+ double blue)
+{
+ _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SOLID);
- if (pattern->source)
- cairo_surface_destroy (pattern->source);
+ pattern->red = red;
+ pattern->green = green;
+ pattern->blue = blue;
}
void
-_cairo_pattern_init_solid (cairo_pattern_t *pattern,
- double red, double green, double blue)
+_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
+ cairo_surface_t *surface)
{
- _cairo_pattern_init (pattern);
+ _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SURFACE);
+
+ pattern->surface = surface;
+ cairo_surface_reference (surface);
+}
- pattern->type = CAIRO_PATTERN_SOLID;
- _cairo_color_set_rgb (&pattern->color, red, green, blue);
+static void
+_cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern,
+ cairo_pattern_type_t type)
+{
+ _cairo_pattern_init (&pattern->base, type);
+
+ pattern->stops = 0;
+ pattern->n_stops = 0;
+}
+
+void
+_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
+ double x0, double y0, double x1, double y1)
+{
+ _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_LINEAR);
+
+ pattern->point0.x = x0;
+ pattern->point0.y = y0;
+ pattern->point1.x = x1;
+ pattern->point1.y = y1;
+}
+
+void
+_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
+ double cx0, double cy0, double radius0,
+ double cx1, double cy1, double radius1)
+{
+ _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_RADIAL);
+
+ pattern->center0.x = cx0;
+ pattern->center0.y = cy0;
+ pattern->radius0 = fabs (radius0);
+ pattern->center1.x = cx1;
+ pattern->center1.y = cy1;
+ pattern->radius1 = fabs (radius1);
}
cairo_pattern_t *
_cairo_pattern_create_solid (double red, double green, double blue)
{
- cairo_pattern_t *pattern;
+ cairo_solid_pattern_t *pattern;
- pattern = malloc (sizeof (cairo_pattern_t));
+ pattern = malloc (sizeof (cairo_solid_pattern_t));
if (pattern == NULL)
return NULL;
_cairo_pattern_init_solid (pattern, red, green, blue);
- return pattern;
+ return &pattern->base;
}
cairo_pattern_t *
cairo_pattern_create_for_surface (cairo_surface_t *surface)
{
- cairo_pattern_t *pattern;
+ cairo_surface_pattern_t *pattern;
- pattern = malloc (sizeof (cairo_pattern_t));
+ pattern = malloc (sizeof (cairo_surface_pattern_t));
if (pattern == NULL)
return NULL;
- _cairo_pattern_init (pattern);
-
- pattern->type = CAIRO_PATTERN_SURFACE;
- pattern->u.surface.surface = surface;
- cairo_surface_reference (surface);
+ _cairo_pattern_init_for_surface (pattern, surface);
+
+ /* this will go away when we completely remove the surface attributes */
+ if (surface->repeat)
+ pattern->base.extend = CAIRO_EXTEND_REPEAT;
+ else
+ pattern->base.extend = CAIRO_EXTEND_DEFAULT;
- return pattern;
+ return &pattern->base;
}
cairo_pattern_t *
cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
{
- cairo_pattern_t *pattern;
+ cairo_linear_pattern_t *pattern;
- pattern = malloc (sizeof (cairo_pattern_t));
+ pattern = malloc (sizeof (cairo_linear_pattern_t));
if (pattern == NULL)
return NULL;
- _cairo_pattern_init (pattern);
-
- pattern->type = CAIRO_PATTERN_LINEAR;
- pattern->u.linear.point0.x = x0;
- pattern->u.linear.point0.y = y0;
- pattern->u.linear.point1.x = x1;
- pattern->u.linear.point1.y = y1;
+ _cairo_pattern_init_linear (pattern, x0, y0, x1, y1);
- return pattern;
+ return &pattern->base.base;
}
cairo_pattern_t *
cairo_pattern_create_radial (double cx0, double cy0, double radius0,
double cx1, double cy1, double radius1)
{
- cairo_pattern_t *pattern;
+ cairo_radial_pattern_t *pattern;
- pattern = malloc (sizeof (cairo_pattern_t));
+ pattern = malloc (sizeof (cairo_radial_pattern_t));
if (pattern == NULL)
return NULL;
- _cairo_pattern_init (pattern);
-
- pattern->type = CAIRO_PATTERN_RADIAL;
- pattern->u.radial.center0.x = cx0;
- pattern->u.radial.center0.y = cy0;
- pattern->u.radial.radius0 = fabs (radius0);
- pattern->u.radial.center1.x = cx1;
- pattern->u.radial.center1.y = cy1;
- pattern->u.radial.radius1 = fabs (radius1);
+ _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1);
- return pattern;
+ return &pattern->base.base;
}
void
@@ -209,37 +294,19 @@ cairo_pattern_destroy (cairo_pattern_t *pattern)
free (pattern);
}
-static int
-_cairo_pattern_stop_compare (const void *elem1, const void *elem2)
-{
- return
- (((cairo_color_stop_t *) elem1)->offset ==
- ((cairo_color_stop_t *) elem2)->offset) ?
- /* equal offsets, sort on id */
- ((((cairo_color_stop_t *) elem1)->id <
- ((cairo_color_stop_t *) elem2)->id) ? -1 : 1) :
- /* sort on offset */
- ((((cairo_color_stop_t *) elem1)->offset <
- ((cairo_color_stop_t *) elem2)->offset) ? -1 : 1);
-}
-
-cairo_status_t
-cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
- double offset,
- double red, double green, double blue,
- double alpha)
+static cairo_status_t
+_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
+ double offset,
+ double red,
+ double green,
+ double blue,
+ double alpha)
{
cairo_color_stop_t *stop;
- int i;
-
- _cairo_restrict_value (&offset, 0.0, 1.0);
- _cairo_restrict_value (&red, 0.0, 1.0);
- _cairo_restrict_value (&green, 0.0, 1.0);
- _cairo_restrict_value (&blue, 0.0, 1.0);
pattern->n_stops++;
pattern->stops = realloc (pattern->stops,
- sizeof (cairo_color_stop_t) * pattern->n_stops);
+ pattern->n_stops * sizeof (cairo_color_stop_t));
if (pattern->stops == NULL) {
pattern->n_stops = 0;
@@ -249,41 +316,51 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
stop = &pattern->stops[pattern->n_stops - 1];
stop->offset = _cairo_fixed_from_double (offset);
- stop->id = pattern->n_stops;
- stop->color_char[0] = red * 0xff;
- stop->color_char[1] = green * 0xff;
- stop->color_char[2] = blue * 0xff;
- stop->color_char[3] = alpha * 0xff;
+ _cairo_color_init (&stop->color);
+ _cairo_color_set_rgb (&stop->color, red, green, blue);
+ _cairo_color_set_alpha (&stop->color, alpha);
- /* sort stops in ascending order */
- qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t),
- _cairo_pattern_stop_compare);
-
- for (i = 0; i < pattern->n_stops - 1; i++) {
- pattern->stops[i + 1].scale =
- pattern->stops[i + 1].offset - pattern->stops[i].offset;
- if (pattern->stops[i + 1].scale == 65536)
- pattern->stops[i + 1].scale = 0;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
+ double offset,
+ double red,
+ double green,
+ double blue,
+ double alpha)
+{
+ if (pattern->type != CAIRO_PATTERN_LINEAR &&
+ pattern->type != CAIRO_PATTERN_RADIAL)
+ {
+ /* XXX: CAIRO_STATUS_INVALID_PATTERN? */
+ return CAIRO_STATUS_SUCCESS;
}
- return CAIRO_STATUS_SUCCESS;
+ _cairo_restrict_value (&offset, 0.0, 1.0);
+ _cairo_restrict_value (&red, 0.0, 1.0);
+ _cairo_restrict_value (&green, 0.0, 1.0);
+ _cairo_restrict_value (&blue, 0.0, 1.0);
+ _cairo_restrict_value (&alpha, 0.0, 1.0);
+
+ return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
+ offset,
+ red, green, blue,
+ alpha);
}
cairo_status_t
cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
{
- cairo_matrix_copy (&pattern->matrix, matrix);
-
- return CAIRO_STATUS_SUCCESS;
+ return cairo_matrix_copy (&pattern->matrix, matrix);
}
cairo_status_t
cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
{
- cairo_matrix_copy (matrix, &pattern->matrix);
-
- return CAIRO_STATUS_SUCCESS;
+ return cairo_matrix_copy (matrix, &pattern->matrix);
}
cairo_status_t
@@ -316,9 +393,20 @@ cairo_pattern_get_extend (cairo_pattern_t *pattern)
cairo_status_t
_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
- double *red, double *green, double *blue)
+ double *red,
+ double *green,
+ double *blue)
{
- _cairo_color_get_rgb (&pattern->color, red, green, blue);
+
+ if (pattern->type == CAIRO_PATTERN_SOLID)
+ {
+ cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
+
+ *red = solid->red;
+ *green = solid->green;
+ *blue = solid->blue;
+ } else
+ *red = *green = *blue = 1.0;
return CAIRO_STATUS_SUCCESS;
}
@@ -326,63 +414,16 @@ _cairo_pattern_get_rgb (cairo_pattern_t *pattern,
void
_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha)
{
- int i;
-
- _cairo_color_set_alpha (&pattern->color, alpha);
-
- for (i = 0; i < pattern->n_stops; i++)
- pattern->stops[i].color_char[3] =
- MULTIPLY_COLORCOMP (pattern->stops[i].color_char[3], alpha * 0xff);
-}
-
-void
-_cairo_pattern_set_source_offset (cairo_pattern_t *pattern,
- double x, double y)
-{
- pattern->source_offset.x = x;
- pattern->source_offset.y = y;
+ pattern->alpha = alpha;
}
void
_cairo_pattern_transform (cairo_pattern_t *pattern,
- cairo_matrix_t *ctm_inverse)
+ cairo_matrix_t *ctm_inverse)
{
cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
}
-void
-_cairo_pattern_prepare_surface (cairo_pattern_t *pattern)
-{
- cairo_matrix_t device_to_source;
- cairo_matrix_t user_to_source;
-
- /* should the surface matrix interface be remove from the API?
- for now we multiple the surface matrix with the pattern matrix */
- cairo_surface_get_matrix (pattern->u.surface.surface, &user_to_source);
- cairo_matrix_multiply (&device_to_source, &pattern->matrix,
- &user_to_source);
- cairo_surface_set_matrix (pattern->source, &device_to_source);
-
- /* storing original surface matrix in pattern */
- pattern->u.surface.save_matrix = user_to_source;
-
- /* storing original surface repeat mode in pattern */
- pattern->u.surface.save_repeat = pattern->source->repeat;
-
- /* what do we do with extend types pad and reflect? */
- if (pattern->extend == CAIRO_EXTEND_REPEAT
- || pattern->source->repeat == 1)
- cairo_surface_set_repeat (pattern->source, 1);
- else
- cairo_surface_set_repeat (pattern->source, 0);
-
- /* storing original surface filter in pattern */
- pattern->u.surface.save_filter =
- cairo_surface_get_filter (pattern->source);
-
- cairo_surface_set_filter (pattern->source, pattern->filter);
-}
-
#define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \
((factor < 32768)? c1: c2)
@@ -390,7 +431,7 @@ static void
_cairo_pattern_shader_nearest (unsigned char *color0,
unsigned char *color1,
cairo_fixed_t factor,
- int *pixel)
+ uint32_t *pixel)
{
*pixel =
((INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor) << 24) |
@@ -408,7 +449,7 @@ static void
_cairo_pattern_shader_linear (unsigned char *color0,
unsigned char *color1,
cairo_fixed_t factor,
- int *pixel)
+ uint32_t *pixel)
{
*pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) |
(INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) |
@@ -422,7 +463,7 @@ static void
_cairo_pattern_shader_gaussian (unsigned char *color0,
unsigned char *color1,
cairo_fixed_t factor,
- int *pixel)
+ uint32_t *pixel)
{
double f = ((double) factor) / 65536.0;
@@ -436,17 +477,59 @@ _cairo_pattern_shader_gaussian (unsigned char *color0,
#undef INTERPOLATE_COLOR_LINEAR
-void
-_cairo_pattern_shader_init (cairo_pattern_t *pattern,
- cairo_shader_op_t *op)
-{
- op->stops = pattern->stops;
- op->n_stops = pattern->n_stops - 1;
- op->min_offset = pattern->stops[0].offset;
- op->max_offset = pattern->stops[op->n_stops].offset;
- op->extend = pattern->extend;
-
- switch (pattern->filter) {
+static int
+_cairo_shader_color_stop_compare (const void *elem1, const void *elem2)
+{
+ cairo_shader_color_stop_t *s1 = (cairo_shader_color_stop_t *) elem1;
+ cairo_shader_color_stop_t *s2 = (cairo_shader_color_stop_t *) elem2;
+
+ return
+ (s1->offset == s2->offset) ?
+ /* equal offsets, sort on id */
+ ((s1->id < s2->id) ? -1 : 1) :
+ /* sort on offset */
+ ((s1->offset < s2->offset) ? -1 : 1);
+}
+
+static cairo_status_t
+_cairo_pattern_shader_init (cairo_gradient_pattern_t *pattern,
+ cairo_shader_op_t *op)
+{
+ int i;
+
+ op->stops = malloc (pattern->n_stops * sizeof (cairo_shader_color_stop_t));
+ if (!op->stops)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ for (i = 0; i < pattern->n_stops; i++)
+ {
+ op->stops[i].color_char[0] = pattern->stops[i].color.red * 0xff;
+ op->stops[i].color_char[1] = pattern->stops[i].color.green * 0xff;
+ op->stops[i].color_char[2] = pattern->stops[i].color.blue * 0xff;
+ op->stops[i].color_char[3] = pattern->stops[i].color.alpha *
+ pattern->base.alpha * 0xff;
+ op->stops[i].offset = pattern->stops[i].offset;
+ op->stops[i].id = i;
+ }
+
+ /* sort stops in ascending order */
+ qsort (op->stops, pattern->n_stops, sizeof (cairo_shader_color_stop_t),
+ _cairo_shader_color_stop_compare);
+
+ for (i = 0; i < pattern->n_stops - 1; i++)
+ {
+ op->stops[i + 1].scale = op->stops[i + 1].offset - op->stops[i].offset;
+ if (op->stops[i + 1].scale == 65536)
+ op->stops[i + 1].scale = 0;
+ }
+
+ op->n_stops = pattern->n_stops;
+ op->extend = pattern->base.extend;
+
+ /* XXX: this is wrong, the filter should not be used for selecting
+ color stop interpolation function. function should always be 'linear'
+ and filter should be used for computing pixels. */
+ switch (pattern->base.filter) {
case CAIRO_FILTER_FAST:
case CAIRO_FILTER_NEAREST:
op->shader_function = _cairo_pattern_shader_nearest;
@@ -460,15 +543,56 @@ _cairo_pattern_shader_init (cairo_pattern_t *pattern,
op->shader_function = _cairo_pattern_shader_linear;
break;
}
+
+ return CAIRO_STATUS_SUCCESS;
}
-void
-_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
- cairo_fixed_t factor,
- int *pixel)
+static void
+_cairo_pattern_shader_fini (cairo_shader_op_t *op)
+{
+ if (op->stops)
+ free (op->stops);
+}
+
+/* Find two color stops bounding the given offset. If the given offset
+ * is before the first or after the last stop offset, the nearest
+ * offset is returned twice.
+ */
+static void
+_cairo_shader_op_find_color_stops (cairo_shader_op_t *op,
+ cairo_fixed_t offset,
+ cairo_shader_color_stop_t *stops[2])
{
int i;
-
+
+ /* Before first stop. */
+ if (offset <= op->stops[0].offset) {
+ stops[0] = &op->stops[0];
+ stops[1] = &op->stops[0];
+ return;
+ }
+
+ /* Between two stops. */
+ for (i = 0; i < op->n_stops - 1; i++) {
+ if (offset <= op->stops[i + 1].offset) {
+ stops[0] = &op->stops[i];
+ stops[1] = &op->stops[i + 1];
+ return;
+ }
+ }
+
+ /* After last stop. */
+ stops[0] = &op->stops[op->n_stops - 1];
+ stops[1] = &op->stops[op->n_stops - 1];
+}
+
+static void
+_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
+ cairo_fixed_t factor,
+ uint32_t *pixel)
+{
+ cairo_shader_color_stop_t *stops[2];
+
switch (op->extend) {
case CAIRO_EXTEND_REPEAT:
factor -= factor & 0xffff0000;
@@ -485,96 +609,158 @@ _cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
break;
}
- if (factor < op->min_offset)
- factor = op->min_offset;
- else if (factor > op->max_offset)
- factor = op->max_offset;
-
- for (i = 0; i < op->n_stops; i++) {
- if (factor <= op->stops[i + 1].offset) {
-
- /* take offset as new 0 of coordinate system */
- factor -= op->stops[i].offset;
-
- /* difference between two offsets == 0, abrubt change */
- if (op->stops[i + 1].scale)
- factor = ((cairo_fixed_48_16_t) factor << 16) /
- op->stops[i + 1].scale;
+ _cairo_shader_op_find_color_stops (op, factor, stops);
+
+ /* take offset as new 0 of coordinate system */
+ factor -= stops[0]->offset;
- op->shader_function (op->stops[i].color_char,
- op->stops[i + 1].color_char,
- factor, pixel);
+ /* difference between two offsets == 0, abrubt change */
+ if (stops[1]->scale)
+ factor = ((cairo_fixed_48_16_t) factor << 16) /
+ stops[1]->scale;
+
+ op->shader_function (stops[0]->color_char,
+ stops[1]->color_char,
+ factor, pixel);
- /* multiply alpha */
- if (((unsigned char) (*pixel >> 24)) != 0xff) {
- *pixel = (*pixel & 0xff000000) |
- (MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) |
- (MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) |
- (MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0);
- }
- break;
- }
+ /* multiply alpha */
+ if (((unsigned char) (*pixel >> 24)) != 0xff) {
+ *pixel = (*pixel & 0xff000000) |
+ (MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) |
+ (MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) |
+ (MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0);
}
}
-static void
-_cairo_image_data_set_linear (cairo_pattern_t *pattern,
- double offset_x,
- double offset_y,
- int *pixels,
- int width,
- int height)
+static cairo_status_t
+_cairo_image_data_set_linear (cairo_linear_pattern_t *pattern,
+ double offset_x,
+ double offset_y,
+ uint32_t *pixels,
+ int width,
+ int height)
{
int x, y;
cairo_point_double_t point0, point1;
- double px, py, ex, ey;
double a, b, c, d, tx, ty;
- double length, start, angle, fx, fy, factor;
+ double scale, start, dx, dy, factor;
cairo_shader_op_t op;
-
- _cairo_pattern_shader_init (pattern, &op);
-
- point0.x = pattern->u.linear.point0.x;
- point0.y = pattern->u.linear.point0.y;
- point1.x = pattern->u.linear.point1.x;
- point1.y = pattern->u.linear.point1.y;
-
- cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty);
-
- length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) +
- (point1.y - point0.y) * (point1.y - point0.y));
- length = (length) ? 1.0 / length : CAIRO_MAXSHORT;
-
- angle = -atan2 (point1.y - point0.y, point1.x - point0.x);
- fx = cos (angle);
- fy = -sin (angle);
-
- start = fx * point0.x;
- start += fy * point0.y;
+ cairo_status_t status;
+
+ status = _cairo_pattern_shader_init (&pattern->base, &op);
+ if (status)
+ return status;
+
+ /* We compute the position in the linear gradient for
+ * a point q as:
+ *
+ * [q . (p1 - p0) - p0 . (p1 - p0)] / (p1 - p0) ^ 2
+ *
+ * The computation is done in pattern space. The
+ * calculation could be heavily optimized by using the
+ * fact that 'factor' increases linearly in both
+ * directions.
+ */
+ point0.x = pattern->point0.x;
+ point0.y = pattern->point0.y;
+ point1.x = pattern->point1.x;
+ point1.y = pattern->point1.y;
+
+ cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
+
+ dx = point1.x - point0.x;
+ dy = point1.y - point0.y;
+ scale = dx * dx + dy * dy;
+ scale = (scale) ? 1.0 / scale : 1.0;
+
+ start = dx * point0.x + dy * point0.y;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
- px = x + offset_x;
- py = y + offset_y;
+ double qx_device = x + offset_x;
+ double qy_device = y + offset_y;
- /* transform fragment */
- ex = a * px + c * py + tx;
- ey = b * px + d * py + ty;
+ /* transform fragment into pattern space */
+ double qx = a * qx_device + c * qy_device + tx;
+ double qy = b * qx_device + d * qy_device + ty;
- factor = ((fx * ex + fy * ey) - start) * length;
+ factor = ((dx * qx + dy * qy) - start) * scale;
_cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
}
}
+
+ _cairo_pattern_shader_fini (&op);
+
+ return CAIRO_STATUS_SUCCESS;
}
static void
-_cairo_image_data_set_radial (cairo_pattern_t *pattern,
- double offset_x,
- double offset_y,
- int *pixels,
- int width,
- int height)
+_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
+ double offset_x,
+ double offset_y,
+ int width,
+ int height,
+ cairo_bool_t *is_horizontal,
+ cairo_bool_t *is_vertical)
+{
+ cairo_point_double_t point0, point1;
+ double a, b, c, d, tx, ty;
+ double scale, start, dx, dy;
+ cairo_fixed_t factors[3];
+ int i;
+
+ /* To classidy a pattern as horizontal or vertical, we first
+ * compute the (fixed point) factors at the corners of the
+ * pattern. We actually only need 3/4 corners, so we skip the
+ * fourth.
+ */
+ point0.x = pattern->point0.x;
+ point0.y = pattern->point0.y;
+ point1.x = pattern->point1.x;
+ point1.y = pattern->point1.y;
+
+ cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
+
+ dx = point1.x - point0.x;
+ dy = point1.y - point0.y;
+ scale = dx * dx + dy * dy;
+ scale = (scale) ? 1.0 / scale : 1.0;
+
+ start = dx * point0.x + dy * point0.y;
+
+ for (i = 0; i < 3; i++) {
+ double qx_device = (i % 2) * (width - 1) + offset_x;
+ double qy_device = (i / 2) * (height - 1) + offset_y;
+
+ /* transform fragment into pattern space */
+ double qx = a * qx_device + c * qy_device + tx;
+ double qy = b * qx_device + d * qy_device + ty;
+
+ factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale);
+ }
+
+ /* We consider a pattern to be vertical if the fixed point factor
+ * at the two upper corners is the same. We could accept a small
+ * change, but determining what change is acceptable would require
+ * sorting the stops in the pattern and looking at the differences.
+ *
+ * Horizontal works the same way with the two left corners.
+ */
+
+ *is_vertical = factors[1] == factors[0];
+ *is_horizontal = factors[2] == factors[0];
+}
+
+static cairo_status_t
+_cairo_image_data_set_radial (cairo_radial_pattern_t *pattern,
+ double offset_x,
+ double offset_y,
+ uint32_t *pixels,
+ int width,
+ int height)
{
int x, y, aligned_circles;
cairo_point_double_t c0, c1;
@@ -584,15 +770,18 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern,
c0_c1_x, c0_c1_y, c0_c1, angle_c0, c1_y, y_x, c0_y, c0_x, r1_2,
denumerator, fraction, factor;
cairo_shader_op_t op;
+ cairo_status_t status;
- _cairo_pattern_shader_init (pattern, &op);
+ status = _cairo_pattern_shader_init (&pattern->base, &op);
+ if (status)
+ return status;
- c0.x = pattern->u.radial.center0.x;
- c0.y = pattern->u.radial.center0.y;
- r0 = pattern->u.radial.radius0;
- c1.x = pattern->u.radial.center1.x;
- c1.y = pattern->u.radial.center1.y;
- r1 = pattern->u.radial.radius1;
+ c0.x = pattern->center0.x;
+ c0.y = pattern->center0.y;
+ r0 = pattern->radius0;
+ c1.x = pattern->center1.x;
+ c1.y = pattern->center1.y;
+ r1 = pattern->radius1;
if (c0.x != c1.x || c0.y != c1.y) {
aligned_circles = 0;
@@ -606,7 +795,8 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern,
r1_2 = c0_c1 = 0.0; /* shut up compiler */
}
- cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty);
+ cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
@@ -682,70 +872,454 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern,
_cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
}
}
+
+ _cairo_pattern_shader_fini (&op);
+
+ return CAIRO_STATUS_SUCCESS;
}
-cairo_image_surface_t *
-_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
+static cairo_int_status_t
+_cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **out,
+ cairo_surface_attributes_t *attr)
{
- cairo_surface_t *surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
+ uint32_t *data;
+ cairo_bool_t repeat = FALSE;
+
+ if (pattern->base.type == CAIRO_PATTERN_LINEAR) {
+ cairo_bool_t is_horizontal;
+ cairo_bool_t is_vertical;
+
+ _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern,
+ x, y, width, height,
+ &is_horizontal, &is_vertical);
+ if (is_horizontal) {
+ height = 1;
+ repeat = TRUE;
+ }
+ if (is_vertical) {
+ width = 1;
+ repeat = TRUE;
+ }
+ }
+
+ data = malloc (width * height * 4);
+ if (!data)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (pattern->base.type == CAIRO_PATTERN_LINEAR)
+ {
+ cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
+
+ status = _cairo_image_data_set_linear (linear, x, y, data,
+ width, height);
+ }
+ else
+ {
+ cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
+
+ status = _cairo_image_data_set_radial (radial, x, y, data,
+ width, height);
+ }
- switch (pattern->type) {
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- char *data;
- double x = box->p1.x >> 16;
- double y = box->p1.y >> 16;
- int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16);
- int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16);
+ if (status) {
+ free (data);
+ return status;
+ }
+
+ image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data ((char *) data,
+ CAIRO_FORMAT_ARGB32,
+ width, height,
+ width * 4);
+
+ if (image == NULL) {
+ free (data);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ _cairo_image_surface_assume_ownership_of_data (image);
+
+ status = _cairo_surface_clone_similar (dst, &image->base, out);
+
+ cairo_surface_destroy (&image->base);
+
+ attr->x_offset = -x;
+ attr->y_offset = -y;
+ cairo_matrix_set_identity (&attr->matrix);
+ attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
+ attr->filter = CAIRO_FILTER_NEAREST;
+ attr->acquired = FALSE;
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **out,
+ cairo_surface_attributes_t *attribs)
+{
+ cairo_color_t color;
+
+ _cairo_color_init (&color);
+ _cairo_color_set_rgb (&color, pattern->red, pattern->green, pattern->blue);
+ _cairo_color_set_alpha (&color, pattern->base.alpha);
+
+ *out = _cairo_surface_create_similar_solid (dst,
+ CAIRO_FORMAT_ARGB32,
+ 1, 1,
+ &color);
+
+ if (*out == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ attribs->x_offset = attribs->y_offset = 0;
+ cairo_matrix_set_identity (&attribs->matrix);
+ attribs->extend = CAIRO_EXTEND_REPEAT;
+ attribs->filter = CAIRO_FILTER_NEAREST;
+ attribs->acquired = FALSE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+/**
+ * _cairo_pattern_is_opaque
+ *
+ * Convenience function to determine whether a pattern has an opaque
+ * alpha value. This is done by testing whether the pattern's alpha
+ * value when converted to a byte is 255, so if a backend actually
+ * supported deep alpha channels this function might not do the right
+ * thing.
+ *
+ * Note that for a gradient or surface pattern, the overall resulting
+ * alpha for the pattern can be non-opaque even this function returns
+ * %TRUE, since the resulting alpha is the multiplication of the
+ * alpha of the gradient or surface with the pattern's alpha. In
+ * the future, alpha will be moved from the base pattern to the
+ * solid pattern subtype, at which point this function should
+ * probably be renamed to _cairo_pattern_is_opaque_solid()
+ *
+ * Return value: %TRUE if the pattern is opaque
+ **/
+cairo_bool_t
+_cairo_pattern_is_opaque (cairo_pattern_t *pattern)
+{
+ return (pattern->alpha >= ((double)0xff00 / (double)0xffff));
+}
+
+static cairo_int_status_t
+_cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **out,
+ cairo_surface_attributes_t *attr)
+{
+ cairo_int_status_t status;
+
+ attr->acquired = FALSE;
+
+ /* handle pattern opacity */
+ if (!_cairo_pattern_is_opaque (&pattern->base))
+ {
+ cairo_surface_pattern_t tmp;
+ cairo_color_t color;
+
+ _cairo_color_init (&color);
+ _cairo_color_set_alpha (&color, pattern->base.alpha);
+
+ *out = _cairo_surface_create_similar_solid (dst,
+ CAIRO_FORMAT_ARGB32,
+ width, height,
+ &color);
+ if (*out == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ status = _cairo_pattern_init_copy (&tmp.base, &pattern->base);
+ if (CAIRO_OK (status))
+ {
+ tmp.base.alpha = 1.0;
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ &tmp.base,
+ NULL,
+ *out,
+ x, y, 0, 0, 0, 0,
+ width, height);
+
+ _cairo_pattern_fini (&tmp.base);
+ }
+
+ if (status) {
+ cairo_surface_destroy (*out);
+ return status;
+ }
- data = malloc (width * height * 4);
- if (!data)
- return NULL;
+ attr->x_offset = -x;
+ attr->y_offset = -y;
+ attr->extend = CAIRO_EXTEND_NONE;
+ attr->filter = CAIRO_FILTER_NEAREST;
+
+ cairo_matrix_set_identity (&attr->matrix);
+ }
+ else
+ {
+ int tx, ty;
+
+ if (_cairo_surface_is_image (dst))
+ {
+ cairo_image_surface_t *image;
+
+ status = _cairo_surface_acquire_source_image (pattern->surface,
+ &image,
+ &attr->extra);
+ if (CAIRO_OK (status))
+ *out = &image->base;
+
+ attr->acquired = TRUE;
+ }
+ else
+ status = _cairo_surface_clone_similar (dst, pattern->surface, out);
- if (pattern->type == CAIRO_PATTERN_RADIAL)
- _cairo_image_data_set_radial (pattern, x, y, (int *) data,
- width, height);
+ attr->extend = pattern->base.extend;
+ attr->filter = pattern->base.filter;
+ if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
+ &tx, &ty))
+ {
+ cairo_matrix_set_identity (&attr->matrix);
+ attr->x_offset = tx;
+ attr->y_offset = ty;
+ }
else
- _cairo_image_data_set_linear (pattern, x, y, (int *) data,
- width, height);
+ {
+ attr->matrix = pattern->base.matrix;
+ attr->x_offset = attr->y_offset = 0;
+ }
+ }
+
+ return status;
+}
- _cairo_pattern_set_source_offset (pattern, x, y);
+/**
+ * _cairo_pattern_acquire_surface:
+ * @pattern: a #cairo_pattern_t
+ * @dst: destination surface
+ * @x: X coordinate in source corresponding to left side of destination area
+ * @y: Y coordinate in source corresponding to top side of destination area
+ * @width: width of destination area
+ * @height: height of destination area
+ * @surface_out: location to store a pointer to a surface
+ * @attributes: surface attributes that destination backend should apply to
+ * the returned surface
+ *
+ * A convenience function to obtain a surface to use as the source for
+ * drawing on @dst.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out.
+ **/
+cairo_int_status_t
+_cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **surface_out,
+ cairo_surface_attributes_t *attributes)
+{
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SOLID: {
+ cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern;
+
+ return _cairo_pattern_acquire_surface_for_solid (src, dst,
+ x, y, width, height,
+ surface_out,
+ attributes);
+ } break;
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern;
+
+ /* fast path for gradients with less than 2 color stops */
+ if (src->n_stops < 2)
+ {
+ cairo_solid_pattern_t solid;
+
+ if (src->n_stops)
+ {
+ _cairo_pattern_init_solid (&solid,
+ src->stops->color.red,
+ src->stops->color.green,
+ src->stops->color.blue);
+ _cairo_pattern_set_alpha (&solid.base,
+ src->stops->color.alpha);
+ }
+ else
+ {
+ _cairo_pattern_init_solid (&solid, 0.0, 0.0, 0.0);
+ _cairo_pattern_set_alpha (&solid.base, 0.0);
+ }
- surface = cairo_image_surface_create_for_data (data,
- CAIRO_FORMAT_ARGB32,
- width, height,
- width * 4);
+ return _cairo_pattern_acquire_surface_for_solid (&solid, dst,
+ x, y,
+ width, height,
+ surface_out,
+ attributes);
+ }
+ else
+ return _cairo_pattern_acquire_surface_for_gradient (src, dst,
+ x, y,
+ width, height,
+ surface_out,
+ attributes);
+ } break;
+ case CAIRO_PATTERN_SURFACE: {
+ cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;
- if (surface)
- _cairo_image_surface_assume_ownership_of_data (
- (cairo_image_surface_t *) surface);
+ return _cairo_pattern_acquire_surface_for_surface (src, dst,
+ x, y, width, height,
+ surface_out,
+ attributes);
+ } break;
}
- break;
- case CAIRO_PATTERN_SOLID:
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
- if (surface) {
- _cairo_surface_fill_rectangle (surface,
- CAIRO_OPERATOR_SRC,
- &pattern->color, 0, 0, 1, 1);
- cairo_surface_set_repeat (surface, 1);
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+/**
+ * _cairo_pattern_release_surface:
+ * @pattern: a #cairo_pattern_t
+ * @info: pointer to #cairo_surface_attributes_t filled in by
+ * _cairo_pattern_acquire_surface
+ *
+ * Releases resources obtained by _cairo_pattern_acquire_surface.
+ **/
+void
+_cairo_pattern_release_surface (cairo_surface_t *dst,
+ cairo_surface_t *surface,
+ cairo_surface_attributes_t *attributes)
+{
+ if (attributes->acquired)
+ _cairo_surface_release_source_image (dst,
+ (cairo_image_surface_t *) surface,
+ attributes->extra);
+ else
+ cairo_surface_destroy (surface);
+}
+
+cairo_int_status_t
+_cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
+ cairo_pattern_t *mask,
+ cairo_surface_t *dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **src_out,
+ cairo_surface_t **mask_out,
+ cairo_surface_attributes_t *src_attributes,
+ cairo_surface_attributes_t *mask_attributes)
+{
+ cairo_int_status_t status;
+
+ cairo_pattern_union_t tmp;
+ cairo_bool_t src_opaque, mask_opaque;
+ double src_alpha, mask_alpha;
+
+ src_opaque = _cairo_pattern_is_opaque (src);
+ mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
+
+ /* For surface patterns, we move any translucency from src->alpha
+ * to mask->alpha so we can use the source unchanged. Otherwise we
+ * move the translucency from mask->alpha to src->alpha so that
+ * we can drop the mask if possible.
+ */
+ if (src->type == CAIRO_PATTERN_SURFACE)
+ {
+ if (mask) {
+ mask_opaque = mask_opaque && src_opaque;
+ mask_alpha = mask->alpha * src->alpha;
+ } else {
+ mask_opaque = src_opaque;
+ mask_alpha = src->alpha;
}
- break;
- case CAIRO_PATTERN_SURFACE: {
- cairo_image_surface_t *image;
+
+ src_alpha = 1.0;
+ src_opaque = TRUE;
+ }
+ else
+ {
+ if (mask)
+ {
+ src_opaque = mask_opaque && src_opaque;
+ src_alpha = mask->alpha * src->alpha;
+ /* FIXME: This needs changing when we support RENDER
+ * style 4-channel masks.
+ */
+ if (mask->type == CAIRO_PATTERN_SOLID)
+ mask = NULL;
+ } else
+ src_alpha = src->alpha;
+
+ mask_alpha = 1.0;
+ mask_opaque = TRUE;
+ }
- image = _cairo_surface_get_image (pattern->u.surface.surface);
- if (image)
- surface = &image->base;
+ _cairo_pattern_init_copy (&tmp.base, src);
+ _cairo_pattern_set_alpha (&tmp.base, src_alpha);
+
+ status = _cairo_pattern_acquire_surface (&tmp.base, dst,
+ src_x, src_y,
+ width, height,
+ src_out, src_attributes);
+
+ _cairo_pattern_fini (&tmp.base);
+
+ if (status)
+ return status;
+
+ if (mask || !mask_opaque)
+ {
+ if (mask)
+ _cairo_pattern_init_copy (&tmp.base, mask);
else
- surface = NULL;
+ _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
+
+ _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
+
+ status = _cairo_pattern_acquire_surface (&tmp.base, dst,
+ mask_x, mask_y,
+ width, height,
+ mask_out, mask_attributes);
+ _cairo_pattern_fini (&tmp.base);
+
+ if (status)
+ {
+ _cairo_pattern_release_surface (dst, *src_out, src_attributes);
+ return status;
+ }
}
- break;
- default:
- surface = NULL;
- break;
+ else
+ {
+ *mask_out = NULL;
}
-
- return (cairo_image_surface_t *) surface;
+
+ return CAIRO_STATUS_SUCCESS;
}
-
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 23230aa74..fee918355 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -36,9 +36,8 @@
#include "cairoint.h"
#include "cairo-pdf.h"
-/* XXX: This seems broken to me. What about users without freetype
- * that want to use a cairo PDF surface? */
-#include "cairo-ft.h"
+/* XXX: Eventually, we need to handle other font backends */
+#include "cairo-ft-private.h"
#include <ft2build.h>
#include FT_FREETYPE_H
@@ -54,10 +53,6 @@
* - Why doesn't pages inherit /alpha%d GS dictionaries from the Pages
* object?
*
- * - Why isn't the pattern passed to composite traps instead of
- * pattern->source? If composite traps needs an image or a surface it
- * can call create_pattern().
- *
* - We embed an image in the stream each time it's composited. We
* could add generation counters to surfaces and remember the stream
* ID for a particular generation for a particular surface.
@@ -183,9 +178,6 @@ struct cairo_pdf_surface {
double width_inches;
double height_inches;
- /* HACK: Non-null if this surface was created for a pattern. */
- cairo_pattern_t *pattern;
-
cairo_pdf_document_t *document;
cairo_pdf_stream_t *current_stream;
@@ -240,8 +232,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend;
#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) )
#define SFNT_VERSION 0x00010000
-#define OFFSET_TABLE_SIZE 12
-#define TABLE_DIRECTORY_ENTRY_SIZE 16
#ifdef WORDS_BIGENDIAN
@@ -300,19 +290,15 @@ cairo_pdf_font_destroy (cairo_pdf_font_t *font)
}
static cairo_pdf_font_t *
-cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
- cairo_unscaled_font_t *unscaled_font,
- cairo_font_scale_t *scale)
+cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
+ cairo_unscaled_font_t *unscaled_font)
{
- cairo_font_t scaled_font;
FT_Face face;
cairo_pdf_ft_font_t *font;
unsigned long size;
int i, j;
- /* FIXME: Why do I have to pass a scaled font to get the FT_Face? */
- _cairo_font_init (&scaled_font, scale, unscaled_font);
- face = cairo_ft_font_face (&scaled_font);
+ face = _cairo_ft_unscaled_font_lock_face (unscaled_font);
/* We currently only support freetype truetype fonts. */
size = 0;
@@ -333,7 +319,8 @@ cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
goto fail1;
- font->face = face;
+ font->base.unscaled_font = unscaled_font;
+ _cairo_unscaled_font_reference (unscaled_font);
font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
if (font->glyphs == NULL)
goto fail2;
@@ -364,6 +351,8 @@ cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
if (font->base.widths == NULL)
goto fail5;
+ _cairo_ft_unscaled_font_unlock_face (unscaled_font);
+
font->status = CAIRO_STATUS_SUCCESS;
return &font->base;
@@ -447,7 +436,7 @@ cairo_pdf_ft_font_write_cmap_table (cairo_pdf_ft_font_t *font, unsigned long tag
cairo_pdf_ft_font_write_be16 (font, 0);
cairo_pdf_ft_font_write_be16 (font, 1);
- cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 1);
cairo_pdf_ft_font_write_be16 (font, 0);
cairo_pdf_ft_font_write_be32 (font, 12);
@@ -764,12 +753,15 @@ cairo_pdf_ft_font_generate (void *abstract_font,
unsigned long start, end, next, checksum;
int i;
+ font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font);
+
if (cairo_pdf_ft_font_write_offset_table (font))
- return font->status;
+ goto fail;
start = cairo_pdf_ft_font_align_output (font);
end = start;
+ end = 0;
for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) {
if (truetype_tables[i].write (font, truetype_tables[i].tag))
goto fail;
@@ -789,6 +781,9 @@ cairo_pdf_ft_font_generate (void *abstract_font,
*length = _cairo_array_num_elements (&font->output);
fail:
+ _cairo_ft_unscaled_font_unlock_face (font->base.unscaled_font);
+ font->face = NULL;
+
return font->status;
}
@@ -947,14 +942,13 @@ _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
surface->width_inches = width_inches;
surface->height_inches = height_inches;
- surface->pattern = NULL;
_cairo_pdf_document_reference (document);
surface->document = document;
_cairo_array_init (&surface->streams, sizeof (cairo_pdf_stream_t *));
_cairo_array_init (&surface->patterns, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&surface->alphas, sizeof (double));
- _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
+ _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_resource_t));
return &surface->base;
}
@@ -1102,38 +1096,46 @@ _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface)
}
}
-static cairo_image_surface_t *
-_cairo_pdf_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_cairo_pdf_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
- return NULL;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_status_t
-_cairo_pdf_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+static void
+_cairo_pdf_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_status_t
-_cairo_pdf_surface_set_matrix (void *abstract_surface,
- cairo_matrix_t *matrix)
+_cairo_pdf_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect,
+ void **image_extra)
{
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_status_t
-_cairo_pdf_surface_set_filter (void *abstract_surface,
- cairo_filter_t filter)
+static void
+_cairo_pdf_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
{
- return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_pdf_surface_set_repeat (void *abstract_surface,
- int repeat)
+_cairo_pdf_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
static void *
@@ -1210,23 +1212,34 @@ emit_image_data (cairo_pdf_document_t *document,
}
static cairo_int_status_t
-_cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
- cairo_image_surface_t *image)
+_cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
+ cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
FILE *file = document->file;
unsigned id;
cairo_matrix_t i2u;
+ cairo_status_t status;
+ cairo_image_surface_t *image;
+ cairo_surface_t *src;
+ void *image_extra;
+
+ src = pattern->surface;
+ status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
+ if (!CAIRO_OK (status))
+ return status;
id = emit_image_data (dst->document, image);
- if (id == 0)
- return CAIRO_STATUS_NO_MEMORY;
+ if (id == 0) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto bail;
+ }
_cairo_pdf_surface_add_xobject (dst, id);
_cairo_pdf_surface_ensure_stream (dst);
- cairo_matrix_copy (&i2u, &image->base.matrix);
+ cairo_matrix_copy (&i2u, &pattern->base.matrix);
cairo_matrix_invert (&i2u);
cairo_matrix_translate (&i2u, 0, image->height);
cairo_matrix_scale (&i2u, image->width, -image->height);
@@ -1238,7 +1251,10 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
i2u.m[2][0], i2u.m[2][1],
id);
- return CAIRO_STATUS_SUCCESS;
+ bail:
+ _cairo_surface_release_source_image (src, image, image_extra);
+
+ return status;
}
/* The contents of the surface is already transformed into PDF units,
@@ -1253,20 +1269,19 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
static cairo_int_status_t
_cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
- cairo_pdf_surface_t *src,
- int width, int height)
+ cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
FILE *file = document->file;
cairo_matrix_t i2u;
cairo_pdf_stream_t *stream;
int num_streams, i;
-
- if (src->pattern != NULL)
- return CAIRO_STATUS_SUCCESS;
+ cairo_pdf_surface_t *src;
_cairo_pdf_surface_ensure_stream (dst);
+ src = (cairo_pdf_surface_t *) pattern->surface;
+
cairo_matrix_copy (&i2u, &src->base.matrix);
cairo_matrix_invert (&i2u);
cairo_matrix_scale (&i2u,
@@ -1297,8 +1312,8 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
static cairo_int_status_t
_cairo_pdf_surface_composite (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
+ cairo_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
void *abstract_dst,
int src_x,
int src_y,
@@ -1310,17 +1325,18 @@ _cairo_pdf_surface_composite (cairo_operator_t operator,
unsigned int height)
{
cairo_pdf_surface_t *dst = abstract_dst;
- cairo_pdf_surface_t *src;
- cairo_image_surface_t *image;
+ cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) src_pattern;
- if (generic_src->backend == &cairo_pdf_surface_backend) {
- src = (cairo_pdf_surface_t *) generic_src;
- return _cairo_pdf_surface_composite_pdf (dst, src, width, height);
- }
- else {
- image = _cairo_surface_get_image (generic_src);
- return _cairo_pdf_surface_composite_image (dst, image);
- }
+ if (mask_pattern)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (src_pattern->type != CAIRO_PATTERN_SURFACE)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (src->surface->backend == &cairo_pdf_surface_backend)
+ return _cairo_pdf_surface_composite_pdf (dst, src);
+ else
+ return _cairo_pdf_surface_composite_image (dst, src);
}
static cairo_int_status_t
@@ -1335,9 +1351,6 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface,
FILE *file = document->file;
int i;
- if (surface->pattern != NULL)
- return CAIRO_STATUS_SUCCESS;
-
_cairo_pdf_surface_ensure_stream (surface);
fprintf (file,
@@ -1355,23 +1368,44 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface,
}
static void
-emit_tiling_pattern (cairo_operator_t operator,
- cairo_pdf_surface_t *dst,
- cairo_pattern_t *pattern)
+emit_solid_pattern (cairo_pdf_surface_t *surface,
+ cairo_solid_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ unsigned int alpha;
+
+ alpha = _cairo_pdf_surface_add_alpha (surface, pattern->base.alpha);
+ _cairo_pdf_surface_ensure_stream (surface);
+ fprintf (file,
+ "%f %f %f rg /a%d gs\r\n",
+ pattern->red,
+ pattern->green,
+ pattern->blue,
+ alpha);
+}
+
+static void
+emit_surface_pattern (cairo_pdf_surface_t *dst,
+ cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
FILE *file = document->file;
cairo_pdf_stream_t *stream;
cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_status_t status;
char entries[250];
unsigned int id, alpha;
cairo_matrix_t pm;
- if (pattern->u.surface.surface->backend == &cairo_pdf_surface_backend) {
+ if (pattern->surface->backend == &cairo_pdf_surface_backend) {
return;
}
-
- image = _cairo_surface_get_image (pattern->u.surface.surface);
+
+ status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
+ if (!CAIRO_OK (status))
+ return;
_cairo_pdf_document_close_stream (document);
@@ -1382,7 +1416,7 @@ emit_tiling_pattern (cairo_operator_t operator,
cairo_matrix_set_identity (&pm);
cairo_matrix_scale (&pm, image->width, image->height);
- cairo_matrix_copy (&pm, &pattern->matrix);
+ cairo_matrix_copy (&pm, &pattern->base.matrix);
cairo_matrix_invert (&pm);
snprintf (entries, sizeof entries,
@@ -1401,6 +1435,8 @@ emit_tiling_pattern (cairo_operator_t operator,
stream = _cairo_pdf_document_open_stream (document, entries);
+ /* FIXME: emit code to show surface here. */
+
_cairo_pdf_surface_add_pattern (dst, stream->id);
_cairo_pdf_surface_ensure_stream (dst);
@@ -1408,10 +1444,12 @@ emit_tiling_pattern (cairo_operator_t operator,
fprintf (file,
"/Pattern cs /res%d scn /a%d gs\r\n",
stream->id, alpha);
+
+ _cairo_surface_release_source_image (pattern->surface, image, image_extra);
}
static unsigned int
-emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
FILE *file = document->file;
@@ -1430,12 +1468,12 @@ emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
"stream\r\n",
function_id);
- fputc (pattern->stops[0].color_char[0], file);
- fputc (pattern->stops[0].color_char[1], file);
- fputc (pattern->stops[0].color_char[2], file);
- fputc (pattern->stops[1].color_char[0], file);
- fputc (pattern->stops[1].color_char[1], file);
- fputc (pattern->stops[1].color_char[2], file);
+ fputc (pattern->stops[0].color.red * 0xff, file);
+ fputc (pattern->stops[0].color.green * 0xff, file);
+ fputc (pattern->stops[0].color.blue * 0xff, file);
+ fputc (pattern->stops[1].color.red * 0xff, file);
+ fputc (pattern->stops[1].color.green * 0xff, file);
+ fputc (pattern->stops[1].color.blue * 0xff, file);
fprintf (file,
"\r\n"
@@ -1446,7 +1484,7 @@ emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
}
static void
-emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
FILE *file = document->file;
@@ -1456,16 +1494,16 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
_cairo_pdf_document_close_stream (document);
- function_id = emit_pattern_stops (surface, pattern);
+ function_id = emit_pattern_stops (surface, &pattern->base);
- cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
cairo_matrix_invert (&p2u);
- x0 = pattern->u.linear.point0.x;
- y0 = pattern->u.linear.point0.y;
+ x0 = pattern->point0.x;
+ y0 = pattern->point0.y;
cairo_matrix_transform_point (&p2u, &x0, &y0);
- x1 = pattern->u.linear.point1.x;
- y1 = pattern->u.linear.point1.y;
+ x1 = pattern->point1.x;
+ y1 = pattern->point1.y;
cairo_matrix_transform_point (&p2u, &x1, &y1);
pattern_id = _cairo_pdf_document_new_object (document);
@@ -1479,16 +1517,14 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
" /ColorSpace /DeviceRGB\r\n"
" /Coords [ %f %f %f %f ]\r\n"
" /Function %d 0 R\r\n"
- " /Extend [ %s %s ]\r\n"
+ " /Extend [ true true ]\r\n"
" >>\r\n"
">>\r\n"
"endobj\r\n",
pattern_id,
document->height_inches * document->y_ppi,
x0, y0, x1, y1,
- function_id,
- (1 || pattern->extend) ? "true" : "false",
- (1 || pattern->extend) ? "true" : "false");
+ function_id);
_cairo_pdf_surface_add_pattern (surface, pattern_id);
@@ -1502,7 +1538,7 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
}
static void
-emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
FILE *file = document->file;
@@ -1512,24 +1548,31 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
_cairo_pdf_document_close_stream (document);
- function_id = emit_pattern_stops (surface, pattern);
+ function_id = emit_pattern_stops (surface, &pattern->base);
- cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
cairo_matrix_invert (&p2u);
- x0 = pattern->u.radial.center0.x;
- y0 = pattern->u.radial.center0.y;
- r0 = pattern->u.radial.radius0;
+ x0 = pattern->center0.x;
+ y0 = pattern->center0.y;
+ r0 = pattern->radius0;
cairo_matrix_transform_point (&p2u, &x0, &y0);
- x1 = pattern->u.radial.center1.x;
- y1 = pattern->u.radial.center1.y;
- r1 = pattern->u.radial.radius1;
+ x1 = pattern->center1.x;
+ y1 = pattern->center1.y;
+ r1 = pattern->radius1;
cairo_matrix_transform_point (&p2u, &x1, &y1);
/* FIXME: This is surely crack, but how should you scale a radius
* in a non-orthogonal coordinate system? */
cairo_matrix_transform_distance (&p2u, &r0, &r1);
+ /* FIXME: There is a difference between the cairo gradient extend
+ * semantics and PDF extend semantics. PDFs extend=false means
+ * that nothing is painted outside the gradient boundaries,
+ * whereas cairo takes this to mean that the end color is padded
+ * to infinity. Setting extend=true in PDF gives the cairo default
+ * behavoir, not yet sure how to implement the cairo mirror and
+ * repeat behaviour. */
pattern_id = _cairo_pdf_document_new_object (document);
fprintf (file,
"%d 0 obj\r\n"
@@ -1541,16 +1584,14 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
" /ColorSpace /DeviceRGB\r\n"
" /Coords [ %f %f %f %f %f %f ]\r\n"
" /Function %d 0 R\r\n"
- " /Extend [ %s %s ]\r\n"
+ " /Extend [ true true ]\r\n"
" >>\r\n"
">>\r\n"
"endobj\r\n",
pattern_id,
document->height_inches * document->y_ppi,
x0, y0, r0, x1, y1, r1,
- function_id,
- (1 || pattern->extend) ? "true" : "false",
- (1 || pattern->extend) ? "true" : "false");
+ function_id);
_cairo_pdf_surface_add_pattern (surface, pattern_id);
@@ -1563,6 +1604,28 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
pattern_id, alpha);
}
+static void
+emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+{
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SOLID:
+ emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
+ break;
+
+ case CAIRO_PATTERN_SURFACE:
+ emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
+ break;
+
+ case CAIRO_PATTERN_LINEAR:
+ emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
+ break;
+
+ case CAIRO_PATTERN_RADIAL:
+ emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
+ break;
+ }
+}
+
static double
intersect (cairo_line_t *line, cairo_fixed_t y)
{
@@ -1574,60 +1637,23 @@ intersect (cairo_line_t *line, cairo_fixed_t y)
static cairo_int_status_t
_cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *generic_src,
+ cairo_pattern_t *pattern,
void *abstract_dst,
int x_src,
int y_src,
+ int x_dst,
+ int y_dst,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
cairo_pdf_surface_t *surface = abstract_dst;
- cairo_pdf_surface_t *source = (cairo_pdf_surface_t *) generic_src;
cairo_pdf_document_t *document = surface->document;
- cairo_pattern_t *pattern;
FILE *file = document->file;
int i;
- unsigned int alpha;
- /* FIXME: we really just want the original pattern here, not a
- * source surface. */
- pattern = source->pattern;
-
- if (source->base.backend != &cairo_pdf_surface_backend) {
- printf ("_cairo_pdf_surface_composite_trapezoids: not a pdf source\r");
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (pattern == NULL) {
- printf ("_cairo_pdf_surface_composite_trapezoids: "
- "non-pattern pdf source\r");
- return CAIRO_STATUS_SUCCESS;
- }
-
- switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
- alpha = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha);
- _cairo_pdf_surface_ensure_stream (surface);
- fprintf (file,
- "%f %f %f rg /a%d gs\r\n",
- pattern->color.red,
- pattern->color.green,
- pattern->color.blue,
- alpha);
- break;
-
- case CAIRO_PATTERN_SURFACE:
- emit_tiling_pattern (operator, surface, pattern);
- break;
-
- case CAIRO_PATTERN_LINEAR:
- emit_linear_pattern (surface, pattern);
- break;
-
- case CAIRO_PATTERN_RADIAL:
- emit_radial_pattern (surface, pattern );
- break;
- }
+ emit_pattern (surface, pattern);
/* After the above switch the current stream should belong to this
* surface, so no need to _cairo_pdf_surface_ensure_stream() */
@@ -1686,59 +1712,48 @@ _cairo_pdf_surface_set_clip_region (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_int_status_t
-_cairo_pdf_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
- cairo_pdf_surface_t *source;
-
- source = (cairo_pdf_surface_t *)
- _cairo_pdf_surface_create_for_document (surface->document, 0, 0);
- source->pattern = pattern;
- pattern->source = &source->base;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_pdf_font_t *
_cairo_pdf_document_get_font (cairo_pdf_document_t *document,
- cairo_unscaled_font_t *unscaled_font,
- cairo_font_scale_t *scale)
+ cairo_font_t *font)
{
- cairo_pdf_font_t *font;
+ cairo_unscaled_font_t *unscaled_font;
+ cairo_pdf_font_t *pdf_font;
unsigned int num_fonts, i;
+ unscaled_font = _cairo_ft_font_get_unscaled_font (font);
+
num_fonts = _cairo_array_num_elements (&document->fonts);
for (i = 0; i < num_fonts; i++) {
- _cairo_array_copy_element (&document->fonts, i, &font);
- if (font->unscaled_font == unscaled_font)
- return font;
+ _cairo_array_copy_element (&document->fonts, i, &pdf_font);
+ if (pdf_font->unscaled_font == unscaled_font)
+ return pdf_font;
}
/* FIXME: Figure out here which font backend is in use and call
* the appropriate constructor. */
- font = cairo_pdf_ft_font_create (document, unscaled_font, scale);
- if (font == NULL)
+ pdf_font = cairo_pdf_ft_font_create (document, unscaled_font);
+ if (pdf_font == NULL)
return NULL;
- if (_cairo_array_append (&document->fonts, &font, 1) == NULL) {
- cairo_pdf_font_destroy (font);
+ if (_cairo_array_append (&document->fonts, &pdf_font, 1) == NULL) {
+ cairo_pdf_font_destroy (pdf_font);
return NULL;
}
- return font;
+ return pdf_font;
}
static cairo_status_t
-_cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
+_cairo_pdf_surface_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
- cairo_surface_t *source,
+ cairo_pattern_t *pattern,
void *abstract_surface,
int source_x,
int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
@@ -1748,23 +1763,23 @@ _cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font,
cairo_pdf_font_t *pdf_font;
int i, index;
- pdf_font = _cairo_pdf_document_get_font (document, font, scale);
+ pdf_font = _cairo_pdf_document_get_font (document, font);
if (pdf_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
- _cairo_pdf_surface_ensure_stream (surface);
+ emit_pattern (surface, pattern);
- fprintf (file, "0 0 0 rg BT /res%u 1 Tf", pdf_font->font_id);
+ fprintf (file, "BT /res%u 1 Tf", pdf_font->font_id);
for (i = 0; i < num_glyphs; i++) {
index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index);
fprintf (file,
- " %f %f %f %f %f %f Tm (%c) Tj",
- scale->matrix[0][0],
- scale->matrix[0][1],
- scale->matrix[1][0],
- -scale->matrix[1][1],
+ " %f %f %f %f %f %f Tm (\\%o) Tj",
+ font->scale.matrix[0][0],
+ font->scale.matrix[0][1],
+ font->scale.matrix[1][0],
+ -font->scale.matrix[1][1],
glyphs[i].x,
glyphs[i].y,
index);
@@ -1780,18 +1795,17 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
_cairo_pdf_surface_create_similar,
_cairo_pdf_surface_destroy,
_cairo_pdf_surface_pixels_per_inch,
- _cairo_pdf_surface_get_image,
- _cairo_pdf_surface_set_image,
- _cairo_pdf_surface_set_matrix,
- _cairo_pdf_surface_set_filter,
- _cairo_pdf_surface_set_repeat,
+ _cairo_pdf_surface_acquire_source_image,
+ _cairo_pdf_surface_release_source_image,
+ _cairo_pdf_surface_acquire_dest_image,
+ _cairo_pdf_surface_release_dest_image,
+ _cairo_pdf_surface_clone_similar,
_cairo_pdf_surface_composite,
_cairo_pdf_surface_fill_rectangles,
_cairo_pdf_surface_composite_trapezoids,
_cairo_pdf_surface_copy_page,
_cairo_pdf_surface_show_page,
_cairo_pdf_surface_set_clip_region,
- _cairo_pdf_surface_create_pattern,
_cairo_pdf_surface_show_glyphs
};
@@ -1930,8 +1944,8 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
fprintf (file,
"%d 0 obj\r\n"
"<< /Type /FontDescriptor\r\n"
- " /FontName /%s\r\n"
- " /Flags 32\r\n"
+ " /FontName /7%s\r\n"
+ " /Flags 4\r\n"
" /FontBBox [ %ld %ld %ld %ld ]\r\n"
" /ItalicAngle 0\r\n"
" /Ascent %ld\r\n"
diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h
index 0f624af31..701a7b4a7 100644
--- a/src/cairo-pdf.h
+++ b/src/cairo-pdf.h
@@ -31,17 +31,20 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
-#include <cairo.h>
-
#ifndef CAIRO_PDF_H
#define CAIRO_PDF_H
+
+#include <cairo.h>
+
#ifdef CAIRO_HAS_PDF_SURFACE
#include <stdio.h>
+CAIRO_BEGIN_DECLS
+
void
cairo_set_target_pdf (cairo_t *cr,
FILE *file,
@@ -58,5 +61,7 @@ cairo_pdf_surface_create (FILE *file,
double x_pixels_per_inch,
double y_pixels_per_inch);
+CAIRO_END_DECLS
+
#endif /* CAIRO_HAS_PDF_SURFACE */
#endif /* CAIRO_PDF_H */
diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index f365091dc..6ecaa00b3 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo-png.h b/src/cairo-png.h
index 766d6f91f..3e86210b0 100644
--- a/src/cairo-png.h
+++ b/src/cairo-png.h
@@ -31,17 +31,20 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
-#include <cairo.h>
-
#ifndef CAIRO_PNG_H
#define CAIRO_PNG_H
-#ifdef CAIRO_HAS_PNG_SURFACE
+
+#include <cairo.h>
+
+#ifdef CAIRO_HAS_PNG_SURFACE
#include <stdio.h>
+CAIRO_BEGIN_DECLS
+
void
cairo_set_target_png (cairo_t *cr,
FILE *file,
@@ -55,5 +58,7 @@ cairo_png_surface_create (FILE *file,
int width,
int height);
+CAIRO_END_DECLS
+
#endif /* CAIRO_HAS_PNG_SURFACE */
#endif /* CAIRO_PNG_H */
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index e85858033..59c615da2 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include <stdlib.h>
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 4da8162c7..4a45fc679 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
@@ -42,6 +42,22 @@
static const cairo_surface_backend_t cairo_ps_surface_backend;
+/**
+ * cairo_set_target_ps:
+ * @cr: a #cairo_t
+ * @file: an open, writeable file
+ * @width_inches: width of the output page, in inches
+ * @height_inches: height of the output page, in inches
+ * @x_pixels_per_inch: X resolution to use for image fallbacks;
+ * not all Cairo drawing can be represented in a postscript
+ * file, so Cairo will write out images for some portions
+ * of the output.
+ * @y_pixels_per_inch: Y resolution to use for image fallbacks.
+ *
+ * Directs output for a #cairo_t to a postscript file. The file must
+ * be kept open until the #cairo_t is destroyed or set to have a
+ * different target, and then must be closed by the application.
+ **/
void
cairo_set_target_ps (cairo_t *cr,
FILE *file,
@@ -192,62 +208,65 @@ _cairo_ps_surface_pixels_per_inch (void *abstract_surface)
return surface->y_ppi;
}
-static cairo_image_surface_t *
-_cairo_ps_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_cairo_ps_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
cairo_ps_surface_t *surface = abstract_surface;
+
+ *image_out = surface->image;
- cairo_surface_reference (&surface->image->base);
-
- return surface->image;
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_ps_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+static void
+_cairo_ps_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
{
- cairo_ps_surface_t *surface = abstract_surface;
-
- if (image == surface->image)
- return CAIRO_STATUS_SUCCESS;
-
- /* XXX: Need to call _cairo_image_surface_set_image here, but it's
- not implemented yet. */
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_status_t
-_cairo_ps_surface_set_matrix (void *abstract_surface,
- cairo_matrix_t *matrix)
+_cairo_ps_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect,
+ void **image_extra)
{
cairo_ps_surface_t *surface = abstract_surface;
+
+ image_rect->x = 0;
+ image_rect->y = 0;
+ image_rect->width = surface->image->width;
+ image_rect->height = surface->image->height;
+
+ *image_out = surface->image;
- return _cairo_image_surface_set_matrix (surface->image, matrix);
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_ps_surface_set_filter (void *abstract_surface,
- cairo_filter_t filter)
+static void
+_cairo_ps_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
{
- cairo_ps_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_filter (surface->image, filter);
}
static cairo_status_t
-_cairo_ps_surface_set_repeat (void *abstract_surface,
- int repeat)
+_cairo_ps_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
- cairo_ps_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_repeat (surface->image, repeat);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_ps_surface_composite (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
+ cairo_pattern_t *src,
+ cairo_pattern_t *mask,
void *abstract_dst,
int src_x,
int src_y,
@@ -273,10 +292,14 @@ _cairo_ps_surface_fill_rectangles (void *abstract_surface,
static cairo_int_status_t
_cairo_ps_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *generic_src,
+ cairo_pattern_t *generic_src,
void *abstract_dst,
int x_src,
int y_src,
+ int x_dst,
+ int y_dst,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
@@ -294,12 +317,10 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
int i, x, y;
- cairo_surface_t *white_surface;
+ cairo_solid_pattern_t white_pattern;
char *rgb, *compressed;
long rgb_size, compressed_size;
- cairo_color_t white;
-
rgb_size = 3 * width * height;
rgb = malloc (rgb_size);
if (rgb == NULL) {
@@ -316,26 +337,19 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
/* PostScript can not represent the alpha channel, so we blend the
current image over a white RGB surface to eliminate it. */
- white_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
- if (white_surface == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL2;
- }
- _cairo_color_init (&white);
- _cairo_surface_fill_rectangle (white_surface,
- CAIRO_OPERATOR_SRC,
- &white,
- 0, 0, 1, 1);
- cairo_surface_set_repeat (white_surface, 1);
+ _cairo_pattern_init_solid (&white_pattern, 1.0, 1.0, 1.0);
+
_cairo_surface_composite (CAIRO_OPERATOR_OVER_REVERSE,
- white_surface,
+ &white_pattern.base,
NULL,
&surface->image->base,
0, 0,
0, 0,
0, 0,
width, height);
+
+ _cairo_pattern_fini (&white_pattern.base);
i = 0;
for (y = 0; y < height; y++) {
@@ -379,8 +393,6 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
/* Page footer */
fprintf (file, "%%%%EndPage\n");
- cairo_surface_destroy (white_surface);
- BAIL2:
free (compressed);
BAIL1:
free (rgb);
@@ -412,29 +424,20 @@ _cairo_ps_surface_set_clip_region (void *abstract_surface,
return _cairo_image_surface_set_clip_region (surface->image, region);
}
-static cairo_int_status_t
-_cairo_ps_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static const cairo_surface_backend_t cairo_ps_surface_backend = {
_cairo_ps_surface_create_similar,
_cairo_ps_surface_destroy,
_cairo_ps_surface_pixels_per_inch,
- _cairo_ps_surface_get_image,
- _cairo_ps_surface_set_image,
- _cairo_ps_surface_set_matrix,
- _cairo_ps_surface_set_filter,
- _cairo_ps_surface_set_repeat,
+ _cairo_ps_surface_acquire_source_image,
+ _cairo_ps_surface_release_source_image,
+ _cairo_ps_surface_acquire_dest_image,
+ _cairo_ps_surface_release_dest_image,
+ _cairo_ps_surface_clone_similar,
_cairo_ps_surface_composite,
_cairo_ps_surface_fill_rectangles,
_cairo_ps_surface_composite_trapezoids,
_cairo_ps_surface_copy_page,
_cairo_ps_surface_show_page,
_cairo_ps_surface_set_clip_region,
- _cairo_ps_surface_create_pattern,
NULL /* show_glyphs */
};
diff --git a/src/cairo-ps.h b/src/cairo-ps.h
index ae8e72192..88382920e 100644
--- a/src/cairo-ps.h
+++ b/src/cairo-ps.h
@@ -31,17 +31,20 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
-#include <cairo.h>
-
#ifndef CAIRO_PS_H
#define CAIRO_PS_H
+
+#include <cairo.h>
+
#ifdef CAIRO_HAS_PS_SURFACE
#include <stdio.h>
+CAIRO_BEGIN_DECLS
+
void
cairo_set_target_ps (cairo_t *cr,
FILE *file,
@@ -59,5 +62,7 @@ cairo_ps_surface_create (FILE *file,
double x_pixels_per_inch,
double y_pixels_per_inch);
+CAIRO_END_DECLS
+
#endif /* CAIRO_HAS_PS_SURFACE */
#endif /* CAIRO_PS_H */
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index b7103b051..01b345cdc 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2004 Calum Robinson
+ * Copyright © 2004 Calum Robinson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
diff --git a/src/cairo-quartz.h b/src/cairo-quartz.h
index 918bc18d7..5afd46426 100644
--- a/src/cairo-quartz.h
+++ b/src/cairo-quartz.h
@@ -31,17 +31,20 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
-#include <cairo.h>
-
#ifndef CAIRO_QUARTZ_H
#define CAIRO_QUARTZ_H
+
+#include <cairo.h>
+
#ifdef CAIRO_HAS_QUARTZ_SURFACE
#include <Carbon/Carbon.h>
+CAIRO_BEGIN_DECLS
+
void
cairo_set_target_quartz_context( cairo_t *cr,
CGContextRef context,
@@ -53,6 +56,8 @@ cairo_quartz_surface_create ( CGContextRef context,
int width,
int height);
+CAIRO_END_DECLS
+
#endif /* CAIRO_HAS_QUARTZ_SURFACE */
#endif /* CAIRO_QUARTZ_H */
diff --git a/src/cairo-slope.c b/src/cairo-slope.c
index 1a1497988..a2edec038 100644
--- a/src/cairo-slope.c
+++ b/src/cairo-slope.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo-spline.c b/src/cairo-spline.c
index ff290d9dd..5119a8e2b 100644
--- a/src/cairo-spline.c
+++ b/src/cairo-spline.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index a457d2062..330d58b1e 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include <stdlib.h>
@@ -151,16 +151,151 @@ _cairo_surface_pixels_per_inch (cairo_surface_t *surface)
return surface->backend->pixels_per_inch (surface);
}
-cairo_image_surface_t *
-_cairo_surface_get_image (cairo_surface_t *surface)
+/**
+ * _cairo_surface_acquire_source_image:
+ * @surface: a #cairo_surface_t
+ * @image_out: location to store a pointer to an image surface that includes at least
+ * the intersection of @interest_rect with the visible area of @surface.
+ * This surface could be @surface itself, a surface held internal to @surface,
+ * or it could be a new surface with a copy of the relevant portion of @surface.
+ * @image_extra: location to store image specific backend data
+ *
+ * Gets an image surface to use when drawing as a fallback when drawing with
+ * @surface as a source. _cairo_surface_release_source_image() must be called
+ * when finished.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if a an image was stored in @image_out.
+ * %CAIRO_INT_STATUS_UNSUPPORTED if an image cannot be retrieved for the specified
+ * surface. Or %CAIRO_STATUS_NO_MEMORY.
+ **/
+cairo_private cairo_status_t
+_cairo_surface_acquire_source_image (cairo_surface_t *surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
- return surface->backend->get_image (surface);
+ return surface->backend->acquire_source_image (surface, image_out, image_extra);
}
+/**
+ * _cairo_surface_release_source_image:
+ * @surface: a #cairo_surface_t
+ * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image()
+ *
+ * Releases any resources obtained with _cairo_surface_acquire_source_image()
+ **/
+cairo_private void
+_cairo_surface_release_source_image (cairo_surface_t *surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ surface->backend->release_source_image (surface, image, image_extra);
+}
+
+/**
+ * _cairo_surface_acquire_dest_image:
+ * @surface: a #cairo_surface_t
+ * @interest_rect: area of @surface for which fallback drawing is being done.
+ * A value of %NULL indicates that the entire surface is desired.
+ * @image_out: location to store a pointer to an image surface that includes at least
+ * the intersection of @interest_rect with the visible area of @surface.
+ * This surface could be @surface itself, a surface held internal to @surface,
+ * or it could be a new surface with a copy of the relevant portion of @surface.
+ * @image_rect: location to store area of the original surface occupied
+ * by the surface stored in @image.
+ * @image_extra: location to store image specific backend data
+ *
+ * Retrieves a local image for a surface for implementing a fallback drawing
+ * operation. After calling this function, the implementation of the fallback
+ * drawing operation draws the primitive to the surface stored in @image_out
+ * then calls _cairo_surface_release_dest_fallback(),
+ * which, if a temporary surface was created, copies the bits back to the
+ * main surface and frees the temporary surface.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY.
+ * %CAIRO_INT_STATUS_UNSUPPORTED can be returned but this will mean that
+ * the backend can't draw with fallbacks. It's possible for the routine
+ * to store NULL in @local_out and return %CAIRO_STATUS_SUCCESS;
+ * that indicates that no part of @interest_rect is visible, so no drawing
+ * is necessary. _cairo_surface_release_dest_fallback() should not be called in that
+ * case.
+ **/
+cairo_status_t
+_cairo_surface_acquire_dest_image (cairo_surface_t *surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect,
+ void **image_extra)
+{
+ return surface->backend->acquire_dest_image (surface, interest_rect,
+ image_out, image_rect, image_extra);
+}
+
+/**
+ * _cairo_surface_end_fallback:
+ * @surface: a #cairo_surface_t
+ * @interest_rect: same as passed to the matching _cairo_surface_acquire_dest_image()
+ * @image: same as returned from the matching _cairo_surface_acquire_dest_image()
+ * @image_rect: same as returned from the matching _cairo_surface_acquire_dest_image()
+ * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image()
+ *
+ * Finishes the operation started with _cairo_surface_acquire_dest_image(), by, if
+ * necessary, copying the image from @image back to @surface and freeing any
+ * resources that were allocated.
+ **/
+void
+_cairo_surface_release_dest_image (cairo_surface_t *surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+ surface->backend->release_dest_image (surface, interest_rect,
+ image, image_rect, image_extra);
+}
+
+/**
+ * _cairo_surface_clone_similar:
+ * @surface: a #cairo_surface_t
+ * @src: the source image
+ * @clone_out: location to store a surface compatible with @surface
+ * and with contents identical to @src. The caller must call
+ * cairo_surface_destroy() on the result.
+ *
+ * Creates a surface with contents identical to @src but that
+ * can be used efficiently with @surface. If @surface and @src are
+ * already compatible then it may return a new reference to @src.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if a surface was created and stored
+ * in @clone_out. Otherwise %CAIRO_INT_STATUS_UNSUPPORTED or another
+ * error like %CAIRO_STATUS_NO_MEMORY.
+ **/
cairo_status_t
-_cairo_surface_set_image (cairo_surface_t *surface, cairo_image_surface_t *image)
+_cairo_surface_clone_similar (cairo_surface_t *surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
- return surface->backend->set_image (surface, image);
+ cairo_status_t status;
+ cairo_image_surface_t *image;
+ void *image_extra;
+
+ status = surface->backend->clone_similar (surface, src, clone_out);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
+ if (status != CAIRO_STATUS_SUCCESS)
+ return status;
+
+ status = surface->backend->clone_similar (surface, &image->base, clone_out);
+
+ /* If the above failed point, we could implement a full fallback
+ * using acquire_dest_image, but that's going to be very
+ * inefficient compared to a backend-specific implementation of
+ * clone_similar() with an image source. So we don't bother
+ */
+
+ _cairo_surface_release_source_image (src, image, image_extra);
+ return status;
}
cairo_status_t
@@ -169,9 +304,7 @@ cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
if (surface == NULL)
return CAIRO_STATUS_NULL_POINTER;
- cairo_matrix_copy (&surface->matrix, matrix);
-
- return surface->backend->set_matrix (surface, matrix);
+ return cairo_matrix_copy (&surface->matrix, matrix);
}
slim_hidden_def(cairo_surface_set_matrix);
@@ -192,7 +325,7 @@ cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
return CAIRO_STATUS_NULL_POINTER;
surface->filter = filter;
- return surface->backend->set_filter (surface, filter);
+ return CAIRO_STATUS_SUCCESS;
}
cairo_filter_t
@@ -224,14 +357,81 @@ cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
surface->repeat = repeat;
- return surface->backend->set_repeat (surface, repeat);
+ return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def(cairo_surface_set_repeat);
+typedef struct {
+ cairo_surface_t *dst;
+ cairo_rectangle_t extents;
+ cairo_image_surface_t *image;
+ cairo_rectangle_t image_rect;
+ void *image_extra;
+} fallback_state_t;
+
+static cairo_status_t
+_fallback_init (fallback_state_t *state,
+ cairo_surface_t *dst,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ state->extents.x = x;
+ state->extents.y = y;
+ state->extents.width = width;
+ state->extents.height = height;
+
+ state->dst = dst;
+
+ return _cairo_surface_acquire_dest_image (dst, &state->extents,
+ &state->image, &state->image_rect, &state->image_extra);
+}
+
+static void
+_fallback_cleanup (fallback_state_t *state)
+{
+ _cairo_surface_release_dest_image (state->dst, &state->extents,
+ state->image, &state->image_rect, state->image_extra);
+}
+
+static cairo_status_t
+_fallback_composite (cairo_operator_t operator,
+ cairo_pattern_t *src,
+ cairo_pattern_t *mask,
+ cairo_surface_t *dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ fallback_state_t state;
+ cairo_status_t status;
+
+ status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
+ if (!CAIRO_OK (status) || !state.image)
+ return status;
+
+ state.image->base.backend->composite (operator, src, mask,
+ &state.image->base,
+ src_x, src_y, mask_x, mask_y,
+ dst_x - state.image_rect.x,
+ dst_y - state.image_rect.y,
+ width, height);
+
+ _fallback_cleanup (&state);
+
+ return status;
+}
+
cairo_status_t
_cairo_surface_composite (cairo_operator_t operator,
- cairo_surface_t *src,
- cairo_surface_t *mask,
+ cairo_pattern_t *src,
+ cairo_pattern_t *mask,
cairo_surface_t *dst,
int src_x,
int src_y,
@@ -243,7 +443,6 @@ _cairo_surface_composite (cairo_operator_t operator,
unsigned int height)
{
cairo_int_status_t status;
- cairo_image_surface_t *src_image, *mask_image = 0, *dst_image;
status = dst->backend->composite (operator,
src, mask, dst,
@@ -254,28 +453,12 @@ _cairo_surface_composite (cairo_operator_t operator,
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- src_image = _cairo_surface_get_image (src);
- if (mask)
- mask_image = _cairo_surface_get_image (mask);
- dst_image = _cairo_surface_get_image (dst);
-
- dst_image->base.backend->composite (operator,
- &src_image->base,
- mask ? &mask_image->base : NULL,
- dst_image,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
-
- status = _cairo_surface_set_image (dst, dst_image);
-
- cairo_surface_destroy (&src_image->base);
- if (mask)
- cairo_surface_destroy (&mask_image->base);
- cairo_surface_destroy (&dst_image->base);
-
- return status;
+ return _fallback_composite (operator,
+ src, mask, dst,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
}
cairo_status_t
@@ -297,6 +480,77 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface,
return _cairo_surface_fill_rectangles (surface, operator, color, &rect, 1);
}
+static cairo_status_t
+_fallback_fill_rectangles (cairo_surface_t *surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ fallback_state_t state;
+ cairo_rectangle_t *offset_rects = NULL;
+ cairo_status_t status;
+ int x1, y1, x2, y2;
+ int i;
+
+ if (num_rects <= 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* Compute the bounds of the rectangles, so that we know what area of the
+ * destination surface to fetch
+ */
+ x1 = rects[0].x;
+ y1 = rects[0].y;
+ x2 = rects[0].x + rects[0].width;
+ y2 = rects[0].y + rects[0].height;
+
+ for (i = 1; i < num_rects; i++) {
+ if (rects[0].x < x1)
+ x1 = rects[0].x;
+ if (rects[0].y < y1)
+ y1 = rects[0].y;
+
+ if (rects[0].x + rects[0].width > x2)
+ x2 = rects[0].x + rects[0].width;
+ if (rects[0].y + rects[0].height > y2)
+ y2 = rects[0].y + rects[0].height;
+ }
+
+ status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
+ if (!CAIRO_OK (status) || !state.image)
+ return status;
+
+ /* If the fetched image isn't at 0,0, we need to offset the rectangles */
+
+ if (state.image_rect.x != 0 || state.image_rect.y != 0) {
+ offset_rects = malloc (sizeof (cairo_rectangle_t) * num_rects);
+ if (!offset_rects) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
+ for (i = 0; i < num_rects; i++) {
+ offset_rects[i].x = rects[i].x - state.image_rect.x;
+ offset_rects[i].y = rects[i].y - state.image_rect.y;
+ offset_rects[i].width = rects[i].width;
+ offset_rects[i].height = rects[i].height;
+ }
+
+ rects = offset_rects;
+ }
+
+ state.image->base.backend->fill_rectangles (&state.image->base, operator, color,
+ rects, num_rects);
+
+ if (offset_rects)
+ free (offset_rects);
+
+ FAIL:
+ _fallback_cleanup (&state);
+
+ return status;
+}
+
cairo_status_t
_cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_operator_t operator,
@@ -305,7 +559,6 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
int num_rects)
{
cairo_int_status_t status;
- cairo_image_surface_t *surface_image;
if (num_rects == 0)
return CAIRO_STATUS_SUCCESS;
@@ -317,54 +570,105 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- surface_image = _cairo_surface_get_image (surface);
+ return _fallback_fill_rectangles (surface, operator, color, rects, num_rects);
+}
+
+static cairo_status_t
+_fallback_composite_trapezoids (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ fallback_state_t state;
+ cairo_trapezoid_t *offset_traps = NULL;
+ cairo_status_t status;
+ int i;
+
+ status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
+ if (!CAIRO_OK (status) || !state.image)
+ return status;
- surface_image->base.backend->fill_rectangles (surface_image,
- operator,
- color,
- rects, num_rects);
+ /* If the destination image isn't at 0,0, we need to offset the trapezoids */
+
+ if (state.image_rect.x != 0 || state.image_rect.y != 0) {
+
+ cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x);
+ cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y);
+
+ offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
+ if (!offset_traps) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
- status = _cairo_surface_set_image (surface, surface_image);
+ for (i = 0; i < num_traps; i++) {
+ offset_traps[i].top = traps[i].top - yoff;
+ offset_traps[i].bottom = traps[i].bottom - yoff;
+ offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff;
+ offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff;
+ offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff;
+ offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff;
+ offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff;
+ offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff;
+ offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff;
+ offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff;
+ }
- cairo_surface_destroy (&surface_image->base);
+ traps = offset_traps;
+ }
+ state.image->base.backend->composite_trapezoids (operator, pattern,
+ &state.image->base,
+ src_x, src_y,
+ dst_x - state.image_rect.x,
+ dst_y - state.image_rect.y,
+ width, height, traps, num_traps);
+ if (offset_traps)
+ free (offset_traps);
+
+ FAIL:
+ _fallback_cleanup (&state);
+
return status;
}
+
cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *src,
+ cairo_pattern_t *pattern,
cairo_surface_t *dst,
- int x_src,
- int y_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
cairo_int_status_t status;
- cairo_image_surface_t *src_image, *dst_image;
status = dst->backend->composite_trapezoids (operator,
- src, dst,
- x_src, y_src,
+ pattern, dst,
+ src_x, src_y,
+ dst_x, dst_y,
+ width, height,
traps, num_traps);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- src_image = _cairo_surface_get_image (src);
- dst_image = _cairo_surface_get_image (dst);
-
- dst_image->base.backend->composite_trapezoids (operator,
- &src_image->base,
- dst_image,
- x_src, y_src,
- traps, num_traps);
-
- status = _cairo_surface_set_image (dst, dst_image);
-
- cairo_surface_destroy (&src_image->base);
- cairo_surface_destroy (&dst_image->base);
-
- return status;
+ return _fallback_composite_trapezoids (operator, pattern, dst,
+ src_x, src_y,
+ dst_x, dst_y,
+ width, height,
+ traps, num_traps);
}
cairo_status_t
@@ -402,109 +706,3 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *reg
{
return surface->backend->set_clip_region (surface, region);
}
-
-cairo_status_t
-_cairo_surface_create_pattern (cairo_surface_t *surface,
- cairo_pattern_t *pattern,
- cairo_box_t *box)
-{
- cairo_int_status_t status;
-
- status = surface->backend->create_pattern (surface, pattern, box);
-
- /* The backend cannot accelerate this pattern, lets create an
- unaccelerated source instead. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-
- status = CAIRO_STATUS_SUCCESS;
- switch (pattern->type) {
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- cairo_image_surface_t *image;
-
- image = _cairo_pattern_get_image (pattern, box);
- if (image) {
- pattern->source = &image->base;
-
- return CAIRO_STATUS_SUCCESS;
- } else
- return CAIRO_STATUS_NO_MEMORY;
-
- } break;
- case CAIRO_PATTERN_SOLID:
- pattern->source =
- _cairo_surface_create_similar_solid (surface,
- CAIRO_FORMAT_ARGB32,
- 1, 1,
- &pattern->color);
- if (pattern->source) {
- cairo_surface_set_repeat (pattern->source, 1);
-
- return CAIRO_STATUS_SUCCESS;
- } else
- return CAIRO_STATUS_NO_MEMORY;
- break;
- case CAIRO_PATTERN_SURFACE:
- status = CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* handle pattern opacity */
- if (pattern->color.alpha != 1.0) {
- double x = box->p1.x >> 16;
- double y = box->p1.y >> 16;
- int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16);
- int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16);
- cairo_pattern_t alpha;
-
- pattern->source =
- cairo_surface_create_similar (surface,
- CAIRO_FORMAT_ARGB32,
- width, height);
- if (pattern->source) {
- _cairo_pattern_init_solid (&alpha, 1.0, 1.0, 1.0);
- _cairo_pattern_set_alpha (&alpha, pattern->color.alpha);
-
- status = _cairo_surface_create_pattern (pattern->source,
- &alpha, box);
-
- if (status == CAIRO_STATUS_SUCCESS) {
- int save_repeat = pattern->u.surface.surface->repeat;
-
- if (pattern->extend == CAIRO_EXTEND_REPEAT ||
- pattern->u.surface.surface->repeat == 1)
- cairo_surface_set_repeat (pattern->u.surface.surface, 1);
- else
- cairo_surface_set_repeat (pattern->u.surface.surface, 0);
-
- status =
- _cairo_surface_composite (CAIRO_OPERATOR_OVER,
- pattern->u.surface.surface,
- alpha.source,
- pattern->source,
- 0, 0, 0, 0, 0, 0,
- width, height);
-
- cairo_surface_set_repeat (pattern->u.surface.surface,
- save_repeat);
-
- if (status == CAIRO_STATUS_SUCCESS)
- _cairo_pattern_set_source_offset (pattern, x, y);
- else
- cairo_surface_destroy (pattern->source);
- }
-
- _cairo_pattern_fini (&alpha);
- }
- }
-
- if (status != CAIRO_STATUS_SUCCESS) {
- pattern->source = pattern->u.surface.surface;
- cairo_surface_reference (pattern->u.surface.surface);
-
- return CAIRO_STATUS_SUCCESS;
- }
- break;
- }
- }
-
- return status;
-}
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index d17a27281..79c7e16b6 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -1,31 +1,42 @@
/*
- * Copyright © 2002 Keith Packard
+ * Copyright © 2002 Keith Packard
*
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
+ * 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.
*
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * 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 Keith Packard
+ *
+ * Contributor(s):
+ * Keith R. Packard <keithp@keithp.com>
+ * Carl D. Worth <cworth@cworth.org>
*
* 2002-07-15: Converted from XRenderCompositeDoublePoly to cairo_trap. Carl D. Worth
*/
#include "cairoint.h"
-#define CAIRO_TRAPS_GROWTH_INC 10
-
/* private functions */
static cairo_status_t
@@ -52,12 +63,6 @@ _compare_cairo_edge_by_slope (const void *av, const void *bv);
static cairo_fixed_16_16_t
_compute_x (cairo_line_t *line, cairo_fixed_t y);
-static double
-_compute_inverse_slope (cairo_line_t *l);
-
-static double
-_compute_x_intercept (cairo_line_t *l, double inverse_slope);
-
static int
_line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret);
@@ -68,6 +73,8 @@ _cairo_traps_init (cairo_traps_t *traps)
traps->traps_size = 0;
traps->traps = NULL;
+ traps->extents.p1.x = traps->extents.p1.y = CAIRO_MAXSHORT << 16;
+ traps->extents.p2.x = traps->extents.p2.y = CAIRO_MINSHORT << 16;
}
void
@@ -93,7 +100,8 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo
}
if (traps->num_traps >= traps->traps_size) {
- status = _cairo_traps_grow_by (traps, CAIRO_TRAPS_GROWTH_INC);
+ int inc = traps->traps_size ? traps->traps_size : 32;
+ status = _cairo_traps_grow_by (traps, inc);
if (status)
return status;
}
@@ -104,6 +112,28 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo
trap->left = *left;
trap->right = *right;
+ if (top < traps->extents.p1.y)
+ traps->extents.p1.y = top;
+ if (bottom > traps->extents.p2.y)
+ traps->extents.p2.y = bottom;
+ /*
+ * This isn't generally accurate, but it is close enough for
+ * this purpose. Assuming that the left and right segments always
+ * contain the trapezoid vertical extents, these compares will
+ * yield a containing box. Assuming that the points all come from
+ * the same figure which will eventually be completely drawn, then
+ * the compares will yield the correct overall extents
+ */
+ if (left->p1.x < traps->extents.p1.x)
+ traps->extents.p1.x = left->p1.x;
+ if (left->p2.x < traps->extents.p1.x)
+ traps->extents.p1.x = left->p2.x;
+
+ if (right->p1.x > traps->extents.p2.x)
+ traps->extents.p2.x = right->p1.x;
+ if (right->p2.x > traps->extents.p2.x)
+ traps->extents.p2.x = right->p2.x;
+
traps->num_traps++;
return CAIRO_STATUS_SUCCESS;
@@ -327,40 +357,132 @@ _compare_cairo_edge_by_current_x_slope (const void *av, const void *bv)
sub-computations -- just a bunch of determinants. I haven't
looked at complexity, (both are probably similar and it probably
doesn't matter much anyway).
+ */
-static double
-_det (double a, double b, double c, double d)
+/* XXX: Keith's new intersection code is much cleaner, and uses
+ * sufficient precision for correctly sorting intersections according
+ * to the analysis in Hobby's paper.
+ *
+ * But, when we enable this code, some things are failing, (eg. the
+ * stars in test/fill_rule get filled wrong). This could indicate a
+ * bug in one of tree places:
+ *
+ * 1) The new intersection code in this file
+ *
+ * 2) cairo_wideint.c (which is only exercised here)
+ *
+ * 3) In the current tessellator, (where the old intersection
+ * code, with its mystic increments could be masking the bug).
+ *
+ * It will likely be easier to revisit this when the new tessellation
+ * code is in place. So, for now, we'll simply disable the new
+ * intersection code.
+ */
+
+#define CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE 0
+
+#if CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
+static const cairo_fixed_32_32_t
+_det16_32 (cairo_fixed_16_16_t a,
+ cairo_fixed_16_16_t b,
+ cairo_fixed_16_16_t c,
+ cairo_fixed_16_16_t d)
{
- return a * d - b * c;
+ return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),
+ _cairo_int32x32_64_mul (b, c));
}
-static int
-_lines_intersect (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection)
+static const cairo_fixed_64_64_t
+_det32_64 (cairo_fixed_32_32_t a,
+ cairo_fixed_32_32_t b,
+ cairo_fixed_32_32_t c,
+ cairo_fixed_32_32_t d)
{
- double dx1 = cairo_fixed_to_double (l1->p1.x - l1->p2.x);
- double dy1 = cairo_fixed_to_double (l1->p1.y - l1->p2.y);
-
- double dx2 = cairo_fixed_to_double (l2->p1.x - l2->p2.x);
- double dy2 = cairo_fixed_to_double (l2->p1.y - l2->p2.y);
-
- double l1_det, l2_det;
+ return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d),
+ _cairo_int64x64_128_mul (b, c));
+}
- double den_det = _det (dx1, dy1, dx2, dy2);
+static const cairo_fixed_32_32_t
+_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a)
+{
+ return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16);
+}
- if (den_det == 0)
+static int
+_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection)
+{
+ cairo_fixed_16_16_t dx1, dx2, dy1, dy2;
+ cairo_fixed_32_32_t den_det;
+ cairo_fixed_32_32_t l1_det, l2_det;
+ cairo_fixed_64_64_t num_det;
+ cairo_fixed_32_32_t intersect_32_32;
+ cairo_fixed_48_16_t intersect_48_16;
+ cairo_fixed_16_16_t intersect_16_16;
+ cairo_quorem128_t qr;
+
+ dx1 = l1->p1.x - l1->p2.x;
+ dy1 = l1->p1.y - l1->p2.y;
+ dx2 = l2->p1.x - l2->p2.x;
+ dy2 = l2->p1.y - l2->p2.y;
+ den_det = _det16_32 (dx1, dy1,
+ dx2, dy2);
+
+ if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0)))
return 0;
- l1_det = _det (l1->p1.x, l1->p1.y,
- l1->p2.x, l1->p2.y);
- l2_det = _det (l2->p1.x, l2->p1.y,
- l2->p2.x, l2->p2.y);
+ l1_det = _det16_32 (l1->p1.x, l1->p1.y,
+ l1->p2.x, l1->p2.y);
+ l2_det = _det16_32 (l2->p1.x, l2->p1.y,
+ l2->p2.x, l2->p2.y);
- *y_intersection = _det (l1_det, dy1,
- l2_det, dy2) / den_det;
+
+ num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1),
+ l2_det, _fixed_16_16_to_fixed_32_32 (dy2));
+
+ /*
+ * Ok, this one is a bit tricky in fixed point, the denominator
+ * needs to be left with 32-bits of fraction so that the
+ * result of the divide ends up with 32-bits of fraction (64 - 32 = 32)
+ */
+ qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det));
+
+ intersect_32_32 = _cairo_int128_to_int64 (qr.quo);
+
+ /*
+ * Find the ceiling of the quotient -- divrem returns
+ * the quotient truncated towards zero, so if the
+ * quotient should be positive (num_den and den_det have same sign)
+ * bump the quotient up by one.
+ */
+
+ if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) &&
+ (_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) ==
+ _cairo_int64_ge (den_det, _cairo_int32_to_int64 (0))))
+ {
+ intersect_32_32 = _cairo_int64_add (intersect_32_32,
+ _cairo_int32_to_int64 (1));
+ }
+
+ /*
+ * Now convert from 32.32 to 48.16 and take the ceiling;
+ * this requires adding in 15 1 bits and shifting the result
+ */
+
+ intersect_32_32 = _cairo_int64_add (intersect_32_32,
+ _cairo_int32_to_int64 ((1 << 16) - 1));
+ intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16);
+
+ /*
+ * And drop the top bits
+ */
+ intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16);
+
+ *y_intersection = intersect_16_16;
return 1;
}
-*/
+#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
+
static cairo_fixed_16_16_t
_compute_x (cairo_line_t *line, cairo_fixed_t y)
{
@@ -371,6 +493,7 @@ _compute_x (cairo_line_t *line, cairo_fixed_t y)
return line->p1.x + (ex / dy);
}
+#if ! CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
static double
_compute_inverse_slope (cairo_line_t *l)
{
@@ -460,6 +583,7 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_
return 1;
}
+#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
/* The algorithm here is pretty simple:
@@ -567,32 +691,32 @@ _cairo_traps_tessellate_polygon (cairo_traps_t *traps,
return CAIRO_STATUS_SUCCESS;
}
-static int
+static cairo_bool_t
_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
{
cairo_slope_t slope_left, slope_pt, slope_right;
if (t->top > pt->y)
- return 0;
+ return FALSE;
if (t->bottom < pt->y)
- return 0;
+ return FALSE;
_cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
_cairo_slope_init (&slope_pt, &t->left.p1, pt);
if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
- return 0;
+ return FALSE;
_cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
_cairo_slope_init (&slope_pt, &t->right.p1, pt);
if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
- return 0;
+ return FALSE;
- return 1;
+ return TRUE;
}
-int
+cairo_bool_t
_cairo_traps_contain (cairo_traps_t *traps, double x, double y)
{
int i;
@@ -603,45 +727,14 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y)
for (i = 0; i < traps->num_traps; i++) {
if (_cairo_trap_contains (&traps->traps[i], &point))
- return 1;
+ return TRUE;
}
- return 0;
-}
-
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-
-static void
-_cairo_trap_extents (cairo_trapezoid_t *t, cairo_box_t *extents)
-{
- cairo_fixed_t x;
-
- if (t->top < extents->p1.y)
- extents->p1.y = t->top;
-
- if (t->bottom > extents->p2.y)
- extents->p2.y = t->bottom;
-
- x = MIN (_compute_x (&t->left, t->top),
- _compute_x (&t->left, t->bottom));
- if (x < extents->p1.x)
- extents->p1.x = x;
-
- x = MAX (_compute_x (&t->right, t->top),
- _compute_x (&t->right, t->bottom));
- if (x > extents->p2.x)
- extents->p2.x = x;
+ return FALSE;
}
void
_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
{
- int i;
-
- extents->p1.x = extents->p1.y = CAIRO_MAXSHORT << 16;
- extents->p2.x = extents->p2.y = CAIRO_MINSHORT << 16;
-
- for (i = 0; i < traps->num_traps; i++)
- _cairo_trap_extents (&traps->traps[i], extents);
+ *extents = traps->extents;
}
diff --git a/src/cairo-unicode.c b/src/cairo-unicode.c
new file mode 100644
index 000000000..92201391a
--- /dev/null
+++ b/src/cairo-unicode.c
@@ -0,0 +1,340 @@
+/* cairo_unicode.c: Unicode conversion routines
+ *
+ * The code in this file is derived from GLib's gutf8.c and
+ * ultimately from libunicode. It is relicensed under the
+ * dual LGPL/MPL with permission of the original authors.
+ *
+ * Copyright © 1999 Tom Tromey
+ * Copyright © 2005 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 cairo_unicode.c as distributed with the
+ * cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Tom Tromey.
+ * and Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Owen Taylor <otaylor@redhat.com>
+ */
+
+#include <limits.h>
+
+#include <cairoint.h>
+
+#define UTF8_COMPUTE(Char, Mask, Len) \
+ if (Char < 128) \
+ { \
+ Len = 1; \
+ Mask = 0x7f; \
+ } \
+ else if ((Char & 0xe0) == 0xc0) \
+ { \
+ Len = 2; \
+ Mask = 0x1f; \
+ } \
+ else if ((Char & 0xf0) == 0xe0) \
+ { \
+ Len = 3; \
+ Mask = 0x0f; \
+ } \
+ else if ((Char & 0xf8) == 0xf0) \
+ { \
+ Len = 4; \
+ Mask = 0x07; \
+ } \
+ else if ((Char & 0xfc) == 0xf8) \
+ { \
+ Len = 5; \
+ Mask = 0x03; \
+ } \
+ else if ((Char & 0xfe) == 0xfc) \
+ { \
+ Len = 6; \
+ Mask = 0x01; \
+ } \
+ else \
+ Len = -1;
+
+#define UTF8_LENGTH(Char) \
+ ((Char) < 0x80 ? 1 : \
+ ((Char) < 0x800 ? 2 : \
+ ((Char) < 0x10000 ? 3 : \
+ ((Char) < 0x200000 ? 4 : \
+ ((Char) < 0x4000000 ? 5 : 6)))))
+
+
+#define UTF8_GET(Result, Chars, Count, Mask, Len) \
+ (Result) = (Chars)[0] & (Mask); \
+ for ((Count) = 1; (Count) < (Len); ++(Count)) \
+ { \
+ if (((Chars)[(Count)] & 0xc0) != 0x80) \
+ { \
+ (Result) = -1; \
+ break; \
+ } \
+ (Result) <<= 6; \
+ (Result) |= ((Chars)[(Count)] & 0x3f); \
+ }
+
+#define UNICODE_VALID(Char) \
+ ((Char) < 0x110000 && \
+ (((Char) & 0xFFFFF800) != 0xD800) && \
+ ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
+ ((Char) & 0xFFFE) != 0xFFFE)
+
+
+static const char utf8_skip_data[256] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
+};
+
+#define UTF8_NEXT_CHAR(p) (char *)((p) + utf8_skip_data[*(unsigned char *)(p)])
+
+/* Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
+ * If @p does not point to a valid UTF-8 encoded character, results are
+ * undefined.
+ **/
+static uint32_t
+_utf8_get_char (const char *p)
+{
+ int i, mask = 0, len;
+ uint32_t result;
+ unsigned char c = (unsigned char) *p;
+
+ UTF8_COMPUTE (c, mask, len);
+ if (len == -1)
+ return (uint32_t)-1;
+ UTF8_GET (result, p, i, mask, len);
+
+ return result;
+}
+
+/* Like _utf8_get_char, but take a maximum length
+ * and return (uint32_t)-2 on incomplete trailing character
+ */
+static uint32_t
+_utf8_get_char_extended (const char *p,
+ long max_len)
+{
+ int i, len;
+ uint32_t wc = (unsigned char) *p;
+
+ if (wc < 0x80) {
+ return wc;
+ } else if (wc < 0xc0) {
+ return (uint32_t)-1;
+ } else if (wc < 0xe0) {
+ len = 2;
+ wc &= 0x1f;
+ } else if (wc < 0xf0) {
+ len = 3;
+ wc &= 0x0f;
+ } else if (wc < 0xf8) {
+ len = 4;
+ wc &= 0x07;
+ } else if (wc < 0xfc) {
+ len = 5;
+ wc &= 0x03;
+ } else if (wc < 0xfe) {
+ len = 6;
+ wc &= 0x01;
+ } else {
+ return (uint32_t)-1;
+ }
+
+ if (max_len >= 0 && len > max_len) {
+ for (i = 1; i < max_len; i++) {
+ if ((((unsigned char *)p)[i] & 0xc0) != 0x80)
+ return (uint32_t)-1;
+ }
+ return (uint32_t)-2;
+ }
+
+ for (i = 1; i < len; ++i) {
+ uint32_t ch = ((unsigned char *)p)[i];
+
+ if ((ch & 0xc0) != 0x80) {
+ if (ch)
+ return (uint32_t)-1;
+ else
+ return (uint32_t)-2;
+ }
+
+ wc <<= 6;
+ wc |= (ch & 0x3f);
+ }
+
+ if (UTF8_LENGTH(wc) != len)
+ return (uint32_t)-1;
+
+ return wc;
+}
+
+/**
+ * _cairo_utf8_to_utf32:
+ * @str: an UTF-8 string
+ * @len: length of @str in bytes, or -1 if it is nul-terminated.
+ * If @len is supplied and the string has an embedded nul
+ * byte, only the portion before the nul byte is converted.
+ * @result: location to store a pointer to a newly allocated UTF-32
+ * string (always native endian). Free with free(). A 0
+ * word will be written after the last character.
+ * @items_written: location to store number of 32-bit words
+ * written. (Not including the trailing 0)
+ *
+ * Converts a UTF-8 string to UCS-4. UCS-4 is an encoding of Unicode
+ * with 1 32-bit word per character. The string is validated to
+ * consist entirely of valid Unicode characters.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if the entire string was
+ * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an
+ * an invalid sequence was found.
+ **/
+cairo_status_t
+_cairo_utf8_to_ucs4 (const char *str,
+ int len,
+ uint32_t **result,
+ int *items_written)
+{
+ uint32_t *str32 = NULL;
+ int n_chars, i;
+ const char *in;
+
+ in = str;
+ n_chars = 0;
+ while ((len < 0 || str + len - in > 0) && *in)
+ {
+ uint32_t wc = _utf8_get_char_extended (in, str + len - in);
+ if (wc & 0x80000000 || !UNICODE_VALID (wc))
+ return CAIRO_STATUS_INVALID_STRING;
+
+ n_chars++;
+ if (n_chars == INT_MAX)
+ return CAIRO_STATUS_INVALID_STRING;
+
+ in = UTF8_NEXT_CHAR (in);
+ }
+
+ str32 = malloc (sizeof (uint32_t) * (n_chars + 1));
+ if (!str32)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ in = str;
+ for (i=0; i < n_chars; i++) {
+ str32[i] = _utf8_get_char (in);
+ in = UTF8_NEXT_CHAR (in);
+ }
+ str32[i] = 0;
+
+ *result = str32;
+ if (items_written)
+ *items_written = n_chars;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * _cairo_utf8_to_utf16:
+ * @str: an UTF-8 string
+ * @len: length of @str in bytes, or -1 if it is nul-terminated.
+ * If @len is supplied and the string has an embedded nul
+ * byte, only the portion before the nul byte is converted.
+ * @result: location to store a pointer to a newly allocated UTF-16
+ * string (always native endian). Free with free(). A 0
+ * word will be written after the last character.
+ * @items_written: location to store number of 16-bit words
+ * written. (Not including the trailing 0)
+ *
+ * Converts a UTF-8 string to UTF-16. UTF-16 is an encoding of Unicode
+ * where characters are represented either as a single 16-bit word, or
+ * as a pair of 16-bit "surrogates". The string is validated to
+ * consist entirely of valid Unicode characters.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if the entire string was
+ * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an
+ * an invalid sequence was found.
+ **/
+cairo_status_t
+_cairo_utf8_to_utf16 (const char *str,
+ int len,
+ uint16_t **result,
+ int *items_written)
+{
+ uint16_t *str16 = NULL;
+ int n16, i;
+ const char *in;
+
+ in = str;
+ n16 = 0;
+ while ((len < 0 || str + len - in > 0) && *in) {
+ uint32_t wc = _utf8_get_char_extended (in, str + len - in);
+ if (wc & 0x80000000 || !UNICODE_VALID (wc))
+ return CAIRO_STATUS_INVALID_STRING;
+
+ if (wc < 0x10000)
+ n16 += 1;
+ else
+ n16 += 2;
+
+ if (n16 == INT_MAX - 1 || n16 == INT_MAX)
+ return CAIRO_STATUS_INVALID_STRING;
+
+ in = UTF8_NEXT_CHAR (in);
+ }
+
+
+ str16 = malloc (sizeof (uint16_t) * (n16 + 1));
+ if (!str16)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ in = str;
+ for (i = 0; i < n16;) {
+ uint32_t wc = _utf8_get_char (in);
+
+ if (wc < 0x10000) {
+ str16[i++] = wc;
+ } else {
+ str16[i++] = (wc - 0x10000) / 0x400 + 0xd800;
+ str16[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
+ }
+
+ in = UTF8_NEXT_CHAR (in);
+ }
+
+ str16[i] = 0;
+
+ *result = str16;
+ if (items_written)
+ *items_written = n16;
+
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
new file mode 100644
index 000000000..02f0cffd6
--- /dev/null
+++ b/src/cairo-win32-font.c
@@ -0,0 +1,1252 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 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):
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "cairo-win32-private.h"
+
+#ifndef SPI_GETFONTSMOOTHINGTYPE
+#define SPI_GETFONTSMOOTHINGTYPE 0x200a
+#endif
+#ifndef FE_FONTSMOOTHINGCLEARTYPE
+#define FE_FONTSMOOTHINGCLEARTYPE 2
+#endif
+#ifndef CLEARTYPE_QUALITY
+#define CLEARTYPE_QUALITY 5
+#endif
+
+const cairo_font_backend_t cairo_win32_font_backend;
+
+#define LOGICAL_SCALE 32
+
+typedef struct {
+ cairo_font_t base;
+
+ LOGFONTW logfont;
+
+ BYTE quality;
+
+ /* We do drawing and metrics computation in a "logical space" which
+ * is similar to font space, except that it is scaled by a factor
+ * of the (desired font size) * (LOGICAL_SCALE). The multiplication
+ * by LOGICAL_SCALE allows for sub-pixel precision.
+ */
+ double logical_scale;
+
+ /* The size we should actually request the font at from Windows; differs
+ * from the logical_scale because it is quantized for orthogonal
+ * transformations
+ */
+ double logical_size;
+
+ /* Transformations from device <=> logical space
+ */
+ cairo_matrix_t logical_to_device;
+ cairo_matrix_t device_to_logical;
+
+ /* We special case combinations of 90-degree-rotations, scales and
+ * flips ... that is transformations that take the axes to the
+ * axes. If preserve_axes is true, then swap_axes/swap_x/swap_y
+ * encode the 8 possibilities for orientation (4 rotation angles with
+ * and without a flip), and scale_x, scale_y the scale components.
+ */
+ cairo_bool_t preserve_axes;
+ cairo_bool_t swap_axes;
+ cairo_bool_t swap_x;
+ cairo_bool_t swap_y;
+ double x_scale;
+ double y_scale;
+
+ /* The size of the design unit of the font
+ */
+ int em_square;
+
+ HFONT scaled_font;
+ HFONT unscaled_font;
+
+} cairo_win32_font_t;
+
+#define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.))
+
+static void
+_compute_transform (cairo_win32_font_t *font,
+ cairo_font_scale_t *sc)
+{
+ if (NEARLY_ZERO (sc->matrix[0][1]) && NEARLY_ZERO (sc->matrix[1][0])) {
+ font->preserve_axes = TRUE;
+ font->x_scale = sc->matrix[0][0];
+ font->swap_x = (sc->matrix[0][0] < 0);
+ font->y_scale = sc->matrix[1][1];
+ font->swap_y = (sc->matrix[1][1] < 0);
+ font->swap_axes = FALSE;
+
+ } else if (NEARLY_ZERO (sc->matrix[0][0]) && NEARLY_ZERO (sc->matrix[1][1])) {
+ font->preserve_axes = TRUE;
+ font->x_scale = sc->matrix[0][1];
+ font->swap_x = (sc->matrix[0][1] < 0);
+ font->y_scale = sc->matrix[1][0];
+ font->swap_y = (sc->matrix[1][0] < 0);
+ font->swap_axes = TRUE;
+
+ } else {
+ font->preserve_axes = FALSE;
+ font->swap_x = font->swap_y = font->swap_axes = FALSE;
+ }
+
+ if (font->preserve_axes) {
+ if (font->swap_x)
+ font->x_scale = - font->x_scale;
+ if (font->swap_y)
+ font->y_scale = - font->y_scale;
+
+ font->logical_scale = LOGICAL_SCALE * font->y_scale;
+ font->logical_size = LOGICAL_SCALE * floor (font->y_scale + 0.5);
+ }
+
+ /* The font matrix has x and y "scale" components which we extract and
+ * use as character scale values.
+ */
+ cairo_matrix_set_affine (&font->logical_to_device,
+ sc->matrix[0][0],
+ sc->matrix[0][1],
+ sc->matrix[1][0],
+ sc->matrix[1][1],
+ 0, 0);
+
+ if (!font->preserve_axes) {
+ _cairo_matrix_compute_scale_factors (&font->logical_to_device,
+ &font->x_scale, &font->y_scale,
+ TRUE); /* XXX: Handle vertical text */
+
+ font->logical_size = floor (LOGICAL_SCALE * font->y_scale + 0.5);
+ font->logical_scale = LOGICAL_SCALE * font->y_scale;
+ }
+
+ cairo_matrix_scale (&font->logical_to_device,
+ 1.0 / font->logical_scale, 1.0 / font->logical_scale);
+
+ font->device_to_logical = font->logical_to_device;
+ if (!CAIRO_OK (cairo_matrix_invert (&font->device_to_logical)))
+ cairo_matrix_set_identity (&font->device_to_logical);
+}
+
+static BYTE
+_get_system_quality (void)
+{
+ BOOL font_smoothing;
+
+ if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
+ _cairo_win32_print_gdi_error ("_get_system_quality");
+ return FALSE;
+ }
+
+ if (font_smoothing) {
+ OSVERSIONINFO version_info;
+
+ version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+
+ if (!GetVersionEx (&version_info)) {
+ _cairo_win32_print_gdi_error ("_get_system_quality");
+ return FALSE;
+ }
+
+ if (version_info.dwMajorVersion > 5 ||
+ (version_info.dwMajorVersion == 5 &&
+ version_info.dwMinorVersion >= 1)) { /* XP or newer */
+ UINT smoothing_type;
+
+ if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE,
+ 0, &smoothing_type, 0)) {
+ _cairo_win32_print_gdi_error ("_get_system_quality");
+ return FALSE;
+ }
+
+ if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
+ return CLEARTYPE_QUALITY;
+ }
+
+ return ANTIALIASED_QUALITY;
+ } else
+ return DEFAULT_QUALITY;
+}
+
+static cairo_font_t *
+_win32_font_create (LOGFONTW *logfont,
+ cairo_font_scale_t *scale)
+{
+ cairo_win32_font_t *f;
+
+ f = malloc (sizeof(cairo_win32_font_t));
+ if (f == NULL)
+ return NULL;
+
+ f->logfont = *logfont;
+ f->quality = _get_system_quality ();
+ f->em_square = 0;
+ f->scaled_font = NULL;
+ f->unscaled_font = NULL;
+
+ _compute_transform (f, scale);
+
+ _cairo_font_init ((cairo_font_t *)f, scale, &cairo_win32_font_backend);
+
+ return (cairo_font_t *)f;
+}
+
+static cairo_status_t
+_win32_font_set_world_transform (cairo_win32_font_t *font,
+ HDC hdc)
+{
+ XFORM xform;
+
+ xform.eM11 = font->logical_to_device.m[0][0];
+ xform.eM21 = font->logical_to_device.m[1][0];
+ xform.eM12 = font->logical_to_device.m[0][1];
+ xform.eM22 = font->logical_to_device.m[1][1];
+ xform.eDx = font->logical_to_device.m[2][0];
+ xform.eDy = font->logical_to_device.m[2][1];
+
+ if (!SetWorldTransform (hdc, &xform))
+ return _cairo_win32_print_gdi_error ("_win32_font_set_world_transform");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_win32_font_set_identity_transform (HDC hdc)
+{
+ if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY))
+ return _cairo_win32_print_gdi_error ("_win32_font_set_identity_transform");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static HDC
+_get_global_font_dc (void)
+{
+ static HDC hdc;
+
+ if (!hdc) {
+ hdc = CreateCompatibleDC (NULL);
+ if (!hdc) {
+ _cairo_win32_print_gdi_error ("_get_global_font_dc");
+ return NULL;
+ }
+
+ if (!SetGraphicsMode (hdc, GM_ADVANCED)) {
+ _cairo_win32_print_gdi_error ("_get_global_font_dc");
+ DeleteDC (hdc);
+ return NULL;
+ }
+ }
+
+ return hdc;
+}
+
+static HFONT
+_win32_font_get_scaled_font (cairo_win32_font_t *font)
+{
+ if (!font->scaled_font) {
+ LOGFONTW logfont = font->logfont;
+ logfont.lfHeight = font->logical_size;
+ logfont.lfWidth = 0;
+ logfont.lfEscapement = 0;
+ logfont.lfOrientation = 0;
+ logfont.lfQuality = font->quality;
+
+ font->scaled_font = CreateFontIndirectW (&logfont);
+ if (!font->scaled_font) {
+ _cairo_win32_print_gdi_error ("_win32_font_get_scaled_font");
+ return NULL;
+ }
+ }
+
+ return font->scaled_font;
+}
+
+static HFONT
+_win32_font_get_unscaled_font (cairo_win32_font_t *font,
+ HDC hdc)
+{
+ if (!font->unscaled_font) {
+ OUTLINETEXTMETRIC *otm;
+ unsigned int otm_size;
+ HFONT scaled_font;
+ LOGFONTW logfont;
+
+ scaled_font = _win32_font_get_scaled_font (font);
+ if (!scaled_font)
+ return NULL;
+
+ if (!SelectObject (hdc, scaled_font)) {
+ _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:SelectObject");
+ return NULL;
+ }
+
+ otm_size = GetOutlineTextMetrics (hdc, 0, NULL);
+ if (!otm_size) {
+ _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
+ return NULL;
+ }
+
+ otm = malloc (otm_size);
+ if (!otm)
+ return NULL;
+
+ if (!GetOutlineTextMetrics (hdc, otm_size, otm)) {
+ _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
+ free (otm);
+ return NULL;
+ }
+
+ font->em_square = otm->otmEMSquare;
+ free (otm);
+
+ logfont = font->logfont;
+ logfont.lfHeight = font->em_square;
+ logfont.lfWidth = 0;
+ logfont.lfEscapement = 0;
+ logfont.lfOrientation = 0;
+ logfont.lfQuality = font->quality;
+
+ font->unscaled_font = CreateFontIndirectW (&logfont);
+ if (!font->unscaled_font) {
+ _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:CreateIndirect");
+ return NULL;
+ }
+ }
+
+ return font->unscaled_font;
+}
+
+static cairo_status_t
+_cairo_win32_font_select_unscaled_font (cairo_font_t *font,
+ HDC hdc)
+{
+ cairo_status_t status;
+ HFONT hfont;
+ HFONT old_hfont = NULL;
+
+ hfont = _win32_font_get_unscaled_font ((cairo_win32_font_t *)font, hdc);
+ if (!hfont)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ old_hfont = SelectObject (hdc, hfont);
+ if (!old_hfont)
+ return _cairo_win32_print_gdi_error ("_cairo_win32_font_select_unscaled_font");
+
+ status = _win32_font_set_identity_transform (hdc);
+ if (!CAIRO_OK (status)) {
+ SelectObject (hdc, old_hfont);
+ return status;
+ }
+
+ SetMapMode (hdc, MM_TEXT);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_win32_font_done_unscaled_font (cairo_font_t *font)
+{
+}
+
+/* implement the font backend interface */
+
+static cairo_status_t
+_cairo_win32_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ cairo_font_scale_t *scale,
+ cairo_font_t **font_out)
+{
+ LOGFONTW logfont;
+ cairo_font_t *font;
+ uint16_t *face_name;
+ int face_name_len;
+ cairo_status_t status;
+
+ status = _cairo_utf8_to_utf16 (family, -1, &face_name, &face_name_len);
+ if (!CAIRO_OK (status))
+ return status;
+
+ if (face_name_len > LF_FACESIZE - 1) {
+ free (face_name);
+ return CAIRO_STATUS_INVALID_STRING;
+ }
+
+ memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * (face_name_len + 1));
+ free (face_name);
+
+ logfont.lfHeight = 0; /* filled in later */
+ logfont.lfWidth = 0; /* filled in later */
+ logfont.lfEscapement = 0; /* filled in later */
+ logfont.lfOrientation = 0; /* filled in later */
+
+ switch (weight) {
+ case CAIRO_FONT_WEIGHT_NORMAL:
+ default:
+ logfont.lfWeight = FW_NORMAL;
+ break;
+ case CAIRO_FONT_WEIGHT_BOLD:
+ logfont.lfWeight = FW_BOLD;
+ break;
+ }
+
+ switch (slant) {
+ case CAIRO_FONT_SLANT_NORMAL:
+ default:
+ logfont.lfItalic = FALSE;
+ break;
+ case CAIRO_FONT_SLANT_ITALIC:
+ case CAIRO_FONT_SLANT_OBLIQUE:
+ logfont.lfItalic = TRUE;
+ break;
+ }
+
+ logfont.lfUnderline = FALSE;
+ logfont.lfStrikeOut = FALSE;
+ /* The docs for LOGFONT discourage using this, since the
+ * interpretation is locale-specific, but it's not clear what
+ * would be a better alternative.
+ */
+ logfont.lfCharSet = DEFAULT_CHARSET;
+ logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ logfont.lfQuality = DEFAULT_QUALITY; /* filled in later */
+ logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+
+ if (!logfont.lfFaceName)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ font = _win32_font_create (&logfont, scale);
+ if (!font)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ *font_out = font;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_win32_font_destroy_font (void *abstract_font)
+{
+ cairo_win32_font_t *font = abstract_font;
+
+ if (font->scaled_font)
+ DeleteObject (font->scaled_font);
+
+ if (font->unscaled_font)
+ DeleteObject (font->unscaled_font);
+
+ free (font);
+}
+
+static void
+_cairo_win32_font_destroy_unscaled_font (void *abstract_font)
+{
+}
+
+static void
+_cairo_win32_font_get_glyph_cache_key (void *abstract_font,
+ cairo_glyph_cache_key_t *key)
+{
+}
+
+static cairo_status_t
+_cairo_win32_font_text_to_glyphs (void *abstract_font,
+ const unsigned char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
+{
+ cairo_win32_font_t *font = abstract_font;
+ uint16_t *utf16;
+ int n16;
+ GCP_RESULTSW gcp_results;
+ unsigned int buffer_size, i;
+ WCHAR *glyph_indices = NULL;
+ int *dx = NULL;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ double x_pos;
+ HDC hdc = NULL;
+
+ status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16);
+ if (!CAIRO_OK (status))
+ return status;
+
+ gcp_results.lStructSize = sizeof (GCP_RESULTS);
+ gcp_results.lpOutString = NULL;
+ gcp_results.lpOrder = NULL;
+ gcp_results.lpCaretPos = NULL;
+ gcp_results.lpClass = NULL;
+
+ buffer_size = MAX (n16 * 1.2, 16); /* Initially guess number of chars plus a few */
+ if (buffer_size > INT_MAX) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL1;
+ }
+
+ hdc = _get_global_font_dc ();
+ if (!hdc) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL1;
+ }
+
+ status = cairo_win32_font_select_font (&font->base, hdc);
+ if (!CAIRO_OK (status))
+ goto FAIL1;
+
+ while (TRUE) {
+ if (glyph_indices) {
+ free (glyph_indices);
+ glyph_indices = NULL;
+ }
+ if (dx) {
+ free (dx);
+ dx = NULL;
+ }
+
+ glyph_indices = malloc (sizeof (WCHAR) * buffer_size);
+ dx = malloc (sizeof (int) * buffer_size);
+ if (!glyph_indices || !dx) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL2;
+ }
+
+ gcp_results.nGlyphs = buffer_size;
+ gcp_results.lpDx = dx;
+ gcp_results.lpGlyphs = glyph_indices;
+
+ if (!GetCharacterPlacementW (hdc, utf16, n16,
+ 0,
+ &gcp_results,
+ GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER)) {
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_font_text_to_glyphs");
+ goto FAIL2;
+ }
+
+ if (gcp_results.lpDx && gcp_results.lpGlyphs)
+ break;
+
+ /* Too small a buffer, try again */
+
+ buffer_size *= 1.5;
+ if (buffer_size > INT_MAX) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL2;
+ }
+ }
+
+ *num_glyphs = gcp_results.nGlyphs;
+ *glyphs = malloc (sizeof (cairo_glyph_t) * gcp_results.nGlyphs);
+ if (!*glyphs) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL2;
+ }
+
+ x_pos = 0;
+ for (i = 0; i < gcp_results.nGlyphs; i++) {
+ (*glyphs)[i].index = glyph_indices[i];
+ (*glyphs)[i].x = x_pos ;
+ (*glyphs)[i].y = 0;
+
+ x_pos += dx[i] / font->logical_scale;
+ }
+
+ FAIL2:
+ if (glyph_indices)
+ free (glyph_indices);
+ if (dx)
+ free (dx);
+
+ cairo_win32_font_done_font (&font->base);
+
+ FAIL1:
+ free (utf16);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_win32_font_font_extents (void *abstract_font,
+ cairo_font_extents_t *extents)
+{
+ cairo_win32_font_t *font = abstract_font;
+ cairo_status_t status;
+ TEXTMETRIC metrics;
+ HDC hdc;
+
+ hdc = _get_global_font_dc ();
+ if (!hdc)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (font->preserve_axes) {
+ /* For 90-degree rotations (including 0), we get the metrics
+ * from the GDI in logical space, then convert back to font space
+ */
+ status = cairo_win32_font_select_font (&font->base, hdc);
+ if (!CAIRO_OK (status))
+ return status;
+ GetTextMetrics (hdc, &metrics);
+ cairo_win32_font_done_font (&font->base);
+
+ extents->ascent = metrics.tmAscent / font->logical_scale;
+ extents->descent = metrics.tmDescent / font->logical_scale;
+
+ extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / font->logical_scale;
+ extents->max_x_advance = metrics.tmMaxCharWidth / font->logical_scale;
+ extents->max_y_advance = 0;
+
+ } else {
+ /* For all other transformations, we use the design metrics
+ * of the font. The GDI results from GetTextMetrics() on a
+ * transformed font are inexplicably large and we want to
+ * avoid them.
+ */
+ status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
+ if (!CAIRO_OK (status))
+ return status;
+ GetTextMetrics (hdc, &metrics);
+ _cairo_win32_font_done_unscaled_font (&font->base);
+
+ extents->ascent = (double)metrics.tmAscent / font->em_square;
+ extents->descent = metrics.tmDescent * font->em_square;
+ extents->height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / font->em_square;
+ extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / font->em_square;
+ extents->max_y_advance = 0;
+
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_font_glyph_extents (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
+{
+ cairo_win32_font_t *font = abstract_font;
+ static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
+ GLYPHMETRICS metrics;
+ cairo_status_t status;
+ HDC hdc;
+
+ hdc = _get_global_font_dc ();
+ if (!hdc)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ /* We handle only the case num_glyphs == 1, glyphs[i].x == glyphs[0].y == 0.
+ * This is all that the calling code triggers, and the backend interface
+ * will eventually be changed to match
+ */
+ assert (num_glyphs == 1);
+
+ if (font->preserve_axes) {
+ /* If we aren't rotating / skewing the axes, then we get the metrics
+ * from the GDI in device space and convert to font space.
+ */
+ status = cairo_win32_font_select_font (&font->base, hdc);
+ if (!CAIRO_OK (status))
+ return status;
+ GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
+ &metrics, 0, NULL, &matrix);
+ cairo_win32_font_done_font (&font->base);
+
+ if (font->swap_axes) {
+ extents->x_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
+ extents->y_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
+ extents->width = metrics.gmBlackBoxY / font->y_scale;
+ extents->height = metrics.gmBlackBoxX / font->x_scale;
+ extents->x_advance = metrics.gmCellIncY / font->x_scale;
+ extents->y_advance = metrics.gmCellIncX / font->y_scale;
+ } else {
+ extents->x_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
+ extents->y_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
+ extents->width = metrics.gmBlackBoxX / font->x_scale;
+ extents->height = metrics.gmBlackBoxY / font->y_scale;
+ extents->x_advance = metrics.gmCellIncX / font->x_scale;
+ extents->y_advance = metrics.gmCellIncY / font->y_scale;
+ }
+
+ if (font->swap_x) {
+ extents->x_bearing = (- extents->x_bearing - extents->width);
+ extents->x_advance = - extents->x_advance;
+ }
+
+ if (font->swap_y) {
+ extents->y_bearing = (- extents->y_bearing - extents->height);
+ extents->y_advance = - extents->y_advance;
+ }
+
+ } else {
+ /* For all other transformations, we use the design metrics
+ * of the font.
+ */
+ status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
+ GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
+ &metrics, 0, NULL, &matrix);
+ _cairo_win32_font_done_unscaled_font (&font->base);
+
+ extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / font->em_square;
+ extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / font->em_square;
+ extents->width = (double)metrics.gmBlackBoxX / font->em_square;
+ extents->height = (double)metrics.gmBlackBoxY / font->em_square;
+ extents->x_advance = (double)metrics.gmCellIncX / font->em_square;
+ extents->y_advance = (double)metrics.gmCellIncY / font->em_square;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_cairo_win32_font_glyph_bbox (void *abstract_font,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
+{
+ static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
+ cairo_win32_font_t *font = abstract_font;
+ int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
+
+ if (num_glyphs > 0) {
+ HDC hdc = _get_global_font_dc ();
+ GLYPHMETRICS metrics;
+ cairo_status_t status;
+ int i;
+
+ if (!hdc)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ status = cairo_win32_font_select_font (&font->base, hdc);
+ if (!CAIRO_OK (status))
+ return status;
+
+ for (i = 0; i < num_glyphs; i++) {
+ int x = floor (0.5 + glyphs[i].x);
+ int y = floor (0.5 + glyphs[i].y);
+
+ GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | GGO_GLYPH_INDEX,
+ &metrics, 0, NULL, &matrix);
+
+ if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x)
+ x1 = x + metrics.gmptGlyphOrigin.x;
+ if (i == 0 || y1 > y - metrics.gmptGlyphOrigin.y)
+ y1 = y - metrics.gmptGlyphOrigin.y;
+ if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX)
+ x2 = x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX;
+ if (i == 0 || y2 < y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY)
+ y2 = y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY;
+ }
+
+ cairo_win32_font_done_font (&font->base);
+ }
+
+ bbox->p1.x = _cairo_fixed_from_int (x1);
+ bbox->p1.y = _cairo_fixed_from_int (y1);
+ bbox->p2.x = _cairo_fixed_from_int (x2);
+ bbox->p2.y = _cairo_fixed_from_int (y2);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+typedef struct {
+ cairo_win32_font_t *font;
+ HDC hdc;
+
+ cairo_array_t glyphs;
+ cairo_array_t dx;
+
+ int start_x;
+ int last_x;
+ int last_y;
+} cairo_glyph_state_t;
+
+static void
+_start_glyphs (cairo_glyph_state_t *state,
+ cairo_win32_font_t *font,
+ HDC hdc)
+{
+ state->hdc = hdc;
+ state->font = font;
+
+ _cairo_array_init (&state->glyphs, sizeof (WCHAR));
+ _cairo_array_init (&state->dx, sizeof (int));
+}
+
+static cairo_status_t
+_flush_glyphs (cairo_glyph_state_t *state)
+{
+ int dx = 0;
+ if (!_cairo_array_append (&state->dx, &dx, 1))
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (!ExtTextOutW (state->hdc,
+ state->start_x, state->last_y,
+ ETO_GLYPH_INDEX,
+ NULL,
+ (WCHAR *)state->glyphs.elements,
+ state->glyphs.num_elements,
+ (int *)state->dx.elements)) {
+ return _cairo_win32_print_gdi_error ("_flush_glyphs");
+ }
+
+ _cairo_array_truncate (&state->glyphs, 0);
+ _cairo_array_truncate (&state->dx, 0);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_add_glyph (cairo_glyph_state_t *state,
+ unsigned long index,
+ double device_x,
+ double device_y)
+{
+ double user_x = device_x;
+ double user_y = device_y;
+ WCHAR glyph_index = index;
+ int logical_x, logical_y;
+
+ cairo_matrix_transform_point (&state->font->device_to_logical, &user_x, &user_y);
+
+ logical_x = floor (user_x + 0.5);
+ logical_y = floor (user_y + 0.5);
+
+ if (state->glyphs.num_elements > 0) {
+ int dx;
+
+ if (logical_y != state->last_y) {
+ cairo_status_t status = _flush_glyphs (state);
+ if (!CAIRO_OK (status))
+ return status;
+ state->start_x = logical_x;
+ }
+
+ dx = logical_x - state->last_x;
+ if (!_cairo_array_append (&state->dx, &dx, 1))
+ return CAIRO_STATUS_NO_MEMORY;
+ } else {
+ state->start_x = logical_x;
+ }
+
+ state->last_x = logical_x;
+ state->last_y = logical_y;
+
+ _cairo_array_append (&state->glyphs, &glyph_index, 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_finish_glyphs (cairo_glyph_state_t *state)
+{
+ _flush_glyphs (state);
+
+ _cairo_array_fini (&state->glyphs);
+ _cairo_array_fini (&state->dx);
+}
+
+static cairo_status_t
+_draw_glyphs_on_surface (cairo_win32_surface_t *surface,
+ cairo_win32_font_t *font,
+ COLORREF color,
+ int x_offset,
+ int y_offset,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_glyph_state_t state;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ int i;
+
+ if (!SaveDC (surface->dc))
+ return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC");
+
+ status = cairo_win32_font_select_font (&font->base, surface->dc);
+ if (!CAIRO_OK (status))
+ goto FAIL1;
+
+ SetTextColor (surface->dc, color);
+ SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT);
+ SetBkMode (surface->dc, TRANSPARENT);
+
+ _start_glyphs (&state, font, surface->dc);
+
+ for (i = 0; i < num_glyphs; i++) {
+ status = _add_glyph (&state, glyphs[i].index,
+ glyphs[i].x - x_offset, glyphs[i].y - y_offset);
+ if (!CAIRO_OK (status))
+ goto FAIL2;
+ }
+
+ FAIL2:
+ _finish_glyphs (&state);
+ cairo_win32_font_done_font (&font->base);
+ FAIL1:
+ RestoreDC (surface->dc, 1);
+
+ return status;
+}
+
+/* Duplicate the green channel of a 4-channel mask in the alpha channel, then
+ * invert the whole mask.
+ */
+static void
+_compute_argb32_mask_alpha (cairo_win32_surface_t *mask_surface)
+{
+ cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image;
+ int i, j;
+
+ for (i = 0; i < image->height; i++) {
+ uint32_t *p = (uint32_t *) (image->data + i * image->stride);
+ for (j = 0; j < image->width; j++) {
+ *p = 0xffffffff ^ (*p | ((*p & 0x0000ff00) << 16));
+ p++;
+ }
+ }
+}
+
+/* Invert a mask
+ */
+static void
+_invert_argb32_mask (cairo_win32_surface_t *mask_surface)
+{
+ cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image;
+ int i, j;
+
+ for (i = 0; i < image->height; i++) {
+ uint32_t *p = (uint32_t *) (image->data + i * image->stride);
+ for (j = 0; j < image->width; j++) {
+ *p = 0xffffffff ^ *p;
+ p++;
+ }
+ }
+}
+
+/* Compute an alpha-mask from a monochrome RGB24 image
+ */
+static cairo_surface_t *
+_compute_a8_mask (cairo_win32_surface_t *mask_surface)
+{
+ cairo_image_surface_t *image24 = (cairo_image_surface_t *)mask_surface->image;
+ cairo_image_surface_t *image8;
+ int i, j;
+
+ image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8,
+ image24->width, image24->height);
+ if (!image8)
+ return NULL;
+
+ for (i = 0; i < image24->height; i++) {
+ uint32_t *p = (uint32_t *) (image24->data + i * image24->stride);
+ unsigned char *q = (unsigned char *) (image8->data + i * image8->stride);
+
+ for (j = 0; j < image24->width; j++) {
+ *q = 255 - ((*p & 0x0000ff00) >> 8);
+ p++;
+ q++;
+ }
+ }
+
+ return &image8->base;
+}
+
+static cairo_status_t
+_cairo_win32_font_show_glyphs (void *abstract_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *generic_surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_win32_font_t *font = abstract_font;
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
+ cairo_status_t status;
+
+ if (width == 0 || height == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (_cairo_surface_is_win32 (generic_surface) &&
+ surface->format == CAIRO_FORMAT_RGB24 &&
+ operator == CAIRO_OPERATOR_OVER &&
+ pattern->type == CAIRO_PATTERN_SOLID &&
+ _cairo_pattern_is_opaque (pattern)) {
+
+ cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)pattern;
+
+ /* When compositing OVER on a GDI-understood surface, with a
+ * solid opaque color, we can just call ExtTextOut directly.
+ */
+ COLORREF new_color;
+
+ new_color = RGB (((int)(0xffff * solid_pattern->red)) >> 8,
+ ((int)(0xffff * solid_pattern->green)) >> 8,
+ ((int)(0xffff * solid_pattern->blue)) >> 8);
+
+ status = _draw_glyphs_on_surface (surface, font, new_color,
+ 0, 0,
+ glyphs, num_glyphs);
+
+ return status;
+ } else {
+ /* Otherwise, we need to draw using software fallbacks. We create a mask
+ * surface by drawing the the glyphs onto a DIB, black-on-white then
+ * inverting. GDI outputs gamma-corrected images so inverted black-on-white
+ * is very different from white-on-black. We favor the more common
+ * case where the final output is dark-on-light.
+ */
+ cairo_win32_surface_t *tmp_surface;
+ cairo_surface_t *mask_surface;
+ cairo_surface_pattern_t mask;
+ RECT r;
+
+ tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height);
+ if (!tmp_surface)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ r.left = 0;
+ r.top = 0;
+ r.right = width;
+ r.bottom = height;
+ FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH));
+
+ _draw_glyphs_on_surface (tmp_surface, font, RGB (0, 0, 0),
+ dest_x, dest_y,
+ glyphs, num_glyphs);
+
+ if (font->quality == CLEARTYPE_QUALITY) {
+ /* For ClearType, we need a 4-channel mask. If we are compositing on
+ * a surface with alpha, we need to compute the alpha channel of
+ * the mask (we just copy the green channel). But for a destination
+ * surface without alpha the alpha channel of the mask is ignored
+ */
+
+ if (surface->format != CAIRO_FORMAT_RGB24)
+ _compute_argb32_mask_alpha (tmp_surface);
+ else
+ _invert_argb32_mask (tmp_surface);
+
+ mask_surface = &tmp_surface->base;
+
+ /* XXX: Hacky, should expose this in cairo_image_surface */
+ pixman_image_set_component_alpha (((cairo_image_surface_t *)tmp_surface->image)->pixman_image, TRUE);
+
+ } else {
+ mask_surface = _compute_a8_mask (tmp_surface);
+ cairo_surface_destroy (&tmp_surface->base);
+ if (!mask_surface)
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ /* For operator == OVER, no-cleartype, a possible optimization here is to
+ * draw onto an intermediate ARGB32 surface and alpha-blend that with the
+ * destination
+ */
+ _cairo_pattern_init_for_surface (&mask, mask_surface);
+
+ status = _cairo_surface_composite (operator, pattern,
+ &mask.base,
+ &surface->base,
+ source_x, source_y,
+ 0, 0,
+ dest_x, dest_y,
+ width, height);
+
+ _cairo_pattern_fini (&mask.base);
+
+ cairo_surface_destroy (mask_surface);
+
+ return status;
+ }
+}
+
+static cairo_status_t
+_cairo_win32_font_glyph_path (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
+{
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+const cairo_font_backend_t cairo_win32_font_backend = {
+ _cairo_win32_font_create,
+ _cairo_win32_font_destroy_font,
+ _cairo_win32_font_destroy_unscaled_font,
+ _cairo_win32_font_font_extents,
+ _cairo_win32_font_text_to_glyphs,
+ _cairo_win32_font_glyph_extents,
+ _cairo_win32_font_glyph_bbox,
+ _cairo_win32_font_show_glyphs,
+ _cairo_win32_font_glyph_path,
+ _cairo_win32_font_get_glyph_cache_key,
+ _cairo_win32_font_create_glyph
+};
+
+/* implement the platform-specific interface */
+
+/**
+ * cairo_win32_font_create_for_logfontw:
+ * @logfont: A #LOGFONTW structure specifying the font to use.
+ * The lfHeight, lfWidth, lfOrientation and lfEscapement
+ * fields of this structure are ignored; information from
+ * @scale will be used instead.
+ * @scale: The scale at which this font will be used. The
+ * scale is given by multiplying the font matrix (see
+ * cairo_transform_font()) by the current transformation matrix.
+ * The translation elements of the resulting matrix are ignored.
+ *
+ * Creates a new font for the Win32 font backend based on a
+ * #LOGFONT. This font can then be used with
+ * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
+ * specific functions like cairo_win32_font_select_font().
+ *
+ * Return value: a newly created #cairo_font_t. Free with
+ * cairo_font_destroy() when you are done using it.
+ **/
+cairo_font_t *
+cairo_win32_font_create_for_logfontw (LOGFONTW *logfont,
+ cairo_matrix_t *scale)
+{
+ cairo_font_scale_t sc;
+
+ cairo_matrix_get_affine (scale,
+ &sc.matrix[0][0], &sc.matrix[0][1],
+ &sc.matrix[1][0], &sc.matrix[1][1],
+ NULL, NULL);
+
+ return _win32_font_create (logfont, &sc);
+}
+
+/**
+ * cairo_win32_font_select_font:
+ * @font: A #cairo_font_t from the Win32 font backend. Such an
+ * object can be created with cairo_win32_font_create_for_logfontw().
+ * @hdc: a device context
+ *
+ * Selects the font into the given device context and changes the
+ * map mode and world transformation of the device context to match
+ * that of the font. This function is intended for use when using
+ * layout APIs such as Uniscribe to do text layout with the
+ * Cairo font. After finishing using the device context, you must call
+ * cairo_win32_font_done_font() to release any resources allocated
+ * by this function.
+ *
+ * See cairo_win32_font_get_scale_factor() for converting logical
+ * coordinates from the device context to font space.
+ *
+ * Normally, calls to SaveDC() and RestoreDC() would be made around
+ * the use of this function to preserve the original graphics state.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if the operation succeeded.
+ * otherwise an error such as %CAIRO_STATUS_NO_MEMORY and
+ * the device context is unchanged.
+ **/
+cairo_status_t
+cairo_win32_font_select_font (cairo_font_t *font,
+ HDC hdc)
+{
+ cairo_status_t status;
+ HFONT hfont;
+ HFONT old_hfont = NULL;
+ int old_mode;
+
+ hfont = _win32_font_get_scaled_font ((cairo_win32_font_t *)font);
+ if (!hfont)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ old_hfont = SelectObject (hdc, hfont);
+ if (!old_hfont)
+ return _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
+
+ old_mode = SetGraphicsMode (hdc, GM_ADVANCED);
+ if (!old_mode) {
+ status = _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
+ SelectObject (hdc, old_hfont);
+ return status;
+ }
+
+ status = _win32_font_set_world_transform ((cairo_win32_font_t *)font, hdc);
+ if (!CAIRO_OK (status)) {
+ SetGraphicsMode (hdc, old_mode);
+ SelectObject (hdc, old_hfont);
+ return status;
+ }
+
+ SetMapMode (hdc, MM_TEXT);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * cairo_win32_font_done_font:
+ * @font: A #cairo_font_t from the Win32 font backend.
+ *
+ * Releases any resources allocated by cairo_win32_font_select_font()
+ **/
+void
+cairo_win32_font_done_font (cairo_font_t *font)
+{
+}
+
+/**
+ * cairo_win32_font_get_scale_factor:
+ * @font: a #cairo_font_t from the Win32 font backend
+ *
+ * Gets a scale factor between logical coordinates in the coordinate
+ * space used by cairo_win32_font_select_font() and font space coordinates.
+ *
+ * Return value: factor to multiply logical units by to get font space
+ * coordinates.
+ **/
+double
+cairo_win32_font_get_scale_factor (cairo_font_t *font)
+{
+ return 1. / ((cairo_win32_font_t *)font)->logical_scale;
+}
diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
new file mode 100644
index 000000000..71e677ad1
--- /dev/null
+++ b/src/cairo-win32-private.h
@@ -0,0 +1,87 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 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):
+ * Owen Taylor <otaylor@redhat.com>
+ */
+
+#ifndef CAIRO_WIN32_PRIVATE_H
+#define CAIRO_WIN32_PRIVATE_H
+
+/* We depend on various features introduced with Win2k and Win98,
+ * like AlphaBlend. If it turns out to be a problem, we could
+ * use GetProcAddress() to look them up.
+ */
+#define WINVER 0x0500
+
+#include <cairo-win32.h>
+#include <cairoint.h>
+
+typedef struct _cairo_win32_surface {
+ cairo_surface_t base;
+
+ cairo_format_t format;
+
+ HDC dc;
+
+ /* We create off-screen surfaces as DIBs */
+ HBITMAP bitmap;
+
+ /* Used to save the initial 1x1 monochrome bitmap for the DC to
+ * select back into the DC before deleting the DC and our
+ * bitmap. For Windows XP, this doesn't seem to be necessary
+ * ... we can just delete the DC and that automatically unselects
+ * out bitmap. But it's standard practice so apparently is needed
+ * on some versions of Windows.
+ */
+ HBITMAP saved_dc_bitmap;
+
+ cairo_surface_t *image;
+
+ cairo_rectangle_t clip_rect;
+
+ int set_clip;
+ HRGN saved_clip;
+
+} cairo_win32_surface_t;
+
+cairo_status_t
+_cairo_win32_print_gdi_error (const char *context);
+
+cairo_surface_t *
+_cairo_win32_surface_create_dib (cairo_format_t format,
+ int width,
+ int height);
+
+cairo_bool_t
+_cairo_surface_is_win32 (cairo_surface_t *surface);
+
+#endif /* CAIRO_WIN32_PRIVATE_H */
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
new file mode 100644
index 000000000..dcfe6d044
--- /dev/null
+++ b/src/cairo-win32-surface.c
@@ -0,0 +1,931 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 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):
+ * Owen Taylor <otaylor@redhat.com>
+ */
+
+#include <stdio.h>
+
+#include "cairo-win32-private.h"
+
+static const cairo_surface_backend_t cairo_win32_surface_backend;
+
+/**
+ * _cairo_win32_print_gdi_error:
+ * @context: context string to display along with the error
+ *
+ * Helper function to dump out a human readable form of the
+ * current error code.
+ *
+ * Return value: A Cairo status code for the error code
+ **/
+cairo_status_t
+_cairo_win32_print_gdi_error (const char *context)
+{
+ void *lpMsgBuf;
+ DWORD last_error = GetLastError ();
+
+ if (!FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ last_error,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL)) {
+ fprintf (stderr, "%s: Unknown GDI error", context);
+ } else {
+ fprintf (stderr, "%s: %s", context, (char *)lpMsgBuf);
+
+ LocalFree (lpMsgBuf);
+ }
+
+ /* We should switch off of last_status, but we'd either return
+ * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
+ * is no CAIRO_STATUS_UNKNOWN_ERROR.
+ */
+
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+void
+cairo_set_target_win32 (cairo_t *cr,
+ HDC hdc)
+{
+ cairo_surface_t *surface;
+
+ if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
+ return;
+
+ surface = cairo_win32_surface_create (hdc);
+ if (surface == NULL) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_set_target_surface (cr, surface);
+
+ /* cairo_set_target_surface takes a reference, so we must destroy ours */
+ cairo_surface_destroy (surface);
+}
+
+static cairo_status_t
+_create_dc_and_bitmap (cairo_win32_surface_t *surface,
+ HDC original_dc,
+ cairo_format_t format,
+ int width,
+ int height,
+ char **bits_out,
+ int *rowstride_out)
+{
+ cairo_status_t status;
+
+ BITMAPINFO *bitmap_info = NULL;
+ struct {
+ BITMAPINFOHEADER bmiHeader;
+ RGBQUAD bmiColors[2];
+ } bmi_stack;
+ void *bits;
+
+ int num_palette = 0; /* Quiet GCC */
+ int i;
+
+ surface->dc = NULL;
+ surface->bitmap = NULL;
+
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB24:
+ num_palette = 0;
+ break;
+
+ case CAIRO_FORMAT_A8:
+ num_palette = 256;
+ break;
+
+ case CAIRO_FORMAT_A1:
+ num_palette = 2;
+ break;
+ }
+
+ if (num_palette > 2) {
+ bitmap_info = malloc (sizeof (BITMAPINFOHEADER) + num_palette * sizeof (RGBQUAD));
+ if (!bitmap_info)
+ return CAIRO_STATUS_NO_MEMORY;
+ } else {
+ bitmap_info = (BITMAPINFO *)&bmi_stack;
+ }
+
+ bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+ bitmap_info->bmiHeader.biWidth = width;
+ bitmap_info->bmiHeader.biHeight = - height; /* top-down */
+ bitmap_info->bmiHeader.biSizeImage = 0;
+ bitmap_info->bmiHeader.biXPelsPerMeter = 72. / 0.0254; /* unused here */
+ bitmap_info->bmiHeader.biYPelsPerMeter = 72. / 0.0254; /* unused here */
+ bitmap_info->bmiHeader.biPlanes = 1;
+
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB24:
+ bitmap_info->bmiHeader.biBitCount = 32;
+ bitmap_info->bmiHeader.biCompression = BI_RGB;
+ bitmap_info->bmiHeader.biClrUsed = 0; /* unused */
+ bitmap_info->bmiHeader.biClrImportant = 0;
+ break;
+
+ case CAIRO_FORMAT_A8:
+ bitmap_info->bmiHeader.biBitCount = 8;
+ bitmap_info->bmiHeader.biCompression = BI_RGB;
+ bitmap_info->bmiHeader.biClrUsed = 256;
+ bitmap_info->bmiHeader.biClrImportant = 0;
+
+ for (i = 0; i < 256; i++) {
+ bitmap_info->bmiColors[i].rgbBlue = i;
+ bitmap_info->bmiColors[i].rgbGreen = i;
+ bitmap_info->bmiColors[i].rgbRed = i;
+ bitmap_info->bmiColors[i].rgbReserved = 0;
+ }
+
+ break;
+
+ case CAIRO_FORMAT_A1:
+ bitmap_info->bmiHeader.biBitCount = 1;
+ bitmap_info->bmiHeader.biCompression = BI_RGB;
+ bitmap_info->bmiHeader.biClrUsed = 2;
+ bitmap_info->bmiHeader.biClrImportant = 0;
+
+ for (i = 0; i < 2; i++) {
+ bitmap_info->bmiColors[i].rgbBlue = i * 255;
+ bitmap_info->bmiColors[i].rgbGreen = i * 255;
+ bitmap_info->bmiColors[i].rgbRed = i * 255;
+ bitmap_info->bmiColors[i].rgbReserved = 0;
+ break;
+ }
+ }
+
+ surface->dc = CreateCompatibleDC (original_dc);
+ if (!surface->dc)
+ goto FAIL;
+
+ surface->bitmap = CreateDIBSection (surface->dc,
+ bitmap_info,
+ DIB_RGB_COLORS,
+ &bits,
+ NULL, 0);
+ if (!surface->bitmap)
+ goto FAIL;
+
+ surface->saved_dc_bitmap = SelectObject (surface->dc,
+ surface->bitmap);
+ if (!surface->saved_dc_bitmap)
+ goto FAIL;
+
+ if (bitmap_info && num_palette > 2)
+ free (bitmap_info);
+
+ if (bits_out)
+ *bits_out = bits;
+
+ if (rowstride_out) {
+ /* Windows bitmaps are padded to 16-bit (word) boundaries */
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB24:
+ *rowstride_out = 4 * width;
+ break;
+
+ case CAIRO_FORMAT_A8:
+ *rowstride_out = (width + 1) & -2;
+ break;
+
+ case CAIRO_FORMAT_A1:
+ *rowstride_out = ((width + 15) & -16) / 8;
+ break;
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+
+ FAIL:
+ status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap");
+
+ if (bitmap_info && num_palette > 2)
+ free (bitmap_info);
+
+ if (surface->saved_dc_bitmap) {
+ SelectObject (surface->dc, surface->saved_dc_bitmap);
+ surface->saved_dc_bitmap = NULL;
+ }
+
+ if (surface->bitmap) {
+ DeleteObject (surface->bitmap);
+ surface->bitmap = NULL;
+ }
+
+ if (surface->dc) {
+ DeleteDC (surface->dc);
+ surface->dc = NULL;
+ }
+
+ return status;
+}
+
+static cairo_surface_t *
+_cairo_win32_surface_create_for_dc (HDC original_dc,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ cairo_win32_surface_t *surface;
+ char *bits;
+ int rowstride;
+
+ surface = malloc (sizeof (cairo_win32_surface_t));
+ if (!surface)
+ return NULL;
+
+ if (_create_dc_and_bitmap (surface, original_dc, format,
+ width, height,
+ &bits, &rowstride) != CAIRO_STATUS_SUCCESS)
+ goto FAIL;
+
+ surface->image = cairo_image_surface_create_for_data (bits, format,
+ width, height, rowstride);
+ if (!surface->image)
+ goto FAIL;
+
+ surface->format = format;
+
+ surface->clip_rect.x = 0;
+ surface->clip_rect.y = 0;
+ surface->clip_rect.width = width;
+ surface->clip_rect.height = height;
+
+ surface->set_clip = 0;
+ surface->saved_clip = NULL;
+
+ _cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
+
+ return (cairo_surface_t *)surface;
+
+ FAIL:
+ if (surface->bitmap) {
+ SelectObject (surface->dc, surface->saved_dc_bitmap);
+ DeleteObject (surface->bitmap);
+ DeleteDC (surface->dc);
+ }
+ if (surface)
+ free (surface);
+
+ return NULL;
+
+}
+
+static cairo_surface_t *
+_cairo_win32_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ cairo_win32_surface_t *src = abstract_src;
+
+ return _cairo_win32_surface_create_for_dc (src->dc, format, drawable,
+ width, height);
+}
+
+/**
+ * _cairo_win32_surface_create_dib:
+ * @format: format of pixels in the surface to create
+ * @width: width of the surface, in pixels
+ * @height: height of the surface, in pixels
+ *
+ * Creates a device-independent-bitmap surface not associated with
+ * any particular existing surface or device context. The created
+ * bitmap will be unititialized.
+ *
+ * Return value: the newly created surface, or %NULL if it couldn't
+ * be created (probably because of lack of memory)
+ **/
+cairo_surface_t *
+_cairo_win32_surface_create_dib (cairo_format_t format,
+ int width,
+ int height)
+{
+ return _cairo_win32_surface_create_for_dc (NULL, format, TRUE,
+ width, height);
+}
+
+static void
+_cairo_win32_surface_destroy (void *abstract_surface)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+
+ if (surface->image)
+ cairo_surface_destroy (surface->image);
+
+ if (surface->saved_clip)
+ DeleteObject (surface->saved_clip);
+
+ /* If we created the Bitmap and DC, destroy them */
+ if (surface->bitmap) {
+ SelectObject (surface->dc, surface->saved_dc_bitmap);
+ DeleteObject (surface->bitmap);
+ DeleteDC (surface->dc);
+ }
+
+ free (surface);
+}
+
+static double
+_cairo_win32_surface_pixels_per_inch (void *abstract_surface)
+{
+ /* XXX: We should really get this value from somewhere */
+ return 96.0;
+}
+
+static cairo_status_t
+_cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
+ int x,
+ int y,
+ int width,
+ int height,
+ cairo_win32_surface_t **local_out)
+{
+ cairo_win32_surface_t *local;
+ cairo_status_t status;
+
+ local =
+ (cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface,
+ surface->format,
+ 0,
+ width, height);
+ if (!local)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (!BitBlt (local->dc,
+ 0, 0,
+ width, height,
+ surface->dc,
+ x, y,
+ SRCCOPY))
+ goto FAIL;
+
+ *local_out = local;
+
+ return CAIRO_STATUS_SUCCESS;
+
+ FAIL:
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_get_subimage");
+
+ if (local)
+ cairo_surface_destroy (&local->base);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_win32_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_win32_surface_t *local = NULL;
+ cairo_status_t status;
+
+ if (surface->image) {
+ *image_out = (cairo_image_surface_t *)surface->image;
+ *image_extra = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0,
+ surface->clip_rect.width,
+ surface->clip_rect.height, &local);
+ if (CAIRO_OK (status)) {
+ cairo_surface_set_filter (&local->base, surface->base.filter);
+ cairo_surface_set_matrix (&local->base, &surface->base.matrix);
+ cairo_surface_set_repeat (&local->base, surface->base.repeat);
+
+ *image_out = (cairo_image_surface_t *)local->image;
+ *image_extra = local;
+ }
+
+ return status;
+}
+
+static void
+_cairo_win32_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ cairo_win32_surface_t *local = image_extra;
+
+ if (local)
+ cairo_surface_destroy ((cairo_surface_t *)local);
+}
+
+static cairo_status_t
+_cairo_win32_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect,
+ void **image_extra)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_win32_surface_t *local = NULL;
+ cairo_status_t status;
+ RECT clip_box;
+ int x1, y1, x2, y2;
+
+ if (surface->image) {
+ image_rect->x = 0;
+ image_rect->y = 0;
+ image_rect->width = surface->clip_rect.width;
+ image_rect->height = surface->clip_rect.height;
+
+ *image_out = (cairo_image_surface_t *)surface->image;
+ *image_extra = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (GetClipBox (surface->dc, &clip_box) == ERROR)
+ return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
+
+ x1 = clip_box.left;
+ x2 = clip_box.right;
+ y1 = clip_box.top;
+ y2 = clip_box.bottom;
+
+ if (interest_rect->x > x1)
+ x1 = interest_rect->x;
+ if (interest_rect->y > y1)
+ y1 = interest_rect->y;
+ if (interest_rect->x + interest_rect->width < x2)
+ x2 = interest_rect->x + interest_rect->width;
+ if (interest_rect->y + interest_rect->height < y2)
+ y2 = interest_rect->y + interest_rect->height;
+
+ if (x1 >= x2 || y1 >= y2) {
+ *image_out = NULL;
+ *image_extra = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ status = _cairo_win32_surface_get_subimage (abstract_surface,
+ x1, y1, x2 - x1, y2 - y1,
+ &local);
+ if (CAIRO_OK (status)) {
+ *image_out = (cairo_image_surface_t *)local->image;
+ *image_extra = local;
+
+ image_rect->x = x1;
+ image_rect->y = y1;
+ image_rect->width = x2 - x1;
+ image_rect->height = y2 - y1;
+ }
+
+ return status;
+}
+
+static void
+_cairo_win32_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_win32_surface_t *local = image_extra;
+
+ if (!local)
+ return;
+
+ if (!BitBlt (surface->dc,
+ image_rect->x, image_rect->y,
+ image_rect->width, image_rect->height,
+ local->dc,
+ 0, 0,
+ SRCCOPY))
+ _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
+
+ cairo_surface_destroy ((cairo_surface_t *)local);
+}
+
+static cairo_status_t
+_cairo_win32_surface_clone_similar (void *surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_composite (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_pattern_t *mask_pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ cairo_win32_surface_t *dst = abstract_dst;
+ cairo_win32_surface_t *src;
+ cairo_surface_pattern_t *src_surface_pattern;
+ int alpha;
+ int integer_transform;
+ int itx, ity;
+
+ if (pattern->type != CAIRO_PATTERN_SURFACE ||
+ pattern->extend != CAIRO_EXTEND_NONE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (mask_pattern) {
+ /* FIXME: When we fully support RENDER style 4-channel
+ * masks we need to check r/g/b != 1.0.
+ */
+ if (mask_pattern->type != CAIRO_PATTERN_SOLID)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ alpha = (int)(0xffff * pattern->alpha * mask_pattern->alpha) >> 8;
+ } else {
+ alpha = (int)(0xffff * pattern->alpha) >> 8;
+ }
+
+ src_surface_pattern = (cairo_surface_pattern_t *)pattern;
+ src = (cairo_win32_surface_t *)src_surface_pattern->surface;
+
+ if (src->base.backend != dst->base.backend)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ integer_transform = _cairo_matrix_is_integer_translation (&pattern->matrix, &itx, &ity);
+ if (!integer_transform)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (alpha == 255 &&
+ src->format == dst->format &&
+ (operator == CAIRO_OPERATOR_SRC ||
+ (src->format == CAIRO_FORMAT_RGB24 && operator == CAIRO_OPERATOR_OVER))) {
+
+ if (!BitBlt (dst->dc,
+ dst_x, dst_y,
+ width, height,
+ src->dc,
+ src_x + itx, src_y + ity,
+ SRCCOPY))
+ return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
+
+ return CAIRO_STATUS_SUCCESS;
+
+ } else if (integer_transform &&
+ (src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) &&
+ dst->format == CAIRO_FORMAT_RGB24 &&
+ !src->base.repeat &&
+ operator == CAIRO_OPERATOR_OVER) {
+
+ BLENDFUNCTION blend_function;
+
+ blend_function.BlendOp = AC_SRC_OVER;
+ blend_function.BlendFlags = 0;
+ blend_function.SourceConstantAlpha = alpha;
+ blend_function.AlphaFormat = src->format == CAIRO_FORMAT_ARGB32 ? AC_SRC_ALPHA : 0;
+
+ if (!AlphaBlend (dst->dc,
+ dst_x, dst_y,
+ width, height,
+ src->dc,
+ src_x + itx, src_y + ity,
+ width, height,
+ blend_function))
+ return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_fill_rectangles (void *abstract_surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+ COLORREF new_color;
+ HBRUSH new_brush;
+ int i;
+
+ /* If we have a local image, use the fallback code; it will be as fast
+ * as calling out to GDI.
+ */
+ if (surface->image)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* We could support possibly support more operators for color->alpha = 0xffff.
+ * for CAIRO_OPERATOR_SRC, alpha doesn't matter since we know the destination
+ * image doesn't have alpha. (surface->pixman_image is non-NULL for all
+ * surfaces with alpha.)
+ */
+ if (operator != CAIRO_OPERATOR_SRC)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
+
+ new_brush = CreateSolidBrush (new_color);
+ if (!new_brush)
+ return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
+
+ for (i = 0; i < num_rects; i++) {
+ RECT rect;
+
+ rect.left = rects[i].x;
+ rect.top = rects[i].y;
+ rect.right = rects[i].x + rects[i].width;
+ rect.bottom = rects[i].y + rects[i].height;
+
+ if (!FillRect (surface->dc, &rect, new_brush))
+ goto FAIL;
+ }
+
+ DeleteObject (new_brush);
+
+ return CAIRO_STATUS_SUCCESS;
+
+ FAIL:
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
+
+ DeleteObject (new_brush);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_composite_trapezoids (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_copy_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_show_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ /* If we are in-memory, then we set the clip on the image surface
+ * as well as on the underlying GDI surface.
+ */
+ if (surface->image)
+ _cairo_surface_set_clip_region (surface->image, region);
+
+ /* The semantics we want is that any clip set by Cairo combines
+ * is intersected with the clip on device context that the
+ * surface was created for. To implement this, we need to
+ * save the original clip when first setting a clip on surface.
+ */
+
+ if (region == NULL) {
+ /* Clear any clip set by Cairo, return to the original */
+
+ if (surface->set_clip) {
+ if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
+ return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
+
+ if (surface->saved_clip) {
+ DeleteObject (surface->saved_clip);
+ surface->saved_clip = NULL;
+ }
+
+ surface->set_clip = 0;
+ }
+
+
+ return CAIRO_STATUS_SUCCESS;
+
+ } else {
+ pixman_box16_t *boxes = pixman_region_rects (region);
+ int num_boxes = pixman_region_num_rects (region);
+ pixman_box16_t *extents = pixman_region_extents (region);
+ RGNDATA *data;
+ size_t data_size;
+ RECT *rects;
+ int i;
+ HRGN gdi_region;
+
+ /* Create a GDI region for the cairo region */
+
+ data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT);
+ data = malloc (data_size);
+ if (!data)
+ return CAIRO_STATUS_NO_MEMORY;
+ rects = (RECT *)data->Buffer;
+
+ data->rdh.dwSize = sizeof (RGNDATAHEADER);
+ data->rdh.iType = RDH_RECTANGLES;
+ data->rdh.nCount = num_boxes;
+ data->rdh.nRgnSize = num_boxes * sizeof (RECT);
+ data->rdh.rcBound.left = extents->x1;
+ data->rdh.rcBound.top = extents->y1;
+ data->rdh.rcBound.right = extents->x2;
+ data->rdh.rcBound.bottom = extents->y2;
+
+ for (i = 0; i < num_boxes; i++) {
+ rects[i].left = boxes[i].x1;
+ rects[i].top = boxes[i].y1;
+ rects[i].right = boxes[i].x2;
+ rects[i].bottom = boxes[i].y2;
+ }
+
+ gdi_region = ExtCreateRegion (NULL, data_size, data);
+ free (data);
+
+ if (!gdi_region)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (surface->set_clip) {
+ /* Combine the new region with the original clip */
+
+ if (surface->saved_clip) {
+ if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR)
+ goto FAIL;
+ }
+
+ if (SelectClipRgn (surface->dc, gdi_region) == ERROR)
+ goto FAIL;
+
+ } else {
+ /* Save the the current region */
+
+ surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
+ if (!surface->saved_clip) {
+ goto FAIL; }
+
+ /* This function has no error return! */
+ if (GetClipRgn (surface->dc, surface->saved_clip) == 0) { /* No clip */
+ DeleteObject (surface->saved_clip);
+ surface->saved_clip = NULL;
+ }
+
+ if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
+ goto FAIL;
+
+ surface->set_clip = 1;
+ }
+
+ DeleteObject (gdi_region);
+ return CAIRO_STATUS_SUCCESS;
+
+ FAIL:
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
+ DeleteObject (gdi_region);
+ return status;
+ }
+}
+
+static cairo_status_t
+_cairo_win32_surface_show_glyphs (cairo_font_t *font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ void *abstract_surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_surface_t *
+cairo_win32_surface_create (HDC hdc)
+{
+ cairo_win32_surface_t *surface;
+ RECT rect;
+
+ /* Try to figure out the drawing bounds for the Device context
+ */
+ if (GetClipBox (hdc, &rect) == ERROR) {
+ _cairo_win32_print_gdi_error ("cairo_win32_surface_create");
+ return NULL;
+ }
+
+ surface = malloc (sizeof (cairo_win32_surface_t));
+ if (!surface)
+ return NULL;
+
+ surface->image = NULL;
+ surface->format = CAIRO_FORMAT_RGB24;
+
+ surface->dc = hdc;
+ surface->bitmap = NULL;
+
+ surface->clip_rect.x = rect.left;
+ surface->clip_rect.y = rect.top;
+ surface->clip_rect.width = rect.right - rect.left;
+ surface->clip_rect.height = rect.bottom - rect.top;
+
+ surface->set_clip = 0;
+ surface->saved_clip = NULL;
+
+ _cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
+
+ return (cairo_surface_t *)surface;
+}
+
+/**
+ * _cairo_surface_is_win32:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is an #cairo_win32_surface_t
+ *
+ * Return value: True if the surface is an win32 surface
+ **/
+int
+_cairo_surface_is_win32 (cairo_surface_t *surface)
+{
+ return surface->backend == &cairo_win32_surface_backend;
+}
+
+static const cairo_surface_backend_t cairo_win32_surface_backend = {
+ _cairo_win32_surface_create_similar,
+ _cairo_win32_surface_destroy,
+ _cairo_win32_surface_pixels_per_inch,
+ _cairo_win32_surface_acquire_source_image,
+ _cairo_win32_surface_release_source_image,
+ _cairo_win32_surface_acquire_dest_image,
+ _cairo_win32_surface_release_dest_image,
+ _cairo_win32_surface_clone_similar,
+ _cairo_win32_surface_composite,
+ _cairo_win32_surface_fill_rectangles,
+ _cairo_win32_surface_composite_trapezoids,
+ _cairo_win32_surface_copy_page,
+ _cairo_win32_surface_show_page,
+ _cairo_win32_surface_set_clip_region,
+ _cairo_win32_surface_show_glyphs
+};
diff --git a/src/cairo-win32.h b/src/cairo-win32.h
new file mode 100644
index 000000000..fab497aa4
--- /dev/null
+++ b/src/cairo-win32.h
@@ -0,0 +1,71 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 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):
+ * Owen Taylor <otaylor@redhat.com>
+ */
+
+#ifndef _CAIRO_WIN32_H_
+
+#include <cairo.h>
+
+#ifdef CAIRO_HAS_WIN32_SURFACE
+
+#include <windows.h>
+
+CAIRO_BEGIN_DECLS
+
+void
+cairo_set_target_win32 (cairo_t *cr,
+ HDC hdc);
+
+cairo_surface_t *
+cairo_win32_surface_create (HDC hdc);
+
+cairo_font_t *
+cairo_win32_font_create_for_logfontw (LOGFONTW *logfont,
+ cairo_matrix_t *scale);
+
+cairo_status_t
+cairo_win32_font_select_font (cairo_font_t *font,
+ HDC hdc);
+
+void
+cairo_win32_font_done_font (cairo_font_t *font);
+
+double
+cairo_win32_font_get_scale_factor (cairo_font_t *font);
+
+#endif /* CAIRO_HAS_WIN32_SURFACE */
+
+CAIRO_END_DECLS
+
+#endif /* _CAIRO_WIN32_H_ */
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 758cf26de..0694b77a2 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -31,10 +31,11 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
+#include "cairo-xcb.h"
cairo_surface_t *
cairo_xcb_surface_create (XCBConnection *dpy,
@@ -327,14 +328,17 @@ bytes_per_line(XCBConnection *c, int width, int bpp)
return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
}
-static cairo_image_surface_t *
-_cairo_xcb_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_get_image_surface (cairo_xcb_surface_t *surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect)
{
- cairo_xcb_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
XCBGetGeometryRep *geomrep;
XCBGetImageRep *imagerep;
int bpp;
+ int x1, y1, x2, y2;
geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0);
if(!geomrep)
@@ -344,11 +348,39 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
surface->height = geomrep->height;
free(geomrep);
+ x1 = 0;
+ y1 = 0;
+ x2 = surface->width;
+ y2 = surface->height;
+
+ if (interest_rect) {
+ if (interest_rect->x > x1)
+ x1 = interest_rect->x;
+ if (interest_rect->y > y1)
+ y1 = interest_rect->y;
+ if (interest_rect->x + interest_rect->width < x2)
+ x2 = interest_rect->x + interest_rect->width;
+ if (interest_rect->y + interest_rect->height < y2)
+ y2 = interest_rect->y + interest_rect->height;
+
+ if (x1 >= x2 || y1 >= y2) {
+ *image_out = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ if (image_rect) {
+ image_rect->x = x1;
+ image_rect->y = y1;
+ image_rect->width = x2 - x1;
+ image_rect->height = y2 - y1;
+ }
+
imagerep = XCBGetImageReply(surface->dpy,
XCBGetImage(surface->dpy, ZPixmap,
surface->drawable,
- 0, 0,
- surface->width, surface->height,
+ x1, y1,
+ x2 - x1, y2 - y1,
AllPlanes), 0);
if(!imagerep)
return 0;
@@ -368,15 +400,15 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep),
&masks,
- surface->width,
- surface->height,
+ x2 - x1,
+ y2 - y1,
bytes_per_line(surface->dpy, surface->width, bpp));
} else {
image = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (XCBGetImageData(imagerep),
surface->format,
- surface->width,
- surface->height,
+ x2 - x1,
+ y2 - y1,
bytes_per_line(surface->dpy, surface->width, bpp));
}
@@ -388,7 +420,8 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
_cairo_image_surface_set_repeat (image, surface->base.repeat);
_cairo_image_surface_set_matrix (image, &(surface->base.matrix));
- return image;
+ *image_out = image;
+ return CAIRO_STATUS_SUCCESS;
}
static void
@@ -402,10 +435,11 @@ _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
}
static cairo_status_t
-_cairo_xcb_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+_draw_image_surface (cairo_xcb_surface_t *surface,
+ cairo_image_surface_t *image,
+ int dst_x,
+ int dst_y)
{
- cairo_xcb_surface_t *surface = abstract_surface;
int bpp, data_len;
_cairo_xcb_surface_ensure_gc (surface);
@@ -414,7 +448,7 @@ _cairo_xcb_surface_set_image (void *abstract_surface,
XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
image->width,
image->height,
- /* dst_x */ 0, /* dst_y */ 0,
+ dst_x, dst_y,
/* left_pad */ 0, image->depth,
data_len, image->data);
@@ -422,9 +456,107 @@ _cairo_xcb_surface_set_image (void *abstract_surface,
}
static cairo_status_t
-_cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
+_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
+
+ status = _get_image_surface (surface, NULL, &image, NULL);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ cairo_surface_set_filter (&image->base, surface->base.filter);
+ cairo_surface_set_matrix (&image->base, &surface->base.matrix);
+ cairo_surface_set_repeat (&image->base, surface->base.repeat);
+
+ *image_out = image;
+ }
+
+ return status;
+}
+
+static void
+_cairo_xcb_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ cairo_surface_destroy (&image->base);
+}
+
+static cairo_status_t
+_cairo_xcb_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect_out,
+ void **image_extra)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
+
+ status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
+ if (status == CAIRO_STATUS_SUCCESS)
+ *image_out = image;
+
+ return status;
+}
+
+static void
+_cairo_xcb_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+
+ /* ignore errors */
+ _draw_image_surface (surface, image, image_rect->x, image_rect->y);
+
+ cairo_surface_destroy (&image->base);
+}
+
+static cairo_status_t
+_cairo_xcb_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_xcb_surface_t *clone;
+
+ if (src->backend == surface->base.backend ) {
+ cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
+
+ if (xcb_src->dpy == surface->dpy) {
+ *clone_out = src;
+ cairo_surface_reference (src);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+ } else if (_cairo_surface_is_image (src)) {
+ cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
+
+ clone = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_similar (surface, image_src->format, 0,
+ image_src->width, image_src->height);
+ if (clone == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _draw_image_surface (clone, image_src, 0, 0);
+
+ *clone_out = &clone->base;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
+ cairo_matrix_t *matrix)
+{
XCBRenderTRANSFORM xtransform;
if (!surface->picture.xid)
@@ -442,27 +574,42 @@ _cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
xtransform.matrix32 = 0;
xtransform.matrix33 = _cairo_fixed_from_double (1);
- if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
+ if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
{
- XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
- } else {
- /* XXX: Need support here if using an old RENDER without support
- for SetPictureTransform */
+ static const XCBRenderTRANSFORM identity = {
+ 1 << 16, 0x00000, 0x00000,
+ 0x00000, 1 << 16, 0x00000,
+ 0x00000, 0x00000, 1 << 16
+ };
+
+ if (memcmp (&xtransform, &identity, sizeof (XCBRenderTRANSFORM)) == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
+
+ XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
+_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
+ cairo_filter_t filter)
{
- cairo_xcb_surface_t *surface = abstract_surface;
char *render_filter;
- if (!(surface->picture.xid
- && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)))
+ if (!surface->picture.xid)
return CAIRO_STATUS_SUCCESS;
-
+
+ if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
+ {
+ if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
+ return CAIRO_STATUS_SUCCESS;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
switch (filter) {
case CAIRO_FILTER_FAST:
render_filter = "fast";
@@ -491,10 +638,8 @@ _cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
}
static cairo_status_t
-_cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat)
+_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat)
{
- cairo_xcb_surface_t *surface = abstract_surface;
-
CARD32 mask = XCBRenderCPRepeat;
CARD32 pa[] = { repeat };
@@ -506,33 +651,32 @@ _cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_xcb_surface_t *
-_cairo_xcb_surface_clone_similar (cairo_surface_t *src,
- cairo_xcb_surface_t *template,
- cairo_format_t format,
- int depth)
+static cairo_int_status_t
+_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface,
+ cairo_surface_attributes_t *attributes)
{
- cairo_xcb_surface_t *clone;
- cairo_image_surface_t *src_image;
-
- src_image = _cairo_surface_get_image (src);
-
- clone = (cairo_xcb_surface_t *)
- _cairo_xcb_surface_create_similar (template, format, 0,
- src_image->width,
- src_image->height);
- if (clone == NULL)
- return NULL;
-
- _cairo_xcb_surface_set_filter (clone, cairo_surface_get_filter(src));
-
- _cairo_xcb_surface_set_image (clone, src_image);
+ cairo_int_status_t status;
- _cairo_xcb_surface_set_matrix (clone, &(src_image->base.matrix));
+ status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix);
+ if (status)
+ return status;
+
+ switch (attributes->extend) {
+ case CAIRO_EXTEND_NONE:
+ _cairo_xcb_surface_set_repeat (surface, 0);
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ _cairo_xcb_surface_set_repeat (surface, 1);
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
- cairo_surface_destroy (&src_image->base);
+ status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
+ if (status)
+ return status;
- return clone;
+ return CAIRO_STATUS_SUCCESS;
}
static int
@@ -574,65 +718,80 @@ _render_operator (cairo_operator_t operator)
static cairo_int_status_t
_cairo_xcb_surface_composite (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
+ cairo_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
{
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
- cairo_xcb_surface_t *mask = (cairo_xcb_surface_t *) generic_mask;
- cairo_xcb_surface_t *src_clone = NULL;
- cairo_xcb_surface_t *mask_clone = NULL;
- XCBRenderPICTURE maskpict = { 0 };
-
+ cairo_surface_attributes_t src_attr, mask_attr;
+ cairo_xcb_surface_t *dst = abstract_dst;
+ cairo_xcb_surface_t *src;
+ cairo_xcb_surface_t *mask;
+ cairo_int_status_t status;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
- src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
- CAIRO_FORMAT_ARGB32, 32);
- if (!src_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- src = src_clone;
- }
- if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) {
- mask_clone = _cairo_xcb_surface_clone_similar (generic_mask, dst,
- CAIRO_FORMAT_A8, 8);
- if (!mask_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- mask = mask_clone;
+ status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
+ &dst->base,
+ src_x, src_y,
+ mask_x, mask_y,
+ width, height,
+ (cairo_surface_t **) &src,
+ (cairo_surface_t **) &mask,
+ &src_attr, &mask_attr);
+ if (status)
+ return status;
+
+ status = _cairo_xcb_surface_set_attributes (src, &src_attr);
+ if (CAIRO_OK (status))
+ {
+ if (mask)
+ {
+ status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
+ if (CAIRO_OK (status))
+ XCBRenderComposite (dst->dpy,
+ _render_operator (operator),
+ src->picture,
+ mask->picture,
+ dst->picture,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ mask_x + mask_attr.x_offset,
+ mask_y + mask_attr.y_offset,
+ dst_x, dst_y,
+ width, height);
+ }
+ else
+ {
+ static XCBRenderPICTURE maskpict = { 0 };
+
+ XCBRenderComposite (dst->dpy,
+ _render_operator (operator),
+ src->picture,
+ maskpict,
+ dst->picture,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ }
}
- if(mask)
- maskpict = mask->picture;
-
- XCBRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- maskpict,
- dst->picture,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
-
- /* XXX: This is messed up. If I can xcb_surface_create, then I
- should be able to xcb_surface_destroy. */
- if (src_clone)
- cairo_surface_destroy (&src_clone->base);
- if (mask_clone)
- cairo_surface_destroy (&mask_clone->base);
+ if (mask)
+ _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
+
+ _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_int_status_t
@@ -664,42 +823,60 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface,
static cairo_int_status_t
_cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- void *abstract_dst,
- int xSrc,
- int ySrc,
- cairo_trapezoid_t *traps,
- int num_traps)
+ cairo_pattern_t *pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_trapezoid_t *traps,
+ int num_traps)
{
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
- cairo_xcb_surface_t *src_clone = NULL;
+ cairo_surface_attributes_t attributes;
+ cairo_xcb_surface_t *dst = abstract_dst;
+ cairo_xcb_surface_t *src;
+ cairo_int_status_t status;
+ int render_reference_x, render_reference_y;
+ int render_src_x, render_src_y;
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
- src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
- CAIRO_FORMAT_ARGB32, 32);
- if (!src_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- src = src_clone;
+
+ status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ src_x, src_y, width, height,
+ (cairo_surface_t **) &src,
+ &attributes);
+ if (status)
+ return status;
+
+ if (traps[0].left.p1.y < traps[0].left.p2.y) {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
+ } else {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
}
- /* XXX: The XCBRenderTRAP cast is evil and needs to go away somehow. */
- /* XXX: format_from_cairo is slow. should cache something. */
- XCBRenderTrapezoids (dst->dpy,
- _render_operator (operator),
- src->picture, dst->picture,
- format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
- xSrc, ySrc, num_traps, (XCBRenderTRAP *) traps);
-
- /* XXX: This is messed up. If I can xcb_surface_create, then I
- should be able to xcb_surface_destroy. */
- if (src_clone)
- cairo_surface_destroy (&src_clone->base);
+ render_src_x = src_x + render_reference_x - dst_x;
+ render_src_y = src_y + render_reference_y - dst_y;
- return CAIRO_STATUS_SUCCESS;
+ /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
+ /* XXX: format_from_cairo is slow. should cache something. */
+ status = _cairo_xcb_surface_set_attributes (src, &attributes);
+ if (CAIRO_OK (status))
+ XCBRenderTrapezoids (dst->dpy,
+ _render_operator (operator),
+ src->picture, dst->picture,
+ format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
+ render_src_x + attributes.x_offset,
+ render_src_y + attributes.y_offset,
+ num_traps, (XCBRenderTRAP *) traps);
+
+ _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
+
+ return status;
}
static cairo_int_status_t
@@ -722,30 +899,21 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_int_status_t
-_cairo_xcb_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_destroy,
_cairo_xcb_surface_pixels_per_inch,
- _cairo_xcb_surface_get_image,
- _cairo_xcb_surface_set_image,
- _cairo_xcb_surface_set_matrix,
- _cairo_xcb_surface_set_filter,
- _cairo_xcb_surface_set_repeat,
+ _cairo_xcb_surface_acquire_source_image,
+ _cairo_xcb_surface_release_source_image,
+ _cairo_xcb_surface_acquire_dest_image,
+ _cairo_xcb_surface_release_dest_image,
+ _cairo_xcb_surface_clone_similar,
_cairo_xcb_surface_composite,
_cairo_xcb_surface_fill_rectangles,
_cairo_xcb_surface_composite_trapezoids,
_cairo_xcb_surface_copy_page,
_cairo_xcb_surface_show_page,
_cairo_xcb_surface_set_clip_region,
- _cairo_xcb_surface_create_pattern,
NULL /* show_glyphs */
};
diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h
index 27ebad523..a5c65f441 100644
--- a/src/cairo-xcb.h
+++ b/src/cairo-xcb.h
@@ -31,18 +31,21 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
-#include <cairo.h>
-
#ifndef CAIRO_XCB_H
#define CAIRO_XCB_H
+
+#include <cairo.h>
+
#ifdef CAIRO_HAS_XCB_SURFACE
#include <X11/XCB/xcb.h>
#include <X11/XCB/render.h>
+CAIRO_BEGIN_DECLS
+
void
cairo_set_target_xcb (cairo_t *cr,
XCBConnection *dpy,
@@ -50,5 +53,7 @@ cairo_set_target_xcb (cairo_t *cr,
XCBVISUALTYPE *visual,
cairo_format_t format);
+CAIRO_END_DECLS
+
#endif /* CAIRO_HAS_XCB_SURFACE */
#endif /* CAIRO_XCB_H */
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index d9d74f583..3eaef57e5 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -31,12 +31,28 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
#include "cairo-xlib.h"
+/**
+ * cairo_set_target_drawable:
+ * @cr: a #cairo_t
+ * @dpy: an X display
+ * @drawable: a window or pixmap on the default screen of @dpy
+ *
+ * Directs output for a #cairo_t to an Xlib drawable. @drawable must
+ * be a Window or Pixmap on the default screen of @dpy using the
+ * default colormap and visual. Using this function is slow because
+ * the function must retrieve information about @drawable from the X
+ * server.
+
+ * The combination of cairo_xlib_surface_create() and
+ * cairo_set_target_surface() is somewhat more flexible, although
+ * it still is slow.
+ **/
void
cairo_set_target_drawable (cairo_t *cr,
Display *dpy,
@@ -87,6 +103,8 @@ typedef struct _cairo_xlib_surface {
#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+
#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
@@ -141,18 +159,13 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
Pixmap pix;
cairo_xlib_surface_t *surface;
- /* XXX: There's a pretty lame heuristic here. This assumes that
- * all non-Render X servers do not support depth-32 pixmaps, (and
- * that they do support depths 1, 8, and 24). Obviously, it would
- * be much better to check the depths that are actually
- * supported. */
- if (!dpy
- || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)
- && format == CAIRO_FORMAT_ARGB32))
- {
- return NULL;
+ /* As a good first approximation, if the display doesn't have COMPOSITE,
+ * we're better off using image surfaces for all temporary operations
+ */
+ if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE(src)) {
+ return cairo_image_surface_create (format, width, height);
}
-
+
scr = DefaultScreen (dpy);
pix = XCreatePixmap (dpy, DefaultRootWindow (dpy),
@@ -196,15 +209,17 @@ _cairo_xlib_surface_pixels_per_inch (void *abstract_surface)
return 96.0;
}
-static cairo_image_surface_t *
-_cairo_xlib_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_get_image_surface (cairo_xlib_surface_t *surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect)
{
- cairo_xlib_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
-
XImage *ximage;
Window root_ignore;
int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
+ int x1, y1, x2, y2;
XGetGeometry (surface->dpy,
surface->drawable,
@@ -212,11 +227,39 @@ _cairo_xlib_surface_get_image (void *abstract_surface)
&surface->width, &surface->height,
&bwidth_ignore, &depth_ignore);
+ x1 = 0;
+ y1 = 0;
+ x2 = surface->width;
+ y2 = surface->height;
+
+ if (interest_rect) {
+ if (interest_rect->x > x1)
+ x1 = interest_rect->x;
+ if (interest_rect->y > y1)
+ y1 = interest_rect->y;
+ if (interest_rect->x + interest_rect->width < x2)
+ x2 = interest_rect->x + interest_rect->width;
+ if (interest_rect->y + interest_rect->height < y2)
+ y2 = interest_rect->y + interest_rect->height;
+
+ if (x1 >= x2 || y1 >= y2) {
+ *image_out = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ if (image_rect) {
+ image_rect->x = x1;
+ image_rect->y = y1;
+ image_rect->width = x2 - x1;
+ image_rect->height = y2 - y1;
+ }
+
/* XXX: This should try to use the XShm extension if availible */
ximage = XGetImage (surface->dpy,
surface->drawable,
- 0, 0,
- surface->width, surface->height,
+ x1, y1,
+ x2 - x1, y2 - y1,
AllPlanes, ZPixmap);
if (surface->visual) {
@@ -253,7 +296,8 @@ _cairo_xlib_surface_get_image (void *abstract_surface)
_cairo_image_surface_set_repeat (image, surface->base.repeat);
_cairo_image_surface_set_matrix (image, &(surface->base.matrix));
- return image;
+ *image_out = image;
+ return CAIRO_STATUS_SUCCESS;
}
static void
@@ -266,10 +310,11 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
}
static cairo_status_t
-_cairo_xlib_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+_draw_image_surface (cairo_xlib_surface_t *surface,
+ cairo_image_surface_t *image,
+ int dst_x,
+ int dst_y)
{
- cairo_xlib_surface_t *surface = abstract_surface;
XImage *ximage;
unsigned bitmap_pad;
@@ -295,9 +340,8 @@ _cairo_xlib_surface_set_image (void *abstract_surface,
_cairo_xlib_surface_ensure_gc (surface);
XPutImage(surface->dpy, surface->drawable, surface->gc,
- ximage, 0, 0, 0, 0,
- surface->width,
- surface->height);
+ ximage, 0, 0, dst_x, dst_y,
+ image->width, image->height);
/* Foolish XDestroyImage thinks it can free my data, but I won't
stand for it. */
@@ -305,17 +349,116 @@ _cairo_xlib_surface_set_image (void *abstract_surface,
XDestroyImage (ximage);
return CAIRO_STATUS_SUCCESS;
+
+}
+
+static cairo_status_t
+_cairo_xlib_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ cairo_xlib_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
+
+ status = _get_image_surface (surface, NULL, &image, NULL);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ cairo_surface_set_filter (&image->base, surface->base.filter);
+ cairo_surface_set_matrix (&image->base, &surface->base.matrix);
+ cairo_surface_set_repeat (&image->base, surface->base.repeat);
+
+ *image_out = image;
+ }
+
+ return status;
+}
+
+static void
+_cairo_xlib_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ cairo_surface_destroy (&image->base);
+}
+
+static cairo_status_t
+_cairo_xlib_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect_out,
+ void **image_extra)
+{
+ cairo_xlib_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
+
+ status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
+ if (status == CAIRO_STATUS_SUCCESS)
+ *image_out = image;
+
+ return status;
+}
+
+static void
+_cairo_xlib_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+ cairo_xlib_surface_t *surface = abstract_surface;
+
+ /* ignore errors */
+ _draw_image_surface (surface, image, image_rect->x, image_rect->y);
+
+ cairo_surface_destroy (&image->base);
}
static cairo_status_t
-_cairo_xlib_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
+_cairo_xlib_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
cairo_xlib_surface_t *surface = abstract_surface;
+ cairo_xlib_surface_t *clone;
+
+ if (src->backend == surface->base.backend ) {
+ cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src;
+
+ if (xlib_src->dpy == surface->dpy) {
+ *clone_out = src;
+ cairo_surface_reference (src);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+ } else if (_cairo_surface_is_image (src)) {
+ cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
+
+ clone = (cairo_xlib_surface_t *)
+ _cairo_xlib_surface_create_similar (surface, image_src->format, 0,
+ image_src->width, image_src->height);
+ if (clone == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _draw_image_surface (clone, image_src, 0, 0);
+
+ *clone_out = &clone->base;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
+ cairo_matrix_t *matrix)
+{
XTransform xtransform;
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
-
+
xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
@@ -328,26 +471,41 @@ _cairo_xlib_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
xtransform.matrix[2][1] = 0;
xtransform.matrix[2][2] = _cairo_fixed_from_double (1);
- if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
+ if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
{
- XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform);
- } else {
- /* XXX: Need support here if using an old RENDER without support
- for SetPictureTransform */
+ static const XTransform identity = { {
+ { 1 << 16, 0x00000, 0x00000 },
+ { 0x00000, 1 << 16, 0x00000 },
+ { 0x00000, 0x00000, 1 << 16 },
+ } };
+
+ if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
+ XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform);
+
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
+_cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
+ cairo_filter_t filter)
{
- cairo_xlib_surface_t *surface = abstract_surface;
char *render_filter;
- if (!(surface->picture
- && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)))
+ if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
+
+ if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
+ {
+ if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
+ return CAIRO_STATUS_SUCCESS;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
switch (filter) {
case CAIRO_FILTER_FAST:
@@ -377,11 +535,10 @@ _cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
}
static cairo_status_t
-_cairo_xlib_surface_set_repeat (void *abstract_surface, int repeat)
+_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat)
{
- cairo_xlib_surface_t *surface = abstract_surface;
- unsigned long mask;
XRenderPictureAttributes pa;
+ unsigned long mask;
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
@@ -394,33 +551,32 @@ _cairo_xlib_surface_set_repeat (void *abstract_surface, int repeat)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_xlib_surface_t *
-_cairo_xlib_surface_clone_similar (cairo_surface_t *src,
- cairo_xlib_surface_t *template,
- cairo_format_t format,
- int depth)
+static cairo_int_status_t
+_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
+ cairo_surface_attributes_t *attributes)
{
- cairo_xlib_surface_t *clone;
- cairo_image_surface_t *src_image;
+ cairo_int_status_t status;
- src_image = _cairo_surface_get_image (src);
-
- clone = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_similar (template, format, 0,
- src_image->width,
- src_image->height);
- if (clone == NULL)
- return NULL;
-
- _cairo_xlib_surface_set_filter (clone, cairo_surface_get_filter(src));
-
- _cairo_xlib_surface_set_image (clone, src_image);
-
- _cairo_xlib_surface_set_matrix (clone, &(src_image->base.matrix));
+ status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix);
+ if (status)
+ return status;
+
+ switch (attributes->extend) {
+ case CAIRO_EXTEND_NONE:
+ _cairo_xlib_surface_set_repeat (surface, 0);
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ _cairo_xlib_surface_set_repeat (surface, 1);
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
- cairo_surface_destroy (&src_image->base);
+ status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
+ if (status)
+ return status;
- return clone;
+ return CAIRO_STATUS_SUCCESS;
}
static int
@@ -462,8 +618,8 @@ _render_operator (cairo_operator_t operator)
static cairo_int_status_t
_cairo_xlib_surface_composite (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
+ cairo_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
void *abstract_dst,
int src_x,
int src_y,
@@ -474,73 +630,66 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
unsigned int width,
unsigned int height)
{
- cairo_xlib_surface_t *dst = abstract_dst;
- cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) generic_src;
- cairo_xlib_surface_t *mask = (cairo_xlib_surface_t *) generic_mask;
- cairo_xlib_surface_t *src_clone = NULL;
- cairo_xlib_surface_t *mask_clone = NULL;
- XGCValues gc_values;
- int src_x_off, src_y_off, dst_x_off, dst_y_off;
+ cairo_surface_attributes_t src_attr, mask_attr;
+ cairo_xlib_surface_t *dst = abstract_dst;
+ cairo_xlib_surface_t *src;
+ cairo_xlib_surface_t *mask;
+ cairo_int_status_t status;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
- src_clone = _cairo_xlib_surface_clone_similar (generic_src, dst,
- CAIRO_FORMAT_ARGB32, 32);
- if (!src_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- src = src_clone;
- }
- if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) {
- mask_clone = _cairo_xlib_surface_clone_similar (generic_mask, dst,
- CAIRO_FORMAT_A8, 8);
- if (!mask_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- mask = mask_clone;
- }
-
- if (operator == CAIRO_OPERATOR_SRC
- && !mask
- && _cairo_matrix_is_integer_translation(&(src->base.matrix),
- &src_x_off, &src_y_off)
- && _cairo_matrix_is_integer_translation(&(dst->base.matrix),
- &dst_x_off, &dst_y_off)) {
- /* Fast path for copying "raw" areas. */
- _cairo_xlib_surface_ensure_gc (dst);
- XGetGCValues(dst->dpy, dst->gc, GCGraphicsExposures, &gc_values);
- XSetGraphicsExposures(dst->dpy, dst->gc, False);
- XCopyArea(dst->dpy,
- src->drawable,
- dst->drawable,
- dst->gc,
- src_x + src_x_off,
- src_y + src_y_off,
- width, height,
- dst_x + dst_x_off,
- dst_y + dst_y_off);
- XSetGraphicsExposures(dst->dpy, dst->gc, gc_values.graphics_exposures);
-
- } else {
- XRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- mask ? mask->picture : 0,
- dst->picture,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
+ status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
+ &dst->base,
+ src_x, src_y,
+ mask_x, mask_y,
+ width, height,
+ (cairo_surface_t **) &src,
+ (cairo_surface_t **) &mask,
+ &src_attr, &mask_attr);
+ if (status)
+ return status;
+
+ status = _cairo_xlib_surface_set_attributes (src, &src_attr);
+ if (CAIRO_OK (status))
+ {
+ if (mask)
+ {
+ status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
+ if (CAIRO_OK (status))
+ XRenderComposite (dst->dpy,
+ _render_operator (operator),
+ src->picture,
+ mask->picture,
+ dst->picture,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ mask_x + mask_attr.x_offset,
+ mask_y + mask_attr.y_offset,
+ dst_x, dst_y,
+ width, height);
+ }
+ else
+ {
+ XRenderComposite (dst->dpy,
+ _render_operator (operator),
+ src->picture,
+ 0,
+ dst->picture,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ }
}
- /* XXX: This is messed up. If I can xlib_surface_create, then I
- should be able to xlib_surface_destroy. */
- if (src_clone)
- cairo_surface_destroy (&src_clone->base);
- if (mask_clone)
- cairo_surface_destroy (&mask_clone->base);
+ if (mask)
+ _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
+
+ _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_int_status_t
@@ -572,41 +721,59 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
static cairo_int_status_t
_cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *generic_src,
+ cairo_pattern_t *pattern,
void *abstract_dst,
- int xSrc,
- int ySrc,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
- cairo_xlib_surface_t *dst = abstract_dst;
- cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) generic_src;
- cairo_xlib_surface_t *src_clone = NULL;
+ cairo_surface_attributes_t attributes;
+ cairo_xlib_surface_t *dst = abstract_dst;
+ cairo_xlib_surface_t *src;
+ cairo_int_status_t status;
+ int render_reference_x, render_reference_y;
+ int render_src_x, render_src_y;
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
- src_clone = _cairo_xlib_surface_clone_similar (generic_src, dst,
- CAIRO_FORMAT_ARGB32, 32);
- if (!src_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- src = src_clone;
+
+ status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ src_x, src_y, width, height,
+ (cairo_surface_t **) &src,
+ &attributes);
+ if (status)
+ return status;
+
+ if (traps[0].left.p1.y < traps[0].left.p2.y) {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
+ } else {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
}
- /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
- XRenderCompositeTrapezoids (dst->dpy,
- _render_operator (operator),
- src->picture, dst->picture,
- XRenderFindStandardFormat (dst->dpy, PictStandardA8),
- xSrc, ySrc, (XTrapezoid *) traps, num_traps);
+ render_src_x = src_x + render_reference_x - dst_x;
+ render_src_y = src_y + render_reference_y - dst_y;
- /* XXX: This is messed up. If I can xlib_surface_create, then I
- should be able to xlib_surface_destroy. */
- if (src_clone)
- cairo_surface_destroy (&src_clone->base);
+ /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
+ status = _cairo_xlib_surface_set_attributes (src, &attributes);
+ if (CAIRO_OK (status))
+ XRenderCompositeTrapezoids (dst->dpy,
+ _render_operator (operator),
+ src->picture, dst->picture,
+ XRenderFindStandardFormat (dst->dpy, PictStandardA8),
+ render_src_x + attributes.x_offset,
+ render_src_y + attributes.y_offset,
+ (XTrapezoid *) traps, num_traps);
+
+ _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_int_status_t
@@ -685,22 +852,17 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_xlib_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
-{
- 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_xlib_surface_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
- cairo_surface_t *source,
+ cairo_pattern_t *pattern,
void *abstract_surface,
int source_x,
int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs);
@@ -708,18 +870,17 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_create_similar,
_cairo_xlib_surface_destroy,
_cairo_xlib_surface_pixels_per_inch,
- _cairo_xlib_surface_get_image,
- _cairo_xlib_surface_set_image,
- _cairo_xlib_surface_set_matrix,
- _cairo_xlib_surface_set_filter,
- _cairo_xlib_surface_set_repeat,
+ _cairo_xlib_surface_acquire_source_image,
+ _cairo_xlib_surface_release_source_image,
+ _cairo_xlib_surface_acquire_dest_image,
+ _cairo_xlib_surface_release_dest_image,
+ _cairo_xlib_surface_clone_similar,
_cairo_xlib_surface_composite,
_cairo_xlib_surface_fill_rectangles,
_cairo_xlib_surface_composite_trapezoids,
_cairo_xlib_surface_copy_page,
_cairo_xlib_surface_show_page,
_cairo_xlib_surface_set_clip_region,
- _cairo_xlib_surface_create_pattern,
_cairo_xlib_surface_show_glyphs
};
@@ -827,6 +988,7 @@ typedef struct {
cairo_glyph_cache_key_t key;
Glyph glyph;
XGlyphInfo info;
+ int refcount;
} glyphset_cache_entry_t;
static Glyph
@@ -854,17 +1016,18 @@ _xlib_glyphset_cache_create_entry (void *cache,
_cairo_lock_global_image_glyph_cache ();
im_cache = _cairo_get_global_image_glyph_cache ();
- if (g == NULL || v == NULL ||g == NULL || im_cache == NULL) {
+ if (g == NULL || v == NULL || im_cache == NULL) {
_cairo_unlock_global_image_glyph_cache ();
return CAIRO_STATUS_NO_MEMORY;
}
- status = _cairo_cache_lookup (im_cache, key, (void **) (&im));
+ status = _cairo_cache_lookup (im_cache, key, (void **) (&im), NULL);
if (status != CAIRO_STATUS_SUCCESS || im == NULL) {
_cairo_unlock_global_image_glyph_cache ();
return CAIRO_STATUS_NO_MEMORY;
}
+ v->refcount = 1;
v->key = *k;
_cairo_unscaled_font_reference (v->key.unscaled);
@@ -925,6 +1088,12 @@ _xlib_glyphset_cache_create_entry (void *cache,
return CAIRO_STATUS_SUCCESS;
}
+static void
+_glyphset_cache_entry_reference (glyphset_cache_entry_t *e)
+{
+ e->refcount++;
+}
+
static void
_xlib_glyphset_cache_destroy_cache (void *cache)
{
@@ -940,6 +1109,9 @@ _xlib_glyphset_cache_destroy_entry (void *cache, void *entry)
g = (glyphset_cache_t *) cache;
v = (glyphset_cache_entry_t *) entry;
+ if (--v->refcount > 0)
+ return;
+
_cairo_unscaled_font_destroy (v->key.unscaled);
XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1);
free (v);
@@ -1014,8 +1186,7 @@ _get_glyphset_cache (Display *d)
#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_xlib_surface_show_glyphs32 (cairo_font_t *font,
cairo_operator_t operator,
glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
@@ -1092,8 +1263,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
static cairo_status_t
-_cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
+_cairo_xlib_surface_show_glyphs16 (cairo_font_t *font,
cairo_operator_t operator,
glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
@@ -1169,10 +1339,9 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
}
static cairo_status_t
-_cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
+_cairo_xlib_surface_show_glyphs8 (cairo_font_t *font,
cairo_operator_t operator,
- glyphset_cache_t *g,
+ glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
cairo_xlib_surface_t *src,
cairo_xlib_surface_t *self,
@@ -1247,27 +1416,44 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
+_cairo_xlib_surface_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
- cairo_surface_t *source,
+ cairo_pattern_t *pattern,
void *abstract_surface,
int source_x,
int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
+ cairo_surface_attributes_t attributes;
+ cairo_int_status_t status;
unsigned int elt_size;
cairo_xlib_surface_t *self = abstract_surface;
- cairo_image_surface_t *tmp = NULL;
- cairo_xlib_surface_t *src = NULL;
+ cairo_xlib_surface_t *src;
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;
+ if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_pattern_acquire_surface (pattern, &self->base,
+ source_x, source_y, width, height,
+ (cairo_surface_t **) &src,
+ &attributes);
+ if (status)
+ return status;
+
+ status = _cairo_xlib_surface_set_attributes (src, &attributes);
+ if (status)
+ goto FAIL;
+
/* Acquire an entry array of suitable size. */
if (num_glyphs < N_STACK_BUF) {
entries = stack_entries;
@@ -1278,26 +1464,6 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
goto FAIL;
}
- /* prep the source surface. */
- if (source->backend == self->base.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 (&self->base, 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)
@@ -1305,15 +1471,23 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
/* Work out the index size to use. */
elt_size = 8;
- key.scale = *scale;
- key.unscaled = font;
+ _cairo_font_get_glyph_cache_key (font, &key);
for (i = 0; i < num_glyphs; ++i) {
key.index = glyphs[i].index;
- status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]));
+ status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]), NULL);
if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL)
goto UNLOCK;
+ /* Referencing the glyph entries we use prevents them from
+ * being freed if lookup of later entries causes them to
+ * be ejected from the cache. It would be more efficient
+ * (though more complex) to prevent them from being ejected
+ * from the cache at all, so they could get reused later
+ * in the same string.
+ */
+ _glyphset_cache_entry_reference (entries[i]);
+
if (elt_size == 8 && entries[i]->glyph > 0xff)
elt_size = 16;
if (elt_size == 16 && entries[i]->glyph > 0xffff) {
@@ -1325,43 +1499,32 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
/* 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,
+ status = _cairo_xlib_surface_show_glyphs8 (font, operator, g, &key, src, self,
+ source_x + attributes.x_offset,
+ source_y + attributes.y_offset,
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,
+ status = _cairo_xlib_surface_show_glyphs16 (font, operator, g, &key, src, self,
+ source_x + attributes.x_offset,
+ source_y + attributes.y_offset,
glyphs, entries, num_glyphs);
else
- status = _cairo_xlib_surface_show_glyphs32 (font, scale, operator, g, &key, src, self,
- source_x, source_y,
+ status = _cairo_xlib_surface_show_glyphs32 (font, operator, g, &key, src, self,
+ source_x + attributes.x_offset,
+ source_y + attributes.y_offset,
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;
+ for (i = 0; i < num_glyphs; ++i)
+ _xlib_glyphset_cache_destroy_entry (g, entries[i]);
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;
+ _cairo_pattern_release_surface (&self->base, &src->base, &attributes);
+
+ return status;
}
diff --git a/src/cairo-xlib.h b/src/cairo-xlib.h
index 4f241b034..18db7b114 100644
--- a/src/cairo-xlib.h
+++ b/src/cairo-xlib.h
@@ -31,17 +31,20 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
-#include <cairo.h>
-
#ifndef CAIRO_XLIB_H
#define CAIRO_XLIB_H
+
+#include <cairo.h>
+
#ifdef CAIRO_HAS_XLIB_SURFACE
#include <X11/extensions/Xrender.h>
+CAIRO_BEGIN_DECLS
+
/* XXX: This shold be renamed to cairo_set_target_xlib to match the
* other backends */
void
@@ -66,6 +69,8 @@ cairo_status_t
cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height);
*/
+CAIRO_END_DECLS
+
#endif /* CAIRO_HAS_XLIB_SURFACE */
#endif /* CAIRO_XLIB_H */
diff --git a/src/cairo.c b/src/cairo.c
index 20d94938c..fd10b5cac 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
@@ -68,6 +68,18 @@ cairo_sane_state (cairo_t *cr)
#endif
+/**
+ * cairo_create:
+ *
+ * Creates a new #cairo_t with default values. The target
+ * surface must be set on the #cairo_t with cairo_set_target_surface(),
+ * or a backend-specific function like cairo_set_target_image() before
+ * drawing with the #cairo_t.
+ *
+ * Return value: a newly allocated #cairo_t with a reference
+ * count of 1. The initial reference count should be released
+ * with cairo_destroy() when you are done using the #cairo_t.
+ **/
cairo_t *
cairo_create (void)
{
@@ -88,6 +100,14 @@ cairo_create (void)
return cr;
}
+/**
+ * cairo_reference:
+ * @cr: a #cairo_t
+ *
+ * Increases the reference count on @cr by one. This prevents
+ * @cr from being destroyed until a matching call to cairo_destroy()
+ * is made.
+ **/
void
cairo_reference (cairo_t *cr)
{
@@ -99,6 +119,14 @@ cairo_reference (cairo_t *cr)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_destroy:
+ * @cr: a #cairo_t
+ *
+ * Decreases the reference count on @cr by one. If the result
+ * is zero, then @cr and all associated resources are freed.
+ * See cairo_destroy().
+ **/
void
cairo_destroy (cairo_t *cr)
{
@@ -117,6 +145,22 @@ cairo_destroy (cairo_t *cr)
free (cr);
}
+/**
+ * cairo_save:
+ * @cr: a #cairo_t
+ *
+ * Makes a copy of the current state of @cr and saves it
+ * on an internal stack of saved states for @cr. When
+ * cairo_restore() is called, @cr will be restored to
+ * the saved state. Multiple calls to cairo_save() and
+ * cairo_restore() can be nested; each call to cairo_restore()
+ * restores the state from the matching paired cairo_save().
+ *
+ * It isn't necessary to clear all saved states before
+ * a #cairo_t is freed. If the reference count of a #cairo_t
+ * drops to zero in response to a call to cairo_destroy(),
+ * any saved states will be freed along with the #cairo_t.
+ **/
void
cairo_save (cairo_t *cr)
{
@@ -144,6 +188,14 @@ cairo_save (cairo_t *cr)
}
slim_hidden_def(cairo_save);
+/**
+ * cairo_restore:
+ * @cr: a #cairo_t
+ *
+ * Restores @cr to the state saved by a preceding call to
+ * cairo_save() and removes that state from the stack of
+ * saved states.
+ **/
void
cairo_restore (cairo_t *cr)
{
@@ -170,6 +222,20 @@ cairo_restore (cairo_t *cr)
}
slim_hidden_def(cairo_restore);
+/**
+ * cairo_copy:
+ * @dest: a #cairo_t
+ * @src: another #cairo_t
+ *
+ * This function copies all current state information from src to
+ * dest. This includes the current point and path, the target surface,
+ * the transformation matrix, and so forth.
+ *
+ * The stack of states saved with cairo_save() is <emphasis>not</emphasis>
+ * not copied; nor are any saved states on @dest cleared. The
+ * operation only copies the current state of @src to the current
+ * state of @dest.
+ **/
void
cairo_copy (cairo_t *dest, cairo_t *src)
{
@@ -216,6 +282,16 @@ cairo_pop_group (cairo_t *cr)
}
*/
+/**
+ * cairo_set_target_surface:
+ * @cr: a #cairo_t
+ * @surface: a #cairo_surface_t
+ *
+ * Directs output for a #cairo_t to a given surface. The surface
+ * will be referenced by the #cairo_t, so you can immediately
+ * call cairo_surface_destroy() on it if you don't need to
+ * keep a reference to it around.
+ **/
void
cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface)
{
@@ -228,6 +304,26 @@ cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface)
}
slim_hidden_def(cairo_set_target_surface);
+/**
+ * cairo_set_target_image:
+ * @cr: a #cairo_t
+ * @data: a pointer to a buffer supplied by the application
+ * in which to write contents.
+ * @format: the format of pixels in the buffer
+ * @width: the width of the image to be stored in the buffer
+ * @height: the eight of the image to be stored in the buffer
+ * @stride: the number of bytes between the start of rows
+ * in the buffer. Having this be specified separate from @width
+ * allows for padding at the end of rows, or for writing
+ * to a subportion of a larger image.
+ *
+ * Directs output for a #cairo_t to an in-memory image. The output
+ * buffer must be kept around until the #cairo_t is destroyed or set
+ * to to have a different target. The initial contents of @buffer
+ * will be used as the inital image contents; you must explicitely
+ * clear the buffer, using, for example, cairo_rectangle() and
+ * cairo_fill() if you want it cleared.
+ **/
void
cairo_set_target_image (cairo_t *cr,
char *data,
@@ -268,6 +364,18 @@ cairo_set_operator (cairo_t *cr, cairo_operator_t op)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_rgb_color:
+ * @cr: a #cairo_t
+ * @red: red component of color
+ * @green: green component of color
+ * @blue: blue component of color
+ *
+ * Sets a constant color for filling and stroking. This replaces any
+ * pattern set with cairo_set_pattern(). The color components are
+ * floating point numbers in the range 0 to 1. If the values passed in
+ * are outside that range, they will be clamped.
+ **/
void
cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue)
{
@@ -301,6 +409,19 @@ cairo_current_pattern (cairo_t *cr)
return _cairo_gstate_current_pattern (cr->gstate);
}
+/**
+ * cairo_set_tolerance:
+ * @cr: a #cairo_t
+ * @tolerance: the tolerance, in device units (typically pixels)
+ *
+ * Sets the tolerance used when converting paths into trapezoids.
+ * Curved segments of the path will be subdivided until the maximum
+ * deviation between the original path and the polygonal approximation
+ * is less than @tolerance. The default value is 0.1. A larger
+ * value will give better performance, a smaller value, better
+ * appearance. (Reducing the value from the default value of 0.1
+ * is unlikely to improve appearance significantly.)
+ **/
void
cairo_set_tolerance (cairo_t *cr, double tolerance)
{
@@ -314,6 +435,17 @@ cairo_set_tolerance (cairo_t *cr, double tolerance)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_alpha:
+ * @cr: a #cairo_t
+ * @alpha: the alpha value. 0 is transparent, 1 fully opaque.
+ * if the value is outside the range 0 to 1, it will be
+ * clamped to that range.
+ *
+ * Sets an overall alpha value used for stroking and filling. This
+ * value is multiplied with any alpha value coming from a gradient or
+ * image pattern.
+ **/
void
cairo_set_alpha (cairo_t *cr, double alpha)
{
@@ -569,6 +701,39 @@ cairo_curve_to (cairo_t *cr,
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_arc:
+ * @cr: a Cairo context
+ * @xc: X position of the center of the arc
+ * @yc: Y position of the center of the arc
+ * @radius: the radius of the arc
+ * @angle1: the start angle, in radians
+ * @angle2: the end angle, in radians
+ *
+ * Adds an arc from @angle1 to @angle2 to the current path. If there
+ * is a current point, that point is connected to the start of the arc
+ * by a straight line segment. Angles are measured in radians with an
+ * angle of 0 along the X axis and an angle of %M_PI radians (90
+ * degrees) along the Y axis, so with the default transformation
+ * matrix, positive angles are clockwise. (To convert from degrees to
+ * radians, use <literal>degrees * (M_PI / 180.)</literal>.) This
+ * function gives the arc in the direction of increasing angle; see
+ * cairo_arc_negative() to get the arc in the direction of decreasing
+ * angle.
+ *
+ * A full arc is drawn as a circle. To make an oval arc, you can scale
+ * the current transformation matrix by different amounts in the X and
+ * Y directions. For example, to draw a full oval in the box given
+ * by @x, @y, @width, @height:
+
+ * <informalexample><programlisting>
+ * cairo_save (cr);
+ * cairo_translate (x + width / 2., y + height / 2.);
+ * cairo_scale (1. / (height / 2.), 1. / (width / 2.));
+ * cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI);
+ * cairo_restore (cr);
+ * </programlisting></informalexample>
+ **/
void
cairo_arc (cairo_t *cr,
double xc, double yc,
@@ -586,6 +751,20 @@ cairo_arc (cairo_t *cr,
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_arc_negative:
+ * @cr: a Cairo context
+ * @xc: X position of the center of the arc
+ * @yc: Y position of the center of the arc
+ * @radius: the radius of the arc
+ * @angle1: the start angle, in radians
+ * @angle2: the end angle, in radians
+ *
+ * Adds an arc from @angle1 to @angle2 to the current path. The
+ * function behaves identically to cairo_arc() except that instead of
+ * giving the arc in the direction of increasing angle, it gives
+ * the arc in the direction of decreasing angle.
+ **/
void
cairo_arc_negative (cairo_t *cr,
double xc, double yc,
@@ -744,7 +923,7 @@ cairo_show_page (cairo_t *cr)
CAIRO_CHECK_SANITY (cr);
}
-int
+cairo_bool_t
cairo_in_stroke (cairo_t *cr, double x, double y)
{
int inside;
@@ -842,6 +1021,20 @@ cairo_select_font (cairo_t *cr,
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_current_font:
+ * @cr: a #cairo_t
+ *
+ * Gets the current font object for a #cairo_t. If there is no current
+ * font object, because the font parameters, transform, or target
+ * surface has been changed since a font was last used, a font object
+ * will be created and stored in in the #cairo_t.
+ *
+ * Return value: the current font object. Can return %NULL
+ * on out-of-memory or if the context is already in
+ * an error state. This object is owned by Cairo. To keep
+ * a reference to it, you must call cairo_font_reference().
+ **/
cairo_font_t *
cairo_current_font (cairo_t *cr)
{
@@ -869,6 +1062,22 @@ cairo_current_font_extents (cairo_t *cr,
}
+/**
+ * cairo_set_font:
+ * @cr: a #cairo_t
+ * @font: a #cairo_font_t, or %NULL to unset any previously set font.
+ *
+ * Replaces the current #cairo_font_t object in the #cairo_t with
+ * @font. The replaced font in the #cairo_t will be destroyed if there
+ * are no other references to it. Since a #cairo_font_t is specific to
+ * a particular output device and size, changing the transformation,
+ * font transformation, or target surfaces of a #cairo_t will clear
+ * any previously set font. Setting the font using cairo_set_font() is
+ * exclusive with the simple font selection API provided by
+ * cairo_select_font(). The size and transformation set by
+ * cairo_scale_font() and cairo_transform_font() are ignored unless
+ * they were taken into account when creating @font.
+ **/
void
cairo_set_font (cairo_t *cr, cairo_font_t *font)
{
@@ -914,6 +1123,16 @@ cairo_text_extents (cairo_t *cr,
if (cr->status)
return;
+ if (utf8 == NULL) {
+ extents->x_bearing = 0.0;
+ extents->y_bearing = 0.0;
+ extents->width = 0.0;
+ extents->height = 0.0;
+ extents->x_advance = 0.0;
+ extents->y_advance = 0.0;
+ return;
+ }
+
cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
CAIRO_CHECK_SANITY (cr);
@@ -1205,6 +1424,8 @@ cairo_status_string (cairo_t *cr)
return "no target surface has been set";
case CAIRO_STATUS_NULL_POINTER:
return "NULL pointer";
+ case CAIRO_STATUS_INVALID_STRING:
+ return "input string not valid UTF-8";
}
return "<unknown error status>";
diff --git a/src/cairo.h b/src/cairo.h
index b7bcc1dbb..03e063242 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -31,23 +31,83 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#ifndef CAIRO_H
#define CAIRO_H
+#ifdef __cplusplus
+# define CAIRO_BEGIN_DECLS extern "C" {
+# define CAIRO_END_DECLS }
+#else
+# define CAIRO_BEGIN_DECLS
+# define CAIRO_END_DECLS
+#endif
+
#include <cairo-features.h>
#include <pixman.h>
+CAIRO_BEGIN_DECLS
+
+/**
+ * cairo_bool_t:
+ *
+ * #cairo_bool_t is used for boolean values. Returns of type
+ * #cairo_bool_t will always be either 0 or 1, but testing against
+ * these values explicitely is not encouraged; just use the
+ * value as a boolean condition.
+ *
+ * <informalexample><programlisting>
+ * if (cairo_in_stroke (cr, x, y)) {
+ * /<!-- -->* do something *<!-- -->/
+ * }
+ * </programlisting></informalexample>
+ */
+typedef int cairo_bool_t;
+
+/**
+ * cairo_t:
+ *
+ * A #cairo_t contains the current state of the rendering device,
+ * including coordinates of yet to be drawn shapes.
+ **/
typedef struct _cairo cairo_t;
+
+/**
+ * cairo_surface_t:
+ *
+ * A #cairo_surface_t represents an image, either as the destination
+ * of a drawing operation or as source when drawing onto another
+ * surface. There are different subtypes of cairo_surface_t for
+ * different drawing backends; for example, cairo_image_surface_create()
+ * creates a bitmap image in memory.
+ *
+ * Memory management of #cairo_surface_t is done with
+ * cairo_surface_reference() and cairo_surface_destroy().
+ */
typedef struct _cairo_surface cairo_surface_t;
+
+/**
+ * cairo_matrix_t:
+ *
+ * A #cairo_matrix_t holds an affine transformation, such as a scale,
+ * rotation, or shear, or a combination of those.
+ **/
typedef struct _cairo_matrix cairo_matrix_t;
typedef struct _cairo_pattern cairo_pattern_t;
-#ifdef __cplusplus
-extern "C" {
-#endif
+typedef enum cairo_status {
+ CAIRO_STATUS_SUCCESS = 0,
+ CAIRO_STATUS_NO_MEMORY,
+ CAIRO_STATUS_INVALID_RESTORE,
+ CAIRO_STATUS_INVALID_POP_GROUP,
+ CAIRO_STATUS_NO_CURRENT_POINT,
+ CAIRO_STATUS_INVALID_MATRIX,
+ CAIRO_STATUS_NO_TARGET_SURFACE,
+ CAIRO_STATUS_NULL_POINTER,
+ CAIRO_STATUS_INVALID_STRING
+} cairo_status_t;
/* Functions for manipulating state objects */
cairo_t *
@@ -81,6 +141,28 @@ cairo_pop_group (cairo_t *cr);
void
cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface);
+/**
+ * cairo_format_t
+ * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with
+ * alpha in the upper 8 bits, then red, then green, then blue.
+ * The 32-bit quanties are stored native-endian. Pre-multiplied
+ * alpha is used. (That is, 50% transparent red is 0x80800000,
+ * not 0x80ff0000.)
+ * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with
+ * the upper 8 bits unused. Red, Green, and Blue are stored
+ * in the remaining 24 bits in that order.
+ * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding
+ * an alpha value.
+ * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding
+ * an alpha value. Pixels are packed together into 32-bit
+ * quantities. The ordering of the bits matches the
+ * endianess of the platform. On a big-endian machine, the
+ * first pixel is in the uppermost bit, on a little-endian
+ * machine the first pixel is in the least-significant bit.
+ *
+ * #cairo_format_t is used to identify the memory format of
+ * image data.
+ */
typedef enum cairo_format {
CAIRO_FORMAT_ARGB32,
CAIRO_FORMAT_RGB24,
@@ -88,6 +170,7 @@ typedef enum cairo_format {
CAIRO_FORMAT_A1
} cairo_format_t;
+/* XXX: Need to add cairo_set_target_image_data */
void
cairo_set_target_image (cairo_t *cr,
char *data,
@@ -149,6 +232,27 @@ cairo_set_alpha (cairo_t *cr, double alpha);
void
cairo_set_tolerance (cairo_t *cr, double tolerance);
+/**
+ * cairo_fill_rule_t
+ * @CAIRO_FILL_RULE_WINDING: If the path crosses the ray from
+ * left-to-right, counts +1. If the path crosses the ray
+ * from right to left, counts -1. (Left and right are determined
+ * from the perspective of looking along the ray from the starting
+ * point.) If the total count is non-zero, the point will be filled.
+ * @CAIRO_FILL_RULE_EVEN_ODD: Counts the total number of
+ * intersections, without regard to the orientation of the contour. If
+ * the total number of intersections is odd, the point will be
+ * filled.
+ *
+ * #cairo_fill_rule_t is used to select how paths are filled. For both
+ * fill rules, whether or not a point is included in the fill is
+ * determined by taking a ray from that point to infinity and looking
+ * at intersections with the path. The ray can be in any direction,
+ * as long as it doesn't pass through the end point of a segment
+ * or have a tricky intersection such as intersecting tangent to the path.
+ * (Note that filling is not actually implemented in this way. This
+ * is just a description of the rule that is applied.)
+ **/
typedef enum cairo_fill_rule {
CAIRO_FILL_RULE_WINDING,
CAIRO_FILL_RULE_EVEN_ODD
@@ -160,6 +264,15 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule);
void
cairo_set_line_width (cairo_t *cr, double width);
+
+/**
+ * cairo_line_cap_t
+ * @CAIRO_LINE_CAP_BUTT: start(stop) the line exactly at the start(end) point
+ * @CAIRO_LINE_CAP_ROUND: use a round ending, the center of the circle is the end point
+ * @CAIRO_LINE_CAP_SQUARE: use squared ending, the center of the square is the end point
+ *
+ * enumeration for style of line-endings
+ **/
typedef enum cairo_line_cap {
CAIRO_LINE_CAP_BUTT,
CAIRO_LINE_CAP_ROUND,
@@ -303,10 +416,10 @@ void
cairo_show_page (cairo_t *cr);
/* Insideness testing */
-int
+cairo_bool_t
cairo_in_stroke (cairo_t *cr, double x, double y);
-int
+cairo_bool_t
cairo_in_fill (cairo_t *cr, double x, double y);
/* Rectangular extents */
@@ -330,14 +443,75 @@ cairo_clip (cairo_t *cr);
/* Font/Text functions */
+/**
+ * cairo_font_t:
+ *
+ * A #cairo_font_t is a font scaled to a particular size and device
+ * resolution. A font can be set on a #cairo_t by using
+ * cairo_set_font() assuming that the current transformation and
+ * target surface of the #cairo_t match that for which the
+ * #cairo_font_t was created. The effect of using a mismatched
+ * #cairo_font_t will be incorrect font metrics.
+ */
typedef struct _cairo_font cairo_font_t;
+/**
+ * cairo_glyph_t:
+ * @index: glyph index in the font. The exact interpretation of the
+ * glyph index depends on the font technology being used.
+ * @x: the offset in the X direction between the origin used for
+ * drawing or measuring the string and the origin of this glyph.
+ * @y: the offset in the Y direction between the origin used for
+ * drawing or measuring the string and the origin of this glyph.
+ *
+ * The #cairo_glyph_t structure holds information about a single glyph
+ * when drawing or measuring text. A font is (in simple terms) a
+ * collection of shapes used to draw text. A glyph is one of these
+ * shapes. There can be multiple glyphs for a single character
+ * (alternates to be used in different contexts, for example), or a
+ * glyph can be a <firstterm>ligature</firstterm> of multiple
+ * characters. Cairo doesn't expose any way of converting input text
+ * into glyphs, so in order to use the Cairo interfaces that take
+ * arrays of glyphs, you must directly access the appropriate
+ * underlying font system.
+ *
+ * Note that the offsets given by @x and @y are not cumulative. When
+ * drawing or measuring text, each glyph is individually positioned
+ * with respect to the overall origin
+ **/
typedef struct {
unsigned long index;
double x;
double y;
} cairo_glyph_t;
+/**
+ * cairo_text_extents_t:
+ * @x_bearing: the horizontal distance from the origin to the
+ * leftmost part of the glyphs as drawn. Positive if the
+ * glyphs lie entirely to the right of the origin.
+ * @y_bearing: the vertical distance from the origin to the
+ * topmost part of the glyphs as drawn. Positive only if the
+ * glyphs lie completely below the origin; will usually be
+ * negative.
+ * @width: width of the glyphs as drawn
+ * @height: height of the glyphs as drawn
+ * @x_advance:distance to advance in the X direction
+ * after drawing these glyphs
+ * @y_advance: distance to advance in the Y direction
+ * after drawing these glyphs. Will typically be zero except
+ * for vertical text layout as found in East-Asian languages.
+ *
+ * The #cairo_text_extents_t< structure stores the extents of a single
+ * glyph or a string of glyphs in user-space coordinates. Because text
+ * extents are in user-space coordinates, they don't scale along with
+ * the current transformation matrix. If you call
+ * <literal>cairo_scale(cr, 2.0, 2.0)</literal>, text will
+ * be drawn twice as big, but the reported text extents will not be
+ * doubled. They will change slightly due to hinting (so you can't
+ * assume that metrics are independent of the transformation matrix),
+ * but otherwise will remain unchanged.
+ */
typedef struct {
double x_bearing;
double y_bearing;
@@ -422,13 +596,17 @@ cairo_font_reference (cairo_font_t *font);
void
cairo_font_destroy (cairo_font_t *font);
-void
-cairo_font_set_transform (cairo_font_t *font,
- cairo_matrix_t *matrix);
+cairo_status_t
+cairo_font_extents (cairo_font_t *font,
+ cairo_matrix_t *font_matrix,
+ cairo_font_extents_t *extents);
void
-cairo_font_current_transform (cairo_font_t *font,
- cairo_matrix_t *matrix);
+cairo_font_glyph_extents (cairo_font_t *font,
+ cairo_matrix_t *font_matrix,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents);
/* Image functions */
@@ -521,17 +699,6 @@ cairo_current_path_flat (cairo_t *cr,
/* Error status queries */
-typedef enum cairo_status {
- CAIRO_STATUS_SUCCESS = 0,
- CAIRO_STATUS_NO_MEMORY,
- CAIRO_STATUS_INVALID_RESTORE,
- CAIRO_STATUS_INVALID_POP_GROUP,
- CAIRO_STATUS_NO_CURRENT_POINT,
- CAIRO_STATUS_INVALID_MATRIX,
- CAIRO_STATUS_NO_TARGET_SURFACE,
- CAIRO_STATUS_NULL_POINTER
-} cairo_status_t;
-
cairo_status_t
cairo_status (cairo_t *cr);
@@ -671,7 +838,7 @@ cairo_status_t
cairo_matrix_set_identity (cairo_matrix_t *matrix);
cairo_status_t
-cairo_matrix_set_affine (cairo_matrix_t *cr,
+cairo_matrix_set_affine (cairo_matrix_t *matrix,
double a, double b,
double c, double d,
double tx, double ty);
@@ -724,8 +891,6 @@ cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y);
#define cairo_get_status_string cairo_get_status_string_DEPRECATED_BY_cairo_status_string
#endif
-#ifdef __cplusplus
-}
-#endif
+CAIRO_END_DECLS
#endif /* CAIRO_H */
diff --git a/src/cairo_atsui_font.c b/src/cairo_atsui_font.c
index 52cfc6bd8..cb4b1c5d7 100644
--- a/src/cairo_atsui_font.c
+++ b/src/cairo_atsui_font.c
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2004 Calum Robinson
+ * Copyright © 2004 Calum Robinson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
diff --git a/src/cairo_cache.c b/src/cairo_cache.c
index b097b609b..d1ad5a4e2 100644
--- a/src/cairo_cache.c
+++ b/src/cairo_cache.c
@@ -94,9 +94,9 @@ static const cairo_cache_arrangement_t cache_arrangements [] = {
* 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.
+ * cache will expire entries randomly as it experiences memory pressure.
+ * If max_memory is set, entries are not expired, and must be explicitely
+ * removed.
*
* 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
@@ -282,17 +282,51 @@ _load_factor (cairo_cache_t *cache)
}
#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;
-}
+/* Find a random in the cache matching the given predicate. We use the
+ * same algorithm as the probing algorithm to walk over the entries in
+ * the hash table in a pseudo-random order. Walking linearly would
+ * favor entries following gaps in the hash table. We could also
+ * call rand() repeatedly, which works well for almost-full tables,
+ * but degrades when the table is almost empty, or predicate
+ * returns false for most entries.
+ */
+static cairo_cache_entry_base_t **
+_random_entry (cairo_cache_t *cache,
+ int (*predicate)(void*))
+{
+ cairo_cache_entry_base_t **probe;
+ unsigned long hash;
+ unsigned long table_size, i, idx, step;
+
+ _cache_sane_state (cache);
+
+ table_size = cache->arrangement->size;
+ hash = rand ();
+ idx = hash % table_size;
+ step = 0;
+
+ for (i = 0; i < table_size; ++i)
+ {
+ assert(idx < table_size);
+ probe = cache->entries + idx;
+ if (LIVE_ENTRY_P(cache, idx)
+ && (!predicate || predicate (*probe)))
+ return probe;
+
+ if (step == 0) {
+ step = hash % cache->arrangement->rehash;
+ if (step == 0)
+ step = 1;
+ }
+
+ idx += step;
+ if (idx >= table_size)
+ idx -= table_size;
+ }
+
+ return NULL;
+}
/* public API follows */
@@ -356,8 +390,9 @@ _cairo_cache_destroy (cairo_cache_t *cache)
cairo_status_t
_cairo_cache_lookup (cairo_cache_t *cache,
- void *key,
- void **entry_return)
+ void *key,
+ void **entry_return,
+ int *created_entry)
{
unsigned long idx;
@@ -392,6 +427,8 @@ _cairo_cache_lookup (cairo_cache_t *cache,
cache->hits++;
#endif
*entry_return = *slot;
+ if (created_entry)
+ *created_entry = 0;
return status;
}
@@ -401,19 +438,18 @@ _cairo_cache_lookup (cairo_cache_t *cache,
/* Build the new entry. */
status = cache->backend->create_entry (cache, key,
- entry_return);
+ (void **)&new_entry);
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 > 0 &&
((cache->max_memory - cache->used_memory) < new_entry->memory)) {
- idx = _random_live_entry (cache);
+ idx = _random_entry (cache, NULL) - cache->entries;
assert (idx < cache->arrangement->size);
_entry_destroy (cache, idx);
}
@@ -425,7 +461,6 @@ _cairo_cache_lookup (cairo_cache_t *cache,
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;
}
@@ -439,9 +474,38 @@ _cairo_cache_lookup (cairo_cache_t *cache,
_cache_sane_state (cache);
+ *entry_return = new_entry;
+ if (created_entry)
+ *created_entry = 1;
+
return status;
}
+cairo_status_t
+_cairo_cache_remove (cairo_cache_t *cache,
+ void *key)
+{
+ cairo_cache_entry_base_t **slot;
+
+ _cache_sane_state (cache);
+
+ /* See if we have an entry in the table already. */
+ slot = _find_exact_live_entry_for (cache, key);
+ if (slot != NULL)
+ _entry_destroy (cache, slot - cache->entries);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void *
+_cairo_cache_random_entry (cairo_cache_t *cache,
+ int (*predicate)(void*))
+{
+ cairo_cache_entry_base_t **slot = _random_entry (cache, predicate);
+
+ return slot ? *slot : NULL;
+}
+
unsigned long
_cairo_hash_string (const char *c)
{
diff --git a/src/cairo_color.c b/src/cairo_color.c
index 899b1e3d5..f203d96cc 100644
--- a/src/cairo_color.c
+++ b/src/cairo_color.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
@@ -67,7 +67,8 @@ _cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blu
}
void
-_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue)
+_cairo_color_get_rgb (const cairo_color_t *color,
+ double *red, double *green, double *blue)
{
if (red)
*red = color->red;
diff --git a/src/cairo_fixed.c b/src/cairo_fixed.c
index ee31718ef..a4faa1708 100644
--- a/src/cairo_fixed.c
+++ b/src/cairo_fixed.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo_font.c b/src/cairo_font.c
index f5fc0e981..529c1c7c3 100644
--- a/src/cairo_font.c
+++ b/src/cairo_font.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 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
@@ -31,293 +32,129 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
+ * Graydon Hoare <graydon@redhat.com>
+ * Owen Taylor <otaylor@redhat.com>
*/
#include "cairoint.h"
-/* First we implement a global font cache for named fonts. */
-
-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;
-
-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)
-{
- unsigned long hash;
- cairo_font_cache_key_t *in;
- in = (cairo_font_cache_key_t *) key;
-
- /* 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)
-{
- const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
- cairo_font_cache_key_t *k;
- cairo_font_cache_entry_t *entry;
- k = (cairo_font_cache_key_t *) key;
-
- /* XXX: The current freetype backend may return NULL, (for example
- * if no fonts are installed), but I would like to guarantee that
- * the toy API always returns at least *some* font, so I would
- * like to build in some sort fo font here, (even a really lame,
- * ugly one if necessary). */
-
- 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);
-}
-
-static const cairo_cache_backend_t 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_private cairo_status_t
+_cairo_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ cairo_font_scale_t *sc,
+ cairo_font_t **font)
{
- 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;
- }
+ const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
- _cairo_unscaled_font_reference (font->unscaled);
- _unlock_global_font_cache ();
- return font->unscaled;
+ return backend->create (family, slant, weight, sc, font);
}
void
-_cairo_font_init (cairo_font_t *scaled,
- cairo_font_scale_t *scale,
- cairo_unscaled_font_t *unscaled)
+_cairo_font_init (cairo_font_t *font,
+ cairo_font_scale_t *scale,
+ const cairo_font_backend_t *backend)
{
- scaled->scale = *scale;
- scaled->unscaled = unscaled;
- scaled->refcount = 1;
+ font->scale = *scale;
+ font->refcount = 1;
+ font->backend = backend;
}
-cairo_status_t
-_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const cairo_font_backend_t *backend)
+void
+_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
+ const cairo_font_backend_t *backend)
{
font->refcount = 1;
font->backend = backend;
- return CAIRO_STATUS_SUCCESS;
}
-
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)
+_cairo_font_text_to_glyphs (cairo_font_t *font,
+ const unsigned char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
{
- return font->backend->text_to_glyphs (font, scale, utf8, glyphs, num_glyphs);
+ return font->backend->text_to_glyphs (font, 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)
+_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, scale, glyphs, num_glyphs, extents);
+ return font->backend->glyph_extents(font, 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)
+_cairo_font_glyph_bbox (cairo_font_t *font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
{
- return font->backend->glyph_bbox (font, scale, glyphs, num_glyphs, bbox);
+ return font->backend->glyph_bbox (font, 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_font_show_glyphs (cairo_font_t *font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glyph_t *glyphs,
+ int num_glyphs)
{
cairo_status_t status;
if (surface->backend->show_glyphs != NULL) {
- status = surface->backend->show_glyphs (font, scale, operator, source,
- surface, source_x, source_y,
+ status = surface->backend->show_glyphs (font, operator, pattern,
+ surface,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
glyphs, num_glyphs);
if (status == CAIRO_STATUS_SUCCESS)
return status;
}
/* Surface display routine either does not exist or failed. */
- return font->backend->show_glyphs (font, scale, operator, source,
- surface, source_x, source_y,
+ return font->backend->show_glyphs (font, operator, pattern,
+ surface,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
glyphs, num_glyphs);
}
cairo_status_t
-_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)
+_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);
+}
+
+void
+_cairo_font_get_glyph_cache_key (cairo_font_t *font,
+ cairo_glyph_cache_key_t *key)
{
- return font->backend->glyph_path (font, scale, glyphs, num_glyphs, path);
+ font->backend->get_glyph_cache_key (font, key);
}
cairo_status_t
-_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
- cairo_font_extents_t *extents)
+_cairo_font_font_extents (cairo_font_t *font,
+ cairo_font_extents_t *extents)
{
- return font->backend->font_extents(font, scale, extents);
+ return font->backend->font_extents (font, extents);
}
void
@@ -332,8 +169,7 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font)
if (--(font->refcount) > 0)
return;
- if (font->backend)
- font->backend->destroy (font);
+ font->backend->destroy_unscaled_font (font);
}
@@ -352,37 +188,154 @@ cairo_font_destroy (cairo_font_t *font)
if (--(font->refcount) > 0)
return;
- if (font->unscaled)
- _cairo_unscaled_font_destroy (font->unscaled);
-
- free (font);
+ font->backend->destroy_font (font);
}
-void
-cairo_font_set_transform (cairo_font_t *font,
- cairo_matrix_t *matrix)
+/**
+ * cairo_font_extents:
+ * @font: a #cairo_font_t
+ * @font_matrix: the font transformation for which this font was
+ * created. (See cairo_transform_font()). This is needed
+ * properly convert the metrics from the font into user space.
+ * @extents: a #cairo_font_extents_t which to store the retrieved extents.
+ *
+ * Gets the metrics for a #cairo_font_t.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an
+ * error such as %CAIRO_STATUS_NO_MEMORY.
+ **/
+cairo_status_t
+cairo_font_extents (cairo_font_t *font,
+ cairo_matrix_t *font_matrix,
+ cairo_font_extents_t *extents)
{
- 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);
+ cairo_int_status_t status;
+ double font_scale_x, font_scale_y;
+
+ status = _cairo_font_font_extents (font, extents);
+
+ if (!CAIRO_OK (status))
+ return status;
+
+ _cairo_matrix_compute_scale_factors (font_matrix,
+ &font_scale_x, &font_scale_y,
+ /* XXX */ 1);
+
+ /*
+ * The font responded in unscaled units, scale by the font
+ * matrix scale factors to get to user space
+ */
+
+ extents->ascent *= font_scale_y;
+ extents->descent *= font_scale_y;
+ extents->height *= font_scale_y;
+ extents->max_x_advance *= font_scale_x;
+ extents->max_y_advance *= font_scale_y;
+
+ return status;
}
+/**
+ * cairo_font_glyph_extents:
+ * @font: a #cairo_font_t
+ * @font_matrix: the font transformation for which this font was
+ * created. (See cairo_transform_font()). This is needed
+ * properly convert the metrics from the font into user space.
+ * @glyphs: an array of glyph IDs with X and Y offsets.
+ * @num_glyphs: the number of glyphs in the @glyphs array
+ * @extents: a #cairo_text_extents_t which to store the retrieved extents.
+ *
+ * cairo_font_glyph_extents() gets the overall metrics for a string of
+ * glyphs. The X and Y offsets in @glyphs are taken from an origin of 0,0.
+ **/
void
-cairo_font_current_transform (cairo_font_t *font,
- cairo_matrix_t *matrix)
+cairo_font_glyph_extents (cairo_font_t *font,
+ cairo_matrix_t *font_matrix,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
- 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);
-}
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_glyph_t origin_glyph;
+ cairo_text_extents_t origin_extents;
+ int i;
+ double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
+ double x_pos = 0.0, y_pos = 0.0;
+ int set = 0;
+
+ if (!num_glyphs)
+ {
+ extents->x_bearing = 0.0;
+ extents->y_bearing = 0.0;
+ extents->width = 0.0;
+ extents->height = 0.0;
+ extents->x_advance = 0.0;
+ extents->y_advance = 0.0;
+
+ return;
+ }
+ for (i = 0; i < num_glyphs; i++)
+ {
+ double x, y;
+ double wm, hm;
+
+ origin_glyph = glyphs[i];
+ origin_glyph.x = 0.0;
+ origin_glyph.y = 0.0;
+ status = _cairo_font_glyph_extents (font,
+ &origin_glyph, 1,
+ &origin_extents);
+
+ /*
+ * Transform font space metrics into user space metrics
+ * by running the corners through the font matrix and
+ * expanding the bounding box as necessary
+ */
+ x = origin_extents.x_bearing;
+ y = origin_extents.y_bearing;
+ cairo_matrix_transform_point (font_matrix,
+ &x, &y);
+
+ for (hm = 0.0; hm <= 1.0; hm += 1.0)
+ for (wm = 0.0; wm <= 1.0; wm += 1.0)
+ {
+ x = origin_extents.x_bearing + origin_extents.width * wm;
+ y = origin_extents.y_bearing + origin_extents.height * hm;
+ cairo_matrix_transform_point (font_matrix,
+ &x, &y);
+ x += glyphs[i].x;
+ y += glyphs[i].y;
+ if (!set)
+ {
+ min_x = max_x = x;
+ min_y = max_y = y;
+ set = 1;
+ }
+ else
+ {
+ if (x < min_x) min_x = x;
+ if (x > max_x) max_x = x;
+ if (y < min_y) min_y = y;
+ if (y > max_y) max_y = y;
+ }
+ }
+
+ x = origin_extents.x_advance;
+ y = origin_extents.y_advance;
+ cairo_matrix_transform_point (font_matrix,
+ &x, &y);
+ x_pos = glyphs[i].x + x;
+ y_pos = glyphs[i].y + y;
+ }
+
+ extents->x_bearing = min_x - glyphs[0].x;
+ extents->y_bearing = min_y - glyphs[0].y;
+ extents->width = max_x - min_x;
+ extents->height = max_y - min_y;
+ extents->x_advance = x_pos - glyphs[0].x;
+ extents->y_advance = y_pos - glyphs[0].y;
+}
/* Now we implement functions to access a default global image & metrics
* cache.
@@ -398,7 +351,8 @@ _cairo_glyph_cache_hash (void *cache, void *key)
^ ((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])
+ ^ ((unsigned long) in->scale.matrix[1][1])
+ ^ (in->flags * 1451) /* 1451 is just an abitrary prime */
^ in->index;
}
@@ -412,6 +366,7 @@ _cairo_glyph_cache_keys_equal (void *cache,
b = (cairo_glyph_cache_key_t *) k2;
return (a->index == b->index)
&& (a->unscaled == b->unscaled)
+ && (a->flags == b->flags)
&& (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])
diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c
index b928b04fc..44e1b0e84 100644
--- a/src/cairo_ft_font.c
+++ b/src/cairo_ft_font.c
@@ -1,29 +1,40 @@
-/*
- * Copyright © 2003 Red Hat Inc.
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 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
*
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee,
- * provided that the above copyright notice appear in all copies and that
- * both that copyright notice and this permission notice appear in
- * supporting documentation, and that the name of Red Hat Inc. not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. Red Hat Inc. makes no
- * representations about the suitability of this software for any purpose.
- * It is provided "as is" without express or implied warranty.
+ * 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/
*
- * RED HAT INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL RED HAT INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
- * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * 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.
*
- * Author: Graydon Hoare <graydon@redhat.com>
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Graydon Hoare <graydon@redhat.com>
+ * Owen Taylor <otaylor@redhat.com>
*/
-#include "cairoint.h"
-#include "cairo-ft.h"
+#include "cairo-ft-private.h"
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
@@ -38,19 +49,9 @@
#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))
#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0)
-/*
- * First we make a private, sharable implementation object which can be
- * stored both in a private cache and in public font objects (including
- * those connected to fonts we don't own)
+/* This is the max number of FT_face objects we keep open at once
*/
-
-typedef struct {
- int refcount;
-
- FT_Face face;
- int owns_face;
-
-} ft_font_val_t;
+#define MAX_OPEN_FACES 10
/*
* The simple 2x2 matrix is converted into separate scale and shape
@@ -62,141 +63,126 @@ typedef struct {
double shape[2][2];
} ft_font_transform_t;
-static ft_font_val_t *
-_create_from_face (FT_Face face, int owns_face)
-{
- ft_font_val_t *tmp = malloc (sizeof(ft_font_val_t));
- if (tmp) {
- tmp->refcount = 1;
- tmp->face = face;
- tmp->owns_face = owns_face;
- FT_Set_Char_Size (face,
- DOUBLE_TO_26_6 (1.0),
- DOUBLE_TO_26_6 (1.0),
- 0, 0);
- }
- return tmp;
-}
+/*
+ * We create an object that corresponds to a single font on the disk;
+ * (identified by a filename/id pair) these are shared between all
+ * fonts using that file. For cairo_ft_font_create_for_ft_face(), we
+ * just create a one-off version with a permanent face value.
+ */
-static void
-_reference_font_val (ft_font_val_t *f)
-{
- f->refcount++;
-}
+typedef struct {
+ cairo_unscaled_font_t base;
-static void
-_destroy_font_val (ft_font_val_t *f)
-{
- if (--(f->refcount) > 0)
- return;
+ int from_face; /* from cairo_ft_font_create_for_ft_face()? */
+ FT_Face face; /* provided or cached face */
- if (f->owns_face)
- FT_Done_Face (f->face);
+ /* only set if from_face is false */
+ FT_Library library;
+ char *filename;
+ int id;
- free (f);
-}
+ /* We temporarily scale the unscaled font as neede */
+ int have_scale;
+ cairo_font_scale_t current_scale;
+ double x_scale; /* Extracted X scale factor */
+ double y_scale; /* Extracted Y scale factor */
+
+ int lock; /* count of how many times this font has been locked */
+} ft_unscaled_font_t;
-static ft_font_val_t *
-_create_from_library_and_pattern (FT_Library ft_library, FcPattern *pattern)
-{
- ft_font_val_t *f = NULL;
- char *filename = NULL;
- int owns_face = 0;
- FT_Face face = NULL;
- FcPattern *resolved = NULL;
- FcResult result = FcResultMatch;
+const cairo_font_backend_t cairo_ft_font_backend;
- if (pattern == NULL)
- goto FAIL;
+static ft_unscaled_font_t *
+_ft_unscaled_font_create_from_face (FT_Face face)
+{
+ ft_unscaled_font_t *unscaled = malloc (sizeof(ft_unscaled_font_t));
+ if (!unscaled)
+ return NULL;
+
+ unscaled->from_face = 1;
+ unscaled->face = face;
- FcConfigSubstitute (0, pattern, FcMatchPattern);
- FcDefaultSubstitute (pattern);
+ unscaled->library = NULL;
+ unscaled->filename = NULL;
+ unscaled->id = 0;
- resolved = FcFontMatch (0, pattern, &result);
- if (!resolved)
- goto FAIL;
+ unscaled->have_scale = 0;
+ unscaled->lock = 0;
- if (result != FcResultMatch)
- goto FREE_RESOLVED;
+ _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
+ &cairo_ft_font_backend);
+ return unscaled;
+}
+
+static ft_unscaled_font_t *
+_ft_unscaled_font_create_from_filename (FT_Library library,
+ const char *filename,
+ int id)
+{
+ ft_unscaled_font_t *unscaled;
+ char *new_filename;
- /* If the pattern has an FT_Face object, use that. */
- if (FcPatternGetFTFace (resolved, FC_FT_FACE, 0, &face) != FcResultMatch
- || face == NULL)
- {
- /* otherwise it had better have a filename */
- result = FcPatternGetString (resolved, FC_FILE, 0, (FcChar8 **)(&filename));
-
- if (result == FcResultMatch)
- if (FT_New_Face (ft_library, filename, 0, &face))
- goto FREE_RESOLVED;
-
- if (face == NULL)
- goto FREE_RESOLVED;
-
- owns_face = 1;
+ new_filename = strdup (filename);
+ if (!new_filename)
+ return NULL;
+
+ unscaled = malloc (sizeof (ft_unscaled_font_t));
+ if (!unscaled) {
+ free (new_filename);
+ return NULL;
}
+
+ unscaled->from_face = 0;
+ unscaled->face = NULL;
- f = _create_from_face (face, owns_face);
-
- FcPatternDestroy (resolved);
- return f;
+ unscaled->library = library;
+ unscaled->filename = new_filename;
+ unscaled->id = id;
- FREE_RESOLVED:
- if (resolved)
- FcPatternDestroy (resolved);
-
- FAIL:
- return NULL;
+ unscaled->have_scale = 0;
+ unscaled->lock = 0;
+
+ _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
+ &cairo_ft_font_backend);
+ return unscaled;
}
-
-/*
- * We then make the user-exposed structure out of one of these impls, such
- * that it is reasonably cheap to copy and/or destroy. Unfortunately this
- * duplicates a certain amount of the caching machinery in the font cache,
- * but that's unavoidable as we also provide an FcPattern resolution API,
- * which is not part of cairo's generic font finding system.
- */
-
-typedef struct {
- cairo_unscaled_font_t base;
- FcPattern *pattern;
- ft_font_val_t *val;
-} cairo_ft_font_t;
-
-/*
- * We then make a key and entry type which are compatible with the generic
- * cache system. This cache serves to share single ft_font_val_t instances
- * between fonts (or between font lifecycles).
+/*
+ * We keep a global cache from [file/id] => [ft_unscaled_font_t]. This
+ * hash isn't limited in size. However, we limit the number of
+ * FT_Face objects we keep around; when we've exceeeded that
+ * limit and need to create a new FT_Face, we dump the FT_Face from
+ * a random ft_unscaled_font_t.
*/
typedef struct {
cairo_cache_entry_base_t base;
- FcPattern *pattern;
+ char *filename;
+ int id;
} cairo_ft_cache_key_t;
typedef struct {
cairo_ft_cache_key_t key;
- ft_font_val_t *val;
+ ft_unscaled_font_t *unscaled;
} cairo_ft_cache_entry_t;
-/*
- * Then we create a cache which maps FcPattern keys to the refcounted
- * ft_font_val_t values.
- */
-
typedef struct {
cairo_cache_t base;
FT_Library lib;
+ int n_faces; /* Number of open FT_Face objects */
} ft_cache_t;
-
static unsigned long
_ft_font_cache_hash (void *cache, void *key)
{
- cairo_ft_cache_key_t *in;
- in = (cairo_ft_cache_key_t *) key;
- return FcPatternHash (in->pattern);
+ cairo_ft_cache_key_t *in = (cairo_ft_cache_key_t *) key;
+ unsigned long hash;
+
+ /* 1607 is just a random prime. */
+ hash = _cairo_hash_string (in->filename);
+ hash += ((unsigned long) in->id) * 1607;
+
+ return hash;
}
static int
@@ -208,10 +194,10 @@ _ft_font_cache_keys_equal (void *cache,
cairo_ft_cache_key_t *b;
a = (cairo_ft_cache_key_t *) k1;
b = (cairo_ft_cache_key_t *) k2;
-
- return FcPatternEqual (a->pattern, b->pattern);
-}
+ return strcmp (a->filename, b->filename) == 0 &&
+ a->id == b->id;
+}
static cairo_status_t
_ft_font_cache_create_entry (void *cache,
@@ -226,27 +212,33 @@ _ft_font_cache_create_entry (void *cache,
if (entry == NULL)
return CAIRO_STATUS_NO_MEMORY;
- entry->key.pattern = FcPatternDuplicate (k->pattern);
- if (!entry->key.pattern) {
+ entry->unscaled = _ft_unscaled_font_create_from_filename (ftcache->lib,
+ k->filename,
+ k->id);
+ if (!entry->unscaled) {
free (entry);
return CAIRO_STATUS_NO_MEMORY;
}
-
- entry->val = _create_from_library_and_pattern (ftcache->lib, entry->key.pattern);
- entry->key.base.memory = 1;
-
+
+ entry->key.base.memory = 0;
+ entry->key.filename = entry->unscaled->filename;
+ entry->key.id = entry->unscaled->id;
+
*return_entry = entry;
return CAIRO_STATUS_SUCCESS;
}
+/* Entries are never spontaneously destroyed; but only when
+ * we remove them from the cache specifically. We free entry->unscaled
+ * in the code that removes the entry from the cache
+ */
static void
_ft_font_cache_destroy_entry (void *cache,
void *entry)
{
cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry;
- FcPatternDestroy (e->key.pattern);
- _destroy_font_val (e->val);
+
free (e);
}
@@ -291,11 +283,12 @@ _get_global_ft_cache (void)
if (_cairo_cache_init (&_global_ft_cache->base,
&_ft_font_cache_backend,
- CAIRO_FT_CACHE_NUM_FONTS_DEFAULT))
+ 0)) /* No memory limit */
goto FAIL;
if (FT_Init_FreeType (&_global_ft_cache->lib))
goto FAIL;
+ _global_ft_cache->n_faces = 0;
}
return &_global_ft_cache->base;
@@ -306,30 +299,304 @@ _get_global_ft_cache (void)
return NULL;
}
-/* implement the backend interface */
+/* Finds or creates a ft_unscaled_font for the filename/id from pattern.
+ * Returns a new reference to the unscaled font.
+ */
+static ft_unscaled_font_t *
+_ft_unscaled_font_get_for_pattern (FcPattern *pattern)
+{
+ cairo_ft_cache_entry_t *entry;
+ cairo_ft_cache_key_t key;
+ cairo_cache_t *cache;
+ cairo_status_t status;
+ FcChar8 *filename;
+ int created_entry;
+
+ if (FcPatternGetString (pattern, FC_FILE, 0, &filename) != FcResultMatch)
+ return NULL;
+ key.filename = (char *)filename;
+
+ if (FcPatternGetInteger (pattern, FC_INDEX, 0, &key.id) != FcResultMatch)
+ return NULL;
+
+ _lock_global_ft_cache ();
+ cache = _get_global_ft_cache ();
+ if (cache == NULL) {
+ _unlock_global_ft_cache ();
+ return NULL;
+ }
+
+ status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry);
+ _unlock_global_ft_cache ();
+ if (status)
+ return NULL;
+
+ if (!created_entry)
+ _cairo_unscaled_font_reference ((cairo_unscaled_font_t *)entry->unscaled);
+
+ return entry->unscaled;
+}
+
+static int
+_has_unlocked_face (void *entry)
+{
+ cairo_ft_cache_entry_t *e = entry;
-const cairo_font_backend_t cairo_ft_font_backend;
+ return (e->unscaled->lock == 0 && e->unscaled->face);
+}
+
+/* Ensures that an unscaled font has a face object. If we exceed
+ * MAX_OPEN_FACES, try to close some.
+ */
+static FT_Face
+_ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled)
+{
+ ft_cache_t *ftcache;
+ FT_Face face = NULL;
+
+ if (unscaled->face) {
+ unscaled->lock++;
+ return unscaled->face;
+ }
-static cairo_unscaled_font_t *
-_cairo_ft_font_create (const char *family,
+ assert (!unscaled->from_face);
+
+ _lock_global_ft_cache ();
+ ftcache = (ft_cache_t *) _get_global_ft_cache ();
+ assert (ftcache != NULL);
+
+ while (ftcache->n_faces >= MAX_OPEN_FACES) {
+ cairo_ft_cache_entry_t *entry;
+
+ entry = _cairo_cache_random_entry ((cairo_cache_t *)ftcache, _has_unlocked_face);
+ if (entry) {
+ FT_Done_Face (entry->unscaled->face);
+ entry->unscaled->face = NULL;
+ entry->unscaled->have_scale = 0;
+ ftcache->n_faces--;
+ } else {
+ break;
+ }
+ }
+
+ if (FT_New_Face (ftcache->lib,
+ unscaled->filename,
+ unscaled->id,
+ &face) != FT_Err_Ok)
+ goto FAIL;
+
+ unscaled->face = face;
+ unscaled->lock++;
+ ftcache->n_faces++;
+
+ FAIL:
+ _unlock_global_ft_cache ();
+ return face;
+}
+
+/* Unlock unscaled font locked with _ft_unscaled_font_lock_face
+ */
+static void
+_ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled)
+{
+ assert (unscaled->lock > 0);
+
+ unscaled->lock--;
+}
+
+static void
+_compute_transform (ft_font_transform_t *sf,
+ cairo_font_scale_t *sc)
+{
+ cairo_matrix_t normalized;
+ double tx, ty;
+
+ /* The font matrix has x and y "scale" components which we extract and
+ * use as character scale values. These influence the way freetype
+ * chooses hints, as well as selecting different bitmaps in
+ * hand-rendered fonts. We also copy the normalized matrix to
+ * freetype's transformation.
+ */
+
+ cairo_matrix_set_affine (&normalized,
+ sc->matrix[0][0],
+ sc->matrix[0][1],
+ sc->matrix[1][0],
+ sc->matrix[1][1],
+ 0, 0);
+
+ _cairo_matrix_compute_scale_factors (&normalized,
+ &sf->x_scale, &sf->y_scale,
+ /* XXX */ 1);
+ cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
+ cairo_matrix_get_affine (&normalized,
+ &sf->shape[0][0], &sf->shape[0][1],
+ &sf->shape[1][0], &sf->shape[1][1],
+ &tx, &ty);
+}
+
+/* Temporarily scales an unscaled font to the give scale. We catch
+ * scaling to the same size, since changing a FT_Face is expensive.
+ */
+static void
+_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
+ cairo_font_scale_t *scale)
+{
+ ft_font_transform_t sf;
+ FT_Matrix mat;
+
+ assert (unscaled->face != NULL);
+
+ if (unscaled->have_scale &&
+ scale->matrix[0][0] == unscaled->current_scale.matrix[0][0] &&
+ scale->matrix[0][1] == unscaled->current_scale.matrix[0][1] &&
+ scale->matrix[1][0] == unscaled->current_scale.matrix[1][0] &&
+ scale->matrix[1][1] == unscaled->current_scale.matrix[1][1])
+ return;
+
+ unscaled->have_scale = 1;
+ unscaled->current_scale = *scale;
+
+ _compute_transform (&sf, scale);
+
+ unscaled->x_scale = sf.x_scale;
+ unscaled->y_scale = sf.y_scale;
+
+ mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]);
+ mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]);
+ mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]);
+ mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]);
+
+ FT_Set_Transform(unscaled->face, &mat, NULL);
+
+ FT_Set_Pixel_Sizes(unscaled->face,
+ (FT_UInt) sf.x_scale,
+ (FT_UInt) sf.y_scale);
+}
+
+/* implement the font backend interface */
+
+typedef struct {
+ cairo_font_t base;
+ FcPattern *pattern;
+ int load_flags;
+ ft_unscaled_font_t *unscaled;
+} cairo_ft_font_t;
+
+/* for compatibility with older freetype versions */
+#ifndef FT_LOAD_TARGET_MONO
+#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME
+#endif
+
+/* The load flags passed to FT_Load_Glyph control aspects like hinting and
+ * antialiasing. Here we compute them from the fields of a FcPattern.
+ */
+static int
+_get_load_flags (FcPattern *pattern)
+{
+ FcBool antialias, hinting, autohint;
+#ifdef FC_HINT_STYLE
+ int hintstyle;
+#endif
+ int load_flags = 0;
+
+ /* disable antialiasing if requested */
+ if (FcPatternGetBool (pattern,
+ FC_ANTIALIAS, 0, &antialias) != FcResultMatch)
+ antialias = FcTrue;
+
+ if (antialias)
+ load_flags |= FT_LOAD_NO_BITMAP;
+ else
+ load_flags |= FT_LOAD_TARGET_MONO;
+
+ /* disable hinting if requested */
+ if (FcPatternGetBool (pattern,
+ FC_HINTING, 0, &hinting) != FcResultMatch)
+ hinting = FcTrue;
+
+#ifdef FC_HINT_STYLE
+ if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch)
+ hintstyle = FC_HINT_FULL;
+
+ if (!hinting || hintstyle == FC_HINT_NONE)
+ load_flags |= FT_LOAD_NO_HINTING;
+
+ switch (hintstyle) {
+ case FC_HINT_SLIGHT:
+ case FC_HINT_MEDIUM:
+ load_flags |= FT_LOAD_TARGET_LIGHT;
+ break;
+ default:
+ load_flags |= FT_LOAD_TARGET_NORMAL;
+ break;
+ }
+#else /* !FC_HINT_STYLE */
+ if (!hinting)
+ load_flags |= FT_LOAD_NO_HINTING;
+#endif /* FC_FHINT_STYLE */
+
+ /* force autohinting if requested */
+ if (FcPatternGetBool (pattern,
+ FC_AUTOHINT, 0, &autohint) != FcResultMatch)
+ autohint = FcFalse;
+
+ if (autohint)
+ load_flags |= FT_LOAD_FORCE_AUTOHINT;
+
+ return load_flags;
+}
+
+/* Like the public cairo_ft_font_create, but takes a cairo_font_scale_t,
+ * rather than a cairo_font_t
+ */
+static cairo_font_t *
+_ft_font_create (FcPattern *pattern,
+ cairo_font_scale_t *scale)
+{
+ cairo_ft_font_t *f = NULL;
+ ft_unscaled_font_t *unscaled = NULL;
+
+ unscaled = _ft_unscaled_font_get_for_pattern (pattern);
+ if (unscaled == NULL)
+ return NULL;
+
+ f = malloc (sizeof(cairo_ft_font_t));
+ if (f == NULL)
+ goto FREE_UNSCALED;
+
+ f->unscaled = unscaled;
+ f->pattern = pattern;
+ FcPatternReference (pattern);
+ f->load_flags = _get_load_flags (pattern);
+
+ _cairo_font_init ((cairo_font_t *)f, scale, &cairo_ft_font_backend);
+
+ return (cairo_font_t *)f;
+
+ FREE_UNSCALED:
+ _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
+
+ return NULL;
+}
+
+static cairo_status_t
+_cairo_ft_font_create (const char *family,
cairo_font_slant_t slant,
- cairo_font_weight_t weight)
+ cairo_font_weight_t weight,
+ cairo_font_scale_t *scale,
+ cairo_font_t **font)
{
- cairo_status_t status;
- cairo_ft_font_t *font = NULL;
+ FcPattern *pattern, *resolved;
+ cairo_font_t *new_font;
+ FcResult result;
int fcslant;
int fcweight;
- cairo_cache_t *cache;
- cairo_ft_cache_entry_t *entry;
- cairo_ft_cache_key_t key;
-
- key.pattern = FcPatternCreate ();
- if (key.pattern == NULL)
- goto FAIL;
+ ft_font_transform_t sf;
- font = malloc (sizeof (cairo_ft_font_t));
- if (font == NULL)
- goto FREE_PATTERN;
+ pattern = FcPatternCreate ();
+ if (!pattern)
+ return CAIRO_STATUS_NO_MEMORY;
switch (weight)
{
@@ -356,46 +623,44 @@ _cairo_ft_font_create (const char *family,
break;
}
- FcPatternAddString (key.pattern, FC_FAMILY, family);
- FcPatternAddInteger (key.pattern, FC_SLANT, fcslant);
- FcPatternAddInteger (key.pattern, FC_WEIGHT, fcweight);
-
- if (_cairo_unscaled_font_init (&font->base, &cairo_ft_font_backend))
+ if (!FcPatternAddString (pattern, FC_FAMILY, family))
goto FREE_PATTERN;
-
- _lock_global_ft_cache ();
- cache = _get_global_ft_cache ();
- if (cache == NULL) {
- _unlock_global_ft_cache ();
+ if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant))
+ goto FREE_PATTERN;
+ if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight))
goto FREE_PATTERN;
- }
- status = _cairo_cache_lookup (cache, &key, (void **) &entry);
- _unlock_global_ft_cache ();
+ _compute_transform (&sf, scale);
- if (status)
- goto FREE_PATTERN;
+ FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale);
- font->pattern = FcPatternDuplicate (entry->key.pattern);
- if (font->pattern == NULL)
+ FcConfigSubstitute (NULL, pattern, FcMatchPattern);
+ FcDefaultSubstitute (pattern);
+
+ resolved = FcFontMatch (NULL, pattern, &result);
+ if (!resolved)
goto FREE_PATTERN;
- font->val = entry->val;
- _reference_font_val (font->val);
-
- return &font->base;
+ new_font = _ft_font_create (resolved, scale);
- FREE_PATTERN:
- FcPatternDestroy (key.pattern);
+ FcPatternDestroy (resolved);
+ FcPatternDestroy (pattern);
- FAIL:
- return NULL;
+ if (new_font) {
+ *font = new_font;
+ return CAIRO_STATUS_SUCCESS;
+ } else {
+ return CAIRO_STATUS_NO_MEMORY; /* A guess */
+ }
-}
+ FREE_PATTERN:
+ FcPatternDestroy (pattern);
+ return CAIRO_STATUS_NO_MEMORY;
+}
static void
-_cairo_ft_font_destroy (void *abstract_font)
+_cairo_ft_font_destroy_font (void *abstract_font)
{
cairo_ft_font_t * font = abstract_font;
@@ -405,179 +670,94 @@ _cairo_ft_font_destroy (void *abstract_font)
if (font->pattern != NULL)
FcPatternDestroy (font->pattern);
- _destroy_font_val (font->val);
+ _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)font->unscaled);
free (font);
}
static void
-_utf8_to_ucs4 (char const *utf8,
- FT_ULong **ucs4,
- int *nchars)
+_cairo_ft_font_destroy_unscaled_font (void *abstract_font)
{
- int len = 0, step = 0;
- int n = 0, alloc = 0;
- FcChar32 u = 0;
+ ft_unscaled_font_t *unscaled = abstract_font;
- if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
- return;
+ if (!unscaled->from_face) {
+ cairo_cache_t *cache;
+ cairo_ft_cache_key_t key;
+
+ _lock_global_ft_cache ();
+ cache = _get_global_ft_cache ();
+ assert (cache);
- len = strlen (utf8);
- alloc = len;
- *ucs4 = malloc (sizeof (FT_ULong) * alloc);
- if (*ucs4 == NULL)
- return;
-
- while (len && (step = FcUtf8ToUcs4(utf8, &u, len)) > 0)
- {
- if (n == alloc)
- {
- alloc *= 2;
- *ucs4 = realloc (*ucs4, sizeof (FT_ULong) * alloc);
- if (*ucs4 == NULL)
- return;
- }
- (*ucs4)[n++] = u;
- len -= step;
- utf8 += step;
+ key.filename = unscaled->filename;
+ key.id = unscaled->id;
+
+ _cairo_cache_remove (cache, &key);
+
+ _unlock_global_ft_cache ();
}
- *nchars = n;
-}
-
-/*
- * Split a matrix into the component pieces of scale and shape
- */
-
-static void
-_cairo_ft_font_compute_transform (ft_font_transform_t *sf, cairo_font_scale_t *sc)
-{
- cairo_matrix_t normalized;
- double tx, ty;
- /* The font matrix has x and y "scale" components which we extract and
- * use as character scale values. These influence the way freetype
- * chooses hints, as well as selecting different bitmaps in
- * hand-rendered fonts. We also copy the normalized matrix to
- * freetype's transformation.
- */
-
- cairo_matrix_set_affine (&normalized,
- sc->matrix[0][0],
- sc->matrix[0][1],
- sc->matrix[1][0],
- sc->matrix[1][1],
- 0, 0);
-
- _cairo_matrix_compute_scale_factors (&normalized,
- &sf->x_scale, &sf->y_scale,
- /* XXX */ 1);
- cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
- cairo_matrix_get_affine (&normalized,
- &sf->shape[0][0], &sf->shape[0][1],
- &sf->shape[1][0], &sf->shape[1][1],
- &tx, &ty);
-}
-
-/*
- * Set the font transformation
- */
-
-static void
-_cairo_ft_font_install_transform (ft_font_transform_t *sf, FT_Face face)
-{
- FT_Matrix mat;
-
- mat.xx = DOUBLE_TO_16_16(sf->shape[0][0]);
- mat.yx = -DOUBLE_TO_16_16(sf->shape[0][1]);
- mat.xy = -DOUBLE_TO_16_16(sf->shape[1][0]);
- mat.yy = DOUBLE_TO_16_16(sf->shape[1][1]);
+ if (unscaled == NULL)
+ return;
- FT_Set_Transform(face, &mat, NULL);
+ if (!unscaled->from_face && unscaled->face)
+ FT_Done_Face (unscaled->face);
- FT_Set_Char_Size(face,
- (FT_F26Dot6) (sf->x_scale * 64.0),
- (FT_F26Dot6) (sf->y_scale * 64.0),
- 0, 0);
+ if (unscaled->filename)
+ free (unscaled->filename);
+
+ free (unscaled);
}
static void
-_install_font_scale (cairo_font_scale_t *sc, FT_Face face)
+_cairo_ft_font_get_glyph_cache_key (void *abstract_font,
+ cairo_glyph_cache_key_t *key)
{
- cairo_matrix_t normalized;
- double x_scale, y_scale;
- double xx, xy, yx, yy, tx, ty;
- FT_Matrix mat;
-
- /* The font matrix has x and y "scale" components which we extract and
- * use as character scale values. These influence the way freetype
- * chooses hints, as well as selecting different bitmaps in
- * hand-rendered fonts. We also copy the normalized matrix to
- * freetype's transformation.
- */
-
- cairo_matrix_set_affine (&normalized,
- sc->matrix[0][0],
- sc->matrix[0][1],
- sc->matrix[1][0],
- sc->matrix[1][1],
- 0, 0);
-
- _cairo_matrix_compute_scale_factors (&normalized, &x_scale, &y_scale,
- /* XXX */ 1);
- cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale);
- cairo_matrix_get_affine (&normalized,
- &xx /* 00 */ , &yx /* 01 */,
- &xy /* 10 */, &yy /* 11 */,
- &tx, &ty);
-
- mat.xx = DOUBLE_TO_16_16(xx);
- mat.xy = -DOUBLE_TO_16_16(xy);
- mat.yx = -DOUBLE_TO_16_16(yx);
- mat.yy = DOUBLE_TO_16_16(yy);
-
- FT_Set_Transform(face, &mat, NULL);
+ cairo_ft_font_t *font = abstract_font;
- FT_Set_Pixel_Sizes(face,
- (FT_UInt) x_scale,
- (FT_UInt) y_scale);
+ key->unscaled = (cairo_unscaled_font_t *)font->unscaled;
+ key->scale = font->base.scale;
+ key->flags = font->load_flags;
}
static cairo_status_t
_cairo_ft_font_text_to_glyphs (void *abstract_font,
- cairo_font_scale_t *sc,
const unsigned char *utf8,
cairo_glyph_t **glyphs,
int *nglyphs)
{
double x = 0., y = 0.;
size_t i;
- FT_ULong *ucs4 = NULL;
+ uint32_t *ucs4 = NULL;
cairo_ft_font_t *font = abstract_font;
- FT_Face face = font->val->face;
+ FT_Face face;
cairo_glyph_cache_key_t key;
cairo_image_glyph_cache_entry_t *val;
- cairo_cache_t *cache;
+ cairo_cache_t *cache = NULL;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
- key.unscaled = &font->base;
- key.scale = *sc;
+ _cairo_ft_font_get_glyph_cache_key (font, &key);
- _utf8_to_ucs4 (utf8, &ucs4, nglyphs);
-
- if (ucs4 == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, nglyphs);
+ if (!CAIRO_OK (status))
+ return status;
- *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t)));
- if (*glyphs == NULL)
- {
- free (ucs4);
- return CAIRO_STATUS_NO_MEMORY;
+ face = cairo_ft_font_lock_face ((cairo_font_t *)font);
+ if (!face) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL1;
}
_cairo_lock_global_image_glyph_cache ();
cache = _cairo_get_global_image_glyph_cache ();
if (cache == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL2;
+ }
+
+ *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t)));
+ if (*glyphs == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL2;
}
for (i = 0; i < *nglyphs; i++)
@@ -589,51 +769,62 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
val = NULL;
key.index = (*glyphs)[i].index;
- if (_cairo_cache_lookup (cache, &key, (void **) &val)
+ if (_cairo_cache_lookup (cache, &key, (void **) &val, NULL)
!= CAIRO_STATUS_SUCCESS || val == NULL)
continue;
x += val->extents.x_advance;
y += val->extents.y_advance;
}
- _cairo_unlock_global_image_glyph_cache ();
+ FAIL2:
+ if (cache)
+ _cairo_unlock_global_image_glyph_cache ();
+
+ cairo_ft_font_unlock_face ((cairo_font_t *)font);
+
+ FAIL1:
free (ucs4);
- return CAIRO_STATUS_SUCCESS;
+
+ return status;
}
static cairo_status_t
_cairo_ft_font_font_extents (void *abstract_font,
- cairo_font_scale_t *sc,
cairo_font_extents_t *extents)
{
cairo_ft_font_t *font = abstract_font;
- FT_Face face = font->val->face;
- FT_Size_Metrics *metrics = &face->size->metrics;
- ft_font_transform_t sf;
+ FT_Face face;
+ FT_Size_Metrics *metrics;
+
+ face = _ft_unscaled_font_lock_face (font->unscaled);
+ if (!face)
+ return CAIRO_STATUS_NO_MEMORY;
- _cairo_ft_font_compute_transform (&sf, sc);
- _cairo_ft_font_install_transform (&sf, face);
+ metrics = &face->size->metrics;
+ _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
+
/*
* Get to unscaled metrics so that the upper level can get back to
* user space
*/
- extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / sf.y_scale;
- extents->descent = DOUBLE_FROM_26_6(metrics->descender) / sf.y_scale;
- extents->height = DOUBLE_FROM_26_6(metrics->height) / sf.y_scale;
- extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / sf.x_scale;
+ extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / font->unscaled->y_scale;
+ extents->descent = DOUBLE_FROM_26_6(metrics->descender) / font->unscaled->y_scale;
+ extents->height = DOUBLE_FROM_26_6(metrics->height) / font->unscaled->y_scale;
+ extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / font->unscaled->x_scale;
/* FIXME: this doesn't do vertical layout atm. */
extents->max_y_advance = 0.0;
+ _ft_unscaled_font_unlock_face (font->unscaled);
+
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ft_font_glyph_extents (void *abstract_font,
- cairo_font_scale_t *sc,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents)
@@ -670,14 +861,13 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
return CAIRO_STATUS_NO_MEMORY;
}
- key.unscaled = &font->base;
- key.scale = *sc;
+ _cairo_ft_font_get_glyph_cache_key (font, &key);
for (i = 0; i < num_glyphs; i++)
{
img = NULL;
key.index = glyphs[i].index;
- if (_cairo_cache_lookup (cache, &key, (void **) &img)
+ if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
!= CAIRO_STATUS_SUCCESS || img == NULL)
continue;
@@ -721,7 +911,6 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
static cairo_status_t
_cairo_ft_font_glyph_bbox (void *abstract_font,
- cairo_font_scale_t *sc,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_box_t *bbox)
@@ -747,16 +936,15 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
return CAIRO_STATUS_NO_MEMORY;
}
- key.unscaled = &font->base;
- key.scale = *sc;
-
+ _cairo_ft_font_get_glyph_cache_key (font, &key);
+
for (i = 0; i < num_glyphs; i++)
{
img = NULL;
key.index = glyphs[i].index;
- if (_cairo_cache_lookup (cache, &key, (void **) &img)
+ if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
!= CAIRO_STATUS_SUCCESS || img == NULL)
continue;
@@ -785,12 +973,15 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
static cairo_status_t
_cairo_ft_font_show_glyphs (void *abstract_font,
- cairo_font_scale_t *sc,
cairo_operator_t operator,
- cairo_surface_t *source,
+ cairo_pattern_t *pattern,
cairo_surface_t *surface,
int source_x,
int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
@@ -798,9 +989,9 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
cairo_cache_t *cache;
cairo_glyph_cache_key_t key;
cairo_ft_font_t *font = abstract_font;
+ cairo_surface_pattern_t glyph_pattern;
cairo_status_t status;
-
- double x, y;
+ int x, y;
int i;
_cairo_lock_global_image_glyph_cache ();
@@ -808,47 +999,54 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
if (cache == NULL
|| font == NULL
- || source == NULL
+ || pattern == NULL
|| surface == NULL
|| glyphs == NULL) {
_cairo_unlock_global_image_glyph_cache ();
return CAIRO_STATUS_NO_MEMORY;
}
- key.unscaled = &font->base;
- key.scale = *sc;
+ key.unscaled = (cairo_unscaled_font_t *)font->unscaled;
+ key.scale = font->base.scale;
+ key.flags = font->load_flags;
for (i = 0; i < num_glyphs; i++)
{
img = NULL;
key.index = glyphs[i].index;
- if (_cairo_cache_lookup (cache, &key, (void **) &img)
+ if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
!= CAIRO_STATUS_SUCCESS
|| img == NULL
|| img->image == NULL)
continue;
- x = glyphs[i].x;
- y = glyphs[i].y;
+ x = (int) floor (glyphs[i].x + 0.5);
+ y = (int) floor (glyphs[i].y + 0.5);
+
+ _cairo_pattern_init_for_surface (&glyph_pattern, &(img->image->base));
- status = _cairo_surface_composite (operator, source,
- &(img->image->base),
+ status = _cairo_surface_composite (operator, pattern,
+ &glyph_pattern.base,
surface,
- source_x + x + img->size.x,
- source_y + y + img->size.y,
+ x + img->size.x,
+ y + img->size.y,
0, 0,
x + img->size.x,
y + img->size.y,
(double) img->size.width,
(double) img->size.height);
+ _cairo_pattern_fini (&glyph_pattern.base);
+
if (status) {
- _cairo_unlock_global_image_glyph_cache ();
+ _cairo_unlock_global_image_glyph_cache ();
return status;
}
}
+
_cairo_unlock_global_image_glyph_cache ();
+
return CAIRO_STATUS_SUCCESS;
}
@@ -932,7 +1130,6 @@ _cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closur
static cairo_status_t
_cairo_ft_font_glyph_path (void *abstract_font,
- cairo_font_scale_t *sc,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_t *path)
@@ -940,6 +1137,7 @@ _cairo_ft_font_glyph_path (void *abstract_font,
int i;
cairo_ft_font_t *font = abstract_font;
FT_GlyphSlot glyph;
+ FT_Face face;
FT_Error error;
FT_Outline_Funcs outline_funcs = {
_move_to,
@@ -949,10 +1147,12 @@ _cairo_ft_font_glyph_path (void *abstract_font,
0, /* shift */
0, /* delta */
};
+
+ face = cairo_ft_font_lock_face (abstract_font);
+ if (!face)
+ return CAIRO_STATUS_NO_MEMORY;
- glyph = font->val->face->glyph;
-
- _install_font_scale (sc, font->val->face);
+ glyph = face->glyph;
for (i = 0; i < num_glyphs; i++)
{
@@ -961,7 +1161,7 @@ _cairo_ft_font_glyph_path (void *abstract_font,
0, DOUBLE_TO_16_16 (-1.0),
};
- error = FT_Load_Glyph (font->val->face, glyphs[i].index, FT_LOAD_DEFAULT);
+ error = FT_Load_Glyph (font->unscaled->face, glyphs[i].index, font->load_flags | FT_LOAD_NO_BITMAP);
/* XXX: What to do in this error case? */
if (error)
continue;
@@ -977,32 +1177,39 @@ _cairo_ft_font_glyph_path (void *abstract_font,
FT_Outline_Decompose (&glyph->outline, &outline_funcs, path);
}
_cairo_path_close_path (path);
+
+ cairo_ft_font_unlock_face (abstract_font);
return CAIRO_STATUS_SUCCESS;
}
-
static cairo_status_t
-_cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
+_cairo_ft_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *)val->key.unscaled;
+ ft_unscaled_font_t *unscaled = (ft_unscaled_font_t *)val->key.unscaled;
FT_GlyphSlot glyphslot;
unsigned int width, height, stride;
+ FT_Face face;
FT_Outline *outline;
FT_BBox cbox;
FT_Bitmap bitmap;
FT_Glyph_Metrics *metrics;
- ft_font_transform_t sf;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
- glyphslot = font->val->face->glyph;
+ glyphslot = unscaled->face->glyph;
metrics = &glyphslot->metrics;
- _cairo_ft_font_compute_transform (&sf, &val->key.scale);
- _cairo_ft_font_install_transform (&sf, font->val->face);
-
- if (FT_Load_Glyph (font->val->face, val->key.index, FT_LOAD_DEFAULT) != 0)
+ face = _ft_unscaled_font_lock_face (unscaled);
+ if (!face)
return CAIRO_STATUS_NO_MEMORY;
+ _ft_unscaled_font_set_scale (unscaled, &val->key.scale);
+
+ if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
/*
* Note: the font's coordinate system is upside down from ours, so the
* Y coordinates of the bearing and advance need to be negated.
@@ -1011,11 +1218,11 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
* by FreeType
*/
- val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / sf.x_scale;
- val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / sf.y_scale;
+ val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale;
+ val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale;
- val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / sf.x_scale;
- val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / sf.y_scale;
+ val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale;
+ val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale;
/*
* use untransformed advance values
@@ -1023,8 +1230,8 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
should provide FT_LOAD_VERTICAL_LAYOUT
*/
- val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->metrics.horiAdvance) / sf.x_scale;
- val->extents.y_advance = 0 / sf.y_scale;
+ val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale;
+ val->extents.y_advance = 0 / unscaled->y_scale;
outline = &glyphslot->outline;
@@ -1052,14 +1259,16 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
bitmap.buffer = calloc (1, stride * height);
if (bitmap.buffer == NULL) {
- return CAIRO_STATUS_NO_MEMORY;
- };
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
free (bitmap.buffer);
- return CAIRO_STATUS_NO_MEMORY;
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
}
val->image = (cairo_image_surface_t *)
@@ -1068,7 +1277,8 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
width, height, stride);
if (val->image == NULL) {
free (bitmap.buffer);
- return CAIRO_STATUS_NO_MEMORY;
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
}
_cairo_image_surface_assume_ownership_of_data (val->image);
@@ -1084,138 +1294,245 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
val->size.x = (short) (cbox.xMin >> 6);
val->size.y = - (short) (cbox.yMax >> 6);
- return CAIRO_STATUS_SUCCESS;
+ FAIL:
+ _ft_unscaled_font_unlock_face (unscaled);
+
+ return status;
}
const cairo_font_backend_t cairo_ft_font_backend = {
_cairo_ft_font_create,
- _cairo_ft_font_destroy,
+ _cairo_ft_font_destroy_font,
+ _cairo_ft_font_destroy_unscaled_font,
_cairo_ft_font_font_extents,
_cairo_ft_font_text_to_glyphs,
_cairo_ft_font_glyph_extents,
_cairo_ft_font_glyph_bbox,
_cairo_ft_font_show_glyphs,
_cairo_ft_font_glyph_path,
+ _cairo_ft_font_get_glyph_cache_key,
_cairo_ft_font_create_glyph
};
-
/* implement the platform-specific interface */
+/**
+ * cairo_ft_font_create:
+ * @pattern: A fully resolved fontconfig
+ * pattern. A pattern can be resolved, by, among other things, calling
+ * FcConfigSubstitute(), FcDefaultSubstitute(), then
+ * FcFontMatch(). Cairo will call FcPatternReference() on this
+ * pattern, so you should not further modify the pattern, but you can
+ * release your reference to the pattern with FcPatternDestroy() if
+ * you no longer need to access it.
+ * @scale: The scale at which this font will be used. The
+ * scale is given by multiplying the font matrix (see
+ * cairo_transform_font()) by the current transformation matrix.
+ * The translation elements of the resulting matrix are ignored.
+ *
+ * Creates a new font for the FreeType font backend based on a
+ * fontconfig pattern. This font can then be used with
+ * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
+ * specific functions like cairo_ft_font_lock_face().
+ *
+ * Return value: a newly created #cairo_font_t. Free with
+ * cairo_font_destroy() when you are done using it.
+ **/
cairo_font_t *
-cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern)
+cairo_ft_font_create (FcPattern *pattern,
+ cairo_matrix_t *scale)
{
- cairo_font_scale_t scale;
- cairo_font_t *scaled;
- cairo_ft_font_t *f = NULL;
- ft_font_val_t *v = NULL;
- FcPattern *dup;
-
- scale.matrix[0][0] = 1.;
- scale.matrix[0][1] = 0.;
- scale.matrix[1][0] = 0.;
- scale.matrix[1][1] = 1.;
-
- scaled = malloc (sizeof (cairo_font_t));
- if (scaled == NULL)
- goto FAIL;
-
- dup = FcPatternDuplicate(pattern);
- if (dup == NULL)
- goto FREE_SCALED;
-
- v = _create_from_library_and_pattern (ft_library, pattern);
- if (v == NULL)
- goto FREE_PATTERN;
-
- f = malloc (sizeof(cairo_ft_font_t));
- if (f == NULL)
- goto FREE_VAL;
-
- if (_cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend))
- goto FREE_VAL;
-
- f->pattern = dup;
- f->val = v;
-
- _cairo_font_init (scaled, &scale, &f->base);
-
- return scaled;
-
- FREE_VAL:
- _destroy_font_val (v);
-
- FREE_PATTERN:
- FcPatternDestroy (dup);
+ cairo_font_scale_t sc;
+ double tx, ty;
- FREE_SCALED:
- free (scaled);
+ cairo_matrix_get_affine (scale,
+ &sc.matrix[0][0], &sc.matrix[0][1],
+ &sc.matrix[1][0], &sc.matrix[1][1],
+ &tx, &ty);
- FAIL:
- return NULL;
+ return _ft_font_create (pattern, &sc);
}
+/**
+ * cairo_ft_font_create_for_ft_face:
+ * @face: A FreeType face object, already opened. This must
+ * be kept around until the font object's refcount drops to
+ * zero and it is freed. The font object can be kept alive by
+ * internal caching, so it's safest to keep the face object
+ * around forever.
+ * @load_flags: The flags to pass to FT_Load_Glyph when loading
+ * glyphs from the font. These flags control aspects of
+ * rendering such as hinting and antialiasing. See the FreeType
+ * docs for full information.
+ * @scale: The scale at which this font will be used. The
+ * scale is given by multiplying the font matrix (see
+ * cairo_transform_font()) by the current transformation matrix.
+ * The translation elements of the resulting matrix are ignored.
+ *
+ * Creates a new font forthe FreeType font backend from a pre-opened
+ * FreeType face. This font can then be used with cairo_set_font(),
+ * cairo_font_glyph_extents(), or FreeType backend specific
+ * functions like cairo_ft_font_lock_face() Cairo will determine the
+ * pixel size and transformation from the @scale parameter and call
+ * FT_Set_Transform() and FT_Set_Pixel_Sizes().
+ *
+ * Return value: a newly created #cairo_font_t. Free with
+ * cairo_font_destroy() when you are done using it.
+ **/
cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face)
+cairo_ft_font_create_for_ft_face (FT_Face face,
+ int load_flags,
+ cairo_matrix_t *scale)
{
- cairo_font_scale_t scale;
- cairo_font_t *scaled;
cairo_ft_font_t *f = NULL;
- ft_font_val_t *v = NULL;
-
- scale.matrix[0][0] = 1.;
- scale.matrix[0][1] = 0.;
- scale.matrix[1][0] = 0.;
- scale.matrix[1][1] = 1.;
-
- scaled = malloc (sizeof (cairo_font_t));
- if (scaled == NULL)
- goto FAIL;
+ ft_unscaled_font_t *unscaled = NULL;
+ cairo_font_scale_t sc;
+ double tx, ty;
- v = _create_from_face (face, 0);
- if (v == NULL)
- goto FREE_SCALED;
+ unscaled = _ft_unscaled_font_create_from_face (face);
+ if (unscaled == NULL)
+ return NULL;
f = malloc (sizeof(cairo_ft_font_t));
if (f == NULL)
- goto FREE_VAL;
+ goto FREE_UNSCALED;
- _cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend);
+ f->unscaled = unscaled;
f->pattern = NULL;
- f->val = v;
+ f->load_flags = load_flags;
- _cairo_font_init (scaled, &scale, &f->base);
+ cairo_matrix_get_affine (scale,
+ &sc.matrix[0][0], &sc.matrix[0][1],
+ &sc.matrix[1][0], &sc.matrix[1][1],
+ &tx, &ty);
- return scaled;
+ _cairo_font_init ((cairo_font_t *)f, &sc, &cairo_ft_font_backend);
- FREE_VAL:
- _destroy_font_val (v);
+ return (cairo_font_t *)f;
- FREE_SCALED:
- free (scaled);
+ FREE_UNSCALED:
+ _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
- FAIL:
return NULL;
}
+
+/**
+ * cairo_ft_font_lock_face:
+ * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
+ * object can be created with cairo_ft_font_create() or
+ * cairo_ft_font_create_for_ft_face(). On some platforms the font from
+ * cairo_current_font() will also be a FreeType font, but using this
+ * functionality with fonts you don't create yourself is not
+ * recommended.
+ *
+ * cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType
+ * backend font and scales it appropriately for the font. You must
+ * release the face with cairo_ft_font_unlock_face()
+ * when you are done using it. Since the #FT_Face object can be
+ * shared between multiple #cairo_font_t objects, you must not
+ * lock any other font objects until you unlock this one. A count is
+ * kept of the number of times cairo_ft_font_lock_face() is
+ * called. cairo_ft_font_unlock_face() must be called the same number
+ * of times.
+ *
+ * You must be careful when using this function in a library or in a
+ * threaded application, because other threads may lock faces that
+ * share the same #FT_Face object. For this reason, you must call
+ * cairo_ft_lock() before locking any face objects, and
+ * cairo_ft_unlock() after you are done. (These functions are not yet
+ * implemented, so this function cannot be currently safely used in a
+ * threaded application.)
+
+ * Return value: The #FT_Face object for @font, scaled appropriately.
+ **/
FT_Face
-cairo_ft_font_face (cairo_font_t *abstract_font)
+cairo_ft_font_lock_face (cairo_font_t *abstract_font)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled;
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+ FT_Face face;
- if (font == NULL || font->val == NULL)
- return NULL;
+ face = _ft_unscaled_font_lock_face (font->unscaled);
+ if (!face)
+ return NULL;
+
+ _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
+
+ return face;
+}
- return font->val->face;
+/**
+ * cairo_ft_font_unlock_face:
+ * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
+ * object can be created with cairo_ft_font_create() or
+ * cairo_ft_font_create_for_ft_face(). On some platforms the font from
+ * cairo_current_font() will also be a FreeType font, but using this
+ * functionality with fonts you don't create yourself is not
+ * recommended.
+ *
+ * Releases a face obtained with cairo_ft_font_lock_face(). See the
+ * documentation for that function for full details.
+ **/
+void
+cairo_ft_font_unlock_face (cairo_font_t *abstract_font)
+{
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+
+ _ft_unscaled_font_unlock_face (font->unscaled);
}
+/**
+ * cairo_ft_font_get_pattern:
+ * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
+ * object can be created with cairo_ft_font_create() or
+ * cairo_ft_font_create_for_ft_face(). On some platforms the font from
+ * cairo_current_font() will also be a FreeType font, but using this
+ * functionality with fonts you don't create yourself is not
+ * recommended.
+ *
+ * cairo_ft_font_get_pattern() gets the #FcPattern for a FreeType
+ * backend font.
+
+ * Return value: The #FcPattenr for @font. The return value is owned
+ * by the font, so you must not modify it, and must call
+ * FcPatternReference() to keep a persistant reference to the
+ * pattern. If the font was created with cairo_ft_font_create_for_ft_face()
+ * returns %NULL.
+ **/
FcPattern *
-cairo_ft_font_pattern (cairo_font_t *abstract_font)
+cairo_ft_font_get_pattern (cairo_font_t *abstract_font)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled;
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
if (font == NULL)
return NULL;
return font->pattern;
}
+
+/* We expose our unscaled font implementation internally for the the
+ * PDF backend, which needs to keep track of the the different
+ * fonts-on-disk used by a document, so it can embed them.
+ */
+cairo_unscaled_font_t *
+_cairo_ft_font_get_unscaled_font (cairo_font_t *abstract_font)
+{
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+
+ return (cairo_unscaled_font_t *)font->unscaled;
+}
+
+/* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't
+ * set the scale on the face, but just returns it at the last scale.
+ */
+FT_Face
+_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font)
+{
+ return _ft_unscaled_font_lock_face ((ft_unscaled_font_t *)unscaled_font);
+}
+
+void
+_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font)
+{
+ _ft_unscaled_font_unlock_face ((ft_unscaled_font_t *)unscaled_font);
+}
diff --git a/src/cairo_gdip_font.cpp b/src/cairo_gdip_font.cpp
deleted file mode 100644
index e932e3bac..000000000
--- a/src/cairo_gdip_font.cpp
+++ /dev/null
@@ -1,665 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 Stuart Parmenter
- *
- * 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 Stuart Parmenter.
- *
- * Contributor(s):
- * Stuart Parmenter <pavlov@pavlov.net>
- */
-
-extern "C" {
-#include "cairoint.h"
-}
-
-#include <windows.h>
-
-#include <gdiplus.h>
-using namespace Gdiplus;
-
-#if 0
-#include <fontconfig/fontconfig.h>
-#include <fontconfig/fcfreetype.h>
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_OUTLINE_H
-#include FT_IMAGE_H
-#endif
-
-typedef struct {
- cairo_font_t base;
- HDC hdc;
- HFONT hfont;
-} cairo_win32_font_t;
-
-
-
-static int
-_utf8_to_glyphs (cairo_win32_font_t *font,
- const unsigned char *utf8,
- double x0,
- double y0,
- cairo_glyph_t **glyphs,
- size_t *nglyphs)
-{
- /* XXX implement me */
- *glyphs = NULL;
- *nglyphs = 0;
-
- return 0;
-}
-
-/* implement the platform-specific interface */
-
-cairo_font_t *
-cairo_win32_font_create (HFONT hfont)
-{
- cairo_win32_font_t *f = (cairo_win32_font_t*)malloc(sizeof(cairo_win32_font_t));
- if (f == NULL)
- return NULL;
-
- f->hfont = hfont;
-
- _cairo_font_init (&f->base, &cairo_win32_font_backend);
-
- return (cairo_font_t *) f;
-}
-
-#if 0
-FT_Face
-cairo_win32_font_face (cairo_font_t *abstract_font)
-{
- cairo_win32_font_t *font = (cairo_win32_font_t *) abstract_font;
-
- if (font == NULL)
- return NULL;
-
- return font->face;
-}
-
-FcPattern *
-cairo_win32_font_pattern (cairo_font_t *abstract_font)
-{
- cairo_win32_font_t *font = (cairo_win32_font_t *) abstract_font;
-
- if (font == NULL)
- return NULL;
-
- return font->pattern;
-}
-#endif
-
-/* implement the backend interface */
-
-static cairo_font_t *
-_cairo_win32_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight)
-{
- int fontHeight = 60; // in Pixels in this case
- int fontWidth = 0;
- int italic = 0;
- int bold = FW_REGULAR;
-
- switch (slant) {
- case CAIRO_FONT_SLANT_ITALIC:
- italic = 1;
- case CAIRO_FONT_SLANT_OBLIQUE:
- case CAIRO_FONT_SLANT_NORMAL:
- default:
- break;
- }
-
- if (weight == CAIRO_FONT_WEIGHT_BOLD)
- bold = FW_BOLD;
-
- HFONT hfont = CreateFont(fontHeight, // height of font
- fontWidth, // average character width
- 0, // angle of escapement
- 0, // base-line orientation angle
- bold, // font weight
- italic, // italic attribute option
- FALSE, // underline attribute option
- FALSE, // strikeout attribute option
- ANSI_CHARSET, // character set identifier
- OUT_DEFAULT_PRECIS, // output precision
- CLIP_DEFAULT_PRECIS, // clipping precision
- ANTIALIASED_QUALITY, // output quality
- FF_DONTCARE, // pitch and family
- family); // typeface name
-
- return cairo_win32_font_create(hfont);
-}
-
-static cairo_font_t *
-_cairo_win32_font_copy (void *abstract_font)
-{
- cairo_win32_font_t *font_new = NULL;
- cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
-
- if (font->base.backend != &cairo_win32_font_backend)
- return NULL;
-
- font_new = (cairo_win32_font_t *) cairo_win32_font_create(font->hfont);
- if (font_new == NULL)
- return NULL;
-
- return (cairo_font_t *) font_new;
-}
-
-static void
-_cairo_win32_font_destroy (void *abstract_font)
-{
- cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
-
- //delete font->font;
-
- free (font);
-}
-
-static cairo_status_t
-_cairo_win32_font_font_extents (void *abstract_font,
- cairo_font_extents_t *extents)
-{
- cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
-
- TEXTMETRIC metrics;
- GetTextMetrics(font->hdc, &metrics);
-
- extents->ascent = metrics.tmAscent;
- extents->descent = metrics.tmDescent;
- extents->height = metrics.tmHeight;
- extents->max_x_advance = 0; /* XXX */
- extents->max_y_advance = 0; /* XXX */
-
-
-#if 0
- FT_Face face = font->face;
- double scale_x, scale_y;
-
- double upm = face->units_per_EM;
-
- _cairo_matrix_compute_scale_factors (&font->base.matrix, &scale_x, &scale_y);
-
- extents->ascent = face->ascender / upm * scale_y;
- extents->descent = face->descender / upm * scale_y;
- extents->height = face->height / upm * scale_y;
- extents->max_x_advance = face->max_advance_width / upm * scale_x;
- extents->max_y_advance = face->max_advance_height / upm * scale_y;
-#endif
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_win32_font_glyph_extents (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
-
- int i;
- for (i = 0; i < num_glyphs; ++i) {
- GLYPHMETRICS metrics;
- GetGlyphOutline(font->hdc, 'a', GGO_METRICS, &metrics, 0, NULL, NULL);
-
- extents->width += metrics.gmBlackBoxX;
- extents->height += metrics.gmBlackBoxY;
- /* metrics has:
- UINT gmBlackBoxX;
- UINT gmBlackBoxY;
- POINT gmptGlyphOrigin;
- short gmCellIncX;
- short gmCellIncY;
-
- extents has:
- double x_bearing;
- double y_bearing;
- double width;
- double height;
- double x_advance;
- double y_advance;
- */
- }
-
-#if 0
- int i;
- cairo_win32_font_t *font = abstract_font;
- cairo_point_double_t origin;
- cairo_point_double_t glyph_min, glyph_max;
- cairo_point_double_t total_min, total_max;
- FT_Error error;
- FT_Face face = font->face;
- FT_GlyphSlot glyph = face->glyph;
- FT_Glyph_Metrics *metrics = &glyph->metrics;
-
- if (num_glyphs == 0)
- {
- extents->x_bearing = 0.0;
- extents->y_bearing = 0.0;
- extents->width = 0.0;
- extents->height = 0.0;
- extents->x_advance = 0.0;
- extents->y_advance = 0.0;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- origin.x = glyphs[0].x;
- origin.y = glyphs[0].y;
-
- _install_font_matrix (&font->base.matrix, face);
-
- for (i = 0; i < num_glyphs; i++)
- {
- error = FT_Load_Glyph (face, glyphs[i].index, FT_LOAD_DEFAULT);
- /* XXX: What to do in this error case? */
- if (error)
- continue;
-
- /* XXX: Need to add code here to check the font's FcPattern
- for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y
- instead. This will require that
- cairo_win32_font_create_for_ft_face accept an
- FcPattern. */
- glyph_min.x = glyphs[i].x + DOUBLE_FROM_26_6 (metrics->horiBearingX);
- glyph_min.y = glyphs[i].y - DOUBLE_FROM_26_6 (metrics->horiBearingY);
- glyph_max.x = glyph_min.x + DOUBLE_FROM_26_6 (metrics->width);
- glyph_max.y = glyph_min.y + DOUBLE_FROM_26_6 (metrics->height);
-
- if (i==0) {
- total_min = glyph_min;
- total_max = glyph_max;
- } else {
- if (glyph_min.x < total_min.x)
- total_min.x = glyph_min.x;
- if (glyph_min.y < total_min.y)
- total_min.y = glyph_min.y;
-
- if (glyph_max.x > total_max.x)
- total_max.x = glyph_max.x;
- if (glyph_max.y > total_max.y)
- total_max.y = glyph_max.y;
- }
- }
-
- extents->x_bearing = total_min.x - origin.x;
- extents->y_bearing = total_min.y - origin.y;
- extents->width = total_max.x - total_min.x;
- extents->height = total_max.y - total_min.y;
- extents->x_advance = glyphs[i-1].x + DOUBLE_FROM_26_6 (metrics->horiAdvance) - origin.x;
- extents->y_advance = glyphs[i-1].y + 0 - origin.y;
-#endif
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static cairo_status_t
-_cairo_win32_font_text_extents (void *abstract_font,
- const unsigned char *utf8,
- cairo_text_extents_t *extents)
-{
- cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
-
- cairo_glyph_t *glyphs;
- size_t nglyphs;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- if (_utf8_to_glyphs (font, utf8, 0, 0, &glyphs, &nglyphs))
- {
- status = _cairo_win32_font_glyph_extents (font, glyphs, nglyphs,
- extents);
- free (glyphs);
- }
-
- return status;
-}
-
-static cairo_status_t
-_cairo_win32_font_glyph_bbox (void *abstract_font,
- cairo_surface_t *surface,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
-{
- cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
-#if 0
- cairo_surface_t *mask = NULL;
- cairo_glyph_size_t size;
-
- cairo_fixed_t x1, y1, x2, y2;
- int i;
-
- bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16;
- bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16;
-
- if (font == NULL
- || surface == NULL
- || glyphs == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < num_glyphs; i++)
- {
- mask = _cairo_font_lookup_glyph (&font->base, surface,
- &glyphs[i], &size);
- if (mask == NULL)
- continue;
-
- x1 = _cairo_fixed_from_double (glyphs[i].x + size.x);
- y1 = _cairo_fixed_from_double (glyphs[i].y - size.y);
- x2 = x1 + _cairo_fixed_from_double (size.width);
- y2 = y1 + _cairo_fixed_from_double (size.height);
-
- if (x1 < bbox->p1.x)
- bbox->p1.x = x1;
-
- if (y1 < bbox->p1.y)
- bbox->p1.y = y1;
-
- if (x2 > bbox->p2.x)
- bbox->p2.x = x2;
-
- if (y2 > bbox->p2.y)
- bbox->p2.y = y2;
-
- if (mask)
- cairo_surface_destroy (mask);
- }
-#endif
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_win32_font_text_bbox (void *abstract_font,
- cairo_surface_t *surface,
- double x0,
- double y0,
- const unsigned char *utf8,
- cairo_box_t *bbox)
-{
- cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
-
- cairo_glyph_t *glyphs;
- size_t num_glyphs;
-
- if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs))
- {
- cairo_status_t res;
- res = _cairo_win32_font_glyph_bbox (font, surface,
- glyphs, num_glyphs, bbox);
- free (glyphs);
- return res;
- }
- else
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-static cairo_status_t
-_cairo_win32_font_show_glyphs (void *abstract_font,
- cairo_operator_t op,
- cairo_surface_t *source,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
-#if 0
- cairo_status_t status;
- cairo_surface_t *mask = NULL;
- cairo_glyph_size_t size;
-
- double x, y;
- int i;
-
- if (font == NULL
- || source == NULL
- || surface == NULL
- || glyphs == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < num_glyphs; i++)
- {
- mask = _cairo_font_lookup_glyph (&font->base, surface,
- &glyphs[i], &size);
- if (mask == NULL)
- continue;
-
- x = glyphs[i].x;
- y = glyphs[i].y;
-
- status = _cairo_surface_composite (operator, source, mask, surface,
- source_x + x + size.x,
- source_y + y - size.y,
- 0, 0,
- x + size.x,
- y - size.y,
- (double) size.width,
- (double) size.height);
-
- cairo_surface_destroy (mask);
-
- if (status)
- return status;
- }
-#endif
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_win32_font_show_text (void *abstract_font,
- cairo_operator_t op,
- cairo_surface_t *source,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- double x0,
- double y0,
- const unsigned char *utf8)
-{
- cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
-
- cairo_glyph_t *glyphs;
- size_t num_glyphs;
-
- if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs))
- {
- cairo_status_t res;
- res = _cairo_win32_font_show_glyphs (font, op,
- source, surface,
- source_x, source_y,
- glyphs, num_glyphs);
- free (glyphs);
- return res;
- }
- else
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-static cairo_status_t
-_cairo_win32_font_glyph_path (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
-{
-#if 0
- int i;
- cairo_win32_font_t *font = abstract_font;
- FT_GlyphSlot glyph;
- FT_Error error;
- FT_Outline_Funcs outline_funcs = {
- _move_to,
- _line_to,
- _conic_to,
- _cubic_to,
- 0, /* shift */
- 0, /* delta */
- };
-
- glyph = font->face->glyph;
- _install_font_matrix (&font->base.matrix, font->face);
-
- for (i = 0; i < num_glyphs; i++)
- {
- FT_Matrix invert_y = {
- DOUBLE_TO_16_16 (1.0), 0,
- 0, DOUBLE_TO_16_16 (-1.0),
- };
-
- error = FT_Load_Glyph (font->face, glyphs[i].index, FT_LOAD_DEFAULT);
- /* XXX: What to do in this error case? */
- if (error)
- continue;
- /* XXX: Do we want to support bitmap fonts here? */
- if (glyph->format == ft_glyph_format_bitmap)
- continue;
-
- /* Font glyphs have an inverted Y axis compared to cairo. */
- FT_Outline_Transform (&glyph->outline, &invert_y);
- FT_Outline_Translate (&glyph->outline,
- DOUBLE_TO_26_6(glyphs[i].x),
- DOUBLE_TO_26_6(glyphs[i].y));
- FT_Outline_Decompose (&glyph->outline, &outline_funcs, path);
- }
- _cairo_path_close_path (path);
-#endif
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_win32_font_text_path (void *abstract_font,
- double x,
- double y,
- const unsigned char *utf8,
- cairo_path_t *path)
-{
-#if 0
- cairo_win32_font_t *font = abstract_font;
- cairo_glyph_t *glyphs;
- size_t nglyphs;
-
- if (_utf8_to_glyphs (font, utf8, x, y, &glyphs, &nglyphs))
- {
- cairo_status_t res;
- res = _cairo_win32_font_glyph_path (font, glyphs, nglyphs, path);
- free (glyphs);
- return res;
- }
- else
-#endif
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-static cairo_surface_t *
-_cairo_win32_font_create_glyph (void *abstract_font,
- const cairo_glyph_t *glyph,
- cairo_glyph_size_t *return_size)
-{
-#if 0
- cairo_win32_font_t *font = abstract_font;
- cairo_image_surface_t *image;
- FT_GlyphSlot glyphslot;
- unsigned int width, height, stride;
- FT_Outline *outline;s
- FT_BBox cbox;
- FT_Bitmap bitmap;
-
- glyphslot = font->face->glyph;
- _install_font_matrix (&font->base.matrix, font->face);
-
- FT_Load_Glyph (font->face, glyph->index, FT_LOAD_DEFAULT);
-
- outline = &glyphslot->outline;
-
- FT_Outline_Get_CBox (outline, &cbox);
-
- cbox.xMin &= -64;
- cbox.yMin &= -64;
- cbox.xMax = (cbox.xMax + 63) & -64;
- cbox.yMax = (cbox.yMax + 63) & -64;
-
- width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6);
- height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6);
- stride = (width + 3) & -4;
-
- bitmap.pixel_mode = ft_pixel_mode_grays;
- bitmap.num_grays = 256;
- bitmap.width = width;
- bitmap.rows = height;
- bitmap.pitch = stride;
-
- if (width * height == 0)
- return NULL;
-
- bitmap.buffer = malloc (stride * height);
- if (bitmap.buffer == NULL)
- return NULL;
-
- memset (bitmap.buffer, 0x0, stride * height);
-
- FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
- FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap);
-
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data ((char *) bitmap.buffer,
- CAIRO_FORMAT_A8,
- width, height, stride);
- if (image == NULL) {
- free (bitmap.buffer);
- return NULL;
- }
-
- _cairo_image_surface_assume_ownership_of_data (image);
-
- return_size->width = (unsigned short) width;
- return_size->height = (unsigned short) height;
- return_size->x = (short) (cbox.xMin >> 6);
- return_size->y = (short) (cbox.yMax >> 6);
-
- return &image->base;
-#endif
- return NULL;
-}
-
-const struct cairo_font_backend cairo_win32_font_backend = {
- _cairo_win32_font_create,
- _cairo_win32_font_copy,
- _cairo_win32_font_destroy,
- _cairo_win32_font_font_extents,
- _cairo_win32_font_text_extents,
- _cairo_win32_font_glyph_extents,
- _cairo_win32_font_text_bbox,
- _cairo_win32_font_glyph_bbox,
- _cairo_win32_font_show_text,
- _cairo_win32_font_show_glyphs,
- _cairo_win32_font_text_path,
- _cairo_win32_font_glyph_path,
- _cairo_win32_font_create_glyph
-};
diff --git a/src/cairo_gdip_surface.cpp b/src/cairo_gdip_surface.cpp
deleted file mode 100644
index ec1982b55..000000000
--- a/src/cairo_gdip_surface.cpp
+++ /dev/null
@@ -1,727 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 Stuart Parmenter
- *
- * 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 Stuart Parmenter.
- *
- * Contributor(s):
- * Stuart Parmenter <pavlov@pavlov.net>
- */
-
-extern "C" {
-#include "cairoint.h"
-}
-
-/* export symbols, for cairo.dll only */
-
-#pragma comment(linker, "/EXPORT:_cairo_create")
-#pragma comment(linker, "/EXPORT:_cairo_reference")
-#pragma comment(linker, "/EXPORT:_cairo_destroy")
-#pragma comment(linker, "/EXPORT:_cairo_save")
-#pragma comment(linker, "/EXPORT:_cairo_restore")
-#pragma comment(linker, "/EXPORT:_cairo_copy")
-#pragma comment(linker, "/EXPORT:_cairo_set_target_surface")
-#pragma comment(linker, "/EXPORT:_cairo_set_target_image")
-
-#ifdef CAIRO_HAS_PS_SURFACE
-#pragma comment(linker, "/EXPORT:_cairo_set_target_ps")
-#endif
-
-#ifdef CAIRO_HAS_PS_SURFACE
-#pragma comment(linker, "/EXPORT:_cairo_set_target_pdf")
-#endif
-
-#ifdef CAIRO_HAS_PNG_SURFACE
-#pragma comment(linker, "/EXPORT:_cairo_set_target_png")
-#endif
-
-#ifdef CAIRO_HAS_GL_SURFACE
-#pragma comment(linker, "/EXPORT:_cairo_set_target_gl")
-#endif
-
-#ifdef CAIRO_HAS_WIN32_SURFACE
-#pragma comment(linker, "/EXPORT:_cairo_set_target_win32")
-#endif
-
-#pragma comment(linker, "/EXPORT:_cairo_set_operator")
-#pragma comment(linker, "/EXPORT:_cairo_set_rgb_color")
-#pragma comment(linker, "/EXPORT:_cairo_set_pattern")
-#pragma comment(linker, "/EXPORT:_cairo_set_alpha")
-#pragma comment(linker, "/EXPORT:_cairo_set_tolerance")
-#pragma comment(linker, "/EXPORT:_cairo_set_fill_rule")
-#pragma comment(linker, "/EXPORT:_cairo_set_line_width")
-#pragma comment(linker, "/EXPORT:_cairo_set_line_cap")
-#pragma comment(linker, "/EXPORT:_cairo_set_line_join")
-#pragma comment(linker, "/EXPORT:_cairo_set_dash")
-#pragma comment(linker, "/EXPORT:_cairo_set_miter_limit")
-#pragma comment(linker, "/EXPORT:_cairo_set_line_cap")
-
-#pragma comment(linker, "/EXPORT:_cairo_translate")
-#pragma comment(linker, "/EXPORT:_cairo_scale")
-#pragma comment(linker, "/EXPORT:_cairo_rotate")
-
-#pragma comment(linker, "/EXPORT:_cairo_concat_matrix")
-#pragma comment(linker, "/EXPORT:_cairo_set_matrix")
-#pragma comment(linker, "/EXPORT:_cairo_default_matrix")
-#pragma comment(linker, "/EXPORT:_cairo_identity_matrix")
-#pragma comment(linker, "/EXPORT:_cairo_transform_point")
-#pragma comment(linker, "/EXPORT:_cairo_transform_distance")
-#pragma comment(linker, "/EXPORT:_cairo_inverse_transform_point")
-#pragma comment(linker, "/EXPORT:_cairo_inverse_transform_distance")
-
-#pragma comment(linker, "/EXPORT:_cairo_new_path")
-#pragma comment(linker, "/EXPORT:_cairo_move_to")
-#pragma comment(linker, "/EXPORT:_cairo_line_to")
-#pragma comment(linker, "/EXPORT:_cairo_curve_to")
-#pragma comment(linker, "/EXPORT:_cairo_arc")
-#pragma comment(linker, "/EXPORT:_cairo_arc_negative")
-#pragma comment(linker, "/EXPORT:_cairo_rel_move_to")
-#pragma comment(linker, "/EXPORT:_cairo_rel_line_to")
-#pragma comment(linker, "/EXPORT:_cairo_rel_curve_to")
-#pragma comment(linker, "/EXPORT:_cairo_rectangle")
-#pragma comment(linker, "/EXPORT:_cairo_close_path")
-
-#pragma comment(linker, "/EXPORT:_cairo_stroke")
-#pragma comment(linker, "/EXPORT:_cairo_fill")
-#pragma comment(linker, "/EXPORT:_cairo_copy_page")
-#pragma comment(linker, "/EXPORT:_cairo_show_page")
-#pragma comment(linker, "/EXPORT:_cairo_in_stroke")
-#pragma comment(linker, "/EXPORT:_cairo_in_fill")
-#pragma comment(linker, "/EXPORT:_cairo_stroke_extents")
-#pragma comment(linker, "/EXPORT:_cairo_fill_extents")
-
-#pragma comment(linker, "/EXPORT:_cairo_init_clip")
-#pragma comment(linker, "/EXPORT:_cairo_clip")
-#pragma comment(linker, "/EXPORT:_cairo_select_font")
-#pragma comment(linker, "/EXPORT:_cairo_scale_font")
-#pragma comment(linker, "/EXPORT:_cairo_transform_font")
-#pragma comment(linker, "/EXPORT:_cairo_show_text")
-#pragma comment(linker, "/EXPORT:_cairo_show_glyphs")
-#pragma comment(linker, "/EXPORT:_cairo_current_font")
-#pragma comment(linker, "/EXPORT:_cairo_current_font_extents")
-#pragma comment(linker, "/EXPORT:_cairo_set_font")
-#pragma comment(linker, "/EXPORT:_cairo_text_extents")
-#pragma comment(linker, "/EXPORT:_cairo_glyph_extents")
-#pragma comment(linker, "/EXPORT:_cairo_text_path")
-#pragma comment(linker, "/EXPORT:_cairo_glyph_path")
-#pragma comment(linker, "/EXPORT:_cairo_font_reference")
-#pragma comment(linker, "/EXPORT:_cairo_font_destroy")
-#pragma comment(linker, "/EXPORT:_cairo_font_set_transform")
-#pragma comment(linker, "/EXPORT:_cairo_font_current_transform")
-
-/*#pragma comment(linker, "/EXPORT:_cairo_ft_font_create")
-#pragma comment(linker, "/EXPORT:_cairo_ft_font_create_for_ft_face")
-*/
-#if 0
-/* hmm, this function doesn't exist, but __cairo_ft_font_destroy does */
-#pragma comment(linker, "/EXPORT:_cairo_ft_font_destroy")
-#endif
-/*
-#pragma comment(linker, "/EXPORT:_cairo_ft_font_face")
-#pragma comment(linker, "/EXPORT:_cairo_ft_font_pattern")
-*/
-#pragma comment(linker, "/EXPORT:_cairo_show_surface")
-#pragma comment(linker, "/EXPORT:_cairo_current_operator")
-#pragma comment(linker, "/EXPORT:_cairo_current_rgb_color")
-#pragma comment(linker, "/EXPORT:_cairo_current_pattern")
-#pragma comment(linker, "/EXPORT:_cairo_current_alpha")
-#pragma comment(linker, "/EXPORT:_cairo_current_tolerance")
-#pragma comment(linker, "/EXPORT:_cairo_current_point")
-#pragma comment(linker, "/EXPORT:_cairo_current_fill_rule")
-#pragma comment(linker, "/EXPORT:_cairo_current_line_width")
-#pragma comment(linker, "/EXPORT:_cairo_current_line_cap")
-#pragma comment(linker, "/EXPORT:_cairo_current_line_join")
-#pragma comment(linker, "/EXPORT:_cairo_current_rgb_color")
-#pragma comment(linker, "/EXPORT:_cairo_current_miter_limit")
-#pragma comment(linker, "/EXPORT:_cairo_current_matrix")
-#pragma comment(linker, "/EXPORT:_cairo_current_target_surface")
-#pragma comment(linker, "/EXPORT:_cairo_current_path")
-#pragma comment(linker, "/EXPORT:_cairo_current_path_flat")
-
-#pragma comment(linker, "/EXPORT:_cairo_status")
-#pragma comment(linker, "/EXPORT:_cairo_status_string")
-
-#pragma comment(linker, "/EXPORT:_cairo_surface_create_for_image")
-#pragma comment(linker, "/EXPORT:_cairo_surface_create_similar")
-#pragma comment(linker, "/EXPORT:_cairo_surface_reference")
-#pragma comment(linker, "/EXPORT:_cairo_surface_destroy")
-#pragma comment(linker, "/EXPORT:_cairo_surface_set_repeat")
-#pragma comment(linker, "/EXPORT:_cairo_surface_set_matrix")
-#pragma comment(linker, "/EXPORT:_cairo_surface_get_matrix")
-#pragma comment(linker, "/EXPORT:_cairo_surface_set_filter")
-#pragma comment(linker, "/EXPORT:_cairo_surface_get_filter")
-
-#pragma comment(linker, "/EXPORT:_cairo_image_surface_create")
-#pragma comment(linker, "/EXPORT:_cairo_image_surface_create_for_data")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_create_for_surface")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_create_linear")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_create_radial")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_reference")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_destroy")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_add_color_stop")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_set_matrix")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_get_matrix")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_set_extend")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_get_extend")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_set_filter")
-#pragma comment(linker, "/EXPORT:_cairo_pattern_get_filter")
-
-#ifdef CAIRO_HAS_PS_SURFACE
-#pragma comment(linker, "/EXPORT:_cairo_ps_surface_create")
-#endif
-
-#ifdef CAIRO_HAS_PNG_SURFACE
-#pragma comment(linker, "/EXPORT:_cairo_png_surface_create")
-#endif
-
-#ifdef CAIRO_HAS_GL_SURFACE
-#pragma comment(linker, "/EXPORT:_cairo_gl_surface_create")
-#endif
-
-#pragma comment(linker, "/EXPORT:_cairo_matrix_create")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_destroy")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_copy")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_set_identity")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_set_affine")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_get_affine")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_translate")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_scale")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_rotate")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_invert")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_multiply")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_transform_distance")
-#pragma comment(linker, "/EXPORT:_cairo_matrix_transform_point")
-
-#include <windows.h>
-
-#include <gdiplus.h>
-using namespace Gdiplus;
-
-extern const cairo_surface_backend_t cairo_win32_surface_backend;
-
-cairo_surface_t *_cairo_win32_surface_create (HDC dc);
-
-void
-cairo_set_target_win32(cairo_t *cr, HDC dc)
-{
- cairo_surface_t *surface;
-
- surface = _cairo_win32_surface_create(dc);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
-
-typedef struct cairo_win32_surface {
- cairo_surface_t base;
- Graphics *gr;
-
- Brush *brush;
-} cairo_win32_surface_t;
-
-
-static void
-_cairo_win32_surface_erase(cairo_win32_surface_t *surface);
-
-cairo_surface_t *
-_cairo_win32_surface_create(HDC dc)
-{
- cairo_win32_surface_t *surface;
-
- surface = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
- if (surface == NULL)
- return NULL;
-
- surface->gr = new Graphics(dc);
- surface->brush = NULL;
-// surface->gr->TranslateTransform(-2000*2.5, -3000*2.2);
-// surface->gr->ScaleTransform(20, 20);
-
- surface->gr->SetSmoothingMode(SmoothingModeAntiAlias);
-
- /* do pixmap creation, etc */
-
- _cairo_surface_init(&surface->base, &cairo_win32_surface_backend);
-
- _cairo_win32_surface_erase(surface);
-
- return &surface->base;
-}
-
-static cairo_surface_t *
-_cairo_win32_surface_create_similar(void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- return NULL;
-}
-
-static void
-_cairo_win32_surface_destroy (void *abstract_surface)
-{
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
-
- delete surface->gr;
- delete surface->brush;
-
- free(surface);
-}
-
-static void
-_cairo_win32_surface_erase(cairo_win32_surface_t *surface)
-{
- surface->gr->Clear(Color(255, 0, 0, 0));
-}
-
-/* XXX: We should re-work this interface to return both X/Y ppi values. */
-static double
-_cairo_win32_surface_pixels_per_inch(void *abstract_surface)
-{
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
-
- return surface->gr->GetDpiY();
-}
-
-static Image *
-make_image(cairo_image_surface_t *image)
-{
- Rect r(0, 0, image->width, image->height);
- Bitmap *b = new Bitmap(image->width, image->height, PixelFormat32bppPARGB);
- BitmapData data;
-
- b->LockBits(&r, ImageLockModeWrite, PixelFormat32bppPARGB, &data);
-
- memcpy(data.Scan0, image->data, image->stride * image->height);
-
- b->UnlockBits(&data);
-
- return b;
-}
-
-static cairo_image_surface_t *
-_cairo_win32_surface_get_image(void *abstract_surface)
-{
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
-
- /* need to figure out how to get the data from a Graphics and turn it in to an Image */
- return NULL;
-}
-
-
-static cairo_status_t
-_cairo_win32_surface_set_image(void *abstract_surface,
- cairo_image_surface_t *image)
-{
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
-
- Image *img = make_image(image);
- surface->gr->DrawImage(img, 0, 0);
- delete img;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_win32_surface_set_matrix(void *abstract_surface,
- cairo_matrix_t *matrix)
-{
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
-
- Matrix m((float)matrix->m[0][0], (float)matrix->m[1][0], (float)matrix->m[2][0],
- (float)matrix->m[0][1], (float)matrix->m[1][1], (float)matrix->m[2][1]);
-
-
- surface->gr->SetTransform(&m);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_win32_surface_set_filter (void *abstract_surface,
- cairo_filter_t filter)
-{
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
- SmoothingMode mode;
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- mode = SmoothingModeNone;
- break;
- case CAIRO_FILTER_GOOD:
- case CAIRO_FILTER_BEST:
- case CAIRO_FILTER_NEAREST:
- case CAIRO_FILTER_BILINEAR:
- case CAIRO_FILTER_GAUSSIAN:
- default:
- mode = SmoothingModeAntiAlias;
- break;
- }
- surface->gr->SetSmoothingMode(mode);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_win32_surface_set_repeat (void *abstract_surface,
- int repeat)
-{
- /* what is this function supposed to do? */
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
-
- return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_composite(cairo_operator_t op,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-
-static cairo_int_status_t
-_cairo_win32_surface_fill_rectangles(void *abstract_surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
-
- SolidBrush brush(Color(color->alpha_short, color->red_short, color->green_short, color->blue_short));
-
- RectF *r = new RectF[num_rects]; /* should really allocate a small number here on the stack and use those if possible */
- for (int i = 0; i < num_rects; ++i) {
- r[i].X = rects[i].x;
- r[i].Y = rects[i].y;
- r[i].Width = rects[i].width;
- r[i].Height = rects[i].height;
- }
-
- surface->gr->FillRectangles(&brush, r, num_rects);
-
- delete[] r;
-
- return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
-}
-
-
-
-static int
-_cairo_win32_extract_rectangle (cairo_trapezoid_t *trap,
- RectF *rect)
-{
- if (trap->left.p1.x == trap->left.p2.x &&
- trap->right.p1.x == trap->right.p2.x &&
- trap->left.p1.y == trap->right.p1.y &&
- trap->left.p2.y == trap->right.p2.y) {
-
- double x = _cairo_fixed_to_double (trap->left.p1.x);
- double y = _cairo_fixed_to_double (trap->left.p1.y);
- rect->X = (float)x;
- rect->Y = (float)y;
- rect->Width = (float)(_cairo_fixed_to_double(trap->right.p1.x) - x);
- rect->Height = (float)(_cairo_fixed_to_double(trap->left.p2.y) - y);
-
- return 1;
- }
-
- return 0;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_composite_trapezoids (cairo_operator_t op,
- cairo_surface_t *generic_src,
- void *abstract_dst,
- int x_src,
- int y_src,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_dst;
-
- static int zzz = 0;
- zzz += num_traps;
-
- Image *img = NULL;
- Brush *brush = NULL; /* i'd really like to not allocate this on the heap.. */
-
-#define FIXED_TO_FLOAT(x) (float)_cairo_fixed_to_double((x))
-
- /* ugh.. figure out if we're a "native" pattern or an image_surface pattern.. */
- if (generic_src->backend == &cairo_win32_surface_backend) {
- brush = ((cairo_win32_surface_t*)generic_src)->brush;
- /* XXX move this outside so that TextureBrushes can take advantage of it */
- /* Check to see if we can represent these traps as a rectangle. */
- RectF rect;
- if (num_traps == 1 && _cairo_win32_extract_rectangle(traps, &rect)) {
- surface->gr->FillRectangle(brush, rect);
- return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
- }
- } else {
- /* I would really love to move this code in to create_pattern if possible */
- img = make_image((cairo_image_surface_t*)generic_src);
- brush = new TextureBrush(img);
-
- // XXX this will probably break. Don't know why we have +1 and +2 offsets..
- float xoff = (FIXED_TO_FLOAT(traps[0].left.p1.x) + 0.5f);
- float yoff = (FIXED_TO_FLOAT(traps[0].left.p1.y) + 1.5f);
- static_cast<TextureBrush*>(brush)->TranslateTransform((int)(-x_src + xoff),
- (int)(-y_src + yoff));
- }
-
- CompositingMode mode;
- switch (op) {
- case CAIRO_OPERATOR_OVER:
- mode = CompositingModeSourceOver;
- break;
- case CAIRO_OPERATOR_CLEAR:
- mode = CompositingModeSourceCopy;
- break;
- case CAIRO_OPERATOR_SRC:
- case CAIRO_OPERATOR_DST:
- case CAIRO_OPERATOR_OVER_REVERSE:
- case CAIRO_OPERATOR_IN:
- case CAIRO_OPERATOR_IN_REVERSE:
- case CAIRO_OPERATOR_OUT:
- case CAIRO_OPERATOR_OUT_REVERSE:
- case CAIRO_OPERATOR_ATOP:
- case CAIRO_OPERATOR_ATOP_REVERSE:
- case CAIRO_OPERATOR_XOR:
- case CAIRO_OPERATOR_ADD:
- case CAIRO_OPERATOR_SATURATE:
- mode = CompositingModeSourceOver;
- break;
- }
- surface->gr->SetCompositingMode(mode);
-
- PointF points[4];
- for (int i = 0; i < num_traps; ++i) {
- float top = FIXED_TO_FLOAT(traps[i].top);
- float bottom = FIXED_TO_FLOAT(traps[i].bottom);
-
- /* left line */
- points[0].X = FIXED_TO_FLOAT(traps[i].left.p1.x);
- points[0].Y = FIXED_TO_FLOAT(traps[i].left.p1.y);
- points[1].X = FIXED_TO_FLOAT(traps[i].left.p2.x);
- points[1].Y = FIXED_TO_FLOAT(traps[i].left.p2.y);
-
- /* right line */
- points[2].X = FIXED_TO_FLOAT(traps[i].right.p2.x);
- points[2].Y = FIXED_TO_FLOAT(traps[i].right.p2.y);
- points[3].X = FIXED_TO_FLOAT(traps[i].right.p1.x);
- points[3].Y = FIXED_TO_FLOAT(traps[i].right.p1.y);
-
- surface->gr->FillPolygon(brush, points, 4);
- //Pen p(Color(255,0,0,0), 1.0f/10.0f);
- //surface->gr->DrawPolygon(&p, points, 4);
- }
-
-#undef FIXED_TO_FLOAT
-
- delete img;
- return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-
-static cairo_int_status_t
-_cairo_win32_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-
-static cairo_int_status_t
-_cairo_win32_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
-
- pixman_box16_t *box;
- int n = pixman_region_num_rects(region);
-
- if (n == 0)
- return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
-
- box = pixman_region_rects(region);
-
- surface->gr->ResetClip();
- for (int i = 0; i < n; ++i) {
- Rect r(box[i].x1, box[i].y1, box[i].x2 - box[i].x1, box[i].y2 - box[i].y1);
- surface->gr->SetClip(r, CombineModeUnion); /* do I need to do replace once and then union? */
- }
-
- return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *box)
-{
- /* SOLID is easy -> SolidBrush
- LINEAR we can only do a gradient from 1 color to another -> LinearGradientBrush
- We should do this if thats all we need, otherwise use software.
- RADIAL we can't really do it. Let it fall back to software I guess. */
-
-
- /* in the case of PATTERN_SOLID, we really just want to create a brush and hand that back... */
- if (pattern->type == CAIRO_PATTERN_SOLID) {
-
- /* ugh, this surface creation code should _really_ live somewhere else */
- cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
- if (src == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- _cairo_surface_init(&src->base, &cairo_win32_surface_backend);
- pattern->source = &src->base;
-
- src->gr = NULL;
- src->brush = new SolidBrush(Color(pattern->color.alpha_short,
- pattern->color.red_short,
- pattern->color.green_short,
- pattern->color.blue_short));
-
-
- return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
- }
-
- else if (pattern->type == CAIRO_PATTERN_LINEAR && pattern->n_stops == 2) {
-
- /* ugh, this surface creation code should _really_ live somewhere else */
- cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
- if (src == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- _cairo_surface_init(&src->base, &cairo_win32_surface_backend);
- pattern->source = &src->base;
-
- src->gr = NULL;
-
- RectF r((float)pattern->u.linear.point0.x,
- (float)pattern->u.linear.point0.y,
- ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16),
- ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16));
-
- src->brush = new LinearGradientBrush(r,
- Color(pattern->stops[0].color_char[3],
- pattern->stops[0].color_char[0],
- pattern->stops[0].color_char[1],
- pattern->stops[0].color_char[2]),
- Color(pattern->stops[1].color_char[3],
- pattern->stops[1].color_char[0],
- pattern->stops[1].color_char[1],
- pattern->stops[1].color_char[2]),
- 90.0, FALSE);
-
- static_cast<LinearGradientBrush*>(src->brush)->TranslateTransform((float)pattern->source_offset.x,
- (float)pattern->source_offset.y);
- return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
- }
-
- else if (pattern->type == CAIRO_PATTERN_RADIAL) {
-#if 0 /* XXX not sure this will work.. do we have to draw with FillPath() in order for this brush to work properly? */
- /* use PathGradientBrush here */
-
- /* ugh, this surface creation code should _really_ live somewhere else */
- cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
- if (src == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- _cairo_surface_init(&src->base, &cairo_win32_surface_backend);
- pattern->source = &src->base;
-
- src->gr = NULL;
-
- PointF center(pattern->u.radial.center1.x, pattern->u.radial.center1.y);
-
- GraphicsPath path;
- path.AddEllipse(0, 0, 140, 70);
-
- // Use the path to construct a brush.
- PathGradientBrush *brush = new PathGradientBrush(&path);
- src->brush = brush;
-
- // Set the color at the center of the path to blue.
- brush->SetCenterColor(Color(50, 100, 0, 255));
-
- // Set the color along the entire boundary of the path to aqua.
- Color colors[] = {Color(255, 0, 255, 255)};
- int count = 1;
- brush->SetSurroundColors(colors, &count);
-
- brush->SetCenterPoint(center);
-
- return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
-#endif
-
- }
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static const cairo_surface_backend_t cairo_win32_surface_backend = {
- _cairo_win32_surface_create_similar,
- _cairo_win32_surface_destroy,
- _cairo_win32_surface_pixels_per_inch,
- _cairo_win32_surface_get_image,
- _cairo_win32_surface_set_image,
- _cairo_win32_surface_set_matrix,
- _cairo_win32_surface_set_filter,
- _cairo_win32_surface_set_repeat,
- _cairo_win32_surface_composite,
- _cairo_win32_surface_fill_rectangles,
- _cairo_win32_surface_composite_trapezoids,
- _cairo_win32_surface_copy_page,
- _cairo_win32_surface_show_page,
- _cairo_win32_surface_set_clip_region,
- _cairo_win32_surface_create_pattern,
-};
diff --git a/src/cairo_glitz_surface.c b/src/cairo_glitz_surface.c
index 69fc82f2e..ee664e1cc 100644
--- a/src/cairo_glitz_surface.c
+++ b/src/cairo_glitz_surface.c
@@ -21,30 +21,12 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * Author: David Reveman <c99drn@cs.umu.se>
+ * Author: David Reveman <davidr@novell.com>
*/
#include "cairoint.h"
#include "cairo-glitz.h"
-#define GLITZ_FIXED_TO_FLOAT(f) \
- (((glitz_float_t) (f)) / 65536)
-
-#define GLITZ_FIXED_LINE_X_TO_FLOAT(line, v) \
- (((glitz_float_t) \
- ((line).p1.x + (cairo_fixed_16_16_t) \
- (((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \
- ((line).p2.x - (line).p1.x)) / \
- ((line).p2.y - (line).p1.y)))) / 65536)
-
-#define GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \
- (((glitz_float_t) \
- ((line).p1.x + (cairo_fixed_16_16_t) \
- (((((line).p2.y - (line).p1.y) - 1) + \
- ((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \
- ((line).p2.x - (line).p1.x))) / \
- ((line).p2.y - (line).p1.y)))) / 65536)
-
void
cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
{
@@ -65,13 +47,11 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
}
typedef struct _cairo_glitz_surface {
- cairo_surface_t base;
-
- glitz_surface_t *surface;
- glitz_format_t *format;
+ cairo_surface_t base;
- cairo_pattern_t pattern;
- cairo_box_t pattern_box;
+ glitz_surface_t *surface;
+ glitz_format_t *format;
+ pixman_region16_t *clip;
} cairo_glitz_surface_t;
static void
@@ -79,11 +59,60 @@ _cairo_glitz_surface_destroy (void *abstract_surface)
{
cairo_glitz_surface_t *surface = abstract_surface;
+ if (surface->clip)
+ {
+ glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
+ pixman_region_destroy (surface->clip);
+ }
+
glitz_surface_destroy (surface->surface);
+ free (surface);
+}
- _cairo_pattern_fini (&surface->pattern);
+static glitz_format_name_t
+_glitz_format (cairo_format_t format)
+{
+ switch (format) {
+ default:
+ case CAIRO_FORMAT_ARGB32:
+ return GLITZ_STANDARD_ARGB32;
+ case CAIRO_FORMAT_RGB24:
+ return GLITZ_STANDARD_RGB24;
+ case CAIRO_FORMAT_A8:
+ return GLITZ_STANDARD_A8;
+ case CAIRO_FORMAT_A1:
+ return GLITZ_STANDARD_A1;
+ }
+}
- free (surface);
+static cairo_surface_t *
+_cairo_glitz_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int draw,
+ int width,
+ int height)
+{
+ cairo_glitz_surface_t *src = abstract_src;
+ cairo_surface_t *crsurface;
+ glitz_drawable_t *drawable;
+ glitz_surface_t *surface;
+ glitz_format_t *gformat;
+
+ drawable = glitz_surface_get_drawable (src->surface);
+
+ gformat = glitz_find_standard_format (drawable, _glitz_format (format));
+ if (!gformat)
+ return NULL;
+
+ surface = glitz_surface_create (drawable, gformat, width, height, 0, NULL);
+ if (!surface)
+ return NULL;
+
+ crsurface = cairo_glitz_surface_create (surface);
+
+ glitz_surface_destroy (surface);
+
+ return crsurface;
}
static double
@@ -92,31 +121,54 @@ _cairo_glitz_surface_pixels_per_inch (void *abstract_surface)
return 96.0;
}
-static cairo_image_surface_t *
-_cairo_glitz_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
+ cairo_rectangle_t *interest,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *rect_out)
{
- cairo_glitz_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
- char *pixels;
- int width, height;
- cairo_format_masks_t format;
- glitz_buffer_t *buffer;
- glitz_pixel_format_t pf;
-
- if (surface->pattern.type != CAIRO_PATTERN_SURFACE) {
- cairo_box_t box;
-
- box.p1.x = box.p1.y = 0;
- box.p2.x = surface->pattern_box.p2.x;
- box.p2.y = surface->pattern_box.p2.y;
-
- return _cairo_pattern_get_image (&surface->pattern, &box);
+ int x1, y1, x2, y2;
+ int width, height;
+ char *pixels;
+ cairo_format_masks_t format;
+ glitz_buffer_t *buffer;
+ glitz_pixel_format_t pf;
+
+ x1 = 0;
+ y1 = 0;
+ x2 = glitz_surface_get_width (surface->surface);
+ y2 = glitz_surface_get_height (surface->surface);
+
+ if (interest)
+ {
+ if (interest->x > x1)
+ x1 = interest->x;
+ if (interest->y > y1)
+ y1 = interest->y;
+ if (interest->x + interest->width < x2)
+ x2 = interest->x + interest->width;
+ if (interest->y + interest->height < y2)
+ y2 = interest->y + interest->height;
+
+ if (x1 >= x2 || y1 >= y2)
+ {
+ *image_out = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
}
+ width = x2 - x1;
+ height = y2 - y1;
- width = glitz_surface_get_width (surface->surface);
- height = glitz_surface_get_height (surface->surface);
-
+ if (rect_out)
+ {
+ rect_out->x = x1;
+ rect_out->y = y1;
+ rect_out->width = width;
+ rect_out->height = height;
+ }
+
if (surface->format->type == GLITZ_FORMAT_TYPE_COLOR) {
if (surface->format->color.red_size > 0) {
format.bpp = 32;
@@ -149,21 +201,24 @@ _cairo_glitz_surface_get_image (void *abstract_surface)
pf.masks.blue_mask = format.blue_mask;
pf.xoffset = 0;
pf.skip_lines = 0;
+
+ /* XXX: we should eventually return images with negative stride,
+ need to verify that libpixman have no problem with this first. */
pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4;
pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
pixels = malloc (height * pf.bytes_per_line);
if (!pixels)
- return NULL;
+ return CAIRO_STATUS_NO_MEMORY;
buffer = glitz_buffer_create_for_data (pixels);
if (!buffer) {
free (pixels);
- return NULL;
+ return CAIRO_STATUS_NO_MEMORY;
}
glitz_get_pixels (surface->surface,
- 0, 0,
+ x1, y1,
width, height,
&pf,
buffer);
@@ -175,27 +230,38 @@ _cairo_glitz_surface_get_image (void *abstract_surface)
&format,
width, height,
pf.bytes_per_line);
-
+
+ if (!image)
+ {
+ free (pixels);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
_cairo_image_surface_assume_ownership_of_data (image);
_cairo_image_surface_set_repeat (image, surface->base.repeat);
_cairo_image_surface_set_matrix (image, &(surface->base.matrix));
- return image;
+ *image_out = image;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_glitz_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+_cairo_glitz_surface_set_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ int x_dst,
+ int y_dst)
{
cairo_glitz_surface_t *surface = abstract_surface;
- glitz_buffer_t *buffer;
- glitz_pixel_format_t pf;
- pixman_format_t *format;
- int am, rm, gm, bm;
+ glitz_buffer_t *buffer;
+ glitz_pixel_format_t pf;
+ pixman_format_t *format;
+ int am, rm, gm, bm;
+ char *data;
format = pixman_image_get_format (image->pixman_image);
- if (format == NULL)
+ if (!format)
return CAIRO_STATUS_NO_MEMORY;
pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm);
@@ -206,15 +272,27 @@ _cairo_glitz_surface_set_image (void *abstract_surface,
pf.masks.blue_mask = bm;
pf.xoffset = 0;
pf.skip_lines = 0;
- pf.bytes_per_line = image->stride;
- pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
- buffer = glitz_buffer_create_for_data (image->data);
+ /* check for negative stride */
+ if (image->stride < 0)
+ {
+ pf.bytes_per_line = -image->stride;
+ pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
+ data = (char *) image->data + image->stride * (image->height - 1);
+ }
+ else
+ {
+ pf.bytes_per_line = image->stride;
+ pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
+ data = (char *) image->data;
+ }
+
+ buffer = glitz_buffer_create_for_data (data);
if (!buffer)
return CAIRO_STATUS_NO_MEMORY;
glitz_set_pixels (surface->surface,
- 0, 0,
+ x_dst, y_dst,
image->width, image->height,
&pf,
buffer);
@@ -225,63 +303,118 @@ _cairo_glitz_surface_set_image (void *abstract_surface,
}
static cairo_status_t
-_cairo_glitz_surface_set_matrix (void *abstract_surface,
- cairo_matrix_t *matrix)
+_cairo_glitz_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
cairo_glitz_surface_t *surface = abstract_surface;
- glitz_transform_t transform;
- transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
+ *image_extra = NULL;
+
+ return _cairo_glitz_surface_get_image (surface, NULL, image_out, NULL);
+}
- transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
+static void
+_cairo_glitz_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ cairo_surface_destroy (&image->base);
+}
- transform.matrix[2][0] = 0;
- transform.matrix[2][1] = 0;
- transform.matrix[2][2] = 1 << 16;
+static cairo_status_t
+_cairo_glitz_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect_out,
+ void **image_extra)
+{
+ cairo_glitz_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
- glitz_surface_set_transform (surface->surface, &transform);
+ status = _cairo_glitz_surface_get_image (surface, interest_rect, &image,
+ image_rect_out);
+ if (status)
+ return status;
- return CAIRO_STATUS_SUCCESS;
+ *image_out = image;
+ *image_extra = NULL;
+
+ return status;
}
+static void
+_cairo_glitz_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+ cairo_glitz_surface_t *surface = abstract_surface;
+
+ _cairo_glitz_surface_set_image (surface, image,
+ image_rect->x, image_rect->y);
+
+ cairo_surface_destroy (&image->base);
+}
+
+
static cairo_status_t
-_cairo_glitz_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
+_cairo_glitz_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
cairo_glitz_surface_t *surface = abstract_surface;
- glitz_filter_t glitz_filter;
+ cairo_glitz_surface_t *clone;
- switch (filter) {
- case CAIRO_FILTER_FAST:
- case CAIRO_FILTER_NEAREST:
- glitz_filter = GLITZ_FILTER_NEAREST;
- break;
- case CAIRO_FILTER_GOOD:
- case CAIRO_FILTER_BEST:
- case CAIRO_FILTER_BILINEAR:
- default:
- glitz_filter = GLITZ_FILTER_BILINEAR;
- break;
+ if (src->backend == surface->base.backend)
+ {
+ *clone_out = src;
+ cairo_surface_reference (src);
+
+ return CAIRO_STATUS_SUCCESS;
}
+ else if (_cairo_surface_is_image (src))
+ {
+ cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
+
+ clone = (cairo_glitz_surface_t *)
+ _cairo_glitz_surface_create_similar (surface, image_src->format, 0,
+ image_src->width,
+ image_src->height);
+ if (!clone)
+ return CAIRO_STATUS_NO_MEMORY;
- glitz_surface_set_filter (surface->surface, glitz_filter, NULL, 0);
+ _cairo_glitz_surface_set_image (clone, image_src, 0, 0);
+
+ *clone_out = &clone->base;
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_status_t
-_cairo_glitz_surface_set_repeat (void *abstract_surface, int repeat)
+static void
+_cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface,
+ cairo_matrix_t *matrix)
{
- cairo_glitz_surface_t *surface = abstract_surface;
+ glitz_transform_t transform;
+
+ transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
+ transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
+ transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
- glitz_surface_set_fill (surface->surface,
- (repeat)? GLITZ_FILL_REPEAT:
- GLITZ_FILL_TRANSPARENT);
+ transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
+ transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
+ transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
- return CAIRO_STATUS_SUCCESS;
+ transform.matrix[2][0] = 0;
+ transform.matrix[2][1] = 0;
+ transform.matrix[2][2] = 1 << 16;
+
+ glitz_surface_set_transform (surface->surface, &transform);
}
static glitz_operator_t
@@ -318,32 +451,6 @@ _glitz_operator (cairo_operator_t op)
}
}
-static glitz_surface_t *
-_glitz_surface_create_solid (glitz_surface_t *other,
- glitz_format_name_t format_name,
- glitz_color_t *color)
-{
- glitz_drawable_t *drawable;
- glitz_format_t *format;
- glitz_surface_t *surface;
-
- drawable = glitz_surface_get_drawable (other);
-
- format = glitz_find_standard_format (drawable, format_name);
- if (format == NULL)
- return NULL;
-
- surface = glitz_surface_create (drawable, format, 1, 1);
- if (surface == NULL)
- return NULL;
-
- glitz_set_rectangle (surface, color, 0, 0, 1, 1);
-
- glitz_surface_set_fill (surface, GLITZ_FILL_REPEAT);
-
- return surface;
-}
-
static glitz_status_t
_glitz_ensure_target (glitz_surface_t *surface)
{
@@ -355,7 +462,6 @@ _glitz_ensure_target (glitz_surface_t *surface)
glitz_drawable_format_t templ;
glitz_format_t *format;
glitz_drawable_t *pbuffer;
- glitz_pbuffer_attributes_t attributes;
unsigned long mask;
int i;
@@ -397,21 +503,13 @@ _glitz_ensure_target (glitz_surface_t *surface)
if (!dformat)
return CAIRO_INT_STATUS_UNSUPPORTED;
- attributes.width = glitz_surface_get_width (surface);
- attributes.height = glitz_surface_get_height (surface);
- mask = GLITZ_PBUFFER_WIDTH_MASK | GLITZ_PBUFFER_HEIGHT_MASK;
-
- pbuffer = glitz_create_pbuffer_drawable (drawable, dformat,
- &attributes, mask);
+ pbuffer =
+ glitz_create_pbuffer_drawable (drawable, dformat,
+ glitz_surface_get_width (surface),
+ glitz_surface_get_height (surface));
if (!pbuffer)
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (glitz_drawable_get_width (pbuffer) < attributes.width ||
- glitz_drawable_get_height (pbuffer) < attributes.height) {
- glitz_drawable_destroy (pbuffer);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
glitz_surface_attach (surface, pbuffer,
GLITZ_DRAWABLE_BUFFER_FRONT_COLOR,
0, 0);
@@ -422,388 +520,711 @@ _glitz_ensure_target (glitz_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
}
-static glitz_format_name_t
-_glitz_format (cairo_format_t format)
+typedef struct _cairo_glitz_surface_attributes {
+ cairo_surface_attributes_t base;
+
+ glitz_fill_t fill;
+ glitz_filter_t filter;
+ glitz_fixed16_16_t *params;
+ int n_params;
+ cairo_bool_t acquired;
+} cairo_glitz_surface_attributes_t;
+
+static cairo_int_status_t
+_cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
+ cairo_glitz_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glitz_surface_t **surface_out,
+ cairo_glitz_surface_attributes_t *attr)
{
- switch (format) {
+ cairo_glitz_surface_t *src = NULL;
+
+ attr->acquired = FALSE;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ cairo_gradient_pattern_t *gradient =
+ (cairo_gradient_pattern_t *) pattern;
+ glitz_drawable_t *drawable;
+ glitz_fixed16_16_t *params;
+ int n_params;
+ int i;
+ unsigned short alpha;
+
+ /* XXX: the current color gradient acceleration provided by glitz is
+ * experimental, it's been proven inappropriate in a number of ways,
+ * most importantly, it's currently implemented as filters and
+ * gradients are not filters. eventually, it will be replaced with
+ * something more appropriate.
+ */
+
+ if (gradient->n_stops < 2)
+ break;
+
+ /* glitz doesn't support inner and outer circle with different
+ center points. */
+ if (pattern->type == CAIRO_PATTERN_RADIAL)
+ {
+ cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
+
+ if (grad->center0.x != grad->center1.x ||
+ grad->center0.y != grad->center1.y)
+ break;
+ }
+
+ drawable = glitz_surface_get_drawable (dst->surface);
+ if (!(glitz_drawable_get_features (drawable) &
+ GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
+ break;
+
+ if (pattern->filter != CAIRO_FILTER_BILINEAR &&
+ pattern->filter != CAIRO_FILTER_GOOD &&
+ pattern->filter != CAIRO_FILTER_BEST)
+ break;
+
+ alpha = (gradient->stops[0].color.alpha * pattern->alpha) * 0xffff;
+ for (i = 1; i < gradient->n_stops; i++)
+ {
+ unsigned short a;
+
+ a = (gradient->stops[i].color.alpha * pattern->alpha) * 0xffff;
+ if (a != alpha)
+ break;
+ }
+
+ /* we can't have color stops with different alpha as gradient color
+ interpolation should be done to unpremultiplied colors. */
+ if (i < gradient->n_stops)
+ break;
+
+ n_params = gradient->n_stops * 3 + 4;
+
+ params = malloc (sizeof (glitz_fixed16_16_t) * n_params);
+ if (!params)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ src = (cairo_glitz_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ CAIRO_FORMAT_ARGB32, 0,
+ gradient->n_stops, 1);
+ if (!src)
+ {
+ free (params);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < gradient->n_stops; i++) {
+ glitz_color_t color;
+
+ color.red = gradient->stops[i].color.red * alpha;
+ color.green = gradient->stops[i].color.green * alpha;
+ color.blue = gradient->stops[i].color.blue * alpha;
+ color.alpha = alpha;
+
+ glitz_set_rectangle (src->surface, &color, i, 0, 1, 1);
+
+ params[4 + 3 * i] = gradient->stops[i].offset;
+ params[5 + 3 * i] = i << 16;
+ params[6 + 3 * i] = 0;
+ }
+
+ if (pattern->type == CAIRO_PATTERN_LINEAR)
+ {
+ cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern;
+
+ params[0] = _cairo_fixed_from_double (grad->point0.x);
+ params[1] = _cairo_fixed_from_double (grad->point0.y);
+ params[2] = _cairo_fixed_from_double (grad->point1.x);
+ params[3] = _cairo_fixed_from_double (grad->point1.y);
+ attr->filter = GLITZ_FILTER_LINEAR_GRADIENT;
+ }
+ else
+ {
+ cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
+
+ params[0] = _cairo_fixed_from_double (grad->center0.x);
+ params[1] = _cairo_fixed_from_double (grad->center0.y);
+ params[2] = _cairo_fixed_from_double (grad->radius0);
+ params[3] = _cairo_fixed_from_double (grad->radius1);
+ attr->filter = GLITZ_FILTER_RADIAL_GRADIENT;
+ }
+
+ switch (pattern->extend) {
+ case CAIRO_EXTEND_NONE:
+ attr->fill = GLITZ_FILL_NEAREST;
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ attr->fill = GLITZ_FILL_REPEAT;
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ attr->fill = GLITZ_FILL_REFLECT;
+ break;
+ }
+
+ attr->params = params;
+ attr->n_params = n_params;
+ attr->base.matrix = pattern->matrix;
+ attr->base.x_offset = 0;
+ attr->base.y_offset = 0;
+ } break;
default:
- case CAIRO_FORMAT_ARGB32:
- return GLITZ_STANDARD_ARGB32;
- case CAIRO_FORMAT_RGB24:
- return GLITZ_STANDARD_RGB24;
- case CAIRO_FORMAT_A8:
- return GLITZ_STANDARD_A8;
- case CAIRO_FORMAT_A1:
- return GLITZ_STANDARD_A1;
+ break;
}
-}
-static cairo_surface_t *
-_cairo_glitz_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int draw,
- int width,
- int height)
-{
- cairo_glitz_surface_t *src = abstract_src;
- cairo_surface_t *crsurface;
- glitz_drawable_t *drawable;
- glitz_surface_t *surface;
- glitz_format_t *gformat;
+ if (!src)
+ {
+ cairo_int_status_t status;
- drawable = glitz_surface_get_drawable (src->surface);
-
- gformat = glitz_find_standard_format (drawable, _glitz_format (format));
- if (gformat == NULL)
- return NULL;
-
- surface = glitz_surface_create (drawable, gformat, width, height);
- if (surface == NULL)
- return NULL;
+ status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ x, y, width, height,
+ (cairo_surface_t **) &src,
+ &attr->base);
+ if (status)
+ return status;
+
+ if (src)
+ {
+ switch (attr->base.extend) {
+ case CAIRO_EXTEND_NONE:
+ attr->fill = GLITZ_FILL_TRANSPARENT;
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ attr->fill = GLITZ_FILL_REPEAT;
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ attr->fill = GLITZ_FILL_REFLECT;
+ break;
+ }
- crsurface = cairo_glitz_surface_create (surface);
-
- glitz_surface_destroy (surface);
+ switch (attr->base.filter) {
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ attr->filter = GLITZ_FILTER_NEAREST;
+ break;
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_BILINEAR:
+ default:
+ attr->filter = GLITZ_FILTER_BILINEAR;
+ break;
+ }
+
+ attr->params = NULL;
+ attr->n_params = 0;
+ attr->acquired = TRUE;
+ }
+ }
- return crsurface;
+ *surface_out = src;
+
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_glitz_surface_t *
-_cairo_glitz_surface_clone_similar (cairo_glitz_surface_t *templ,
- cairo_surface_t *src,
- cairo_format_t format)
+static void
+_cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst,
+ cairo_glitz_surface_t *surface,
+ cairo_glitz_surface_attributes_t *attr)
{
- cairo_glitz_surface_t *clone;
- cairo_image_surface_t *src_image;
+ if (attr->acquired)
+ _cairo_pattern_release_surface (&dst->base, &surface->base,
+ &attr->base);
+ else
+ _cairo_glitz_surface_destroy (surface);
+}
- src_image = _cairo_surface_get_image (src);
+static cairo_int_status_t
+_cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
+ cairo_pattern_t *mask,
+ cairo_glitz_surface_t *dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glitz_surface_t **src_out,
+ cairo_glitz_surface_t **mask_out,
+ cairo_glitz_surface_attributes_t *sattr,
+ cairo_glitz_surface_attributes_t *mattr)
+{
+ cairo_int_status_t status;
+ cairo_pattern_union_t tmp;
+ cairo_bool_t src_opaque, mask_opaque;
+ double src_alpha, mask_alpha;
- clone = (cairo_glitz_surface_t *)
- _cairo_glitz_surface_create_similar (templ, format, 0,
- src_image->width,
- src_image->height);
- if (clone == NULL)
- return NULL;
-
- _cairo_glitz_surface_set_filter (clone, cairo_surface_get_filter (src));
+ src_opaque = _cairo_pattern_is_opaque (src);
+ mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
- _cairo_glitz_surface_set_image (clone, src_image);
-
- _cairo_glitz_surface_set_matrix (clone, &(src_image->base.matrix));
+ /* For surface patterns, we move any translucency from src->alpha
+ * to mask->alpha so we can use the source unchanged. Otherwise we
+ * move the translucency from mask->alpha to src->alpha so that
+ * we can drop the mask if possible.
+ */
+ if (src->type == CAIRO_PATTERN_SURFACE)
+ {
+ if (mask) {
+ mask_opaque = mask_opaque && src_opaque;
+ mask_alpha = mask->alpha * src->alpha;
+ } else {
+ mask_opaque = src_opaque;
+ mask_alpha = src->alpha;
+ }
+
+ src_alpha = 1.0;
+ src_opaque = TRUE;
+ }
+ else
+ {
+ if (mask)
+ {
+ src_opaque = mask_opaque && src_opaque;
+ src_alpha = mask->alpha * src->alpha;
+ /* FIXME: This needs changing when we support RENDER
+ * style 4-channel masks.
+ */
+ if (mask->type == CAIRO_PATTERN_SOLID)
+ mask = NULL;
+ } else
+ src_alpha = src->alpha;
+
+ mask_alpha = 1.0;
+ mask_opaque = TRUE;
+ }
+
+ _cairo_pattern_init_copy (&tmp.base, src);
+ _cairo_pattern_set_alpha (&tmp.base, src_alpha);
+
+ status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
+ src_x, src_y,
+ width, height,
+ src_out, sattr);
- cairo_surface_destroy (&src_image->base);
+ _cairo_pattern_fini (&tmp.base);
- return clone;
-}
+ if (status)
+ return status;
-static cairo_int_status_t
-_glitz_composite (glitz_operator_t op,
- glitz_surface_t *src,
- glitz_surface_t *mask,
- glitz_surface_t *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- int width,
- int height,
- glitz_buffer_t *geometry,
- glitz_geometry_format_t *format)
-{
- if (_glitz_ensure_target (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (mask || !mask_opaque)
+ {
+ if (mask)
+ _cairo_pattern_init_copy (&tmp.base, mask);
+ else
+ _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
- if (glitz_surface_get_status (dst))
- return CAIRO_STATUS_NO_TARGET_SURFACE;
-
- glitz_set_geometry (dst,
- 0, 0,
- format, geometry);
-
- glitz_composite (op,
- src,
- mask,
- dst,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
-
- glitz_set_geometry (dst, 0, 0, NULL, NULL);
+ _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
+
+ status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
+ mask_x, mask_y,
+ width, height,
+ mask_out, mattr);
+
+ _cairo_pattern_fini (&tmp.base);
- if (glitz_surface_get_status (dst) == GLITZ_STATUS_NOT_SUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (status)
+ {
+ _cairo_glitz_pattern_release_surface (dst, *src_out, sattr);
+ return status;
+ }
+ }
+ else
+ {
+ *mask_out = NULL;
+ }
return CAIRO_STATUS_SUCCESS;
}
+static void
+_cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface,
+ cairo_glitz_surface_attributes_t *a)
+{
+ _cairo_glitz_surface_set_matrix (surface, &a->base.matrix);
+ glitz_surface_set_fill (surface->surface, a->fill);
+ glitz_surface_set_filter (surface->surface, a->filter,
+ a->params, a->n_params);
+}
+
static cairo_int_status_t
_cairo_glitz_surface_composite (cairo_operator_t op,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
+ cairo_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
{
- cairo_glitz_surface_t *dst = abstract_dst;
- cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src;
- cairo_glitz_surface_t *mask = (cairo_glitz_surface_t *) generic_mask;
- cairo_glitz_surface_t *src_clone = NULL;
- cairo_glitz_surface_t *mask_clone = NULL;
- cairo_int_status_t status;
+ cairo_glitz_surface_attributes_t src_attr, mask_attr;
+ cairo_glitz_surface_t *dst = abstract_dst;
+ cairo_glitz_surface_t *src;
+ cairo_glitz_surface_t *mask;
+ cairo_int_status_t status;
if (op == CAIRO_OPERATOR_SATURATE)
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (generic_src->backend != dst->base.backend) {
- src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src,
- CAIRO_FORMAT_ARGB32);
- if (!src_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern,
+ dst,
+ src_x, src_y,
+ mask_x, mask_y,
+ width, height,
+ &src, &mask,
+ &src_attr, &mask_attr);
+ if (status)
+ return status;
+
+ _cairo_glitz_surface_set_attributes (src, &src_attr);
+ if (mask)
+ {
+ _cairo_glitz_surface_set_attributes (mask, &mask_attr);
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ mask->surface,
+ dst->surface,
+ src_x + src_attr.base.x_offset,
+ src_y + src_attr.base.y_offset,
+ mask_x + mask_attr.base.x_offset,
+ mask_y + mask_attr.base.y_offset,
+ dst_x, dst_y,
+ width, height);
- src = src_clone;
- }
-
- if (generic_mask && (generic_mask->backend != dst->base.backend)) {
- mask_clone = _cairo_glitz_surface_clone_similar (dst, generic_mask,
- CAIRO_FORMAT_A8);
- if (!mask_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (mask_attr.n_params)
+ free (mask_attr.params);
- mask = mask_clone;
+ _cairo_glitz_pattern_release_surface (dst, mask, &mask_attr);
+ }
+ else
+ {
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ NULL,
+ dst->surface,
+ src_x + src_attr.base.x_offset,
+ src_y + src_attr.base.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
}
- status = _glitz_composite (_glitz_operator (op),
- src->surface,
- (mask)? mask->surface: NULL,
- dst->surface,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height,
- NULL, NULL);
-
- if (src_clone)
- cairo_surface_destroy (&src_clone->base);
-
- if (mask_clone)
- cairo_surface_destroy (&mask_clone->base);
+ if (src_attr.n_params)
+ free (src_attr.params);
- return status;
+ _cairo_glitz_pattern_release_surface (dst, src, &src_attr);
+
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
-_cairo_glitz_surface_fill_rectangles (void *abstract_dst,
- cairo_operator_t op,
+_cairo_glitz_surface_fill_rectangles (void *abstract_dst,
+ cairo_operator_t op,
const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int n_rects)
+ cairo_rectangle_t *rects,
+ int n_rects)
{
cairo_glitz_surface_t *dst = abstract_dst;
- glitz_color_t glitz_color;
- if (op == CAIRO_OPERATOR_SATURATE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- glitz_color.red = color->red_short;
- glitz_color.green = color->green_short;
- glitz_color.blue = color->blue_short;
- glitz_color.alpha = color->alpha_short;
+ if (op == CAIRO_OPERATOR_SRC)
+ {
+ glitz_color_t glitz_color;
+
+ glitz_color.red = color->red_short;
+ glitz_color.green = color->green_short;
+ glitz_color.blue = color->blue_short;
+ glitz_color.alpha = color->alpha_short;
+
+ if (glitz_surface_get_width (dst->surface) != 1 ||
+ glitz_surface_get_height (dst->surface) != 1)
+ _glitz_ensure_target (dst->surface);
- if (op != CAIRO_OPERATOR_SRC) {
- glitz_surface_t *solid;
- glitz_float_t *vertices;
- glitz_buffer_t *buffer;
- glitz_geometry_format_t gf;
- cairo_int_status_t status;
- int width, height;
- void *data;
+ glitz_set_rectangles (dst->surface, &glitz_color,
+ (glitz_rectangle_t *) rects, n_rects);
+ }
+ else
+ {
+ cairo_glitz_surface_t *src;
- gf.mode = GLITZ_GEOMETRY_MODE_DIRECT;
- gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_SHARP;
- gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS;
- gf.type = GLITZ_DATA_TYPE_FLOAT;
- gf.first = 0;
- gf.count = n_rects * 4;
-
- data = malloc (n_rects * 8 * sizeof (glitz_float_t));
- if (!data)
- return CAIRO_STATUS_NO_MEMORY;
-
- buffer = glitz_buffer_create_for_data (data);
- if (buffer == NULL) {
- free (data);
- return CAIRO_STATUS_NO_MEMORY;
- }
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- width = height = 0;
- vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY);
- for (; n_rects; rects++, n_rects--) {
- *vertices++ = (glitz_float_t) rects->x;
- *vertices++ = (glitz_float_t) rects->y;
- *vertices++ = (glitz_float_t) (rects->x + rects->width);
- *vertices++ = (glitz_float_t) rects->y;
- *vertices++ = (glitz_float_t) (rects->x + rects->width);
- *vertices++ = (glitz_float_t) (rects->y + rects->height);
- *vertices++ = (glitz_float_t) rects->x;
- *vertices++ = (glitz_float_t) (rects->y + rects->height);
-
- if ((rects->x + rects->width) > width)
- width = rects->x + rects->width;
-
- if ((rects->y + rects->height) > height)
- height = rects->y + rects->height;
- }
- glitz_buffer_unmap (buffer);
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- solid = _glitz_surface_create_solid (dst->surface,
- GLITZ_STANDARD_ARGB32,
- &glitz_color);
- if (solid == NULL)
+ src = (cairo_glitz_surface_t *)
+ _cairo_surface_create_similar_solid (&dst->base,
+ CAIRO_FORMAT_ARGB32, 1, 1,
+ (cairo_color_t *) color);
+ if (!src)
return CAIRO_STATUS_NO_MEMORY;
-
- status = _glitz_composite (_glitz_operator (op),
- solid,
- NULL,
- dst->surface,
- 0, 0,
- 0, 0,
- 0, 0,
- width, height,
- buffer, &gf);
-
- glitz_surface_destroy (solid);
- glitz_buffer_destroy (buffer);
- free (data);
-
- return status;
- } else {
- if (glitz_surface_get_width (dst->surface) != 1 ||
- glitz_surface_get_height (dst->surface) != 1) {
- if (_glitz_ensure_target (dst->surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ while (n_rects--)
+ {
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ NULL,
+ dst->surface,
+ 0, 0,
+ 0, 0,
+ rects->x, rects->y,
+ rects->width, rects->height);
+ rects++;
}
- glitz_set_rectangles (dst->surface, &glitz_color,
- (glitz_rectangle_t *) rects, n_rects);
+ cairo_surface_destroy (&src->base);
}
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
-_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
- cairo_surface_t *generic_src,
- void *abstract_dst,
- int x_src,
- int y_src,
+_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
+ cairo_pattern_t *pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
- int n_traps)
+ int n_traps)
{
- cairo_glitz_surface_t *dst = abstract_dst;
- cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src;
- glitz_surface_t *mask = NULL;
- glitz_float_t *vertices;
- glitz_buffer_t *buffer;
- glitz_geometry_format_t gf;
- cairo_int_status_t status;
- int x_dst, y_dst, x_rel, y_rel, width, height;
- void *data;
+ cairo_glitz_surface_attributes_t attributes;
+ cairo_glitz_surface_t *dst = abstract_dst;
+ cairo_glitz_surface_t *src;
+ cairo_glitz_surface_t *mask = NULL;
+ glitz_buffer_t *buffer = NULL;
+ void *data = NULL;
+ cairo_int_status_t status;
+ unsigned short alpha;
if (op == CAIRO_OPERATOR_SATURATE)
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (generic_src->backend != dst->base.backend)
+ if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
- gf.mode = GLITZ_GEOMETRY_MODE_DIRECT;
- gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_GOOD_SMOOTH;
- gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS;
- gf.type = GLITZ_DATA_TYPE_FLOAT;
- gf.first = 0;
- gf.count = n_traps * 4;
+ if (pattern->type == CAIRO_PATTERN_SURFACE)
+ {
+ cairo_pattern_union_t tmp;
- data = malloc (n_traps * 8 * sizeof (glitz_float_t));
- if (!data)
- return CAIRO_STATUS_NO_MEMORY;
-
- buffer = glitz_buffer_create_for_data (data);
- if (buffer == NULL) {
- free (data);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- x_dst = traps[0].left.p1.x >> 16;
- y_dst = traps[0].left.p1.y >> 16;
+ _cairo_pattern_init_copy (&tmp.base, pattern);
+ _cairo_pattern_set_alpha (&tmp.base, 1.0);
- vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY);
- for (; n_traps; traps++, n_traps--) {
- glitz_float_t top, bottom;
+ status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
+ src_x, src_y,
+ width, height,
+ &src, &attributes);
- top = GLITZ_FIXED_TO_FLOAT (traps->top);
- bottom = GLITZ_FIXED_TO_FLOAT (traps->bottom);
+ _cairo_pattern_fini (&tmp.base);
- *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->top);
- *vertices++ = top;
- *vertices++ =
- GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->top);
- *vertices++ = top;
- *vertices++ =
- GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->bottom);
- *vertices++ = bottom;
- *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->bottom);
- *vertices++ = bottom;
+ alpha = pattern->alpha * 0xffff;
}
- glitz_buffer_unmap (buffer);
+ else
+ {
+ status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
+ src_x, src_y,
+ width, height,
+ &src, &attributes);
+ alpha = 0xffff;
+ }
+
+ if (status)
+ return status;
+
+ if (op == CAIRO_OPERATOR_ADD || n_traps <= 1)
+ {
+ static glitz_color_t clear_black = { 0, 0, 0, 0 };
+ glitz_color_t color;
+ glitz_geometry_format_t format;
+ int n_trap_added;
+ int offset = 0;
+ int data_size = 0;
+ int size = 30 * n_traps; /* just a guess */
+
+ format.vertex.primitive = GLITZ_PRIMITIVE_QUADS;
+ format.vertex.type = GLITZ_DATA_TYPE_FLOAT;
+ format.vertex.bytes_per_vertex = 3 * sizeof (glitz_float_t);
+ format.vertex.attributes = GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK;
+ format.vertex.mask.type = GLITZ_DATA_TYPE_FLOAT;
+ format.vertex.mask.size = GLITZ_COORDINATE_SIZE_X;
+ format.vertex.mask.offset = 2 * sizeof (glitz_float_t);
+
+ mask = (cairo_glitz_surface_t *)
+ _cairo_glitz_surface_create_similar (&dst->base,
+ CAIRO_FORMAT_A8, 0,
+ 2, 1);
+ if (!mask)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ color.red = color.green = color.blue = color.alpha = alpha;
- if ((src->pattern.type == CAIRO_PATTERN_SURFACE) &&
- (src->pattern.color.alpha != 1.0)) {
- glitz_color_t color;
+ glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1);
+ glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1);
+
+ glitz_surface_set_fill (mask->surface, GLITZ_FILL_NEAREST);
+ glitz_surface_set_filter (mask->surface,
+ GLITZ_FILTER_BILINEAR,
+ NULL, 0);
+
+ size *= format.vertex.bytes_per_vertex;
- color.red = color.green = color.blue = 0;
- color.alpha = src->pattern.color.alpha_short;
+ while (n_traps)
+ {
+ if (data_size < size)
+ {
+ data_size = size;
+ data = realloc (data, data_size);
+ if (!data)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src,
+ &attributes);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ if (buffer)
+ glitz_buffer_destroy (buffer);
+
+ buffer = glitz_buffer_create_for_data (data);
+ if (!buffer) {
+ free (data);
+ _cairo_glitz_pattern_release_surface (dst, src,
+ &attributes);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+ }
- mask = _glitz_surface_create_solid (dst->surface,
- GLITZ_STANDARD_A8,
- &color);
+ offset +=
+ glitz_add_trapezoids (buffer,
+ offset, size - offset,
+ format.vertex.type, mask->surface,
+ (glitz_trapezoid_t *) traps, n_traps,
+ &n_trap_added);
+
+ n_traps -= n_trap_added;
+ traps += n_trap_added;
+ size *= 2;
+ }
+
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_VERTEX,
+ &format, buffer);
+ glitz_set_array (dst->surface, 0, 3,
+ offset / format.vertex.bytes_per_vertex,
+ 0, 0);
}
+ else
+ {
+ cairo_image_surface_t *image;
+ char *ptr;
+ int stride;
+
+ stride = (width + 3) & -4;
+ data = malloc (stride * height);
+ if (!data)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ memset (data, 0, stride * height);
- x_rel = (src->pattern_box.p1.x >> 16) + x_src - x_dst;
- y_rel = (src->pattern_box.p1.y >> 16) + y_src - y_dst;
+ /* using negative stride */
+ ptr = (char *) data + stride * (height - 1);
+
+ image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (ptr,
+ CAIRO_FORMAT_A8,
+ width, height,
+ -stride);
+ if (!image)
+ {
+ cairo_surface_destroy (&src->base);
+ free (data);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
- x_dst = src->pattern_box.p1.x >> 16;
- y_dst = src->pattern_box.p1.y >> 16;
+ pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
+ (pixman_trapezoid_t *) traps, n_traps);
+
+ if (alpha != 0xffff)
+ {
+ pixman_color_t color;
+
+ color.red = color.green = color.blue = color.alpha = alpha;
+
+ pixman_fill_rectangle (PIXMAN_OPERATOR_IN,
+ image->pixman_image,
+ &color,
+ 0, 0, width, height);
+ }
+
+ mask = (cairo_glitz_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ CAIRO_FORMAT_A8, 0,
+ width, height);
+ if (!mask)
+ {
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+ free (data);
+ cairo_surface_destroy (&image->base);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ _cairo_glitz_surface_set_image (mask, image, 0, 0);
+ }
+
+ _cairo_glitz_surface_set_attributes (src, &attributes);
- width = ((src->pattern_box.p2.x + 65535) >> 16) -
- (src->pattern_box.p1.x >> 16);
- height = ((src->pattern_box.p2.y + 65535) >> 16) -
- (src->pattern_box.p1.y >> 16);
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ mask->surface,
+ dst->surface,
+ src_x + attributes.base.x_offset,
+ src_y + attributes.base.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+
+ if (attributes.n_params)
+ free (attributes.params);
+
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_NONE,
+ NULL, NULL);
+
+ if (buffer)
+ glitz_buffer_destroy (buffer);
- status = _glitz_composite (_glitz_operator (op),
- src->surface,
- mask,
- dst->surface,
- x_rel, y_rel,
- 0, 0,
- x_dst, y_dst,
- width, height,
- buffer, &gf);
+ free (data);
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
if (mask)
- glitz_surface_destroy (mask);
+ cairo_surface_destroy (&mask->base);
- glitz_buffer_destroy (buffer);
- free (data);
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@@ -819,173 +1240,56 @@ _cairo_glitz_surface_show_page (void *abstract_surface)
}
static cairo_int_status_t
-_cairo_glitz_surface_create_pattern (void *abstract_dst,
- cairo_pattern_t *pattern,
- cairo_box_t *box)
+_cairo_glitz_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
{
- cairo_glitz_surface_t *dst = abstract_dst;
- cairo_surface_t *generic_src = NULL;
- cairo_image_surface_t *image = NULL;
- cairo_glitz_surface_t *src;
-
- switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
- generic_src =
- _cairo_surface_create_similar_solid (abstract_dst,
- CAIRO_FORMAT_ARGB32,
- 1, 1,
- &pattern->color);
- if (generic_src)
- cairo_surface_set_repeat (generic_src, 1);
- break;
- case CAIRO_PATTERN_RADIAL:
- /* glitz doesn't support inner and outer circle with different
- center points. */
- if (pattern->u.radial.center0.x != pattern->u.radial.center1.x ||
- pattern->u.radial.center0.y != pattern->u.radial.center1.y)
- break;
- /* fall-through */
- case CAIRO_PATTERN_LINEAR: {
- glitz_drawable_t *drawable;
- glitz_fixed16_16_t *params;
- int i, n_params;
-
- drawable = glitz_surface_get_drawable (dst->surface);
- if (!(glitz_drawable_get_features (drawable) &
- GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
- break;
-
- if (pattern->filter != CAIRO_FILTER_BILINEAR)
- break;
-
- n_params = pattern->n_stops * 3 + 4;
-
- params = malloc (sizeof (glitz_fixed16_16_t) * n_params);
- if (params == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- generic_src =
- _cairo_glitz_surface_create_similar (abstract_dst,
- CAIRO_FORMAT_ARGB32, 0,
- pattern->n_stops, 1);
- if (generic_src == NULL) {
- free (params);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- src = (cairo_glitz_surface_t *) generic_src;
-
- for (i = 0; i < pattern->n_stops; i++) {
- glitz_color_t color;
+ cairo_glitz_surface_t *surface = abstract_surface;
- color.alpha = pattern->stops[i].color_char[3];
- color.red = pattern->stops[i].color_char[0] * color.alpha;
- color.green = pattern->stops[i].color_char[1] * color.alpha;
- color.blue = pattern->stops[i].color_char[2] * color.alpha;
- color.alpha *= 256;
+ if (region)
+ {
+ glitz_box_t *box;
+ int n;
- glitz_set_rectangle (src->surface, &color, i, 0, 1, 1);
-
- params[4 + 3 * i] = pattern->stops[i].offset;
- params[5 + 3 * i] = i << 16;
- params[6 + 3 * i] = 0;
- }
-
- if (pattern->type == CAIRO_PATTERN_LINEAR) {
- params[0] = _cairo_fixed_from_double (pattern->u.linear.point0.x);
- params[1] = _cairo_fixed_from_double (pattern->u.linear.point0.y);
- params[2] = _cairo_fixed_from_double (pattern->u.linear.point1.x);
- params[3] = _cairo_fixed_from_double (pattern->u.linear.point1.y);
-
- glitz_surface_set_filter (src->surface,
- GLITZ_FILTER_LINEAR_GRADIENT,
- params, n_params);
- } else {
- params[0] = _cairo_fixed_from_double (pattern->u.radial.center0.x);
- params[1] = _cairo_fixed_from_double (pattern->u.radial.center0.y);
- params[2] = _cairo_fixed_from_double (pattern->u.radial.radius0);
- params[3] = _cairo_fixed_from_double (pattern->u.radial.radius1);
-
- glitz_surface_set_filter (src->surface,
- GLITZ_FILTER_RADIAL_GRADIENT,
- params, n_params);
- }
-
- switch (pattern->extend) {
- case CAIRO_EXTEND_REPEAT:
- glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
- break;
- case CAIRO_EXTEND_REFLECT:
- glitz_surface_set_fill (src->surface, GLITZ_FILL_REFLECT);
- break;
- case CAIRO_EXTEND_NONE:
- default:
- glitz_surface_set_fill (src->surface, GLITZ_FILL_NEAREST);
- break;
+ if (!surface->clip)
+ {
+ surface->clip = pixman_region_create ();
+ if (!surface->clip)
+ return CAIRO_STATUS_NO_MEMORY;
}
+ pixman_region_copy (surface->clip, region);
- cairo_surface_set_matrix (&src->base, &pattern->matrix);
-
- free (params);
- } break;
- case CAIRO_PATTERN_SURFACE:
- generic_src = pattern->u.surface.surface;
- cairo_surface_reference (generic_src);
- break;
- }
-
- if (generic_src == NULL) {
- image = _cairo_pattern_get_image (pattern, box);
- if (image == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- generic_src = &image->base;
+ box = (glitz_box_t *) pixman_region_rects (surface->clip);
+ n = pixman_region_num_rects (surface->clip);
+ glitz_surface_set_clip_region (surface->surface, 0, 0, box, n);
}
+ else
+ {
+ glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
- if (generic_src->backend != dst->base.backend) {
- src = _cairo_glitz_surface_clone_similar (dst, generic_src,
- CAIRO_FORMAT_ARGB32);
- if (src == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- cairo_surface_set_repeat (&src->base, generic_src->repeat);
- } else
- src = (cairo_glitz_surface_t *) generic_src;
+ if (surface->clip)
+ pixman_region_destroy (surface->clip);
- if (image)
- cairo_surface_destroy (&image->base);
-
- _cairo_pattern_init_copy (&src->pattern, pattern);
- src->pattern_box = *box;
-
- pattern->source = &src->base;
+ surface->clip = NULL;
+ }
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_glitz_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_create_similar,
_cairo_glitz_surface_destroy,
_cairo_glitz_surface_pixels_per_inch,
- _cairo_glitz_surface_get_image,
- _cairo_glitz_surface_set_image,
- _cairo_glitz_surface_set_matrix,
- _cairo_glitz_surface_set_filter,
- _cairo_glitz_surface_set_repeat,
+ _cairo_glitz_surface_acquire_source_image,
+ _cairo_glitz_surface_release_source_image,
+ _cairo_glitz_surface_acquire_dest_image,
+ _cairo_glitz_surface_release_dest_image,
+ _cairo_glitz_surface_clone_similar,
_cairo_glitz_surface_composite,
_cairo_glitz_surface_fill_rectangles,
_cairo_glitz_surface_composite_trapezoids,
_cairo_glitz_surface_copy_page,
_cairo_glitz_surface_show_page,
_cairo_glitz_surface_set_clip_region,
- _cairo_glitz_surface_create_pattern,
NULL /* show_glyphs */
};
@@ -1004,12 +1308,10 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
_cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend);
glitz_surface_reference (surface);
- crsurface->surface = surface;
- crsurface->format = glitz_surface_get_format (surface);
- _cairo_pattern_init (&crsurface->pattern);
- crsurface->pattern.type = CAIRO_PATTERN_SURFACE;
- crsurface->pattern.u.surface.surface = NULL;
+ crsurface->surface = surface;
+ crsurface->format = glitz_surface_get_format (surface);
+ crsurface->clip = NULL;
return (cairo_surface_t *) crsurface;
}
diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c
index e855a7a66..d6db560a3 100644
--- a/src/cairo_gstate.c
+++ b/src/cairo_gstate.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include <stdlib.h>
@@ -46,20 +46,33 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
cairo_surface_t *dst,
cairo_traps_t *traps);
+static cairo_status_t
+_cairo_gstate_ensure_font (cairo_gstate_t *gstate);
+
+static void
+_cairo_gstate_unset_font (cairo_gstate_t *gstate);
+
cairo_gstate_t *
_cairo_gstate_create ()
{
+ cairo_status_t status;
cairo_gstate_t *gstate;
gstate = malloc (sizeof (cairo_gstate_t));
if (gstate)
- _cairo_gstate_init (gstate);
+ {
+ status = _cairo_gstate_init (gstate);
+ if (status) {
+ free (gstate);
+ return NULL;
+ }
+ }
return gstate;
}
-void
+cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate)
{
gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
@@ -77,9 +90,11 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->num_dashes = 0;
gstate->dash_offset = 0.0;
- gstate->font = _cairo_unscaled_font_create (CAIRO_FONT_FAMILY_DEFAULT,
- CAIRO_FONT_SLANT_DEFAULT,
- CAIRO_FONT_WEIGHT_DEFAULT);
+ gstate->font_family = NULL;
+ gstate->font_slant = CAIRO_FONT_SLANT_DEFAULT;
+ gstate->font_weight = CAIRO_FONT_WEIGHT_DEFAULT;
+
+ gstate->font = NULL;
gstate->surface = NULL;
@@ -87,6 +102,9 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->clip.surface = NULL;
gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0);
+ if (!gstate->pattern)
+ return CAIRO_STATUS_NO_MEMORY;
+
gstate->alpha = 1.0;
gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
@@ -97,6 +115,8 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
_cairo_pen_init_empty (&gstate->pen_regular);
gstate->next = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@@ -118,9 +138,15 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
}
+ if (other->font_family) {
+ gstate->font_family = strdup (other->font_family);
+ if (!gstate->font_family)
+ goto CLEANUP_DASH;
+ }
+
if (other->font) {
gstate->font = other->font;
- _cairo_unscaled_font_reference (gstate->font);
+ cairo_font_reference (gstate->font);
}
if (other->clip.region)
@@ -148,18 +174,29 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
_cairo_path_fini (&gstate->path);
CLEANUP_FONT:
- _cairo_unscaled_font_destroy (gstate->font);
+ cairo_font_destroy (gstate->font);
+ gstate->font = NULL;
+
+ if (gstate->font_family) {
+ free (gstate->font_family);
+ gstate->font_family = NULL;
+ }
+ CLEANUP_DASH:
free (gstate->dash);
gstate->dash = NULL;
- return status;
+ return CAIRO_STATUS_NO_MEMORY;
}
void
_cairo_gstate_fini (cairo_gstate_t *gstate)
{
- _cairo_unscaled_font_destroy (gstate->font);
+ if (gstate->font_family)
+ free (gstate->font_family);
+
+ if (gstate->font)
+ cairo_font_destroy (gstate->font);
if (gstate->surface)
cairo_surface_destroy (gstate->surface);
@@ -323,6 +360,8 @@ _cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surfa
{
double scale;
+ _cairo_gstate_unset_font (gstate);
+
if (gstate->surface)
cairo_surface_destroy (gstate->surface);
@@ -365,11 +404,9 @@ _cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern)
if (pattern == NULL)
return CAIRO_STATUS_NULL_POINTER;
- if (gstate->pattern)
- cairo_pattern_destroy (gstate->pattern);
-
- gstate->pattern = pattern;
cairo_pattern_reference (pattern);
+ cairo_pattern_destroy (gstate->pattern);
+ gstate->pattern = pattern;
return CAIRO_STATUS_SUCCESS;
}
@@ -407,6 +444,8 @@ _cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, d
cairo_pattern_destroy (gstate->pattern);
gstate->pattern = _cairo_pattern_create_solid (red, green, blue);
+ if (!gstate->pattern)
+ return CAIRO_STATUS_NO_MEMORY;
return CAIRO_STATUS_SUCCESS;
}
@@ -549,6 +588,8 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
{
cairo_matrix_t tmp;
+ _cairo_gstate_unset_font (gstate);
+
_cairo_matrix_set_translate (&tmp, tx, ty);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -566,6 +607,8 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
if (sx == 0 || sy == 0)
return CAIRO_STATUS_INVALID_MATRIX;
+ _cairo_gstate_unset_font (gstate);
+
_cairo_matrix_set_scale (&tmp, sx, sy);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -580,6 +623,8 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
{
cairo_matrix_t tmp;
+ _cairo_gstate_unset_font (gstate);
+
_cairo_matrix_set_rotate (&tmp, angle);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -595,6 +640,8 @@ _cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
{
cairo_matrix_t tmp;
+ _cairo_gstate_unset_font (gstate);
+
cairo_matrix_copy (&tmp, matrix);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -610,6 +657,8 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate,
{
cairo_status_t status;
+ _cairo_gstate_unset_font (gstate);
+
cairo_matrix_copy (&gstate->ctm, matrix);
cairo_matrix_copy (&gstate->ctm_inverse, matrix);
@@ -627,6 +676,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate)
if (scale == 0)
scale = 1;
+ _cairo_gstate_unset_font (gstate);
+
cairo_matrix_set_identity (&gstate->font_matrix);
cairo_matrix_set_identity (&gstate->ctm);
@@ -640,6 +691,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate)
cairo_status_t
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
{
+ _cairo_gstate_unset_font (gstate);
+
cairo_matrix_set_identity (&gstate->ctm);
cairo_matrix_set_identity (&gstate->ctm_inverse);
@@ -1256,54 +1309,17 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate,
&gpi);
}
-/* This function modifies the pattern and the state of the pattern surface it
- may contain. The pattern surface will be restored to its orignal state
- when the pattern is destroyed. The appropriate way is to pass a copy of
- the original pattern to this function just before the pattern should be
- used and destroy the copy when done. */
-static cairo_status_t
-_cairo_gstate_create_pattern (cairo_gstate_t *gstate,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
+/* XXX: gstate->alpha will be going away before too long, and when it
+ * does, it may make sense for this function to just disappear.
+ */
+static void
+_cairo_gstate_pattern_init_copy (cairo_gstate_t *gstate,
+ cairo_pattern_union_t *pattern,
+ cairo_pattern_t *src)
{
- cairo_int_status_t status;
-
- if (gstate->surface == NULL) {
- _cairo_pattern_fini (pattern);
- return CAIRO_STATUS_NO_TARGET_SURFACE;
- }
-
- if (pattern->type == CAIRO_PATTERN_LINEAR ||
- pattern->type == CAIRO_PATTERN_RADIAL) {
- if (pattern->n_stops < 2) {
- pattern->type = CAIRO_PATTERN_SOLID;
-
- if (pattern->n_stops) {
- cairo_color_stop_t *stop = pattern->stops;
-
- _cairo_color_set_rgb (&pattern->color,
- (double) stop->color_char[0] / 0xff,
- (double) stop->color_char[1] / 0xff,
- (double) stop->color_char[2] / 0xff);
- _cairo_color_set_alpha (&pattern->color,
- (double) stop->color_char[3] / 0xff);
- }
- }
- }
-
- _cairo_pattern_set_alpha (pattern, gstate->alpha);
- _cairo_pattern_transform (pattern, &gstate->ctm_inverse);
-
- status = _cairo_surface_create_pattern (gstate->surface, pattern, extents);
- if (status) {
- _cairo_pattern_fini (pattern);
- return status;
- }
-
- if (pattern->type == CAIRO_PATTERN_SURFACE)
- _cairo_pattern_prepare_surface (pattern);
-
- return CAIRO_STATUS_SUCCESS;
+ _cairo_pattern_init_copy (&pattern->base, src);
+ _cairo_pattern_transform (&pattern->base, &gstate->ctm_inverse);
+ _cairo_pattern_set_alpha (&pattern->base, gstate->alpha);
}
cairo_status_t
@@ -1342,7 +1358,7 @@ cairo_status_t
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double x,
double y,
- int *inside_ret)
+ cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;
@@ -1365,51 +1381,85 @@ BAIL:
return status;
}
-static cairo_status_t
-_calculate_region_for_intermediate_clip_surface (pixman_region16_t *out,
- cairo_box_t *extents,
- cairo_clip_rec_t *clip_rect)
+/* XXX We currently have a confusing mix of boxes and rectangles as
+ * exemplified by this function. A cairo_box_t is a rectangular area
+ * represented by the coordinates of the upper left and lower right
+ * corners, expressed in fixed point numbers. A cairo_rectangle_t is
+ * also a rectangular area, but represented by the upper left corner
+ * and the width and the height, as integer numbers.
+ *
+ * This function converts a cairo_box_t to a cairo_rectangle_t by
+ * increasing the area to the nearest integer coordinates. We should
+ * standardize on cairo_rectangle_t and cairo_rectangle_fixed_t, and
+ * this function could be renamed to the more reasonable
+ * _cairo_rectangle_fixed_round.
+ */
+
+static void
+_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle)
{
- cairo_status_t status;
- pixman_region16_t *extents_region, *clip_region;
- pixman_box16_t clip_box, pixman_extents;
-
- pixman_extents.x1 = _cairo_fixed_integer_floor (extents->p1.x);
- pixman_extents.y1 = _cairo_fixed_integer_floor (extents->p1.y);
- pixman_extents.x2 = _cairo_fixed_integer_ceil (extents->p2.x);
- pixman_extents.y2 = _cairo_fixed_integer_ceil (extents->p2.y);
- extents_region = pixman_region_create_simple (&pixman_extents);
- if (extents_region == NULL)
- {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL0;
- }
+ rectangle->x = _cairo_fixed_integer_floor (box->p1.x);
+ rectangle->y = _cairo_fixed_integer_floor (box->p1.y);
+ rectangle->width = _cairo_fixed_integer_ceil (box->p2.x) - rectangle->x;
+ rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y;
+}
- clip_box.x1 = clip_rect->x;
- clip_box.y1 = clip_rect->y;
- clip_box.x2 = clip_rect->x + clip_rect->width;
- clip_box.y2 = clip_rect->y + clip_rect->height;
- clip_region = pixman_region_create_simple (&clip_box);
- if (clip_region == NULL)
- {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
+static void
+_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src)
+{
+ int x1, y1, x2, y2;
- if (pixman_region_intersect (out,
- extents_region,
- clip_region)
- == PIXMAN_REGION_STATUS_FAILURE)
- status = CAIRO_STATUS_NO_MEMORY;
- else
- status = CAIRO_STATUS_SUCCESS;
-
- pixman_region_destroy (extents_region);
- BAIL1:
- pixman_region_destroy (clip_region);
-
- BAIL0:
- return status;
+ x1 = MAX (dest->x, src->x);
+ y1 = MAX (dest->y, src->y);
+ x2 = MIN (dest->x + dest->width, src->x + src->width);
+ y2 = MIN (dest->y + dest->height, src->y + src->height);
+
+ if (x1 >= x2 || y1 >= y2) {
+ dest->x = 0;
+ dest->y = 0;
+ dest->width = 0;
+ dest->height = 0;
+ } else {
+ dest->x = x1;
+ dest->y = y1;
+ dest->width = x2 - x1;
+ dest->height = y2 - y1;
+ }
+}
+
+static int
+_cairo_rectangle_empty (cairo_rectangle_t *rect)
+{
+ return rect->width == 0 || rect->height == 0;
+}
+
+static void
+translate_traps (cairo_traps_t *traps, int x, int y)
+{
+ cairo_fixed_t xoff, yoff;
+ cairo_trapezoid_t *t;
+ int i;
+
+ /* Ugh. The cairo_composite/(Render) interface doesn't allow
+ an offset for the trapezoids. Need to manually shift all
+ the coordinates to align with the offset origin of the
+ intermediate surface. */
+
+ xoff = _cairo_fixed_from_int (x);
+ yoff = _cairo_fixed_from_int (y);
+
+ for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
+ t->top += yoff;
+ t->bottom += yoff;
+ t->left.p1.x += xoff;
+ t->left.p1.y += yoff;
+ t->left.p2.x += xoff;
+ t->left.p2.y += yoff;
+ t->right.p1.x += xoff;
+ t->right.p1.y += yoff;
+ t->right.p2.x += xoff;
+ t->right.p2.y += yoff;
+ }
}
@@ -1422,173 +1472,148 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
cairo_traps_t *traps)
{
cairo_status_t status;
- cairo_pattern_t pattern;
- cairo_box_t extents;
- int x_src, y_src;
+ cairo_pattern_union_t pattern;
+ cairo_rectangle_t extents;
+ cairo_box_t trap_extents;
if (traps->num_traps == 0)
return CAIRO_STATUS_SUCCESS;
+ if (gstate->surface == NULL)
+ return CAIRO_STATUS_NO_TARGET_SURFACE;
+
+ _cairo_traps_extents (traps, &trap_extents);
+ _cairo_box_round_to_rectangle (&trap_extents, &extents);
+
if (gstate->clip.surface) {
- cairo_fixed_t xoff, yoff;
- cairo_trapezoid_t *t;
- int i;
cairo_surface_t *intermediate;
+ cairo_surface_pattern_t intermediate_pattern;
cairo_color_t empty_color;
- pixman_box16_t *draw_extents;
- pixman_region16_t *draw_region;
- draw_region = pixman_region_create ();
- if (draw_region == NULL)
- {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL0;
- }
-
- _cairo_traps_extents (traps, &extents);
-
- status = _calculate_region_for_intermediate_clip_surface (draw_region,
- &extents,
- &gstate->clip);
- if (status)
- goto BAIL1;
+ _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
- /* Shortcut if empty */
- if (!pixman_region_not_empty (draw_region)) {
+ if (_cairo_rectangle_empty (&extents)) {
status = CAIRO_STATUS_SUCCESS;
goto BAIL1;
}
- draw_extents = pixman_region_extents (draw_region);
-
- /* Ugh. The cairo_composite/(Render) interface doesn't allow
- an offset for the trapezoids. Need to manually shift all
- the coordinates to align with the offset origin of the
- intermediate surface. */
- xoff = _cairo_fixed_from_int (draw_extents->x1);
- yoff = _cairo_fixed_from_int (draw_extents->y1);
- for (i=0, t=traps->traps; i < traps->num_traps; i++, t++) {
- t->top -= yoff;
- t->bottom -= yoff;
- t->left.p1.x -= xoff;
- t->left.p1.y -= yoff;
- t->left.p2.x -= xoff;
- t->left.p2.y -= yoff;
- t->right.p1.x -= xoff;
- t->right.p1.y -= yoff;
- t->right.p2.x -= xoff;
- t->right.p2.y -= yoff;
- }
-
- if (traps->traps[0].left.p1.y < traps->traps[0].left.p2.y) {
- x_src = _cairo_fixed_to_double (traps->traps[0].left.p1.x);
- y_src = _cairo_fixed_to_double (traps->traps[0].left.p1.y);
- } else {
- x_src = _cairo_fixed_to_double (traps->traps[0].left.p2.x);
- y_src = _cairo_fixed_to_double (traps->traps[0].left.p2.y);
- }
-
- _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0);
- _cairo_pattern_set_alpha (&pattern, 1.0);
-
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
- if (status)
- goto BAIL1;
+ translate_traps (traps, -extents.x, -extents.y);
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, 0.);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1,
+ extents.width,
+ extents.height,
&empty_color);
if (intermediate == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL2;
+ goto BAIL1;
}
+ _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
+
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
- pattern.source, intermediate,
- x_src,
- y_src,
+ &pattern.base,
+ intermediate,
+ extents.x, extents.y,
+ 0, 0,
+ extents.width,
+ extents.height,
traps->traps,
traps->num_traps);
+ _cairo_pattern_fini (&pattern.base);
+
if (status)
- goto BAIL3;
+ goto BAIL2;
+
+
+ _cairo_pattern_init_for_surface (&pattern.surface,
+ gstate->clip.surface);
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- gstate->clip.surface,
+ &pattern.base,
NULL,
intermediate,
- draw_extents->x1 - gstate->clip.x,
- draw_extents->y1 - gstate->clip.y,
+ extents.x - gstate->clip.rect.x,
+ extents.y - gstate->clip.rect.y,
0, 0,
0, 0,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
- if (status)
- goto BAIL3;
-
- _cairo_pattern_fini (&pattern);
+ extents.width, extents.height);
+ _cairo_pattern_fini (&pattern.base);
- _cairo_pattern_init_copy (&pattern, src);
-
- extents.p1.x = _cairo_fixed_from_int (draw_extents->x1);
- extents.p1.y = _cairo_fixed_from_int (draw_extents->y1);
- extents.p2.x = _cairo_fixed_from_int (draw_extents->x2);
- extents.p2.y = _cairo_fixed_from_int (draw_extents->y2);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
- goto BAIL3;
+ goto BAIL2;
- if (dst == gstate->clip.surface)
- xoff = yoff = 0;
+ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+ _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
status = _cairo_surface_composite (operator,
- pattern.source, intermediate, dst,
- 0, 0,
+ &pattern.base,
+ &intermediate_pattern.base,
+ dst,
+ extents.x, extents.y,
0, 0,
- xoff >> 16,
- yoff >> 16,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
+ extents.x, extents.y,
+ extents.width, extents.height);
+ _cairo_pattern_fini (&pattern.base);
+ _cairo_pattern_fini (&intermediate_pattern.base);
- BAIL3:
- cairo_surface_destroy (intermediate);
BAIL2:
- _cairo_pattern_fini (&pattern);
+ cairo_surface_destroy (intermediate);
BAIL1:
- pixman_region_destroy (draw_region);
- BAIL0:
if (status)
return status;
} else {
- if (traps->traps[0].left.p1.y < traps->traps[0].left.p2.y) {
- x_src = _cairo_fixed_to_double (traps->traps[0].left.p1.x);
- y_src = _cairo_fixed_to_double (traps->traps[0].left.p1.y);
- } else {
- x_src = _cairo_fixed_to_double (traps->traps[0].left.p2.x);
- y_src = _cairo_fixed_to_double (traps->traps[0].left.p2.y);
+ if (gstate->clip.region) {
+ pixman_box16_t box;
+ pixman_box16_t *intersection_extents;
+ pixman_region16_t *rect, *intersection;
+
+ box.x1 = _cairo_fixed_integer_floor (trap_extents.p1.x);
+ box.y1 = _cairo_fixed_integer_floor (trap_extents.p1.y);
+ box.x2 = _cairo_fixed_integer_ceil (trap_extents.p2.x);
+ box.y2 = _cairo_fixed_integer_ceil (trap_extents.p2.y);
+
+ rect = pixman_region_create_simple (&box);
+ if (rect == NULL)
+ goto bail1;
+ intersection = pixman_region_create();
+ if (intersection == NULL)
+ goto bail2;
+
+ if (pixman_region_intersect (intersection, gstate->clip.region,
+ rect) != PIXMAN_REGION_STATUS_SUCCESS)
+ goto bail3;
+ intersection_extents = pixman_region_extents (intersection);
+
+ extents.x = intersection_extents->x1;
+ extents.y = intersection_extents->y1;
+ extents.width = intersection_extents->x2 - intersection_extents->x1;
+ extents.height = intersection_extents->y2 - intersection_extents->y1;
+ bail3:
+ pixman_region_destroy (intersection);
+ bail2:
+ pixman_region_destroy (rect);
+ bail1:
+ ;
}
- _cairo_pattern_init_copy (&pattern, src);
+ _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
- _cairo_traps_extents (traps, &extents);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
- if (status)
- return status;
-
status = _cairo_surface_composite_trapezoids (gstate->operator,
- pattern.source, dst,
- x_src - pattern.source_offset.x,
- y_src - pattern.source_offset.y,
+ &pattern.base, dst,
+ extents.x, extents.y,
+ extents.x, extents.y,
+ extents.width,
+ extents.height,
traps->traps,
traps->num_traps);
- _cairo_pattern_fini (&pattern);
+ _cairo_pattern_fini (&pattern.base);
if (status)
return status;
@@ -1628,7 +1653,7 @@ cairo_status_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
double x,
double y,
- int *inside_ret)
+ cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;
@@ -1807,9 +1832,10 @@ cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate)
{
cairo_status_t status;
- cairo_pattern_t pattern;
+ cairo_pattern_union_t pattern;
cairo_traps_t traps;
cairo_color_t white_color;
+ cairo_box_t extents;
pixman_box16_t box;
/* Fill the clip region as traps. */
@@ -1871,33 +1897,32 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_color_init (&white_color);
if (gstate->clip.surface == NULL) {
- cairo_box_t extents;
-
_cairo_traps_extents (&traps, &extents);
- gstate->clip.x = extents.p1.x >> 16;
- gstate->clip.y = extents.p1.y >> 16;
- gstate->clip.width = ((extents.p2.x + 65535) >> 16) - gstate->clip.x;
- gstate->clip.height = ((extents.p2.y + 65535) >> 16) - gstate->clip.y;
+ _cairo_box_round_to_rectangle (&extents, &gstate->clip.rect);
gstate->clip.surface =
_cairo_surface_create_similar_solid (gstate->surface,
CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
+ gstate->clip.rect.width,
+ gstate->clip.rect.height,
&white_color);
if (gstate->clip.surface == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
- _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0);
- _cairo_pattern_set_alpha (&pattern, 1.0);
-
- _cairo_gstate_clip_and_composite_trapezoids (gstate,
- &pattern,
- CAIRO_OPERATOR_IN,
- gstate->clip.surface,
- &traps);
+ translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y);
+ _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
- _cairo_pattern_fini (&pattern);
+ status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
+ &pattern.base,
+ gstate->clip.surface,
+ 0, 0,
+ 0, 0,
+ gstate->clip.rect.width,
+ gstate->clip.rect.height,
+ traps.traps,
+ traps.num_traps);
+
+ _cairo_pattern_fini (&pattern.base);
_cairo_traps_fini (&traps);
@@ -1978,19 +2003,15 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
*
*/
- cairo_status_t status;
- cairo_matrix_t user_to_image, image_to_user;
- cairo_matrix_t image_to_device, device_to_image;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_matrix_t image_to_user, image_to_device;
double device_x, device_y;
double device_width, device_height;
- cairo_pattern_t pattern;
+ cairo_surface_pattern_t pattern;
cairo_box_t pattern_extents;
+ cairo_rectangle_t extents;
- cairo_surface_get_matrix (surface, &user_to_image);
- cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image);
- cairo_surface_set_matrix (surface, &device_to_image);
-
- image_to_user = user_to_image;
+ cairo_surface_get_matrix (surface, &image_to_user);
cairo_matrix_invert (&image_to_user);
cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm);
@@ -2001,126 +2022,82 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
&device_x, &device_y,
&device_width, &device_height);
- _cairo_pattern_init (&pattern);
+ _cairo_pattern_init_for_surface (&pattern, surface);
+
+ /* inherit surface attributes while surface attribute functions still
+ exist */
+ pattern.base.matrix = surface->matrix;
+ pattern.base.filter = surface->filter;
+ if (surface->repeat)
+ pattern.base.extend = CAIRO_EXTEND_REPEAT;
+ else
+ pattern.base.extend = CAIRO_EXTEND_NONE;
+
+ _cairo_pattern_transform (&pattern.base, &gstate->ctm_inverse);
+ _cairo_pattern_set_alpha (&pattern.base, gstate->alpha);
pattern_extents.p1.x = _cairo_fixed_from_double (device_x);
pattern_extents.p1.y = _cairo_fixed_from_double (device_y);
pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
-
- if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) ||
- (gstate->alpha != 1.0)) {
- /* I'm allowing any type of pattern for the mask right now.
- Maybe this is bad. Will allow for some cool effects though. */
- _cairo_pattern_init_copy (&pattern, gstate->pattern);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &pattern_extents);
- if (status)
- return status;
- }
-
+ _cairo_box_round_to_rectangle (&pattern_extents, &extents);
+
if (gstate->clip.surface)
{
- cairo_surface_t *intermediate;
- cairo_color_t empty_color;
- pixman_box16_t *draw_extents;
- pixman_region16_t *draw_region;
-
- draw_region = pixman_region_create ();
- if (draw_region == NULL)
- {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL0;
+ _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
+
+ /* We only need to composite if the rectangle is not empty. */
+ if (!_cairo_rectangle_empty (&extents)) {
+ cairo_surface_pattern_t clip_pattern;
+
+ _cairo_pattern_init_for_surface (&clip_pattern,
+ gstate->clip.surface);
+
+ status = _cairo_surface_composite (gstate->operator,
+ &pattern.base,
+ &clip_pattern.base,
+ gstate->surface,
+ extents.x, extents.y,
+ 0, 0,
+ extents.x, extents.y,
+ extents.width, extents.height);
+
+ _cairo_pattern_fini (&clip_pattern.base);
}
-
- status = _calculate_region_for_intermediate_clip_surface (draw_region,
- &pattern_extents,
- &gstate->clip);
- if (status)
- goto BAIL1;
-
- /* Shortcut if empty */
- if (!pixman_region_not_empty (draw_region)) {
- status = CAIRO_STATUS_SUCCESS;
- goto BAIL1;
- }
-
- draw_extents = pixman_region_extents (draw_region);
-
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, .0);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_FORMAT_A8,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1,
- &empty_color);
-
- /* it is not completely clear what the "right" way to combine the
- pattern and mask surface is. I will use the the clip as a source
- and the pattern as a mask in building up my temporary, because
- this is not *totally* bogus and accomodates the case where
- pattern's source image is NULL reasonably well. feel free to
- correct this if you see a reason. */
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_SRC,
- gstate->clip.surface,
- pattern.source,
- intermediate,
- draw_extents->x1 - gstate->clip.x,
- draw_extents->y1 - gstate->clip.y,
- 0, 0,
- 0, 0,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
-
-
- if (status)
- goto BAIL2;
-
- status = _cairo_surface_composite (gstate->operator,
- surface,
- intermediate,
- gstate->surface,
- draw_extents->x1, draw_extents->y1,
- 0, 0,
- draw_extents->x1, draw_extents->y1,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
-
- BAIL2:
- cairo_surface_destroy (intermediate);
- BAIL1:
- pixman_region_destroy (draw_region);
- BAIL0:
- ;
}
else
{
-
- /* XXX: The rendered size is sometimes 1 or 2 pixels short from
- what I expect. Need to fix this. */
+ /* XXX: The rendered size is sometimes 1 or 2 pixels short
+ * from what I expect. Need to fix this.
+ * KRH: I'm guessing this was due to rounding error when
+ * passing double coordinates for integer arguments. Using
+ * the extents rectangle should fix this, since it's properly
+ * rounded. Is this still the case?
+ */
status = _cairo_surface_composite (gstate->operator,
- surface,
- pattern.source,
+ &pattern.base,
+ NULL,
gstate->surface,
- device_x, device_y,
+ extents.x, extents.y,
0, 0,
- device_x, device_y,
- device_width,
- device_height);
+ extents.x, extents.y,
+ extents.width, extents.height);
}
- _cairo_pattern_fini (&pattern);
+ _cairo_pattern_fini (&pattern.base);
- /* restore the matrix originally in the surface */
- cairo_surface_set_matrix (surface, &user_to_image);
-
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
+static void
+_cairo_gstate_unset_font (cairo_gstate_t *gstate)
+{
+ if (gstate->font) {
+ cairo_font_destroy (gstate->font);
+ gstate->font = NULL;
+ }
+}
cairo_status_t
_cairo_gstate_select_font (cairo_gstate_t *gstate,
@@ -2128,12 +2105,17 @@ _cairo_gstate_select_font (cairo_gstate_t *gstate,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
- if (gstate->font)
- _cairo_unscaled_font_destroy (gstate->font);
+ char *new_family;
- gstate->font = _cairo_unscaled_font_create (family, slant, weight);
- if (gstate->font == NULL)
+ new_family = strdup (family);
+ if (!new_family)
return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_gstate_unset_font (gstate);
+
+ gstate->font_family = new_family;
+ gstate->font_slant = slant;
+ gstate->font_weight = weight;
cairo_matrix_set_identity (&gstate->font_matrix);
@@ -2144,6 +2126,8 @@ cairo_status_t
_cairo_gstate_scale_font (cairo_gstate_t *gstate,
double scale)
{
+ _cairo_gstate_unset_font (gstate);
+
return cairo_matrix_scale (&gstate->font_matrix, scale, scale);
}
@@ -2153,6 +2137,9 @@ _cairo_gstate_transform_font (cairo_gstate_t *gstate,
{
cairo_matrix_t tmp;
double a, b, c, d, tx, ty;
+
+ _cairo_gstate_unset_font (gstate);
+
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);
@@ -2160,28 +2147,16 @@ _cairo_gstate_transform_font (cairo_gstate_t *gstate,
cairo_status_t
-_cairo_gstate_current_font (cairo_gstate_t *gstate,
- cairo_font_t **font)
+_cairo_gstate_current_font (cairo_gstate_t *gstate,
+ cairo_font_t **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);
+ cairo_status_t status;
- *font = scaled;
+ status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
+
+ *font = gstate->font;
return CAIRO_STATUS_SUCCESS;
}
@@ -2190,6 +2165,8 @@ void
_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
cairo_matrix_t *matrix)
{
+ _cairo_gstate_unset_font (gstate);
+
cairo_matrix_copy (&gstate->font_matrix, matrix);
}
@@ -2214,12 +2191,10 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
* 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 only font type exposed to the user is cairo_font_t which is a
+ * a font specialized to a particular scale matrix, CTM, and target
+ * surface. The user is responsible for not using a cairo_font_t
+ * after changing the parameters; doing so will produce garbled metrics.
*
*
* The font's view
@@ -2279,9 +2254,9 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
*
*/
-static void
-_build_font_scale (cairo_gstate_t *gstate,
- cairo_font_scale_t *sc)
+void
+_cairo_gstate_current_font_scale (cairo_gstate_t *gstate,
+ cairo_font_scale_t *sc)
{
cairo_matrix_t tmp;
double dummy;
@@ -2294,34 +2269,46 @@ _build_font_scale (cairo_gstate_t *gstate,
&dummy, &dummy);
}
-cairo_status_t
-_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
- cairo_font_extents_t *extents)
+static cairo_status_t
+_cairo_gstate_ensure_font (cairo_gstate_t *gstate)
{
- cairo_int_status_t status;
cairo_font_scale_t sc;
- double font_scale_x, font_scale_y;
+ cairo_status_t status;
+ const char *family;
+
+ if (gstate->font)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_gstate_current_font_scale (gstate, &sc);
- _build_font_scale (gstate, &sc);
+ if (gstate->font_family)
+ family = gstate->font_family;
+ else
+ family = CAIRO_FONT_FAMILY_DEFAULT;
+
+ status = _cairo_font_create (family,
+ gstate->font_slant,
+ gstate->font_weight,
+ &sc,
+ &gstate->font);
- status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents);
+ if (status)
+ return status;
- _cairo_matrix_compute_scale_factors (&gstate->font_matrix,
- &font_scale_x, &font_scale_y,
- /* XXX */ 1);
-
- /*
- * The font responded in unscaled units, scale by the font
- * matrix scale factors to get to user space
- */
-
- extents->ascent *= font_scale_y;
- extents->descent *= font_scale_y;
- extents->height *= font_scale_y;
- extents->max_x_advance *= font_scale_x;
- extents->max_y_advance *= font_scale_y;
-
- return status;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
+ cairo_font_extents_t *extents)
+{
+ cairo_status_t status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
+
+ return cairo_font_extents (gstate->font,
+ &gstate->font_matrix,
+ extents);
}
cairo_status_t
@@ -2331,14 +2318,15 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
int *nglyphs)
{
cairo_status_t status;
- cairo_font_scale_t sc;
cairo_point_t point;
double origin_x, origin_y;
int i;
- _build_font_scale (gstate, &sc);
-
+ status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
+
status = _cairo_path_current_point (&gstate->path, &point);
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
origin_x = 0.0;
@@ -2350,8 +2338,8 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
&origin_x, &origin_y);
}
- status = _cairo_unscaled_font_text_to_glyphs (gstate->font,
- &sc, utf8, glyphs, nglyphs);
+ status = _cairo_font_text_to_glyphs (gstate->font,
+ utf8, glyphs, nglyphs);
if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
return status;
@@ -2373,18 +2361,16 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
cairo_status_t
_cairo_gstate_set_font (cairo_gstate_t *gstate,
- cairo_font_t *font)
-{
- if (gstate->font != NULL)
- _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);
+ cairo_font_t *font)
+{
+ if (font != gstate->font) {
+ if (gstate->font)
+ cairo_font_destroy (gstate->font);
+ gstate->font = font;
+ if (gstate->font)
+ cairo_font_reference (gstate->font);
+ }
+
return CAIRO_STATUS_SUCCESS;
}
@@ -2394,90 +2380,18 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
int num_glyphs,
cairo_text_extents_t *extents)
{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_glyph_t origin_glyph;
- cairo_text_extents_t origin_extents;
- cairo_font_scale_t sc;
- int i;
- double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
- double x_pos = 0.0, y_pos = 0.0;
- int set = 0;
-
- if (!num_glyphs)
- {
- extents->x_bearing = 0.0;
- extents->y_bearing = 0.0;
- extents->width = 0.0;
- extents->height = 0.0;
- extents->x_advance = 0.0;
- extents->y_advance = 0.0;
- return CAIRO_STATUS_SUCCESS;
- }
-
- _build_font_scale (gstate, &sc);
-
- for (i = 0; i < num_glyphs; i++)
- {
- double x, y;
- double wm, hm;
-
- origin_glyph = glyphs[i];
- origin_glyph.x = 0.0;
- origin_glyph.y = 0.0;
- status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc,
- &origin_glyph, 1,
- &origin_extents);
-
- /*
- * Transform font space metrics into user space metrics
- * by running the corners through the font matrix and
- * expanding the bounding box as necessary
- */
- x = origin_extents.x_bearing;
- y = origin_extents.y_bearing;
- cairo_matrix_transform_point (&gstate->font_matrix,
- &x, &y);
-
- for (hm = 0.0; hm <= 1.0; hm += 1.0)
- for (wm = 0.0; wm <= 1.0; wm += 1.0)
- {
- x = origin_extents.x_bearing + origin_extents.width * wm;
- y = origin_extents.y_bearing + origin_extents.height * hm;
- cairo_matrix_transform_point (&gstate->font_matrix,
- &x, &y);
- x += glyphs[i].x;
- y += glyphs[i].y;
- if (!set)
- {
- min_x = max_x = x;
- min_y = max_y = y;
- set = 1;
- }
- else
- {
- if (x < min_x) min_x = x;
- if (x > max_x) max_x = x;
- if (y < min_y) min_y = y;
- if (y > max_y) max_y = y;
- }
- }
+ cairo_status_t status;
- x = origin_extents.x_advance;
- y = origin_extents.y_advance;
- cairo_matrix_transform_point (&gstate->font_matrix,
- &x, &y);
- x_pos = glyphs[i].x + x;
- y_pos = glyphs[i].y + y;
- }
+ status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
- extents->x_bearing = min_x - glyphs[0].x;
- extents->y_bearing = min_y - glyphs[0].y;
- extents->width = max_x - min_x;
- extents->height = max_y - min_y;
- extents->x_advance = x_pos - glyphs[0].x;
- extents->y_advance = y_pos - glyphs[0].y;
+ cairo_font_glyph_extents (gstate->font,
+ &gstate->font_matrix,
+ glyphs, num_glyphs,
+ extents);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@@ -2488,12 +2402,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_status_t status;
int i;
cairo_glyph_t *transformed_glyphs = NULL;
- cairo_font_scale_t sc;
- cairo_pattern_t pattern;
+ cairo_pattern_union_t pattern;
cairo_box_t bbox;
+ cairo_rectangle_t extents;
- _build_font_scale (gstate, &sc);
-
+ status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
+
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
if (transformed_glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY;
@@ -2506,52 +2422,34 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
&transformed_glyphs[i].y);
}
- _cairo_pattern_init_copy (&pattern, gstate->pattern);
- status = _cairo_unscaled_font_glyph_bbox (gstate->font, &sc,
- transformed_glyphs, num_glyphs,
- &bbox);
- if (status)
- goto CLEANUP_GLYPHS;
+ status = _cairo_font_glyph_bbox (gstate->font,
+ transformed_glyphs, num_glyphs,
+ &bbox);
+ _cairo_box_round_to_rectangle (&bbox, &extents);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
if (status)
goto CLEANUP_GLYPHS;
-
+
if (gstate->clip.surface)
{
cairo_surface_t *intermediate;
+ cairo_surface_pattern_t intermediate_pattern;
cairo_color_t empty_color;
- pixman_box16_t *draw_extents;
- pixman_region16_t *draw_region;
-
- draw_region = pixman_region_create ();
- if (draw_region == NULL)
- {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL0;
- }
- status = _calculate_region_for_intermediate_clip_surface (draw_region,
- &bbox,
- &gstate->clip);
- if (status) {
- goto BAIL1;
- }
+ _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
/* Shortcut if empty */
- if (!pixman_region_not_empty (draw_region)) {
+ if (_cairo_rectangle_empty (&extents)) {
status = CAIRO_STATUS_SUCCESS;
goto BAIL1;
}
- draw_extents = pixman_region_extents (draw_region);
-
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, .0);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1,
+ extents.width,
+ extents.height,
&empty_color);
if (intermediate == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
@@ -2561,66 +2459,77 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
/* move the glyphs again, from dev space to intermediate space */
for (i = 0; i < num_glyphs; ++i)
{
- transformed_glyphs[i].x -= draw_extents->x1;
- transformed_glyphs[i].y -= draw_extents->y1;
+ transformed_glyphs[i].x -= extents.x;
+ transformed_glyphs[i].y -= extents.y;
}
- status = _cairo_unscaled_font_show_glyphs (gstate->font,
- &sc,
- CAIRO_OPERATOR_ADD,
- pattern.source, intermediate,
- draw_extents->x1 - pattern.source_offset.x,
- draw_extents->y1 - pattern.source_offset.y,
- transformed_glyphs, num_glyphs);
+ _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
+
+ status = _cairo_font_show_glyphs (gstate->font,
+ CAIRO_OPERATOR_ADD,
+ &pattern.base, intermediate,
+ extents.x, extents.y,
+ 0, 0,
+ extents.width, extents.height,
+ transformed_glyphs, num_glyphs);
+
+ _cairo_pattern_fini (&pattern.base);
if (status)
goto BAIL2;
+ _cairo_pattern_init_for_surface (&pattern.surface,
+ gstate->clip.surface);
+
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- gstate->clip.surface,
+ &pattern.base,
NULL,
intermediate,
- draw_extents->x1 - gstate->clip.x,
- draw_extents->y1 - gstate->clip.y,
+ extents.x - gstate->clip.rect.x,
+ extents.y - gstate->clip.rect.y,
0, 0,
0, 0,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
+ extents.width, extents.height);
+
+ _cairo_pattern_fini (&pattern.base);
if (status)
goto BAIL2;
+ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+ _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
+
status = _cairo_surface_composite (gstate->operator,
- pattern.source,
- intermediate,
+ &pattern.base,
+ &intermediate_pattern.base,
gstate->surface,
- 0, 0,
+ extents.x, extents.y,
0, 0,
- draw_extents->x1,
- draw_extents->y1,
- draw_extents->x2 - draw_extents->x1,
- draw_extents->y2 - draw_extents->y1);
+ extents.x, extents.y,
+ extents.width, extents.height);
+ _cairo_pattern_fini (&pattern.base);
+ _cairo_pattern_fini (&intermediate_pattern.base);
BAIL2:
cairo_surface_destroy (intermediate);
BAIL1:
- pixman_region_destroy (draw_region);
- BAIL0:
;
}
else
{
- 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_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
+
+ status = _cairo_font_show_glyphs (gstate->font,
+ gstate->operator, &pattern.base,
+ gstate->surface,
+ extents.x, extents.y,
+ extents.x, extents.y,
+ extents.width, extents.height,
+ transformed_glyphs, num_glyphs);
+
+ _cairo_pattern_fini (&pattern.base);
}
- _cairo_pattern_fini (&pattern);
-
CLEANUP_GLYPHS:
free (transformed_glyphs);
@@ -2635,9 +2544,6 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
cairo_status_t status;
int i;
cairo_glyph_t *transformed_glyphs = NULL;
- cairo_font_scale_t sc;
-
- _build_font_scale (gstate, &sc);
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
if (transformed_glyphs == NULL)
@@ -2651,9 +2557,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
&(transformed_glyphs[i].y));
}
- status = _cairo_unscaled_font_glyph_path (gstate->font, &sc,
- transformed_glyphs, num_glyphs,
- &gstate->path);
+ status = _cairo_font_glyph_path (gstate->font,
+ transformed_glyphs, num_glyphs,
+ &gstate->path);
free (transformed_glyphs);
return status;
diff --git a/src/cairo_hull.c b/src/cairo_hull.c
index 99b16d1ae..c93d70625 100644
--- a/src/cairo_hull.c
+++ b/src/cairo_hull.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c
index 14e30f695..9745b3150 100644
--- a/src/cairo_image_surface.c
+++ b/src/cairo_image_surface.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
@@ -54,7 +54,8 @@ _cairo_format_bpp (cairo_format_t format)
}
static cairo_image_surface_t *
-_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image)
+_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
+ cairo_format_t format)
{
cairo_image_surface_t *surface;
@@ -66,6 +67,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image)
surface->pixman_image = pixman_image;
+ surface->format = format;
surface->data = (char *) pixman_image_get_data (pixman_image);
surface->owns_data = 0;
@@ -105,7 +107,8 @@ _cairo_image_surface_create_with_masks (char *data,
if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
+ (cairo_format_t)-1);
return surface;
}
@@ -130,6 +133,20 @@ _create_pixman_format (cairo_format_t format)
}
}
+/**
+ * cairo_image_surface_create:
+ * @format: format of pixels in the surface to create
+ * @width: width of the surface, in pixels
+ * @height: height of the surface, in pixels
+ *
+ * Creates an image surface of the specified format and
+ * dimensions. The initial contents of the surface is undefined; you
+ * must explicitely clear the buffer, using, for example,
+ * cairo_rectangle() and cairo_fill() if you want it cleared.
+ *
+ * Return value: the newly created surface, or %NULL if it couldn't
+ * be created because of lack of memory
+ **/
cairo_surface_t *
cairo_image_surface_create (cairo_format_t format,
int width,
@@ -150,11 +167,33 @@ cairo_image_surface_create (cairo_format_t format,
if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
return &surface->base;
}
+/**
+ * cairo_image_surface_create_for_data:
+ * @data: a pointer to a buffer supplied by the application
+ * in which to write contents.
+ * @format: the format of pixels in the buffer
+ * @width: the width of the image to be stored in the buffer
+ * @height: the height of the image to be stored in the buffer
+ * @stride: the number of bytes between the start of rows
+ * in the buffer. Having this be specified separate from @width
+ * allows for padding at the end of rows, or for writing
+ * to a subportion of a larger image.
+ *
+ * Creates an image surface for the provided pixel data. The output
+ * buffer must be kept around until the #cairo_surface_t is destroyed
+ * or cairo_surface_finish() is called on the surface. The initial
+ * contents of @buffer will be used as the inital image contents; you
+ * must explicitely clear the buffer, using, for example,
+ * cairo_rectangle() and cairo_fill() if you want it cleared.
+ *
+ * Return value: the newly created surface, or %NULL if it couldn't
+ * be created because of lack of memory
+ **/
cairo_surface_t *
cairo_image_surface_create_for_data (char *data,
cairo_format_t format,
@@ -180,7 +219,7 @@ cairo_image_surface_create_for_data (char *data,
if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
return &surface->base;
}
@@ -224,33 +263,66 @@ _cairo_image_surface_pixels_per_inch (void *abstract_surface)
return 96.0;
}
-static cairo_image_surface_t *
-_cairo_image_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_cairo_image_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
- cairo_image_surface_t *surface = abstract_surface;
-
- cairo_surface_reference (&surface->base);
+ *image_out = abstract_surface;
+
+ return CAIRO_STATUS_SUCCESS;
+}
- return surface;
+static void
+_cairo_image_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
}
static cairo_status_t
-_cairo_image_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+_cairo_image_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect_out,
+ void **image_extra)
{
- if (image == abstract_surface)
- return CAIRO_STATUS_SUCCESS;
+ cairo_image_surface_t *surface = abstract_surface;
+
+ image_rect_out->x = 0;
+ image_rect_out->y = 0;
+ image_rect_out->width = surface->width;
+ image_rect_out->height = surface->height;
+
+ *image_out = surface;
- /* XXX: This case has not yet been implemented. We'll lie for now. */
return CAIRO_STATUS_SUCCESS;
}
+static void
+_cairo_image_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+}
+
static cairo_status_t
-_cairo_image_abstract_surface_set_matrix (void *abstract_surface,
- cairo_matrix_t *matrix)
+_cairo_image_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
cairo_image_surface_t *surface = abstract_surface;
- return _cairo_image_surface_set_matrix (surface, matrix);
+
+ if (src->backend == surface->base.backend) {
+ *clone_out = src;
+ cairo_surface_reference (src);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
cairo_status_t
@@ -276,14 +348,6 @@ _cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_image_abstract_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_filter (surface, filter);
-}
-
cairo_status_t
_cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter)
{
@@ -314,13 +378,6 @@ _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_image_abstract_surface_set_repeat (void *abstract_surface, int repeat)
-{
- cairo_image_surface_t *surface = abstract_surface;
- return _cairo_image_surface_set_repeat (surface, repeat);
-}
-
cairo_status_t
_cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat)
{
@@ -329,6 +386,34 @@ _cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat)
return CAIRO_STATUS_SUCCESS;
}
+static cairo_int_status_t
+_cairo_image_surface_set_attributes (cairo_image_surface_t *surface,
+ cairo_surface_attributes_t *attributes)
+{
+ cairo_int_status_t status;
+
+ status = _cairo_image_surface_set_matrix (surface, &attributes->matrix);
+ if (status)
+ return status;
+
+ switch (attributes->extend) {
+ case CAIRO_EXTEND_NONE:
+ _cairo_image_surface_set_repeat (surface, 0);
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ _cairo_image_surface_set_repeat (surface, 1);
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ /* XXX: Obviously wrong. */
+ _cairo_image_surface_set_repeat (surface, 1);
+ break;
+ }
+
+ status = _cairo_image_surface_set_filter (surface, attributes->filter);
+
+ return status;
+}
+
static pixman_operator_t
_pixman_operator (cairo_operator_t operator)
{
@@ -368,8 +453,8 @@ _pixman_operator (cairo_operator_t operator)
static cairo_int_status_t
_cairo_image_surface_composite (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
+ cairo_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
void *abstract_dst,
int src_x,
int src_y,
@@ -380,26 +465,61 @@ _cairo_image_surface_composite (cairo_operator_t operator,
unsigned int width,
unsigned int height)
{
- cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_t *src = (cairo_image_surface_t *) generic_src;
- cairo_image_surface_t *mask = (cairo_image_surface_t *) generic_mask;
-
- if (generic_src->backend != dst->base.backend ||
- (generic_mask && (generic_mask->backend != dst->base.backend)))
+ cairo_surface_attributes_t src_attr, mask_attr;
+ cairo_image_surface_t *dst = abstract_dst;
+ cairo_image_surface_t *src;
+ cairo_image_surface_t *mask;
+ cairo_int_status_t status;
+
+ status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
+ &dst->base,
+ src_x, src_y,
+ mask_x, mask_y,
+ width, height,
+ (cairo_surface_t **) &src,
+ (cairo_surface_t **) &mask,
+ &src_attr, &mask_attr);
+ if (status)
+ return status;
+
+ status = _cairo_image_surface_set_attributes (src, &src_attr);
+ if (CAIRO_OK (status))
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (mask)
+ {
+ status = _cairo_image_surface_set_attributes (mask, &mask_attr);
+ if (CAIRO_OK (status))
+ pixman_composite (_pixman_operator (operator),
+ src->pixman_image,
+ mask->pixman_image,
+ dst->pixman_image,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ mask_x + mask_attr.x_offset,
+ mask_y + mask_attr.y_offset,
+ dst_x, dst_y,
+ width, height);
+ }
+ else
+ {
+ pixman_composite (_pixman_operator (operator),
+ src->pixman_image,
+ NULL,
+ dst->pixman_image,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ }
}
- pixman_composite (_pixman_operator (operator),
- src->pixman_image,
- mask ? mask->pixman_image : NULL,
- dst->pixman_image,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
-
- return CAIRO_STATUS_SUCCESS;
+ if (mask)
+ _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
+
+ _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
+
+ return status;
}
static cairo_int_status_t
@@ -427,24 +547,56 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
static cairo_int_status_t
_cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *generic_src,
+ cairo_pattern_t *pattern,
void *abstract_dst,
- int x_src,
- int y_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
- cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_t *src = (cairo_image_surface_t *) generic_src;
+ cairo_surface_attributes_t attributes;
+ cairo_image_surface_t *dst = abstract_dst;
+ cairo_image_surface_t *src;
+ cairo_int_status_t status;
+ int render_reference_x, render_reference_y;
+ int render_src_x, render_src_y;
+
+ status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ src_x, src_y, width, height,
+ (cairo_surface_t **) &src,
+ &attributes);
+ if (status)
+ return status;
+
+ if (traps[0].left.p1.y < traps[0].left.p2.y) {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
+ } else {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
+ }
- if (generic_src->backend != dst->base.backend)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ render_src_x = src_x + render_reference_x - dst_x;
+ render_src_y = src_y + render_reference_y - dst_y;
- /* XXX: The pixman_trapezoid_t cast is evil and needs to go away somehow. */
- pixman_composite_trapezoids (operator, src->pixman_image, dst->pixman_image,
- x_src, y_src, (pixman_trapezoid_t *) traps, num_traps);
+ /* XXX: The pixman_trapezoid_t cast is evil and needs to go away
+ * somehow. */
+ status = _cairo_image_surface_set_attributes (src, &attributes);
+ if (CAIRO_OK (status))
+ pixman_composite_trapezoids (operator,
+ src->pixman_image,
+ dst->pixman_image,
+ render_src_x + attributes.x_offset,
+ render_src_y + attributes.y_offset,
+ (pixman_trapezoid_t *) traps, num_traps);
- return CAIRO_STATUS_SUCCESS;
+ _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
+
+ return status;
}
static cairo_int_status_t
@@ -490,41 +642,34 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_image_abstract_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *box)
+/**
+ * _cairo_surface_is_image:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is an #cairo_image_surface_t
+ *
+ * Return value: True if the surface is an image surface
+ **/
+int
+_cairo_surface_is_image (cairo_surface_t *surface)
{
- cairo_image_surface_t *image;
-
- /* Fall back to general pattern creation for surface patterns. */
- if (pattern->type == CAIRO_PATTERN_SURFACE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- image = _cairo_pattern_get_image (pattern, box);
- if (image) {
- pattern->source = &image->base;
-
- return CAIRO_STATUS_SUCCESS;
- } else
- return CAIRO_STATUS_NO_MEMORY;
+ return surface->backend == &cairo_image_surface_backend;
}
-
+
static const cairo_surface_backend_t cairo_image_surface_backend = {
_cairo_image_surface_create_similar,
_cairo_image_abstract_surface_destroy,
_cairo_image_surface_pixels_per_inch,
- _cairo_image_surface_get_image,
- _cairo_image_surface_set_image,
- _cairo_image_abstract_surface_set_matrix,
- _cairo_image_abstract_surface_set_filter,
- _cairo_image_abstract_surface_set_repeat,
+ _cairo_image_surface_acquire_source_image,
+ _cairo_image_surface_release_source_image,
+ _cairo_image_surface_acquire_dest_image,
+ _cairo_image_surface_release_dest_image,
+ _cairo_image_surface_clone_similar,
_cairo_image_surface_composite,
_cairo_image_surface_fill_rectangles,
_cairo_image_surface_composite_trapezoids,
_cairo_image_surface_copy_page,
_cairo_image_surface_show_page,
_cairo_image_abstract_surface_set_clip_region,
- _cairo_image_abstract_surface_create_pattern,
NULL /* show_glyphs */
};
diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c
index b964b688c..88e536e8a 100644
--- a/src/cairo_matrix.c
+++ b/src/cairo_matrix.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#define _GNU_SOURCE
@@ -54,6 +54,14 @@ _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
+/**
+ * cairo_matrix_create:
+ *
+ * Creates a new identity matrix.
+ *
+ * Return value: a newly created matrix; free with cairo_matrix_destroy(),
+ * or %NULL if memory couldn't be allocated.
+ **/
cairo_matrix_t *
cairo_matrix_create (void)
{
@@ -80,6 +88,12 @@ _cairo_matrix_fini (cairo_matrix_t *matrix)
/* nothing to do here */
}
+/**
+ * cairo_matrix_destroy:
+ * @matrix: a #cairo_matrix_t
+ *
+ * Frees a matrix created with cairo_matrix_create.
+ **/
void
cairo_matrix_destroy (cairo_matrix_t *matrix)
{
@@ -87,6 +101,15 @@ cairo_matrix_destroy (cairo_matrix_t *matrix)
free (matrix);
}
+/**
+ * cairo_matrix_copy:
+ * @matrix: a #cairo_matrix_t
+ * @other: another #cairo_
+ *
+ * Modifies @matrix to be identical to @other.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
{
@@ -96,6 +119,14 @@ cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
}
slim_hidden_def(cairo_matrix_copy);
+/**
+ * cairo_matrix_set_identity:
+ * @matrix: a #cairo_matrix_t
+ *
+ * Modifies @matrix to be an identity transformation.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_set_identity (cairo_matrix_t *matrix)
{
@@ -105,6 +136,26 @@ cairo_matrix_set_identity (cairo_matrix_t *matrix)
}
slim_hidden_def(cairo_matrix_set_identity);
+/**
+ * cairo_matrix_set_affine:
+ * @matrix: a cairo_matrix_t
+ * @a: a component of the affine transformation
+ * @b: b component of the affine transformation
+ * @c: c component of the affine transformation
+ * @d: d component of the affine transformation
+ * @tx: X translation component of the affine transformation
+ * @ty: Y translation component of the affine transformation
+ *
+ * Sets @matrix to be the affine transformation given by
+ * @a, b, @c, @d, @tx, @ty. The transformation is given
+ * by:
+ * <programlisting>
+ * x_new = x * a + y * c + tx;
+ * y_new = x * b + y * d + ty;
+ * </programlisting>
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_set_affine (cairo_matrix_t *matrix,
double a, double b,
@@ -119,6 +170,21 @@ cairo_matrix_set_affine (cairo_matrix_t *matrix,
}
slim_hidden_def(cairo_matrix_set_affine);
+/**
+ * cairo_matrix_get_affine:
+ * @matrix: a @cairo_matrix_t
+ * @a: location to store a component of affine transformation, or %NULL
+ * @b: location to store b component of affine transformation, or %NULL
+ * @c: location to store c component of affine transformation, or %NULL
+ * @d: location to store d component of affine transformation, or %NULL
+ * @tx: location to store X-translation component of affine transformation, or %NULL
+ * @ty: location to store Y-translation component of affine transformation, or %NULL
+ *
+ * Gets the matrix values for the affine tranformation that @matrix represents.
+ * See cairo_matrix_set_affine().
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_get_affine (cairo_matrix_t *matrix,
double *a, double *b,
@@ -153,6 +219,18 @@ _cairo_matrix_set_translate (cairo_matrix_t *matrix,
tx, ty);
}
+/**
+ * cairo_matrix_translate:
+ * @matrix: a cairo_matrix_t
+ * @tx: amount to rotate in the X direction
+ * @ty: amount to rotate in the Y direction
+ *
+ * Applies a translation by @tx, @ty to the transformation in
+ * @matrix. The new transformation is given by first translating by
+ * @tx, @ty then applying the original transformation
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
{
@@ -173,6 +251,18 @@ _cairo_matrix_set_scale (cairo_matrix_t *matrix,
0, 0);
}
+/**
+ * cairo_matrix_scale:
+ * @matrix: a #cairo_matrix_t
+ * @sx: Scale factor in the X direction
+ * @sy: Scale factor in the Y direction
+ *
+ * Applies scaling by @tx, @ty to the transformation in
+ * @matrix. The new transformation is given by first scaling by @sx
+ * and @sy then applying the original transformation
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
{
@@ -202,6 +292,21 @@ _cairo_matrix_set_rotate (cairo_matrix_t *matrix,
0, 0);
}
+/**
+ * cairo_matrix_rotate:
+ * @matrix: a @cairo_matrix_t
+ * @radians: angle of rotation, in radians. Angles are defined
+ * so that an angle of 90 degrees (%M_PI radians) rotates the
+ * positive X axis into the positive Y axis. With the default
+ * Cairo choice of axis orientation, positive rotations are
+ * clockwise.
+ *
+ * Applies rotation by @radians to the transformation in
+ * @matrix. The new transformation is given by first rotating by
+ * @radians then applying the original transformation
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
{
@@ -212,6 +317,19 @@ cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
return cairo_matrix_multiply (matrix, &tmp, matrix);
}
+/**
+ * cairo_matrix_multiply:
+ * @result: a @cairo_matrix_t in which to store the result
+ * @a: a @cairo_matrix_t
+ * @b: a @cairo_matrix_t
+ *
+ * Multiplies the affine transformations in @a and @b together
+ * and stores the result in @result. The resulting transformation
+ * is given by first applying the transformation in @b then
+ * applying the transformation in @a.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
{
@@ -238,6 +356,27 @@ cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const ca
}
slim_hidden_def(cairo_matrix_multiply);
+/**
+ * cairo_matrix_transform_distance:
+ * @matrix: a @cairo_matrix_t
+ * @dx: a distance in the X direction. An in/out parameter
+ * @dy: a distance in the Y direction. An in/out parameter
+ *
+ * Transforms the vector (@dx,@dy) by @matrix. Translation is
+ * ignored. In terms of the components of the affine transformation:
+ *
+ * <programlisting>
+ * dx2 = dx1 * a + dy1 * c;
+ * dy2 = dx1 * b + dy1 * d;
+ * </programlisting>
+ *
+ * Affine transformations are position invariant, so the same vector
+ * always transforms to the same vector. If (@x1,@y1) transforms
+ * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
+ * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
{
@@ -255,6 +394,16 @@ cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
}
slim_hidden_def(cairo_matrix_transform_distance);
+/**
+ * cairo_matrix_transform_point:
+ * @matrix: a @cairo_matrix_t
+ * @x: X position. An in/out parameter
+ * @y: Y position. An in/out parameter
+ *
+ * Transforms the point (@x, @y) by @matrix.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS, always.
+ **/
cairo_status_t
cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y)
{
@@ -351,6 +500,19 @@ _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
c*ty - d*tx, b*tx - a*ty);
}
+/**
+ * cairo_matrix_invert:
+ * @matrix: a @cairo_matrix_t
+ *
+ * Changes @matrix to be the inverse of it's original value. Not
+ * all transformation matrices have inverses; if the matrix
+ * collapses points together (it is <firstterm>degenerate</firstterm>),
+ * then it has no inverse and this function will fail.
+ *
+ * Returns: If @matrix has an inverse, modifies @matrix to
+ * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise,
+ * returns %CAIRO_STATUS_INVALID_MATRIX.
+ **/
cairo_status_t
cairo_matrix_invert (cairo_matrix_t *matrix)
{
@@ -458,7 +620,7 @@ _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double
return CAIRO_STATUS_SUCCESS;
}
-int
+cairo_bool_t
_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
int *itx, int *ity)
{
@@ -477,7 +639,7 @@ _cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
if (ok) {
*itx = _cairo_fixed_integer_part(ttx);
*ity = _cairo_fixed_integer_part(tty);
- return 1;
+ return TRUE;
}
- return 0;
+ return FALSE;
}
diff --git a/src/cairo_path.c b/src/cairo_path.c
index 36c25d637..8314f601c 100644
--- a/src/cairo_path.c
+++ b/src/cairo_path.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include <stdlib.h>
@@ -100,6 +100,7 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
for (other_op = other->op_head; other_op; other_op = other_op->next) {
op = _cairo_path_op_buf_create ();
if (op == NULL) {
+ _cairo_path_fini(path);
return CAIRO_STATUS_NO_MEMORY;
}
*op = *other_op;
@@ -109,6 +110,7 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) {
arg = _cairo_path_arg_buf_create ();
if (arg == NULL) {
+ _cairo_path_fini(path);
return CAIRO_STATUS_NO_MEMORY;
}
*arg = *other_arg;
diff --git a/src/cairo_path_bounds.c b/src/cairo_path_bounds.c
index cfcdd97ee..7c5772a82 100644
--- a/src/cairo_path_bounds.c
+++ b/src/cairo_path_bounds.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo_path_fill.c b/src/cairo_path_fill.c
index 6c6ebd976..dc79b6b96 100644
--- a/src/cairo_path_fill.c
+++ b/src/cairo_path_fill.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo_path_stroke.c b/src/cairo_path_stroke.c
index ad0220370..08b380902 100644
--- a/src/cairo_path_stroke.c
+++ b/src/cairo_path_stroke.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo_pattern.c b/src/cairo_pattern.c
index 6cb981458..283c36dbd 100644
--- a/src/cairo_pattern.c
+++ b/src/cairo_pattern.c
@@ -21,58 +21,108 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * Author: David Reveman <c99drn@cs.umu.se>
+ * Author: David Reveman <davidr@novell.com>
*/
#include "cairoint.h"
+typedef void (*cairo_shader_function_t) (unsigned char *color0,
+ unsigned char *color1,
+ cairo_fixed_t factor,
+ uint32_t *pixel);
+
+typedef struct _cairo_shader_color_stop {
+ cairo_fixed_t offset;
+ cairo_fixed_48_16_t scale;
+ int id;
+ unsigned char color_char[4];
+} cairo_shader_color_stop_t;
+
+typedef struct _cairo_shader_op {
+ cairo_shader_color_stop_t *stops;
+ int n_stops;
+ cairo_extend_t extend;
+ cairo_shader_function_t shader_function;
+} cairo_shader_op_t;
+
#define MULTIPLY_COLORCOMP(c1, c2) \
((unsigned char) \
((((unsigned char) (c1)) * (int) ((unsigned char) (c2))) / 0xff))
-void
-_cairo_pattern_init (cairo_pattern_t *pattern)
+static void
+_cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
{
+ pattern->type = type;
pattern->ref_count = 1;
-
- pattern->extend = CAIRO_EXTEND_DEFAULT;
- pattern->filter = CAIRO_FILTER_DEFAULT;
-
- _cairo_color_init (&pattern->color);
+ pattern->extend = CAIRO_EXTEND_DEFAULT;
+ pattern->filter = CAIRO_FILTER_DEFAULT;
+ pattern->alpha = 1.0;
_cairo_matrix_init (&pattern->matrix);
+}
- pattern->stops = NULL;
- pattern->n_stops = 0;
+static cairo_status_t
+_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
+ cairo_gradient_pattern_t *other)
+{
+ if (other->base.type == CAIRO_PATTERN_LINEAR)
+ {
+ cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern;
+ cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other;
+
+ *dst = *src;
+ }
+ else
+ {
+ cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern;
+ cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other;
+
+ *dst = *src;
+ }
- pattern->type = CAIRO_PATTERN_SOLID;
+ if (other->n_stops)
+ {
+ pattern->stops = malloc (other->n_stops * sizeof (cairo_color_stop_t));
+ if (!pattern->stops)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ memcpy (pattern->stops, other->stops,
+ other->n_stops * sizeof (cairo_color_stop_t));
+ }
- pattern->source = NULL;
- pattern->source_offset.x = 0.0;
- pattern->source_offset.y = 0.0;
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other)
{
- *pattern = *other;
-
- pattern->ref_count = 1;
+ switch (other->type) {
+ case CAIRO_PATTERN_SOLID: {
+ cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern;
+ cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other;
- if (pattern->n_stops) {
- pattern->stops =
- malloc (sizeof (cairo_color_stop_t) * pattern->n_stops);
- if (pattern->stops == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- memcpy (pattern->stops, other->stops,
- sizeof (cairo_color_stop_t) * other->n_stops);
+ *dst = *src;
+ } break;
+ case CAIRO_PATTERN_SURFACE: {
+ cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern;
+ cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other;
+
+ *dst = *src;
+ cairo_surface_reference (dst->surface);
+ } break;
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern;
+ cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other;
+ cairo_status_t status;
+
+ status = _cairo_gradient_pattern_init_copy (dst, src);
+ if (status)
+ return status;
+ } break;
}
-
- if (pattern->source)
- cairo_surface_reference (other->source);
-
- if (pattern->type == CAIRO_PATTERN_SURFACE)
- cairo_surface_reference (other->u.surface.surface);
+
+ pattern->ref_count = 1;
return CAIRO_STATUS_SUCCESS;
}
@@ -80,110 +130,145 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other)
void
_cairo_pattern_fini (cairo_pattern_t *pattern)
{
- if (pattern->n_stops)
- free (pattern->stops);
-
- if (pattern->type == CAIRO_PATTERN_SURFACE) {
- /* show_surface require us to restore surface matrix, repeat
- attribute, filter type */
- if (pattern->source) {
- cairo_surface_set_matrix (pattern->source,
- &pattern->u.surface.save_matrix);
- cairo_surface_set_repeat (pattern->source,
- pattern->u.surface.save_repeat);
- cairo_surface_set_filter (pattern->source,
- pattern->u.surface.save_filter);
- }
- cairo_surface_destroy (pattern->u.surface.surface);
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SOLID:
+ break;
+ case CAIRO_PATTERN_SURFACE: {
+ cairo_surface_pattern_t *fini = (cairo_surface_pattern_t *) pattern;
+
+ cairo_surface_destroy (fini->surface);
+ } break;
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ cairo_gradient_pattern_t *fini = (cairo_gradient_pattern_t *) pattern;
+
+ if (fini->n_stops)
+ free (fini->stops);
+ } break;
}
+}
+
+void
+_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
+ double red,
+ double green,
+ double blue)
+{
+ _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SOLID);
- if (pattern->source)
- cairo_surface_destroy (pattern->source);
+ pattern->red = red;
+ pattern->green = green;
+ pattern->blue = blue;
}
void
-_cairo_pattern_init_solid (cairo_pattern_t *pattern,
- double red, double green, double blue)
+_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
+ cairo_surface_t *surface)
{
- _cairo_pattern_init (pattern);
+ _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SURFACE);
+
+ pattern->surface = surface;
+ cairo_surface_reference (surface);
+}
- pattern->type = CAIRO_PATTERN_SOLID;
- _cairo_color_set_rgb (&pattern->color, red, green, blue);
+static void
+_cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern,
+ cairo_pattern_type_t type)
+{
+ _cairo_pattern_init (&pattern->base, type);
+
+ pattern->stops = 0;
+ pattern->n_stops = 0;
+}
+
+void
+_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
+ double x0, double y0, double x1, double y1)
+{
+ _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_LINEAR);
+
+ pattern->point0.x = x0;
+ pattern->point0.y = y0;
+ pattern->point1.x = x1;
+ pattern->point1.y = y1;
+}
+
+void
+_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
+ double cx0, double cy0, double radius0,
+ double cx1, double cy1, double radius1)
+{
+ _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_RADIAL);
+
+ pattern->center0.x = cx0;
+ pattern->center0.y = cy0;
+ pattern->radius0 = fabs (radius0);
+ pattern->center1.x = cx1;
+ pattern->center1.y = cy1;
+ pattern->radius1 = fabs (radius1);
}
cairo_pattern_t *
_cairo_pattern_create_solid (double red, double green, double blue)
{
- cairo_pattern_t *pattern;
+ cairo_solid_pattern_t *pattern;
- pattern = malloc (sizeof (cairo_pattern_t));
+ pattern = malloc (sizeof (cairo_solid_pattern_t));
if (pattern == NULL)
return NULL;
_cairo_pattern_init_solid (pattern, red, green, blue);
- return pattern;
+ return &pattern->base;
}
cairo_pattern_t *
cairo_pattern_create_for_surface (cairo_surface_t *surface)
{
- cairo_pattern_t *pattern;
+ cairo_surface_pattern_t *pattern;
- pattern = malloc (sizeof (cairo_pattern_t));
+ pattern = malloc (sizeof (cairo_surface_pattern_t));
if (pattern == NULL)
return NULL;
- _cairo_pattern_init (pattern);
-
- pattern->type = CAIRO_PATTERN_SURFACE;
- pattern->u.surface.surface = surface;
- cairo_surface_reference (surface);
+ _cairo_pattern_init_for_surface (pattern, surface);
+
+ /* this will go away when we completely remove the surface attributes */
+ if (surface->repeat)
+ pattern->base.extend = CAIRO_EXTEND_REPEAT;
+ else
+ pattern->base.extend = CAIRO_EXTEND_DEFAULT;
- return pattern;
+ return &pattern->base;
}
cairo_pattern_t *
cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
{
- cairo_pattern_t *pattern;
+ cairo_linear_pattern_t *pattern;
- pattern = malloc (sizeof (cairo_pattern_t));
+ pattern = malloc (sizeof (cairo_linear_pattern_t));
if (pattern == NULL)
return NULL;
- _cairo_pattern_init (pattern);
-
- pattern->type = CAIRO_PATTERN_LINEAR;
- pattern->u.linear.point0.x = x0;
- pattern->u.linear.point0.y = y0;
- pattern->u.linear.point1.x = x1;
- pattern->u.linear.point1.y = y1;
+ _cairo_pattern_init_linear (pattern, x0, y0, x1, y1);
- return pattern;
+ return &pattern->base.base;
}
cairo_pattern_t *
cairo_pattern_create_radial (double cx0, double cy0, double radius0,
double cx1, double cy1, double radius1)
{
- cairo_pattern_t *pattern;
+ cairo_radial_pattern_t *pattern;
- pattern = malloc (sizeof (cairo_pattern_t));
+ pattern = malloc (sizeof (cairo_radial_pattern_t));
if (pattern == NULL)
return NULL;
- _cairo_pattern_init (pattern);
-
- pattern->type = CAIRO_PATTERN_RADIAL;
- pattern->u.radial.center0.x = cx0;
- pattern->u.radial.center0.y = cy0;
- pattern->u.radial.radius0 = fabs (radius0);
- pattern->u.radial.center1.x = cx1;
- pattern->u.radial.center1.y = cy1;
- pattern->u.radial.radius1 = fabs (radius1);
+ _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1);
- return pattern;
+ return &pattern->base.base;
}
void
@@ -209,37 +294,19 @@ cairo_pattern_destroy (cairo_pattern_t *pattern)
free (pattern);
}
-static int
-_cairo_pattern_stop_compare (const void *elem1, const void *elem2)
-{
- return
- (((cairo_color_stop_t *) elem1)->offset ==
- ((cairo_color_stop_t *) elem2)->offset) ?
- /* equal offsets, sort on id */
- ((((cairo_color_stop_t *) elem1)->id <
- ((cairo_color_stop_t *) elem2)->id) ? -1 : 1) :
- /* sort on offset */
- ((((cairo_color_stop_t *) elem1)->offset <
- ((cairo_color_stop_t *) elem2)->offset) ? -1 : 1);
-}
-
-cairo_status_t
-cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
- double offset,
- double red, double green, double blue,
- double alpha)
+static cairo_status_t
+_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
+ double offset,
+ double red,
+ double green,
+ double blue,
+ double alpha)
{
cairo_color_stop_t *stop;
- int i;
-
- _cairo_restrict_value (&offset, 0.0, 1.0);
- _cairo_restrict_value (&red, 0.0, 1.0);
- _cairo_restrict_value (&green, 0.0, 1.0);
- _cairo_restrict_value (&blue, 0.0, 1.0);
pattern->n_stops++;
pattern->stops = realloc (pattern->stops,
- sizeof (cairo_color_stop_t) * pattern->n_stops);
+ pattern->n_stops * sizeof (cairo_color_stop_t));
if (pattern->stops == NULL) {
pattern->n_stops = 0;
@@ -249,41 +316,51 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
stop = &pattern->stops[pattern->n_stops - 1];
stop->offset = _cairo_fixed_from_double (offset);
- stop->id = pattern->n_stops;
- stop->color_char[0] = red * 0xff;
- stop->color_char[1] = green * 0xff;
- stop->color_char[2] = blue * 0xff;
- stop->color_char[3] = alpha * 0xff;
+ _cairo_color_init (&stop->color);
+ _cairo_color_set_rgb (&stop->color, red, green, blue);
+ _cairo_color_set_alpha (&stop->color, alpha);
- /* sort stops in ascending order */
- qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t),
- _cairo_pattern_stop_compare);
-
- for (i = 0; i < pattern->n_stops - 1; i++) {
- pattern->stops[i + 1].scale =
- pattern->stops[i + 1].offset - pattern->stops[i].offset;
- if (pattern->stops[i + 1].scale == 65536)
- pattern->stops[i + 1].scale = 0;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
+ double offset,
+ double red,
+ double green,
+ double blue,
+ double alpha)
+{
+ if (pattern->type != CAIRO_PATTERN_LINEAR &&
+ pattern->type != CAIRO_PATTERN_RADIAL)
+ {
+ /* XXX: CAIRO_STATUS_INVALID_PATTERN? */
+ return CAIRO_STATUS_SUCCESS;
}
- return CAIRO_STATUS_SUCCESS;
+ _cairo_restrict_value (&offset, 0.0, 1.0);
+ _cairo_restrict_value (&red, 0.0, 1.0);
+ _cairo_restrict_value (&green, 0.0, 1.0);
+ _cairo_restrict_value (&blue, 0.0, 1.0);
+ _cairo_restrict_value (&alpha, 0.0, 1.0);
+
+ return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
+ offset,
+ red, green, blue,
+ alpha);
}
cairo_status_t
cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
{
- cairo_matrix_copy (&pattern->matrix, matrix);
-
- return CAIRO_STATUS_SUCCESS;
+ return cairo_matrix_copy (&pattern->matrix, matrix);
}
cairo_status_t
cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
{
- cairo_matrix_copy (matrix, &pattern->matrix);
-
- return CAIRO_STATUS_SUCCESS;
+ return cairo_matrix_copy (matrix, &pattern->matrix);
}
cairo_status_t
@@ -316,9 +393,20 @@ cairo_pattern_get_extend (cairo_pattern_t *pattern)
cairo_status_t
_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
- double *red, double *green, double *blue)
+ double *red,
+ double *green,
+ double *blue)
{
- _cairo_color_get_rgb (&pattern->color, red, green, blue);
+
+ if (pattern->type == CAIRO_PATTERN_SOLID)
+ {
+ cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
+
+ *red = solid->red;
+ *green = solid->green;
+ *blue = solid->blue;
+ } else
+ *red = *green = *blue = 1.0;
return CAIRO_STATUS_SUCCESS;
}
@@ -326,63 +414,16 @@ _cairo_pattern_get_rgb (cairo_pattern_t *pattern,
void
_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha)
{
- int i;
-
- _cairo_color_set_alpha (&pattern->color, alpha);
-
- for (i = 0; i < pattern->n_stops; i++)
- pattern->stops[i].color_char[3] =
- MULTIPLY_COLORCOMP (pattern->stops[i].color_char[3], alpha * 0xff);
-}
-
-void
-_cairo_pattern_set_source_offset (cairo_pattern_t *pattern,
- double x, double y)
-{
- pattern->source_offset.x = x;
- pattern->source_offset.y = y;
+ pattern->alpha = alpha;
}
void
_cairo_pattern_transform (cairo_pattern_t *pattern,
- cairo_matrix_t *ctm_inverse)
+ cairo_matrix_t *ctm_inverse)
{
cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
}
-void
-_cairo_pattern_prepare_surface (cairo_pattern_t *pattern)
-{
- cairo_matrix_t device_to_source;
- cairo_matrix_t user_to_source;
-
- /* should the surface matrix interface be remove from the API?
- for now we multiple the surface matrix with the pattern matrix */
- cairo_surface_get_matrix (pattern->u.surface.surface, &user_to_source);
- cairo_matrix_multiply (&device_to_source, &pattern->matrix,
- &user_to_source);
- cairo_surface_set_matrix (pattern->source, &device_to_source);
-
- /* storing original surface matrix in pattern */
- pattern->u.surface.save_matrix = user_to_source;
-
- /* storing original surface repeat mode in pattern */
- pattern->u.surface.save_repeat = pattern->source->repeat;
-
- /* what do we do with extend types pad and reflect? */
- if (pattern->extend == CAIRO_EXTEND_REPEAT
- || pattern->source->repeat == 1)
- cairo_surface_set_repeat (pattern->source, 1);
- else
- cairo_surface_set_repeat (pattern->source, 0);
-
- /* storing original surface filter in pattern */
- pattern->u.surface.save_filter =
- cairo_surface_get_filter (pattern->source);
-
- cairo_surface_set_filter (pattern->source, pattern->filter);
-}
-
#define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \
((factor < 32768)? c1: c2)
@@ -390,7 +431,7 @@ static void
_cairo_pattern_shader_nearest (unsigned char *color0,
unsigned char *color1,
cairo_fixed_t factor,
- int *pixel)
+ uint32_t *pixel)
{
*pixel =
((INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor) << 24) |
@@ -408,7 +449,7 @@ static void
_cairo_pattern_shader_linear (unsigned char *color0,
unsigned char *color1,
cairo_fixed_t factor,
- int *pixel)
+ uint32_t *pixel)
{
*pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) |
(INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) |
@@ -422,7 +463,7 @@ static void
_cairo_pattern_shader_gaussian (unsigned char *color0,
unsigned char *color1,
cairo_fixed_t factor,
- int *pixel)
+ uint32_t *pixel)
{
double f = ((double) factor) / 65536.0;
@@ -436,17 +477,59 @@ _cairo_pattern_shader_gaussian (unsigned char *color0,
#undef INTERPOLATE_COLOR_LINEAR
-void
-_cairo_pattern_shader_init (cairo_pattern_t *pattern,
- cairo_shader_op_t *op)
-{
- op->stops = pattern->stops;
- op->n_stops = pattern->n_stops - 1;
- op->min_offset = pattern->stops[0].offset;
- op->max_offset = pattern->stops[op->n_stops].offset;
- op->extend = pattern->extend;
-
- switch (pattern->filter) {
+static int
+_cairo_shader_color_stop_compare (const void *elem1, const void *elem2)
+{
+ cairo_shader_color_stop_t *s1 = (cairo_shader_color_stop_t *) elem1;
+ cairo_shader_color_stop_t *s2 = (cairo_shader_color_stop_t *) elem2;
+
+ return
+ (s1->offset == s2->offset) ?
+ /* equal offsets, sort on id */
+ ((s1->id < s2->id) ? -1 : 1) :
+ /* sort on offset */
+ ((s1->offset < s2->offset) ? -1 : 1);
+}
+
+static cairo_status_t
+_cairo_pattern_shader_init (cairo_gradient_pattern_t *pattern,
+ cairo_shader_op_t *op)
+{
+ int i;
+
+ op->stops = malloc (pattern->n_stops * sizeof (cairo_shader_color_stop_t));
+ if (!op->stops)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ for (i = 0; i < pattern->n_stops; i++)
+ {
+ op->stops[i].color_char[0] = pattern->stops[i].color.red * 0xff;
+ op->stops[i].color_char[1] = pattern->stops[i].color.green * 0xff;
+ op->stops[i].color_char[2] = pattern->stops[i].color.blue * 0xff;
+ op->stops[i].color_char[3] = pattern->stops[i].color.alpha *
+ pattern->base.alpha * 0xff;
+ op->stops[i].offset = pattern->stops[i].offset;
+ op->stops[i].id = i;
+ }
+
+ /* sort stops in ascending order */
+ qsort (op->stops, pattern->n_stops, sizeof (cairo_shader_color_stop_t),
+ _cairo_shader_color_stop_compare);
+
+ for (i = 0; i < pattern->n_stops - 1; i++)
+ {
+ op->stops[i + 1].scale = op->stops[i + 1].offset - op->stops[i].offset;
+ if (op->stops[i + 1].scale == 65536)
+ op->stops[i + 1].scale = 0;
+ }
+
+ op->n_stops = pattern->n_stops;
+ op->extend = pattern->base.extend;
+
+ /* XXX: this is wrong, the filter should not be used for selecting
+ color stop interpolation function. function should always be 'linear'
+ and filter should be used for computing pixels. */
+ switch (pattern->base.filter) {
case CAIRO_FILTER_FAST:
case CAIRO_FILTER_NEAREST:
op->shader_function = _cairo_pattern_shader_nearest;
@@ -460,15 +543,56 @@ _cairo_pattern_shader_init (cairo_pattern_t *pattern,
op->shader_function = _cairo_pattern_shader_linear;
break;
}
+
+ return CAIRO_STATUS_SUCCESS;
}
-void
-_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
- cairo_fixed_t factor,
- int *pixel)
+static void
+_cairo_pattern_shader_fini (cairo_shader_op_t *op)
+{
+ if (op->stops)
+ free (op->stops);
+}
+
+/* Find two color stops bounding the given offset. If the given offset
+ * is before the first or after the last stop offset, the nearest
+ * offset is returned twice.
+ */
+static void
+_cairo_shader_op_find_color_stops (cairo_shader_op_t *op,
+ cairo_fixed_t offset,
+ cairo_shader_color_stop_t *stops[2])
{
int i;
-
+
+ /* Before first stop. */
+ if (offset <= op->stops[0].offset) {
+ stops[0] = &op->stops[0];
+ stops[1] = &op->stops[0];
+ return;
+ }
+
+ /* Between two stops. */
+ for (i = 0; i < op->n_stops - 1; i++) {
+ if (offset <= op->stops[i + 1].offset) {
+ stops[0] = &op->stops[i];
+ stops[1] = &op->stops[i + 1];
+ return;
+ }
+ }
+
+ /* After last stop. */
+ stops[0] = &op->stops[op->n_stops - 1];
+ stops[1] = &op->stops[op->n_stops - 1];
+}
+
+static void
+_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
+ cairo_fixed_t factor,
+ uint32_t *pixel)
+{
+ cairo_shader_color_stop_t *stops[2];
+
switch (op->extend) {
case CAIRO_EXTEND_REPEAT:
factor -= factor & 0xffff0000;
@@ -485,96 +609,158 @@ _cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
break;
}
- if (factor < op->min_offset)
- factor = op->min_offset;
- else if (factor > op->max_offset)
- factor = op->max_offset;
-
- for (i = 0; i < op->n_stops; i++) {
- if (factor <= op->stops[i + 1].offset) {
-
- /* take offset as new 0 of coordinate system */
- factor -= op->stops[i].offset;
-
- /* difference between two offsets == 0, abrubt change */
- if (op->stops[i + 1].scale)
- factor = ((cairo_fixed_48_16_t) factor << 16) /
- op->stops[i + 1].scale;
+ _cairo_shader_op_find_color_stops (op, factor, stops);
+
+ /* take offset as new 0 of coordinate system */
+ factor -= stops[0]->offset;
- op->shader_function (op->stops[i].color_char,
- op->stops[i + 1].color_char,
- factor, pixel);
+ /* difference between two offsets == 0, abrubt change */
+ if (stops[1]->scale)
+ factor = ((cairo_fixed_48_16_t) factor << 16) /
+ stops[1]->scale;
+
+ op->shader_function (stops[0]->color_char,
+ stops[1]->color_char,
+ factor, pixel);
- /* multiply alpha */
- if (((unsigned char) (*pixel >> 24)) != 0xff) {
- *pixel = (*pixel & 0xff000000) |
- (MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) |
- (MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) |
- (MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0);
- }
- break;
- }
+ /* multiply alpha */
+ if (((unsigned char) (*pixel >> 24)) != 0xff) {
+ *pixel = (*pixel & 0xff000000) |
+ (MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) |
+ (MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) |
+ (MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0);
}
}
-static void
-_cairo_image_data_set_linear (cairo_pattern_t *pattern,
- double offset_x,
- double offset_y,
- int *pixels,
- int width,
- int height)
+static cairo_status_t
+_cairo_image_data_set_linear (cairo_linear_pattern_t *pattern,
+ double offset_x,
+ double offset_y,
+ uint32_t *pixels,
+ int width,
+ int height)
{
int x, y;
cairo_point_double_t point0, point1;
- double px, py, ex, ey;
double a, b, c, d, tx, ty;
- double length, start, angle, fx, fy, factor;
+ double scale, start, dx, dy, factor;
cairo_shader_op_t op;
-
- _cairo_pattern_shader_init (pattern, &op);
-
- point0.x = pattern->u.linear.point0.x;
- point0.y = pattern->u.linear.point0.y;
- point1.x = pattern->u.linear.point1.x;
- point1.y = pattern->u.linear.point1.y;
-
- cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty);
-
- length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) +
- (point1.y - point0.y) * (point1.y - point0.y));
- length = (length) ? 1.0 / length : CAIRO_MAXSHORT;
-
- angle = -atan2 (point1.y - point0.y, point1.x - point0.x);
- fx = cos (angle);
- fy = -sin (angle);
-
- start = fx * point0.x;
- start += fy * point0.y;
+ cairo_status_t status;
+
+ status = _cairo_pattern_shader_init (&pattern->base, &op);
+ if (status)
+ return status;
+
+ /* We compute the position in the linear gradient for
+ * a point q as:
+ *
+ * [q . (p1 - p0) - p0 . (p1 - p0)] / (p1 - p0) ^ 2
+ *
+ * The computation is done in pattern space. The
+ * calculation could be heavily optimized by using the
+ * fact that 'factor' increases linearly in both
+ * directions.
+ */
+ point0.x = pattern->point0.x;
+ point0.y = pattern->point0.y;
+ point1.x = pattern->point1.x;
+ point1.y = pattern->point1.y;
+
+ cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
+
+ dx = point1.x - point0.x;
+ dy = point1.y - point0.y;
+ scale = dx * dx + dy * dy;
+ scale = (scale) ? 1.0 / scale : 1.0;
+
+ start = dx * point0.x + dy * point0.y;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
- px = x + offset_x;
- py = y + offset_y;
+ double qx_device = x + offset_x;
+ double qy_device = y + offset_y;
- /* transform fragment */
- ex = a * px + c * py + tx;
- ey = b * px + d * py + ty;
+ /* transform fragment into pattern space */
+ double qx = a * qx_device + c * qy_device + tx;
+ double qy = b * qx_device + d * qy_device + ty;
- factor = ((fx * ex + fy * ey) - start) * length;
+ factor = ((dx * qx + dy * qy) - start) * scale;
_cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
}
}
+
+ _cairo_pattern_shader_fini (&op);
+
+ return CAIRO_STATUS_SUCCESS;
}
static void
-_cairo_image_data_set_radial (cairo_pattern_t *pattern,
- double offset_x,
- double offset_y,
- int *pixels,
- int width,
- int height)
+_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
+ double offset_x,
+ double offset_y,
+ int width,
+ int height,
+ cairo_bool_t *is_horizontal,
+ cairo_bool_t *is_vertical)
+{
+ cairo_point_double_t point0, point1;
+ double a, b, c, d, tx, ty;
+ double scale, start, dx, dy;
+ cairo_fixed_t factors[3];
+ int i;
+
+ /* To classidy a pattern as horizontal or vertical, we first
+ * compute the (fixed point) factors at the corners of the
+ * pattern. We actually only need 3/4 corners, so we skip the
+ * fourth.
+ */
+ point0.x = pattern->point0.x;
+ point0.y = pattern->point0.y;
+ point1.x = pattern->point1.x;
+ point1.y = pattern->point1.y;
+
+ cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
+
+ dx = point1.x - point0.x;
+ dy = point1.y - point0.y;
+ scale = dx * dx + dy * dy;
+ scale = (scale) ? 1.0 / scale : 1.0;
+
+ start = dx * point0.x + dy * point0.y;
+
+ for (i = 0; i < 3; i++) {
+ double qx_device = (i % 2) * (width - 1) + offset_x;
+ double qy_device = (i / 2) * (height - 1) + offset_y;
+
+ /* transform fragment into pattern space */
+ double qx = a * qx_device + c * qy_device + tx;
+ double qy = b * qx_device + d * qy_device + ty;
+
+ factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale);
+ }
+
+ /* We consider a pattern to be vertical if the fixed point factor
+ * at the two upper corners is the same. We could accept a small
+ * change, but determining what change is acceptable would require
+ * sorting the stops in the pattern and looking at the differences.
+ *
+ * Horizontal works the same way with the two left corners.
+ */
+
+ *is_vertical = factors[1] == factors[0];
+ *is_horizontal = factors[2] == factors[0];
+}
+
+static cairo_status_t
+_cairo_image_data_set_radial (cairo_radial_pattern_t *pattern,
+ double offset_x,
+ double offset_y,
+ uint32_t *pixels,
+ int width,
+ int height)
{
int x, y, aligned_circles;
cairo_point_double_t c0, c1;
@@ -584,15 +770,18 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern,
c0_c1_x, c0_c1_y, c0_c1, angle_c0, c1_y, y_x, c0_y, c0_x, r1_2,
denumerator, fraction, factor;
cairo_shader_op_t op;
+ cairo_status_t status;
- _cairo_pattern_shader_init (pattern, &op);
+ status = _cairo_pattern_shader_init (&pattern->base, &op);
+ if (status)
+ return status;
- c0.x = pattern->u.radial.center0.x;
- c0.y = pattern->u.radial.center0.y;
- r0 = pattern->u.radial.radius0;
- c1.x = pattern->u.radial.center1.x;
- c1.y = pattern->u.radial.center1.y;
- r1 = pattern->u.radial.radius1;
+ c0.x = pattern->center0.x;
+ c0.y = pattern->center0.y;
+ r0 = pattern->radius0;
+ c1.x = pattern->center1.x;
+ c1.y = pattern->center1.y;
+ r1 = pattern->radius1;
if (c0.x != c1.x || c0.y != c1.y) {
aligned_circles = 0;
@@ -606,7 +795,8 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern,
r1_2 = c0_c1 = 0.0; /* shut up compiler */
}
- cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty);
+ cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
@@ -682,70 +872,454 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern,
_cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
}
}
+
+ _cairo_pattern_shader_fini (&op);
+
+ return CAIRO_STATUS_SUCCESS;
}
-cairo_image_surface_t *
-_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
+static cairo_int_status_t
+_cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **out,
+ cairo_surface_attributes_t *attr)
{
- cairo_surface_t *surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
+ uint32_t *data;
+ cairo_bool_t repeat = FALSE;
+
+ if (pattern->base.type == CAIRO_PATTERN_LINEAR) {
+ cairo_bool_t is_horizontal;
+ cairo_bool_t is_vertical;
+
+ _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern,
+ x, y, width, height,
+ &is_horizontal, &is_vertical);
+ if (is_horizontal) {
+ height = 1;
+ repeat = TRUE;
+ }
+ if (is_vertical) {
+ width = 1;
+ repeat = TRUE;
+ }
+ }
+
+ data = malloc (width * height * 4);
+ if (!data)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (pattern->base.type == CAIRO_PATTERN_LINEAR)
+ {
+ cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
+
+ status = _cairo_image_data_set_linear (linear, x, y, data,
+ width, height);
+ }
+ else
+ {
+ cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
+
+ status = _cairo_image_data_set_radial (radial, x, y, data,
+ width, height);
+ }
- switch (pattern->type) {
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- char *data;
- double x = box->p1.x >> 16;
- double y = box->p1.y >> 16;
- int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16);
- int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16);
+ if (status) {
+ free (data);
+ return status;
+ }
+
+ image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data ((char *) data,
+ CAIRO_FORMAT_ARGB32,
+ width, height,
+ width * 4);
+
+ if (image == NULL) {
+ free (data);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ _cairo_image_surface_assume_ownership_of_data (image);
+
+ status = _cairo_surface_clone_similar (dst, &image->base, out);
+
+ cairo_surface_destroy (&image->base);
+
+ attr->x_offset = -x;
+ attr->y_offset = -y;
+ cairo_matrix_set_identity (&attr->matrix);
+ attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
+ attr->filter = CAIRO_FILTER_NEAREST;
+ attr->acquired = FALSE;
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **out,
+ cairo_surface_attributes_t *attribs)
+{
+ cairo_color_t color;
+
+ _cairo_color_init (&color);
+ _cairo_color_set_rgb (&color, pattern->red, pattern->green, pattern->blue);
+ _cairo_color_set_alpha (&color, pattern->base.alpha);
+
+ *out = _cairo_surface_create_similar_solid (dst,
+ CAIRO_FORMAT_ARGB32,
+ 1, 1,
+ &color);
+
+ if (*out == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ attribs->x_offset = attribs->y_offset = 0;
+ cairo_matrix_set_identity (&attribs->matrix);
+ attribs->extend = CAIRO_EXTEND_REPEAT;
+ attribs->filter = CAIRO_FILTER_NEAREST;
+ attribs->acquired = FALSE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+/**
+ * _cairo_pattern_is_opaque
+ *
+ * Convenience function to determine whether a pattern has an opaque
+ * alpha value. This is done by testing whether the pattern's alpha
+ * value when converted to a byte is 255, so if a backend actually
+ * supported deep alpha channels this function might not do the right
+ * thing.
+ *
+ * Note that for a gradient or surface pattern, the overall resulting
+ * alpha for the pattern can be non-opaque even this function returns
+ * %TRUE, since the resulting alpha is the multiplication of the
+ * alpha of the gradient or surface with the pattern's alpha. In
+ * the future, alpha will be moved from the base pattern to the
+ * solid pattern subtype, at which point this function should
+ * probably be renamed to _cairo_pattern_is_opaque_solid()
+ *
+ * Return value: %TRUE if the pattern is opaque
+ **/
+cairo_bool_t
+_cairo_pattern_is_opaque (cairo_pattern_t *pattern)
+{
+ return (pattern->alpha >= ((double)0xff00 / (double)0xffff));
+}
+
+static cairo_int_status_t
+_cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **out,
+ cairo_surface_attributes_t *attr)
+{
+ cairo_int_status_t status;
+
+ attr->acquired = FALSE;
+
+ /* handle pattern opacity */
+ if (!_cairo_pattern_is_opaque (&pattern->base))
+ {
+ cairo_surface_pattern_t tmp;
+ cairo_color_t color;
+
+ _cairo_color_init (&color);
+ _cairo_color_set_alpha (&color, pattern->base.alpha);
+
+ *out = _cairo_surface_create_similar_solid (dst,
+ CAIRO_FORMAT_ARGB32,
+ width, height,
+ &color);
+ if (*out == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ status = _cairo_pattern_init_copy (&tmp.base, &pattern->base);
+ if (CAIRO_OK (status))
+ {
+ tmp.base.alpha = 1.0;
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ &tmp.base,
+ NULL,
+ *out,
+ x, y, 0, 0, 0, 0,
+ width, height);
+
+ _cairo_pattern_fini (&tmp.base);
+ }
+
+ if (status) {
+ cairo_surface_destroy (*out);
+ return status;
+ }
- data = malloc (width * height * 4);
- if (!data)
- return NULL;
+ attr->x_offset = -x;
+ attr->y_offset = -y;
+ attr->extend = CAIRO_EXTEND_NONE;
+ attr->filter = CAIRO_FILTER_NEAREST;
+
+ cairo_matrix_set_identity (&attr->matrix);
+ }
+ else
+ {
+ int tx, ty;
+
+ if (_cairo_surface_is_image (dst))
+ {
+ cairo_image_surface_t *image;
+
+ status = _cairo_surface_acquire_source_image (pattern->surface,
+ &image,
+ &attr->extra);
+ if (CAIRO_OK (status))
+ *out = &image->base;
+
+ attr->acquired = TRUE;
+ }
+ else
+ status = _cairo_surface_clone_similar (dst, pattern->surface, out);
- if (pattern->type == CAIRO_PATTERN_RADIAL)
- _cairo_image_data_set_radial (pattern, x, y, (int *) data,
- width, height);
+ attr->extend = pattern->base.extend;
+ attr->filter = pattern->base.filter;
+ if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
+ &tx, &ty))
+ {
+ cairo_matrix_set_identity (&attr->matrix);
+ attr->x_offset = tx;
+ attr->y_offset = ty;
+ }
else
- _cairo_image_data_set_linear (pattern, x, y, (int *) data,
- width, height);
+ {
+ attr->matrix = pattern->base.matrix;
+ attr->x_offset = attr->y_offset = 0;
+ }
+ }
+
+ return status;
+}
- _cairo_pattern_set_source_offset (pattern, x, y);
+/**
+ * _cairo_pattern_acquire_surface:
+ * @pattern: a #cairo_pattern_t
+ * @dst: destination surface
+ * @x: X coordinate in source corresponding to left side of destination area
+ * @y: Y coordinate in source corresponding to top side of destination area
+ * @width: width of destination area
+ * @height: height of destination area
+ * @surface_out: location to store a pointer to a surface
+ * @attributes: surface attributes that destination backend should apply to
+ * the returned surface
+ *
+ * A convenience function to obtain a surface to use as the source for
+ * drawing on @dst.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out.
+ **/
+cairo_int_status_t
+_cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **surface_out,
+ cairo_surface_attributes_t *attributes)
+{
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SOLID: {
+ cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern;
+
+ return _cairo_pattern_acquire_surface_for_solid (src, dst,
+ x, y, width, height,
+ surface_out,
+ attributes);
+ } break;
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern;
+
+ /* fast path for gradients with less than 2 color stops */
+ if (src->n_stops < 2)
+ {
+ cairo_solid_pattern_t solid;
+
+ if (src->n_stops)
+ {
+ _cairo_pattern_init_solid (&solid,
+ src->stops->color.red,
+ src->stops->color.green,
+ src->stops->color.blue);
+ _cairo_pattern_set_alpha (&solid.base,
+ src->stops->color.alpha);
+ }
+ else
+ {
+ _cairo_pattern_init_solid (&solid, 0.0, 0.0, 0.0);
+ _cairo_pattern_set_alpha (&solid.base, 0.0);
+ }
- surface = cairo_image_surface_create_for_data (data,
- CAIRO_FORMAT_ARGB32,
- width, height,
- width * 4);
+ return _cairo_pattern_acquire_surface_for_solid (&solid, dst,
+ x, y,
+ width, height,
+ surface_out,
+ attributes);
+ }
+ else
+ return _cairo_pattern_acquire_surface_for_gradient (src, dst,
+ x, y,
+ width, height,
+ surface_out,
+ attributes);
+ } break;
+ case CAIRO_PATTERN_SURFACE: {
+ cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;
- if (surface)
- _cairo_image_surface_assume_ownership_of_data (
- (cairo_image_surface_t *) surface);
+ return _cairo_pattern_acquire_surface_for_surface (src, dst,
+ x, y, width, height,
+ surface_out,
+ attributes);
+ } break;
}
- break;
- case CAIRO_PATTERN_SOLID:
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
- if (surface) {
- _cairo_surface_fill_rectangle (surface,
- CAIRO_OPERATOR_SRC,
- &pattern->color, 0, 0, 1, 1);
- cairo_surface_set_repeat (surface, 1);
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+/**
+ * _cairo_pattern_release_surface:
+ * @pattern: a #cairo_pattern_t
+ * @info: pointer to #cairo_surface_attributes_t filled in by
+ * _cairo_pattern_acquire_surface
+ *
+ * Releases resources obtained by _cairo_pattern_acquire_surface.
+ **/
+void
+_cairo_pattern_release_surface (cairo_surface_t *dst,
+ cairo_surface_t *surface,
+ cairo_surface_attributes_t *attributes)
+{
+ if (attributes->acquired)
+ _cairo_surface_release_source_image (dst,
+ (cairo_image_surface_t *) surface,
+ attributes->extra);
+ else
+ cairo_surface_destroy (surface);
+}
+
+cairo_int_status_t
+_cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
+ cairo_pattern_t *mask,
+ cairo_surface_t *dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **src_out,
+ cairo_surface_t **mask_out,
+ cairo_surface_attributes_t *src_attributes,
+ cairo_surface_attributes_t *mask_attributes)
+{
+ cairo_int_status_t status;
+
+ cairo_pattern_union_t tmp;
+ cairo_bool_t src_opaque, mask_opaque;
+ double src_alpha, mask_alpha;
+
+ src_opaque = _cairo_pattern_is_opaque (src);
+ mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
+
+ /* For surface patterns, we move any translucency from src->alpha
+ * to mask->alpha so we can use the source unchanged. Otherwise we
+ * move the translucency from mask->alpha to src->alpha so that
+ * we can drop the mask if possible.
+ */
+ if (src->type == CAIRO_PATTERN_SURFACE)
+ {
+ if (mask) {
+ mask_opaque = mask_opaque && src_opaque;
+ mask_alpha = mask->alpha * src->alpha;
+ } else {
+ mask_opaque = src_opaque;
+ mask_alpha = src->alpha;
}
- break;
- case CAIRO_PATTERN_SURFACE: {
- cairo_image_surface_t *image;
+
+ src_alpha = 1.0;
+ src_opaque = TRUE;
+ }
+ else
+ {
+ if (mask)
+ {
+ src_opaque = mask_opaque && src_opaque;
+ src_alpha = mask->alpha * src->alpha;
+ /* FIXME: This needs changing when we support RENDER
+ * style 4-channel masks.
+ */
+ if (mask->type == CAIRO_PATTERN_SOLID)
+ mask = NULL;
+ } else
+ src_alpha = src->alpha;
+
+ mask_alpha = 1.0;
+ mask_opaque = TRUE;
+ }
- image = _cairo_surface_get_image (pattern->u.surface.surface);
- if (image)
- surface = &image->base;
+ _cairo_pattern_init_copy (&tmp.base, src);
+ _cairo_pattern_set_alpha (&tmp.base, src_alpha);
+
+ status = _cairo_pattern_acquire_surface (&tmp.base, dst,
+ src_x, src_y,
+ width, height,
+ src_out, src_attributes);
+
+ _cairo_pattern_fini (&tmp.base);
+
+ if (status)
+ return status;
+
+ if (mask || !mask_opaque)
+ {
+ if (mask)
+ _cairo_pattern_init_copy (&tmp.base, mask);
else
- surface = NULL;
+ _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
+
+ _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
+
+ status = _cairo_pattern_acquire_surface (&tmp.base, dst,
+ mask_x, mask_y,
+ width, height,
+ mask_out, mask_attributes);
+ _cairo_pattern_fini (&tmp.base);
+
+ if (status)
+ {
+ _cairo_pattern_release_surface (dst, *src_out, src_attributes);
+ return status;
+ }
}
- break;
- default:
- surface = NULL;
- break;
+ else
+ {
+ *mask_out = NULL;
}
-
- return (cairo_image_surface_t *) surface;
+
+ return CAIRO_STATUS_SUCCESS;
}
-
diff --git a/src/cairo_pdf_surface.c b/src/cairo_pdf_surface.c
index 23230aa74..fee918355 100644
--- a/src/cairo_pdf_surface.c
+++ b/src/cairo_pdf_surface.c
@@ -36,9 +36,8 @@
#include "cairoint.h"
#include "cairo-pdf.h"
-/* XXX: This seems broken to me. What about users without freetype
- * that want to use a cairo PDF surface? */
-#include "cairo-ft.h"
+/* XXX: Eventually, we need to handle other font backends */
+#include "cairo-ft-private.h"
#include <ft2build.h>
#include FT_FREETYPE_H
@@ -54,10 +53,6 @@
* - Why doesn't pages inherit /alpha%d GS dictionaries from the Pages
* object?
*
- * - Why isn't the pattern passed to composite traps instead of
- * pattern->source? If composite traps needs an image or a surface it
- * can call create_pattern().
- *
* - We embed an image in the stream each time it's composited. We
* could add generation counters to surfaces and remember the stream
* ID for a particular generation for a particular surface.
@@ -183,9 +178,6 @@ struct cairo_pdf_surface {
double width_inches;
double height_inches;
- /* HACK: Non-null if this surface was created for a pattern. */
- cairo_pattern_t *pattern;
-
cairo_pdf_document_t *document;
cairo_pdf_stream_t *current_stream;
@@ -240,8 +232,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend;
#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) )
#define SFNT_VERSION 0x00010000
-#define OFFSET_TABLE_SIZE 12
-#define TABLE_DIRECTORY_ENTRY_SIZE 16
#ifdef WORDS_BIGENDIAN
@@ -300,19 +290,15 @@ cairo_pdf_font_destroy (cairo_pdf_font_t *font)
}
static cairo_pdf_font_t *
-cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
- cairo_unscaled_font_t *unscaled_font,
- cairo_font_scale_t *scale)
+cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
+ cairo_unscaled_font_t *unscaled_font)
{
- cairo_font_t scaled_font;
FT_Face face;
cairo_pdf_ft_font_t *font;
unsigned long size;
int i, j;
- /* FIXME: Why do I have to pass a scaled font to get the FT_Face? */
- _cairo_font_init (&scaled_font, scale, unscaled_font);
- face = cairo_ft_font_face (&scaled_font);
+ face = _cairo_ft_unscaled_font_lock_face (unscaled_font);
/* We currently only support freetype truetype fonts. */
size = 0;
@@ -333,7 +319,8 @@ cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
goto fail1;
- font->face = face;
+ font->base.unscaled_font = unscaled_font;
+ _cairo_unscaled_font_reference (unscaled_font);
font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
if (font->glyphs == NULL)
goto fail2;
@@ -364,6 +351,8 @@ cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
if (font->base.widths == NULL)
goto fail5;
+ _cairo_ft_unscaled_font_unlock_face (unscaled_font);
+
font->status = CAIRO_STATUS_SUCCESS;
return &font->base;
@@ -447,7 +436,7 @@ cairo_pdf_ft_font_write_cmap_table (cairo_pdf_ft_font_t *font, unsigned long tag
cairo_pdf_ft_font_write_be16 (font, 0);
cairo_pdf_ft_font_write_be16 (font, 1);
- cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 1);
cairo_pdf_ft_font_write_be16 (font, 0);
cairo_pdf_ft_font_write_be32 (font, 12);
@@ -764,12 +753,15 @@ cairo_pdf_ft_font_generate (void *abstract_font,
unsigned long start, end, next, checksum;
int i;
+ font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font);
+
if (cairo_pdf_ft_font_write_offset_table (font))
- return font->status;
+ goto fail;
start = cairo_pdf_ft_font_align_output (font);
end = start;
+ end = 0;
for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) {
if (truetype_tables[i].write (font, truetype_tables[i].tag))
goto fail;
@@ -789,6 +781,9 @@ cairo_pdf_ft_font_generate (void *abstract_font,
*length = _cairo_array_num_elements (&font->output);
fail:
+ _cairo_ft_unscaled_font_unlock_face (font->base.unscaled_font);
+ font->face = NULL;
+
return font->status;
}
@@ -947,14 +942,13 @@ _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
surface->width_inches = width_inches;
surface->height_inches = height_inches;
- surface->pattern = NULL;
_cairo_pdf_document_reference (document);
surface->document = document;
_cairo_array_init (&surface->streams, sizeof (cairo_pdf_stream_t *));
_cairo_array_init (&surface->patterns, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t));
_cairo_array_init (&surface->alphas, sizeof (double));
- _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
+ _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_resource_t));
return &surface->base;
}
@@ -1102,38 +1096,46 @@ _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface)
}
}
-static cairo_image_surface_t *
-_cairo_pdf_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_cairo_pdf_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
- return NULL;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_status_t
-_cairo_pdf_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+static void
+_cairo_pdf_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_status_t
-_cairo_pdf_surface_set_matrix (void *abstract_surface,
- cairo_matrix_t *matrix)
+_cairo_pdf_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect,
+ void **image_extra)
{
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_status_t
-_cairo_pdf_surface_set_filter (void *abstract_surface,
- cairo_filter_t filter)
+static void
+_cairo_pdf_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
{
- return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_pdf_surface_set_repeat (void *abstract_surface,
- int repeat)
+_cairo_pdf_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
static void *
@@ -1210,23 +1212,34 @@ emit_image_data (cairo_pdf_document_t *document,
}
static cairo_int_status_t
-_cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
- cairo_image_surface_t *image)
+_cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
+ cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
FILE *file = document->file;
unsigned id;
cairo_matrix_t i2u;
+ cairo_status_t status;
+ cairo_image_surface_t *image;
+ cairo_surface_t *src;
+ void *image_extra;
+
+ src = pattern->surface;
+ status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
+ if (!CAIRO_OK (status))
+ return status;
id = emit_image_data (dst->document, image);
- if (id == 0)
- return CAIRO_STATUS_NO_MEMORY;
+ if (id == 0) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto bail;
+ }
_cairo_pdf_surface_add_xobject (dst, id);
_cairo_pdf_surface_ensure_stream (dst);
- cairo_matrix_copy (&i2u, &image->base.matrix);
+ cairo_matrix_copy (&i2u, &pattern->base.matrix);
cairo_matrix_invert (&i2u);
cairo_matrix_translate (&i2u, 0, image->height);
cairo_matrix_scale (&i2u, image->width, -image->height);
@@ -1238,7 +1251,10 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
i2u.m[2][0], i2u.m[2][1],
id);
- return CAIRO_STATUS_SUCCESS;
+ bail:
+ _cairo_surface_release_source_image (src, image, image_extra);
+
+ return status;
}
/* The contents of the surface is already transformed into PDF units,
@@ -1253,20 +1269,19 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
static cairo_int_status_t
_cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
- cairo_pdf_surface_t *src,
- int width, int height)
+ cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
FILE *file = document->file;
cairo_matrix_t i2u;
cairo_pdf_stream_t *stream;
int num_streams, i;
-
- if (src->pattern != NULL)
- return CAIRO_STATUS_SUCCESS;
+ cairo_pdf_surface_t *src;
_cairo_pdf_surface_ensure_stream (dst);
+ src = (cairo_pdf_surface_t *) pattern->surface;
+
cairo_matrix_copy (&i2u, &src->base.matrix);
cairo_matrix_invert (&i2u);
cairo_matrix_scale (&i2u,
@@ -1297,8 +1312,8 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
static cairo_int_status_t
_cairo_pdf_surface_composite (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
+ cairo_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
void *abstract_dst,
int src_x,
int src_y,
@@ -1310,17 +1325,18 @@ _cairo_pdf_surface_composite (cairo_operator_t operator,
unsigned int height)
{
cairo_pdf_surface_t *dst = abstract_dst;
- cairo_pdf_surface_t *src;
- cairo_image_surface_t *image;
+ cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) src_pattern;
- if (generic_src->backend == &cairo_pdf_surface_backend) {
- src = (cairo_pdf_surface_t *) generic_src;
- return _cairo_pdf_surface_composite_pdf (dst, src, width, height);
- }
- else {
- image = _cairo_surface_get_image (generic_src);
- return _cairo_pdf_surface_composite_image (dst, image);
- }
+ if (mask_pattern)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (src_pattern->type != CAIRO_PATTERN_SURFACE)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (src->surface->backend == &cairo_pdf_surface_backend)
+ return _cairo_pdf_surface_composite_pdf (dst, src);
+ else
+ return _cairo_pdf_surface_composite_image (dst, src);
}
static cairo_int_status_t
@@ -1335,9 +1351,6 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface,
FILE *file = document->file;
int i;
- if (surface->pattern != NULL)
- return CAIRO_STATUS_SUCCESS;
-
_cairo_pdf_surface_ensure_stream (surface);
fprintf (file,
@@ -1355,23 +1368,44 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface,
}
static void
-emit_tiling_pattern (cairo_operator_t operator,
- cairo_pdf_surface_t *dst,
- cairo_pattern_t *pattern)
+emit_solid_pattern (cairo_pdf_surface_t *surface,
+ cairo_solid_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ unsigned int alpha;
+
+ alpha = _cairo_pdf_surface_add_alpha (surface, pattern->base.alpha);
+ _cairo_pdf_surface_ensure_stream (surface);
+ fprintf (file,
+ "%f %f %f rg /a%d gs\r\n",
+ pattern->red,
+ pattern->green,
+ pattern->blue,
+ alpha);
+}
+
+static void
+emit_surface_pattern (cairo_pdf_surface_t *dst,
+ cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
FILE *file = document->file;
cairo_pdf_stream_t *stream;
cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_status_t status;
char entries[250];
unsigned int id, alpha;
cairo_matrix_t pm;
- if (pattern->u.surface.surface->backend == &cairo_pdf_surface_backend) {
+ if (pattern->surface->backend == &cairo_pdf_surface_backend) {
return;
}
-
- image = _cairo_surface_get_image (pattern->u.surface.surface);
+
+ status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
+ if (!CAIRO_OK (status))
+ return;
_cairo_pdf_document_close_stream (document);
@@ -1382,7 +1416,7 @@ emit_tiling_pattern (cairo_operator_t operator,
cairo_matrix_set_identity (&pm);
cairo_matrix_scale (&pm, image->width, image->height);
- cairo_matrix_copy (&pm, &pattern->matrix);
+ cairo_matrix_copy (&pm, &pattern->base.matrix);
cairo_matrix_invert (&pm);
snprintf (entries, sizeof entries,
@@ -1401,6 +1435,8 @@ emit_tiling_pattern (cairo_operator_t operator,
stream = _cairo_pdf_document_open_stream (document, entries);
+ /* FIXME: emit code to show surface here. */
+
_cairo_pdf_surface_add_pattern (dst, stream->id);
_cairo_pdf_surface_ensure_stream (dst);
@@ -1408,10 +1444,12 @@ emit_tiling_pattern (cairo_operator_t operator,
fprintf (file,
"/Pattern cs /res%d scn /a%d gs\r\n",
stream->id, alpha);
+
+ _cairo_surface_release_source_image (pattern->surface, image, image_extra);
}
static unsigned int
-emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
FILE *file = document->file;
@@ -1430,12 +1468,12 @@ emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
"stream\r\n",
function_id);
- fputc (pattern->stops[0].color_char[0], file);
- fputc (pattern->stops[0].color_char[1], file);
- fputc (pattern->stops[0].color_char[2], file);
- fputc (pattern->stops[1].color_char[0], file);
- fputc (pattern->stops[1].color_char[1], file);
- fputc (pattern->stops[1].color_char[2], file);
+ fputc (pattern->stops[0].color.red * 0xff, file);
+ fputc (pattern->stops[0].color.green * 0xff, file);
+ fputc (pattern->stops[0].color.blue * 0xff, file);
+ fputc (pattern->stops[1].color.red * 0xff, file);
+ fputc (pattern->stops[1].color.green * 0xff, file);
+ fputc (pattern->stops[1].color.blue * 0xff, file);
fprintf (file,
"\r\n"
@@ -1446,7 +1484,7 @@ emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
}
static void
-emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
FILE *file = document->file;
@@ -1456,16 +1494,16 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
_cairo_pdf_document_close_stream (document);
- function_id = emit_pattern_stops (surface, pattern);
+ function_id = emit_pattern_stops (surface, &pattern->base);
- cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
cairo_matrix_invert (&p2u);
- x0 = pattern->u.linear.point0.x;
- y0 = pattern->u.linear.point0.y;
+ x0 = pattern->point0.x;
+ y0 = pattern->point0.y;
cairo_matrix_transform_point (&p2u, &x0, &y0);
- x1 = pattern->u.linear.point1.x;
- y1 = pattern->u.linear.point1.y;
+ x1 = pattern->point1.x;
+ y1 = pattern->point1.y;
cairo_matrix_transform_point (&p2u, &x1, &y1);
pattern_id = _cairo_pdf_document_new_object (document);
@@ -1479,16 +1517,14 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
" /ColorSpace /DeviceRGB\r\n"
" /Coords [ %f %f %f %f ]\r\n"
" /Function %d 0 R\r\n"
- " /Extend [ %s %s ]\r\n"
+ " /Extend [ true true ]\r\n"
" >>\r\n"
">>\r\n"
"endobj\r\n",
pattern_id,
document->height_inches * document->y_ppi,
x0, y0, x1, y1,
- function_id,
- (1 || pattern->extend) ? "true" : "false",
- (1 || pattern->extend) ? "true" : "false");
+ function_id);
_cairo_pdf_surface_add_pattern (surface, pattern_id);
@@ -1502,7 +1538,7 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
}
static void
-emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
FILE *file = document->file;
@@ -1512,24 +1548,31 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
_cairo_pdf_document_close_stream (document);
- function_id = emit_pattern_stops (surface, pattern);
+ function_id = emit_pattern_stops (surface, &pattern->base);
- cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
cairo_matrix_invert (&p2u);
- x0 = pattern->u.radial.center0.x;
- y0 = pattern->u.radial.center0.y;
- r0 = pattern->u.radial.radius0;
+ x0 = pattern->center0.x;
+ y0 = pattern->center0.y;
+ r0 = pattern->radius0;
cairo_matrix_transform_point (&p2u, &x0, &y0);
- x1 = pattern->u.radial.center1.x;
- y1 = pattern->u.radial.center1.y;
- r1 = pattern->u.radial.radius1;
+ x1 = pattern->center1.x;
+ y1 = pattern->center1.y;
+ r1 = pattern->radius1;
cairo_matrix_transform_point (&p2u, &x1, &y1);
/* FIXME: This is surely crack, but how should you scale a radius
* in a non-orthogonal coordinate system? */
cairo_matrix_transform_distance (&p2u, &r0, &r1);
+ /* FIXME: There is a difference between the cairo gradient extend
+ * semantics and PDF extend semantics. PDFs extend=false means
+ * that nothing is painted outside the gradient boundaries,
+ * whereas cairo takes this to mean that the end color is padded
+ * to infinity. Setting extend=true in PDF gives the cairo default
+ * behavoir, not yet sure how to implement the cairo mirror and
+ * repeat behaviour. */
pattern_id = _cairo_pdf_document_new_object (document);
fprintf (file,
"%d 0 obj\r\n"
@@ -1541,16 +1584,14 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
" /ColorSpace /DeviceRGB\r\n"
" /Coords [ %f %f %f %f %f %f ]\r\n"
" /Function %d 0 R\r\n"
- " /Extend [ %s %s ]\r\n"
+ " /Extend [ true true ]\r\n"
" >>\r\n"
">>\r\n"
"endobj\r\n",
pattern_id,
document->height_inches * document->y_ppi,
x0, y0, r0, x1, y1, r1,
- function_id,
- (1 || pattern->extend) ? "true" : "false",
- (1 || pattern->extend) ? "true" : "false");
+ function_id);
_cairo_pdf_surface_add_pattern (surface, pattern_id);
@@ -1563,6 +1604,28 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
pattern_id, alpha);
}
+static void
+emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+{
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SOLID:
+ emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
+ break;
+
+ case CAIRO_PATTERN_SURFACE:
+ emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
+ break;
+
+ case CAIRO_PATTERN_LINEAR:
+ emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
+ break;
+
+ case CAIRO_PATTERN_RADIAL:
+ emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
+ break;
+ }
+}
+
static double
intersect (cairo_line_t *line, cairo_fixed_t y)
{
@@ -1574,60 +1637,23 @@ intersect (cairo_line_t *line, cairo_fixed_t y)
static cairo_int_status_t
_cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *generic_src,
+ cairo_pattern_t *pattern,
void *abstract_dst,
int x_src,
int y_src,
+ int x_dst,
+ int y_dst,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
cairo_pdf_surface_t *surface = abstract_dst;
- cairo_pdf_surface_t *source = (cairo_pdf_surface_t *) generic_src;
cairo_pdf_document_t *document = surface->document;
- cairo_pattern_t *pattern;
FILE *file = document->file;
int i;
- unsigned int alpha;
- /* FIXME: we really just want the original pattern here, not a
- * source surface. */
- pattern = source->pattern;
-
- if (source->base.backend != &cairo_pdf_surface_backend) {
- printf ("_cairo_pdf_surface_composite_trapezoids: not a pdf source\r");
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (pattern == NULL) {
- printf ("_cairo_pdf_surface_composite_trapezoids: "
- "non-pattern pdf source\r");
- return CAIRO_STATUS_SUCCESS;
- }
-
- switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
- alpha = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha);
- _cairo_pdf_surface_ensure_stream (surface);
- fprintf (file,
- "%f %f %f rg /a%d gs\r\n",
- pattern->color.red,
- pattern->color.green,
- pattern->color.blue,
- alpha);
- break;
-
- case CAIRO_PATTERN_SURFACE:
- emit_tiling_pattern (operator, surface, pattern);
- break;
-
- case CAIRO_PATTERN_LINEAR:
- emit_linear_pattern (surface, pattern);
- break;
-
- case CAIRO_PATTERN_RADIAL:
- emit_radial_pattern (surface, pattern );
- break;
- }
+ emit_pattern (surface, pattern);
/* After the above switch the current stream should belong to this
* surface, so no need to _cairo_pdf_surface_ensure_stream() */
@@ -1686,59 +1712,48 @@ _cairo_pdf_surface_set_clip_region (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_int_status_t
-_cairo_pdf_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
- cairo_pdf_surface_t *source;
-
- source = (cairo_pdf_surface_t *)
- _cairo_pdf_surface_create_for_document (surface->document, 0, 0);
- source->pattern = pattern;
- pattern->source = &source->base;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_pdf_font_t *
_cairo_pdf_document_get_font (cairo_pdf_document_t *document,
- cairo_unscaled_font_t *unscaled_font,
- cairo_font_scale_t *scale)
+ cairo_font_t *font)
{
- cairo_pdf_font_t *font;
+ cairo_unscaled_font_t *unscaled_font;
+ cairo_pdf_font_t *pdf_font;
unsigned int num_fonts, i;
+ unscaled_font = _cairo_ft_font_get_unscaled_font (font);
+
num_fonts = _cairo_array_num_elements (&document->fonts);
for (i = 0; i < num_fonts; i++) {
- _cairo_array_copy_element (&document->fonts, i, &font);
- if (font->unscaled_font == unscaled_font)
- return font;
+ _cairo_array_copy_element (&document->fonts, i, &pdf_font);
+ if (pdf_font->unscaled_font == unscaled_font)
+ return pdf_font;
}
/* FIXME: Figure out here which font backend is in use and call
* the appropriate constructor. */
- font = cairo_pdf_ft_font_create (document, unscaled_font, scale);
- if (font == NULL)
+ pdf_font = cairo_pdf_ft_font_create (document, unscaled_font);
+ if (pdf_font == NULL)
return NULL;
- if (_cairo_array_append (&document->fonts, &font, 1) == NULL) {
- cairo_pdf_font_destroy (font);
+ if (_cairo_array_append (&document->fonts, &pdf_font, 1) == NULL) {
+ cairo_pdf_font_destroy (pdf_font);
return NULL;
}
- return font;
+ return pdf_font;
}
static cairo_status_t
-_cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
+_cairo_pdf_surface_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
- cairo_surface_t *source,
+ cairo_pattern_t *pattern,
void *abstract_surface,
int source_x,
int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
@@ -1748,23 +1763,23 @@ _cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font,
cairo_pdf_font_t *pdf_font;
int i, index;
- pdf_font = _cairo_pdf_document_get_font (document, font, scale);
+ pdf_font = _cairo_pdf_document_get_font (document, font);
if (pdf_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
- _cairo_pdf_surface_ensure_stream (surface);
+ emit_pattern (surface, pattern);
- fprintf (file, "0 0 0 rg BT /res%u 1 Tf", pdf_font->font_id);
+ fprintf (file, "BT /res%u 1 Tf", pdf_font->font_id);
for (i = 0; i < num_glyphs; i++) {
index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index);
fprintf (file,
- " %f %f %f %f %f %f Tm (%c) Tj",
- scale->matrix[0][0],
- scale->matrix[0][1],
- scale->matrix[1][0],
- -scale->matrix[1][1],
+ " %f %f %f %f %f %f Tm (\\%o) Tj",
+ font->scale.matrix[0][0],
+ font->scale.matrix[0][1],
+ font->scale.matrix[1][0],
+ -font->scale.matrix[1][1],
glyphs[i].x,
glyphs[i].y,
index);
@@ -1780,18 +1795,17 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
_cairo_pdf_surface_create_similar,
_cairo_pdf_surface_destroy,
_cairo_pdf_surface_pixels_per_inch,
- _cairo_pdf_surface_get_image,
- _cairo_pdf_surface_set_image,
- _cairo_pdf_surface_set_matrix,
- _cairo_pdf_surface_set_filter,
- _cairo_pdf_surface_set_repeat,
+ _cairo_pdf_surface_acquire_source_image,
+ _cairo_pdf_surface_release_source_image,
+ _cairo_pdf_surface_acquire_dest_image,
+ _cairo_pdf_surface_release_dest_image,
+ _cairo_pdf_surface_clone_similar,
_cairo_pdf_surface_composite,
_cairo_pdf_surface_fill_rectangles,
_cairo_pdf_surface_composite_trapezoids,
_cairo_pdf_surface_copy_page,
_cairo_pdf_surface_show_page,
_cairo_pdf_surface_set_clip_region,
- _cairo_pdf_surface_create_pattern,
_cairo_pdf_surface_show_glyphs
};
@@ -1930,8 +1944,8 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
fprintf (file,
"%d 0 obj\r\n"
"<< /Type /FontDescriptor\r\n"
- " /FontName /%s\r\n"
- " /Flags 32\r\n"
+ " /FontName /7%s\r\n"
+ " /Flags 4\r\n"
" /FontBBox [ %ld %ld %ld %ld ]\r\n"
" /ItalicAngle 0\r\n"
" /Ascent %ld\r\n"
diff --git a/src/cairo_pen.c b/src/cairo_pen.c
index f365091dc..6ecaa00b3 100644
--- a/src/cairo_pen.c
+++ b/src/cairo_pen.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c
index 2279b07a9..1ae745cb5 100644
--- a/src/cairo_png_surface.c
+++ b/src/cairo_png_surface.c
@@ -32,7 +32,7 @@
*
* Contributor(s):
* Olivier Andrieu <oliv__a@users.sourceforge.net>
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include <png.h>
@@ -185,62 +185,65 @@ _cairo_png_surface_pixels_per_inch (void *abstract_surface)
return 96.0;
}
-static cairo_image_surface_t *
-_cairo_png_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_cairo_png_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
cairo_png_surface_t *surface = abstract_surface;
+
+ *image_out = surface->image;
- cairo_surface_reference (&surface->image->base);
-
- return surface->image;
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_png_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+static void
+_cairo_png_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
{
- cairo_png_surface_t *surface = abstract_surface;
-
- if (image == surface->image)
- return CAIRO_STATUS_SUCCESS;
-
- /* XXX: Need to call _cairo_image_surface_set_image here, but it's
- not implemented yet. */
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_status_t
-_cairo_png_surface_set_matrix (void *abstract_surface,
- cairo_matrix_t *matrix)
+_cairo_png_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect,
+ void **image_extra)
{
cairo_png_surface_t *surface = abstract_surface;
+
+ image_rect->x = 0;
+ image_rect->y = 0;
+ image_rect->width = surface->image->width;
+ image_rect->height = surface->image->height;
+
+ *image_out = surface->image;
- return _cairo_image_surface_set_matrix (surface->image, matrix);
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_png_surface_set_filter (void *abstract_surface,
- cairo_filter_t filter)
+static void
+_cairo_png_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
{
- cairo_png_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_filter (surface->image, filter);
}
static cairo_status_t
-_cairo_png_surface_set_repeat (void *abstract_surface,
- int repeat)
+_cairo_png_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
- cairo_png_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_repeat (surface->image, repeat);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_png_surface_composite (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
+ cairo_pattern_t *src,
+ cairo_pattern_t *mask,
void *abstract_dst,
int src_x,
int src_y,
@@ -266,10 +269,14 @@ _cairo_png_surface_fill_rectangles (void *abstract_surface,
static cairo_int_status_t
_cairo_png_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *generic_src,
+ cairo_pattern_t *pattern,
void *abstract_dst,
- int x_src,
- int y_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
@@ -297,18 +304,20 @@ _cairo_png_surface_copy_page (void *abstract_surface)
rows[i] = surface->image->data + i * surface->image->stride;
png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (png == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ if (png == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL1;
+ }
info = png_create_info_struct (png);
if (info == NULL) {
- png_destroy_write_struct (&png, NULL);
- return CAIRO_STATUS_NO_MEMORY;
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL2;
}
if (setjmp (png_jmpbuf (png))) {
status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL;
+ goto BAIL2;
}
png_init_io (png, surface->file);
@@ -332,7 +341,7 @@ _cairo_png_surface_copy_page (void *abstract_surface)
break;
default:
status = CAIRO_STATUS_NULL_POINTER;
- goto BAIL;
+ goto BAIL2;
}
png_set_IHDR (png, info,
@@ -365,9 +374,9 @@ _cairo_png_surface_copy_page (void *abstract_surface)
surface->copied = 1;
-BAIL:
+BAIL2:
png_destroy_write_struct (&png, &info);
-
+BAIL1:
free (rows);
return status;
@@ -397,29 +406,20 @@ _cairo_png_surface_set_clip_region (void *abstract_surface,
return _cairo_image_surface_set_clip_region (surface->image, region);
}
-static cairo_int_status_t
-_cairo_png_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static const cairo_surface_backend_t cairo_png_surface_backend = {
_cairo_png_surface_create_similar,
_cairo_png_surface_destroy,
_cairo_png_surface_pixels_per_inch,
- _cairo_png_surface_get_image,
- _cairo_png_surface_set_image,
- _cairo_png_surface_set_matrix,
- _cairo_png_surface_set_filter,
- _cairo_png_surface_set_repeat,
+ _cairo_png_surface_acquire_source_image,
+ _cairo_png_surface_release_source_image,
+ _cairo_png_surface_acquire_dest_image,
+ _cairo_png_surface_release_dest_image,
+ _cairo_png_surface_clone_similar,
_cairo_png_surface_composite,
_cairo_png_surface_fill_rectangles,
_cairo_png_surface_composite_trapezoids,
_cairo_png_surface_copy_page,
_cairo_png_surface_show_page,
_cairo_png_surface_set_clip_region,
- _cairo_png_surface_create_pattern,
NULL /* show_glyphs */
};
diff --git a/src/cairo_polygon.c b/src/cairo_polygon.c
index e85858033..59c615da2 100644
--- a/src/cairo_polygon.c
+++ b/src/cairo_polygon.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include <stdlib.h>
diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c
index 4da8162c7..4a45fc679 100644
--- a/src/cairo_ps_surface.c
+++ b/src/cairo_ps_surface.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
@@ -42,6 +42,22 @@
static const cairo_surface_backend_t cairo_ps_surface_backend;
+/**
+ * cairo_set_target_ps:
+ * @cr: a #cairo_t
+ * @file: an open, writeable file
+ * @width_inches: width of the output page, in inches
+ * @height_inches: height of the output page, in inches
+ * @x_pixels_per_inch: X resolution to use for image fallbacks;
+ * not all Cairo drawing can be represented in a postscript
+ * file, so Cairo will write out images for some portions
+ * of the output.
+ * @y_pixels_per_inch: Y resolution to use for image fallbacks.
+ *
+ * Directs output for a #cairo_t to a postscript file. The file must
+ * be kept open until the #cairo_t is destroyed or set to have a
+ * different target, and then must be closed by the application.
+ **/
void
cairo_set_target_ps (cairo_t *cr,
FILE *file,
@@ -192,62 +208,65 @@ _cairo_ps_surface_pixels_per_inch (void *abstract_surface)
return surface->y_ppi;
}
-static cairo_image_surface_t *
-_cairo_ps_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_cairo_ps_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
cairo_ps_surface_t *surface = abstract_surface;
+
+ *image_out = surface->image;
- cairo_surface_reference (&surface->image->base);
-
- return surface->image;
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_ps_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+static void
+_cairo_ps_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
{
- cairo_ps_surface_t *surface = abstract_surface;
-
- if (image == surface->image)
- return CAIRO_STATUS_SUCCESS;
-
- /* XXX: Need to call _cairo_image_surface_set_image here, but it's
- not implemented yet. */
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_status_t
-_cairo_ps_surface_set_matrix (void *abstract_surface,
- cairo_matrix_t *matrix)
+_cairo_ps_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect,
+ void **image_extra)
{
cairo_ps_surface_t *surface = abstract_surface;
+
+ image_rect->x = 0;
+ image_rect->y = 0;
+ image_rect->width = surface->image->width;
+ image_rect->height = surface->image->height;
+
+ *image_out = surface->image;
- return _cairo_image_surface_set_matrix (surface->image, matrix);
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_ps_surface_set_filter (void *abstract_surface,
- cairo_filter_t filter)
+static void
+_cairo_ps_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
{
- cairo_ps_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_filter (surface->image, filter);
}
static cairo_status_t
-_cairo_ps_surface_set_repeat (void *abstract_surface,
- int repeat)
+_cairo_ps_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
- cairo_ps_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_repeat (surface->image, repeat);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
_cairo_ps_surface_composite (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
+ cairo_pattern_t *src,
+ cairo_pattern_t *mask,
void *abstract_dst,
int src_x,
int src_y,
@@ -273,10 +292,14 @@ _cairo_ps_surface_fill_rectangles (void *abstract_surface,
static cairo_int_status_t
_cairo_ps_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *generic_src,
+ cairo_pattern_t *generic_src,
void *abstract_dst,
int x_src,
int y_src,
+ int x_dst,
+ int y_dst,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
@@ -294,12 +317,10 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
int i, x, y;
- cairo_surface_t *white_surface;
+ cairo_solid_pattern_t white_pattern;
char *rgb, *compressed;
long rgb_size, compressed_size;
- cairo_color_t white;
-
rgb_size = 3 * width * height;
rgb = malloc (rgb_size);
if (rgb == NULL) {
@@ -316,26 +337,19 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
/* PostScript can not represent the alpha channel, so we blend the
current image over a white RGB surface to eliminate it. */
- white_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
- if (white_surface == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL2;
- }
- _cairo_color_init (&white);
- _cairo_surface_fill_rectangle (white_surface,
- CAIRO_OPERATOR_SRC,
- &white,
- 0, 0, 1, 1);
- cairo_surface_set_repeat (white_surface, 1);
+ _cairo_pattern_init_solid (&white_pattern, 1.0, 1.0, 1.0);
+
_cairo_surface_composite (CAIRO_OPERATOR_OVER_REVERSE,
- white_surface,
+ &white_pattern.base,
NULL,
&surface->image->base,
0, 0,
0, 0,
0, 0,
width, height);
+
+ _cairo_pattern_fini (&white_pattern.base);
i = 0;
for (y = 0; y < height; y++) {
@@ -379,8 +393,6 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
/* Page footer */
fprintf (file, "%%%%EndPage\n");
- cairo_surface_destroy (white_surface);
- BAIL2:
free (compressed);
BAIL1:
free (rgb);
@@ -412,29 +424,20 @@ _cairo_ps_surface_set_clip_region (void *abstract_surface,
return _cairo_image_surface_set_clip_region (surface->image, region);
}
-static cairo_int_status_t
-_cairo_ps_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static const cairo_surface_backend_t cairo_ps_surface_backend = {
_cairo_ps_surface_create_similar,
_cairo_ps_surface_destroy,
_cairo_ps_surface_pixels_per_inch,
- _cairo_ps_surface_get_image,
- _cairo_ps_surface_set_image,
- _cairo_ps_surface_set_matrix,
- _cairo_ps_surface_set_filter,
- _cairo_ps_surface_set_repeat,
+ _cairo_ps_surface_acquire_source_image,
+ _cairo_ps_surface_release_source_image,
+ _cairo_ps_surface_acquire_dest_image,
+ _cairo_ps_surface_release_dest_image,
+ _cairo_ps_surface_clone_similar,
_cairo_ps_surface_composite,
_cairo_ps_surface_fill_rectangles,
_cairo_ps_surface_composite_trapezoids,
_cairo_ps_surface_copy_page,
_cairo_ps_surface_show_page,
_cairo_ps_surface_set_clip_region,
- _cairo_ps_surface_create_pattern,
NULL /* show_glyphs */
};
diff --git a/src/cairo_quartz_surface.c b/src/cairo_quartz_surface.c
index b7103b051..01b345cdc 100644
--- a/src/cairo_quartz_surface.c
+++ b/src/cairo_quartz_surface.c
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2004 Calum Robinson
+ * Copyright © 2004 Calum Robinson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
diff --git a/src/cairo_slope.c b/src/cairo_slope.c
index 1a1497988..a2edec038 100644
--- a/src/cairo_slope.c
+++ b/src/cairo_slope.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo_spline.c b/src/cairo_spline.c
index ff290d9dd..5119a8e2b 100644
--- a/src/cairo_spline.c
+++ b/src/cairo_spline.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
diff --git a/src/cairo_surface.c b/src/cairo_surface.c
index a457d2062..330d58b1e 100644
--- a/src/cairo_surface.c
+++ b/src/cairo_surface.c
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include <stdlib.h>
@@ -151,16 +151,151 @@ _cairo_surface_pixels_per_inch (cairo_surface_t *surface)
return surface->backend->pixels_per_inch (surface);
}
-cairo_image_surface_t *
-_cairo_surface_get_image (cairo_surface_t *surface)
+/**
+ * _cairo_surface_acquire_source_image:
+ * @surface: a #cairo_surface_t
+ * @image_out: location to store a pointer to an image surface that includes at least
+ * the intersection of @interest_rect with the visible area of @surface.
+ * This surface could be @surface itself, a surface held internal to @surface,
+ * or it could be a new surface with a copy of the relevant portion of @surface.
+ * @image_extra: location to store image specific backend data
+ *
+ * Gets an image surface to use when drawing as a fallback when drawing with
+ * @surface as a source. _cairo_surface_release_source_image() must be called
+ * when finished.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if a an image was stored in @image_out.
+ * %CAIRO_INT_STATUS_UNSUPPORTED if an image cannot be retrieved for the specified
+ * surface. Or %CAIRO_STATUS_NO_MEMORY.
+ **/
+cairo_private cairo_status_t
+_cairo_surface_acquire_source_image (cairo_surface_t *surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
- return surface->backend->get_image (surface);
+ return surface->backend->acquire_source_image (surface, image_out, image_extra);
}
+/**
+ * _cairo_surface_release_source_image:
+ * @surface: a #cairo_surface_t
+ * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image()
+ *
+ * Releases any resources obtained with _cairo_surface_acquire_source_image()
+ **/
+cairo_private void
+_cairo_surface_release_source_image (cairo_surface_t *surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ surface->backend->release_source_image (surface, image, image_extra);
+}
+
+/**
+ * _cairo_surface_acquire_dest_image:
+ * @surface: a #cairo_surface_t
+ * @interest_rect: area of @surface for which fallback drawing is being done.
+ * A value of %NULL indicates that the entire surface is desired.
+ * @image_out: location to store a pointer to an image surface that includes at least
+ * the intersection of @interest_rect with the visible area of @surface.
+ * This surface could be @surface itself, a surface held internal to @surface,
+ * or it could be a new surface with a copy of the relevant portion of @surface.
+ * @image_rect: location to store area of the original surface occupied
+ * by the surface stored in @image.
+ * @image_extra: location to store image specific backend data
+ *
+ * Retrieves a local image for a surface for implementing a fallback drawing
+ * operation. After calling this function, the implementation of the fallback
+ * drawing operation draws the primitive to the surface stored in @image_out
+ * then calls _cairo_surface_release_dest_fallback(),
+ * which, if a temporary surface was created, copies the bits back to the
+ * main surface and frees the temporary surface.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY.
+ * %CAIRO_INT_STATUS_UNSUPPORTED can be returned but this will mean that
+ * the backend can't draw with fallbacks. It's possible for the routine
+ * to store NULL in @local_out and return %CAIRO_STATUS_SUCCESS;
+ * that indicates that no part of @interest_rect is visible, so no drawing
+ * is necessary. _cairo_surface_release_dest_fallback() should not be called in that
+ * case.
+ **/
+cairo_status_t
+_cairo_surface_acquire_dest_image (cairo_surface_t *surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect,
+ void **image_extra)
+{
+ return surface->backend->acquire_dest_image (surface, interest_rect,
+ image_out, image_rect, image_extra);
+}
+
+/**
+ * _cairo_surface_end_fallback:
+ * @surface: a #cairo_surface_t
+ * @interest_rect: same as passed to the matching _cairo_surface_acquire_dest_image()
+ * @image: same as returned from the matching _cairo_surface_acquire_dest_image()
+ * @image_rect: same as returned from the matching _cairo_surface_acquire_dest_image()
+ * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image()
+ *
+ * Finishes the operation started with _cairo_surface_acquire_dest_image(), by, if
+ * necessary, copying the image from @image back to @surface and freeing any
+ * resources that were allocated.
+ **/
+void
+_cairo_surface_release_dest_image (cairo_surface_t *surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+ surface->backend->release_dest_image (surface, interest_rect,
+ image, image_rect, image_extra);
+}
+
+/**
+ * _cairo_surface_clone_similar:
+ * @surface: a #cairo_surface_t
+ * @src: the source image
+ * @clone_out: location to store a surface compatible with @surface
+ * and with contents identical to @src. The caller must call
+ * cairo_surface_destroy() on the result.
+ *
+ * Creates a surface with contents identical to @src but that
+ * can be used efficiently with @surface. If @surface and @src are
+ * already compatible then it may return a new reference to @src.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if a surface was created and stored
+ * in @clone_out. Otherwise %CAIRO_INT_STATUS_UNSUPPORTED or another
+ * error like %CAIRO_STATUS_NO_MEMORY.
+ **/
cairo_status_t
-_cairo_surface_set_image (cairo_surface_t *surface, cairo_image_surface_t *image)
+_cairo_surface_clone_similar (cairo_surface_t *surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
- return surface->backend->set_image (surface, image);
+ cairo_status_t status;
+ cairo_image_surface_t *image;
+ void *image_extra;
+
+ status = surface->backend->clone_similar (surface, src, clone_out);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
+ if (status != CAIRO_STATUS_SUCCESS)
+ return status;
+
+ status = surface->backend->clone_similar (surface, &image->base, clone_out);
+
+ /* If the above failed point, we could implement a full fallback
+ * using acquire_dest_image, but that's going to be very
+ * inefficient compared to a backend-specific implementation of
+ * clone_similar() with an image source. So we don't bother
+ */
+
+ _cairo_surface_release_source_image (src, image, image_extra);
+ return status;
}
cairo_status_t
@@ -169,9 +304,7 @@ cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
if (surface == NULL)
return CAIRO_STATUS_NULL_POINTER;
- cairo_matrix_copy (&surface->matrix, matrix);
-
- return surface->backend->set_matrix (surface, matrix);
+ return cairo_matrix_copy (&surface->matrix, matrix);
}
slim_hidden_def(cairo_surface_set_matrix);
@@ -192,7 +325,7 @@ cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
return CAIRO_STATUS_NULL_POINTER;
surface->filter = filter;
- return surface->backend->set_filter (surface, filter);
+ return CAIRO_STATUS_SUCCESS;
}
cairo_filter_t
@@ -224,14 +357,81 @@ cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
surface->repeat = repeat;
- return surface->backend->set_repeat (surface, repeat);
+ return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def(cairo_surface_set_repeat);
+typedef struct {
+ cairo_surface_t *dst;
+ cairo_rectangle_t extents;
+ cairo_image_surface_t *image;
+ cairo_rectangle_t image_rect;
+ void *image_extra;
+} fallback_state_t;
+
+static cairo_status_t
+_fallback_init (fallback_state_t *state,
+ cairo_surface_t *dst,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ state->extents.x = x;
+ state->extents.y = y;
+ state->extents.width = width;
+ state->extents.height = height;
+
+ state->dst = dst;
+
+ return _cairo_surface_acquire_dest_image (dst, &state->extents,
+ &state->image, &state->image_rect, &state->image_extra);
+}
+
+static void
+_fallback_cleanup (fallback_state_t *state)
+{
+ _cairo_surface_release_dest_image (state->dst, &state->extents,
+ state->image, &state->image_rect, state->image_extra);
+}
+
+static cairo_status_t
+_fallback_composite (cairo_operator_t operator,
+ cairo_pattern_t *src,
+ cairo_pattern_t *mask,
+ cairo_surface_t *dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ fallback_state_t state;
+ cairo_status_t status;
+
+ status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
+ if (!CAIRO_OK (status) || !state.image)
+ return status;
+
+ state.image->base.backend->composite (operator, src, mask,
+ &state.image->base,
+ src_x, src_y, mask_x, mask_y,
+ dst_x - state.image_rect.x,
+ dst_y - state.image_rect.y,
+ width, height);
+
+ _fallback_cleanup (&state);
+
+ return status;
+}
+
cairo_status_t
_cairo_surface_composite (cairo_operator_t operator,
- cairo_surface_t *src,
- cairo_surface_t *mask,
+ cairo_pattern_t *src,
+ cairo_pattern_t *mask,
cairo_surface_t *dst,
int src_x,
int src_y,
@@ -243,7 +443,6 @@ _cairo_surface_composite (cairo_operator_t operator,
unsigned int height)
{
cairo_int_status_t status;
- cairo_image_surface_t *src_image, *mask_image = 0, *dst_image;
status = dst->backend->composite (operator,
src, mask, dst,
@@ -254,28 +453,12 @@ _cairo_surface_composite (cairo_operator_t operator,
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- src_image = _cairo_surface_get_image (src);
- if (mask)
- mask_image = _cairo_surface_get_image (mask);
- dst_image = _cairo_surface_get_image (dst);
-
- dst_image->base.backend->composite (operator,
- &src_image->base,
- mask ? &mask_image->base : NULL,
- dst_image,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
-
- status = _cairo_surface_set_image (dst, dst_image);
-
- cairo_surface_destroy (&src_image->base);
- if (mask)
- cairo_surface_destroy (&mask_image->base);
- cairo_surface_destroy (&dst_image->base);
-
- return status;
+ return _fallback_composite (operator,
+ src, mask, dst,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
}
cairo_status_t
@@ -297,6 +480,77 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface,
return _cairo_surface_fill_rectangles (surface, operator, color, &rect, 1);
}
+static cairo_status_t
+_fallback_fill_rectangles (cairo_surface_t *surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ fallback_state_t state;
+ cairo_rectangle_t *offset_rects = NULL;
+ cairo_status_t status;
+ int x1, y1, x2, y2;
+ int i;
+
+ if (num_rects <= 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* Compute the bounds of the rectangles, so that we know what area of the
+ * destination surface to fetch
+ */
+ x1 = rects[0].x;
+ y1 = rects[0].y;
+ x2 = rects[0].x + rects[0].width;
+ y2 = rects[0].y + rects[0].height;
+
+ for (i = 1; i < num_rects; i++) {
+ if (rects[0].x < x1)
+ x1 = rects[0].x;
+ if (rects[0].y < y1)
+ y1 = rects[0].y;
+
+ if (rects[0].x + rects[0].width > x2)
+ x2 = rects[0].x + rects[0].width;
+ if (rects[0].y + rects[0].height > y2)
+ y2 = rects[0].y + rects[0].height;
+ }
+
+ status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
+ if (!CAIRO_OK (status) || !state.image)
+ return status;
+
+ /* If the fetched image isn't at 0,0, we need to offset the rectangles */
+
+ if (state.image_rect.x != 0 || state.image_rect.y != 0) {
+ offset_rects = malloc (sizeof (cairo_rectangle_t) * num_rects);
+ if (!offset_rects) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
+ for (i = 0; i < num_rects; i++) {
+ offset_rects[i].x = rects[i].x - state.image_rect.x;
+ offset_rects[i].y = rects[i].y - state.image_rect.y;
+ offset_rects[i].width = rects[i].width;
+ offset_rects[i].height = rects[i].height;
+ }
+
+ rects = offset_rects;
+ }
+
+ state.image->base.backend->fill_rectangles (&state.image->base, operator, color,
+ rects, num_rects);
+
+ if (offset_rects)
+ free (offset_rects);
+
+ FAIL:
+ _fallback_cleanup (&state);
+
+ return status;
+}
+
cairo_status_t
_cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_operator_t operator,
@@ -305,7 +559,6 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
int num_rects)
{
cairo_int_status_t status;
- cairo_image_surface_t *surface_image;
if (num_rects == 0)
return CAIRO_STATUS_SUCCESS;
@@ -317,54 +570,105 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- surface_image = _cairo_surface_get_image (surface);
+ return _fallback_fill_rectangles (surface, operator, color, rects, num_rects);
+}
+
+static cairo_status_t
+_fallback_composite_trapezoids (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ fallback_state_t state;
+ cairo_trapezoid_t *offset_traps = NULL;
+ cairo_status_t status;
+ int i;
+
+ status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
+ if (!CAIRO_OK (status) || !state.image)
+ return status;
- surface_image->base.backend->fill_rectangles (surface_image,
- operator,
- color,
- rects, num_rects);
+ /* If the destination image isn't at 0,0, we need to offset the trapezoids */
+
+ if (state.image_rect.x != 0 || state.image_rect.y != 0) {
+
+ cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x);
+ cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y);
+
+ offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
+ if (!offset_traps) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
- status = _cairo_surface_set_image (surface, surface_image);
+ for (i = 0; i < num_traps; i++) {
+ offset_traps[i].top = traps[i].top - yoff;
+ offset_traps[i].bottom = traps[i].bottom - yoff;
+ offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff;
+ offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff;
+ offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff;
+ offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff;
+ offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff;
+ offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff;
+ offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff;
+ offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff;
+ }
- cairo_surface_destroy (&surface_image->base);
+ traps = offset_traps;
+ }
+ state.image->base.backend->composite_trapezoids (operator, pattern,
+ &state.image->base,
+ src_x, src_y,
+ dst_x - state.image_rect.x,
+ dst_y - state.image_rect.y,
+ width, height, traps, num_traps);
+ if (offset_traps)
+ free (offset_traps);
+
+ FAIL:
+ _fallback_cleanup (&state);
+
return status;
}
+
cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *src,
+ cairo_pattern_t *pattern,
cairo_surface_t *dst,
- int x_src,
- int y_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
cairo_int_status_t status;
- cairo_image_surface_t *src_image, *dst_image;
status = dst->backend->composite_trapezoids (operator,
- src, dst,
- x_src, y_src,
+ pattern, dst,
+ src_x, src_y,
+ dst_x, dst_y,
+ width, height,
traps, num_traps);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- src_image = _cairo_surface_get_image (src);
- dst_image = _cairo_surface_get_image (dst);
-
- dst_image->base.backend->composite_trapezoids (operator,
- &src_image->base,
- dst_image,
- x_src, y_src,
- traps, num_traps);
-
- status = _cairo_surface_set_image (dst, dst_image);
-
- cairo_surface_destroy (&src_image->base);
- cairo_surface_destroy (&dst_image->base);
-
- return status;
+ return _fallback_composite_trapezoids (operator, pattern, dst,
+ src_x, src_y,
+ dst_x, dst_y,
+ width, height,
+ traps, num_traps);
}
cairo_status_t
@@ -402,109 +706,3 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *reg
{
return surface->backend->set_clip_region (surface, region);
}
-
-cairo_status_t
-_cairo_surface_create_pattern (cairo_surface_t *surface,
- cairo_pattern_t *pattern,
- cairo_box_t *box)
-{
- cairo_int_status_t status;
-
- status = surface->backend->create_pattern (surface, pattern, box);
-
- /* The backend cannot accelerate this pattern, lets create an
- unaccelerated source instead. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-
- status = CAIRO_STATUS_SUCCESS;
- switch (pattern->type) {
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- cairo_image_surface_t *image;
-
- image = _cairo_pattern_get_image (pattern, box);
- if (image) {
- pattern->source = &image->base;
-
- return CAIRO_STATUS_SUCCESS;
- } else
- return CAIRO_STATUS_NO_MEMORY;
-
- } break;
- case CAIRO_PATTERN_SOLID:
- pattern->source =
- _cairo_surface_create_similar_solid (surface,
- CAIRO_FORMAT_ARGB32,
- 1, 1,
- &pattern->color);
- if (pattern->source) {
- cairo_surface_set_repeat (pattern->source, 1);
-
- return CAIRO_STATUS_SUCCESS;
- } else
- return CAIRO_STATUS_NO_MEMORY;
- break;
- case CAIRO_PATTERN_SURFACE:
- status = CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* handle pattern opacity */
- if (pattern->color.alpha != 1.0) {
- double x = box->p1.x >> 16;
- double y = box->p1.y >> 16;
- int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16);
- int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16);
- cairo_pattern_t alpha;
-
- pattern->source =
- cairo_surface_create_similar (surface,
- CAIRO_FORMAT_ARGB32,
- width, height);
- if (pattern->source) {
- _cairo_pattern_init_solid (&alpha, 1.0, 1.0, 1.0);
- _cairo_pattern_set_alpha (&alpha, pattern->color.alpha);
-
- status = _cairo_surface_create_pattern (pattern->source,
- &alpha, box);
-
- if (status == CAIRO_STATUS_SUCCESS) {
- int save_repeat = pattern->u.surface.surface->repeat;
-
- if (pattern->extend == CAIRO_EXTEND_REPEAT ||
- pattern->u.surface.surface->repeat == 1)
- cairo_surface_set_repeat (pattern->u.surface.surface, 1);
- else
- cairo_surface_set_repeat (pattern->u.surface.surface, 0);
-
- status =
- _cairo_surface_composite (CAIRO_OPERATOR_OVER,
- pattern->u.surface.surface,
- alpha.source,
- pattern->source,
- 0, 0, 0, 0, 0, 0,
- width, height);
-
- cairo_surface_set_repeat (pattern->u.surface.surface,
- save_repeat);
-
- if (status == CAIRO_STATUS_SUCCESS)
- _cairo_pattern_set_source_offset (pattern, x, y);
- else
- cairo_surface_destroy (pattern->source);
- }
-
- _cairo_pattern_fini (&alpha);
- }
- }
-
- if (status != CAIRO_STATUS_SUCCESS) {
- pattern->source = pattern->u.surface.surface;
- cairo_surface_reference (pattern->u.surface.surface);
-
- return CAIRO_STATUS_SUCCESS;
- }
- break;
- }
- }
-
- return status;
-}
diff --git a/src/cairo_traps.c b/src/cairo_traps.c
index d17a27281..79c7e16b6 100644
--- a/src/cairo_traps.c
+++ b/src/cairo_traps.c
@@ -1,31 +1,42 @@
/*
- * Copyright © 2002 Keith Packard
+ * Copyright © 2002 Keith Packard
*
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
+ * 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.
*
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * 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 Keith Packard
+ *
+ * Contributor(s):
+ * Keith R. Packard <keithp@keithp.com>
+ * Carl D. Worth <cworth@cworth.org>
*
* 2002-07-15: Converted from XRenderCompositeDoublePoly to cairo_trap. Carl D. Worth
*/
#include "cairoint.h"
-#define CAIRO_TRAPS_GROWTH_INC 10
-
/* private functions */
static cairo_status_t
@@ -52,12 +63,6 @@ _compare_cairo_edge_by_slope (const void *av, const void *bv);
static cairo_fixed_16_16_t
_compute_x (cairo_line_t *line, cairo_fixed_t y);
-static double
-_compute_inverse_slope (cairo_line_t *l);
-
-static double
-_compute_x_intercept (cairo_line_t *l, double inverse_slope);
-
static int
_line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret);
@@ -68,6 +73,8 @@ _cairo_traps_init (cairo_traps_t *traps)
traps->traps_size = 0;
traps->traps = NULL;
+ traps->extents.p1.x = traps->extents.p1.y = CAIRO_MAXSHORT << 16;
+ traps->extents.p2.x = traps->extents.p2.y = CAIRO_MINSHORT << 16;
}
void
@@ -93,7 +100,8 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo
}
if (traps->num_traps >= traps->traps_size) {
- status = _cairo_traps_grow_by (traps, CAIRO_TRAPS_GROWTH_INC);
+ int inc = traps->traps_size ? traps->traps_size : 32;
+ status = _cairo_traps_grow_by (traps, inc);
if (status)
return status;
}
@@ -104,6 +112,28 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo
trap->left = *left;
trap->right = *right;
+ if (top < traps->extents.p1.y)
+ traps->extents.p1.y = top;
+ if (bottom > traps->extents.p2.y)
+ traps->extents.p2.y = bottom;
+ /*
+ * This isn't generally accurate, but it is close enough for
+ * this purpose. Assuming that the left and right segments always
+ * contain the trapezoid vertical extents, these compares will
+ * yield a containing box. Assuming that the points all come from
+ * the same figure which will eventually be completely drawn, then
+ * the compares will yield the correct overall extents
+ */
+ if (left->p1.x < traps->extents.p1.x)
+ traps->extents.p1.x = left->p1.x;
+ if (left->p2.x < traps->extents.p1.x)
+ traps->extents.p1.x = left->p2.x;
+
+ if (right->p1.x > traps->extents.p2.x)
+ traps->extents.p2.x = right->p1.x;
+ if (right->p2.x > traps->extents.p2.x)
+ traps->extents.p2.x = right->p2.x;
+
traps->num_traps++;
return CAIRO_STATUS_SUCCESS;
@@ -327,40 +357,132 @@ _compare_cairo_edge_by_current_x_slope (const void *av, const void *bv)
sub-computations -- just a bunch of determinants. I haven't
looked at complexity, (both are probably similar and it probably
doesn't matter much anyway).
+ */
-static double
-_det (double a, double b, double c, double d)
+/* XXX: Keith's new intersection code is much cleaner, and uses
+ * sufficient precision for correctly sorting intersections according
+ * to the analysis in Hobby's paper.
+ *
+ * But, when we enable this code, some things are failing, (eg. the
+ * stars in test/fill_rule get filled wrong). This could indicate a
+ * bug in one of tree places:
+ *
+ * 1) The new intersection code in this file
+ *
+ * 2) cairo_wideint.c (which is only exercised here)
+ *
+ * 3) In the current tessellator, (where the old intersection
+ * code, with its mystic increments could be masking the bug).
+ *
+ * It will likely be easier to revisit this when the new tessellation
+ * code is in place. So, for now, we'll simply disable the new
+ * intersection code.
+ */
+
+#define CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE 0
+
+#if CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
+static const cairo_fixed_32_32_t
+_det16_32 (cairo_fixed_16_16_t a,
+ cairo_fixed_16_16_t b,
+ cairo_fixed_16_16_t c,
+ cairo_fixed_16_16_t d)
{
- return a * d - b * c;
+ return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),
+ _cairo_int32x32_64_mul (b, c));
}
-static int
-_lines_intersect (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection)
+static const cairo_fixed_64_64_t
+_det32_64 (cairo_fixed_32_32_t a,
+ cairo_fixed_32_32_t b,
+ cairo_fixed_32_32_t c,
+ cairo_fixed_32_32_t d)
{
- double dx1 = cairo_fixed_to_double (l1->p1.x - l1->p2.x);
- double dy1 = cairo_fixed_to_double (l1->p1.y - l1->p2.y);
-
- double dx2 = cairo_fixed_to_double (l2->p1.x - l2->p2.x);
- double dy2 = cairo_fixed_to_double (l2->p1.y - l2->p2.y);
-
- double l1_det, l2_det;
+ return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d),
+ _cairo_int64x64_128_mul (b, c));
+}
- double den_det = _det (dx1, dy1, dx2, dy2);
+static const cairo_fixed_32_32_t
+_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a)
+{
+ return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16);
+}
- if (den_det == 0)
+static int
+_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection)
+{
+ cairo_fixed_16_16_t dx1, dx2, dy1, dy2;
+ cairo_fixed_32_32_t den_det;
+ cairo_fixed_32_32_t l1_det, l2_det;
+ cairo_fixed_64_64_t num_det;
+ cairo_fixed_32_32_t intersect_32_32;
+ cairo_fixed_48_16_t intersect_48_16;
+ cairo_fixed_16_16_t intersect_16_16;
+ cairo_quorem128_t qr;
+
+ dx1 = l1->p1.x - l1->p2.x;
+ dy1 = l1->p1.y - l1->p2.y;
+ dx2 = l2->p1.x - l2->p2.x;
+ dy2 = l2->p1.y - l2->p2.y;
+ den_det = _det16_32 (dx1, dy1,
+ dx2, dy2);
+
+ if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0)))
return 0;
- l1_det = _det (l1->p1.x, l1->p1.y,
- l1->p2.x, l1->p2.y);
- l2_det = _det (l2->p1.x, l2->p1.y,
- l2->p2.x, l2->p2.y);
+ l1_det = _det16_32 (l1->p1.x, l1->p1.y,
+ l1->p2.x, l1->p2.y);
+ l2_det = _det16_32 (l2->p1.x, l2->p1.y,
+ l2->p2.x, l2->p2.y);
- *y_intersection = _det (l1_det, dy1,
- l2_det, dy2) / den_det;
+
+ num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1),
+ l2_det, _fixed_16_16_to_fixed_32_32 (dy2));
+
+ /*
+ * Ok, this one is a bit tricky in fixed point, the denominator
+ * needs to be left with 32-bits of fraction so that the
+ * result of the divide ends up with 32-bits of fraction (64 - 32 = 32)
+ */
+ qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det));
+
+ intersect_32_32 = _cairo_int128_to_int64 (qr.quo);
+
+ /*
+ * Find the ceiling of the quotient -- divrem returns
+ * the quotient truncated towards zero, so if the
+ * quotient should be positive (num_den and den_det have same sign)
+ * bump the quotient up by one.
+ */
+
+ if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) &&
+ (_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) ==
+ _cairo_int64_ge (den_det, _cairo_int32_to_int64 (0))))
+ {
+ intersect_32_32 = _cairo_int64_add (intersect_32_32,
+ _cairo_int32_to_int64 (1));
+ }
+
+ /*
+ * Now convert from 32.32 to 48.16 and take the ceiling;
+ * this requires adding in 15 1 bits and shifting the result
+ */
+
+ intersect_32_32 = _cairo_int64_add (intersect_32_32,
+ _cairo_int32_to_int64 ((1 << 16) - 1));
+ intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16);
+
+ /*
+ * And drop the top bits
+ */
+ intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16);
+
+ *y_intersection = intersect_16_16;
return 1;
}
-*/
+#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
+
static cairo_fixed_16_16_t
_compute_x (cairo_line_t *line, cairo_fixed_t y)
{
@@ -371,6 +493,7 @@ _compute_x (cairo_line_t *line, cairo_fixed_t y)
return line->p1.x + (ex / dy);
}
+#if ! CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
static double
_compute_inverse_slope (cairo_line_t *l)
{
@@ -460,6 +583,7 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_
return 1;
}
+#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
/* The algorithm here is pretty simple:
@@ -567,32 +691,32 @@ _cairo_traps_tessellate_polygon (cairo_traps_t *traps,
return CAIRO_STATUS_SUCCESS;
}
-static int
+static cairo_bool_t
_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
{
cairo_slope_t slope_left, slope_pt, slope_right;
if (t->top > pt->y)
- return 0;
+ return FALSE;
if (t->bottom < pt->y)
- return 0;
+ return FALSE;
_cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
_cairo_slope_init (&slope_pt, &t->left.p1, pt);
if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
- return 0;
+ return FALSE;
_cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
_cairo_slope_init (&slope_pt, &t->right.p1, pt);
if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
- return 0;
+ return FALSE;
- return 1;
+ return TRUE;
}
-int
+cairo_bool_t
_cairo_traps_contain (cairo_traps_t *traps, double x, double y)
{
int i;
@@ -603,45 +727,14 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y)
for (i = 0; i < traps->num_traps; i++) {
if (_cairo_trap_contains (&traps->traps[i], &point))
- return 1;
+ return TRUE;
}
- return 0;
-}
-
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-
-static void
-_cairo_trap_extents (cairo_trapezoid_t *t, cairo_box_t *extents)
-{
- cairo_fixed_t x;
-
- if (t->top < extents->p1.y)
- extents->p1.y = t->top;
-
- if (t->bottom > extents->p2.y)
- extents->p2.y = t->bottom;
-
- x = MIN (_compute_x (&t->left, t->top),
- _compute_x (&t->left, t->bottom));
- if (x < extents->p1.x)
- extents->p1.x = x;
-
- x = MAX (_compute_x (&t->right, t->top),
- _compute_x (&t->right, t->bottom));
- if (x > extents->p2.x)
- extents->p2.x = x;
+ return FALSE;
}
void
_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
{
- int i;
-
- extents->p1.x = extents->p1.y = CAIRO_MAXSHORT << 16;
- extents->p2.x = extents->p2.y = CAIRO_MINSHORT << 16;
-
- for (i = 0; i < traps->num_traps; i++)
- _cairo_trap_extents (&traps->traps[i], extents);
+ *extents = traps->extents;
}
diff --git a/src/cairo_unicode.c b/src/cairo_unicode.c
new file mode 100644
index 000000000..92201391a
--- /dev/null
+++ b/src/cairo_unicode.c
@@ -0,0 +1,340 @@
+/* cairo_unicode.c: Unicode conversion routines
+ *
+ * The code in this file is derived from GLib's gutf8.c and
+ * ultimately from libunicode. It is relicensed under the
+ * dual LGPL/MPL with permission of the original authors.
+ *
+ * Copyright © 1999 Tom Tromey
+ * Copyright © 2005 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 cairo_unicode.c as distributed with the
+ * cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Tom Tromey.
+ * and Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Owen Taylor <otaylor@redhat.com>
+ */
+
+#include <limits.h>
+
+#include <cairoint.h>
+
+#define UTF8_COMPUTE(Char, Mask, Len) \
+ if (Char < 128) \
+ { \
+ Len = 1; \
+ Mask = 0x7f; \
+ } \
+ else if ((Char & 0xe0) == 0xc0) \
+ { \
+ Len = 2; \
+ Mask = 0x1f; \
+ } \
+ else if ((Char & 0xf0) == 0xe0) \
+ { \
+ Len = 3; \
+ Mask = 0x0f; \
+ } \
+ else if ((Char & 0xf8) == 0xf0) \
+ { \
+ Len = 4; \
+ Mask = 0x07; \
+ } \
+ else if ((Char & 0xfc) == 0xf8) \
+ { \
+ Len = 5; \
+ Mask = 0x03; \
+ } \
+ else if ((Char & 0xfe) == 0xfc) \
+ { \
+ Len = 6; \
+ Mask = 0x01; \
+ } \
+ else \
+ Len = -1;
+
+#define UTF8_LENGTH(Char) \
+ ((Char) < 0x80 ? 1 : \
+ ((Char) < 0x800 ? 2 : \
+ ((Char) < 0x10000 ? 3 : \
+ ((Char) < 0x200000 ? 4 : \
+ ((Char) < 0x4000000 ? 5 : 6)))))
+
+
+#define UTF8_GET(Result, Chars, Count, Mask, Len) \
+ (Result) = (Chars)[0] & (Mask); \
+ for ((Count) = 1; (Count) < (Len); ++(Count)) \
+ { \
+ if (((Chars)[(Count)] & 0xc0) != 0x80) \
+ { \
+ (Result) = -1; \
+ break; \
+ } \
+ (Result) <<= 6; \
+ (Result) |= ((Chars)[(Count)] & 0x3f); \
+ }
+
+#define UNICODE_VALID(Char) \
+ ((Char) < 0x110000 && \
+ (((Char) & 0xFFFFF800) != 0xD800) && \
+ ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
+ ((Char) & 0xFFFE) != 0xFFFE)
+
+
+static const char utf8_skip_data[256] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
+};
+
+#define UTF8_NEXT_CHAR(p) (char *)((p) + utf8_skip_data[*(unsigned char *)(p)])
+
+/* Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
+ * If @p does not point to a valid UTF-8 encoded character, results are
+ * undefined.
+ **/
+static uint32_t
+_utf8_get_char (const char *p)
+{
+ int i, mask = 0, len;
+ uint32_t result;
+ unsigned char c = (unsigned char) *p;
+
+ UTF8_COMPUTE (c, mask, len);
+ if (len == -1)
+ return (uint32_t)-1;
+ UTF8_GET (result, p, i, mask, len);
+
+ return result;
+}
+
+/* Like _utf8_get_char, but take a maximum length
+ * and return (uint32_t)-2 on incomplete trailing character
+ */
+static uint32_t
+_utf8_get_char_extended (const char *p,
+ long max_len)
+{
+ int i, len;
+ uint32_t wc = (unsigned char) *p;
+
+ if (wc < 0x80) {
+ return wc;
+ } else if (wc < 0xc0) {
+ return (uint32_t)-1;
+ } else if (wc < 0xe0) {
+ len = 2;
+ wc &= 0x1f;
+ } else if (wc < 0xf0) {
+ len = 3;
+ wc &= 0x0f;
+ } else if (wc < 0xf8) {
+ len = 4;
+ wc &= 0x07;
+ } else if (wc < 0xfc) {
+ len = 5;
+ wc &= 0x03;
+ } else if (wc < 0xfe) {
+ len = 6;
+ wc &= 0x01;
+ } else {
+ return (uint32_t)-1;
+ }
+
+ if (max_len >= 0 && len > max_len) {
+ for (i = 1; i < max_len; i++) {
+ if ((((unsigned char *)p)[i] & 0xc0) != 0x80)
+ return (uint32_t)-1;
+ }
+ return (uint32_t)-2;
+ }
+
+ for (i = 1; i < len; ++i) {
+ uint32_t ch = ((unsigned char *)p)[i];
+
+ if ((ch & 0xc0) != 0x80) {
+ if (ch)
+ return (uint32_t)-1;
+ else
+ return (uint32_t)-2;
+ }
+
+ wc <<= 6;
+ wc |= (ch & 0x3f);
+ }
+
+ if (UTF8_LENGTH(wc) != len)
+ return (uint32_t)-1;
+
+ return wc;
+}
+
+/**
+ * _cairo_utf8_to_utf32:
+ * @str: an UTF-8 string
+ * @len: length of @str in bytes, or -1 if it is nul-terminated.
+ * If @len is supplied and the string has an embedded nul
+ * byte, only the portion before the nul byte is converted.
+ * @result: location to store a pointer to a newly allocated UTF-32
+ * string (always native endian). Free with free(). A 0
+ * word will be written after the last character.
+ * @items_written: location to store number of 32-bit words
+ * written. (Not including the trailing 0)
+ *
+ * Converts a UTF-8 string to UCS-4. UCS-4 is an encoding of Unicode
+ * with 1 32-bit word per character. The string is validated to
+ * consist entirely of valid Unicode characters.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if the entire string was
+ * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an
+ * an invalid sequence was found.
+ **/
+cairo_status_t
+_cairo_utf8_to_ucs4 (const char *str,
+ int len,
+ uint32_t **result,
+ int *items_written)
+{
+ uint32_t *str32 = NULL;
+ int n_chars, i;
+ const char *in;
+
+ in = str;
+ n_chars = 0;
+ while ((len < 0 || str + len - in > 0) && *in)
+ {
+ uint32_t wc = _utf8_get_char_extended (in, str + len - in);
+ if (wc & 0x80000000 || !UNICODE_VALID (wc))
+ return CAIRO_STATUS_INVALID_STRING;
+
+ n_chars++;
+ if (n_chars == INT_MAX)
+ return CAIRO_STATUS_INVALID_STRING;
+
+ in = UTF8_NEXT_CHAR (in);
+ }
+
+ str32 = malloc (sizeof (uint32_t) * (n_chars + 1));
+ if (!str32)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ in = str;
+ for (i=0; i < n_chars; i++) {
+ str32[i] = _utf8_get_char (in);
+ in = UTF8_NEXT_CHAR (in);
+ }
+ str32[i] = 0;
+
+ *result = str32;
+ if (items_written)
+ *items_written = n_chars;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * _cairo_utf8_to_utf16:
+ * @str: an UTF-8 string
+ * @len: length of @str in bytes, or -1 if it is nul-terminated.
+ * If @len is supplied and the string has an embedded nul
+ * byte, only the portion before the nul byte is converted.
+ * @result: location to store a pointer to a newly allocated UTF-16
+ * string (always native endian). Free with free(). A 0
+ * word will be written after the last character.
+ * @items_written: location to store number of 16-bit words
+ * written. (Not including the trailing 0)
+ *
+ * Converts a UTF-8 string to UTF-16. UTF-16 is an encoding of Unicode
+ * where characters are represented either as a single 16-bit word, or
+ * as a pair of 16-bit "surrogates". The string is validated to
+ * consist entirely of valid Unicode characters.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if the entire string was
+ * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an
+ * an invalid sequence was found.
+ **/
+cairo_status_t
+_cairo_utf8_to_utf16 (const char *str,
+ int len,
+ uint16_t **result,
+ int *items_written)
+{
+ uint16_t *str16 = NULL;
+ int n16, i;
+ const char *in;
+
+ in = str;
+ n16 = 0;
+ while ((len < 0 || str + len - in > 0) && *in) {
+ uint32_t wc = _utf8_get_char_extended (in, str + len - in);
+ if (wc & 0x80000000 || !UNICODE_VALID (wc))
+ return CAIRO_STATUS_INVALID_STRING;
+
+ if (wc < 0x10000)
+ n16 += 1;
+ else
+ n16 += 2;
+
+ if (n16 == INT_MAX - 1 || n16 == INT_MAX)
+ return CAIRO_STATUS_INVALID_STRING;
+
+ in = UTF8_NEXT_CHAR (in);
+ }
+
+
+ str16 = malloc (sizeof (uint16_t) * (n16 + 1));
+ if (!str16)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ in = str;
+ for (i = 0; i < n16;) {
+ uint32_t wc = _utf8_get_char (in);
+
+ if (wc < 0x10000) {
+ str16[i++] = wc;
+ } else {
+ str16[i++] = (wc - 0x10000) / 0x400 + 0xd800;
+ str16[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
+ }
+
+ in = UTF8_NEXT_CHAR (in);
+ }
+
+ str16[i] = 0;
+
+ *result = str16;
+ if (items_written)
+ *items_written = n16;
+
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo_win32_font.c b/src/cairo_win32_font.c
new file mode 100644
index 000000000..02f0cffd6
--- /dev/null
+++ b/src/cairo_win32_font.c
@@ -0,0 +1,1252 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 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):
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "cairo-win32-private.h"
+
+#ifndef SPI_GETFONTSMOOTHINGTYPE
+#define SPI_GETFONTSMOOTHINGTYPE 0x200a
+#endif
+#ifndef FE_FONTSMOOTHINGCLEARTYPE
+#define FE_FONTSMOOTHINGCLEARTYPE 2
+#endif
+#ifndef CLEARTYPE_QUALITY
+#define CLEARTYPE_QUALITY 5
+#endif
+
+const cairo_font_backend_t cairo_win32_font_backend;
+
+#define LOGICAL_SCALE 32
+
+typedef struct {
+ cairo_font_t base;
+
+ LOGFONTW logfont;
+
+ BYTE quality;
+
+ /* We do drawing and metrics computation in a "logical space" which
+ * is similar to font space, except that it is scaled by a factor
+ * of the (desired font size) * (LOGICAL_SCALE). The multiplication
+ * by LOGICAL_SCALE allows for sub-pixel precision.
+ */
+ double logical_scale;
+
+ /* The size we should actually request the font at from Windows; differs
+ * from the logical_scale because it is quantized for orthogonal
+ * transformations
+ */
+ double logical_size;
+
+ /* Transformations from device <=> logical space
+ */
+ cairo_matrix_t logical_to_device;
+ cairo_matrix_t device_to_logical;
+
+ /* We special case combinations of 90-degree-rotations, scales and
+ * flips ... that is transformations that take the axes to the
+ * axes. If preserve_axes is true, then swap_axes/swap_x/swap_y
+ * encode the 8 possibilities for orientation (4 rotation angles with
+ * and without a flip), and scale_x, scale_y the scale components.
+ */
+ cairo_bool_t preserve_axes;
+ cairo_bool_t swap_axes;
+ cairo_bool_t swap_x;
+ cairo_bool_t swap_y;
+ double x_scale;
+ double y_scale;
+
+ /* The size of the design unit of the font
+ */
+ int em_square;
+
+ HFONT scaled_font;
+ HFONT unscaled_font;
+
+} cairo_win32_font_t;
+
+#define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.))
+
+static void
+_compute_transform (cairo_win32_font_t *font,
+ cairo_font_scale_t *sc)
+{
+ if (NEARLY_ZERO (sc->matrix[0][1]) && NEARLY_ZERO (sc->matrix[1][0])) {
+ font->preserve_axes = TRUE;
+ font->x_scale = sc->matrix[0][0];
+ font->swap_x = (sc->matrix[0][0] < 0);
+ font->y_scale = sc->matrix[1][1];
+ font->swap_y = (sc->matrix[1][1] < 0);
+ font->swap_axes = FALSE;
+
+ } else if (NEARLY_ZERO (sc->matrix[0][0]) && NEARLY_ZERO (sc->matrix[1][1])) {
+ font->preserve_axes = TRUE;
+ font->x_scale = sc->matrix[0][1];
+ font->swap_x = (sc->matrix[0][1] < 0);
+ font->y_scale = sc->matrix[1][0];
+ font->swap_y = (sc->matrix[1][0] < 0);
+ font->swap_axes = TRUE;
+
+ } else {
+ font->preserve_axes = FALSE;
+ font->swap_x = font->swap_y = font->swap_axes = FALSE;
+ }
+
+ if (font->preserve_axes) {
+ if (font->swap_x)
+ font->x_scale = - font->x_scale;
+ if (font->swap_y)
+ font->y_scale = - font->y_scale;
+
+ font->logical_scale = LOGICAL_SCALE * font->y_scale;
+ font->logical_size = LOGICAL_SCALE * floor (font->y_scale + 0.5);
+ }
+
+ /* The font matrix has x and y "scale" components which we extract and
+ * use as character scale values.
+ */
+ cairo_matrix_set_affine (&font->logical_to_device,
+ sc->matrix[0][0],
+ sc->matrix[0][1],
+ sc->matrix[1][0],
+ sc->matrix[1][1],
+ 0, 0);
+
+ if (!font->preserve_axes) {
+ _cairo_matrix_compute_scale_factors (&font->logical_to_device,
+ &font->x_scale, &font->y_scale,
+ TRUE); /* XXX: Handle vertical text */
+
+ font->logical_size = floor (LOGICAL_SCALE * font->y_scale + 0.5);
+ font->logical_scale = LOGICAL_SCALE * font->y_scale;
+ }
+
+ cairo_matrix_scale (&font->logical_to_device,
+ 1.0 / font->logical_scale, 1.0 / font->logical_scale);
+
+ font->device_to_logical = font->logical_to_device;
+ if (!CAIRO_OK (cairo_matrix_invert (&font->device_to_logical)))
+ cairo_matrix_set_identity (&font->device_to_logical);
+}
+
+static BYTE
+_get_system_quality (void)
+{
+ BOOL font_smoothing;
+
+ if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
+ _cairo_win32_print_gdi_error ("_get_system_quality");
+ return FALSE;
+ }
+
+ if (font_smoothing) {
+ OSVERSIONINFO version_info;
+
+ version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+
+ if (!GetVersionEx (&version_info)) {
+ _cairo_win32_print_gdi_error ("_get_system_quality");
+ return FALSE;
+ }
+
+ if (version_info.dwMajorVersion > 5 ||
+ (version_info.dwMajorVersion == 5 &&
+ version_info.dwMinorVersion >= 1)) { /* XP or newer */
+ UINT smoothing_type;
+
+ if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE,
+ 0, &smoothing_type, 0)) {
+ _cairo_win32_print_gdi_error ("_get_system_quality");
+ return FALSE;
+ }
+
+ if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
+ return CLEARTYPE_QUALITY;
+ }
+
+ return ANTIALIASED_QUALITY;
+ } else
+ return DEFAULT_QUALITY;
+}
+
+static cairo_font_t *
+_win32_font_create (LOGFONTW *logfont,
+ cairo_font_scale_t *scale)
+{
+ cairo_win32_font_t *f;
+
+ f = malloc (sizeof(cairo_win32_font_t));
+ if (f == NULL)
+ return NULL;
+
+ f->logfont = *logfont;
+ f->quality = _get_system_quality ();
+ f->em_square = 0;
+ f->scaled_font = NULL;
+ f->unscaled_font = NULL;
+
+ _compute_transform (f, scale);
+
+ _cairo_font_init ((cairo_font_t *)f, scale, &cairo_win32_font_backend);
+
+ return (cairo_font_t *)f;
+}
+
+static cairo_status_t
+_win32_font_set_world_transform (cairo_win32_font_t *font,
+ HDC hdc)
+{
+ XFORM xform;
+
+ xform.eM11 = font->logical_to_device.m[0][0];
+ xform.eM21 = font->logical_to_device.m[1][0];
+ xform.eM12 = font->logical_to_device.m[0][1];
+ xform.eM22 = font->logical_to_device.m[1][1];
+ xform.eDx = font->logical_to_device.m[2][0];
+ xform.eDy = font->logical_to_device.m[2][1];
+
+ if (!SetWorldTransform (hdc, &xform))
+ return _cairo_win32_print_gdi_error ("_win32_font_set_world_transform");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_win32_font_set_identity_transform (HDC hdc)
+{
+ if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY))
+ return _cairo_win32_print_gdi_error ("_win32_font_set_identity_transform");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static HDC
+_get_global_font_dc (void)
+{
+ static HDC hdc;
+
+ if (!hdc) {
+ hdc = CreateCompatibleDC (NULL);
+ if (!hdc) {
+ _cairo_win32_print_gdi_error ("_get_global_font_dc");
+ return NULL;
+ }
+
+ if (!SetGraphicsMode (hdc, GM_ADVANCED)) {
+ _cairo_win32_print_gdi_error ("_get_global_font_dc");
+ DeleteDC (hdc);
+ return NULL;
+ }
+ }
+
+ return hdc;
+}
+
+static HFONT
+_win32_font_get_scaled_font (cairo_win32_font_t *font)
+{
+ if (!font->scaled_font) {
+ LOGFONTW logfont = font->logfont;
+ logfont.lfHeight = font->logical_size;
+ logfont.lfWidth = 0;
+ logfont.lfEscapement = 0;
+ logfont.lfOrientation = 0;
+ logfont.lfQuality = font->quality;
+
+ font->scaled_font = CreateFontIndirectW (&logfont);
+ if (!font->scaled_font) {
+ _cairo_win32_print_gdi_error ("_win32_font_get_scaled_font");
+ return NULL;
+ }
+ }
+
+ return font->scaled_font;
+}
+
+static HFONT
+_win32_font_get_unscaled_font (cairo_win32_font_t *font,
+ HDC hdc)
+{
+ if (!font->unscaled_font) {
+ OUTLINETEXTMETRIC *otm;
+ unsigned int otm_size;
+ HFONT scaled_font;
+ LOGFONTW logfont;
+
+ scaled_font = _win32_font_get_scaled_font (font);
+ if (!scaled_font)
+ return NULL;
+
+ if (!SelectObject (hdc, scaled_font)) {
+ _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:SelectObject");
+ return NULL;
+ }
+
+ otm_size = GetOutlineTextMetrics (hdc, 0, NULL);
+ if (!otm_size) {
+ _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
+ return NULL;
+ }
+
+ otm = malloc (otm_size);
+ if (!otm)
+ return NULL;
+
+ if (!GetOutlineTextMetrics (hdc, otm_size, otm)) {
+ _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
+ free (otm);
+ return NULL;
+ }
+
+ font->em_square = otm->otmEMSquare;
+ free (otm);
+
+ logfont = font->logfont;
+ logfont.lfHeight = font->em_square;
+ logfont.lfWidth = 0;
+ logfont.lfEscapement = 0;
+ logfont.lfOrientation = 0;
+ logfont.lfQuality = font->quality;
+
+ font->unscaled_font = CreateFontIndirectW (&logfont);
+ if (!font->unscaled_font) {
+ _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:CreateIndirect");
+ return NULL;
+ }
+ }
+
+ return font->unscaled_font;
+}
+
+static cairo_status_t
+_cairo_win32_font_select_unscaled_font (cairo_font_t *font,
+ HDC hdc)
+{
+ cairo_status_t status;
+ HFONT hfont;
+ HFONT old_hfont = NULL;
+
+ hfont = _win32_font_get_unscaled_font ((cairo_win32_font_t *)font, hdc);
+ if (!hfont)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ old_hfont = SelectObject (hdc, hfont);
+ if (!old_hfont)
+ return _cairo_win32_print_gdi_error ("_cairo_win32_font_select_unscaled_font");
+
+ status = _win32_font_set_identity_transform (hdc);
+ if (!CAIRO_OK (status)) {
+ SelectObject (hdc, old_hfont);
+ return status;
+ }
+
+ SetMapMode (hdc, MM_TEXT);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_win32_font_done_unscaled_font (cairo_font_t *font)
+{
+}
+
+/* implement the font backend interface */
+
+static cairo_status_t
+_cairo_win32_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ cairo_font_scale_t *scale,
+ cairo_font_t **font_out)
+{
+ LOGFONTW logfont;
+ cairo_font_t *font;
+ uint16_t *face_name;
+ int face_name_len;
+ cairo_status_t status;
+
+ status = _cairo_utf8_to_utf16 (family, -1, &face_name, &face_name_len);
+ if (!CAIRO_OK (status))
+ return status;
+
+ if (face_name_len > LF_FACESIZE - 1) {
+ free (face_name);
+ return CAIRO_STATUS_INVALID_STRING;
+ }
+
+ memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * (face_name_len + 1));
+ free (face_name);
+
+ logfont.lfHeight = 0; /* filled in later */
+ logfont.lfWidth = 0; /* filled in later */
+ logfont.lfEscapement = 0; /* filled in later */
+ logfont.lfOrientation = 0; /* filled in later */
+
+ switch (weight) {
+ case CAIRO_FONT_WEIGHT_NORMAL:
+ default:
+ logfont.lfWeight = FW_NORMAL;
+ break;
+ case CAIRO_FONT_WEIGHT_BOLD:
+ logfont.lfWeight = FW_BOLD;
+ break;
+ }
+
+ switch (slant) {
+ case CAIRO_FONT_SLANT_NORMAL:
+ default:
+ logfont.lfItalic = FALSE;
+ break;
+ case CAIRO_FONT_SLANT_ITALIC:
+ case CAIRO_FONT_SLANT_OBLIQUE:
+ logfont.lfItalic = TRUE;
+ break;
+ }
+
+ logfont.lfUnderline = FALSE;
+ logfont.lfStrikeOut = FALSE;
+ /* The docs for LOGFONT discourage using this, since the
+ * interpretation is locale-specific, but it's not clear what
+ * would be a better alternative.
+ */
+ logfont.lfCharSet = DEFAULT_CHARSET;
+ logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ logfont.lfQuality = DEFAULT_QUALITY; /* filled in later */
+ logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+
+ if (!logfont.lfFaceName)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ font = _win32_font_create (&logfont, scale);
+ if (!font)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ *font_out = font;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_win32_font_destroy_font (void *abstract_font)
+{
+ cairo_win32_font_t *font = abstract_font;
+
+ if (font->scaled_font)
+ DeleteObject (font->scaled_font);
+
+ if (font->unscaled_font)
+ DeleteObject (font->unscaled_font);
+
+ free (font);
+}
+
+static void
+_cairo_win32_font_destroy_unscaled_font (void *abstract_font)
+{
+}
+
+static void
+_cairo_win32_font_get_glyph_cache_key (void *abstract_font,
+ cairo_glyph_cache_key_t *key)
+{
+}
+
+static cairo_status_t
+_cairo_win32_font_text_to_glyphs (void *abstract_font,
+ const unsigned char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
+{
+ cairo_win32_font_t *font = abstract_font;
+ uint16_t *utf16;
+ int n16;
+ GCP_RESULTSW gcp_results;
+ unsigned int buffer_size, i;
+ WCHAR *glyph_indices = NULL;
+ int *dx = NULL;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ double x_pos;
+ HDC hdc = NULL;
+
+ status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16);
+ if (!CAIRO_OK (status))
+ return status;
+
+ gcp_results.lStructSize = sizeof (GCP_RESULTS);
+ gcp_results.lpOutString = NULL;
+ gcp_results.lpOrder = NULL;
+ gcp_results.lpCaretPos = NULL;
+ gcp_results.lpClass = NULL;
+
+ buffer_size = MAX (n16 * 1.2, 16); /* Initially guess number of chars plus a few */
+ if (buffer_size > INT_MAX) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL1;
+ }
+
+ hdc = _get_global_font_dc ();
+ if (!hdc) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL1;
+ }
+
+ status = cairo_win32_font_select_font (&font->base, hdc);
+ if (!CAIRO_OK (status))
+ goto FAIL1;
+
+ while (TRUE) {
+ if (glyph_indices) {
+ free (glyph_indices);
+ glyph_indices = NULL;
+ }
+ if (dx) {
+ free (dx);
+ dx = NULL;
+ }
+
+ glyph_indices = malloc (sizeof (WCHAR) * buffer_size);
+ dx = malloc (sizeof (int) * buffer_size);
+ if (!glyph_indices || !dx) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL2;
+ }
+
+ gcp_results.nGlyphs = buffer_size;
+ gcp_results.lpDx = dx;
+ gcp_results.lpGlyphs = glyph_indices;
+
+ if (!GetCharacterPlacementW (hdc, utf16, n16,
+ 0,
+ &gcp_results,
+ GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER)) {
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_font_text_to_glyphs");
+ goto FAIL2;
+ }
+
+ if (gcp_results.lpDx && gcp_results.lpGlyphs)
+ break;
+
+ /* Too small a buffer, try again */
+
+ buffer_size *= 1.5;
+ if (buffer_size > INT_MAX) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL2;
+ }
+ }
+
+ *num_glyphs = gcp_results.nGlyphs;
+ *glyphs = malloc (sizeof (cairo_glyph_t) * gcp_results.nGlyphs);
+ if (!*glyphs) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL2;
+ }
+
+ x_pos = 0;
+ for (i = 0; i < gcp_results.nGlyphs; i++) {
+ (*glyphs)[i].index = glyph_indices[i];
+ (*glyphs)[i].x = x_pos ;
+ (*glyphs)[i].y = 0;
+
+ x_pos += dx[i] / font->logical_scale;
+ }
+
+ FAIL2:
+ if (glyph_indices)
+ free (glyph_indices);
+ if (dx)
+ free (dx);
+
+ cairo_win32_font_done_font (&font->base);
+
+ FAIL1:
+ free (utf16);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_win32_font_font_extents (void *abstract_font,
+ cairo_font_extents_t *extents)
+{
+ cairo_win32_font_t *font = abstract_font;
+ cairo_status_t status;
+ TEXTMETRIC metrics;
+ HDC hdc;
+
+ hdc = _get_global_font_dc ();
+ if (!hdc)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (font->preserve_axes) {
+ /* For 90-degree rotations (including 0), we get the metrics
+ * from the GDI in logical space, then convert back to font space
+ */
+ status = cairo_win32_font_select_font (&font->base, hdc);
+ if (!CAIRO_OK (status))
+ return status;
+ GetTextMetrics (hdc, &metrics);
+ cairo_win32_font_done_font (&font->base);
+
+ extents->ascent = metrics.tmAscent / font->logical_scale;
+ extents->descent = metrics.tmDescent / font->logical_scale;
+
+ extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / font->logical_scale;
+ extents->max_x_advance = metrics.tmMaxCharWidth / font->logical_scale;
+ extents->max_y_advance = 0;
+
+ } else {
+ /* For all other transformations, we use the design metrics
+ * of the font. The GDI results from GetTextMetrics() on a
+ * transformed font are inexplicably large and we want to
+ * avoid them.
+ */
+ status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
+ if (!CAIRO_OK (status))
+ return status;
+ GetTextMetrics (hdc, &metrics);
+ _cairo_win32_font_done_unscaled_font (&font->base);
+
+ extents->ascent = (double)metrics.tmAscent / font->em_square;
+ extents->descent = metrics.tmDescent * font->em_square;
+ extents->height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / font->em_square;
+ extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / font->em_square;
+ extents->max_y_advance = 0;
+
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_font_glyph_extents (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
+{
+ cairo_win32_font_t *font = abstract_font;
+ static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
+ GLYPHMETRICS metrics;
+ cairo_status_t status;
+ HDC hdc;
+
+ hdc = _get_global_font_dc ();
+ if (!hdc)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ /* We handle only the case num_glyphs == 1, glyphs[i].x == glyphs[0].y == 0.
+ * This is all that the calling code triggers, and the backend interface
+ * will eventually be changed to match
+ */
+ assert (num_glyphs == 1);
+
+ if (font->preserve_axes) {
+ /* If we aren't rotating / skewing the axes, then we get the metrics
+ * from the GDI in device space and convert to font space.
+ */
+ status = cairo_win32_font_select_font (&font->base, hdc);
+ if (!CAIRO_OK (status))
+ return status;
+ GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
+ &metrics, 0, NULL, &matrix);
+ cairo_win32_font_done_font (&font->base);
+
+ if (font->swap_axes) {
+ extents->x_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
+ extents->y_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
+ extents->width = metrics.gmBlackBoxY / font->y_scale;
+ extents->height = metrics.gmBlackBoxX / font->x_scale;
+ extents->x_advance = metrics.gmCellIncY / font->x_scale;
+ extents->y_advance = metrics.gmCellIncX / font->y_scale;
+ } else {
+ extents->x_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
+ extents->y_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
+ extents->width = metrics.gmBlackBoxX / font->x_scale;
+ extents->height = metrics.gmBlackBoxY / font->y_scale;
+ extents->x_advance = metrics.gmCellIncX / font->x_scale;
+ extents->y_advance = metrics.gmCellIncY / font->y_scale;
+ }
+
+ if (font->swap_x) {
+ extents->x_bearing = (- extents->x_bearing - extents->width);
+ extents->x_advance = - extents->x_advance;
+ }
+
+ if (font->swap_y) {
+ extents->y_bearing = (- extents->y_bearing - extents->height);
+ extents->y_advance = - extents->y_advance;
+ }
+
+ } else {
+ /* For all other transformations, we use the design metrics
+ * of the font.
+ */
+ status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
+ GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
+ &metrics, 0, NULL, &matrix);
+ _cairo_win32_font_done_unscaled_font (&font->base);
+
+ extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / font->em_square;
+ extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / font->em_square;
+ extents->width = (double)metrics.gmBlackBoxX / font->em_square;
+ extents->height = (double)metrics.gmBlackBoxY / font->em_square;
+ extents->x_advance = (double)metrics.gmCellIncX / font->em_square;
+ extents->y_advance = (double)metrics.gmCellIncY / font->em_square;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_cairo_win32_font_glyph_bbox (void *abstract_font,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
+{
+ static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
+ cairo_win32_font_t *font = abstract_font;
+ int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
+
+ if (num_glyphs > 0) {
+ HDC hdc = _get_global_font_dc ();
+ GLYPHMETRICS metrics;
+ cairo_status_t status;
+ int i;
+
+ if (!hdc)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ status = cairo_win32_font_select_font (&font->base, hdc);
+ if (!CAIRO_OK (status))
+ return status;
+
+ for (i = 0; i < num_glyphs; i++) {
+ int x = floor (0.5 + glyphs[i].x);
+ int y = floor (0.5 + glyphs[i].y);
+
+ GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | GGO_GLYPH_INDEX,
+ &metrics, 0, NULL, &matrix);
+
+ if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x)
+ x1 = x + metrics.gmptGlyphOrigin.x;
+ if (i == 0 || y1 > y - metrics.gmptGlyphOrigin.y)
+ y1 = y - metrics.gmptGlyphOrigin.y;
+ if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX)
+ x2 = x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX;
+ if (i == 0 || y2 < y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY)
+ y2 = y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY;
+ }
+
+ cairo_win32_font_done_font (&font->base);
+ }
+
+ bbox->p1.x = _cairo_fixed_from_int (x1);
+ bbox->p1.y = _cairo_fixed_from_int (y1);
+ bbox->p2.x = _cairo_fixed_from_int (x2);
+ bbox->p2.y = _cairo_fixed_from_int (y2);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+typedef struct {
+ cairo_win32_font_t *font;
+ HDC hdc;
+
+ cairo_array_t glyphs;
+ cairo_array_t dx;
+
+ int start_x;
+ int last_x;
+ int last_y;
+} cairo_glyph_state_t;
+
+static void
+_start_glyphs (cairo_glyph_state_t *state,
+ cairo_win32_font_t *font,
+ HDC hdc)
+{
+ state->hdc = hdc;
+ state->font = font;
+
+ _cairo_array_init (&state->glyphs, sizeof (WCHAR));
+ _cairo_array_init (&state->dx, sizeof (int));
+}
+
+static cairo_status_t
+_flush_glyphs (cairo_glyph_state_t *state)
+{
+ int dx = 0;
+ if (!_cairo_array_append (&state->dx, &dx, 1))
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (!ExtTextOutW (state->hdc,
+ state->start_x, state->last_y,
+ ETO_GLYPH_INDEX,
+ NULL,
+ (WCHAR *)state->glyphs.elements,
+ state->glyphs.num_elements,
+ (int *)state->dx.elements)) {
+ return _cairo_win32_print_gdi_error ("_flush_glyphs");
+ }
+
+ _cairo_array_truncate (&state->glyphs, 0);
+ _cairo_array_truncate (&state->dx, 0);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_add_glyph (cairo_glyph_state_t *state,
+ unsigned long index,
+ double device_x,
+ double device_y)
+{
+ double user_x = device_x;
+ double user_y = device_y;
+ WCHAR glyph_index = index;
+ int logical_x, logical_y;
+
+ cairo_matrix_transform_point (&state->font->device_to_logical, &user_x, &user_y);
+
+ logical_x = floor (user_x + 0.5);
+ logical_y = floor (user_y + 0.5);
+
+ if (state->glyphs.num_elements > 0) {
+ int dx;
+
+ if (logical_y != state->last_y) {
+ cairo_status_t status = _flush_glyphs (state);
+ if (!CAIRO_OK (status))
+ return status;
+ state->start_x = logical_x;
+ }
+
+ dx = logical_x - state->last_x;
+ if (!_cairo_array_append (&state->dx, &dx, 1))
+ return CAIRO_STATUS_NO_MEMORY;
+ } else {
+ state->start_x = logical_x;
+ }
+
+ state->last_x = logical_x;
+ state->last_y = logical_y;
+
+ _cairo_array_append (&state->glyphs, &glyph_index, 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_finish_glyphs (cairo_glyph_state_t *state)
+{
+ _flush_glyphs (state);
+
+ _cairo_array_fini (&state->glyphs);
+ _cairo_array_fini (&state->dx);
+}
+
+static cairo_status_t
+_draw_glyphs_on_surface (cairo_win32_surface_t *surface,
+ cairo_win32_font_t *font,
+ COLORREF color,
+ int x_offset,
+ int y_offset,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_glyph_state_t state;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ int i;
+
+ if (!SaveDC (surface->dc))
+ return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC");
+
+ status = cairo_win32_font_select_font (&font->base, surface->dc);
+ if (!CAIRO_OK (status))
+ goto FAIL1;
+
+ SetTextColor (surface->dc, color);
+ SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT);
+ SetBkMode (surface->dc, TRANSPARENT);
+
+ _start_glyphs (&state, font, surface->dc);
+
+ for (i = 0; i < num_glyphs; i++) {
+ status = _add_glyph (&state, glyphs[i].index,
+ glyphs[i].x - x_offset, glyphs[i].y - y_offset);
+ if (!CAIRO_OK (status))
+ goto FAIL2;
+ }
+
+ FAIL2:
+ _finish_glyphs (&state);
+ cairo_win32_font_done_font (&font->base);
+ FAIL1:
+ RestoreDC (surface->dc, 1);
+
+ return status;
+}
+
+/* Duplicate the green channel of a 4-channel mask in the alpha channel, then
+ * invert the whole mask.
+ */
+static void
+_compute_argb32_mask_alpha (cairo_win32_surface_t *mask_surface)
+{
+ cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image;
+ int i, j;
+
+ for (i = 0; i < image->height; i++) {
+ uint32_t *p = (uint32_t *) (image->data + i * image->stride);
+ for (j = 0; j < image->width; j++) {
+ *p = 0xffffffff ^ (*p | ((*p & 0x0000ff00) << 16));
+ p++;
+ }
+ }
+}
+
+/* Invert a mask
+ */
+static void
+_invert_argb32_mask (cairo_win32_surface_t *mask_surface)
+{
+ cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image;
+ int i, j;
+
+ for (i = 0; i < image->height; i++) {
+ uint32_t *p = (uint32_t *) (image->data + i * image->stride);
+ for (j = 0; j < image->width; j++) {
+ *p = 0xffffffff ^ *p;
+ p++;
+ }
+ }
+}
+
+/* Compute an alpha-mask from a monochrome RGB24 image
+ */
+static cairo_surface_t *
+_compute_a8_mask (cairo_win32_surface_t *mask_surface)
+{
+ cairo_image_surface_t *image24 = (cairo_image_surface_t *)mask_surface->image;
+ cairo_image_surface_t *image8;
+ int i, j;
+
+ image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8,
+ image24->width, image24->height);
+ if (!image8)
+ return NULL;
+
+ for (i = 0; i < image24->height; i++) {
+ uint32_t *p = (uint32_t *) (image24->data + i * image24->stride);
+ unsigned char *q = (unsigned char *) (image8->data + i * image8->stride);
+
+ for (j = 0; j < image24->width; j++) {
+ *q = 255 - ((*p & 0x0000ff00) >> 8);
+ p++;
+ q++;
+ }
+ }
+
+ return &image8->base;
+}
+
+static cairo_status_t
+_cairo_win32_font_show_glyphs (void *abstract_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *generic_surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_win32_font_t *font = abstract_font;
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
+ cairo_status_t status;
+
+ if (width == 0 || height == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (_cairo_surface_is_win32 (generic_surface) &&
+ surface->format == CAIRO_FORMAT_RGB24 &&
+ operator == CAIRO_OPERATOR_OVER &&
+ pattern->type == CAIRO_PATTERN_SOLID &&
+ _cairo_pattern_is_opaque (pattern)) {
+
+ cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)pattern;
+
+ /* When compositing OVER on a GDI-understood surface, with a
+ * solid opaque color, we can just call ExtTextOut directly.
+ */
+ COLORREF new_color;
+
+ new_color = RGB (((int)(0xffff * solid_pattern->red)) >> 8,
+ ((int)(0xffff * solid_pattern->green)) >> 8,
+ ((int)(0xffff * solid_pattern->blue)) >> 8);
+
+ status = _draw_glyphs_on_surface (surface, font, new_color,
+ 0, 0,
+ glyphs, num_glyphs);
+
+ return status;
+ } else {
+ /* Otherwise, we need to draw using software fallbacks. We create a mask
+ * surface by drawing the the glyphs onto a DIB, black-on-white then
+ * inverting. GDI outputs gamma-corrected images so inverted black-on-white
+ * is very different from white-on-black. We favor the more common
+ * case where the final output is dark-on-light.
+ */
+ cairo_win32_surface_t *tmp_surface;
+ cairo_surface_t *mask_surface;
+ cairo_surface_pattern_t mask;
+ RECT r;
+
+ tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height);
+ if (!tmp_surface)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ r.left = 0;
+ r.top = 0;
+ r.right = width;
+ r.bottom = height;
+ FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH));
+
+ _draw_glyphs_on_surface (tmp_surface, font, RGB (0, 0, 0),
+ dest_x, dest_y,
+ glyphs, num_glyphs);
+
+ if (font->quality == CLEARTYPE_QUALITY) {
+ /* For ClearType, we need a 4-channel mask. If we are compositing on
+ * a surface with alpha, we need to compute the alpha channel of
+ * the mask (we just copy the green channel). But for a destination
+ * surface without alpha the alpha channel of the mask is ignored
+ */
+
+ if (surface->format != CAIRO_FORMAT_RGB24)
+ _compute_argb32_mask_alpha (tmp_surface);
+ else
+ _invert_argb32_mask (tmp_surface);
+
+ mask_surface = &tmp_surface->base;
+
+ /* XXX: Hacky, should expose this in cairo_image_surface */
+ pixman_image_set_component_alpha (((cairo_image_surface_t *)tmp_surface->image)->pixman_image, TRUE);
+
+ } else {
+ mask_surface = _compute_a8_mask (tmp_surface);
+ cairo_surface_destroy (&tmp_surface->base);
+ if (!mask_surface)
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ /* For operator == OVER, no-cleartype, a possible optimization here is to
+ * draw onto an intermediate ARGB32 surface and alpha-blend that with the
+ * destination
+ */
+ _cairo_pattern_init_for_surface (&mask, mask_surface);
+
+ status = _cairo_surface_composite (operator, pattern,
+ &mask.base,
+ &surface->base,
+ source_x, source_y,
+ 0, 0,
+ dest_x, dest_y,
+ width, height);
+
+ _cairo_pattern_fini (&mask.base);
+
+ cairo_surface_destroy (mask_surface);
+
+ return status;
+ }
+}
+
+static cairo_status_t
+_cairo_win32_font_glyph_path (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
+{
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+const cairo_font_backend_t cairo_win32_font_backend = {
+ _cairo_win32_font_create,
+ _cairo_win32_font_destroy_font,
+ _cairo_win32_font_destroy_unscaled_font,
+ _cairo_win32_font_font_extents,
+ _cairo_win32_font_text_to_glyphs,
+ _cairo_win32_font_glyph_extents,
+ _cairo_win32_font_glyph_bbox,
+ _cairo_win32_font_show_glyphs,
+ _cairo_win32_font_glyph_path,
+ _cairo_win32_font_get_glyph_cache_key,
+ _cairo_win32_font_create_glyph
+};
+
+/* implement the platform-specific interface */
+
+/**
+ * cairo_win32_font_create_for_logfontw:
+ * @logfont: A #LOGFONTW structure specifying the font to use.
+ * The lfHeight, lfWidth, lfOrientation and lfEscapement
+ * fields of this structure are ignored; information from
+ * @scale will be used instead.
+ * @scale: The scale at which this font will be used. The
+ * scale is given by multiplying the font matrix (see
+ * cairo_transform_font()) by the current transformation matrix.
+ * The translation elements of the resulting matrix are ignored.
+ *
+ * Creates a new font for the Win32 font backend based on a
+ * #LOGFONT. This font can then be used with
+ * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
+ * specific functions like cairo_win32_font_select_font().
+ *
+ * Return value: a newly created #cairo_font_t. Free with
+ * cairo_font_destroy() when you are done using it.
+ **/
+cairo_font_t *
+cairo_win32_font_create_for_logfontw (LOGFONTW *logfont,
+ cairo_matrix_t *scale)
+{
+ cairo_font_scale_t sc;
+
+ cairo_matrix_get_affine (scale,
+ &sc.matrix[0][0], &sc.matrix[0][1],
+ &sc.matrix[1][0], &sc.matrix[1][1],
+ NULL, NULL);
+
+ return _win32_font_create (logfont, &sc);
+}
+
+/**
+ * cairo_win32_font_select_font:
+ * @font: A #cairo_font_t from the Win32 font backend. Such an
+ * object can be created with cairo_win32_font_create_for_logfontw().
+ * @hdc: a device context
+ *
+ * Selects the font into the given device context and changes the
+ * map mode and world transformation of the device context to match
+ * that of the font. This function is intended for use when using
+ * layout APIs such as Uniscribe to do text layout with the
+ * Cairo font. After finishing using the device context, you must call
+ * cairo_win32_font_done_font() to release any resources allocated
+ * by this function.
+ *
+ * See cairo_win32_font_get_scale_factor() for converting logical
+ * coordinates from the device context to font space.
+ *
+ * Normally, calls to SaveDC() and RestoreDC() would be made around
+ * the use of this function to preserve the original graphics state.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if the operation succeeded.
+ * otherwise an error such as %CAIRO_STATUS_NO_MEMORY and
+ * the device context is unchanged.
+ **/
+cairo_status_t
+cairo_win32_font_select_font (cairo_font_t *font,
+ HDC hdc)
+{
+ cairo_status_t status;
+ HFONT hfont;
+ HFONT old_hfont = NULL;
+ int old_mode;
+
+ hfont = _win32_font_get_scaled_font ((cairo_win32_font_t *)font);
+ if (!hfont)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ old_hfont = SelectObject (hdc, hfont);
+ if (!old_hfont)
+ return _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
+
+ old_mode = SetGraphicsMode (hdc, GM_ADVANCED);
+ if (!old_mode) {
+ status = _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
+ SelectObject (hdc, old_hfont);
+ return status;
+ }
+
+ status = _win32_font_set_world_transform ((cairo_win32_font_t *)font, hdc);
+ if (!CAIRO_OK (status)) {
+ SetGraphicsMode (hdc, old_mode);
+ SelectObject (hdc, old_hfont);
+ return status;
+ }
+
+ SetMapMode (hdc, MM_TEXT);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * cairo_win32_font_done_font:
+ * @font: A #cairo_font_t from the Win32 font backend.
+ *
+ * Releases any resources allocated by cairo_win32_font_select_font()
+ **/
+void
+cairo_win32_font_done_font (cairo_font_t *font)
+{
+}
+
+/**
+ * cairo_win32_font_get_scale_factor:
+ * @font: a #cairo_font_t from the Win32 font backend
+ *
+ * Gets a scale factor between logical coordinates in the coordinate
+ * space used by cairo_win32_font_select_font() and font space coordinates.
+ *
+ * Return value: factor to multiply logical units by to get font space
+ * coordinates.
+ **/
+double
+cairo_win32_font_get_scale_factor (cairo_font_t *font)
+{
+ return 1. / ((cairo_win32_font_t *)font)->logical_scale;
+}
diff --git a/src/cairo_win32_surface.c b/src/cairo_win32_surface.c
new file mode 100644
index 000000000..dcfe6d044
--- /dev/null
+++ b/src/cairo_win32_surface.c
@@ -0,0 +1,931 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 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):
+ * Owen Taylor <otaylor@redhat.com>
+ */
+
+#include <stdio.h>
+
+#include "cairo-win32-private.h"
+
+static const cairo_surface_backend_t cairo_win32_surface_backend;
+
+/**
+ * _cairo_win32_print_gdi_error:
+ * @context: context string to display along with the error
+ *
+ * Helper function to dump out a human readable form of the
+ * current error code.
+ *
+ * Return value: A Cairo status code for the error code
+ **/
+cairo_status_t
+_cairo_win32_print_gdi_error (const char *context)
+{
+ void *lpMsgBuf;
+ DWORD last_error = GetLastError ();
+
+ if (!FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ last_error,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL)) {
+ fprintf (stderr, "%s: Unknown GDI error", context);
+ } else {
+ fprintf (stderr, "%s: %s", context, (char *)lpMsgBuf);
+
+ LocalFree (lpMsgBuf);
+ }
+
+ /* We should switch off of last_status, but we'd either return
+ * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
+ * is no CAIRO_STATUS_UNKNOWN_ERROR.
+ */
+
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+void
+cairo_set_target_win32 (cairo_t *cr,
+ HDC hdc)
+{
+ cairo_surface_t *surface;
+
+ if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
+ return;
+
+ surface = cairo_win32_surface_create (hdc);
+ if (surface == NULL) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_set_target_surface (cr, surface);
+
+ /* cairo_set_target_surface takes a reference, so we must destroy ours */
+ cairo_surface_destroy (surface);
+}
+
+static cairo_status_t
+_create_dc_and_bitmap (cairo_win32_surface_t *surface,
+ HDC original_dc,
+ cairo_format_t format,
+ int width,
+ int height,
+ char **bits_out,
+ int *rowstride_out)
+{
+ cairo_status_t status;
+
+ BITMAPINFO *bitmap_info = NULL;
+ struct {
+ BITMAPINFOHEADER bmiHeader;
+ RGBQUAD bmiColors[2];
+ } bmi_stack;
+ void *bits;
+
+ int num_palette = 0; /* Quiet GCC */
+ int i;
+
+ surface->dc = NULL;
+ surface->bitmap = NULL;
+
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB24:
+ num_palette = 0;
+ break;
+
+ case CAIRO_FORMAT_A8:
+ num_palette = 256;
+ break;
+
+ case CAIRO_FORMAT_A1:
+ num_palette = 2;
+ break;
+ }
+
+ if (num_palette > 2) {
+ bitmap_info = malloc (sizeof (BITMAPINFOHEADER) + num_palette * sizeof (RGBQUAD));
+ if (!bitmap_info)
+ return CAIRO_STATUS_NO_MEMORY;
+ } else {
+ bitmap_info = (BITMAPINFO *)&bmi_stack;
+ }
+
+ bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+ bitmap_info->bmiHeader.biWidth = width;
+ bitmap_info->bmiHeader.biHeight = - height; /* top-down */
+ bitmap_info->bmiHeader.biSizeImage = 0;
+ bitmap_info->bmiHeader.biXPelsPerMeter = 72. / 0.0254; /* unused here */
+ bitmap_info->bmiHeader.biYPelsPerMeter = 72. / 0.0254; /* unused here */
+ bitmap_info->bmiHeader.biPlanes = 1;
+
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB24:
+ bitmap_info->bmiHeader.biBitCount = 32;
+ bitmap_info->bmiHeader.biCompression = BI_RGB;
+ bitmap_info->bmiHeader.biClrUsed = 0; /* unused */
+ bitmap_info->bmiHeader.biClrImportant = 0;
+ break;
+
+ case CAIRO_FORMAT_A8:
+ bitmap_info->bmiHeader.biBitCount = 8;
+ bitmap_info->bmiHeader.biCompression = BI_RGB;
+ bitmap_info->bmiHeader.biClrUsed = 256;
+ bitmap_info->bmiHeader.biClrImportant = 0;
+
+ for (i = 0; i < 256; i++) {
+ bitmap_info->bmiColors[i].rgbBlue = i;
+ bitmap_info->bmiColors[i].rgbGreen = i;
+ bitmap_info->bmiColors[i].rgbRed = i;
+ bitmap_info->bmiColors[i].rgbReserved = 0;
+ }
+
+ break;
+
+ case CAIRO_FORMAT_A1:
+ bitmap_info->bmiHeader.biBitCount = 1;
+ bitmap_info->bmiHeader.biCompression = BI_RGB;
+ bitmap_info->bmiHeader.biClrUsed = 2;
+ bitmap_info->bmiHeader.biClrImportant = 0;
+
+ for (i = 0; i < 2; i++) {
+ bitmap_info->bmiColors[i].rgbBlue = i * 255;
+ bitmap_info->bmiColors[i].rgbGreen = i * 255;
+ bitmap_info->bmiColors[i].rgbRed = i * 255;
+ bitmap_info->bmiColors[i].rgbReserved = 0;
+ break;
+ }
+ }
+
+ surface->dc = CreateCompatibleDC (original_dc);
+ if (!surface->dc)
+ goto FAIL;
+
+ surface->bitmap = CreateDIBSection (surface->dc,
+ bitmap_info,
+ DIB_RGB_COLORS,
+ &bits,
+ NULL, 0);
+ if (!surface->bitmap)
+ goto FAIL;
+
+ surface->saved_dc_bitmap = SelectObject (surface->dc,
+ surface->bitmap);
+ if (!surface->saved_dc_bitmap)
+ goto FAIL;
+
+ if (bitmap_info && num_palette > 2)
+ free (bitmap_info);
+
+ if (bits_out)
+ *bits_out = bits;
+
+ if (rowstride_out) {
+ /* Windows bitmaps are padded to 16-bit (word) boundaries */
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB24:
+ *rowstride_out = 4 * width;
+ break;
+
+ case CAIRO_FORMAT_A8:
+ *rowstride_out = (width + 1) & -2;
+ break;
+
+ case CAIRO_FORMAT_A1:
+ *rowstride_out = ((width + 15) & -16) / 8;
+ break;
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+
+ FAIL:
+ status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap");
+
+ if (bitmap_info && num_palette > 2)
+ free (bitmap_info);
+
+ if (surface->saved_dc_bitmap) {
+ SelectObject (surface->dc, surface->saved_dc_bitmap);
+ surface->saved_dc_bitmap = NULL;
+ }
+
+ if (surface->bitmap) {
+ DeleteObject (surface->bitmap);
+ surface->bitmap = NULL;
+ }
+
+ if (surface->dc) {
+ DeleteDC (surface->dc);
+ surface->dc = NULL;
+ }
+
+ return status;
+}
+
+static cairo_surface_t *
+_cairo_win32_surface_create_for_dc (HDC original_dc,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ cairo_win32_surface_t *surface;
+ char *bits;
+ int rowstride;
+
+ surface = malloc (sizeof (cairo_win32_surface_t));
+ if (!surface)
+ return NULL;
+
+ if (_create_dc_and_bitmap (surface, original_dc, format,
+ width, height,
+ &bits, &rowstride) != CAIRO_STATUS_SUCCESS)
+ goto FAIL;
+
+ surface->image = cairo_image_surface_create_for_data (bits, format,
+ width, height, rowstride);
+ if (!surface->image)
+ goto FAIL;
+
+ surface->format = format;
+
+ surface->clip_rect.x = 0;
+ surface->clip_rect.y = 0;
+ surface->clip_rect.width = width;
+ surface->clip_rect.height = height;
+
+ surface->set_clip = 0;
+ surface->saved_clip = NULL;
+
+ _cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
+
+ return (cairo_surface_t *)surface;
+
+ FAIL:
+ if (surface->bitmap) {
+ SelectObject (surface->dc, surface->saved_dc_bitmap);
+ DeleteObject (surface->bitmap);
+ DeleteDC (surface->dc);
+ }
+ if (surface)
+ free (surface);
+
+ return NULL;
+
+}
+
+static cairo_surface_t *
+_cairo_win32_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ cairo_win32_surface_t *src = abstract_src;
+
+ return _cairo_win32_surface_create_for_dc (src->dc, format, drawable,
+ width, height);
+}
+
+/**
+ * _cairo_win32_surface_create_dib:
+ * @format: format of pixels in the surface to create
+ * @width: width of the surface, in pixels
+ * @height: height of the surface, in pixels
+ *
+ * Creates a device-independent-bitmap surface not associated with
+ * any particular existing surface or device context. The created
+ * bitmap will be unititialized.
+ *
+ * Return value: the newly created surface, or %NULL if it couldn't
+ * be created (probably because of lack of memory)
+ **/
+cairo_surface_t *
+_cairo_win32_surface_create_dib (cairo_format_t format,
+ int width,
+ int height)
+{
+ return _cairo_win32_surface_create_for_dc (NULL, format, TRUE,
+ width, height);
+}
+
+static void
+_cairo_win32_surface_destroy (void *abstract_surface)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+
+ if (surface->image)
+ cairo_surface_destroy (surface->image);
+
+ if (surface->saved_clip)
+ DeleteObject (surface->saved_clip);
+
+ /* If we created the Bitmap and DC, destroy them */
+ if (surface->bitmap) {
+ SelectObject (surface->dc, surface->saved_dc_bitmap);
+ DeleteObject (surface->bitmap);
+ DeleteDC (surface->dc);
+ }
+
+ free (surface);
+}
+
+static double
+_cairo_win32_surface_pixels_per_inch (void *abstract_surface)
+{
+ /* XXX: We should really get this value from somewhere */
+ return 96.0;
+}
+
+static cairo_status_t
+_cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
+ int x,
+ int y,
+ int width,
+ int height,
+ cairo_win32_surface_t **local_out)
+{
+ cairo_win32_surface_t *local;
+ cairo_status_t status;
+
+ local =
+ (cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface,
+ surface->format,
+ 0,
+ width, height);
+ if (!local)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (!BitBlt (local->dc,
+ 0, 0,
+ width, height,
+ surface->dc,
+ x, y,
+ SRCCOPY))
+ goto FAIL;
+
+ *local_out = local;
+
+ return CAIRO_STATUS_SUCCESS;
+
+ FAIL:
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_get_subimage");
+
+ if (local)
+ cairo_surface_destroy (&local->base);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_win32_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_win32_surface_t *local = NULL;
+ cairo_status_t status;
+
+ if (surface->image) {
+ *image_out = (cairo_image_surface_t *)surface->image;
+ *image_extra = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0,
+ surface->clip_rect.width,
+ surface->clip_rect.height, &local);
+ if (CAIRO_OK (status)) {
+ cairo_surface_set_filter (&local->base, surface->base.filter);
+ cairo_surface_set_matrix (&local->base, &surface->base.matrix);
+ cairo_surface_set_repeat (&local->base, surface->base.repeat);
+
+ *image_out = (cairo_image_surface_t *)local->image;
+ *image_extra = local;
+ }
+
+ return status;
+}
+
+static void
+_cairo_win32_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ cairo_win32_surface_t *local = image_extra;
+
+ if (local)
+ cairo_surface_destroy ((cairo_surface_t *)local);
+}
+
+static cairo_status_t
+_cairo_win32_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect,
+ void **image_extra)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_win32_surface_t *local = NULL;
+ cairo_status_t status;
+ RECT clip_box;
+ int x1, y1, x2, y2;
+
+ if (surface->image) {
+ image_rect->x = 0;
+ image_rect->y = 0;
+ image_rect->width = surface->clip_rect.width;
+ image_rect->height = surface->clip_rect.height;
+
+ *image_out = (cairo_image_surface_t *)surface->image;
+ *image_extra = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (GetClipBox (surface->dc, &clip_box) == ERROR)
+ return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
+
+ x1 = clip_box.left;
+ x2 = clip_box.right;
+ y1 = clip_box.top;
+ y2 = clip_box.bottom;
+
+ if (interest_rect->x > x1)
+ x1 = interest_rect->x;
+ if (interest_rect->y > y1)
+ y1 = interest_rect->y;
+ if (interest_rect->x + interest_rect->width < x2)
+ x2 = interest_rect->x + interest_rect->width;
+ if (interest_rect->y + interest_rect->height < y2)
+ y2 = interest_rect->y + interest_rect->height;
+
+ if (x1 >= x2 || y1 >= y2) {
+ *image_out = NULL;
+ *image_extra = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ status = _cairo_win32_surface_get_subimage (abstract_surface,
+ x1, y1, x2 - x1, y2 - y1,
+ &local);
+ if (CAIRO_OK (status)) {
+ *image_out = (cairo_image_surface_t *)local->image;
+ *image_extra = local;
+
+ image_rect->x = x1;
+ image_rect->y = y1;
+ image_rect->width = x2 - x1;
+ image_rect->height = y2 - y1;
+ }
+
+ return status;
+}
+
+static void
+_cairo_win32_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_win32_surface_t *local = image_extra;
+
+ if (!local)
+ return;
+
+ if (!BitBlt (surface->dc,
+ image_rect->x, image_rect->y,
+ image_rect->width, image_rect->height,
+ local->dc,
+ 0, 0,
+ SRCCOPY))
+ _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
+
+ cairo_surface_destroy ((cairo_surface_t *)local);
+}
+
+static cairo_status_t
+_cairo_win32_surface_clone_similar (void *surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_composite (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_pattern_t *mask_pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ cairo_win32_surface_t *dst = abstract_dst;
+ cairo_win32_surface_t *src;
+ cairo_surface_pattern_t *src_surface_pattern;
+ int alpha;
+ int integer_transform;
+ int itx, ity;
+
+ if (pattern->type != CAIRO_PATTERN_SURFACE ||
+ pattern->extend != CAIRO_EXTEND_NONE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (mask_pattern) {
+ /* FIXME: When we fully support RENDER style 4-channel
+ * masks we need to check r/g/b != 1.0.
+ */
+ if (mask_pattern->type != CAIRO_PATTERN_SOLID)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ alpha = (int)(0xffff * pattern->alpha * mask_pattern->alpha) >> 8;
+ } else {
+ alpha = (int)(0xffff * pattern->alpha) >> 8;
+ }
+
+ src_surface_pattern = (cairo_surface_pattern_t *)pattern;
+ src = (cairo_win32_surface_t *)src_surface_pattern->surface;
+
+ if (src->base.backend != dst->base.backend)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ integer_transform = _cairo_matrix_is_integer_translation (&pattern->matrix, &itx, &ity);
+ if (!integer_transform)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (alpha == 255 &&
+ src->format == dst->format &&
+ (operator == CAIRO_OPERATOR_SRC ||
+ (src->format == CAIRO_FORMAT_RGB24 && operator == CAIRO_OPERATOR_OVER))) {
+
+ if (!BitBlt (dst->dc,
+ dst_x, dst_y,
+ width, height,
+ src->dc,
+ src_x + itx, src_y + ity,
+ SRCCOPY))
+ return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
+
+ return CAIRO_STATUS_SUCCESS;
+
+ } else if (integer_transform &&
+ (src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) &&
+ dst->format == CAIRO_FORMAT_RGB24 &&
+ !src->base.repeat &&
+ operator == CAIRO_OPERATOR_OVER) {
+
+ BLENDFUNCTION blend_function;
+
+ blend_function.BlendOp = AC_SRC_OVER;
+ blend_function.BlendFlags = 0;
+ blend_function.SourceConstantAlpha = alpha;
+ blend_function.AlphaFormat = src->format == CAIRO_FORMAT_ARGB32 ? AC_SRC_ALPHA : 0;
+
+ if (!AlphaBlend (dst->dc,
+ dst_x, dst_y,
+ width, height,
+ src->dc,
+ src_x + itx, src_y + ity,
+ width, height,
+ blend_function))
+ return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_fill_rectangles (void *abstract_surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+ COLORREF new_color;
+ HBRUSH new_brush;
+ int i;
+
+ /* If we have a local image, use the fallback code; it will be as fast
+ * as calling out to GDI.
+ */
+ if (surface->image)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* We could support possibly support more operators for color->alpha = 0xffff.
+ * for CAIRO_OPERATOR_SRC, alpha doesn't matter since we know the destination
+ * image doesn't have alpha. (surface->pixman_image is non-NULL for all
+ * surfaces with alpha.)
+ */
+ if (operator != CAIRO_OPERATOR_SRC)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
+
+ new_brush = CreateSolidBrush (new_color);
+ if (!new_brush)
+ return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
+
+ for (i = 0; i < num_rects; i++) {
+ RECT rect;
+
+ rect.left = rects[i].x;
+ rect.top = rects[i].y;
+ rect.right = rects[i].x + rects[i].width;
+ rect.bottom = rects[i].y + rects[i].height;
+
+ if (!FillRect (surface->dc, &rect, new_brush))
+ goto FAIL;
+ }
+
+ DeleteObject (new_brush);
+
+ return CAIRO_STATUS_SUCCESS;
+
+ FAIL:
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
+
+ DeleteObject (new_brush);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_composite_trapezoids (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_copy_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_show_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ cairo_win32_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ /* If we are in-memory, then we set the clip on the image surface
+ * as well as on the underlying GDI surface.
+ */
+ if (surface->image)
+ _cairo_surface_set_clip_region (surface->image, region);
+
+ /* The semantics we want is that any clip set by Cairo combines
+ * is intersected with the clip on device context that the
+ * surface was created for. To implement this, we need to
+ * save the original clip when first setting a clip on surface.
+ */
+
+ if (region == NULL) {
+ /* Clear any clip set by Cairo, return to the original */
+
+ if (surface->set_clip) {
+ if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
+ return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
+
+ if (surface->saved_clip) {
+ DeleteObject (surface->saved_clip);
+ surface->saved_clip = NULL;
+ }
+
+ surface->set_clip = 0;
+ }
+
+
+ return CAIRO_STATUS_SUCCESS;
+
+ } else {
+ pixman_box16_t *boxes = pixman_region_rects (region);
+ int num_boxes = pixman_region_num_rects (region);
+ pixman_box16_t *extents = pixman_region_extents (region);
+ RGNDATA *data;
+ size_t data_size;
+ RECT *rects;
+ int i;
+ HRGN gdi_region;
+
+ /* Create a GDI region for the cairo region */
+
+ data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT);
+ data = malloc (data_size);
+ if (!data)
+ return CAIRO_STATUS_NO_MEMORY;
+ rects = (RECT *)data->Buffer;
+
+ data->rdh.dwSize = sizeof (RGNDATAHEADER);
+ data->rdh.iType = RDH_RECTANGLES;
+ data->rdh.nCount = num_boxes;
+ data->rdh.nRgnSize = num_boxes * sizeof (RECT);
+ data->rdh.rcBound.left = extents->x1;
+ data->rdh.rcBound.top = extents->y1;
+ data->rdh.rcBound.right = extents->x2;
+ data->rdh.rcBound.bottom = extents->y2;
+
+ for (i = 0; i < num_boxes; i++) {
+ rects[i].left = boxes[i].x1;
+ rects[i].top = boxes[i].y1;
+ rects[i].right = boxes[i].x2;
+ rects[i].bottom = boxes[i].y2;
+ }
+
+ gdi_region = ExtCreateRegion (NULL, data_size, data);
+ free (data);
+
+ if (!gdi_region)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (surface->set_clip) {
+ /* Combine the new region with the original clip */
+
+ if (surface->saved_clip) {
+ if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR)
+ goto FAIL;
+ }
+
+ if (SelectClipRgn (surface->dc, gdi_region) == ERROR)
+ goto FAIL;
+
+ } else {
+ /* Save the the current region */
+
+ surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
+ if (!surface->saved_clip) {
+ goto FAIL; }
+
+ /* This function has no error return! */
+ if (GetClipRgn (surface->dc, surface->saved_clip) == 0) { /* No clip */
+ DeleteObject (surface->saved_clip);
+ surface->saved_clip = NULL;
+ }
+
+ if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
+ goto FAIL;
+
+ surface->set_clip = 1;
+ }
+
+ DeleteObject (gdi_region);
+ return CAIRO_STATUS_SUCCESS;
+
+ FAIL:
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
+ DeleteObject (gdi_region);
+ return status;
+ }
+}
+
+static cairo_status_t
+_cairo_win32_surface_show_glyphs (cairo_font_t *font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ void *abstract_surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_surface_t *
+cairo_win32_surface_create (HDC hdc)
+{
+ cairo_win32_surface_t *surface;
+ RECT rect;
+
+ /* Try to figure out the drawing bounds for the Device context
+ */
+ if (GetClipBox (hdc, &rect) == ERROR) {
+ _cairo_win32_print_gdi_error ("cairo_win32_surface_create");
+ return NULL;
+ }
+
+ surface = malloc (sizeof (cairo_win32_surface_t));
+ if (!surface)
+ return NULL;
+
+ surface->image = NULL;
+ surface->format = CAIRO_FORMAT_RGB24;
+
+ surface->dc = hdc;
+ surface->bitmap = NULL;
+
+ surface->clip_rect.x = rect.left;
+ surface->clip_rect.y = rect.top;
+ surface->clip_rect.width = rect.right - rect.left;
+ surface->clip_rect.height = rect.bottom - rect.top;
+
+ surface->set_clip = 0;
+ surface->saved_clip = NULL;
+
+ _cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
+
+ return (cairo_surface_t *)surface;
+}
+
+/**
+ * _cairo_surface_is_win32:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is an #cairo_win32_surface_t
+ *
+ * Return value: True if the surface is an win32 surface
+ **/
+int
+_cairo_surface_is_win32 (cairo_surface_t *surface)
+{
+ return surface->backend == &cairo_win32_surface_backend;
+}
+
+static const cairo_surface_backend_t cairo_win32_surface_backend = {
+ _cairo_win32_surface_create_similar,
+ _cairo_win32_surface_destroy,
+ _cairo_win32_surface_pixels_per_inch,
+ _cairo_win32_surface_acquire_source_image,
+ _cairo_win32_surface_release_source_image,
+ _cairo_win32_surface_acquire_dest_image,
+ _cairo_win32_surface_release_dest_image,
+ _cairo_win32_surface_clone_similar,
+ _cairo_win32_surface_composite,
+ _cairo_win32_surface_fill_rectangles,
+ _cairo_win32_surface_composite_trapezoids,
+ _cairo_win32_surface_copy_page,
+ _cairo_win32_surface_show_page,
+ _cairo_win32_surface_set_clip_region,
+ _cairo_win32_surface_show_glyphs
+};
diff --git a/src/cairo_xcb_surface.c b/src/cairo_xcb_surface.c
index 758cf26de..0694b77a2 100644
--- a/src/cairo_xcb_surface.c
+++ b/src/cairo_xcb_surface.c
@@ -31,10 +31,11 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
+#include "cairo-xcb.h"
cairo_surface_t *
cairo_xcb_surface_create (XCBConnection *dpy,
@@ -327,14 +328,17 @@ bytes_per_line(XCBConnection *c, int width, int bpp)
return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
}
-static cairo_image_surface_t *
-_cairo_xcb_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_get_image_surface (cairo_xcb_surface_t *surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect)
{
- cairo_xcb_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
XCBGetGeometryRep *geomrep;
XCBGetImageRep *imagerep;
int bpp;
+ int x1, y1, x2, y2;
geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0);
if(!geomrep)
@@ -344,11 +348,39 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
surface->height = geomrep->height;
free(geomrep);
+ x1 = 0;
+ y1 = 0;
+ x2 = surface->width;
+ y2 = surface->height;
+
+ if (interest_rect) {
+ if (interest_rect->x > x1)
+ x1 = interest_rect->x;
+ if (interest_rect->y > y1)
+ y1 = interest_rect->y;
+ if (interest_rect->x + interest_rect->width < x2)
+ x2 = interest_rect->x + interest_rect->width;
+ if (interest_rect->y + interest_rect->height < y2)
+ y2 = interest_rect->y + interest_rect->height;
+
+ if (x1 >= x2 || y1 >= y2) {
+ *image_out = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ if (image_rect) {
+ image_rect->x = x1;
+ image_rect->y = y1;
+ image_rect->width = x2 - x1;
+ image_rect->height = y2 - y1;
+ }
+
imagerep = XCBGetImageReply(surface->dpy,
XCBGetImage(surface->dpy, ZPixmap,
surface->drawable,
- 0, 0,
- surface->width, surface->height,
+ x1, y1,
+ x2 - x1, y2 - y1,
AllPlanes), 0);
if(!imagerep)
return 0;
@@ -368,15 +400,15 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep),
&masks,
- surface->width,
- surface->height,
+ x2 - x1,
+ y2 - y1,
bytes_per_line(surface->dpy, surface->width, bpp));
} else {
image = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (XCBGetImageData(imagerep),
surface->format,
- surface->width,
- surface->height,
+ x2 - x1,
+ y2 - y1,
bytes_per_line(surface->dpy, surface->width, bpp));
}
@@ -388,7 +420,8 @@ _cairo_xcb_surface_get_image (void *abstract_surface)
_cairo_image_surface_set_repeat (image, surface->base.repeat);
_cairo_image_surface_set_matrix (image, &(surface->base.matrix));
- return image;
+ *image_out = image;
+ return CAIRO_STATUS_SUCCESS;
}
static void
@@ -402,10 +435,11 @@ _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
}
static cairo_status_t
-_cairo_xcb_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+_draw_image_surface (cairo_xcb_surface_t *surface,
+ cairo_image_surface_t *image,
+ int dst_x,
+ int dst_y)
{
- cairo_xcb_surface_t *surface = abstract_surface;
int bpp, data_len;
_cairo_xcb_surface_ensure_gc (surface);
@@ -414,7 +448,7 @@ _cairo_xcb_surface_set_image (void *abstract_surface,
XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
image->width,
image->height,
- /* dst_x */ 0, /* dst_y */ 0,
+ dst_x, dst_y,
/* left_pad */ 0, image->depth,
data_len, image->data);
@@ -422,9 +456,107 @@ _cairo_xcb_surface_set_image (void *abstract_surface,
}
static cairo_status_t
-_cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
+_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
+
+ status = _get_image_surface (surface, NULL, &image, NULL);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ cairo_surface_set_filter (&image->base, surface->base.filter);
+ cairo_surface_set_matrix (&image->base, &surface->base.matrix);
+ cairo_surface_set_repeat (&image->base, surface->base.repeat);
+
+ *image_out = image;
+ }
+
+ return status;
+}
+
+static void
+_cairo_xcb_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ cairo_surface_destroy (&image->base);
+}
+
+static cairo_status_t
+_cairo_xcb_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect_out,
+ void **image_extra)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
+
+ status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
+ if (status == CAIRO_STATUS_SUCCESS)
+ *image_out = image;
+
+ return status;
+}
+
+static void
+_cairo_xcb_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+
+ /* ignore errors */
+ _draw_image_surface (surface, image, image_rect->x, image_rect->y);
+
+ cairo_surface_destroy (&image->base);
+}
+
+static cairo_status_t
+_cairo_xcb_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_xcb_surface_t *clone;
+
+ if (src->backend == surface->base.backend ) {
+ cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
+
+ if (xcb_src->dpy == surface->dpy) {
+ *clone_out = src;
+ cairo_surface_reference (src);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+ } else if (_cairo_surface_is_image (src)) {
+ cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
+
+ clone = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_similar (surface, image_src->format, 0,
+ image_src->width, image_src->height);
+ if (clone == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _draw_image_surface (clone, image_src, 0, 0);
+
+ *clone_out = &clone->base;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
+ cairo_matrix_t *matrix)
+{
XCBRenderTRANSFORM xtransform;
if (!surface->picture.xid)
@@ -442,27 +574,42 @@ _cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
xtransform.matrix32 = 0;
xtransform.matrix33 = _cairo_fixed_from_double (1);
- if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
+ if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
{
- XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
- } else {
- /* XXX: Need support here if using an old RENDER without support
- for SetPictureTransform */
+ static const XCBRenderTRANSFORM identity = {
+ 1 << 16, 0x00000, 0x00000,
+ 0x00000, 1 << 16, 0x00000,
+ 0x00000, 0x00000, 1 << 16
+ };
+
+ if (memcmp (&xtransform, &identity, sizeof (XCBRenderTRANSFORM)) == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
+
+ XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
+_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
+ cairo_filter_t filter)
{
- cairo_xcb_surface_t *surface = abstract_surface;
char *render_filter;
- if (!(surface->picture.xid
- && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)))
+ if (!surface->picture.xid)
return CAIRO_STATUS_SUCCESS;
-
+
+ if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
+ {
+ if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
+ return CAIRO_STATUS_SUCCESS;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
switch (filter) {
case CAIRO_FILTER_FAST:
render_filter = "fast";
@@ -491,10 +638,8 @@ _cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
}
static cairo_status_t
-_cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat)
+_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat)
{
- cairo_xcb_surface_t *surface = abstract_surface;
-
CARD32 mask = XCBRenderCPRepeat;
CARD32 pa[] = { repeat };
@@ -506,33 +651,32 @@ _cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_xcb_surface_t *
-_cairo_xcb_surface_clone_similar (cairo_surface_t *src,
- cairo_xcb_surface_t *template,
- cairo_format_t format,
- int depth)
+static cairo_int_status_t
+_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface,
+ cairo_surface_attributes_t *attributes)
{
- cairo_xcb_surface_t *clone;
- cairo_image_surface_t *src_image;
-
- src_image = _cairo_surface_get_image (src);
-
- clone = (cairo_xcb_surface_t *)
- _cairo_xcb_surface_create_similar (template, format, 0,
- src_image->width,
- src_image->height);
- if (clone == NULL)
- return NULL;
-
- _cairo_xcb_surface_set_filter (clone, cairo_surface_get_filter(src));
-
- _cairo_xcb_surface_set_image (clone, src_image);
+ cairo_int_status_t status;
- _cairo_xcb_surface_set_matrix (clone, &(src_image->base.matrix));
+ status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix);
+ if (status)
+ return status;
+
+ switch (attributes->extend) {
+ case CAIRO_EXTEND_NONE:
+ _cairo_xcb_surface_set_repeat (surface, 0);
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ _cairo_xcb_surface_set_repeat (surface, 1);
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
- cairo_surface_destroy (&src_image->base);
+ status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
+ if (status)
+ return status;
- return clone;
+ return CAIRO_STATUS_SUCCESS;
}
static int
@@ -574,65 +718,80 @@ _render_operator (cairo_operator_t operator)
static cairo_int_status_t
_cairo_xcb_surface_composite (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
+ cairo_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
{
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
- cairo_xcb_surface_t *mask = (cairo_xcb_surface_t *) generic_mask;
- cairo_xcb_surface_t *src_clone = NULL;
- cairo_xcb_surface_t *mask_clone = NULL;
- XCBRenderPICTURE maskpict = { 0 };
-
+ cairo_surface_attributes_t src_attr, mask_attr;
+ cairo_xcb_surface_t *dst = abstract_dst;
+ cairo_xcb_surface_t *src;
+ cairo_xcb_surface_t *mask;
+ cairo_int_status_t status;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
- src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
- CAIRO_FORMAT_ARGB32, 32);
- if (!src_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- src = src_clone;
- }
- if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) {
- mask_clone = _cairo_xcb_surface_clone_similar (generic_mask, dst,
- CAIRO_FORMAT_A8, 8);
- if (!mask_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- mask = mask_clone;
+ status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
+ &dst->base,
+ src_x, src_y,
+ mask_x, mask_y,
+ width, height,
+ (cairo_surface_t **) &src,
+ (cairo_surface_t **) &mask,
+ &src_attr, &mask_attr);
+ if (status)
+ return status;
+
+ status = _cairo_xcb_surface_set_attributes (src, &src_attr);
+ if (CAIRO_OK (status))
+ {
+ if (mask)
+ {
+ status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
+ if (CAIRO_OK (status))
+ XCBRenderComposite (dst->dpy,
+ _render_operator (operator),
+ src->picture,
+ mask->picture,
+ dst->picture,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ mask_x + mask_attr.x_offset,
+ mask_y + mask_attr.y_offset,
+ dst_x, dst_y,
+ width, height);
+ }
+ else
+ {
+ static XCBRenderPICTURE maskpict = { 0 };
+
+ XCBRenderComposite (dst->dpy,
+ _render_operator (operator),
+ src->picture,
+ maskpict,
+ dst->picture,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ }
}
- if(mask)
- maskpict = mask->picture;
-
- XCBRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- maskpict,
- dst->picture,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
-
- /* XXX: This is messed up. If I can xcb_surface_create, then I
- should be able to xcb_surface_destroy. */
- if (src_clone)
- cairo_surface_destroy (&src_clone->base);
- if (mask_clone)
- cairo_surface_destroy (&mask_clone->base);
+ if (mask)
+ _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
+
+ _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_int_status_t
@@ -664,42 +823,60 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface,
static cairo_int_status_t
_cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- void *abstract_dst,
- int xSrc,
- int ySrc,
- cairo_trapezoid_t *traps,
- int num_traps)
+ cairo_pattern_t *pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_trapezoid_t *traps,
+ int num_traps)
{
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
- cairo_xcb_surface_t *src_clone = NULL;
+ cairo_surface_attributes_t attributes;
+ cairo_xcb_surface_t *dst = abstract_dst;
+ cairo_xcb_surface_t *src;
+ cairo_int_status_t status;
+ int render_reference_x, render_reference_y;
+ int render_src_x, render_src_y;
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
- src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
- CAIRO_FORMAT_ARGB32, 32);
- if (!src_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- src = src_clone;
+
+ status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ src_x, src_y, width, height,
+ (cairo_surface_t **) &src,
+ &attributes);
+ if (status)
+ return status;
+
+ if (traps[0].left.p1.y < traps[0].left.p2.y) {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
+ } else {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
}
- /* XXX: The XCBRenderTRAP cast is evil and needs to go away somehow. */
- /* XXX: format_from_cairo is slow. should cache something. */
- XCBRenderTrapezoids (dst->dpy,
- _render_operator (operator),
- src->picture, dst->picture,
- format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
- xSrc, ySrc, num_traps, (XCBRenderTRAP *) traps);
-
- /* XXX: This is messed up. If I can xcb_surface_create, then I
- should be able to xcb_surface_destroy. */
- if (src_clone)
- cairo_surface_destroy (&src_clone->base);
+ render_src_x = src_x + render_reference_x - dst_x;
+ render_src_y = src_y + render_reference_y - dst_y;
- return CAIRO_STATUS_SUCCESS;
+ /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
+ /* XXX: format_from_cairo is slow. should cache something. */
+ status = _cairo_xcb_surface_set_attributes (src, &attributes);
+ if (CAIRO_OK (status))
+ XCBRenderTrapezoids (dst->dpy,
+ _render_operator (operator),
+ src->picture, dst->picture,
+ format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
+ render_src_x + attributes.x_offset,
+ render_src_y + attributes.y_offset,
+ num_traps, (XCBRenderTRAP *) traps);
+
+ _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
+
+ return status;
}
static cairo_int_status_t
@@ -722,30 +899,21 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static cairo_int_status_t
-_cairo_xcb_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_destroy,
_cairo_xcb_surface_pixels_per_inch,
- _cairo_xcb_surface_get_image,
- _cairo_xcb_surface_set_image,
- _cairo_xcb_surface_set_matrix,
- _cairo_xcb_surface_set_filter,
- _cairo_xcb_surface_set_repeat,
+ _cairo_xcb_surface_acquire_source_image,
+ _cairo_xcb_surface_release_source_image,
+ _cairo_xcb_surface_acquire_dest_image,
+ _cairo_xcb_surface_release_dest_image,
+ _cairo_xcb_surface_clone_similar,
_cairo_xcb_surface_composite,
_cairo_xcb_surface_fill_rectangles,
_cairo_xcb_surface_composite_trapezoids,
_cairo_xcb_surface_copy_page,
_cairo_xcb_surface_show_page,
_cairo_xcb_surface_set_clip_region,
- _cairo_xcb_surface_create_pattern,
NULL /* show_glyphs */
};
diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c
index d9d74f583..3eaef57e5 100644
--- a/src/cairo_xlib_surface.c
+++ b/src/cairo_xlib_surface.c
@@ -31,12 +31,28 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
#include "cairo-xlib.h"
+/**
+ * cairo_set_target_drawable:
+ * @cr: a #cairo_t
+ * @dpy: an X display
+ * @drawable: a window or pixmap on the default screen of @dpy
+ *
+ * Directs output for a #cairo_t to an Xlib drawable. @drawable must
+ * be a Window or Pixmap on the default screen of @dpy using the
+ * default colormap and visual. Using this function is slow because
+ * the function must retrieve information about @drawable from the X
+ * server.
+
+ * The combination of cairo_xlib_surface_create() and
+ * cairo_set_target_surface() is somewhat more flexible, although
+ * it still is slow.
+ **/
void
cairo_set_target_drawable (cairo_t *cr,
Display *dpy,
@@ -87,6 +103,8 @@ typedef struct _cairo_xlib_surface {
#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+
#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
@@ -141,18 +159,13 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
Pixmap pix;
cairo_xlib_surface_t *surface;
- /* XXX: There's a pretty lame heuristic here. This assumes that
- * all non-Render X servers do not support depth-32 pixmaps, (and
- * that they do support depths 1, 8, and 24). Obviously, it would
- * be much better to check the depths that are actually
- * supported. */
- if (!dpy
- || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)
- && format == CAIRO_FORMAT_ARGB32))
- {
- return NULL;
+ /* As a good first approximation, if the display doesn't have COMPOSITE,
+ * we're better off using image surfaces for all temporary operations
+ */
+ if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE(src)) {
+ return cairo_image_surface_create (format, width, height);
}
-
+
scr = DefaultScreen (dpy);
pix = XCreatePixmap (dpy, DefaultRootWindow (dpy),
@@ -196,15 +209,17 @@ _cairo_xlib_surface_pixels_per_inch (void *abstract_surface)
return 96.0;
}
-static cairo_image_surface_t *
-_cairo_xlib_surface_get_image (void *abstract_surface)
+static cairo_status_t
+_get_image_surface (cairo_xlib_surface_t *surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect)
{
- cairo_xlib_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
-
XImage *ximage;
Window root_ignore;
int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
+ int x1, y1, x2, y2;
XGetGeometry (surface->dpy,
surface->drawable,
@@ -212,11 +227,39 @@ _cairo_xlib_surface_get_image (void *abstract_surface)
&surface->width, &surface->height,
&bwidth_ignore, &depth_ignore);
+ x1 = 0;
+ y1 = 0;
+ x2 = surface->width;
+ y2 = surface->height;
+
+ if (interest_rect) {
+ if (interest_rect->x > x1)
+ x1 = interest_rect->x;
+ if (interest_rect->y > y1)
+ y1 = interest_rect->y;
+ if (interest_rect->x + interest_rect->width < x2)
+ x2 = interest_rect->x + interest_rect->width;
+ if (interest_rect->y + interest_rect->height < y2)
+ y2 = interest_rect->y + interest_rect->height;
+
+ if (x1 >= x2 || y1 >= y2) {
+ *image_out = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ if (image_rect) {
+ image_rect->x = x1;
+ image_rect->y = y1;
+ image_rect->width = x2 - x1;
+ image_rect->height = y2 - y1;
+ }
+
/* XXX: This should try to use the XShm extension if availible */
ximage = XGetImage (surface->dpy,
surface->drawable,
- 0, 0,
- surface->width, surface->height,
+ x1, y1,
+ x2 - x1, y2 - y1,
AllPlanes, ZPixmap);
if (surface->visual) {
@@ -253,7 +296,8 @@ _cairo_xlib_surface_get_image (void *abstract_surface)
_cairo_image_surface_set_repeat (image, surface->base.repeat);
_cairo_image_surface_set_matrix (image, &(surface->base.matrix));
- return image;
+ *image_out = image;
+ return CAIRO_STATUS_SUCCESS;
}
static void
@@ -266,10 +310,11 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
}
static cairo_status_t
-_cairo_xlib_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image)
+_draw_image_surface (cairo_xlib_surface_t *surface,
+ cairo_image_surface_t *image,
+ int dst_x,
+ int dst_y)
{
- cairo_xlib_surface_t *surface = abstract_surface;
XImage *ximage;
unsigned bitmap_pad;
@@ -295,9 +340,8 @@ _cairo_xlib_surface_set_image (void *abstract_surface,
_cairo_xlib_surface_ensure_gc (surface);
XPutImage(surface->dpy, surface->drawable, surface->gc,
- ximage, 0, 0, 0, 0,
- surface->width,
- surface->height);
+ ximage, 0, 0, dst_x, dst_y,
+ image->width, image->height);
/* Foolish XDestroyImage thinks it can free my data, but I won't
stand for it. */
@@ -305,17 +349,116 @@ _cairo_xlib_surface_set_image (void *abstract_surface,
XDestroyImage (ximage);
return CAIRO_STATUS_SUCCESS;
+
+}
+
+static cairo_status_t
+_cairo_xlib_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ cairo_xlib_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
+
+ status = _get_image_surface (surface, NULL, &image, NULL);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ cairo_surface_set_filter (&image->base, surface->base.filter);
+ cairo_surface_set_matrix (&image->base, &surface->base.matrix);
+ cairo_surface_set_repeat (&image->base, surface->base.repeat);
+
+ *image_out = image;
+ }
+
+ return status;
+}
+
+static void
+_cairo_xlib_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ cairo_surface_destroy (&image->base);
+}
+
+static cairo_status_t
+_cairo_xlib_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect_out,
+ void **image_extra)
+{
+ cairo_xlib_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
+
+ status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
+ if (status == CAIRO_STATUS_SUCCESS)
+ *image_out = image;
+
+ return status;
+}
+
+static void
+_cairo_xlib_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra)
+{
+ cairo_xlib_surface_t *surface = abstract_surface;
+
+ /* ignore errors */
+ _draw_image_surface (surface, image, image_rect->x, image_rect->y);
+
+ cairo_surface_destroy (&image->base);
}
static cairo_status_t
-_cairo_xlib_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
+_cairo_xlib_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
{
cairo_xlib_surface_t *surface = abstract_surface;
+ cairo_xlib_surface_t *clone;
+
+ if (src->backend == surface->base.backend ) {
+ cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src;
+
+ if (xlib_src->dpy == surface->dpy) {
+ *clone_out = src;
+ cairo_surface_reference (src);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+ } else if (_cairo_surface_is_image (src)) {
+ cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
+
+ clone = (cairo_xlib_surface_t *)
+ _cairo_xlib_surface_create_similar (surface, image_src->format, 0,
+ image_src->width, image_src->height);
+ if (clone == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _draw_image_surface (clone, image_src, 0, 0);
+
+ *clone_out = &clone->base;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
+ cairo_matrix_t *matrix)
+{
XTransform xtransform;
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
-
+
xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
@@ -328,26 +471,41 @@ _cairo_xlib_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
xtransform.matrix[2][1] = 0;
xtransform.matrix[2][2] = _cairo_fixed_from_double (1);
- if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
+ if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
{
- XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform);
- } else {
- /* XXX: Need support here if using an old RENDER without support
- for SetPictureTransform */
+ static const XTransform identity = { {
+ { 1 << 16, 0x00000, 0x00000 },
+ { 0x00000, 1 << 16, 0x00000 },
+ { 0x00000, 0x00000, 1 << 16 },
+ } };
+
+ if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
+ XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform);
+
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
+_cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
+ cairo_filter_t filter)
{
- cairo_xlib_surface_t *surface = abstract_surface;
char *render_filter;
- if (!(surface->picture
- && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)))
+ if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
+
+ if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
+ {
+ if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
+ return CAIRO_STATUS_SUCCESS;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
switch (filter) {
case CAIRO_FILTER_FAST:
@@ -377,11 +535,10 @@ _cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
}
static cairo_status_t
-_cairo_xlib_surface_set_repeat (void *abstract_surface, int repeat)
+_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat)
{
- cairo_xlib_surface_t *surface = abstract_surface;
- unsigned long mask;
XRenderPictureAttributes pa;
+ unsigned long mask;
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
@@ -394,33 +551,32 @@ _cairo_xlib_surface_set_repeat (void *abstract_surface, int repeat)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_xlib_surface_t *
-_cairo_xlib_surface_clone_similar (cairo_surface_t *src,
- cairo_xlib_surface_t *template,
- cairo_format_t format,
- int depth)
+static cairo_int_status_t
+_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
+ cairo_surface_attributes_t *attributes)
{
- cairo_xlib_surface_t *clone;
- cairo_image_surface_t *src_image;
+ cairo_int_status_t status;
- src_image = _cairo_surface_get_image (src);
-
- clone = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_similar (template, format, 0,
- src_image->width,
- src_image->height);
- if (clone == NULL)
- return NULL;
-
- _cairo_xlib_surface_set_filter (clone, cairo_surface_get_filter(src));
-
- _cairo_xlib_surface_set_image (clone, src_image);
-
- _cairo_xlib_surface_set_matrix (clone, &(src_image->base.matrix));
+ status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix);
+ if (status)
+ return status;
+
+ switch (attributes->extend) {
+ case CAIRO_EXTEND_NONE:
+ _cairo_xlib_surface_set_repeat (surface, 0);
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ _cairo_xlib_surface_set_repeat (surface, 1);
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
- cairo_surface_destroy (&src_image->base);
+ status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
+ if (status)
+ return status;
- return clone;
+ return CAIRO_STATUS_SUCCESS;
}
static int
@@ -462,8 +618,8 @@ _render_operator (cairo_operator_t operator)
static cairo_int_status_t
_cairo_xlib_surface_composite (cairo_operator_t operator,
- cairo_surface_t *generic_src,
- cairo_surface_t *generic_mask,
+ cairo_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
void *abstract_dst,
int src_x,
int src_y,
@@ -474,73 +630,66 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
unsigned int width,
unsigned int height)
{
- cairo_xlib_surface_t *dst = abstract_dst;
- cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) generic_src;
- cairo_xlib_surface_t *mask = (cairo_xlib_surface_t *) generic_mask;
- cairo_xlib_surface_t *src_clone = NULL;
- cairo_xlib_surface_t *mask_clone = NULL;
- XGCValues gc_values;
- int src_x_off, src_y_off, dst_x_off, dst_y_off;
+ cairo_surface_attributes_t src_attr, mask_attr;
+ cairo_xlib_surface_t *dst = abstract_dst;
+ cairo_xlib_surface_t *src;
+ cairo_xlib_surface_t *mask;
+ cairo_int_status_t status;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
- src_clone = _cairo_xlib_surface_clone_similar (generic_src, dst,
- CAIRO_FORMAT_ARGB32, 32);
- if (!src_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- src = src_clone;
- }
- if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) {
- mask_clone = _cairo_xlib_surface_clone_similar (generic_mask, dst,
- CAIRO_FORMAT_A8, 8);
- if (!mask_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- mask = mask_clone;
- }
-
- if (operator == CAIRO_OPERATOR_SRC
- && !mask
- && _cairo_matrix_is_integer_translation(&(src->base.matrix),
- &src_x_off, &src_y_off)
- && _cairo_matrix_is_integer_translation(&(dst->base.matrix),
- &dst_x_off, &dst_y_off)) {
- /* Fast path for copying "raw" areas. */
- _cairo_xlib_surface_ensure_gc (dst);
- XGetGCValues(dst->dpy, dst->gc, GCGraphicsExposures, &gc_values);
- XSetGraphicsExposures(dst->dpy, dst->gc, False);
- XCopyArea(dst->dpy,
- src->drawable,
- dst->drawable,
- dst->gc,
- src_x + src_x_off,
- src_y + src_y_off,
- width, height,
- dst_x + dst_x_off,
- dst_y + dst_y_off);
- XSetGraphicsExposures(dst->dpy, dst->gc, gc_values.graphics_exposures);
-
- } else {
- XRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- mask ? mask->picture : 0,
- dst->picture,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
+ status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
+ &dst->base,
+ src_x, src_y,
+ mask_x, mask_y,
+ width, height,
+ (cairo_surface_t **) &src,
+ (cairo_surface_t **) &mask,
+ &src_attr, &mask_attr);
+ if (status)
+ return status;
+
+ status = _cairo_xlib_surface_set_attributes (src, &src_attr);
+ if (CAIRO_OK (status))
+ {
+ if (mask)
+ {
+ status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
+ if (CAIRO_OK (status))
+ XRenderComposite (dst->dpy,
+ _render_operator (operator),
+ src->picture,
+ mask->picture,
+ dst->picture,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ mask_x + mask_attr.x_offset,
+ mask_y + mask_attr.y_offset,
+ dst_x, dst_y,
+ width, height);
+ }
+ else
+ {
+ XRenderComposite (dst->dpy,
+ _render_operator (operator),
+ src->picture,
+ 0,
+ dst->picture,
+ src_x + src_attr.x_offset,
+ src_y + src_attr.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ }
}
- /* XXX: This is messed up. If I can xlib_surface_create, then I
- should be able to xlib_surface_destroy. */
- if (src_clone)
- cairo_surface_destroy (&src_clone->base);
- if (mask_clone)
- cairo_surface_destroy (&mask_clone->base);
+ if (mask)
+ _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
+
+ _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_int_status_t
@@ -572,41 +721,59 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
static cairo_int_status_t
_cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *generic_src,
+ cairo_pattern_t *pattern,
void *abstract_dst,
- int xSrc,
- int ySrc,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps)
{
- cairo_xlib_surface_t *dst = abstract_dst;
- cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) generic_src;
- cairo_xlib_surface_t *src_clone = NULL;
+ cairo_surface_attributes_t attributes;
+ cairo_xlib_surface_t *dst = abstract_dst;
+ cairo_xlib_surface_t *src;
+ cairo_int_status_t status;
+ int render_reference_x, render_reference_y;
+ int render_src_x, render_src_y;
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
- src_clone = _cairo_xlib_surface_clone_similar (generic_src, dst,
- CAIRO_FORMAT_ARGB32, 32);
- if (!src_clone)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- src = src_clone;
+
+ status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ src_x, src_y, width, height,
+ (cairo_surface_t **) &src,
+ &attributes);
+ if (status)
+ return status;
+
+ if (traps[0].left.p1.y < traps[0].left.p2.y) {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
+ } else {
+ render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
+ render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
}
- /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
- XRenderCompositeTrapezoids (dst->dpy,
- _render_operator (operator),
- src->picture, dst->picture,
- XRenderFindStandardFormat (dst->dpy, PictStandardA8),
- xSrc, ySrc, (XTrapezoid *) traps, num_traps);
+ render_src_x = src_x + render_reference_x - dst_x;
+ render_src_y = src_y + render_reference_y - dst_y;
- /* XXX: This is messed up. If I can xlib_surface_create, then I
- should be able to xlib_surface_destroy. */
- if (src_clone)
- cairo_surface_destroy (&src_clone->base);
+ /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
+ status = _cairo_xlib_surface_set_attributes (src, &attributes);
+ if (CAIRO_OK (status))
+ XRenderCompositeTrapezoids (dst->dpy,
+ _render_operator (operator),
+ src->picture, dst->picture,
+ XRenderFindStandardFormat (dst->dpy, PictStandardA8),
+ render_src_x + attributes.x_offset,
+ render_src_y + attributes.y_offset,
+ (XTrapezoid *) traps, num_traps);
+
+ _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_int_status_t
@@ -685,22 +852,17 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_xlib_surface_create_pattern (void *abstract_surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents)
-{
- 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_xlib_surface_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
- cairo_surface_t *source,
+ cairo_pattern_t *pattern,
void *abstract_surface,
int source_x,
int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs);
@@ -708,18 +870,17 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_create_similar,
_cairo_xlib_surface_destroy,
_cairo_xlib_surface_pixels_per_inch,
- _cairo_xlib_surface_get_image,
- _cairo_xlib_surface_set_image,
- _cairo_xlib_surface_set_matrix,
- _cairo_xlib_surface_set_filter,
- _cairo_xlib_surface_set_repeat,
+ _cairo_xlib_surface_acquire_source_image,
+ _cairo_xlib_surface_release_source_image,
+ _cairo_xlib_surface_acquire_dest_image,
+ _cairo_xlib_surface_release_dest_image,
+ _cairo_xlib_surface_clone_similar,
_cairo_xlib_surface_composite,
_cairo_xlib_surface_fill_rectangles,
_cairo_xlib_surface_composite_trapezoids,
_cairo_xlib_surface_copy_page,
_cairo_xlib_surface_show_page,
_cairo_xlib_surface_set_clip_region,
- _cairo_xlib_surface_create_pattern,
_cairo_xlib_surface_show_glyphs
};
@@ -827,6 +988,7 @@ typedef struct {
cairo_glyph_cache_key_t key;
Glyph glyph;
XGlyphInfo info;
+ int refcount;
} glyphset_cache_entry_t;
static Glyph
@@ -854,17 +1016,18 @@ _xlib_glyphset_cache_create_entry (void *cache,
_cairo_lock_global_image_glyph_cache ();
im_cache = _cairo_get_global_image_glyph_cache ();
- if (g == NULL || v == NULL ||g == NULL || im_cache == NULL) {
+ if (g == NULL || v == NULL || im_cache == NULL) {
_cairo_unlock_global_image_glyph_cache ();
return CAIRO_STATUS_NO_MEMORY;
}
- status = _cairo_cache_lookup (im_cache, key, (void **) (&im));
+ status = _cairo_cache_lookup (im_cache, key, (void **) (&im), NULL);
if (status != CAIRO_STATUS_SUCCESS || im == NULL) {
_cairo_unlock_global_image_glyph_cache ();
return CAIRO_STATUS_NO_MEMORY;
}
+ v->refcount = 1;
v->key = *k;
_cairo_unscaled_font_reference (v->key.unscaled);
@@ -925,6 +1088,12 @@ _xlib_glyphset_cache_create_entry (void *cache,
return CAIRO_STATUS_SUCCESS;
}
+static void
+_glyphset_cache_entry_reference (glyphset_cache_entry_t *e)
+{
+ e->refcount++;
+}
+
static void
_xlib_glyphset_cache_destroy_cache (void *cache)
{
@@ -940,6 +1109,9 @@ _xlib_glyphset_cache_destroy_entry (void *cache, void *entry)
g = (glyphset_cache_t *) cache;
v = (glyphset_cache_entry_t *) entry;
+ if (--v->refcount > 0)
+ return;
+
_cairo_unscaled_font_destroy (v->key.unscaled);
XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1);
free (v);
@@ -1014,8 +1186,7 @@ _get_glyphset_cache (Display *d)
#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_xlib_surface_show_glyphs32 (cairo_font_t *font,
cairo_operator_t operator,
glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
@@ -1092,8 +1263,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
static cairo_status_t
-_cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
+_cairo_xlib_surface_show_glyphs16 (cairo_font_t *font,
cairo_operator_t operator,
glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
@@ -1169,10 +1339,9 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
}
static cairo_status_t
-_cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
+_cairo_xlib_surface_show_glyphs8 (cairo_font_t *font,
cairo_operator_t operator,
- glyphset_cache_t *g,
+ glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
cairo_xlib_surface_t *src,
cairo_xlib_surface_t *self,
@@ -1247,27 +1416,44 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
+_cairo_xlib_surface_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
- cairo_surface_t *source,
+ cairo_pattern_t *pattern,
void *abstract_surface,
int source_x,
int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
+ cairo_surface_attributes_t attributes;
+ cairo_int_status_t status;
unsigned int elt_size;
cairo_xlib_surface_t *self = abstract_surface;
- cairo_image_surface_t *tmp = NULL;
- cairo_xlib_surface_t *src = NULL;
+ cairo_xlib_surface_t *src;
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;
+ if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_pattern_acquire_surface (pattern, &self->base,
+ source_x, source_y, width, height,
+ (cairo_surface_t **) &src,
+ &attributes);
+ if (status)
+ return status;
+
+ status = _cairo_xlib_surface_set_attributes (src, &attributes);
+ if (status)
+ goto FAIL;
+
/* Acquire an entry array of suitable size. */
if (num_glyphs < N_STACK_BUF) {
entries = stack_entries;
@@ -1278,26 +1464,6 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
goto FAIL;
}
- /* prep the source surface. */
- if (source->backend == self->base.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 (&self->base, 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)
@@ -1305,15 +1471,23 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
/* Work out the index size to use. */
elt_size = 8;
- key.scale = *scale;
- key.unscaled = font;
+ _cairo_font_get_glyph_cache_key (font, &key);
for (i = 0; i < num_glyphs; ++i) {
key.index = glyphs[i].index;
- status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]));
+ status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]), NULL);
if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL)
goto UNLOCK;
+ /* Referencing the glyph entries we use prevents them from
+ * being freed if lookup of later entries causes them to
+ * be ejected from the cache. It would be more efficient
+ * (though more complex) to prevent them from being ejected
+ * from the cache at all, so they could get reused later
+ * in the same string.
+ */
+ _glyphset_cache_entry_reference (entries[i]);
+
if (elt_size == 8 && entries[i]->glyph > 0xff)
elt_size = 16;
if (elt_size == 16 && entries[i]->glyph > 0xffff) {
@@ -1325,43 +1499,32 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
/* 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,
+ status = _cairo_xlib_surface_show_glyphs8 (font, operator, g, &key, src, self,
+ source_x + attributes.x_offset,
+ source_y + attributes.y_offset,
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,
+ status = _cairo_xlib_surface_show_glyphs16 (font, operator, g, &key, src, self,
+ source_x + attributes.x_offset,
+ source_y + attributes.y_offset,
glyphs, entries, num_glyphs);
else
- status = _cairo_xlib_surface_show_glyphs32 (font, scale, operator, g, &key, src, self,
- source_x, source_y,
+ status = _cairo_xlib_surface_show_glyphs32 (font, operator, g, &key, src, self,
+ source_x + attributes.x_offset,
+ source_y + attributes.y_offset,
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;
+ for (i = 0; i < num_glyphs; ++i)
+ _xlib_glyphset_cache_destroy_entry (g, entries[i]);
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;
+ _cairo_pattern_release_surface (&self->base, &src->base, &attributes);
+
+ return status;
}
diff --git a/src/cairoint.h b/src/cairoint.h
index 6f9d50617..50899eca8 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -31,7 +31,7 @@
* California.
*
* Contributor(s):
- * Carl D. Worth <cworth@isi.edu>
+ * Carl D. Worth <cworth@cworth.org>
*/
/*
@@ -39,7 +39,7 @@
* and constitute no kind of standard. If you need any of these
* functions, please drop me a note. Either the library needs new
* functionality, or there's a way to do what you need using the
- * existing published interfaces. cworth@isi.edu
+ * existing published interfaces. cworth@cworth.org
*/
#ifndef _CAIROINT_H_
@@ -108,6 +108,17 @@
#define __attribute__(x)
#endif
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
#include "cairo-wideint.h"
typedef int32_t cairo_fixed_16_16_t;
@@ -166,6 +177,8 @@ typedef enum cairo_int_status {
CAIRO_INT_STATUS_UNSUPPORTED
} cairo_int_status_t;
+#define CAIRO_OK(status) ((status) == CAIRO_STATUS_SUCCESS)
+
typedef enum cairo_path_op {
CAIRO_PATH_OP_MOVE_TO = 0,
CAIRO_PATH_OP_LINE_TO = 1,
@@ -373,43 +386,49 @@ _cairo_cache_destroy (cairo_cache_t *cache);
cairo_private cairo_status_t
_cairo_cache_lookup (cairo_cache_t *cache,
- void *key,
- void **entry_return);
+ void *key,
+ void **entry_return,
+ int *created_entry);
+
+cairo_private cairo_status_t
+_cairo_cache_remove (cairo_cache_t *cache,
+ void *key);
+
+cairo_private void *
+_cairo_cache_random_entry (cairo_cache_t *cache,
+ int (*predicate) (void*));
cairo_private unsigned long
_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];
+ double matrix[2][2];
} cairo_font_scale_t;
struct _cairo_font_backend;
+/*
+ * A cairo_unscaled_font_t is just an opaque handle we use in the
+ * glyph cache.
+ */
typedef struct {
int refcount;
const struct _cairo_font_backend *backend;
} cairo_unscaled_font_t;
-/*
- * A cairo_font contains a pointer to a cairo_unscaled_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_scale_t scale; /* font space => device space */
+ const struct _cairo_font_backend *backend;
};
-/* cairo_font.c is responsible for two global caches:
+/* cairo_font.c is responsible for a global glyph cache:
*
- * - font entries: [[[base], name, weight, slant], cairo_unscaled_font_t ]
- * - glyph entries: [[[base], cairo_font_t, index], image, size, extents ]
+ * - glyph entries: [[[base], cairo_unscaled_font_t, scale, flags, 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
@@ -420,6 +439,7 @@ typedef struct {
cairo_cache_entry_base_t base;
cairo_unscaled_font_t *unscaled;
cairo_font_scale_t scale;
+ int flags;
unsigned long index;
} cairo_glyph_cache_key_t;
@@ -452,49 +472,52 @@ _cairo_glyph_cache_keys_equal (void *cache,
/* the font backend interface */
typedef struct _cairo_font_backend {
- cairo_unscaled_font_t *(*create) (const char *family,
+ cairo_status_t (*create) (const char *family,
cairo_font_slant_t slant,
- cairo_font_weight_t weight);
+ cairo_font_weight_t weight,
+ cairo_font_scale_t *scale,
+ cairo_font_t **font);
- void (*destroy) (void *font);
+ void (*destroy_font) (void *font);
+ void (*destroy_unscaled_font) (void *font);
cairo_status_t (*font_extents) (void *font,
- cairo_font_scale_t *scale,
cairo_font_extents_t *extents);
cairo_status_t (*text_to_glyphs) (void *font,
- cairo_font_scale_t *scale,
const unsigned char *utf8,
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 (*glyph_bbox) (void *font,
- cairo_font_scale_t *scale,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_box_t *bbox);
cairo_status_t (*show_glyphs) (void *font,
- cairo_font_scale_t *scale,
cairo_operator_t operator,
- cairo_surface_t *source,
+ cairo_pattern_t *pattern,
cairo_surface_t *surface,
int source_x,
int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs);
cairo_status_t (*glyph_path) (void *font,
- cairo_font_scale_t *scale,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_t *path);
+ void (*get_glyph_cache_key) (void *font,
+ cairo_glyph_cache_key_t *key);
cairo_status_t (*create_glyph) (cairo_image_glyph_cache_entry_t *entry);
@@ -507,6 +530,12 @@ extern const cairo_private struct _cairo_font_backend cairo_ft_font_backend;
#endif
+#ifdef CAIRO_HAS_WIN32_FONT
+
+extern const cairo_private struct _cairo_font_backend cairo_win32_font_backend;
+
+#endif
+
#ifdef CAIRO_HAS_ATSUI_FONT
extern const cairo_private struct _cairo_font_backend cairo_atsui_font_backend;
@@ -527,35 +556,40 @@ typedef struct _cairo_surface_backend {
double
(*pixels_per_inch) (void *surface);
- /* XXX: We could use a better name than get_image here. Something
- to suggest the fact that the function will create a new
- surface, (and hence that it needs to be destroyed). Perhaps
- clone_image or maybe simply clone? */
-
- cairo_image_surface_t *
- (*get_image) (void *surface);
-
cairo_status_t
- (*set_image) (void *surface,
- cairo_image_surface_t *image);
+ (* acquire_source_image) (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra);
- cairo_status_t
- (*set_matrix) (void *surface,
- cairo_matrix_t *matrix);
+ void
+ (* release_source_image) (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra);
cairo_status_t
- (*set_filter) (void *surface,
- cairo_filter_t filter);
+ (*acquire_dest_image) (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect,
+ void **image_extra);
+ void
+ (*release_dest_image) (void *abstract_surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra);
+
cairo_status_t
- (*set_repeat) (void *surface,
- int repeat);
-
+ (*clone_similar) (void *surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out);
+
/* XXX: dst should be the first argument for consistency */
cairo_int_status_t
(*composite) (cairo_operator_t operator,
- cairo_surface_t *src,
- cairo_surface_t *mask,
+ cairo_pattern_t *src,
+ cairo_pattern_t *mask,
void *dst,
int src_x,
int src_y,
@@ -576,10 +610,14 @@ typedef struct _cairo_surface_backend {
/* XXX: dst should be the first argument for consistency */
cairo_int_status_t
(*composite_trapezoids) (cairo_operator_t operator,
- cairo_surface_t *src,
+ cairo_pattern_t *pattern,
void *dst,
- int xSrc,
- int ySrc,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int num_traps);
@@ -592,24 +630,22 @@ typedef struct _cairo_surface_backend {
cairo_int_status_t
(*set_clip_region) (void *surface,
pixman_region16_t *region);
- cairo_int_status_t
- (*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,
+ (*show_glyphs) (cairo_font_t *font,
cairo_operator_t operator,
- cairo_surface_t *source,
+ cairo_pattern_t *pattern,
void *surface,
int source_x,
int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
int num_glyphs);
} cairo_surface_backend_t;
@@ -640,6 +676,7 @@ struct _cairo_image_surface {
cairo_surface_t base;
/* libic-specific fields */
+ cairo_format_t format;
char *data;
int owns_data;
@@ -681,60 +718,77 @@ typedef enum {
typedef struct _cairo_color_stop {
cairo_fixed_t offset;
- cairo_fixed_48_16_t scale;
- int id;
- unsigned char color_char[4];
+ cairo_color_t color;
} cairo_color_stop_t;
-typedef void (*cairo_shader_function_t) (unsigned char *color0,
- unsigned char *color1,
- cairo_fixed_t factor,
- int *pixel);
+struct _cairo_pattern {
+ cairo_pattern_type_t type;
+ unsigned int ref_count;
+ cairo_matrix_t matrix;
+ cairo_filter_t filter;
+ cairo_extend_t extend;
+ double alpha;
+};
+
+typedef struct _cairo_solid_pattern {
+ cairo_pattern_t base;
+
+ double red, green, blue;
+} cairo_solid_pattern_t;
+
+typedef struct _cairo_surface_pattern {
+ cairo_pattern_t base;
+
+ cairo_surface_t *surface;
+} cairo_surface_pattern_t;
-typedef struct _cairo_shader_op {
+typedef struct _cairo_gradient_pattern {
+ cairo_pattern_t base;
+
cairo_color_stop_t *stops;
- int n_stops;
- cairo_fixed_t min_offset;
- cairo_fixed_t max_offset;
- cairo_extend_t extend;
- cairo_shader_function_t shader_function;
-} cairo_shader_op_t;
+ int n_stops;
+} cairo_gradient_pattern_t;
-struct _cairo_pattern {
- unsigned int ref_count;
-
+typedef struct _cairo_linear_pattern {
+ cairo_gradient_pattern_t base;
+
+ cairo_point_double_t point0;
+ cairo_point_double_t point1;
+} cairo_linear_pattern_t;
+
+typedef struct _cairo_radial_pattern {
+ cairo_gradient_pattern_t base;
+
+ cairo_point_double_t center0;
+ cairo_point_double_t center1;
+ double radius0;
+ double radius1;
+} cairo_radial_pattern_t;
+
+typedef union {
+ cairo_gradient_pattern_t base;
+
+ cairo_linear_pattern_t linear;
+ cairo_radial_pattern_t radial;
+} cairo_gradient_pattern_union_t;
+
+typedef union {
+ cairo_pattern_t base;
+
+ cairo_solid_pattern_t solid;
+ cairo_surface_pattern_t surface;
+ cairo_gradient_pattern_union_t gradient;
+} cairo_pattern_union_t;
+
+typedef struct _cairo_surface_attributes {
+ cairo_matrix_t matrix;
cairo_extend_t extend;
cairo_filter_t filter;
- cairo_matrix_t matrix;
-
- cairo_color_stop_t *stops;
- int n_stops;
-
- cairo_color_t color;
-
- cairo_surface_t *source;
- cairo_point_double_t source_offset;
-
- cairo_pattern_type_t type;
- union {
- struct {
- cairo_surface_t *surface;
- cairo_matrix_t save_matrix;
- int save_repeat;
- cairo_filter_t save_filter;
- } surface;
- struct {
- cairo_point_double_t point0;
- cairo_point_double_t point1;
- } linear;
- struct {
- cairo_point_double_t center0;
- cairo_point_double_t center1;
- double radius0;
- double radius1;
- } radial;
- } u;
-};
+ int x_offset;
+ int y_offset;
+ cairo_bool_t acquired;
+ void *extra;
+} cairo_surface_attributes_t;
typedef struct _cairo_traps {
cairo_trapezoid_t *traps;
@@ -746,19 +800,21 @@ typedef struct _cairo_traps {
#define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL
#define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL
-#ifdef CAIRO_HAS_FT_FONT
-
-#define CAIRO_FONT_FAMILY_DEFAULT "serif"
+#if defined (CAIRO_HAS_WIN32_FONT)
-/* XXX: Platform-specific. Other platforms may want a different default */
-#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend
+#define CAIRO_FONT_FAMILY_DEFAULT "Arial"
+#define CAIRO_FONT_BACKEND_DEFAULT &cairo_win32_font_backend
-#elif defined(CAIRO_HAS_ATSUI_FONT)
+#elif defined (CAIRO_HAS_ATSUI_FONT)
#define CAIRO_FONT_FAMILY_DEFAULT "Monaco"
-
#define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_font_backend
+#elif defined (CAIRO_HAS_FT_FONT)
+
+#define CAIRO_FONT_FAMILY_DEFAULT "serif"
+#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend
+
#endif
#define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER
@@ -772,10 +828,7 @@ typedef struct _cairo_traps {
/* Need a name distinct from the cairo_clip function */
typedef struct _cairo_clip_rec {
- int x;
- int y;
- int width;
- int height;
+ cairo_rectangle_t rect;
pixman_region16_t *region;
cairo_surface_t *surface;
} cairo_clip_rec_t;
@@ -797,7 +850,11 @@ typedef struct _cairo_gstate {
int num_dashes;
double dash_offset;
- cairo_unscaled_font_t *font;
+ char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */
+ cairo_font_slant_t font_slant;
+ cairo_font_weight_t font_weight;
+
+ cairo_font_t *font; /* Specific to the current CTM */
cairo_surface_t *surface;
@@ -868,7 +925,7 @@ _cairo_fixed_integer_ceil (cairo_fixed_t f);
cairo_private cairo_gstate_t *
_cairo_gstate_create (void);
-cairo_private void
+cairo_private cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate);
cairo_private cairo_status_t
@@ -1086,13 +1143,13 @@ cairo_private cairo_status_t
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double x,
double y,
- int *inside_ret);
+ cairo_bool_t *inside_ret);
cairo_private cairo_status_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
double x,
double y,
- int *inside_ret);
+ cairo_bool_t *inside_ret);
cairo_private cairo_status_t
_cairo_gstate_init_clip (cairo_gstate_t *gstate);
@@ -1119,6 +1176,10 @@ cairo_private cairo_status_t
_cairo_gstate_scale_font (cairo_gstate_t *gstate,
double scale);
+cairo_private void
+_cairo_gstate_current_font_scale (cairo_gstate_t *gstate,
+ cairo_font_scale_t *sc);
+
cairo_private cairo_status_t
_cairo_gstate_transform_font (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
@@ -1177,26 +1238,29 @@ cairo_private void
_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue);
cairo_private void
-_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue);
+_cairo_color_get_rgb (const cairo_color_t *color,
+ double *red, double *green, double *blue);
cairo_private void
_cairo_color_set_alpha (cairo_color_t *color, double alpha);
/* cairo_font.c */
-cairo_private cairo_unscaled_font_t *
-_cairo_unscaled_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight);
+cairo_private cairo_status_t
+_cairo_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ cairo_font_scale_t *sc,
+ cairo_font_t **font);
cairo_private void
-_cairo_font_init (cairo_font_t *scaled,
- cairo_font_scale_t *scale,
- cairo_unscaled_font_t *unscaled);
+_cairo_font_init (cairo_font_t *font,
+ cairo_font_scale_t *scale,
+ const cairo_font_backend_t *backend);
-cairo_private cairo_status_t
-_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const struct _cairo_font_backend *backend);
+cairo_private void
+_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
+ const struct _cairo_font_backend *backend);
cairo_private void
_cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
@@ -1205,48 +1269,56 @@ cairo_private void
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
cairo_private cairo_status_t
-_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font,
- cairo_font_scale_t *scale,
- cairo_font_extents_t *extents);
+_cairo_font_font_extents (cairo_font_t *font,
+ cairo_font_extents_t *extents);
+
+cairo_private cairo_status_t
+_cairo_font_text_to_glyphs (cairo_font_t *font,
+ const unsigned char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs);
cairo_private 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);
+_cairo_font_glyph_extents (cairo_font_t *font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents);
cairo_private 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);
+_cairo_font_glyph_bbox (cairo_font_t *font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox);
cairo_private cairo_status_t
-_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);
+_cairo_font_show_glyphs (cairo_font_t *font,
+ cairo_operator_t operator,
+ cairo_pattern_t *source,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int widht,
+ unsigned int height,
+ cairo_glyph_t *glyphs,
+ int num_glyphs);
cairo_private cairo_status_t
-_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);
+_cairo_font_glyph_path (cairo_font_t *font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path);
cairo_private cairo_status_t
-_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_font_glyph_path (cairo_font_t *font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path);
+
+cairo_private void
+_cairo_font_get_glyph_cache_key (cairo_font_t *font,
+ cairo_glyph_cache_key_t *key);
/* cairo_hull.c */
cairo_private cairo_status_t
@@ -1355,8 +1427,8 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface,
cairo_private cairo_status_t
_cairo_surface_composite (cairo_operator_t operator,
- cairo_surface_t *src,
- cairo_surface_t *mask,
+ cairo_pattern_t *src,
+ cairo_pattern_t *mask,
cairo_surface_t *dst,
int src_x,
int src_y,
@@ -1376,10 +1448,14 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_private cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_surface_t *src,
+ cairo_pattern_t *pattern,
cairo_surface_t *dst,
- int xSrc,
- int ySrc,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
int ntraps);
@@ -1392,20 +1468,37 @@ _cairo_surface_show_page (cairo_surface_t *surface);
cairo_private double
_cairo_surface_pixels_per_inch (cairo_surface_t *surface);
-cairo_private cairo_image_surface_t *
-_cairo_surface_get_image (cairo_surface_t *surface);
+cairo_private cairo_status_t
+_cairo_surface_acquire_source_image (cairo_surface_t *surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra);
+
+cairo_private void
+_cairo_surface_release_source_image (cairo_surface_t *surface,
+ cairo_image_surface_t *image,
+ void *image_extra);
cairo_private cairo_status_t
-_cairo_surface_set_image (cairo_surface_t *surface,
- cairo_image_surface_t *image);
+_cairo_surface_acquire_dest_image (cairo_surface_t *surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_t *image_rect,
+ void **image_extra);
+cairo_private void
+_cairo_surface_release_dest_image (cairo_surface_t *surface,
+ cairo_rectangle_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_t *image_rect,
+ void *image_extra);
+
cairo_private cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region);
+_cairo_surface_clone_similar (cairo_surface_t *surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out);
cairo_private cairo_status_t
-_cairo_surface_create_pattern (cairo_surface_t *surface,
- cairo_pattern_t *pattern,
- cairo_box_t *extents);
+_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region);
/* cairo_image_surface.c */
@@ -1435,6 +1528,9 @@ cairo_private cairo_int_status_t
_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
pixman_region16_t *region);
+cairo_private int
+_cairo_surface_is_image (cairo_surface_t *surface);
+
/* cairo_pen.c */
cairo_private cairo_status_t
_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate);
@@ -1540,7 +1636,7 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
cairo_private cairo_status_t
_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major);
-cairo_private int
+cairo_private cairo_bool_t
_cairo_matrix_is_integer_translation(cairo_matrix_t *matrix, int *itx, int *ity);
/* cairo_traps.c */
@@ -1581,18 +1677,29 @@ cairo_private int
_cairo_slope_counter_clockwise (cairo_slope_t *a, cairo_slope_t *b);
/* cairo_pattern.c */
-cairo_private void
-_cairo_pattern_init (cairo_pattern_t *pattern);
cairo_private cairo_status_t
_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other);
cairo_private void
-_cairo_pattern_fini (cairo_pattern_t *pattern);
+_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
+ double red, double green, double blue);
cairo_private void
-_cairo_pattern_init_solid (cairo_pattern_t *pattern,
- double red, double green, double blue);
+_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
+ cairo_surface_t *surface);
+
+cairo_private void
+_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
+ double x0, double y0, double x1, double y1);
+
+cairo_private void
+_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
+ double cx0, double cy0, double radius0,
+ double cx1, double cy1, double radius1);
+
+cairo_private void
+_cairo_pattern_fini (cairo_pattern_t *pattern);
cairo_private cairo_pattern_t *
_cairo_pattern_create_solid (double red, double green, double blue);
@@ -1605,27 +1712,56 @@ cairo_private void
_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha);
cairo_private void
-_cairo_pattern_set_source_offset (cairo_pattern_t *pattern,
- double x, double y);
-
-cairo_private void
_cairo_pattern_transform (cairo_pattern_t *pattern,
cairo_matrix_t *ctm_inverse);
-cairo_private void
-_cairo_pattern_prepare_surface (cairo_pattern_t *pattern);
+cairo_private cairo_bool_t
+_cairo_pattern_is_opaque (cairo_pattern_t *pattern);
-cairo_private void
-_cairo_pattern_shader_init (cairo_pattern_t *pattern,
- cairo_shader_op_t *op);
+cairo_private cairo_int_status_t
+_cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int x,
+ int y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **surface_out,
+ cairo_surface_attributes_t *attributes);
cairo_private void
-_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
- cairo_fixed_t factor,
- int *pixel);
+_cairo_pattern_release_surface (cairo_surface_t *dst,
+ cairo_surface_t *surface,
+ cairo_surface_attributes_t *attributes);
-cairo_private cairo_image_surface_t *
-_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box);
+cairo_private cairo_int_status_t
+_cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
+ cairo_pattern_t *mask,
+ cairo_surface_t *dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_surface_t **src_out,
+ cairo_surface_t **mask_out,
+ cairo_surface_attributes_t *src_attributes,
+ cairo_surface_attributes_t *mask_attributes);
+
+
+/* cairo_unicode.c */
+
+cairo_private cairo_status_t
+_cairo_utf8_to_ucs4 (const char *str,
+ int len,
+ uint32_t **result,
+ int *items_written);
+
+cairo_private cairo_status_t
+_cairo_utf8_to_utf16 (const char *str,
+ int len,
+ uint16_t **result,
+ int *items_written);
/* Avoid unnecessary PLT entries. */