summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUGS11
-rw-r--r--ChangeLog265
-rw-r--r--NEWS6
-rwxr-xr-xautogen.sh83
-rw-r--r--configure.in32
-rw-r--r--src/Makefile.am4
-rw-r--r--src/cairo-features.h.in2
-rw-r--r--src/cairo-fixed.c11
-rw-r--r--src/cairo-font.c229
-rw-r--r--src/cairo-ft-font.c248
-rw-r--r--src/cairo-gstate.c442
-rw-r--r--src/cairo-image-surface.c1
-rw-r--r--src/cairo-matrix.c24
-rw-r--r--src/cairo-pattern.c84
-rw-r--r--src/cairo-ps-surface.c1
-rw-r--r--src/cairo-surface.c32
-rw-r--r--src/cairo-traps.c118
-rw-r--r--src/cairo-wideint.c986
-rw-r--r--src/cairo-wideint.h272
-rw-r--r--src/cairo-xcb-surface.c15
-rw-r--r--src/cairo-xlib-surface.c55
-rw-r--r--src/cairo.c192
-rw-r--r--src/cairo.h20
-rw-r--r--src/cairo_fixed.c11
-rw-r--r--src/cairo_font.c229
-rw-r--r--src/cairo_ft_font.c248
-rw-r--r--src/cairo_gl_surface.c308
-rw-r--r--src/cairo_gstate.c442
-rw-r--r--src/cairo_image_surface.c1
-rw-r--r--src/cairo_matrix.c24
-rw-r--r--src/cairo_pattern.c84
-rw-r--r--src/cairo_png_surface.c4
-rw-r--r--src/cairo_ps_surface.c1
-rw-r--r--src/cairo_surface.c32
-rw-r--r--src/cairo_traps.c118
-rw-r--r--src/cairo_wideint.c986
-rw-r--r--src/cairo_wideint.h272
-rw-r--r--src/cairo_xcb_surface.c15
-rw-r--r--src/cairo_xlib_surface.c55
-rw-r--r--src/cairoint.h128
40 files changed, 5396 insertions, 695 deletions
diff --git a/BUGS b/BUGS
index c53b26d41..8d24b3d74 100644
--- a/BUGS
+++ b/BUGS
@@ -1,6 +1,6 @@
-cairo_clip is returning the wrong result in several cases. And when it
-doesn't get the wrong result, it is horribly slow. This really needs
-to be fixed.
+cairo_clip is really slow, (with at least the Xlib and image
+backends). An accelerated implementation of the IN operator would
+probably help a lot here.
--
@@ -17,6 +17,11 @@ following paper has the right answers:
Finite Precision Output, Computation Geometry Theory and
Applications, 13(4), 1999.
+Recent improvements to make the intersection code more robust (using
+128-bit arithmetic where needed), have exposed some of the weakness in
+the current tessellation implementation. So, for now, filling some
+polygons will cause "leaking" until we implement Hobby's algorithm.
+
--
Stroking a self-intersecting path generates the wrong answer, (in
diff --git a/ChangeLog b/ChangeLog
index 4122184da..4f2001cd6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,268 @@
+2004-08-02 Carl Worth <cworth@isi.edu>
+
+ * BUGS: Note that cairo_clip is fixed now.
+
+2004-08-01 Øyvind Kolås <oeyvindk@hig.no>
+
+ * src/cairo.h: replaced ct with cr in public headers to keep
+ usage consistent.
+
+2004-07-24 Jamey Sharp <jamey@minilop.net>
+
+ * src/cairo_xcb_surface.c:
+ Updating for XCB API change around iterators.
+
+2004-07-20 David Reveman <c99drn@cs.umu.se>
+
+ * src/cairo_gl_surface.c (_cairo_gl_surface_get_image): Use new
+ pixel buffer interface.
+ (_cairo_gl_surface_set_image): Use new pixel buffer interface.
+ (_cairo_gl_surface_set_filter): Don't use convolution filter for
+ gaussian filter type as we have no software fall-back.
+ (_cairo_gl_surface_create_pattern): Color ranges now need a surface
+ reference.
+ Added new CAIRO_GL_SURFACE_IS_DRAWABLE macro.
+
+2004-07-16 David Reveman <c99drn@cs.umu.se>
+
+ * src/cairo_font.c (_cairo_font_copy): Fixed stupid typo.
+ Added decleration of _cairo_glyph_cache_destroy.
+
+2004-07-15 David Reveman <c99drn@cs.umu.se>
+
+ * src/cairo_font.c (_cairo_font_copy): Destroy glyph cache
+ created by font backend.
+
+2004-07-11 Carl Worth <cworth@isi.edu>
+
+ * src/cairo_gstate.c (_cairo_gstate_init_clip): Don't call
+ _cairo_surface_set_clip_region with a NULL surface.
+
+2004-07-09 Carl Worth <cworth@isi.edu>
+
+ * src/cairo_gstate.c (_cairo_gstate_arc_dir): Fix numerical
+ problem that could lead to infinite loops.
+
+2004-07-09 Dave Beckett <Dave.Beckett@bristol.ac.uk>
+
+ * autogen.sh: Require automake 1.7 (and thus aclocal 1.7) which
+ requires autoconf 2.54. Changed since newer libtools may fail to
+ work with older automake versions such as 1.4. I bet this will
+ annoy people with older tool chains :(
+
+2004-07-05 Carl Worth <cworth@isi.edu>
+
+ * src/cairo.c (CAIRO_CHECK_SANITY): Remove errant semicolon from
+ macro definition.
+
+2004-06-21 David Reveman <c99drn@cs.umu.se>
+
+ * configure.in: Require glitz >= 0.1.5.
+
+ * src/cairo_gstate.c (_cairo_gstate_clip_and_composite_trapezoids):
+ Use correct source offset when creating clip surface.
+
+ * src/cairo_gl_surface.c (_cairo_gl_surface_get_image): Use glitz's
+ new pixel interface.
+ (_cairo_gl_surface_set_image): Use glitz's new pixel interface.
+ (_cairo_gl_surface_create_similar): First try to create a drawable
+ surface and if that fails, create a read only surface.
+ (_cairo_gl_surface_create_similar): Glitz now handles inheritance of
+ anti-aliasing hints, so it can be removed from here.
+ (_cairo_gl_surface_create_pattern): Temporary fix for gradients.
+
+2004-06-16 Keith Packard <keithp@keithp.com>
+
+ * src/cairo_xcb_surface.c: (bytes_per_line),
+ (_cairo_xcb_surface_set_image):
+ Fix image data length computation (XCB doesn't do this part).
+
+2004-06-11 David Reveman <c99drn@cs.umu.se>
+
+ * configure.in: Require glitz 0.1.4.
+
+ * src/cairo_gl_surface.c: Added CAIRO_GL_SURFACE_MULTISAMPLE macro.
+ (_cairo_gl_extract_rectangle): Added _cairo_gl_extract_rectangle.
+ (_cairo_gl_surface_composite_trapezoids): Use fill_rectangles if
+ we can represent the traps as a rectangle. fill_trapezoids cannot be
+ used with software multi-sampling.
+ (CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT): Glitz can no longer composite
+ trapezoids just by using offscreen drawing.
+ (_cairo_gl_surface_create_similar): Inherit anti-aliasing properties.
+
+ * src/cairo_gstate.c (_cairo_gstate_create_pattern): Get solid color
+ from color stop components.
+
+ * src/cairoint.h: Removed cairo color from color stop.
+
+ * src/cairo_pattern.c: Added MULTIPLY_COLORCOMP macro.
+ (cairo_pattern_add_color_stop): Do not pre-multiply stop color.
+ (_cairo_pattern_calc_color_at_pixel): Multiply with alpha.
+
+2004-05-28 Carl Worth <cworth@isi.edu>
+
+ * These two fixes are from David Reveman <c99drn@cs.umu.se>:
+
+ * src/cairo_surface.c (_cairo_surface_create_similar_scratch)
+ (_cairo_surface_create_similar_solid): Move NULL test from
+ create_similar_scratch to create_similar_solid.
+
+ * src/cairo_font.c (_cairo_glyph_surface_init): Fix for when
+ surface->backend != image->backend, but the backend does use
+ images for similar surfaces.
+
+2004-05-28 Keith Packard <keithp@keithp.com>
+
+ * configure.in:
+ * src/Makefile.am:
+ Add WARN_CFLAGS, autodetection for 64/128 bit ints and
+ cairo_wideint.[ch]
+
+ * src/cairo_gstate.c: (_cairo_gstate_show_glyphs):
+ Check status return from _cairo_gstate_glyph_extents
+
+ * src/cairo_pattern.c: (_cairo_image_data_set_radial),
+ (_cairo_pattern_get_image):
+ * src/cairo_png_surface.c: (_cairo_png_surface_copy_page):
+ * src/cairo_surface.c: (_cairo_surface_composite):
+ Quiet compiler warnings about uninitialized variables
+
+ * src/cairo_traps.c: (_det16_32), (_det32_64),
+ (_fixed_16_16_to_fixed_32_32), (_line_segs_intersect_ceil):
+ Switch to alternate exact line intersection code.
+
+ * src/cairo_wideint.c: (_cairo_uint64_divrem),
+ (_cairo_uint32_to_uint64), (_cairo_int32_to_int64),
+ (_cairo_uint32s_to_uint64), (_cairo_uint64_add),
+ (_cairo_uint64_sub), (_cairo_uint32x32_64_mul),
+ (_cairo_uint64_mul), (_cairo_uint64_lsl), (_cairo_uint64_rsl),
+ (_cairo_uint64_rsa), (_cairo_uint64_lt), (_cairo_uint64_eq),
+ (_cairo_int64_lt), (_cairo_uint64_not), (_cairo_uint64_negate),
+ (_cairo_leading_zeros32), (_cairo_uint64x32_normalized_divrem),
+ (_cairo_int64_divrem), (_cairo_uint128_divrem),
+ (_cairo_uint32_to_uint128), (_cairo_int32_to_int128),
+ (_cairo_uint64_to_uint128), (_cairo_int64_to_int128),
+ (_cairo_uint128_add), (_cairo_uint128_sub), (uint64_lo),
+ (uint64_hi), (uint64_shift32), (_cairo_uint64x64_128_mul),
+ (_cairo_uint128_mul), (_cairo_uint128_lsl), (_cairo_uint128_rsl),
+ (_cairo_uint128_rsa), (_cairo_uint128_lt), (_cairo_int128_lt),
+ (_cairo_uint128_eq), (_cairo_uint128x64_normalized_divrem),
+ (_cairo_leading_zeros64), (_cairo_int128_negate),
+ (_cairo_int128_not), (_cairo_int128_divrem):
+ * src/cairo_wideint.h:
+ Add 64/128-bit wide integer arithmetic.
+
+ * src/cairoint.h:
+ Switch to stdint.h types (and new wide types).
+
+2004-05-24 David Reveman <c99drn@cs.umu.se>
+
+ * src/cairo.c (cairo_restore): Moved CAIRO_CHECK_SANITY below
+ declarations.
+ (cairo_current_font): Moved CAIRO_CHECK_SANITY below declarations.
+
+ * src/cairoint.h: Added cairo_glyph_size_t, cairo_glyph_surface_t,
+ cairo_glyph_surface_node_t and cairo_glyph_cache_t.
+ Added font backend functions text_bbox, glyph_bbox and create_glyph.
+ Added source offset parameter to show_text and show_glyphs.
+ Added drawable parameter to backend function create_similar.
+ cairo_font_t now contains a glyph_cache pointer.
+ Added _cairo_font_text_bbox, _cairo_font_glyph_bbox,
+ _cairo_font_lookup_glyph and _cairo_surface_create_similar_scratch.
+
+ * src/cairo_xlib_surface.c (_cairo_xlib_surface_create_similar):
+ (_cairo_xlib_surface_clone_similar):
+ Added drawable parameter to backend function create_similar.
+
+ * src/cairo_xcb_surface.c (_cairo_xcb_surface_create_similar):
+ (_cairo_xcb_surface_clone_similar):
+ Added drawable parameter to backend function create_similar.
+
+ * src/cairo_surface.c: Added _cairo_surface_create_similar_scratch.
+ Added drawable parameter to backend function create_similar.
+
+ * src/cairo_ps_surface.c (_cairo_ps_surface_create_similar):
+ Added drawable parameter to backend function create_similar.
+
+ * src/cairo_png_surface.c (_cairo_png_surface_create_similar):
+ Added drawable parameter to backend function create_similar.
+
+ * src/cairo_image_surface.c (_cairo_image_surface_create_similar):
+ Added drawable parameter to backend function create_similar.
+
+ * src/cairo_gstate.c (_cairo_gstate_show_text): Use new text
+ bounding box function. Pass pattern source offset to show_text.
+ (_cairo_gstate_show_glyphs): Use new text
+ bounding box function. Pass pattern source offset to show_glyps.
+
+ * src/cairo_gl_surface.c (_cairo_gl_surface_create_similar): Added
+ drawable parameter to backend function create_similar. Use glitz's
+ new create similar interface. Support for read-only surfaces.
+ (_cairo_gl_surface_clone_similar): Added drawable parameter to
+ backend function create_similar.
+
+ * src/cairo_ft_font.c: Use new glyph caching system. Added bounding box
+ font backend functions.
+
+ * src/cairo_font.c: Added glyph caching system. Added bounding box
+ font backend functions.
+ (_cairo_font_init): Create new glyph cache.
+ (_cairo_font_copy): Take a reference to other fonts glyph cache.
+ (_cairo_font_show_text):
+ (_cairo_font_show_glyphs): Handle source offset.
+ (cairo_font_destroy): Destroy glyph cache.
+
+2004-05-20 Graydon Hoare <graydon@redhat.com>
+
+ * configure.in: Add sanity checking feature configury.
+
+ * src/cairo-features.h.in: Add sanity checking feature.
+
+ * src/cairo.c: Add sanity checking.
+
+ * src/cairoint.h: Add prototypes.
+
+ * src/cairo_fixed.c
+ (_cairo_fixed_is_integer):
+ (_cairo_fixed_integer_part): New functions.
+
+ * src/cairo_matrix.c
+ (_cairo_matrix_is_integer_translation): New function.
+
+ * src/cairo_gstate.c
+ (extract_transformed_rectangle): Use fixed functions.
+ (_cairo_gstate_clip): Arithmetic fixes.
+ (_cairo_gstate_clip_and_composite_trapezoids):
+ (_cairo_gstate_show_surface):
+ (_cairo_gstate_show_text):
+ (_cairo_gstate_show_glyphs): Corrections to clipping.
+
+ * src/cairo_xlib_surface.c
+ (_cairo_xlib_surface_composite): Add XCopyArea fast path.
+ (_cairo_xlib_surface_set_clip_region): Drive clip to drawable.
+
+2004-05-17 Carl Worth <cworth@isi.edu>
+
+ * src/cairo.c (cairo_show_text): Do nothing when passed a NULL
+ string.
+
+2004-05-11 Øyvind Kolås <oeyvindk@hig.no>
+
+ * src/cairoint.h : changed CAIRO_FILTER_DEFAULT to CAIRO_FILTER_BEST
+ to make gradients easier.
+
+2004-05-11 David Reveman <c99drn@cs.umu.se>
+
+ * src/cairo_pattern.c (_cairo_pattern_get_image): Removed
+ pattern_offset.
+
+ * src/cairo_surface.c (_cairo_surface_create_pattern): Removed
+ pattern_offset.
+
+ * src/cairo_gstate.c: Removed pattern_offset.
+
+ * src/cairoint.h: Removed pattern_offset.
+
2004-05-11 Carl Worth <cworth@isi.edu>
* configure.in: Increment CAIRO_VERSION to 0.1.23.
diff --git a/NEWS b/NEWS
index 5b1e62312..116c8dfcf 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,9 @@
+Glyph caching
+-------------
+Internal caching of glyphs provides a major improvement to
+text rendering performance, especially for Xlib and OpenGL
+backends.
+
Snapshot 0.1.23 (2004-05-11 Carl Worth <cworth@isi.edu>)
========================================================
Fixes for gcc 3.4
diff --git a/autogen.sh b/autogen.sh
index fe847d9eb..4de364a16 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -3,6 +3,8 @@
set -e
+PACKAGE=cairo
+
LIBTOOLIZE=${LIBTOOLIZE-libtoolize}
LIBTOOLIZE_FLAGS="--copy --force"
ACLOCAL=${ACLOCAL-aclocal}
@@ -11,8 +13,82 @@ AUTOMAKE=${AUTOMAKE-automake}
AUTOMAKE_FLAGS="--add-missing"
AUTOCONF=${AUTOCONF-autoconf}
+# automake 1.8 requires autoconf 2.58
+# automake 1.7 requires autoconf 2.54
+automake_min_vers=1.7
+aclocal_min_vers=$automake_min_vers
+autoconf_min_vers=2.54
+libtoolize_min_vers=1.4
+
+
ARGV0=$0
+if ($AUTOCONF --version) < /dev/null > /dev/null 2>&1 ; then
+ if ($AUTOCONF --version | head -1 | awk 'NR==1 { if( $(NF) >= '$autoconf_min_vers') \
+ exit 1; exit 0; }');
+ then
+ echo "$ARGV0: ERROR: \`$AUTOCONF' is too old."
+ $AUTOCONF --version
+ echo " (version $autoconf_min_vers or newer is required)"
+ DIE="yes"
+ fi
+else
+ echo $AUTOCONF: command not found
+ echo
+ echo "$ARGV0: ERROR: You must have \`autoconf' installed to compile $PACKAGE."
+ echo " (version $autoconf_min_vers or newer is required)"
+ DIE="yes"
+fi
+
+if ($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 ; then
+ if ($AUTOMAKE --version | head -1 | awk 'NR==1 { if( $(NF) >= '$automake_min_vers') \
+ exit 1; exit 0; }');
+ then
+ echo "$ARGV0: ERROR: \`$AUTOMAKE' is too old."
+ $AUTOMAKE --version
+ echo " (version $automake_min_vers or newer is required)"
+ DIE="yes"
+ fi
+ if ($ACLOCAL --version) < /dev/null > /dev/null 2>&1; then
+ if ($ACLOCAL --version | head -1 | awk 'NR==1 { if( $(NF) >= '$aclocal_min_vers' ) \
+ exit 1; exit 0; }' );
+ then
+ echo "$ARGV0: ERROR: \`$ACLOCAL' is too old."
+ $ACLOCAL --version
+ echo " (version $aclocal_min_vers or newer is required)"
+ DIE="yes"
+ fi
+ else
+ echo $ACLOCAL: command not found
+ echo
+ echo "$ARGV0: ERROR: Missing \`$ACLOCAL'"
+ echo " The version of $AUTOMAKE installed doesn't appear recent enough."
+ DIE="yes"
+ fi
+else
+ echo $AUTOMAKE: command not found
+ echo
+ echo "$ARGV0: ERROR: You must have \`automake' installed to compile $PACKAGE."
+ echo " (version $automake_min_vers or newer is required)"
+ DIE="yes"
+fi
+
+if ($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 ; then
+ if ($LIBTOOLIZE --version | awk 'NR==1 { if( $4 >= '$libtoolize_min_vers') \
+ exit 1; exit 0; }');
+ then
+ echo "$ARGV0: ERROR: \`$LIBTOOLIZE' is too old."
+ echo " (version $libtoolize_min_vers or newer is required)"
+ DIE="yes"
+ fi
+else
+ echo $LIBTOOLIZE: command not found
+ echo
+ echo "$ARGV0: ERROR: You must have \`libtoolize' installed to compile $PACKAGE."
+ echo " (version $libtoolize_min_vers or newer is required)"
+ DIE="yes"
+fi
+
if test -z "$ACLOCAL_FLAGS"; then
acdir=`aclocal --print-ac-dir`
if [ ! -f $acdir/pkg.m4 ]; then
@@ -24,10 +100,15 @@ if test -z "$ACLOCAL_FLAGS"; then
echo ""
echo "pkg-config is available from:"
echo "http://www.freedesktop.org/software/pkgconfig/"
- exit 1
+ DIE=yes
fi
fi
+if test "X$DIE" != X; then
+ exit 1
+fi
+
+
if test -z "$*"; then
echo "$ARGV0: Note: \`./configure' will be run with no arguments."
echo " If you wish to pass any to it, please specify them on the"
diff --git a/configure.in b/configure.in
index 3ac8f8459..5ab37391a 100644
--- a/configure.in
+++ b/configure.in
@@ -141,7 +141,7 @@ AC_ARG_ENABLE(gl,
[use_gl=$enableval], [use_gl=yes])
if test "x$use_gl" = "xyes"; then
- PKG_CHECK_MODULES(GL, glitz >= 0.1.2, [
+ PKG_CHECK_MODULES(GL, glitz >= 0.1.5, [
GL_REQUIRES=glitz
use_gl=yes], [use_gl="no (requires glitz http://freedesktop.org/software/glitz)"])
fi
@@ -161,6 +161,20 @@ AC_SUBST(GL_REQUIRES)
dnl ===========================================================================
+AC_ARG_ENABLE(sanity-checking,
+ [ --disable-sanity Disable cairo's sanity checking routines],
+ [check_sanity=$enableval], [check_sanity=yes])
+
+if test "x$check_sanity" != "xyes"; then
+ SANITY_CHECKING_FEATURE=CAIRO_NO_SANITY_CHECKING
+else
+ SANITY_CHECKING_FEATURE=CAIRO_DO_SANITY_CHECKING
+fi
+
+AC_SUBST(SANITY_CHECKING_FEATURE)
+
+dnl ===========================================================================
+
PKG_CHECK_MODULES(FONTCONFIG, fontconfig)
PKG_CHECK_MODULES(CAIRO, libpixman >= 0.1.1)
@@ -213,6 +227,22 @@ AC_SUBST(CAIRO_LIBS)
dnl ===========================================================================
+dnl Checks for precise integer types
+AC_CHECK_TYPES([uint64_t, uint128_t])
+
+dnl Use lots of warning flags with GCC
+
+WARN_CFLAGS=""
+
+if test "x$GCC" = "xyes"; then
+ WARN_CFLAGS="-Wall -Wpointer-arith -Wstrict-prototypes \
+ -Wmissing-prototypes -Wmissing-declarations \
+ -Wnested-externs -fno-strict-aliasing"
+fi
+AC_SUBST(WARN_CFLAGS)
+
+dnl ===========================================================================
+
AC_OUTPUT([
cairo.pc
Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 3b42d0e53..38a30adef 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -50,6 +50,8 @@ libcairo_la_SOURCES = \
cairo_surface.c \
cairo_traps.c \
cairo_pattern.c \
+ cairo_wideint.c \
+ cairo_wideint.h \
$(libcairo_ps_sources) \
$(libcairo_png_sources) \
$(libcairo_xlib_sources)\
@@ -59,6 +61,6 @@ libcairo_la_SOURCES = \
libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined
-INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(XCB_CFLAGS) $(PNG_CFLAGS) $(GL_CFLAGS)
+INCLUDES = -I$(srcdir) $(WARN_CFLAGS) $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(XCB_CFLAGS) $(PNG_CFLAGS) $(GL_CFLAGS)
libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(XCB_LIBS) $(PS_LIBS) $(PNG_LIBS) $(GL_LIBS) -lm
diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in
index 7eec9780c..644f55ccc 100644
--- a/src/cairo-features.h.in
+++ b/src/cairo-features.h.in
@@ -38,4 +38,6 @@
#define @GL_SURFACE_FEATURE@
+#define @SANITY_CHECKING_FEATURE@
+
#endif
diff --git a/src/cairo-fixed.c b/src/cairo-fixed.c
index 9a7e7bc47..2561a4ad5 100644
--- a/src/cairo-fixed.c
+++ b/src/cairo-fixed.c
@@ -51,3 +51,14 @@ _cairo_fixed_to_double (cairo_fixed_t f)
return ((double) f) / 65536.0;
}
+int
+_cairo_fixed_is_integer (cairo_fixed_t f)
+{
+ return (f & 0xFFFF) == 0;
+}
+
+int
+_cairo_fixed_integer_part (cairo_fixed_t f)
+{
+ return f >> 16;
+}
diff --git a/src/cairo-font.c b/src/cairo-font.c
index 157ebedbe..3044e8877 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -27,6 +27,15 @@
#include "cairoint.h"
+static cairo_glyph_cache_t *
+_cairo_glyph_cache_create (void);
+
+static void
+_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache);
+
+static void
+_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache);
+
cairo_font_t *
_cairo_font_create (const char *family,
cairo_font_slant_t slant,
@@ -50,6 +59,9 @@ _cairo_font_init (cairo_font_t *font,
cairo_matrix_set_identity (&font->matrix);
font->refcount = 1;
font->backend = backend;
+ font->glyph_cache = _cairo_glyph_cache_create ();
+ if (font->glyph_cache == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
return CAIRO_STATUS_SUCCESS;
}
@@ -72,6 +84,13 @@ _cairo_font_copy (cairo_font_t *font)
newfont->refcount = 1;
cairo_matrix_copy(&newfont->matrix, &font->matrix);
newfont->backend = font->backend;
+
+ if (newfont->glyph_cache)
+ _cairo_glyph_cache_destroy (newfont->glyph_cache);
+
+ newfont->glyph_cache = font->glyph_cache;
+ _cairo_glyph_cache_reference (font->glyph_cache);
+
return newfont;
}
@@ -105,18 +124,40 @@ _cairo_font_glyph_extents (cairo_font_t *font,
return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
}
+cairo_status_t
+_cairo_font_text_bbox (cairo_font_t *font,
+ cairo_surface_t *surface,
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_box_t *bbox)
+{
+ return font->backend->text_bbox (font, surface, x, y, utf8, bbox);
+}
+
+cairo_status_t
+_cairo_font_glyph_bbox (cairo_font_t *font,
+ cairo_surface_t *surface,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
+{
+ return font->backend->glyph_bbox (font, surface, glyphs, num_glyphs, bbox);
+}
cairo_status_t
_cairo_font_show_text (cairo_font_t *font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
+ int source_x,
+ int source_y,
double x,
double y,
const unsigned char *utf8)
{
return font->backend->show_text(font, operator, source,
- surface, x, y, utf8);
+ surface, source_x, source_y, x, y, utf8);
}
cairo_status_t
@@ -124,11 +165,14 @@ _cairo_font_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
+ int source_x,
+ int source_y,
cairo_glyph_t *glyphs,
int num_glyphs)
{
return font->backend->show_glyphs(font, operator, source,
- surface, glyphs, num_glyphs);
+ surface, source_x, source_y,
+ glyphs, num_glyphs);
}
cairo_status_t
@@ -157,6 +201,183 @@ _cairo_font_font_extents (cairo_font_t *font,
return font->backend->font_extents(font, extents);
}
+static void
+_cairo_glyph_cache_pop_last (cairo_glyph_cache_t *glyph_cache)
+{
+ if (glyph_cache->last) {
+ cairo_glyph_surface_node_t *remove = glyph_cache->last;
+
+ cairo_surface_destroy (remove->s.surface);
+ glyph_cache->last = remove->prev;
+ if (glyph_cache->last)
+ glyph_cache->last->next = NULL;
+
+ free (remove);
+ glyph_cache->n_nodes--;
+ }
+}
+
+static cairo_glyph_cache_t *
+_cairo_glyph_cache_create (void)
+{
+ cairo_glyph_cache_t *glyph_cache;
+
+ glyph_cache = malloc (sizeof (cairo_glyph_cache_t));
+ if (glyph_cache == NULL)
+ return NULL;
+
+ glyph_cache->n_nodes = 0;
+ glyph_cache->first = NULL;
+ glyph_cache->last = NULL;
+ glyph_cache->cache_size = CAIRO_FONT_CACHE_SIZE_DEFAULT;
+ glyph_cache->ref_count = 1;
+
+ return glyph_cache;
+}
+
+static void
+_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache)
+{
+ if (glyph_cache == NULL)
+ return;
+
+ glyph_cache->ref_count++;
+}
+
+static void
+_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache)
+{
+ if (glyph_cache == NULL)
+ return;
+
+ glyph_cache->ref_count--;
+ if (glyph_cache->ref_count)
+ return;
+
+ while (glyph_cache->last)
+ _cairo_glyph_cache_pop_last (glyph_cache);
+
+ free (glyph_cache);
+}
+
+static void
+_cairo_glyph_surface_init (cairo_font_t *font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_surface_t *glyph_surface)
+{
+ cairo_surface_t *image;
+
+ glyph_surface->surface = NULL;
+ glyph_surface->index = glyph->index;
+ glyph_surface->matrix[0][0] = font->matrix.m[0][0];
+ glyph_surface->matrix[0][1] = font->matrix.m[0][1];
+ glyph_surface->matrix[1][0] = font->matrix.m[1][0];
+ glyph_surface->matrix[1][1] = font->matrix.m[1][1];
+
+ image = font->backend->create_glyph (font, glyph, &glyph_surface->size);
+ if (image == NULL)
+ return;
+
+ if (surface->backend != image->backend) {
+ cairo_status_t status;
+
+ glyph_surface->surface =
+ _cairo_surface_create_similar_scratch (surface,
+ CAIRO_FORMAT_A8, 0,
+ glyph_surface->size.width,
+ glyph_surface->size.height);
+ if (glyph_surface->surface == NULL) {
+ glyph_surface->surface = image;
+ return;
+ }
+
+ status = _cairo_surface_set_image (glyph_surface->surface,
+ (cairo_image_surface_t *) image);
+ if (status) {
+ cairo_surface_destroy (glyph_surface->surface);
+ glyph_surface->surface = NULL;
+ }
+ cairo_surface_destroy (image);
+ } else
+ glyph_surface->surface = image;
+}
+
+cairo_surface_t *
+_cairo_font_lookup_glyph (cairo_font_t *font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_size_t *return_size)
+{
+ cairo_glyph_surface_t glyph_surface;
+ cairo_glyph_cache_t *cache = font->glyph_cache;
+ cairo_glyph_surface_node_t *node;
+
+ for (node = cache->first; node != NULL; node = node->next) {
+ cairo_glyph_surface_t *s = &node->s;
+
+ if ((s->surface == NULL || s->surface->backend == surface->backend) &&
+ s->index == glyph->index &&
+ s->matrix[0][0] == font->matrix.m[0][0] &&
+ s->matrix[0][1] == font->matrix.m[0][1] &&
+ s->matrix[1][0] == font->matrix.m[1][0] &&
+ s->matrix[1][1] == font->matrix.m[1][1]) {
+
+ /* move node first in cache */
+ if (node->prev) {
+ if (node->next == NULL) {
+ cache->last = node->prev;
+ node->prev->next = NULL;
+ } else {
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ }
+
+ node->prev = NULL;
+ node->next = cache->first;
+ cache->first = node;
+ if (node->next)
+ node->next->prev = node;
+ else
+ cache->last = node;
+ }
+
+ cairo_surface_reference (s->surface);
+ *return_size = s->size;
+
+ return s->surface;
+ }
+ }
+
+ _cairo_glyph_surface_init (font, surface, glyph, &glyph_surface);
+
+ *return_size = glyph_surface.size;
+
+ if (cache->cache_size > 0) {
+ if (cache->n_nodes == cache->cache_size)
+ _cairo_glyph_cache_pop_last (cache);
+
+ node = malloc (sizeof (cairo_glyph_surface_node_t));
+ if (node) {
+ cairo_surface_reference (glyph_surface.surface);
+
+ /* insert node first in cache */
+ node->s = glyph_surface;
+ node->prev = NULL;
+ node->next = cache->first;
+ cache->first = node;
+ if (node->next)
+ node->next->prev = node;
+ else
+ cache->last = node;
+
+ cache->n_nodes++;
+ }
+ }
+
+ return glyph_surface.surface;
+}
+
/* public font interface follows */
void
@@ -171,6 +392,8 @@ cairo_font_destroy (cairo_font_t *font)
if (--(font->refcount) > 0)
return;
+ _cairo_glyph_cache_destroy (font->glyph_cache);
+
if (font->backend->destroy)
font->backend->destroy (font);
}
@@ -188,5 +411,3 @@ cairo_font_current_transform (cairo_font_t *font,
{
cairo_matrix_copy (matrix, &(font->matrix));
}
-
-
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index c1c8d6ea0..5b0a7f641 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -29,6 +29,7 @@
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
+#include FT_IMAGE_H
typedef struct {
cairo_font_t base;
@@ -464,23 +465,99 @@ _cairo_ft_font_text_extents (void *abstract_font,
}
static cairo_status_t
+_cairo_ft_font_glyph_bbox (void *abstract_font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
+{
+ cairo_ft_font_t *font = abstract_font;
+ 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);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_ft_font_text_bbox (void *abstract_font,
+ cairo_surface_t *surface,
+ double x0,
+ double y0,
+ const unsigned char *utf8,
+ cairo_box_t *bbox)
+{
+ cairo_ft_font_t *font = 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_ft_font_glyph_bbox (font, surface,
+ glyphs, num_glyphs, bbox);
+ free (glyphs);
+ return res;
+ }
+ else
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+static cairo_status_t
_cairo_ft_font_show_glyphs (void *abstract_font,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
cairo_ft_font_t *font = abstract_font;
cairo_status_t status;
- int i;
- cairo_ft_font_t *ft = NULL;
- FT_GlyphSlot glyphslot;
cairo_surface_t *mask = NULL;
- cairo_point_double_t origin;
+ cairo_glyph_size_t size;
double x, y;
- int width, height, stride;
+ int i;
if (font == NULL
|| source == NULL
@@ -488,84 +565,27 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
|| glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY;
- ft = (cairo_ft_font_t *)font;
- glyphslot = ft->face->glyph;
- _install_font_matrix (&font->base.matrix, ft->face);
-
for (i = 0; i < num_glyphs; i++)
{
- unsigned char *bitmap;
-
- FT_Load_Glyph (ft->face, glyphs[i].index, FT_LOAD_DEFAULT);
- FT_Render_Glyph (glyphslot, ft_render_mode_normal);
-
- width = glyphslot->bitmap.width;
- height = glyphslot->bitmap.rows;
- stride = glyphslot->bitmap.pitch;
- bitmap = glyphslot->bitmap.buffer;
+ mask = _cairo_font_lookup_glyph (&font->base, surface,
+ &glyphs[i], &size);
+ if (mask == NULL)
+ continue;
x = glyphs[i].x;
y = glyphs[i].y;
- if (i == 0) {
- origin.x = x;
- origin.y = y;
- }
-
- /* X gets upset with zero-sized images (such as whitespace) */
- if (width * height == 0)
- continue;
-
- /*
- * XXX
- * reformat to match libic alignment requirements.
- * This should be done before rendering the glyph,
- * but that requires using FT_Outline_Get_Bitmap
- * function
- */
- if (stride & 3)
- {
- int nstride = (stride + 3) & ~3;
- unsigned char *g, *b;
- int h;
-
- bitmap = malloc (nstride * height);
- if (!bitmap)
- return CAIRO_STATUS_NO_MEMORY;
- g = glyphslot->bitmap.buffer;
- b = bitmap;
- h = height;
- while (h--)
- {
- memcpy (b, g, width);
- b += nstride;
- g += stride;
- }
- stride = nstride;
- }
- mask = cairo_surface_create_for_image (bitmap,
- CAIRO_FORMAT_A8,
- width, height, stride);
- if (mask == NULL)
- {
- if (bitmap != glyphslot->bitmap.buffer)
- free (bitmap);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- status =
- _cairo_surface_composite (operator, source, mask, surface,
- -origin.x + x + glyphslot->bitmap_left,
- -origin.y + y - glyphslot->bitmap_top,
- 0, 0,
- x + glyphslot->bitmap_left,
- y - glyphslot->bitmap_top,
- (double) width, (double) height);
+ 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 (bitmap != glyphslot->bitmap.buffer)
- free (bitmap);
-
+
if (status)
return status;
}
@@ -577,19 +597,22 @@ _cairo_ft_font_show_text (void *abstract_font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
+ int source_x,
+ int source_y,
double x0,
double y0,
const unsigned char *utf8)
{
cairo_ft_font_t *font = abstract_font;
cairo_glyph_t *glyphs;
- int num_glyphs;
+ size_t num_glyphs;
if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs))
{
cairo_status_t res;
res = _cairo_ft_font_show_glyphs (font, operator,
source, surface,
+ source_x, source_y,
glyphs, num_glyphs);
free (glyphs);
return res;
@@ -768,6 +791,74 @@ cairo_ft_font_create_for_ft_face (FT_Face face)
return (cairo_font_t *) f;
}
+static cairo_surface_t *
+_cairo_ft_font_create_glyph (void *abstract_font,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_size_t *return_size)
+{
+ cairo_ft_font_t *font = abstract_font;
+ cairo_image_surface_t *image;
+ FT_GlyphSlot glyphslot;
+ unsigned int width, height, stride;
+ FT_Outline *outline;
+ 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;
+}
+
const struct cairo_font_backend cairo_ft_font_backend = {
_cairo_ft_font_create,
_cairo_ft_font_copy,
@@ -775,8 +866,11 @@ const struct cairo_font_backend cairo_ft_font_backend = {
_cairo_ft_font_font_extents,
_cairo_ft_font_text_extents,
_cairo_ft_font_glyph_extents,
+ _cairo_ft_font_text_bbox,
+ _cairo_ft_font_glyph_bbox,
_cairo_ft_font_show_text,
_cairo_ft_font_show_glyphs,
_cairo_ft_font_text_path,
_cairo_ft_font_glyph_path,
+ _cairo_ft_font_create_glyph
};
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 0ff24c15d..6d89964e8 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -78,8 +78,6 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->clip.surface = NULL;
gstate->pattern = _cairo_pattern_create_solid (1.0, 1.0, 1.0);
- gstate->pattern_offset.x = 0.0;
- gstate->pattern_offset.y = 0.0;
gstate->alpha = 1.0;
gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
@@ -400,8 +398,6 @@ _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);
- gstate->pattern_offset.x = 0.0;
- gstate->pattern_offset.y = 0.0;
return CAIRO_STATUS_SUCCESS;
}
@@ -883,25 +879,26 @@ _cairo_gstate_arc_dir (cairo_gstate_t *gstate,
/* Recurse if drawing arc larger than pi */
if (angle_max - angle_min > M_PI) {
+ double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
/* XXX: Something tells me this block could be condensed. */
if (dir == CAIRO_DIRECTION_FORWARD) {
status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_min + M_PI, dir);
+ angle_min, angle_mid, dir);
if (status)
return status;
status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min + M_PI, angle_max, dir);
+ angle_mid, angle_max, dir);
if (status)
return status;
} else {
status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min + M_PI, angle_max, dir);
+ angle_mid, angle_max, dir);
if (status)
return status;
status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_min + M_PI, dir);
+ angle_min, angle_mid, dir);
if (status)
return status;
}
@@ -1268,18 +1265,22 @@ _cairo_gstate_create_pattern (cairo_gstate_t *gstate,
if (pattern->n_stops < 2) {
pattern->type = CAIRO_PATTERN_SOLID;
- if (pattern->n_stops)
- pattern->color = pattern->stops->color;
+ 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);
- _cairo_pattern_set_source_offset (pattern,
- gstate->pattern_offset.x,
- gstate->pattern_offset.y);
-
status = _cairo_surface_create_pattern (gstate->surface, pattern, extents);
if (status) {
_cairo_pattern_fini (pattern);
@@ -1362,6 +1363,7 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
cairo_status_t status;
cairo_pattern_t pattern;
cairo_box_t extents;
+ int x_src, y_src;
if (traps->num_traps == 0)
return CAIRO_STATUS_SUCCESS;
@@ -1404,6 +1406,14 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
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);
@@ -1414,7 +1424,8 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
pattern.source, intermediate,
- 0, 0,
+ x_src,
+ y_src,
traps->traps,
traps->num_traps);
if (status)
@@ -1443,12 +1454,15 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
if (status)
goto BAIL2;
+ if (dst == gstate->clip.surface)
+ xoff = yoff = 0;
+
status = _cairo_surface_composite (operator,
pattern.source, intermediate, dst,
0, 0,
0, 0,
- gstate->clip.x,
- gstate->clip.y,
+ xoff >> 16,
+ yoff >> 16,
gstate->clip.width,
gstate->clip.height);
@@ -1462,14 +1476,12 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
return status;
} else {
- int xoff, yoff;
-
if (traps->traps[0].left.p1.y < traps->traps[0].left.p2.y) {
- xoff = _cairo_fixed_to_double (traps->traps[0].left.p1.x);
- yoff = _cairo_fixed_to_double (traps->traps[0].left.p1.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 {
- xoff = _cairo_fixed_to_double (traps->traps[0].left.p2.x);
- yoff = _cairo_fixed_to_double (traps->traps[0].left.p2.y);
+ 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_copy (&pattern, src);
@@ -1481,8 +1493,8 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
status = _cairo_surface_composite_trapezoids (gstate->operator,
pattern.source, dst,
- xoff - pattern.source_offset.x,
- yoff - pattern.source_offset.y,
+ x_src - pattern.source_offset.x,
+ y_src - pattern.source_offset.y,
traps->traps,
traps->num_traps);
@@ -1640,8 +1652,9 @@ _cairo_gstate_init_clip (cairo_gstate_t *gstate)
gstate->clip.region = NULL;
/* reset the surface's clip to the whole surface */
- _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
+ if (gstate->surface)
+ _cairo_surface_set_clip_region (gstate->surface,
+ gstate->clip.region);
return CAIRO_STATUS_SUCCESS;
}
@@ -1651,9 +1664,6 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
cairo_traps_t *tr,
pixman_box16_t *box)
{
-#define CAIRO_FIXED_IS_INTEGER(x) (((x) & 0xFFFF) == 0)
-#define CAIRO_FIXED_INTEGER_PART(x) ((x) >> 16)
-
double a, b, c, d, tx, ty;
cairo_status_t st;
@@ -1666,25 +1676,22 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
&& tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
&& tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
&& tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.y)) {
-
- box->x1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.x);
- box->x2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].right.p1.x);
- box->y1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.y);
- box->y2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p2.y);
+ && _cairo_fixed_is_integer(tr->traps[0].left.p1.x)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p1.y)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p2.x)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p2.y)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p1.x)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p1.y)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p2.x)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p2.y)) {
+
+ box->x1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.x);
+ box->x2 = (short) _cairo_fixed_integer_part(tr->traps[0].right.p1.x);
+ box->y1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.y);
+ box->y2 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p2.y);
return 1;
}
return 0;
-
-#undef CAIRO_FIXED_IS_INTEGER
-#undef CAIRO_FIXED_INTEGER_PART
}
cairo_status_t
@@ -1751,20 +1758,20 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_color_init (&white_color);
if (gstate->clip.surface == NULL) {
- double x1, y1, x2, y2;
- _cairo_path_bounds (&gstate->path,
- &x1, &y1, &x2, &y2);
- gstate->clip.x = floor (x1);
- gstate->clip.y = floor (y1);
- gstate->clip.width = ceil (x2 - gstate->clip.x);
- gstate->clip.height = ceil (y2 - gstate->clip.y);
- gstate->clip.surface =
- _cairo_surface_create_similar_solid (gstate->surface,
- CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
- &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;
+ gstate->clip.surface =
+ _cairo_surface_create_similar_solid (gstate->surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &white_color);
+ if (gstate->clip.surface == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
@@ -1790,14 +1797,78 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
int width,
int height)
{
+
+ /* We are dealing with 5 coordinate spaces in this function. this makes
+ * it ugly.
+ *
+ * - "Image" space is the space of the surface we're reading pixels from.
+ * it is the surface argument to this function. The surface has a
+ * matrix attached to it which maps "user" space (see below) into
+ * image space.
+ *
+ * - "Device" space is the space of the surface we're ultimately writing
+ * pixels to. It is the current surface of the gstate argument to
+ * this function.
+ *
+ * - "User" space is an arbitrary space defined by the user, defined
+ * implicitly by the gstate's CTM. The CTM maps from user space to
+ * device space. The CTM inverse (which is also kept at all times)
+ * maps from device space to user space.
+ *
+ * - "Clip" space is the space of the surface being used to clip pixels
+ * during compositing. Space-wise, it is a bounding box (offset+size)
+ * within device space. This surface is usually smaller than the device
+ * surface (and possibly the image surface too) and logically occupies
+ * a bounding box around the "clip path", situated somewhere in device
+ * space. The clip path is already painted on the clip surface.
+ *
+ * - "Pattern" space is another arbitrary space defined in the pattern
+ * element of gstate. As pixels are read from image space, they are
+ * combined with pixels being read from pattern space and pixels
+ * already existing in device space. User coordinates are converted
+ * to pattern space, similarly, using a matrix attached to the pattern.
+ * (in fact, there is a 6th space in here, which is the space of the
+ * surface acting as a source for the pattern)
+ *
+ * To composite these spaces, we temporarily change the image surface
+ * so that it can be read and written in device coordinates; in a sense
+ * this makes it "spatially compatible" with the clip and device spaces.
+ *
+ *
+ * There is also some confusion about the interaction between a clip and
+ * a pattern; it is assumed that in this "show surface" operation a pattern
+ * is to be used as an auxiliary alpha mask. this might be wrong, but it's
+ * what we're doing now.
+ *
+ * so, to follow the operations below, remember that in the compositing
+ * model, each operation is always of the form ((src IN mask) OP dst).
+ * that's the basic operation.
+ *
+ * so the compositing we are trying to do here, in general, involves 2
+ * steps, going via a temporary surface:
+ *
+ * - combining clip and pattern pixels together into a mask channel.
+ * this will be ((pattern IN clip) SRC temporary). it ignores the
+ * pixels already in the temporary, overwriting it with the
+ * pattern, clipped to the clip mask.
+ *
+ * - combining temporary and "image" pixels with "device" pixels,
+ * with a user-provided porter/duff operator. this will be
+ * ((image IN temporary) OP device).
+ *
+ * if there is no clip, the degenerate case is just the second step
+ * with pattern standing in for temporary.
+ *
+ */
+
cairo_status_t status;
cairo_matrix_t user_to_image, image_to_user;
cairo_matrix_t image_to_device, device_to_image;
double device_x, device_y;
double device_width, device_height;
cairo_pattern_t pattern;
- cairo_box_t extents;
-
+ cairo_box_t pattern_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);
@@ -1816,31 +1887,84 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
_cairo_pattern_init (&pattern);
if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) ||
- (gstate->alpha != 1.0)) {
+ (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);
- extents.p1.x = _cairo_fixed_from_double (device_x);
- extents.p1.y = _cairo_fixed_from_double (device_y);
- extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
- extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
+ 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);
+ status = _cairo_gstate_create_pattern (gstate, &pattern, &pattern_extents);
if (status)
return status;
}
- /* XXX: The rendered size is sometimes 1 or 2 pixels short from
- what I expect. Need to fix this. */
- status = _cairo_surface_composite (gstate->operator,
- surface, pattern.source, gstate->surface,
- device_x, device_y,
- 0, 0,
- device_x, device_y,
- device_width,
- device_height);
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
- _cairo_pattern_fini (&pattern);
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ /* 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,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ surface,
+ intermediate,
+ gstate->surface,
+ gstate->clip.x, gstate->clip.y,
+ 0, 0,
+ gstate->clip.x, gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+ }
+ else
+ {
+
+ /* XXX: The rendered size is sometimes 1 or 2 pixels short from
+ what I expect. Need to fix this. */
+ status = _cairo_surface_composite (gstate->operator,
+ surface,
+ pattern.source,
+ gstate->surface,
+ device_x, device_y,
+ 0, 0,
+ device_x, device_y,
+ device_width,
+ device_height);
+
+ }
+
+ _cairo_pattern_fini (&pattern);
+
/* restore the matrix originally in the surface */
cairo_surface_set_matrix (surface, &user_to_image);
@@ -1983,8 +2107,7 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate,
double x, y;
cairo_matrix_t saved_font_matrix;
cairo_pattern_t pattern;
- cairo_text_extents_t text_extents;
- cairo_box_t extents;
+ cairo_box_t bbox;
status = _cairo_path_current_point (&gstate->path, &point);
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
@@ -2001,21 +2124,76 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate,
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- status = _cairo_gstate_text_extents (gstate, utf8, &text_extents);
+ status = _cairo_font_text_bbox (gstate->font, gstate->surface,
+ x, y, utf8, &bbox);
if (status)
return status;
- extents.p1.x = _cairo_fixed_from_double (x);
- extents.p1.y = _cairo_fixed_from_double (y);
- extents.p2.x = _cairo_fixed_from_double (x + text_extents.width);
- extents.p2.y = _cairo_fixed_from_double (y + text_extents.height);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
+ status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
if (status)
return status;
- status = _cairo_font_show_text (gstate->font,
- gstate->operator, pattern.source,
- gstate->surface, x, y, utf8);
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
+
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ status = _cairo_font_show_text (gstate->font,
+ CAIRO_OPERATOR_ADD, pattern.source,
+ intermediate,
+ gstate->clip.x - pattern.source_offset.x,
+ gstate->clip.y - pattern.source_offset.y,
+ x - gstate->clip.x,
+ y - gstate->clip.y, utf8);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ gstate->clip.surface,
+ NULL,
+ intermediate,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ pattern.source,
+ intermediate,
+ gstate->surface,
+ 0, 0,
+ 0, 0,
+ gstate->clip.x,
+ gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+
+ }
+ else
+ {
+ status = _cairo_font_show_text (gstate->font,
+ gstate->operator, pattern.source,
+ gstate->surface,
+ -pattern.source_offset.x,
+ -pattern.source_offset.y,
+ x, y, utf8);
+ }
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
@@ -2034,8 +2212,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
int i;
cairo_glyph_t *transformed_glyphs = NULL;
cairo_pattern_t pattern;
- cairo_text_extents_t text_extents;
- cairo_box_t extents;
+ cairo_box_t bbox;
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
if (transformed_glyphs == NULL)
@@ -2053,25 +2230,82 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs,
- &text_extents);
+ status = _cairo_font_glyph_bbox (gstate->font, gstate->surface,
+ transformed_glyphs, num_glyphs, &bbox);
if (status)
return status;
- extents.p1.x = _cairo_fixed_from_double (transformed_glyphs[0].x);
- extents.p1.y = _cairo_fixed_from_double (transformed_glyphs[0].y);
- extents.p2.x = _cairo_fixed_from_double (transformed_glyphs[0].x +
- text_extents.width);
- extents.p2.y = _cairo_fixed_from_double (transformed_glyphs[0].y +
- text_extents.height);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
+ status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
if (status)
return status;
+
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
+
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ /* move the glyphs again, from dev space to clip space */
+ for (i = 0; i < num_glyphs; ++i)
+ {
+ transformed_glyphs[i].x -= gstate->clip.x;
+ transformed_glyphs[i].y -= gstate->clip.y;
+ }
+
+ status = _cairo_font_show_glyphs (gstate->font,
+ CAIRO_OPERATOR_ADD,
+ pattern.source, intermediate,
+ gstate->clip.x - pattern.source_offset.x,
+ gstate->clip.y - pattern.source_offset.y,
+ transformed_glyphs, num_glyphs);
- status = _cairo_font_show_glyphs (gstate->font,
- gstate->operator, pattern.source,
- gstate->surface,
- transformed_glyphs, num_glyphs);
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ gstate->clip.surface,
+ NULL,
+ intermediate,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ pattern.source,
+ intermediate,
+ gstate->surface,
+ 0, 0,
+ 0, 0,
+ gstate->clip.x,
+ gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+
+ }
+ else
+ {
+ status = _cairo_font_show_glyphs (gstate->font,
+ gstate->operator, pattern.source,
+ gstate->surface,
+ -pattern.source_offset.x,
+ -pattern.source_offset.y,
+ transformed_glyphs, num_glyphs);
+ }
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 2b52e5b21..76a3dbaa9 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -179,6 +179,7 @@ cairo_image_surface_create_for_data (char *data,
static cairo_surface_t *
_cairo_image_surface_create_similar (void *abstract_src,
cairo_format_t format,
+ int drawable,
int width,
int height)
{
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index de89c0fd5..cc5635fff 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -405,3 +405,27 @@ _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double
return CAIRO_STATUS_SUCCESS;
}
+
+int
+_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
+ int *itx, int *ity)
+{
+ double a, b, c, d, tx, ty;
+ int ttx, tty;
+ int ok = 0;
+ cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
+ ttx = _cairo_fixed_from_double (tx);
+ tty = _cairo_fixed_from_double (ty);
+ ok = ((a == 1.0)
+ && (b == 0.0)
+ && (c == 0.0)
+ && (d == 1.0)
+ && (_cairo_fixed_is_integer(ttx))
+ && (_cairo_fixed_is_integer(tty)));
+ if (ok) {
+ *itx = _cairo_fixed_integer_part(ttx);
+ *ity = _cairo_fixed_integer_part(tty);
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index b81b1bd01..e10013729 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1,32 +1,35 @@
-/*
- * Copyright © 2002 University of Southern California
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 David Reveman
*
* 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 the
- * University of Southern California not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. The University of Southern
- * California makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express
- * or implied warranty.
+ * appear in supporting documentation, and that the name of David
+ * Reveman not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. David Reveman makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
*
- * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * SOUTHERN CALIFORNIA 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.
+ * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL DAVID REVEMAN 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.
*
* Author: David Reveman <c99drn@cs.umu.se>
*/
#include "cairoint.h"
+#define MULTIPLY_COLORCOMP(c1, c2) \
+ ((unsigned char) \
+ ((((unsigned char) (c1)) * (int) ((unsigned char) (c2))) / 0xff))
+
void
_cairo_pattern_init (cairo_pattern_t *pattern)
{
@@ -247,13 +250,11 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
stop->offset = _cairo_fixed_from_double (offset);
stop->id = pattern->n_stops;
- _cairo_color_init (&stop->color);
- _cairo_color_set_rgb (&stop->color, red, green, blue);
- _cairo_color_set_alpha (&stop->color, alpha);
- stop->color_char[0] = stop->color.red_short / 256;
- stop->color_char[1] = stop->color.green_short / 256;
- stop->color_char[2] = stop->color.blue_short / 256;
- stop->color_char[3] = stop->color.alpha_short / 256;
+
+ stop->color_char[0] = red * 0xff;
+ stop->color_char[1] = green * 0xff;
+ stop->color_char[2] = blue * 0xff;
+ stop->color_char[3] = alpha * 0xff;
/* sort stops in ascending order */
qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t),
@@ -329,16 +330,9 @@ _cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha)
_cairo_color_set_alpha (&pattern->color, alpha);
- for (i = 0; i < pattern->n_stops; i++) {
- cairo_color_stop_t *stop = &pattern->stops[i];
-
- _cairo_color_set_alpha (&stop->color, stop->color.alpha * alpha);
-
- stop->color_char[0] = stop->color.red_short / 256;
- stop->color_char[1] = stop->color.green_short / 256;
- stop->color_char[2] = stop->color.blue_short / 256;
- stop->color_char[3] = stop->color.alpha_short / 256;
- }
+ 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
@@ -510,6 +504,14 @@ _cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
op->shader_function (op->stops[i].color_char,
op->stops[i + 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;
}
}
@@ -601,6 +603,7 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern,
} else {
aligned_circles = 1;
r1 = 1.0 / (r1 - r0);
+ r1_2 = c0_c1 = 0.0; /* shut up compiler */
}
cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty);
@@ -700,16 +703,10 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
return NULL;
if (pattern->type == CAIRO_PATTERN_RADIAL)
- _cairo_image_data_set_radial (pattern,
- x - pattern->source_offset.x,
- y - pattern->source_offset.y,
- (int *) data,
+ _cairo_image_data_set_radial (pattern, x, y, (int *) data,
width, height);
else
- _cairo_image_data_set_linear (pattern,
- x - pattern->source_offset.x,
- y - pattern->source_offset.y,
- (int *) data,
+ _cairo_image_data_set_linear (pattern, x, y, (int *) data,
width, height);
_cairo_pattern_set_source_offset (pattern, x, y);
@@ -744,6 +741,9 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
}
break;
+ default:
+ surface = NULL;
+ break;
}
return (cairo_image_surface_t *) surface;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 98d34e44d..b7d911ac5 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -139,6 +139,7 @@ cairo_ps_surface_create (FILE *file,
static cairo_surface_t *
_cairo_ps_surface_create_similar (void *abstract_src,
cairo_format_t format,
+ int drawable,
int width,
int height)
{
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 79eee57b2..e42cd5528 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -54,6 +54,20 @@ cairo_surface_create_for_image (char *data,
slim_hidden_def(cairo_surface_create_for_image);
cairo_surface_t *
+_cairo_surface_create_similar_scratch (cairo_surface_t *other,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ if (other == NULL)
+ return NULL;
+
+ return other->backend->create_similar (other, format, drawable,
+ width, height);
+}
+
+cairo_surface_t *
cairo_surface_create_similar (cairo_surface_t *other,
cairo_format_t format,
int width,
@@ -79,12 +93,14 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_color_t *color)
{
cairo_status_t status;
- cairo_surface_t *surface = NULL;
+ cairo_surface_t *surface;
- surface = other->backend->create_similar (other, format, width, height);
+ surface = _cairo_surface_create_similar_scratch (other, format, 1,
+ width, height);
+
if (surface == NULL)
surface = cairo_image_surface_create (format, width, height);
-
+
status = _cairo_surface_fill_rectangle (surface,
CAIRO_OPERATOR_SRC, color,
0, 0, width, height);
@@ -218,7 +234,7 @@ _cairo_surface_composite (cairo_operator_t operator,
unsigned int height)
{
cairo_int_status_t status;
- cairo_image_surface_t *src_image, *mask_image, *dst_image;
+ cairo_image_surface_t *src_image, *mask_image = 0, *dst_image;
status = dst->backend->composite (operator,
src, mask, dst,
@@ -461,11 +477,9 @@ _cairo_surface_create_pattern (cairo_surface_t *surface,
cairo_surface_set_repeat (pattern->u.surface.surface,
save_repeat);
- if (status == CAIRO_STATUS_SUCCESS) {
- _cairo_pattern_set_source_offset (pattern,
- pattern->source_offset.x + x,
- pattern->source_offset.y + y);
- } else
+ if (status == CAIRO_STATUS_SUCCESS)
+ _cairo_pattern_set_source_offset (pattern, x, y);
+ else
cairo_surface_destroy (pattern->source);
}
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index d17a27281..000e05f4f 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -52,12 +52,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);
@@ -327,40 +321,108 @@ _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)
+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;
}
-*/
+
static cairo_fixed_16_16_t
_compute_x (cairo_line_t *line, cairo_fixed_t y)
{
@@ -371,6 +433,7 @@ _compute_x (cairo_line_t *line, cairo_fixed_t y)
return line->p1.x + (ex / dy);
}
+#if 0
static double
_compute_inverse_slope (cairo_line_t *l)
{
@@ -460,6 +523,7 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_
return 1;
}
+#endif
/* The algorithm here is pretty simple:
diff --git a/src/cairo-wideint.c b/src/cairo-wideint.c
new file mode 100644
index 000000000..67ba3f9b9
--- /dev/null
+++ b/src/cairo-wideint.c
@@ -0,0 +1,986 @@
+/*
+ * $Id: cairo-wideint.c,v 1.1 2004-05-28 19:37:15 keithp Exp $
+ *
+ * Copyright © 2004 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.
+ *
+ * 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.
+ */
+
+#include "cairoint.h"
+
+#if !HAVE_UINT64_T || !HAVE_UINT128_T
+
+static const unsigned char top_bit[256] =
+{
+ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+};
+
+#endif
+
+#if HAVE_UINT64_T
+
+#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
+
+const cairo_uquorem64_t
+_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
+{
+ cairo_uquorem64_t qr;
+
+ qr.quo = num / den;
+ qr.rem = num % den;
+ return qr;
+}
+
+#else
+
+const cairo_uint64_t
+_cairo_uint32_to_uint64 (uint32_t i)
+{
+ cairo_uint64_t q;
+
+ q.lo = i;
+ q.hi = 0;
+ return q;
+}
+
+const cairo_int64_t
+_cairo_int32_to_int64 (int32_t i)
+{
+ cairo_uint64_t q;
+
+ q.lo = i;
+ q.hi = i < 0 ? -1 : 0;
+ return q;
+}
+
+static const cairo_uint64_t
+_cairo_uint32s_to_uint64 (uint32_t h, uint32_t l)
+{
+ cairo_uint64_t q;
+
+ q.lo = l;
+ q.hi = h;
+ return q;
+}
+
+const cairo_uint64_t
+_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
+{
+ cairo_uint64_t s;
+
+ s.hi = a.hi + b.hi;
+ s.lo = a.lo + b.lo;
+ if (s.lo < a.lo)
+ s.hi++;
+ return s;
+}
+
+const cairo_uint64_t
+_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
+{
+ cairo_uint64_t s;
+
+ s.hi = a.hi - b.hi;
+ s.lo = a.lo - b.lo;
+ if (s.lo > a.lo)
+ s.hi--;
+ return s;
+}
+
+#define uint32_lo(i) ((i) & 0xffff)
+#define uint32_hi(i) ((i) >> 16)
+#define uint32_carry16 ((1) << 16)
+
+const cairo_uint64_t
+_cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
+{
+ cairo_uint64_t s;
+
+ uint16_t ah, al, bh, bl;
+ uint32_t r0, r1, r2, r3;
+
+ al = uint32_lo (a);
+ ah = uint32_hi (a);
+ bl = uint32_lo (b);
+ bh = uint32_hi (b);
+
+ r0 = (uint32_t) al * bl;
+ r1 = (uint32_t) al * bh;
+ r2 = (uint32_t) ah * bl;
+ r3 = (uint32_t) ah * bh;
+
+ r1 += uint32_hi(r0); /* no carry possible */
+ r1 += r2; /* but this can carry */
+ if (r1 < r2) /* check */
+ r3 += uint32_carry16;
+
+ s.hi = r3 + uint32_hi(r1);
+ s.lo = (uint32_lo (r1) << 16) + uint32_lo (r0);
+ return s;
+}
+
+const cairo_uint64_t
+_cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b)
+{
+ cairo_uint64_t s;
+
+ s = _cairo_uint32x32_64_mul (a.lo, b.lo);
+ s.hi += a.lo * b.hi + a.hi * b.lo;
+ return s;
+}
+
+const cairo_uint64_t
+_cairo_uint64_lsl (cairo_uint64_t a, int shift)
+{
+ if (shift >= 32)
+ {
+ a.hi = a.lo;
+ a.lo = 0;
+ shift -= 32;
+ }
+ if (shift)
+ {
+ a.hi = a.hi << shift | a.lo >> (32 - shift);
+ a.lo = a.lo << shift;
+ }
+ return a;
+}
+
+const cairo_uint64_t
+_cairo_uint64_rsl (cairo_uint64_t a, int shift)
+{
+ if (shift >= 32)
+ {
+ a.lo = a.hi;
+ a.hi = 0;
+ shift -= 32;
+ }
+ if (shift)
+ {
+ a.lo = a.lo >> shift | a.hi << (32 - shift);
+ a.hi = a.hi >> shift;
+ }
+ return a;
+}
+
+#define _cairo_uint32_rsa(a,n) ((uint32_t) (((int32_t) (a)) >> (n)))
+
+const cairo_int64_t
+_cairo_uint64_rsa (cairo_int64_t a, int shift)
+{
+ if (shift >= 32)
+ {
+ a.lo = a.hi;
+ a.hi = _cairo_uint32_rsa (a.hi, 31);
+ shift -= 32;
+ }
+ if (shift)
+ {
+ a.lo = a.lo >> shift | a.hi << (32 - shift);
+ a.hi = _cairo_uint32_rsa (a.hi, shift);
+ }
+ return a;
+}
+
+const int
+_cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b)
+{
+ return (a.hi < b.hi ||
+ (a.hi == b.hi && a.lo < b.lo));
+}
+
+const int
+_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b)
+{
+ return a.hi == b.hi && a.lo == b.lo;
+}
+
+const int
+_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
+{
+ if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
+ return 1;
+ if (!_cairo_int64_negative (a) && _cairo_int64_negative (b))
+ return 0;
+ return _cairo_uint64_lt (a, b);
+}
+
+const cairo_uint64_t
+_cairo_uint64_not (cairo_uint64_t a)
+{
+ a.lo = ~a.lo;
+ a.hi = ~a.hi;
+ return a;
+}
+
+const cairo_uint64_t
+_cairo_uint64_negate (cairo_uint64_t a)
+{
+ a.lo = ~a.lo;
+ a.hi = ~a.hi;
+ if (++a.lo == 0)
+ ++a.hi;
+ return a;
+}
+
+/*
+ * The design of this algorithm comes from GCC,
+ * but the actual implementation is new
+ */
+
+static const int
+_cairo_leading_zeros32 (uint32_t i)
+{
+ int top;
+
+ if (i < 0x100)
+ top = 0;
+ else if (i < 0x10000)
+ top = 8;
+ else if (i < 0x1000000)
+ top = 16;
+ else
+ top = 24;
+ top = top + top_bit [i >> top];
+ return 32 - top;
+}
+
+typedef struct _cairo_uquorem32_t {
+ uint32_t quo;
+ uint32_t rem;
+} cairo_uquorem32_t;
+
+/*
+ * den >= num.hi
+ */
+static const cairo_uquorem32_t
+_cairo_uint64x32_normalized_divrem (cairo_uint64_t num, uint32_t den)
+{
+ cairo_uquorem32_t qr;
+ uint32_t q0, q1, r0, r1;
+ uint16_t d0, d1;
+ uint32_t t;
+
+ d0 = den & 0xffff;
+ d1 = den >> 16;
+
+ q1 = num.hi / d1;
+ r1 = num.hi % d1;
+
+ t = q1 * d0;
+ r1 = (r1 << 16) | (num.lo >> 16);
+ if (r1 < t)
+ {
+ q1--;
+ r1 += den;
+ if (r1 >= den && r1 < t)
+ {
+ q1--;
+ r1 += den;
+ }
+ }
+
+ r1 -= t;
+
+ q0 = r1 / d1;
+ r0 = r1 % d1;
+ t = q0 * d0;
+ r0 = (r0 << 16) | (num.lo & 0xffff);
+ if (r0 < t)
+ {
+ q0--;
+ r0 += den;
+ if (r0 >= den && r0 < t)
+ {
+ q0--;
+ r0 += den;
+ }
+ }
+ r0 -= t;
+ qr.quo = (q1 << 16) | q0;
+ qr.rem = r0;
+ return qr;
+}
+
+const cairo_uquorem64_t
+_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
+{
+ cairo_uquorem32_t qr32;
+ cairo_uquorem64_t qr;
+ int norm;
+ uint32_t q1, q0, r1, r0;
+
+ if (den.hi == 0)
+ {
+ if (den.lo > num.hi)
+ {
+ /* 0q = nn / 0d */
+
+ norm = _cairo_leading_zeros32 (den.lo);
+ if (norm)
+ {
+ den.lo <<= norm;
+ num = _cairo_uint64_lsl (num, norm);
+ }
+ q1 = 0;
+ }
+ else
+ {
+ /* qq = NN / 0d */
+
+ if (den.lo == 0)
+ den.lo = 1 / den.lo;
+
+ norm = _cairo_leading_zeros32 (den.lo);
+ if (norm)
+ {
+ cairo_uint64_t num1;
+ den.lo <<= norm;
+ num1 = _cairo_uint64_rsl (num, 32 - norm);
+ qr32 = _cairo_uint64x32_normalized_divrem (num1, den.lo);
+ q1 = qr32.quo;
+ num.hi = qr32.rem;
+ num.lo <<= norm;
+ }
+ else
+ {
+ num.hi -= den.lo;
+ q1 = 1;
+ }
+ }
+ qr32 = _cairo_uint64x32_normalized_divrem (num, den.lo);
+ q0 = qr32.quo;
+ r1 = 0;
+ r0 = qr32.rem >> norm;
+ }
+ else
+ {
+ if (den.hi > num.hi)
+ {
+ /* 00 = nn / DD */
+ q0 = q1 = 0;
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ else
+ {
+ /* 0q = NN / dd */
+
+ norm = _cairo_leading_zeros32 (den.hi);
+ if (norm == 0)
+ {
+ if (num.hi > den.hi || num.lo >= den.lo)
+ {
+ q0 = 1;
+ num = _cairo_uint64_sub (num, den);
+ }
+ else
+ q0 = 0;
+
+ q1 = 0;
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ else
+ {
+ cairo_uint64_t num1;
+ cairo_uint64_t part;
+
+ num1 = _cairo_uint64_rsl (num, 32 - norm);
+ den = _cairo_uint64_lsl (den, norm);
+
+ qr32 = _cairo_uint64x32_normalized_divrem (num1, den.hi);
+ part = _cairo_uint32x32_64_mul (qr32.quo, den.lo);
+
+ q0 = qr32.quo;
+
+ num.lo <<= norm;
+ num.hi = qr32.rem;
+
+ if (_cairo_uint64_gt (part, num))
+ {
+ q0--;
+ part = _cairo_uint64_sub (part, den);
+ }
+
+ q1 = 0;
+
+ num = _cairo_uint64_sub (num, part);
+ num = _cairo_uint64_rsl (num, norm);
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ }
+ }
+ qr.quo.lo = q0;
+ qr.quo.hi = q1;
+ qr.rem.lo = r0;
+ qr.rem.hi = r1;
+ return qr;
+}
+
+#endif /* !HAVE_UINT64_T */
+
+const cairo_quorem64_t
+_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
+{
+ int num_neg = _cairo_int64_negative (num);
+ int den_neg = _cairo_int64_negative (den);
+ cairo_uquorem64_t uqr;
+ cairo_quorem64_t qr;
+
+ if (num_neg)
+ num = _cairo_int64_negate (num);
+ if (den_neg)
+ den = _cairo_int64_negate (den);
+ uqr = _cairo_uint64_divrem (num, den);
+ if (num_neg)
+ qr.rem = _cairo_int64_negate (uqr.rem);
+ else
+ qr.rem = uqr.rem;
+ if (num_neg != den_neg)
+ qr.quo = (cairo_int64_t) _cairo_int64_negate (uqr.quo);
+ else
+ qr.quo = (cairo_int64_t) uqr.quo;
+ return qr;
+}
+
+#if HAVE_UINT128_T
+
+const cairo_uquorem128_t
+_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
+{
+ cairo_uquorem128_t qr;
+
+ qr.quo = num / den;
+ qr.rem = num % den;
+ return qr;
+}
+
+#else
+
+const cairo_uint128_t
+_cairo_uint32_to_uint128 (uint32_t i)
+{
+ cairo_uint128_t q;
+
+ q.lo = _cairo_uint32_to_uint64 (i);
+ q.hi = _cairo_uint32_to_uint64 (0);
+ return q;
+}
+
+const cairo_int128_t
+_cairo_int32_to_int128 (int32_t i)
+{
+ cairo_int128_t q;
+
+ q.lo = _cairo_int32_to_int64 (i);
+ q.hi = _cairo_int32_to_int64 (i < 0 ? -1 : 0);
+ return q;
+}
+
+const cairo_uint128_t
+_cairo_uint64_to_uint128 (cairo_uint64_t i)
+{
+ cairo_uint128_t q;
+
+ q.lo = i;
+ q.hi = _cairo_uint32_to_uint64 (0);
+ return q;
+}
+
+const cairo_int128_t
+_cairo_int64_to_int128 (cairo_int64_t i)
+{
+ cairo_int128_t q;
+
+ q.lo = i;
+ q.hi = _cairo_int32_to_int64 (_cairo_int64_negative(i) ? -1 : 0);
+ return q;
+}
+
+const cairo_uint128_t
+_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
+{
+ cairo_uint128_t s;
+
+ s.hi = _cairo_uint64_add (a.hi, b.hi);
+ s.lo = _cairo_uint64_add (a.lo, b.lo);
+ if (_cairo_uint64_lt (s.lo, a.lo))
+ s.hi = _cairo_uint64_add (s.hi, _cairo_uint32_to_uint64 (1));
+ return s;
+}
+
+const cairo_uint128_t
+_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b)
+{
+ cairo_uint128_t s;
+
+ s.hi = _cairo_uint64_sub (a.hi, b.hi);
+ s.lo = _cairo_uint64_sub (a.lo, b.lo);
+ if (_cairo_uint64_gt (s.lo, a.lo))
+ s.hi = _cairo_uint64_sub (s.hi, _cairo_uint32_to_uint64(1));
+ return s;
+}
+
+#if HAVE_UINT64_T
+
+#define uint64_lo32(i) ((i) & 0xffffffff)
+#define uint64_hi32(i) ((i) >> 32)
+#define uint64_lo(i) ((i) & 0xffffffff)
+#define uint64_hi(i) ((i) >> 32)
+#define uint64_shift32(i) ((i) << 32)
+#define uint64_carry32 (((uint64_t) 1) << 32)
+
+#else
+
+#define uint64_lo32(i) ((i).lo)
+#define uint64_hi32(i) ((i).hi)
+
+static const cairo_uint64_t
+uint64_lo (cairo_uint64_t i)
+{
+ cairo_uint64_t s;
+
+ s.lo = i.lo;
+ s.hi = 0;
+ return s;
+}
+
+static const cairo_uint64_t
+uint64_hi (cairo_uint64_t i)
+{
+ cairo_uint64_t s;
+
+ s.lo = i.hi;
+ s.hi = 0;
+ return s;
+}
+
+static const cairo_uint64_t
+uint64_shift32 (cairo_uint64_t i)
+{
+ cairo_uint64_t s;
+
+ s.lo = 0;
+ s.hi = i.lo;
+ return s;
+}
+
+static const cairo_uint64_t uint64_carry32 = { 0, 1 };
+
+#endif
+
+const cairo_uint128_t
+_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
+{
+ cairo_uint128_t s;
+ uint32_t ah, al, bh, bl;
+ cairo_uint64_t r0, r1, r2, r3;
+
+ al = uint64_lo32 (a);
+ ah = uint64_hi32 (a);
+ bl = uint64_lo32 (b);
+ bh = uint64_hi32 (b);
+
+ r0 = _cairo_uint32x32_64_mul (al, bl);
+ r1 = _cairo_uint32x32_64_mul (al, bh);
+ r2 = _cairo_uint32x32_64_mul (ah, bl);
+ r3 = _cairo_uint32x32_64_mul (ah, bh);
+
+ r1 = _cairo_uint64_add (r1, uint64_hi (r0)); /* no carry possible */
+ r1 = _cairo_uint64_add (r1, r2); /* but this can carry */
+ if (_cairo_uint64_lt (r1, r2)) /* check */
+ r3 = _cairo_uint64_add (r3, uint64_carry32);
+
+ s.hi = _cairo_uint64_add (r3, uint64_hi(r1));
+ s.lo = _cairo_uint64_add (uint64_shift32 (r1),
+ uint64_lo (r0));
+ return s;
+}
+
+const cairo_uint128_t
+_cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b)
+{
+ cairo_uint128_t s;
+
+ s = _cairo_uint64x64_128_mul (a.lo, b.lo);
+ s.hi = _cairo_uint64_add (s.hi,
+ _cairo_uint64_mul (a.lo, b.hi));
+ s.hi = _cairo_uint64_add (s.hi,
+ _cairo_uint64_mul (a.hi, b.lo));
+ return s;
+}
+
+const cairo_uint128_t
+_cairo_uint128_lsl (cairo_uint128_t a, int shift)
+{
+ if (shift >= 64)
+ {
+ a.hi = a.lo;
+ a.lo = _cairo_uint32_to_uint64 (0);
+ shift -= 64;
+ }
+ if (shift)
+ {
+ a.hi = _cairo_uint64_add (_cairo_uint64_lsl (a.hi, shift),
+ _cairo_uint64_rsl (a.lo, (64 - shift)));
+ a.lo = _cairo_uint64_lsl (a.lo, shift);
+ }
+ return a;
+}
+
+const cairo_uint128_t
+_cairo_uint128_rsl (cairo_uint128_t a, int shift)
+{
+ if (shift >= 64)
+ {
+ a.lo = a.hi;
+ a.hi = _cairo_uint32_to_uint64 (0);
+ shift -= 64;
+ }
+ if (shift)
+ {
+ a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
+ _cairo_uint64_lsl (a.hi, (64 - shift)));
+ a.hi = _cairo_uint64_rsl (a.hi, shift);
+ }
+ return a;
+}
+
+const cairo_uint128_t
+_cairo_uint128_rsa (cairo_int128_t a, int shift)
+{
+ if (shift >= 64)
+ {
+ a.lo = a.hi;
+ a.hi = _cairo_uint64_rsa (a.hi, 64-1);
+ shift -= 64;
+ }
+ if (shift)
+ {
+ a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
+ _cairo_uint64_lsl (a.hi, (64 - shift)));
+ a.hi = _cairo_uint64_rsa (a.hi, shift);
+ }
+ return a;
+}
+
+const int
+_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
+{
+ return (_cairo_uint64_lt (a.hi, b.hi) ||
+ (_cairo_uint64_eq (a.hi, b.hi) &&
+ _cairo_uint64_lt (a.lo, b.lo)));
+}
+
+const int
+_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
+{
+ if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
+ return 1;
+ if (!_cairo_int128_negative (a) && _cairo_int128_negative (b))
+ return 0;
+ return _cairo_uint128_lt (a, b);
+}
+
+const int
+_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
+{
+ return (_cairo_uint64_eq (a.hi, b.hi) &&
+ _cairo_uint64_eq (a.lo, b.lo));
+}
+
+/*
+ * The design of this algorithm comes from GCC,
+ * but the actual implementation is new
+ */
+
+/*
+ * den >= num.hi
+ */
+static const cairo_uquorem64_t
+_cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
+{
+ cairo_uquorem64_t qr64;
+ cairo_uquorem64_t qr;
+ uint32_t q0, q1;
+ cairo_uint64_t r0, r1;
+ uint32_t d0, d1;
+ cairo_uint64_t t;
+
+ d0 = uint64_lo32 (den);
+ d1 = uint64_hi32 (den);
+
+ qr64 = _cairo_uint64_divrem (num.hi, _cairo_uint32_to_uint64 (d1));
+ q1 = _cairo_uint64_to_uint32 (qr64.quo);
+ r1 = qr64.rem;
+
+ t = _cairo_uint32x32_64_mul (q1, d0);
+
+ r1 = _cairo_uint64_add (_cairo_uint64_lsl (r1, 32),
+ _cairo_uint64_rsl (num.lo, 32));
+
+ if (_cairo_uint64_lt (r1, t))
+ {
+ q1--;
+ r1 = _cairo_uint64_add (r1, den);
+ if (_cairo_uint64_ge (r1, den) && _cairo_uint64_lt (r1, t))
+ {
+ q1--;
+ r1 = _cairo_uint64_add (r1, den);
+ }
+ }
+
+ r1 = _cairo_uint64_sub (r1, t);
+
+ qr64 = _cairo_uint64_divrem (r1, _cairo_uint32_to_uint64 (d1));
+
+ q0 = _cairo_uint64_to_uint32 (qr64.quo);
+ r0 = qr64.rem;
+
+ t = _cairo_uint32x32_64_mul (q0, d0);
+
+ r0 = _cairo_uint64_add (_cairo_uint64_lsl (r0, 32),
+ _cairo_uint32_to_uint64 (_cairo_uint64_to_uint32 (num.lo)));
+ if (_cairo_uint64_lt (r0, t))
+ {
+ q0--;
+ r0 = _cairo_uint64_add (r0, den);
+ if (_cairo_uint64_ge (r0, den) && _cairo_uint64_lt (r0, t))
+ {
+ q0--;
+ r0 = _cairo_uint64_add (r0, den);
+ }
+ }
+
+ r0 = _cairo_uint64_sub (r0, t);
+
+ qr.quo = _cairo_uint32s_to_uint64 (q1, q0);
+ qr.rem = r0;
+ return qr;
+}
+
+#if HAVE_UINT64_T
+
+static const int
+_cairo_leading_zeros64 (cairo_uint64_t q)
+{
+ int top = 0;
+
+ if (q >= (uint64_t) 0x10000 << 16)
+ {
+ top += 32;
+ q >>= 32;
+ }
+ if (q >= (uint64_t) 0x10000)
+ {
+ top += 16;
+ q >>= 16;
+ }
+ if (q >= (uint64_t) 0x100)
+ {
+ top += 8;
+ q >>= 8;
+ }
+ top += top_bit [q];
+ return 64 - top;
+}
+
+#else
+
+static const int
+_cairo_leading_zeros64 (cairo_uint64_t d)
+{
+ if (d.hi)
+ return _cairo_leading_zeros32 (d.hi);
+ else
+ return 32 + _cairo_leading_zeros32 (d.lo);
+}
+
+#endif
+
+const cairo_uquorem128_t
+_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
+{
+ cairo_uquorem64_t qr64;
+ cairo_uquorem128_t qr;
+ int norm;
+ cairo_uint64_t q1, q0, r1, r0;
+
+ if (_cairo_uint64_eq (den.hi, _cairo_uint32_to_uint64 (0)))
+ {
+ if (_cairo_uint64_gt (den.lo, num.hi))
+ {
+ /* 0q = nn / 0d */
+
+ norm = _cairo_leading_zeros64 (den.lo);
+ if (norm)
+ {
+ den.lo = _cairo_uint64_lsl (den.lo, norm);
+ num = _cairo_uint128_lsl (num, norm);
+ }
+ q1 = _cairo_uint32_to_uint64 (0);
+ }
+ else
+ {
+ /* qq = NN / 0d */
+
+ if (_cairo_uint64_eq (den.lo, _cairo_uint32_to_uint64 (0)))
+ den.lo = _cairo_uint64_divrem (_cairo_uint32_to_uint64 (1),
+ den.lo).quo;
+
+ norm = _cairo_leading_zeros64 (den.lo);
+ if (norm)
+ {
+ cairo_uint128_t num1;
+
+ den.lo = _cairo_uint64_lsl (den.lo, norm);
+ num1 = _cairo_uint128_rsl (num, 64 - norm);
+ qr64 = _cairo_uint128x64_normalized_divrem (num1, den.lo);
+ q1 = qr64.quo;
+ num.hi = qr64.rem;
+ num.lo = _cairo_uint64_lsl (num.lo, norm);
+ }
+ else
+ {
+ num.hi = _cairo_uint64_sub (num.hi, den.lo);
+ q1 = _cairo_uint32_to_uint64 (1);
+ }
+ }
+ qr64 = _cairo_uint128x64_normalized_divrem (num, den.lo);
+ q0 = qr64.quo;
+ r1 = _cairo_uint32_to_uint64 (0);
+ r0 = _cairo_uint64_rsl (qr64.rem, norm);
+ }
+ else
+ {
+ if (_cairo_uint64_gt (den.hi, num.hi))
+ {
+ /* 00 = nn / DD */
+ q0 = q1 = _cairo_uint32_to_uint64 (0);
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ else
+ {
+ /* 0q = NN / dd */
+
+ norm = _cairo_leading_zeros64 (den.hi);
+ if (norm == 0)
+ {
+ if (_cairo_uint64_gt (num.hi, den.hi) ||
+ _cairo_uint64_ge (num.lo, den.lo))
+ {
+ q0 = _cairo_uint32_to_uint64 (1);
+ num = _cairo_uint128_sub (num, den);
+ }
+ else
+ q0 = _cairo_uint32_to_uint64 (0);
+
+ q1 = _cairo_uint32_to_uint64 (0);
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ else
+ {
+ cairo_uint128_t num1;
+ cairo_uint128_t part;
+
+ num1 = _cairo_uint128_rsl (num, 64 - norm);
+ den = _cairo_uint128_lsl (den, norm);
+
+ qr64 = _cairo_uint128x64_normalized_divrem (num1, den.hi);
+ part = _cairo_uint64x64_128_mul (qr64.quo, den.lo);
+
+ q0 = qr64.quo;
+
+ num.lo = _cairo_uint64_lsl (num.lo, norm);
+ num.hi = qr64.rem;
+
+ if (_cairo_uint128_gt (part, num))
+ {
+ q0 = _cairo_uint64_sub (q0, _cairo_uint32_to_uint64 (1));
+ part = _cairo_uint128_sub (part, den);
+ }
+
+ q1 = _cairo_uint32_to_uint64 (0);
+
+ num = _cairo_uint128_sub (num, part);
+ num = _cairo_uint128_rsl (num, norm);
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ }
+ }
+ qr.quo.lo = q0;
+ qr.quo.hi = q1;
+ qr.rem.lo = r0;
+ qr.rem.hi = r1;
+ return qr;
+}
+
+const cairo_int128_t
+_cairo_int128_negate (cairo_int128_t a)
+{
+ a.lo = _cairo_uint64_not (a.lo);
+ a.hi = _cairo_uint64_not (a.hi);
+ return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1));
+}
+
+const cairo_int128_t
+_cairo_int128_not (cairo_int128_t a)
+{
+ a.lo = _cairo_uint64_not (a.lo);
+ a.hi = _cairo_uint64_not (a.hi);
+ return a;
+}
+
+#endif /* !HAVE_UINT128_T */
+
+const cairo_quorem128_t
+_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den)
+{
+ int num_neg = _cairo_int128_negative (num);
+ int den_neg = _cairo_int128_negative (den);
+ cairo_uquorem128_t uqr;
+ cairo_quorem128_t qr;
+
+ if (num_neg)
+ num = _cairo_int128_negate (num);
+ if (den_neg)
+ den = _cairo_int128_negate (den);
+ uqr = _cairo_uint128_divrem (num, den);
+ if (num_neg)
+ qr.rem = _cairo_int128_negate (uqr.rem);
+ else
+ qr.rem = uqr.rem;
+ if (num_neg != den_neg)
+ qr.quo = _cairo_int128_negate (uqr.quo);
+ else
+ qr.quo = uqr.quo;
+ return qr;
+}
diff --git a/src/cairo-wideint.h b/src/cairo-wideint.h
new file mode 100644
index 000000000..d08e039f1
--- /dev/null
+++ b/src/cairo-wideint.h
@@ -0,0 +1,272 @@
+/*
+ * $Id: cairo-wideint.h,v 1.1 2004-05-28 19:37:15 keithp Exp $
+ *
+ * Copyright © 2004 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.
+ *
+ * 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.
+ */
+
+#ifndef CAIRO_WIDEINT_H
+#define CAIRO_WIDEINT_H
+
+#include <stdint.h>
+
+/*
+ * 64-bit datatypes. Two separate implementations, one using
+ * built-in 64-bit signed/unsigned types another implemented
+ * as a pair of 32-bit ints
+ */
+
+#define I __internal_linkage
+
+#if !HAVE_UINT64_T
+
+typedef struct _cairo_uint64 {
+ uint32_t lo, hi;
+} cairo_uint64_t, cairo_int64_t;
+
+const cairo_uint64_t I _cairo_uint32_to_uint64 (uint32_t i);
+#define _cairo_uint64_to_uint32(a) ((a).lo)
+const cairo_uint64_t I _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b);
+const cairo_uint64_t I _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b);
+const cairo_uint64_t I _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b);
+const cairo_uint64_t I _cairo_uint32x32_64_mul (uint32_t a, uint32_t b);
+const cairo_uint64_t I _cairo_uint64_lsl (cairo_uint64_t a, int shift);
+const cairo_uint64_t I _cairo_uint64_rsl (cairo_uint64_t a, int shift);
+const cairo_uint64_t I _cairo_uint64_rsa (cairo_uint64_t a, int shift);
+const int _cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b);
+const int _cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b);
+const cairo_uint64_t I _cairo_uint64_negate (cairo_uint64_t a);
+#define _cairo_uint64_negative(a) (((int32_t) ((a).hi)) < 0)
+const cairo_uint64_t I _cairo_uint64_not (cairo_uint64_t a);
+
+#define _cairo_uint64_to_int64(i) (i)
+#define _cairo_int64_to_uint64(i) (i)
+
+const cairo_int64_t I _cairo_int32_to_int64(int32_t i);
+#define _cairo_int64_to_int32(a) ((int32_t) _cairo_uint64_to_uint32(a))
+#define _cairo_int64_add(a,b) _cairo_uint64_add (a,b)
+#define _cairo_int64_sub(a,b) _cairo_uint64_sub (a,b)
+#define _cairo_int64_mul(a,b) _cairo_uint64_mul (a,b)
+#define _cairo_int32x32_64_mul(a,b) _cairo_uint32x32_64_mul ((uint32_t) (a), (uint32_t) (b)))
+const int _cairo_int64_lt (cairo_uint64_t a, cairo_uint64_t b);
+#define _cairo_int64_eq(a,b) _cairo_uint64_eq (a,b)
+#define _cairo_int64_lsl(a,b) _cairo_uint64_lsl (a,b)
+#define _cairo_int64_rsl(a,b) _cairo_uint64_rsl (a,b)
+#define _cairo_int64_rsa(a,b) _cairo_uint64_rsa (a,b)
+#define _cairo_int64_negate(a) _cairo_uint64_negate(a)
+#define _cairo_int64_negative(a) (((int32_t) ((a).hi)) < 0)
+#define _cairo_int64_not(a) _cairo_uint64_not(a)
+
+#else
+
+typedef uint64_t cairo_uint64_t;
+typedef int64_t cairo_int64_t;
+
+#define _cairo_uint32_to_uint64(i) ((uint64_t) (i))
+#define _cairo_uint64_to_uint32(i) ((uint32_t) (i))
+#define _cairo_uint64_add(a,b) ((a) + (b))
+#define _cairo_uint64_sub(a,b) ((a) - (b))
+#define _cairo_uint64_mul(a,b) ((a) * (b))
+#define _cairo_uint32x32_64_mul(a,b) ((uint64_t) (a) * (b))
+#define _cairo_uint64_lsl(a,b) ((a) << (b))
+#define _cairo_uint64_rsl(a,b) ((uint64_t) (a) >> (b))
+#define _cairo_uint64_rsa(a,b) ((uint64_t) ((int64_t) (a) >> (b)))
+#define _cairo_uint64_lt(a,b) ((a) < (b))
+#define _cairo_uint64_eq(a,b) ((a) == (b))
+#define _cairo_uint64_negate(a) ((uint64_t) -((int64_t) (a)))
+#define _cairo_uint64_negative(a) ((int64_t) (a) < 0)
+#define _cairo_uint64_not(a) (~(a))
+
+#define _cairo_uint64_to_int64(i) ((int64_t) (i))
+#define _cairo_int64_to_uint64(i) ((uint64_t) (i))
+
+#define _cairo_int32_to_int64(i) ((int64_t) (i))
+#define _cairo_int64_to_int32(i) ((int32_t) (i))
+#define _cairo_int64_add(a,b) ((a) + (b))
+#define _cairo_int64_sub(a,b) ((a) - (b))
+#define _cairo_int64_mul(a,b) ((a) * (b))
+#define _cairo_int32x32_64_mul(a,b) ((int64_t) (a) * (b))
+#define _cairo_int64_lt(a,b) ((a) < (b))
+#define _cairo_int64_eq(a,b) ((a) == (b))
+#define _cairo_int64_lsl(a,b) ((a) << (b))
+#define _cairo_int64_rsl(a,b) ((int64_t) ((uint64_t) (a) >> (b)))
+#define _cairo_int64_rsa(a,b) ((int64_t) (a) >> (b))
+#define _cairo_int64_negate(a) (-(a))
+#define _cairo_int64_negative(a) ((a) < 0)
+#define _cairo_int64_not(a) (~(a))
+
+#endif
+
+/*
+ * 64-bit comparisions derived from lt or eq
+ */
+#define _cairo_uint64_le(a,b) (!_cairo_uint64_gt(a,b))
+#define _cairo_uint64_ne(a,b) (!_cairo_uint64_eq(a,b))
+#define _cairo_uint64_ge(a,b) (!_cairo_uint64_lt(a,b))
+#define _cairo_uint64_gt(a,b) _cairo_uint64_lt(b,a)
+
+#define _cairo_int64_le(a,b) (!_cairo_int64_gt(a,b))
+#define _cairo_int64_ne(a,b) (!_cairo_int64_eq(a,b))
+#define _cairo_int64_ge(a,b) (!_cairo_int64_lt(a,b))
+#define _cairo_int64_gt(a,b) _cairo_int64_lt(b,a)
+
+/*
+ * As the C implementation always computes both, create
+ * a function which returns both for the 'native' type as well
+ */
+
+typedef struct _cairo_uquorem64 {
+ cairo_uint64_t quo;
+ cairo_uint64_t rem;
+} cairo_uquorem64_t;
+
+typedef struct _cairo_quorem64 {
+ cairo_int64_t quo;
+ cairo_int64_t rem;
+} cairo_quorem64_t;
+
+const cairo_uquorem64_t I
+_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den);
+
+const cairo_quorem64_t I
+_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den);
+
+/*
+ * 128-bit datatypes. Again, provide two implementations in
+ * case the machine has a native 128-bit datatype. GCC supports int128_t
+ * on ia64
+ */
+
+#if !HAVE_UINT128_T
+
+typedef struct cairo_uint128 {
+ cairo_uint64_t lo, hi;
+} cairo_uint128_t, cairo_int128_t;
+
+const cairo_uint128_t I _cairo_uint32_to_uint128 (uint32_t i);
+const cairo_uint128_t I _cairo_uint64_to_uint128 (cairo_uint64_t i);
+#define _cairo_uint128_to_uint64(a) ((a).lo)
+#define _cairo_uint128_to_uint32(a) _cairo_uint64_to_uint32(_cairo_uint128_to_uint64(a))
+const cairo_uint128_t I _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b);
+const cairo_uint128_t I _cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b);
+const cairo_uint128_t I _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b);
+const cairo_uint128_t I _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b);
+const cairo_uint128_t I _cairo_uint128_lsl (cairo_uint128_t a, int shift);
+const cairo_uint128_t I _cairo_uint128_rsl (cairo_uint128_t a, int shift);
+const cairo_uint128_t I _cairo_uint128_rsa (cairo_uint128_t a, int shift);
+const int _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b);
+const int _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b);
+const cairo_uint128_t I _cairo_uint128_negate (cairo_uint128_t a);
+#define _cairo_uint128_negative(a) (_cairo_uint64_negative(a.hi))
+const cairo_uint128_t I _cairo_uint128_not (cairo_uint128_t a);
+
+#define _cairo_uint128_to_int128_(i) (i)
+#define _cairo_int128_to_uint128(i) (i)
+
+const cairo_int128_t I _cairo_int32_to_int128 (int32_t i);
+const cairo_int128_t I _cairo_int64_to_int128 (cairo_int64_t i);
+#define _cairo_int128_to_int64(a) ((cairo_int64_t) (a).lo);
+#define _cairo_int128_to_int32(a) _cairo_int64_to_int32(_cairo_int128_to_int64(a))
+#define _cairo_int128_add(a,b) _cairo_uint128_add(a,b)
+#define _cairo_int128_sub(a,b) _cairo_uint128_sub(a,b)
+#define _cairo_int128_mul(a,b) _cairo_uint128_mul(a,b)
+#define _cairo_int64x64_128_mul(a,b) _cairo_uint64x64_128_mul ((cairo_uint64_t) (a), (cairo_uint64_t) (b))
+#define _cairo_int128_lsl(a,b) _cairo_uint128_lsl(a,b)
+#define _cairo_int128_rsl(a,b) _cairo_uint128_rsl(a,b)
+#define _cairo_int128_rsa(a,b) _cairo_uint128_rsa(a,b)
+const int _cairo_int128_lt (cairo_int128_t a, cairo_int128_t b);
+#define _cairo_int128_eq(a,b) _cairo_uint128_eq (a,b)
+#define _cairo_int128_negate(a) _cairo_uint128_negate(a)
+#define _cairo_int128_negative(a) (_cairo_uint128_negative(a))
+#define _cairo_int128_not(a) _cairo_uint128_not(a)
+
+#else /* !HAVE_UINT128_T */
+
+typedef uint128_t cairo_uint128_t;
+typedef int128_t cairo_int128_t;
+
+#define _cairo_uint32_to_uint128(i) ((uint128_t) (i))
+#define _cairo_uint64_to_uint128(i) ((uint128_t) (i))
+#define _cairo_uint128_to_uint64(i) ((uint64_t) (i))
+#define _cairo_uint128_to_uint32(i) ((uint32_t) (i))
+#define _cairo_uint128_add(a,b) ((a) + (b))
+#define _cairo_uint128_sub(a,b) ((a) - (b))
+#define _cairo_uint128_mul(a,b) ((a) * (b))
+#define _cairo_uint64x64_128_mul(a,b) ((uint128_t) (a) * (b))
+#define _cairo_uint128_lsl(a,b) ((a) << (b))
+#define _cairo_uint128_rsl(a,b) ((uint128_t) (a) >> (b))
+#define _cairo_uint128_rsa(a,b) ((uint128_t) ((int128_t) (a) >> (b)))
+#define _cairo_uint128_lt(a,b) ((a) < (b))
+#define _cairo_uint128_eq(a,b) ((a) == (b))
+#define _cairo_uint128_negate(a) ((uint128_t) -((int128_t) (a)))
+#define _cairo_uint128_negative(a) ((int128_t) (a) < 0)
+#define _cairo_uint128_not(a) (~(a))
+
+#define _cairo_uint128_to_int128(i) ((int128_t) (i))
+#define _cairo_int128_to_uint128(i) ((uint128_t) (i))
+
+#define _cairo_int32_to_int128(i) ((int128_t) (i))
+#define _cairo_int64_to_int128(i) ((int128_t) (i))
+#define _cairo_int128_to_int64(i) ((int64_t) (i))
+#define _cairo_int128_to_int32(i) ((int32_t) (i))
+#define _cairo_int128_add(a,b) ((a) + (b))
+#define _cairo_int128_sub(a,b) ((a) - (b))
+#define _cairo_int128_mul(a,b) ((a) * (b))
+#define _cairo_int64x64_128_mul(a,b) ((int128_t) (a) * (b))
+#define _cairo_int128_lt(a,b) ((a) < (b))
+#define _cairo_int128_eq(a,b) ((a) == (b))
+#define _cairo_int128_lsl(a,b) ((a) << (b))
+#define _cairo_int128_rsl(a,b) ((int128_t) ((uint128_t) (a) >> (b)))
+#define _cairo_int128_rsa(a,b) ((int128_t) (a) >> (b))
+#define _cairo_int128_negate(a) (-(a))
+#define _cairo_int128_negative(a) ((a) < 0)
+#define _cairo_int128_not(a) (~(a))
+
+#endif /* HAVE_UINT128_T */
+
+typedef struct _cairo_uquorem128 {
+ cairo_uint128_t quo;
+ cairo_uint128_t rem;
+} cairo_uquorem128_t;
+
+typedef struct _cairo_quorem128 {
+ cairo_int128_t quo;
+ cairo_int128_t rem;
+} cairo_quorem128_t;
+
+const cairo_uquorem128_t I
+_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den);
+
+const cairo_quorem128_t I
+_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den);
+
+#define _cairo_uint128_le(a,b) (!_cairo_uint128_gt(a,b))
+#define _cairo_uint128_ne(a,b) (!_cairo_uint128_eq(a,b))
+#define _cairo_uint128_ge(a,b) (!_cairo_uint128_lt(a,b))
+#define _cairo_uint128_gt(a,b) _cairo_uint128_lt(b,a)
+
+#define _cairo_int128_le(a,b) (!_cairo_int128_gt(a,b))
+#define _cairo_int128_ne(a,b) (!_cairo_int128_eq(a,b))
+#define _cairo_int128_ge(a,b) (!_cairo_int128_lt(a,b))
+#define _cairo_int128_gt(a,b) _cairo_int128_lt(b,a)
+
+#undef I
+
+#endif /* CAIRO_WIDEINT_H */
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index ea1f72e16..f34a62594 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -48,9 +48,9 @@ format_from_visual(XCBConnection *c, XCBVISUALID visual)
if(!r)
return nil;
- for(si = XCBRenderQueryPictFormatsScreens(r); si.rem; XCBRenderPICTSCREENNext(&si))
- for(di = XCBRenderPICTSCREENDepths(si.data); di.rem; XCBRenderPICTDEPTHNext(&di))
- for(vi = XCBRenderPICTDEPTHVisuals(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi))
+ for(si = XCBRenderQueryPictFormatsScreensIter(r); si.rem; XCBRenderPICTSCREENNext(&si))
+ for(di = XCBRenderPICTSCREENDepthsIter(si.data); di.rem; XCBRenderPICTDEPTHNext(&di))
+ for(vi = XCBRenderPICTDEPTHVisualsIter(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi))
if(vi.data->visual.id == visual.id)
{
XCBRenderPICTFORMAT ret = vi.data->format;
@@ -123,7 +123,7 @@ format_from_cairo(XCBConnection *c, cairo_format_t fmt)
if(!r)
return ret;
- for(fi = XCBRenderQueryPictFormatsFormats(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
+ for(fi = XCBRenderQueryPictFormatsFormatsIter(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
{
const XCBRenderDIRECTFORMAT *t, *f;
if(fi.data->type != XCBRenderPictTypeDirect)
@@ -231,6 +231,7 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
static cairo_surface_t *
_cairo_xcb_surface_create_similar (void *abstract_src,
cairo_format_t format,
+ int drawable,
int width,
int height)
{
@@ -314,7 +315,7 @@ static int
bytes_per_line(XCBConnection *c, int width, int bpp)
{
int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
- return (bpp * width + bitmap_pad - 1) & -bitmap_pad;
+ return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
}
static cairo_image_surface_t *
@@ -400,7 +401,7 @@ _cairo_xcb_surface_set_image (void *abstract_surface,
_cairo_xcb_surface_ensure_gc (surface);
bpp = bits_per_pixel(surface->dpy, image->depth);
- data_len = bytes_per_line(surface->dpy, surface->width, bpp) * surface->height;
+ data_len = bytes_per_line(surface->dpy, image->width, bpp) * image->height;
XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
image->width,
image->height,
@@ -508,7 +509,7 @@ _cairo_xcb_surface_clone_similar (cairo_surface_t *src,
src_image = _cairo_surface_get_image (src);
clone = (cairo_xcb_surface_t *)
- _cairo_xcb_surface_create_similar (template, format,
+ _cairo_xcb_surface_create_similar (template, format, 0,
src_image->width,
src_image->height);
if (clone == NULL)
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 19dfde503..4f4425940 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -111,6 +111,7 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
static cairo_surface_t *
_cairo_xlib_surface_create_similar (void *abstract_src,
cairo_format_t format,
+ int drawable,
int width,
int height)
{
@@ -382,7 +383,7 @@ _cairo_xlib_surface_clone_similar (cairo_surface_t *src,
src_image = _cairo_surface_get_image (src);
clone = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_similar (template, format,
+ _cairo_xlib_surface_create_similar (template, format, 0,
src_image->width,
src_image->height);
if (clone == NULL)
@@ -455,7 +456,8 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
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;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -475,6 +477,28 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
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,
@@ -484,6 +508,7 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
mask_x, mask_y,
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. */
@@ -577,8 +602,11 @@ static cairo_int_status_t
_cairo_xlib_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
+
Region xregion;
XRectangle xr;
+ XRectangle *rects = NULL;
+ XGCValues gc_values;
pixman_box16_t *box;
cairo_xlib_surface_t *surf;
int n, m;
@@ -593,13 +621,17 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
xr.width = surf->width;
xr.height = surf->height;
XUnionRectWithRegion (&xr, xregion, xregion);
+ rects = malloc(sizeof(XRectangle));
+ rects[0] = xr;
+ m = 1;
+
} else {
n = pixman_region_num_rects (region);
/* XXX: Are we sure these are the semantics we want for an
* empty, (not null) region? */
if (n == 0)
return CAIRO_STATUS_SUCCESS;
-
+ rects = malloc(sizeof(XRectangle) * n);
box = pixman_region_rects (region);
xregion = XCreateRegion();
@@ -609,13 +641,20 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
xr.y = (short) box->y1;
xr.width = (unsigned short) (box->x2 - box->x1);
xr.height = (unsigned short) (box->y2 - box->y1);
+ rects[n-1] = xr;
XUnionRectWithRegion (&xr, xregion, xregion);
}
}
+ _cairo_xlib_surface_ensure_gc (surf);
+ XGetGCValues(surf->dpy, surf->gc, GCGraphicsExposures, &gc_values);
+ XSetGraphicsExposures(surf->dpy, surf->gc, False);
+ XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
+ free(rects);
+ if (surf->picture)
XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
XDestroyRegion(xregion);
-
+ XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
return CAIRO_STATUS_SUCCESS;
}
@@ -654,6 +693,8 @@ cairo_xlib_surface_create (Display *dpy,
{
cairo_xlib_surface_t *surface;
int render_standard;
+ Window w;
+ unsigned int ignore;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@@ -692,6 +733,12 @@ cairo_xlib_surface_create (Display *dpy,
break;
}
+ XGetGeometry(dpy, drawable,
+ &w, &ignore, &ignore,
+ &surface->width,
+ &surface->height,
+ &ignore, &ignore);
+
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
diff --git a/src/cairo.c b/src/cairo.c
index d173ca767..064cc7f2f 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -29,6 +29,34 @@
#define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */
+
+#ifdef CAIRO_DO_SANITY_CHECKING
+#include <assert.h>
+static int
+cairo_sane_state (cairo_t *cr)
+{
+ switch (cr->status) {
+ case CAIRO_STATUS_SUCCESS:
+ case CAIRO_STATUS_NO_MEMORY:
+ case CAIRO_STATUS_INVALID_RESTORE:
+ case CAIRO_STATUS_INVALID_POP_GROUP:
+ case CAIRO_STATUS_NO_CURRENT_POINT:
+ case CAIRO_STATUS_INVALID_MATRIX:
+ case CAIRO_STATUS_NO_TARGET_SURFACE:
+ case CAIRO_STATUS_NULL_POINTER:
+ break;
+ default:
+ printf ("cairo status is bad: %d\n", cr->status);
+ return 0;
+ }
+ return 1;
+}
+#define CAIRO_CHECK_SANITY(cr) assert(cairo_sane_state ((cr)))
+#else
+#define CAIRO_CHECK_SANITY(cr)
+#endif
+
+
cairo_t *
cairo_create (void)
{
@@ -45,21 +73,25 @@ cairo_create (void)
if (cr->gstate == NULL)
cr->status = CAIRO_STATUS_NO_MEMORY;
+ CAIRO_CHECK_SANITY (cr);
return cr;
}
void
cairo_reference (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->ref_count++;
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_destroy (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
cr->ref_count--;
if (cr->ref_count)
return;
@@ -79,6 +111,7 @@ cairo_save (cairo_t *cr)
{
cairo_gstate_t *top;
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -90,11 +123,13 @@ cairo_save (cairo_t *cr)
if (top == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
+ CAIRO_CHECK_SANITY (cr);
return;
}
top->next = cr->gstate;
cr->gstate = top;
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_save);
@@ -103,6 +138,7 @@ cairo_restore (cairo_t *cr)
{
cairo_gstate_t *top;
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -113,12 +149,15 @@ cairo_restore (cairo_t *cr)
if (cr->gstate == NULL)
cr->status = CAIRO_STATUS_INVALID_RESTORE;
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_restore);
void
cairo_copy (cairo_t *dest, cairo_t *src)
{
+ CAIRO_CHECK_SANITY (src);
+ CAIRO_CHECK_SANITY (dest);
if (dest->status)
return;
@@ -128,6 +167,8 @@ cairo_copy (cairo_t *dest, cairo_t *src)
}
dest->status = _cairo_gstate_copy (dest->gstate, src->gstate);
+ CAIRO_CHECK_SANITY (src);
+ CAIRO_CHECK_SANITY (dest);
}
/* XXX: I want to rethink this API
@@ -161,10 +202,12 @@ cairo_pop_group (cairo_t *cr)
void
cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_target_surface (cr->gstate, surface);
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_set_target_surface);
@@ -178,6 +221,7 @@ cairo_set_target_image (cairo_t *cr,
{
cairo_surface_t *surface;
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -186,26 +230,31 @@ cairo_set_target_image (cairo_t *cr,
width, height, stride);
if (surface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
+ CAIRO_CHECK_SANITY (cr);
return;
}
cairo_set_target_surface (cr, surface);
cairo_surface_destroy (surface);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_operator (cairo_t *cr, cairo_operator_t op)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_operator (cr->gstate, op);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -214,228 +263,276 @@ cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue)
_cairo_restrict_value (&blue, 0.0, 1.0);
cr->status = _cairo_gstate_set_rgb_color (cr->gstate, red, green, blue);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_pattern (cairo_t *cr, cairo_pattern_t *pattern)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_pattern (cr->gstate, pattern);
+ CAIRO_CHECK_SANITY (cr);
}
cairo_pattern_t *
cairo_current_pattern (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_pattern (cr->gstate);
}
void
cairo_set_tolerance (cairo_t *cr, double tolerance)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
_cairo_restrict_value (&tolerance, CAIRO_TOLERANCE_MINIMUM, tolerance);
cr->status = _cairo_gstate_set_tolerance (cr->gstate, tolerance);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_alpha (cairo_t *cr, double alpha)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
_cairo_restrict_value (&alpha, 0.0, 1.0);
cr->status = _cairo_gstate_set_alpha (cr->gstate, alpha);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_line_width (cairo_t *cr, double width)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
_cairo_restrict_value (&width, 0.0, width);
cr->status = _cairo_gstate_set_line_width (cr->gstate, width);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_line_cap (cr->gstate, line_cap);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_line_join (cr->gstate, line_join);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_dash (cairo_t *cr, double *dashes, int ndash, double offset)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_dash (cr->gstate, dashes, ndash, offset);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_miter_limit (cairo_t *cr, double limit)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_miter_limit (cr->gstate, limit);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_translate (cairo_t *cr, double tx, double ty)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_translate (cr->gstate, tx, ty);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_scale (cairo_t *cr, double sx, double sy)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_scale (cr->gstate, sx, sy);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_rotate (cairo_t *cr, double angle)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_rotate (cr->gstate, angle);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_concat_matrix (cairo_t *cr,
cairo_matrix_t *matrix)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_concat_matrix (cr->gstate, matrix);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_matrix (cairo_t *cr,
cairo_matrix_t *matrix)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_matrix (cr->gstate, matrix);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_default_matrix (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_default_matrix (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_identity_matrix (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_identity_matrix (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_transform_point (cairo_t *cr, double *x, double *y)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_transform_point (cr->gstate, x, y);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_transform_distance (cairo_t *cr, double *dx, double *dy)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_transform_distance (cr->gstate, dx, dy);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_inverse_transform_point (cairo_t *cr, double *x, double *y)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_inverse_transform_point (cr->gstate, x, y);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_inverse_transform_distance (cr->gstate, dx, dy);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_new_path (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_new_path (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_move_to (cairo_t *cr, double x, double y)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_move_to (cr->gstate, x, y);
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_move_to);
void
cairo_line_to (cairo_t *cr, double x, double y)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_line_to (cr->gstate, x, y);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -444,6 +541,7 @@ cairo_curve_to (cairo_t *cr,
double x2, double y2,
double x3, double y3)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -451,6 +549,7 @@ cairo_curve_to (cairo_t *cr,
x1, y1,
x2, y2,
x3, y3);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -459,6 +558,7 @@ cairo_arc (cairo_t *cr,
double radius,
double angle1, double angle2)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -466,6 +566,7 @@ cairo_arc (cairo_t *cr,
xc, yc,
radius,
angle1, angle2);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -474,6 +575,7 @@ cairo_arc_negative (cairo_t *cr,
double radius,
double angle1, double angle2)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -481,6 +583,7 @@ cairo_arc_negative (cairo_t *cr,
xc, yc,
radius,
angle1, angle2);
+ CAIRO_CHECK_SANITY (cr);
}
/* XXX: NYI
@@ -503,19 +606,23 @@ cairo_arc_to (cairo_t *cr,
void
cairo_rel_move_to (cairo_t *cr, double dx, double dy)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_rel_move_to (cr->gstate, dx, dy);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_rel_line_to (cairo_t *cr, double dx, double dy)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_rel_line_to (cr->gstate, dx, dy);
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_rel_line_to);
@@ -525,6 +632,7 @@ cairo_rel_curve_to (cairo_t *cr,
double dx2, double dy2,
double dx3, double dy3)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -532,6 +640,7 @@ cairo_rel_curve_to (cairo_t *cr,
dx1, dy1,
dx2, dy2,
dx3, dy3);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -539,6 +648,7 @@ cairo_rectangle (cairo_t *cr,
double x, double y,
double width, double height)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -547,6 +657,7 @@ cairo_rectangle (cairo_t *cr,
cairo_rel_line_to (cr, 0, height);
cairo_rel_line_to (cr, -width, 0);
cairo_close_path (cr);
+ CAIRO_CHECK_SANITY (cr);
}
/* XXX: NYI
@@ -563,47 +674,57 @@ cairo_stroke_path (cairo_t *cr)
void
cairo_close_path (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_close_path (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_close_path);
void
cairo_stroke (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_stroke (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_fill (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_fill (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_copy_page (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_copy_page (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_show_page (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_show_page (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
int
@@ -611,11 +732,14 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
{
int inside;
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return 0;
cr->status = _cairo_gstate_in_stroke (cr->gstate, x, y, &inside);
+ CAIRO_CHECK_SANITY (cr);
+
if (cr->status)
return 0;
@@ -627,11 +751,14 @@ cairo_in_fill (cairo_t *cr, double x, double y)
{
int inside;
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return 0;
cr->status = _cairo_gstate_in_fill (cr->gstate, x, y, &inside);
+ CAIRO_CHECK_SANITY (cr);
+
if (cr->status)
return 0;
@@ -642,38 +769,46 @@ void
cairo_stroke_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_stroke_extents (cr->gstate, x1, y1, x2, y2);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_fill_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_fill_extents (cr->gstate, x1, y1, x2, y2);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_init_clip (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_init_clip (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_clip (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_clip (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -682,60 +817,72 @@ cairo_select_font (cairo_t *cr,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_select_font (cr->gstate, family, slant, weight);
+ CAIRO_CHECK_SANITY (cr);
}
cairo_font_t *
cairo_current_font (cairo_t *cr)
{
- cairo_font_t *ret;
+ cairo_font_t *ret;
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return NULL;
cr->status = _cairo_gstate_current_font (cr->gstate, &ret);
+ CAIRO_CHECK_SANITY (cr);
return ret;
}
void
-cairo_current_font_extents (cairo_t *ct,
+cairo_current_font_extents (cairo_t *cr,
cairo_font_extents_t *extents)
{
- if (ct->status)
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
return;
- ct->status = _cairo_gstate_current_font_extents (ct->gstate, extents);
+ cr->status = _cairo_gstate_current_font_extents (cr->gstate, extents);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_font (cairo_t *cr, cairo_font_t *font)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_font (cr->gstate, font);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_scale_font (cairo_t *cr, double scale)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_scale_font (cr->gstate, scale);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_transform_font (cairo_t *cr, cairo_matrix_t *matrix)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_transform_font (cr->gstate, matrix);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -743,10 +890,12 @@ cairo_text_extents (cairo_t *cr,
const unsigned char *utf8,
cairo_text_extents_t *extents)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_text_extents (cr->gstate, utf8, extents);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -755,47 +904,60 @@ cairo_glyph_extents (cairo_t *cr,
int num_glyphs,
cairo_text_extents_t *extents)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs,
extents);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_show_text (cairo_t *cr, const unsigned char *utf8)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
+ if (utf8 == NULL)
+ return;
+
cr->status = _cairo_gstate_show_text (cr->gstate, utf8);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_text_path (cairo_t *cr, const unsigned char *utf8)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_text_path (cr->gstate, utf8);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -804,16 +966,19 @@ cairo_show_surface (cairo_t *cr,
int width,
int height)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_show_surface (cr->gstate,
surface, width, height);
+ CAIRO_CHECK_SANITY (cr);
}
cairo_operator_t
cairo_current_operator (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_operator (cr->gstate);
}
DEPRECATE (cairo_get_operator, cairo_current_operator);
@@ -821,13 +986,16 @@ DEPRECATE (cairo_get_operator, cairo_current_operator);
void
cairo_current_rgb_color (cairo_t *cr, double *red, double *green, double *blue)
{
+ CAIRO_CHECK_SANITY (cr);
_cairo_gstate_current_rgb_color (cr->gstate, red, green, blue);
+ CAIRO_CHECK_SANITY (cr);
}
DEPRECATE (cairo_get_rgb_color, cairo_current_rgb_color);
double
cairo_current_alpha (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_alpha (cr->gstate);
}
DEPRECATE (cairo_get_alpha, cairo_current_alpha);
@@ -835,6 +1003,7 @@ DEPRECATE (cairo_get_alpha, cairo_current_alpha);
double
cairo_current_tolerance (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_tolerance (cr->gstate);
}
DEPRECATE (cairo_get_tolerance, cairo_current_tolerance);
@@ -842,13 +1011,16 @@ DEPRECATE (cairo_get_tolerance, cairo_current_tolerance);
void
cairo_current_point (cairo_t *cr, double *x, double *y)
{
+ CAIRO_CHECK_SANITY (cr);
_cairo_gstate_current_point (cr->gstate, x, y);
+ CAIRO_CHECK_SANITY (cr);
}
DEPRECATE (cairo_get_current_point, cairo_current_point);
cairo_fill_rule_t
cairo_current_fill_rule (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_fill_rule (cr->gstate);
}
DEPRECATE (cairo_get_fill_rule, cairo_current_fill_rule);
@@ -856,6 +1028,7 @@ DEPRECATE (cairo_get_fill_rule, cairo_current_fill_rule);
double
cairo_current_line_width (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_line_width (cr->gstate);
}
DEPRECATE (cairo_get_line_width, cairo_current_line_width);
@@ -863,6 +1036,7 @@ DEPRECATE (cairo_get_line_width, cairo_current_line_width);
cairo_line_cap_t
cairo_current_line_cap (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_line_cap (cr->gstate);
}
DEPRECATE (cairo_get_line_cap, cairo_current_line_cap);
@@ -870,6 +1044,7 @@ DEPRECATE (cairo_get_line_cap, cairo_current_line_cap);
cairo_line_join_t
cairo_current_line_join (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_line_join (cr->gstate);
}
DEPRECATE (cairo_get_line_join, cairo_current_line_join);
@@ -877,6 +1052,7 @@ DEPRECATE (cairo_get_line_join, cairo_current_line_join);
double
cairo_current_miter_limit (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_miter_limit (cr->gstate);
}
DEPRECATE (cairo_get_miter_limit, cairo_current_miter_limit);
@@ -884,13 +1060,16 @@ DEPRECATE (cairo_get_miter_limit, cairo_current_miter_limit);
void
cairo_current_matrix (cairo_t *cr, cairo_matrix_t *matrix)
{
+ CAIRO_CHECK_SANITY (cr);
_cairo_gstate_current_matrix (cr->gstate, matrix);
+ CAIRO_CHECK_SANITY (cr);
}
DEPRECATE (cairo_get_matrix, cairo_current_matrix);
cairo_surface_t *
cairo_current_target_surface (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_target_surface (cr->gstate);
}
DEPRECATE (cairo_get_target_surface, cairo_current_target_surface);
@@ -903,6 +1082,7 @@ cairo_current_path (cairo_t *cr,
cairo_close_path_func_t *close_path,
void *closure)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -912,6 +1092,7 @@ cairo_current_path (cairo_t *cr,
curve_to,
close_path,
closure);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -921,6 +1102,7 @@ cairo_current_path_flat (cairo_t *cr,
cairo_close_path_func_t *close_path,
void *closure)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -930,11 +1112,13 @@ cairo_current_path_flat (cairo_t *cr,
NULL,
close_path,
closure);
+ CAIRO_CHECK_SANITY (cr);
}
cairo_status_t
cairo_status (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return cr->status;
}
DEPRECATE (cairo_get_status, cairo_status);
diff --git a/src/cairo.h b/src/cairo.h
index ab7cca724..eb7490582 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -424,7 +424,7 @@ typedef enum cairo_font_weight {
font object inside the the cairo_t. */
void
-cairo_select_font (cairo_t *ct,
+cairo_select_font (cairo_t *cr,
const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
@@ -436,37 +436,37 @@ void
cairo_transform_font (cairo_t *cr, cairo_matrix_t *matrix);
void
-cairo_show_text (cairo_t *ct, const unsigned char *utf8);
+cairo_show_text (cairo_t *cr, const unsigned char *utf8);
void
-cairo_show_glyphs (cairo_t *ct, cairo_glyph_t *glyphs, int num_glyphs);
+cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs);
cairo_font_t *
-cairo_current_font (cairo_t *ct);
+cairo_current_font (cairo_t *cr);
void
-cairo_current_font_extents (cairo_t *ct,
+cairo_current_font_extents (cairo_t *cr,
cairo_font_extents_t *extents);
void
-cairo_set_font (cairo_t *ct, cairo_font_t *font);
+cairo_set_font (cairo_t *cr, cairo_font_t *font);
void
-cairo_text_extents (cairo_t *ct,
+cairo_text_extents (cairo_t *cr,
const unsigned char *utf8,
cairo_text_extents_t *extents);
void
-cairo_glyph_extents (cairo_t *ct,
+cairo_glyph_extents (cairo_t *cr,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
void
-cairo_text_path (cairo_t *ct, const unsigned char *utf8);
+cairo_text_path (cairo_t *cr, const unsigned char *utf8);
void
-cairo_glyph_path (cairo_t *ct, cairo_glyph_t *glyphs, int num_glyphs);
+cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs);
/* Portable interface to general font features. */
diff --git a/src/cairo_fixed.c b/src/cairo_fixed.c
index 9a7e7bc47..2561a4ad5 100644
--- a/src/cairo_fixed.c
+++ b/src/cairo_fixed.c
@@ -51,3 +51,14 @@ _cairo_fixed_to_double (cairo_fixed_t f)
return ((double) f) / 65536.0;
}
+int
+_cairo_fixed_is_integer (cairo_fixed_t f)
+{
+ return (f & 0xFFFF) == 0;
+}
+
+int
+_cairo_fixed_integer_part (cairo_fixed_t f)
+{
+ return f >> 16;
+}
diff --git a/src/cairo_font.c b/src/cairo_font.c
index 157ebedbe..3044e8877 100644
--- a/src/cairo_font.c
+++ b/src/cairo_font.c
@@ -27,6 +27,15 @@
#include "cairoint.h"
+static cairo_glyph_cache_t *
+_cairo_glyph_cache_create (void);
+
+static void
+_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache);
+
+static void
+_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache);
+
cairo_font_t *
_cairo_font_create (const char *family,
cairo_font_slant_t slant,
@@ -50,6 +59,9 @@ _cairo_font_init (cairo_font_t *font,
cairo_matrix_set_identity (&font->matrix);
font->refcount = 1;
font->backend = backend;
+ font->glyph_cache = _cairo_glyph_cache_create ();
+ if (font->glyph_cache == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
return CAIRO_STATUS_SUCCESS;
}
@@ -72,6 +84,13 @@ _cairo_font_copy (cairo_font_t *font)
newfont->refcount = 1;
cairo_matrix_copy(&newfont->matrix, &font->matrix);
newfont->backend = font->backend;
+
+ if (newfont->glyph_cache)
+ _cairo_glyph_cache_destroy (newfont->glyph_cache);
+
+ newfont->glyph_cache = font->glyph_cache;
+ _cairo_glyph_cache_reference (font->glyph_cache);
+
return newfont;
}
@@ -105,18 +124,40 @@ _cairo_font_glyph_extents (cairo_font_t *font,
return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
}
+cairo_status_t
+_cairo_font_text_bbox (cairo_font_t *font,
+ cairo_surface_t *surface,
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_box_t *bbox)
+{
+ return font->backend->text_bbox (font, surface, x, y, utf8, bbox);
+}
+
+cairo_status_t
+_cairo_font_glyph_bbox (cairo_font_t *font,
+ cairo_surface_t *surface,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
+{
+ return font->backend->glyph_bbox (font, surface, glyphs, num_glyphs, bbox);
+}
cairo_status_t
_cairo_font_show_text (cairo_font_t *font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
+ int source_x,
+ int source_y,
double x,
double y,
const unsigned char *utf8)
{
return font->backend->show_text(font, operator, source,
- surface, x, y, utf8);
+ surface, source_x, source_y, x, y, utf8);
}
cairo_status_t
@@ -124,11 +165,14 @@ _cairo_font_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
+ int source_x,
+ int source_y,
cairo_glyph_t *glyphs,
int num_glyphs)
{
return font->backend->show_glyphs(font, operator, source,
- surface, glyphs, num_glyphs);
+ surface, source_x, source_y,
+ glyphs, num_glyphs);
}
cairo_status_t
@@ -157,6 +201,183 @@ _cairo_font_font_extents (cairo_font_t *font,
return font->backend->font_extents(font, extents);
}
+static void
+_cairo_glyph_cache_pop_last (cairo_glyph_cache_t *glyph_cache)
+{
+ if (glyph_cache->last) {
+ cairo_glyph_surface_node_t *remove = glyph_cache->last;
+
+ cairo_surface_destroy (remove->s.surface);
+ glyph_cache->last = remove->prev;
+ if (glyph_cache->last)
+ glyph_cache->last->next = NULL;
+
+ free (remove);
+ glyph_cache->n_nodes--;
+ }
+}
+
+static cairo_glyph_cache_t *
+_cairo_glyph_cache_create (void)
+{
+ cairo_glyph_cache_t *glyph_cache;
+
+ glyph_cache = malloc (sizeof (cairo_glyph_cache_t));
+ if (glyph_cache == NULL)
+ return NULL;
+
+ glyph_cache->n_nodes = 0;
+ glyph_cache->first = NULL;
+ glyph_cache->last = NULL;
+ glyph_cache->cache_size = CAIRO_FONT_CACHE_SIZE_DEFAULT;
+ glyph_cache->ref_count = 1;
+
+ return glyph_cache;
+}
+
+static void
+_cairo_glyph_cache_reference (cairo_glyph_cache_t *glyph_cache)
+{
+ if (glyph_cache == NULL)
+ return;
+
+ glyph_cache->ref_count++;
+}
+
+static void
+_cairo_glyph_cache_destroy (cairo_glyph_cache_t *glyph_cache)
+{
+ if (glyph_cache == NULL)
+ return;
+
+ glyph_cache->ref_count--;
+ if (glyph_cache->ref_count)
+ return;
+
+ while (glyph_cache->last)
+ _cairo_glyph_cache_pop_last (glyph_cache);
+
+ free (glyph_cache);
+}
+
+static void
+_cairo_glyph_surface_init (cairo_font_t *font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_surface_t *glyph_surface)
+{
+ cairo_surface_t *image;
+
+ glyph_surface->surface = NULL;
+ glyph_surface->index = glyph->index;
+ glyph_surface->matrix[0][0] = font->matrix.m[0][0];
+ glyph_surface->matrix[0][1] = font->matrix.m[0][1];
+ glyph_surface->matrix[1][0] = font->matrix.m[1][0];
+ glyph_surface->matrix[1][1] = font->matrix.m[1][1];
+
+ image = font->backend->create_glyph (font, glyph, &glyph_surface->size);
+ if (image == NULL)
+ return;
+
+ if (surface->backend != image->backend) {
+ cairo_status_t status;
+
+ glyph_surface->surface =
+ _cairo_surface_create_similar_scratch (surface,
+ CAIRO_FORMAT_A8, 0,
+ glyph_surface->size.width,
+ glyph_surface->size.height);
+ if (glyph_surface->surface == NULL) {
+ glyph_surface->surface = image;
+ return;
+ }
+
+ status = _cairo_surface_set_image (glyph_surface->surface,
+ (cairo_image_surface_t *) image);
+ if (status) {
+ cairo_surface_destroy (glyph_surface->surface);
+ glyph_surface->surface = NULL;
+ }
+ cairo_surface_destroy (image);
+ } else
+ glyph_surface->surface = image;
+}
+
+cairo_surface_t *
+_cairo_font_lookup_glyph (cairo_font_t *font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_size_t *return_size)
+{
+ cairo_glyph_surface_t glyph_surface;
+ cairo_glyph_cache_t *cache = font->glyph_cache;
+ cairo_glyph_surface_node_t *node;
+
+ for (node = cache->first; node != NULL; node = node->next) {
+ cairo_glyph_surface_t *s = &node->s;
+
+ if ((s->surface == NULL || s->surface->backend == surface->backend) &&
+ s->index == glyph->index &&
+ s->matrix[0][0] == font->matrix.m[0][0] &&
+ s->matrix[0][1] == font->matrix.m[0][1] &&
+ s->matrix[1][0] == font->matrix.m[1][0] &&
+ s->matrix[1][1] == font->matrix.m[1][1]) {
+
+ /* move node first in cache */
+ if (node->prev) {
+ if (node->next == NULL) {
+ cache->last = node->prev;
+ node->prev->next = NULL;
+ } else {
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ }
+
+ node->prev = NULL;
+ node->next = cache->first;
+ cache->first = node;
+ if (node->next)
+ node->next->prev = node;
+ else
+ cache->last = node;
+ }
+
+ cairo_surface_reference (s->surface);
+ *return_size = s->size;
+
+ return s->surface;
+ }
+ }
+
+ _cairo_glyph_surface_init (font, surface, glyph, &glyph_surface);
+
+ *return_size = glyph_surface.size;
+
+ if (cache->cache_size > 0) {
+ if (cache->n_nodes == cache->cache_size)
+ _cairo_glyph_cache_pop_last (cache);
+
+ node = malloc (sizeof (cairo_glyph_surface_node_t));
+ if (node) {
+ cairo_surface_reference (glyph_surface.surface);
+
+ /* insert node first in cache */
+ node->s = glyph_surface;
+ node->prev = NULL;
+ node->next = cache->first;
+ cache->first = node;
+ if (node->next)
+ node->next->prev = node;
+ else
+ cache->last = node;
+
+ cache->n_nodes++;
+ }
+ }
+
+ return glyph_surface.surface;
+}
+
/* public font interface follows */
void
@@ -171,6 +392,8 @@ cairo_font_destroy (cairo_font_t *font)
if (--(font->refcount) > 0)
return;
+ _cairo_glyph_cache_destroy (font->glyph_cache);
+
if (font->backend->destroy)
font->backend->destroy (font);
}
@@ -188,5 +411,3 @@ cairo_font_current_transform (cairo_font_t *font,
{
cairo_matrix_copy (matrix, &(font->matrix));
}
-
-
diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c
index c1c8d6ea0..5b0a7f641 100644
--- a/src/cairo_ft_font.c
+++ b/src/cairo_ft_font.c
@@ -29,6 +29,7 @@
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
+#include FT_IMAGE_H
typedef struct {
cairo_font_t base;
@@ -464,23 +465,99 @@ _cairo_ft_font_text_extents (void *abstract_font,
}
static cairo_status_t
+_cairo_ft_font_glyph_bbox (void *abstract_font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
+{
+ cairo_ft_font_t *font = abstract_font;
+ 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);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_ft_font_text_bbox (void *abstract_font,
+ cairo_surface_t *surface,
+ double x0,
+ double y0,
+ const unsigned char *utf8,
+ cairo_box_t *bbox)
+{
+ cairo_ft_font_t *font = 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_ft_font_glyph_bbox (font, surface,
+ glyphs, num_glyphs, bbox);
+ free (glyphs);
+ return res;
+ }
+ else
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+static cairo_status_t
_cairo_ft_font_show_glyphs (void *abstract_font,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
cairo_ft_font_t *font = abstract_font;
cairo_status_t status;
- int i;
- cairo_ft_font_t *ft = NULL;
- FT_GlyphSlot glyphslot;
cairo_surface_t *mask = NULL;
- cairo_point_double_t origin;
+ cairo_glyph_size_t size;
double x, y;
- int width, height, stride;
+ int i;
if (font == NULL
|| source == NULL
@@ -488,84 +565,27 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
|| glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY;
- ft = (cairo_ft_font_t *)font;
- glyphslot = ft->face->glyph;
- _install_font_matrix (&font->base.matrix, ft->face);
-
for (i = 0; i < num_glyphs; i++)
{
- unsigned char *bitmap;
-
- FT_Load_Glyph (ft->face, glyphs[i].index, FT_LOAD_DEFAULT);
- FT_Render_Glyph (glyphslot, ft_render_mode_normal);
-
- width = glyphslot->bitmap.width;
- height = glyphslot->bitmap.rows;
- stride = glyphslot->bitmap.pitch;
- bitmap = glyphslot->bitmap.buffer;
+ mask = _cairo_font_lookup_glyph (&font->base, surface,
+ &glyphs[i], &size);
+ if (mask == NULL)
+ continue;
x = glyphs[i].x;
y = glyphs[i].y;
- if (i == 0) {
- origin.x = x;
- origin.y = y;
- }
-
- /* X gets upset with zero-sized images (such as whitespace) */
- if (width * height == 0)
- continue;
-
- /*
- * XXX
- * reformat to match libic alignment requirements.
- * This should be done before rendering the glyph,
- * but that requires using FT_Outline_Get_Bitmap
- * function
- */
- if (stride & 3)
- {
- int nstride = (stride + 3) & ~3;
- unsigned char *g, *b;
- int h;
-
- bitmap = malloc (nstride * height);
- if (!bitmap)
- return CAIRO_STATUS_NO_MEMORY;
- g = glyphslot->bitmap.buffer;
- b = bitmap;
- h = height;
- while (h--)
- {
- memcpy (b, g, width);
- b += nstride;
- g += stride;
- }
- stride = nstride;
- }
- mask = cairo_surface_create_for_image (bitmap,
- CAIRO_FORMAT_A8,
- width, height, stride);
- if (mask == NULL)
- {
- if (bitmap != glyphslot->bitmap.buffer)
- free (bitmap);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- status =
- _cairo_surface_composite (operator, source, mask, surface,
- -origin.x + x + glyphslot->bitmap_left,
- -origin.y + y - glyphslot->bitmap_top,
- 0, 0,
- x + glyphslot->bitmap_left,
- y - glyphslot->bitmap_top,
- (double) width, (double) height);
+ 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 (bitmap != glyphslot->bitmap.buffer)
- free (bitmap);
-
+
if (status)
return status;
}
@@ -577,19 +597,22 @@ _cairo_ft_font_show_text (void *abstract_font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
+ int source_x,
+ int source_y,
double x0,
double y0,
const unsigned char *utf8)
{
cairo_ft_font_t *font = abstract_font;
cairo_glyph_t *glyphs;
- int num_glyphs;
+ size_t num_glyphs;
if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs))
{
cairo_status_t res;
res = _cairo_ft_font_show_glyphs (font, operator,
source, surface,
+ source_x, source_y,
glyphs, num_glyphs);
free (glyphs);
return res;
@@ -768,6 +791,74 @@ cairo_ft_font_create_for_ft_face (FT_Face face)
return (cairo_font_t *) f;
}
+static cairo_surface_t *
+_cairo_ft_font_create_glyph (void *abstract_font,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_size_t *return_size)
+{
+ cairo_ft_font_t *font = abstract_font;
+ cairo_image_surface_t *image;
+ FT_GlyphSlot glyphslot;
+ unsigned int width, height, stride;
+ FT_Outline *outline;
+ 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;
+}
+
const struct cairo_font_backend cairo_ft_font_backend = {
_cairo_ft_font_create,
_cairo_ft_font_copy,
@@ -775,8 +866,11 @@ const struct cairo_font_backend cairo_ft_font_backend = {
_cairo_ft_font_font_extents,
_cairo_ft_font_text_extents,
_cairo_ft_font_glyph_extents,
+ _cairo_ft_font_text_bbox,
+ _cairo_ft_font_glyph_bbox,
_cairo_ft_font_show_text,
_cairo_ft_font_show_glyphs,
_cairo_ft_font_text_path,
_cairo_ft_font_glyph_path,
+ _cairo_ft_font_create_glyph
};
diff --git a/src/cairo_gl_surface.c b/src/cairo_gl_surface.c
index 3a60302bd..b56fc5fc3 100644
--- a/src/cairo_gl_surface.c
+++ b/src/cairo_gl_surface.c
@@ -1,26 +1,25 @@
-/*
- * Copyright © 2002 University of Southern California
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 David Reveman
*
* 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 the
- * University of Southern California not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. The University of Southern
- * California makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express
- * or implied warranty.
+ * appear in supporting documentation, and that the name of David
+ * Reveman not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. David Reveman makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
*
- * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * SOUTHERN CALIFORNIA 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.
+ * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL DAVID REVEMAN 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.
*
* Author: David Reveman <c99drn@cs.umu.se>
*/
@@ -91,17 +90,20 @@ struct cairo_gl_surface {
(surface->features & GLITZ_FEATURE_TEXTURE_MIRRORED_REPEAT_MASK)
#define CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT(surface) \
- ((surface->format->stencil_size >= \
- ((surface->hints & GLITZ_HINT_CLIPPING_MASK)? 2: 1)) || \
- CAIRO_GL_OFFSCREEN_SUPPORT (surface))
+ (surface->format->stencil_size >= \
+ ((surface->hints & GLITZ_HINT_CLIPPING_MASK)? 2: 1))
-#define CAIRO_GL_SURFACE_IS_OFFSCREEN(surface) \
- (surface->hints & GLITZ_HINT_OFFSCREEN_MASK)
+#define CAIRO_GL_SURFACE_IS_DRAWABLE(surface) \
+ ((surface->hints & GLITZ_HINT_OFFSCREEN_MASK)? \
+ surface->format->draw.offscreen: surface->format->draw.onscreen)
#define CAIRO_GL_SURFACE_IS_SOLID(surface) \
((surface->hints & GLITZ_HINT_PROGRAMMATIC_MASK) && \
(surface->pattern.type == CAIRO_PATTERN_SOLID))
+#define CAIRO_GL_SURFACE_MULTISAMPLE(surface) \
+ (surface->hints & GLITZ_HINT_MULTISAMPLE_MASK)
+
static void
_cairo_gl_surface_destroy (void *abstract_surface)
{
@@ -130,6 +132,8 @@ _cairo_gl_surface_get_image (void *abstract_surface)
int width, height;
int rowstride;
cairo_format_masks_t format;
+ glitz_pixel_buffer_t *buffer;
+ glitz_pixel_format_t pf;
if (surface->hints & GLITZ_HINT_PROGRAMMATIC_MASK)
return _cairo_pattern_get_image (&surface->pattern,
@@ -138,23 +142,57 @@ _cairo_gl_surface_get_image (void *abstract_surface)
width = glitz_surface_get_width (surface->surface);
height = glitz_surface_get_height (surface->surface);
- rowstride = (width * (surface->format->bpp / 8) + 3) & -4;
+ if (surface->format->red_size > 0) {
+ format.bpp = 32;
+
+ if (surface->format->alpha_size > 0)
+ format.alpha_mask = 0xff000000;
+ else
+ format.alpha_mask = 0x0;
+
+ format.red_mask = 0xff0000;
+ format.green_mask = 0xff00;
+ format.blue_mask = 0xff;
+ } else {
+ format.bpp = 8;
+ format.blue_mask = format.green_mask = format.red_mask = 0x0;
+ format.alpha_mask = 0xff;
+ }
+
+ rowstride = (((width * format.bpp) / 8) + 3) & -4;
- pixels = (char *) malloc (sizeof (char) * height * rowstride);
+ pf.masks.bpp = format.bpp;
+ pf.masks.alpha_mask = format.alpha_mask;
+ pf.masks.red_mask = format.red_mask;
+ pf.masks.green_mask = format.green_mask;
+ pf.masks.blue_mask = format.blue_mask;
+ pf.xoffset = 0;
+ pf.skip_lines = 0;
+ pf.bytes_per_line = rowstride;
+ pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
- glitz_surface_read_pixels (surface->surface, 0, 0, width, height, pixels);
+ pixels = (char *) malloc (height * rowstride);
+ if (!pixels)
+ return NULL;
- format.bpp = surface->format->bpp;
- format.red_mask = surface->format->red_mask;
- format.green_mask = surface->format->green_mask;
- format.blue_mask = surface->format->blue_mask;
- format.alpha_mask = surface->format->alpha_mask;
+ buffer = glitz_pixel_buffer_create_for_data (pixels, &pf);
+ if (!buffer) {
+ free (pixels);
+ return NULL;
+ }
+
+ glitz_get_pixels (surface->surface,
+ 0, 0,
+ width, height,
+ buffer);
+ glitz_pixel_buffer_destroy (buffer);
+
image = (cairo_image_surface_t *)
_cairo_image_surface_create_with_masks (pixels,
&format,
width, height, rowstride);
-
+
_cairo_image_surface_assume_ownership_of_data (image);
_cairo_image_surface_set_repeat (image, surface->base.repeat);
@@ -168,10 +206,42 @@ _cairo_gl_surface_set_image (void *abstract_surface,
cairo_image_surface_t *image)
{
cairo_gl_surface_t *surface = abstract_surface;
+ glitz_pixel_buffer_t *buffer;
+ glitz_pixel_format_t pf;
+
+ if (image->depth > 8) {
+ pf.masks.bpp = 32;
+
+ if (surface->format->alpha_size)
+ pf.masks.alpha_mask = 0xff000000;
+ else
+ pf.masks.alpha_mask = 0x0;
+
+ pf.masks.red_mask = 0xff0000;
+ pf.masks.green_mask = 0xff00;
+ pf.masks.blue_mask = 0xff;
+ } else {
+ pf.masks.bpp = 8;
+ pf.masks.alpha_mask = 0xff;
+ pf.masks.red_mask = pf.masks.green_mask = pf.masks.blue_mask = 0x0;
+ }
+
+ pf.xoffset = 0;
+ pf.skip_lines = 0;
+ pf.bytes_per_line = (((image->width * pf.masks.bpp) / 8) + 3) & -4;
+ pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
+
+ buffer = glitz_pixel_buffer_create_for_data (image->data, &pf);
+ if (!buffer)
+ return CAIRO_STATUS_NO_MEMORY;
- glitz_surface_draw_pixels (surface->surface, 0, 0,
- image->width, image->height, image->data);
+ glitz_put_pixels (surface->surface,
+ 0, 0,
+ image->width, image->height,
+ buffer);
+ glitz_pixel_buffer_destroy (buffer);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -204,16 +274,8 @@ _cairo_gl_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
static cairo_status_t
_cairo_gl_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
{
- static glitz_convolution_t gaussian = {
- {
- {0, 1 << 16, 0},
- {1 << 16, 4 << 16, 1 << 16},
- {0, 1 << 16, 0}
- }
- };
cairo_gl_surface_t *surface = abstract_surface;
glitz_filter_t gl_filter;
- glitz_convolution_t *convolution = NULL;
if (!surface->surface)
return CAIRO_STATUS_SUCCESS;
@@ -231,10 +293,6 @@ _cairo_gl_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
case CAIRO_FILTER_NEAREST:
gl_filter = GLITZ_FILTER_NEAREST;
break;
- case CAIRO_FILTER_GAUSSIAN:
- if (CAIRO_GL_CONVOLUTION_SUPPORT (surface))
- convolution = &gaussian;
- /* fall-through */
case CAIRO_FILTER_BILINEAR:
gl_filter = GLITZ_FILTER_BILINEAR;
break;
@@ -243,7 +301,6 @@ _cairo_gl_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
}
glitz_surface_set_filter (surface->surface, gl_filter);
- glitz_surface_set_convolution (surface->surface, convolution);
return CAIRO_STATUS_SUCCESS;
}
@@ -321,15 +378,42 @@ _glitz_format (cairo_format_t format)
static cairo_surface_t *
_cairo_gl_surface_create_similar (void *abstract_src,
cairo_format_t format,
+ int drawable,
int width,
int height)
{
cairo_gl_surface_t *src = abstract_src;
glitz_surface_t *surface;
cairo_surface_t *crsurface;
+ glitz_format_t *glitz_format;
+ unsigned long option_mask;
+ glitz_format_name_t format_name = _glitz_format (format);
+
+ option_mask = GLITZ_FORMAT_OPTION_OFFSCREEN_MASK;
+
+ if (drawable)
+ option_mask |= GLITZ_FORMAT_OPTION_READDRAW_MASK;
+ else
+ option_mask |= GLITZ_FORMAT_OPTION_READONLY_MASK;
- surface = glitz_surface_create_similar (src->surface,
- _glitz_format (format),
+ if (src->format->multisample.samples < 2)
+ option_mask |= GLITZ_FORMAT_OPTION_NO_MULTISAMPLE_MASK;
+
+ glitz_format =
+ glitz_surface_find_similar_standard_format (src->surface, option_mask,
+ format_name);
+ if (glitz_format == NULL) {
+ option_mask &= ~GLITZ_FORMAT_OPTION_READDRAW_MASK;
+ glitz_format =
+ glitz_surface_find_similar_standard_format (src->surface,
+ option_mask,
+ format_name);
+ }
+
+ if (glitz_format == NULL)
+ return NULL;
+
+ surface = glitz_surface_create_similar (src->surface, glitz_format,
width, height);
if (surface == NULL)
return NULL;
@@ -352,7 +436,7 @@ _cairo_gl_surface_clone_similar (cairo_surface_t *src,
src_image = _cairo_surface_get_image (src);
clone = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_similar (template, format,
+ _cairo_gl_surface_create_similar (template, format, 0,
src_image->width,
src_image->height);
if (clone == NULL)
@@ -393,10 +477,8 @@ _cairo_gl_surface_composite (cairo_operator_t operator,
if (glitz_surface_get_status (dst->surface))
return CAIRO_STATUS_NO_TARGET_SURFACE;
- /* If destination surface is offscreen, then offscreen drawing support is
- required. */
- if (CAIRO_GL_SURFACE_IS_OFFSCREEN (dst) &&
- (!CAIRO_GL_OFFSCREEN_SUPPORT (dst)))
+ /* Make sure target surface is drawable */
+ if (!CAIRO_GL_SURFACE_IS_DRAWABLE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
/* We need multi-texturing or offscreen drawing when compositing with
@@ -456,10 +538,8 @@ _cairo_gl_surface_fill_rectangles (void *abstract_surface,
if (glitz_surface_get_status (surface->surface))
return CAIRO_STATUS_NO_TARGET_SURFACE;
- /* If destination surface is offscreen, then offscreen drawing support is
- required. */
- if (CAIRO_GL_SURFACE_IS_OFFSCREEN (surface) &&
- (!CAIRO_GL_OFFSCREEN_SUPPORT (surface)))
+ /* Make sure target surface is drawable */
+ if (!CAIRO_GL_SURFACE_IS_DRAWABLE (surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
glitz_color.red = color->red_short;
@@ -498,6 +578,34 @@ _cairo_gl_surface_fill_trapezoids (cairo_gl_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
+static int
+_cairo_gl_extract_rectangle (cairo_trapezoid_t *trap,
+ cairo_rectangle_t *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 &&
+ _cairo_fixed_is_integer (trap->left.p1.x) &&
+ _cairo_fixed_is_integer (trap->left.p1.y) &&
+ _cairo_fixed_is_integer (trap->left.p2.x) &&
+ _cairo_fixed_is_integer (trap->left.p2.y) &&
+ _cairo_fixed_is_integer (trap->right.p1.x) &&
+ _cairo_fixed_is_integer (trap->right.p1.y) &&
+ _cairo_fixed_is_integer (trap->right.p2.x) &&
+ _cairo_fixed_is_integer (trap->right.p2.y)) {
+
+ rect->x = _cairo_fixed_integer_part (trap->left.p1.x);
+ rect->y = _cairo_fixed_integer_part (trap->left.p1.y);
+ rect->width = _cairo_fixed_integer_part (trap->right.p1.x) - rect->x;
+ rect->height = _cairo_fixed_integer_part (trap->left.p2.y) - rect->y;
+
+ return 1;
+ }
+
+ return 0;
+}
+
static cairo_int_status_t
_cairo_gl_surface_composite_trapezoids (cairo_operator_t operator,
cairo_surface_t *generic_src,
@@ -515,10 +623,8 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t operator,
if (glitz_surface_get_status (dst->surface))
return CAIRO_STATUS_NO_TARGET_SURFACE;
- /* If destination surface is offscreen, then offscreen drawing support is
- required. */
- if (CAIRO_GL_SURFACE_IS_OFFSCREEN (dst) &&
- (!CAIRO_GL_OFFSCREEN_SUPPORT (dst)))
+ /* Make sure target surface is drawable */
+ if (!CAIRO_GL_SURFACE_IS_DRAWABLE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
/* Need to get current hints as clipping may have changed. */
@@ -527,13 +633,19 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t operator,
/* Solid source? */
if ((generic_src->backend == dst->base.backend) &&
(src->pattern.type == CAIRO_PATTERN_SOLID)) {
+ cairo_rectangle_t rect;
- /* We can use fill trapezoids if only one trapezoid should be drawn or
- if solid color alpha is 1.0. If composite trapezoid support
- is missing we always use fill trapezoids. */
- if ((num_traps == 1) ||
- (src->pattern.color.alpha == 1.0) ||
- (!CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT (dst)))
+ /* Check to see if we can represent these traps as a rectangle. */
+ if (num_traps == 1 && _cairo_gl_extract_rectangle (traps, &rect))
+ return _cairo_gl_surface_fill_rectangles (dst, operator,
+ &src->pattern.color,
+ &rect, 1);
+
+ /* If we're not using software multi-sampling, then we can use
+ fill trapezoids if only one trapezoid should be drawn or if
+ solid color alpha is 1.0. */
+ if ((!CAIRO_GL_SURFACE_MULTISAMPLE (dst)) &&
+ (num_traps == 1 || src->pattern.color.alpha == 1.0))
return _cairo_gl_surface_fill_trapezoids (dst, operator,
&src->pattern.color,
traps, num_traps);
@@ -578,17 +690,6 @@ _cairo_gl_surface_show_page (void *abstract_surface)
}
static void
-_cario_gl_uint_to_power_of_two (unsigned int *value)
-{
- unsigned int x = 1;
-
- while (x < *value)
- x <<= 1;
-
- *value = x;
-}
-
-static void
_cairo_gl_create_color_range (cairo_pattern_t *pattern,
unsigned char *data,
unsigned int size)
@@ -624,10 +725,17 @@ _cairo_gl_surface_create_pattern (void *abstract_surface,
source = glitz_surface_create_solid (&color);
} break;
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- unsigned int color_range_size;
+ case CAIRO_PATTERN_RADIAL:
+ /* glitz doesn't support inner circle yet. */
+ if (pattern->u.radial.center0.x != pattern->u.radial.center1.x ||
+ pattern->u.radial.center0.y != pattern->u.radial.center1.y)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ /* fall-through */
+ case CAIRO_PATTERN_LINEAR: {
+ int color_range_size;
glitz_color_range_t *color_range;
+ int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16);
+ int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16);
if (!CAIRO_GL_FRAGMENT_PROGRAM_SUPPORT (surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -638,34 +746,28 @@ _cairo_gl_surface_create_pattern (void *abstract_surface,
if (pattern->extend == CAIRO_EXTEND_REFLECT &&
(!CAIRO_GL_TEXTURE_MIRRORED_REPEAT_SUPPORT (surface)))
return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (pattern->type == CAIRO_PATTERN_LINEAR) {
- double dx, dy;
-
- dx = pattern->u.linear.point1.x - pattern->u.linear.point0.x;
- dy = pattern->u.linear.point1.y - pattern->u.linear.point0.y;
-
- color_range_size = sqrt (dx * dx + dy * dy);
- } else {
- /* glitz doesn't support inner circle yet. */
- if (pattern->u.radial.center0.x != pattern->u.radial.center1.x ||
- pattern->u.radial.center0.y != pattern->u.radial.center1.y)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- color_range_size = pattern->u.radial.radius1;
- }
-
- if ((!CAIRO_GL_TEXTURE_NPOT_SUPPORT (surface)))
- _cario_gl_uint_to_power_of_two (&color_range_size);
-
- color_range = glitz_color_range_create (color_range_size);
+
+ /* TODO: how do we figure out the color range resolution? transforming
+ the gradient vector with the inverse of the pattern matrix should
+ give us a good hint. */
+ color_range_size = 512;
+
+ /* destination surface size less than color range size, an image
+ gradient is probably more efficient. */
+ if ((width * height) <= color_range_size)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ color_range = glitz_color_range_create (surface->surface,
+ color_range_size);
if (!color_range)
return CAIRO_STATUS_NO_MEMORY;
_cairo_gl_create_color_range (pattern,
glitz_color_range_get_data (color_range),
color_range_size);
-
+
+ glitz_color_range_put_back_data (color_range);
+
switch (pattern->extend) {
case CAIRO_EXTEND_REPEAT:
glitz_color_range_set_extend (color_range, GLITZ_EXTEND_REPEAT);
diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c
index 0ff24c15d..6d89964e8 100644
--- a/src/cairo_gstate.c
+++ b/src/cairo_gstate.c
@@ -78,8 +78,6 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->clip.surface = NULL;
gstate->pattern = _cairo_pattern_create_solid (1.0, 1.0, 1.0);
- gstate->pattern_offset.x = 0.0;
- gstate->pattern_offset.y = 0.0;
gstate->alpha = 1.0;
gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
@@ -400,8 +398,6 @@ _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);
- gstate->pattern_offset.x = 0.0;
- gstate->pattern_offset.y = 0.0;
return CAIRO_STATUS_SUCCESS;
}
@@ -883,25 +879,26 @@ _cairo_gstate_arc_dir (cairo_gstate_t *gstate,
/* Recurse if drawing arc larger than pi */
if (angle_max - angle_min > M_PI) {
+ double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
/* XXX: Something tells me this block could be condensed. */
if (dir == CAIRO_DIRECTION_FORWARD) {
status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_min + M_PI, dir);
+ angle_min, angle_mid, dir);
if (status)
return status;
status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min + M_PI, angle_max, dir);
+ angle_mid, angle_max, dir);
if (status)
return status;
} else {
status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min + M_PI, angle_max, dir);
+ angle_mid, angle_max, dir);
if (status)
return status;
status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_min + M_PI, dir);
+ angle_min, angle_mid, dir);
if (status)
return status;
}
@@ -1268,18 +1265,22 @@ _cairo_gstate_create_pattern (cairo_gstate_t *gstate,
if (pattern->n_stops < 2) {
pattern->type = CAIRO_PATTERN_SOLID;
- if (pattern->n_stops)
- pattern->color = pattern->stops->color;
+ 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);
- _cairo_pattern_set_source_offset (pattern,
- gstate->pattern_offset.x,
- gstate->pattern_offset.y);
-
status = _cairo_surface_create_pattern (gstate->surface, pattern, extents);
if (status) {
_cairo_pattern_fini (pattern);
@@ -1362,6 +1363,7 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
cairo_status_t status;
cairo_pattern_t pattern;
cairo_box_t extents;
+ int x_src, y_src;
if (traps->num_traps == 0)
return CAIRO_STATUS_SUCCESS;
@@ -1404,6 +1406,14 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
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);
@@ -1414,7 +1424,8 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
pattern.source, intermediate,
- 0, 0,
+ x_src,
+ y_src,
traps->traps,
traps->num_traps);
if (status)
@@ -1443,12 +1454,15 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
if (status)
goto BAIL2;
+ if (dst == gstate->clip.surface)
+ xoff = yoff = 0;
+
status = _cairo_surface_composite (operator,
pattern.source, intermediate, dst,
0, 0,
0, 0,
- gstate->clip.x,
- gstate->clip.y,
+ xoff >> 16,
+ yoff >> 16,
gstate->clip.width,
gstate->clip.height);
@@ -1462,14 +1476,12 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
return status;
} else {
- int xoff, yoff;
-
if (traps->traps[0].left.p1.y < traps->traps[0].left.p2.y) {
- xoff = _cairo_fixed_to_double (traps->traps[0].left.p1.x);
- yoff = _cairo_fixed_to_double (traps->traps[0].left.p1.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 {
- xoff = _cairo_fixed_to_double (traps->traps[0].left.p2.x);
- yoff = _cairo_fixed_to_double (traps->traps[0].left.p2.y);
+ 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_copy (&pattern, src);
@@ -1481,8 +1493,8 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
status = _cairo_surface_composite_trapezoids (gstate->operator,
pattern.source, dst,
- xoff - pattern.source_offset.x,
- yoff - pattern.source_offset.y,
+ x_src - pattern.source_offset.x,
+ y_src - pattern.source_offset.y,
traps->traps,
traps->num_traps);
@@ -1640,8 +1652,9 @@ _cairo_gstate_init_clip (cairo_gstate_t *gstate)
gstate->clip.region = NULL;
/* reset the surface's clip to the whole surface */
- _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
+ if (gstate->surface)
+ _cairo_surface_set_clip_region (gstate->surface,
+ gstate->clip.region);
return CAIRO_STATUS_SUCCESS;
}
@@ -1651,9 +1664,6 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
cairo_traps_t *tr,
pixman_box16_t *box)
{
-#define CAIRO_FIXED_IS_INTEGER(x) (((x) & 0xFFFF) == 0)
-#define CAIRO_FIXED_INTEGER_PART(x) ((x) >> 16)
-
double a, b, c, d, tx, ty;
cairo_status_t st;
@@ -1666,25 +1676,22 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
&& tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
&& tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
&& tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.y)) {
-
- box->x1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.x);
- box->x2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].right.p1.x);
- box->y1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.y);
- box->y2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p2.y);
+ && _cairo_fixed_is_integer(tr->traps[0].left.p1.x)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p1.y)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p2.x)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p2.y)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p1.x)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p1.y)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p2.x)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p2.y)) {
+
+ box->x1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.x);
+ box->x2 = (short) _cairo_fixed_integer_part(tr->traps[0].right.p1.x);
+ box->y1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.y);
+ box->y2 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p2.y);
return 1;
}
return 0;
-
-#undef CAIRO_FIXED_IS_INTEGER
-#undef CAIRO_FIXED_INTEGER_PART
}
cairo_status_t
@@ -1751,20 +1758,20 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_color_init (&white_color);
if (gstate->clip.surface == NULL) {
- double x1, y1, x2, y2;
- _cairo_path_bounds (&gstate->path,
- &x1, &y1, &x2, &y2);
- gstate->clip.x = floor (x1);
- gstate->clip.y = floor (y1);
- gstate->clip.width = ceil (x2 - gstate->clip.x);
- gstate->clip.height = ceil (y2 - gstate->clip.y);
- gstate->clip.surface =
- _cairo_surface_create_similar_solid (gstate->surface,
- CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
- &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;
+ gstate->clip.surface =
+ _cairo_surface_create_similar_solid (gstate->surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &white_color);
+ if (gstate->clip.surface == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
@@ -1790,14 +1797,78 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
int width,
int height)
{
+
+ /* We are dealing with 5 coordinate spaces in this function. this makes
+ * it ugly.
+ *
+ * - "Image" space is the space of the surface we're reading pixels from.
+ * it is the surface argument to this function. The surface has a
+ * matrix attached to it which maps "user" space (see below) into
+ * image space.
+ *
+ * - "Device" space is the space of the surface we're ultimately writing
+ * pixels to. It is the current surface of the gstate argument to
+ * this function.
+ *
+ * - "User" space is an arbitrary space defined by the user, defined
+ * implicitly by the gstate's CTM. The CTM maps from user space to
+ * device space. The CTM inverse (which is also kept at all times)
+ * maps from device space to user space.
+ *
+ * - "Clip" space is the space of the surface being used to clip pixels
+ * during compositing. Space-wise, it is a bounding box (offset+size)
+ * within device space. This surface is usually smaller than the device
+ * surface (and possibly the image surface too) and logically occupies
+ * a bounding box around the "clip path", situated somewhere in device
+ * space. The clip path is already painted on the clip surface.
+ *
+ * - "Pattern" space is another arbitrary space defined in the pattern
+ * element of gstate. As pixels are read from image space, they are
+ * combined with pixels being read from pattern space and pixels
+ * already existing in device space. User coordinates are converted
+ * to pattern space, similarly, using a matrix attached to the pattern.
+ * (in fact, there is a 6th space in here, which is the space of the
+ * surface acting as a source for the pattern)
+ *
+ * To composite these spaces, we temporarily change the image surface
+ * so that it can be read and written in device coordinates; in a sense
+ * this makes it "spatially compatible" with the clip and device spaces.
+ *
+ *
+ * There is also some confusion about the interaction between a clip and
+ * a pattern; it is assumed that in this "show surface" operation a pattern
+ * is to be used as an auxiliary alpha mask. this might be wrong, but it's
+ * what we're doing now.
+ *
+ * so, to follow the operations below, remember that in the compositing
+ * model, each operation is always of the form ((src IN mask) OP dst).
+ * that's the basic operation.
+ *
+ * so the compositing we are trying to do here, in general, involves 2
+ * steps, going via a temporary surface:
+ *
+ * - combining clip and pattern pixels together into a mask channel.
+ * this will be ((pattern IN clip) SRC temporary). it ignores the
+ * pixels already in the temporary, overwriting it with the
+ * pattern, clipped to the clip mask.
+ *
+ * - combining temporary and "image" pixels with "device" pixels,
+ * with a user-provided porter/duff operator. this will be
+ * ((image IN temporary) OP device).
+ *
+ * if there is no clip, the degenerate case is just the second step
+ * with pattern standing in for temporary.
+ *
+ */
+
cairo_status_t status;
cairo_matrix_t user_to_image, image_to_user;
cairo_matrix_t image_to_device, device_to_image;
double device_x, device_y;
double device_width, device_height;
cairo_pattern_t pattern;
- cairo_box_t extents;
-
+ cairo_box_t pattern_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);
@@ -1816,31 +1887,84 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
_cairo_pattern_init (&pattern);
if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) ||
- (gstate->alpha != 1.0)) {
+ (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);
- extents.p1.x = _cairo_fixed_from_double (device_x);
- extents.p1.y = _cairo_fixed_from_double (device_y);
- extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
- extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
+ 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);
+ status = _cairo_gstate_create_pattern (gstate, &pattern, &pattern_extents);
if (status)
return status;
}
- /* XXX: The rendered size is sometimes 1 or 2 pixels short from
- what I expect. Need to fix this. */
- status = _cairo_surface_composite (gstate->operator,
- surface, pattern.source, gstate->surface,
- device_x, device_y,
- 0, 0,
- device_x, device_y,
- device_width,
- device_height);
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
- _cairo_pattern_fini (&pattern);
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ /* 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,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ surface,
+ intermediate,
+ gstate->surface,
+ gstate->clip.x, gstate->clip.y,
+ 0, 0,
+ gstate->clip.x, gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+ }
+ else
+ {
+
+ /* XXX: The rendered size is sometimes 1 or 2 pixels short from
+ what I expect. Need to fix this. */
+ status = _cairo_surface_composite (gstate->operator,
+ surface,
+ pattern.source,
+ gstate->surface,
+ device_x, device_y,
+ 0, 0,
+ device_x, device_y,
+ device_width,
+ device_height);
+
+ }
+
+ _cairo_pattern_fini (&pattern);
+
/* restore the matrix originally in the surface */
cairo_surface_set_matrix (surface, &user_to_image);
@@ -1983,8 +2107,7 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate,
double x, y;
cairo_matrix_t saved_font_matrix;
cairo_pattern_t pattern;
- cairo_text_extents_t text_extents;
- cairo_box_t extents;
+ cairo_box_t bbox;
status = _cairo_path_current_point (&gstate->path, &point);
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
@@ -2001,21 +2124,76 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate,
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- status = _cairo_gstate_text_extents (gstate, utf8, &text_extents);
+ status = _cairo_font_text_bbox (gstate->font, gstate->surface,
+ x, y, utf8, &bbox);
if (status)
return status;
- extents.p1.x = _cairo_fixed_from_double (x);
- extents.p1.y = _cairo_fixed_from_double (y);
- extents.p2.x = _cairo_fixed_from_double (x + text_extents.width);
- extents.p2.y = _cairo_fixed_from_double (y + text_extents.height);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
+ status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
if (status)
return status;
- status = _cairo_font_show_text (gstate->font,
- gstate->operator, pattern.source,
- gstate->surface, x, y, utf8);
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
+
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ status = _cairo_font_show_text (gstate->font,
+ CAIRO_OPERATOR_ADD, pattern.source,
+ intermediate,
+ gstate->clip.x - pattern.source_offset.x,
+ gstate->clip.y - pattern.source_offset.y,
+ x - gstate->clip.x,
+ y - gstate->clip.y, utf8);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ gstate->clip.surface,
+ NULL,
+ intermediate,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ pattern.source,
+ intermediate,
+ gstate->surface,
+ 0, 0,
+ 0, 0,
+ gstate->clip.x,
+ gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+
+ }
+ else
+ {
+ status = _cairo_font_show_text (gstate->font,
+ gstate->operator, pattern.source,
+ gstate->surface,
+ -pattern.source_offset.x,
+ -pattern.source_offset.y,
+ x, y, utf8);
+ }
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
@@ -2034,8 +2212,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
int i;
cairo_glyph_t *transformed_glyphs = NULL;
cairo_pattern_t pattern;
- cairo_text_extents_t text_extents;
- cairo_box_t extents;
+ cairo_box_t bbox;
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
if (transformed_glyphs == NULL)
@@ -2053,25 +2230,82 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs,
- &text_extents);
+ status = _cairo_font_glyph_bbox (gstate->font, gstate->surface,
+ transformed_glyphs, num_glyphs, &bbox);
if (status)
return status;
- extents.p1.x = _cairo_fixed_from_double (transformed_glyphs[0].x);
- extents.p1.y = _cairo_fixed_from_double (transformed_glyphs[0].y);
- extents.p2.x = _cairo_fixed_from_double (transformed_glyphs[0].x +
- text_extents.width);
- extents.p2.y = _cairo_fixed_from_double (transformed_glyphs[0].y +
- text_extents.height);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
+ status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
if (status)
return status;
+
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
+
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ /* move the glyphs again, from dev space to clip space */
+ for (i = 0; i < num_glyphs; ++i)
+ {
+ transformed_glyphs[i].x -= gstate->clip.x;
+ transformed_glyphs[i].y -= gstate->clip.y;
+ }
+
+ status = _cairo_font_show_glyphs (gstate->font,
+ CAIRO_OPERATOR_ADD,
+ pattern.source, intermediate,
+ gstate->clip.x - pattern.source_offset.x,
+ gstate->clip.y - pattern.source_offset.y,
+ transformed_glyphs, num_glyphs);
- status = _cairo_font_show_glyphs (gstate->font,
- gstate->operator, pattern.source,
- gstate->surface,
- transformed_glyphs, num_glyphs);
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ gstate->clip.surface,
+ NULL,
+ intermediate,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ pattern.source,
+ intermediate,
+ gstate->surface,
+ 0, 0,
+ 0, 0,
+ gstate->clip.x,
+ gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+
+ }
+ else
+ {
+ status = _cairo_font_show_glyphs (gstate->font,
+ gstate->operator, pattern.source,
+ gstate->surface,
+ -pattern.source_offset.x,
+ -pattern.source_offset.y,
+ transformed_glyphs, num_glyphs);
+ }
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c
index 2b52e5b21..76a3dbaa9 100644
--- a/src/cairo_image_surface.c
+++ b/src/cairo_image_surface.c
@@ -179,6 +179,7 @@ cairo_image_surface_create_for_data (char *data,
static cairo_surface_t *
_cairo_image_surface_create_similar (void *abstract_src,
cairo_format_t format,
+ int drawable,
int width,
int height)
{
diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c
index de89c0fd5..cc5635fff 100644
--- a/src/cairo_matrix.c
+++ b/src/cairo_matrix.c
@@ -405,3 +405,27 @@ _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double
return CAIRO_STATUS_SUCCESS;
}
+
+int
+_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
+ int *itx, int *ity)
+{
+ double a, b, c, d, tx, ty;
+ int ttx, tty;
+ int ok = 0;
+ cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
+ ttx = _cairo_fixed_from_double (tx);
+ tty = _cairo_fixed_from_double (ty);
+ ok = ((a == 1.0)
+ && (b == 0.0)
+ && (c == 0.0)
+ && (d == 1.0)
+ && (_cairo_fixed_is_integer(ttx))
+ && (_cairo_fixed_is_integer(tty)));
+ if (ok) {
+ *itx = _cairo_fixed_integer_part(ttx);
+ *ity = _cairo_fixed_integer_part(tty);
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/cairo_pattern.c b/src/cairo_pattern.c
index b81b1bd01..e10013729 100644
--- a/src/cairo_pattern.c
+++ b/src/cairo_pattern.c
@@ -1,32 +1,35 @@
-/*
- * Copyright © 2002 University of Southern California
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 David Reveman
*
* 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 the
- * University of Southern California not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. The University of Southern
- * California makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express
- * or implied warranty.
+ * appear in supporting documentation, and that the name of David
+ * Reveman not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. David Reveman makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
*
- * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * SOUTHERN CALIFORNIA 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.
+ * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL DAVID REVEMAN 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.
*
* Author: David Reveman <c99drn@cs.umu.se>
*/
#include "cairoint.h"
+#define MULTIPLY_COLORCOMP(c1, c2) \
+ ((unsigned char) \
+ ((((unsigned char) (c1)) * (int) ((unsigned char) (c2))) / 0xff))
+
void
_cairo_pattern_init (cairo_pattern_t *pattern)
{
@@ -247,13 +250,11 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
stop->offset = _cairo_fixed_from_double (offset);
stop->id = pattern->n_stops;
- _cairo_color_init (&stop->color);
- _cairo_color_set_rgb (&stop->color, red, green, blue);
- _cairo_color_set_alpha (&stop->color, alpha);
- stop->color_char[0] = stop->color.red_short / 256;
- stop->color_char[1] = stop->color.green_short / 256;
- stop->color_char[2] = stop->color.blue_short / 256;
- stop->color_char[3] = stop->color.alpha_short / 256;
+
+ stop->color_char[0] = red * 0xff;
+ stop->color_char[1] = green * 0xff;
+ stop->color_char[2] = blue * 0xff;
+ stop->color_char[3] = alpha * 0xff;
/* sort stops in ascending order */
qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t),
@@ -329,16 +330,9 @@ _cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha)
_cairo_color_set_alpha (&pattern->color, alpha);
- for (i = 0; i < pattern->n_stops; i++) {
- cairo_color_stop_t *stop = &pattern->stops[i];
-
- _cairo_color_set_alpha (&stop->color, stop->color.alpha * alpha);
-
- stop->color_char[0] = stop->color.red_short / 256;
- stop->color_char[1] = stop->color.green_short / 256;
- stop->color_char[2] = stop->color.blue_short / 256;
- stop->color_char[3] = stop->color.alpha_short / 256;
- }
+ 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
@@ -510,6 +504,14 @@ _cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
op->shader_function (op->stops[i].color_char,
op->stops[i + 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;
}
}
@@ -601,6 +603,7 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern,
} else {
aligned_circles = 1;
r1 = 1.0 / (r1 - r0);
+ r1_2 = c0_c1 = 0.0; /* shut up compiler */
}
cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty);
@@ -700,16 +703,10 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
return NULL;
if (pattern->type == CAIRO_PATTERN_RADIAL)
- _cairo_image_data_set_radial (pattern,
- x - pattern->source_offset.x,
- y - pattern->source_offset.y,
- (int *) data,
+ _cairo_image_data_set_radial (pattern, x, y, (int *) data,
width, height);
else
- _cairo_image_data_set_linear (pattern,
- x - pattern->source_offset.x,
- y - pattern->source_offset.y,
- (int *) data,
+ _cairo_image_data_set_linear (pattern, x, y, (int *) data,
width, height);
_cairo_pattern_set_source_offset (pattern, x, y);
@@ -744,6 +741,9 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
}
break;
+ default:
+ surface = NULL;
+ break;
}
return (cairo_image_surface_t *) surface;
diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c
index b012514b7..1d1fa63e0 100644
--- a/src/cairo_png_surface.c
+++ b/src/cairo_png_surface.c
@@ -82,6 +82,7 @@ cairo_png_surface_create (FILE *file,
static cairo_surface_t *
_cairo_png_surface_create_similar (void *abstract_src,
cairo_format_t format,
+ int drawable,
int width,
int height)
{
@@ -291,6 +292,9 @@ _cairo_png_surface_copy_page (void *abstract_surface)
depth = 1;
png_color_type = PNG_COLOR_TYPE_GRAY;
break;
+ default:
+ status = CAIRO_STATUS_NULL_POINTER;
+ goto BAIL;
}
png_set_IHDR (png, info,
diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c
index 98d34e44d..b7d911ac5 100644
--- a/src/cairo_ps_surface.c
+++ b/src/cairo_ps_surface.c
@@ -139,6 +139,7 @@ cairo_ps_surface_create (FILE *file,
static cairo_surface_t *
_cairo_ps_surface_create_similar (void *abstract_src,
cairo_format_t format,
+ int drawable,
int width,
int height)
{
diff --git a/src/cairo_surface.c b/src/cairo_surface.c
index 79eee57b2..e42cd5528 100644
--- a/src/cairo_surface.c
+++ b/src/cairo_surface.c
@@ -54,6 +54,20 @@ cairo_surface_create_for_image (char *data,
slim_hidden_def(cairo_surface_create_for_image);
cairo_surface_t *
+_cairo_surface_create_similar_scratch (cairo_surface_t *other,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ if (other == NULL)
+ return NULL;
+
+ return other->backend->create_similar (other, format, drawable,
+ width, height);
+}
+
+cairo_surface_t *
cairo_surface_create_similar (cairo_surface_t *other,
cairo_format_t format,
int width,
@@ -79,12 +93,14 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_color_t *color)
{
cairo_status_t status;
- cairo_surface_t *surface = NULL;
+ cairo_surface_t *surface;
- surface = other->backend->create_similar (other, format, width, height);
+ surface = _cairo_surface_create_similar_scratch (other, format, 1,
+ width, height);
+
if (surface == NULL)
surface = cairo_image_surface_create (format, width, height);
-
+
status = _cairo_surface_fill_rectangle (surface,
CAIRO_OPERATOR_SRC, color,
0, 0, width, height);
@@ -218,7 +234,7 @@ _cairo_surface_composite (cairo_operator_t operator,
unsigned int height)
{
cairo_int_status_t status;
- cairo_image_surface_t *src_image, *mask_image, *dst_image;
+ cairo_image_surface_t *src_image, *mask_image = 0, *dst_image;
status = dst->backend->composite (operator,
src, mask, dst,
@@ -461,11 +477,9 @@ _cairo_surface_create_pattern (cairo_surface_t *surface,
cairo_surface_set_repeat (pattern->u.surface.surface,
save_repeat);
- if (status == CAIRO_STATUS_SUCCESS) {
- _cairo_pattern_set_source_offset (pattern,
- pattern->source_offset.x + x,
- pattern->source_offset.y + y);
- } else
+ if (status == CAIRO_STATUS_SUCCESS)
+ _cairo_pattern_set_source_offset (pattern, x, y);
+ else
cairo_surface_destroy (pattern->source);
}
diff --git a/src/cairo_traps.c b/src/cairo_traps.c
index d17a27281..000e05f4f 100644
--- a/src/cairo_traps.c
+++ b/src/cairo_traps.c
@@ -52,12 +52,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);
@@ -327,40 +321,108 @@ _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)
+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;
}
-*/
+
static cairo_fixed_16_16_t
_compute_x (cairo_line_t *line, cairo_fixed_t y)
{
@@ -371,6 +433,7 @@ _compute_x (cairo_line_t *line, cairo_fixed_t y)
return line->p1.x + (ex / dy);
}
+#if 0
static double
_compute_inverse_slope (cairo_line_t *l)
{
@@ -460,6 +523,7 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_
return 1;
}
+#endif
/* The algorithm here is pretty simple:
diff --git a/src/cairo_wideint.c b/src/cairo_wideint.c
new file mode 100644
index 000000000..45682c1cb
--- /dev/null
+++ b/src/cairo_wideint.c
@@ -0,0 +1,986 @@
+/*
+ * $Id: cairo_wideint.c,v 1.1 2004-05-28 19:37:15 keithp Exp $
+ *
+ * Copyright © 2004 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.
+ *
+ * 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.
+ */
+
+#include "cairoint.h"
+
+#if !HAVE_UINT64_T || !HAVE_UINT128_T
+
+static const unsigned char top_bit[256] =
+{
+ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+};
+
+#endif
+
+#if HAVE_UINT64_T
+
+#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
+
+const cairo_uquorem64_t
+_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
+{
+ cairo_uquorem64_t qr;
+
+ qr.quo = num / den;
+ qr.rem = num % den;
+ return qr;
+}
+
+#else
+
+const cairo_uint64_t
+_cairo_uint32_to_uint64 (uint32_t i)
+{
+ cairo_uint64_t q;
+
+ q.lo = i;
+ q.hi = 0;
+ return q;
+}
+
+const cairo_int64_t
+_cairo_int32_to_int64 (int32_t i)
+{
+ cairo_uint64_t q;
+
+ q.lo = i;
+ q.hi = i < 0 ? -1 : 0;
+ return q;
+}
+
+static const cairo_uint64_t
+_cairo_uint32s_to_uint64 (uint32_t h, uint32_t l)
+{
+ cairo_uint64_t q;
+
+ q.lo = l;
+ q.hi = h;
+ return q;
+}
+
+const cairo_uint64_t
+_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
+{
+ cairo_uint64_t s;
+
+ s.hi = a.hi + b.hi;
+ s.lo = a.lo + b.lo;
+ if (s.lo < a.lo)
+ s.hi++;
+ return s;
+}
+
+const cairo_uint64_t
+_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
+{
+ cairo_uint64_t s;
+
+ s.hi = a.hi - b.hi;
+ s.lo = a.lo - b.lo;
+ if (s.lo > a.lo)
+ s.hi--;
+ return s;
+}
+
+#define uint32_lo(i) ((i) & 0xffff)
+#define uint32_hi(i) ((i) >> 16)
+#define uint32_carry16 ((1) << 16)
+
+const cairo_uint64_t
+_cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
+{
+ cairo_uint64_t s;
+
+ uint16_t ah, al, bh, bl;
+ uint32_t r0, r1, r2, r3;
+
+ al = uint32_lo (a);
+ ah = uint32_hi (a);
+ bl = uint32_lo (b);
+ bh = uint32_hi (b);
+
+ r0 = (uint32_t) al * bl;
+ r1 = (uint32_t) al * bh;
+ r2 = (uint32_t) ah * bl;
+ r3 = (uint32_t) ah * bh;
+
+ r1 += uint32_hi(r0); /* no carry possible */
+ r1 += r2; /* but this can carry */
+ if (r1 < r2) /* check */
+ r3 += uint32_carry16;
+
+ s.hi = r3 + uint32_hi(r1);
+ s.lo = (uint32_lo (r1) << 16) + uint32_lo (r0);
+ return s;
+}
+
+const cairo_uint64_t
+_cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b)
+{
+ cairo_uint64_t s;
+
+ s = _cairo_uint32x32_64_mul (a.lo, b.lo);
+ s.hi += a.lo * b.hi + a.hi * b.lo;
+ return s;
+}
+
+const cairo_uint64_t
+_cairo_uint64_lsl (cairo_uint64_t a, int shift)
+{
+ if (shift >= 32)
+ {
+ a.hi = a.lo;
+ a.lo = 0;
+ shift -= 32;
+ }
+ if (shift)
+ {
+ a.hi = a.hi << shift | a.lo >> (32 - shift);
+ a.lo = a.lo << shift;
+ }
+ return a;
+}
+
+const cairo_uint64_t
+_cairo_uint64_rsl (cairo_uint64_t a, int shift)
+{
+ if (shift >= 32)
+ {
+ a.lo = a.hi;
+ a.hi = 0;
+ shift -= 32;
+ }
+ if (shift)
+ {
+ a.lo = a.lo >> shift | a.hi << (32 - shift);
+ a.hi = a.hi >> shift;
+ }
+ return a;
+}
+
+#define _cairo_uint32_rsa(a,n) ((uint32_t) (((int32_t) (a)) >> (n)))
+
+const cairo_int64_t
+_cairo_uint64_rsa (cairo_int64_t a, int shift)
+{
+ if (shift >= 32)
+ {
+ a.lo = a.hi;
+ a.hi = _cairo_uint32_rsa (a.hi, 31);
+ shift -= 32;
+ }
+ if (shift)
+ {
+ a.lo = a.lo >> shift | a.hi << (32 - shift);
+ a.hi = _cairo_uint32_rsa (a.hi, shift);
+ }
+ return a;
+}
+
+const int
+_cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b)
+{
+ return (a.hi < b.hi ||
+ (a.hi == b.hi && a.lo < b.lo));
+}
+
+const int
+_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b)
+{
+ return a.hi == b.hi && a.lo == b.lo;
+}
+
+const int
+_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
+{
+ if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
+ return 1;
+ if (!_cairo_int64_negative (a) && _cairo_int64_negative (b))
+ return 0;
+ return _cairo_uint64_lt (a, b);
+}
+
+const cairo_uint64_t
+_cairo_uint64_not (cairo_uint64_t a)
+{
+ a.lo = ~a.lo;
+ a.hi = ~a.hi;
+ return a;
+}
+
+const cairo_uint64_t
+_cairo_uint64_negate (cairo_uint64_t a)
+{
+ a.lo = ~a.lo;
+ a.hi = ~a.hi;
+ if (++a.lo == 0)
+ ++a.hi;
+ return a;
+}
+
+/*
+ * The design of this algorithm comes from GCC,
+ * but the actual implementation is new
+ */
+
+static const int
+_cairo_leading_zeros32 (uint32_t i)
+{
+ int top;
+
+ if (i < 0x100)
+ top = 0;
+ else if (i < 0x10000)
+ top = 8;
+ else if (i < 0x1000000)
+ top = 16;
+ else
+ top = 24;
+ top = top + top_bit [i >> top];
+ return 32 - top;
+}
+
+typedef struct _cairo_uquorem32_t {
+ uint32_t quo;
+ uint32_t rem;
+} cairo_uquorem32_t;
+
+/*
+ * den >= num.hi
+ */
+static const cairo_uquorem32_t
+_cairo_uint64x32_normalized_divrem (cairo_uint64_t num, uint32_t den)
+{
+ cairo_uquorem32_t qr;
+ uint32_t q0, q1, r0, r1;
+ uint16_t d0, d1;
+ uint32_t t;
+
+ d0 = den & 0xffff;
+ d1 = den >> 16;
+
+ q1 = num.hi / d1;
+ r1 = num.hi % d1;
+
+ t = q1 * d0;
+ r1 = (r1 << 16) | (num.lo >> 16);
+ if (r1 < t)
+ {
+ q1--;
+ r1 += den;
+ if (r1 >= den && r1 < t)
+ {
+ q1--;
+ r1 += den;
+ }
+ }
+
+ r1 -= t;
+
+ q0 = r1 / d1;
+ r0 = r1 % d1;
+ t = q0 * d0;
+ r0 = (r0 << 16) | (num.lo & 0xffff);
+ if (r0 < t)
+ {
+ q0--;
+ r0 += den;
+ if (r0 >= den && r0 < t)
+ {
+ q0--;
+ r0 += den;
+ }
+ }
+ r0 -= t;
+ qr.quo = (q1 << 16) | q0;
+ qr.rem = r0;
+ return qr;
+}
+
+const cairo_uquorem64_t
+_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
+{
+ cairo_uquorem32_t qr32;
+ cairo_uquorem64_t qr;
+ int norm;
+ uint32_t q1, q0, r1, r0;
+
+ if (den.hi == 0)
+ {
+ if (den.lo > num.hi)
+ {
+ /* 0q = nn / 0d */
+
+ norm = _cairo_leading_zeros32 (den.lo);
+ if (norm)
+ {
+ den.lo <<= norm;
+ num = _cairo_uint64_lsl (num, norm);
+ }
+ q1 = 0;
+ }
+ else
+ {
+ /* qq = NN / 0d */
+
+ if (den.lo == 0)
+ den.lo = 1 / den.lo;
+
+ norm = _cairo_leading_zeros32 (den.lo);
+ if (norm)
+ {
+ cairo_uint64_t num1;
+ den.lo <<= norm;
+ num1 = _cairo_uint64_rsl (num, 32 - norm);
+ qr32 = _cairo_uint64x32_normalized_divrem (num1, den.lo);
+ q1 = qr32.quo;
+ num.hi = qr32.rem;
+ num.lo <<= norm;
+ }
+ else
+ {
+ num.hi -= den.lo;
+ q1 = 1;
+ }
+ }
+ qr32 = _cairo_uint64x32_normalized_divrem (num, den.lo);
+ q0 = qr32.quo;
+ r1 = 0;
+ r0 = qr32.rem >> norm;
+ }
+ else
+ {
+ if (den.hi > num.hi)
+ {
+ /* 00 = nn / DD */
+ q0 = q1 = 0;
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ else
+ {
+ /* 0q = NN / dd */
+
+ norm = _cairo_leading_zeros32 (den.hi);
+ if (norm == 0)
+ {
+ if (num.hi > den.hi || num.lo >= den.lo)
+ {
+ q0 = 1;
+ num = _cairo_uint64_sub (num, den);
+ }
+ else
+ q0 = 0;
+
+ q1 = 0;
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ else
+ {
+ cairo_uint64_t num1;
+ cairo_uint64_t part;
+
+ num1 = _cairo_uint64_rsl (num, 32 - norm);
+ den = _cairo_uint64_lsl (den, norm);
+
+ qr32 = _cairo_uint64x32_normalized_divrem (num1, den.hi);
+ part = _cairo_uint32x32_64_mul (qr32.quo, den.lo);
+
+ q0 = qr32.quo;
+
+ num.lo <<= norm;
+ num.hi = qr32.rem;
+
+ if (_cairo_uint64_gt (part, num))
+ {
+ q0--;
+ part = _cairo_uint64_sub (part, den);
+ }
+
+ q1 = 0;
+
+ num = _cairo_uint64_sub (num, part);
+ num = _cairo_uint64_rsl (num, norm);
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ }
+ }
+ qr.quo.lo = q0;
+ qr.quo.hi = q1;
+ qr.rem.lo = r0;
+ qr.rem.hi = r1;
+ return qr;
+}
+
+#endif /* !HAVE_UINT64_T */
+
+const cairo_quorem64_t
+_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
+{
+ int num_neg = _cairo_int64_negative (num);
+ int den_neg = _cairo_int64_negative (den);
+ cairo_uquorem64_t uqr;
+ cairo_quorem64_t qr;
+
+ if (num_neg)
+ num = _cairo_int64_negate (num);
+ if (den_neg)
+ den = _cairo_int64_negate (den);
+ uqr = _cairo_uint64_divrem (num, den);
+ if (num_neg)
+ qr.rem = _cairo_int64_negate (uqr.rem);
+ else
+ qr.rem = uqr.rem;
+ if (num_neg != den_neg)
+ qr.quo = (cairo_int64_t) _cairo_int64_negate (uqr.quo);
+ else
+ qr.quo = (cairo_int64_t) uqr.quo;
+ return qr;
+}
+
+#if HAVE_UINT128_T
+
+const cairo_uquorem128_t
+_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
+{
+ cairo_uquorem128_t qr;
+
+ qr.quo = num / den;
+ qr.rem = num % den;
+ return qr;
+}
+
+#else
+
+const cairo_uint128_t
+_cairo_uint32_to_uint128 (uint32_t i)
+{
+ cairo_uint128_t q;
+
+ q.lo = _cairo_uint32_to_uint64 (i);
+ q.hi = _cairo_uint32_to_uint64 (0);
+ return q;
+}
+
+const cairo_int128_t
+_cairo_int32_to_int128 (int32_t i)
+{
+ cairo_int128_t q;
+
+ q.lo = _cairo_int32_to_int64 (i);
+ q.hi = _cairo_int32_to_int64 (i < 0 ? -1 : 0);
+ return q;
+}
+
+const cairo_uint128_t
+_cairo_uint64_to_uint128 (cairo_uint64_t i)
+{
+ cairo_uint128_t q;
+
+ q.lo = i;
+ q.hi = _cairo_uint32_to_uint64 (0);
+ return q;
+}
+
+const cairo_int128_t
+_cairo_int64_to_int128 (cairo_int64_t i)
+{
+ cairo_int128_t q;
+
+ q.lo = i;
+ q.hi = _cairo_int32_to_int64 (_cairo_int64_negative(i) ? -1 : 0);
+ return q;
+}
+
+const cairo_uint128_t
+_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
+{
+ cairo_uint128_t s;
+
+ s.hi = _cairo_uint64_add (a.hi, b.hi);
+ s.lo = _cairo_uint64_add (a.lo, b.lo);
+ if (_cairo_uint64_lt (s.lo, a.lo))
+ s.hi = _cairo_uint64_add (s.hi, _cairo_uint32_to_uint64 (1));
+ return s;
+}
+
+const cairo_uint128_t
+_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b)
+{
+ cairo_uint128_t s;
+
+ s.hi = _cairo_uint64_sub (a.hi, b.hi);
+ s.lo = _cairo_uint64_sub (a.lo, b.lo);
+ if (_cairo_uint64_gt (s.lo, a.lo))
+ s.hi = _cairo_uint64_sub (s.hi, _cairo_uint32_to_uint64(1));
+ return s;
+}
+
+#if HAVE_UINT64_T
+
+#define uint64_lo32(i) ((i) & 0xffffffff)
+#define uint64_hi32(i) ((i) >> 32)
+#define uint64_lo(i) ((i) & 0xffffffff)
+#define uint64_hi(i) ((i) >> 32)
+#define uint64_shift32(i) ((i) << 32)
+#define uint64_carry32 (((uint64_t) 1) << 32)
+
+#else
+
+#define uint64_lo32(i) ((i).lo)
+#define uint64_hi32(i) ((i).hi)
+
+static const cairo_uint64_t
+uint64_lo (cairo_uint64_t i)
+{
+ cairo_uint64_t s;
+
+ s.lo = i.lo;
+ s.hi = 0;
+ return s;
+}
+
+static const cairo_uint64_t
+uint64_hi (cairo_uint64_t i)
+{
+ cairo_uint64_t s;
+
+ s.lo = i.hi;
+ s.hi = 0;
+ return s;
+}
+
+static const cairo_uint64_t
+uint64_shift32 (cairo_uint64_t i)
+{
+ cairo_uint64_t s;
+
+ s.lo = 0;
+ s.hi = i.lo;
+ return s;
+}
+
+static const cairo_uint64_t uint64_carry32 = { 0, 1 };
+
+#endif
+
+const cairo_uint128_t
+_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
+{
+ cairo_uint128_t s;
+ uint32_t ah, al, bh, bl;
+ cairo_uint64_t r0, r1, r2, r3;
+
+ al = uint64_lo32 (a);
+ ah = uint64_hi32 (a);
+ bl = uint64_lo32 (b);
+ bh = uint64_hi32 (b);
+
+ r0 = _cairo_uint32x32_64_mul (al, bl);
+ r1 = _cairo_uint32x32_64_mul (al, bh);
+ r2 = _cairo_uint32x32_64_mul (ah, bl);
+ r3 = _cairo_uint32x32_64_mul (ah, bh);
+
+ r1 = _cairo_uint64_add (r1, uint64_hi (r0)); /* no carry possible */
+ r1 = _cairo_uint64_add (r1, r2); /* but this can carry */
+ if (_cairo_uint64_lt (r1, r2)) /* check */
+ r3 = _cairo_uint64_add (r3, uint64_carry32);
+
+ s.hi = _cairo_uint64_add (r3, uint64_hi(r1));
+ s.lo = _cairo_uint64_add (uint64_shift32 (r1),
+ uint64_lo (r0));
+ return s;
+}
+
+const cairo_uint128_t
+_cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b)
+{
+ cairo_uint128_t s;
+
+ s = _cairo_uint64x64_128_mul (a.lo, b.lo);
+ s.hi = _cairo_uint64_add (s.hi,
+ _cairo_uint64_mul (a.lo, b.hi));
+ s.hi = _cairo_uint64_add (s.hi,
+ _cairo_uint64_mul (a.hi, b.lo));
+ return s;
+}
+
+const cairo_uint128_t
+_cairo_uint128_lsl (cairo_uint128_t a, int shift)
+{
+ if (shift >= 64)
+ {
+ a.hi = a.lo;
+ a.lo = _cairo_uint32_to_uint64 (0);
+ shift -= 64;
+ }
+ if (shift)
+ {
+ a.hi = _cairo_uint64_add (_cairo_uint64_lsl (a.hi, shift),
+ _cairo_uint64_rsl (a.lo, (64 - shift)));
+ a.lo = _cairo_uint64_lsl (a.lo, shift);
+ }
+ return a;
+}
+
+const cairo_uint128_t
+_cairo_uint128_rsl (cairo_uint128_t a, int shift)
+{
+ if (shift >= 64)
+ {
+ a.lo = a.hi;
+ a.hi = _cairo_uint32_to_uint64 (0);
+ shift -= 64;
+ }
+ if (shift)
+ {
+ a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
+ _cairo_uint64_lsl (a.hi, (64 - shift)));
+ a.hi = _cairo_uint64_rsl (a.hi, shift);
+ }
+ return a;
+}
+
+const cairo_uint128_t
+_cairo_uint128_rsa (cairo_int128_t a, int shift)
+{
+ if (shift >= 64)
+ {
+ a.lo = a.hi;
+ a.hi = _cairo_uint64_rsa (a.hi, 64-1);
+ shift -= 64;
+ }
+ if (shift)
+ {
+ a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
+ _cairo_uint64_lsl (a.hi, (64 - shift)));
+ a.hi = _cairo_uint64_rsa (a.hi, shift);
+ }
+ return a;
+}
+
+const int
+_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
+{
+ return (_cairo_uint64_lt (a.hi, b.hi) ||
+ (_cairo_uint64_eq (a.hi, b.hi) &&
+ _cairo_uint64_lt (a.lo, b.lo)));
+}
+
+const int
+_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
+{
+ if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
+ return 1;
+ if (!_cairo_int128_negative (a) && _cairo_int128_negative (b))
+ return 0;
+ return _cairo_uint128_lt (a, b);
+}
+
+const int
+_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
+{
+ return (_cairo_uint64_eq (a.hi, b.hi) &&
+ _cairo_uint64_eq (a.lo, b.lo));
+}
+
+/*
+ * The design of this algorithm comes from GCC,
+ * but the actual implementation is new
+ */
+
+/*
+ * den >= num.hi
+ */
+static const cairo_uquorem64_t
+_cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
+{
+ cairo_uquorem64_t qr64;
+ cairo_uquorem64_t qr;
+ uint32_t q0, q1;
+ cairo_uint64_t r0, r1;
+ uint32_t d0, d1;
+ cairo_uint64_t t;
+
+ d0 = uint64_lo32 (den);
+ d1 = uint64_hi32 (den);
+
+ qr64 = _cairo_uint64_divrem (num.hi, _cairo_uint32_to_uint64 (d1));
+ q1 = _cairo_uint64_to_uint32 (qr64.quo);
+ r1 = qr64.rem;
+
+ t = _cairo_uint32x32_64_mul (q1, d0);
+
+ r1 = _cairo_uint64_add (_cairo_uint64_lsl (r1, 32),
+ _cairo_uint64_rsl (num.lo, 32));
+
+ if (_cairo_uint64_lt (r1, t))
+ {
+ q1--;
+ r1 = _cairo_uint64_add (r1, den);
+ if (_cairo_uint64_ge (r1, den) && _cairo_uint64_lt (r1, t))
+ {
+ q1--;
+ r1 = _cairo_uint64_add (r1, den);
+ }
+ }
+
+ r1 = _cairo_uint64_sub (r1, t);
+
+ qr64 = _cairo_uint64_divrem (r1, _cairo_uint32_to_uint64 (d1));
+
+ q0 = _cairo_uint64_to_uint32 (qr64.quo);
+ r0 = qr64.rem;
+
+ t = _cairo_uint32x32_64_mul (q0, d0);
+
+ r0 = _cairo_uint64_add (_cairo_uint64_lsl (r0, 32),
+ _cairo_uint32_to_uint64 (_cairo_uint64_to_uint32 (num.lo)));
+ if (_cairo_uint64_lt (r0, t))
+ {
+ q0--;
+ r0 = _cairo_uint64_add (r0, den);
+ if (_cairo_uint64_ge (r0, den) && _cairo_uint64_lt (r0, t))
+ {
+ q0--;
+ r0 = _cairo_uint64_add (r0, den);
+ }
+ }
+
+ r0 = _cairo_uint64_sub (r0, t);
+
+ qr.quo = _cairo_uint32s_to_uint64 (q1, q0);
+ qr.rem = r0;
+ return qr;
+}
+
+#if HAVE_UINT64_T
+
+static const int
+_cairo_leading_zeros64 (cairo_uint64_t q)
+{
+ int top = 0;
+
+ if (q >= (uint64_t) 0x10000 << 16)
+ {
+ top += 32;
+ q >>= 32;
+ }
+ if (q >= (uint64_t) 0x10000)
+ {
+ top += 16;
+ q >>= 16;
+ }
+ if (q >= (uint64_t) 0x100)
+ {
+ top += 8;
+ q >>= 8;
+ }
+ top += top_bit [q];
+ return 64 - top;
+}
+
+#else
+
+static const int
+_cairo_leading_zeros64 (cairo_uint64_t d)
+{
+ if (d.hi)
+ return _cairo_leading_zeros32 (d.hi);
+ else
+ return 32 + _cairo_leading_zeros32 (d.lo);
+}
+
+#endif
+
+const cairo_uquorem128_t
+_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
+{
+ cairo_uquorem64_t qr64;
+ cairo_uquorem128_t qr;
+ int norm;
+ cairo_uint64_t q1, q0, r1, r0;
+
+ if (_cairo_uint64_eq (den.hi, _cairo_uint32_to_uint64 (0)))
+ {
+ if (_cairo_uint64_gt (den.lo, num.hi))
+ {
+ /* 0q = nn / 0d */
+
+ norm = _cairo_leading_zeros64 (den.lo);
+ if (norm)
+ {
+ den.lo = _cairo_uint64_lsl (den.lo, norm);
+ num = _cairo_uint128_lsl (num, norm);
+ }
+ q1 = _cairo_uint32_to_uint64 (0);
+ }
+ else
+ {
+ /* qq = NN / 0d */
+
+ if (_cairo_uint64_eq (den.lo, _cairo_uint32_to_uint64 (0)))
+ den.lo = _cairo_uint64_divrem (_cairo_uint32_to_uint64 (1),
+ den.lo).quo;
+
+ norm = _cairo_leading_zeros64 (den.lo);
+ if (norm)
+ {
+ cairo_uint128_t num1;
+
+ den.lo = _cairo_uint64_lsl (den.lo, norm);
+ num1 = _cairo_uint128_rsl (num, 64 - norm);
+ qr64 = _cairo_uint128x64_normalized_divrem (num1, den.lo);
+ q1 = qr64.quo;
+ num.hi = qr64.rem;
+ num.lo = _cairo_uint64_lsl (num.lo, norm);
+ }
+ else
+ {
+ num.hi = _cairo_uint64_sub (num.hi, den.lo);
+ q1 = _cairo_uint32_to_uint64 (1);
+ }
+ }
+ qr64 = _cairo_uint128x64_normalized_divrem (num, den.lo);
+ q0 = qr64.quo;
+ r1 = _cairo_uint32_to_uint64 (0);
+ r0 = _cairo_uint64_rsl (qr64.rem, norm);
+ }
+ else
+ {
+ if (_cairo_uint64_gt (den.hi, num.hi))
+ {
+ /* 00 = nn / DD */
+ q0 = q1 = _cairo_uint32_to_uint64 (0);
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ else
+ {
+ /* 0q = NN / dd */
+
+ norm = _cairo_leading_zeros64 (den.hi);
+ if (norm == 0)
+ {
+ if (_cairo_uint64_gt (num.hi, den.hi) ||
+ _cairo_uint64_ge (num.lo, den.lo))
+ {
+ q0 = _cairo_uint32_to_uint64 (1);
+ num = _cairo_uint128_sub (num, den);
+ }
+ else
+ q0 = _cairo_uint32_to_uint64 (0);
+
+ q1 = _cairo_uint32_to_uint64 (0);
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ else
+ {
+ cairo_uint128_t num1;
+ cairo_uint128_t part;
+
+ num1 = _cairo_uint128_rsl (num, 64 - norm);
+ den = _cairo_uint128_lsl (den, norm);
+
+ qr64 = _cairo_uint128x64_normalized_divrem (num1, den.hi);
+ part = _cairo_uint64x64_128_mul (qr64.quo, den.lo);
+
+ q0 = qr64.quo;
+
+ num.lo = _cairo_uint64_lsl (num.lo, norm);
+ num.hi = qr64.rem;
+
+ if (_cairo_uint128_gt (part, num))
+ {
+ q0 = _cairo_uint64_sub (q0, _cairo_uint32_to_uint64 (1));
+ part = _cairo_uint128_sub (part, den);
+ }
+
+ q1 = _cairo_uint32_to_uint64 (0);
+
+ num = _cairo_uint128_sub (num, part);
+ num = _cairo_uint128_rsl (num, norm);
+ r0 = num.lo;
+ r1 = num.hi;
+ }
+ }
+ }
+ qr.quo.lo = q0;
+ qr.quo.hi = q1;
+ qr.rem.lo = r0;
+ qr.rem.hi = r1;
+ return qr;
+}
+
+const cairo_int128_t
+_cairo_int128_negate (cairo_int128_t a)
+{
+ a.lo = _cairo_uint64_not (a.lo);
+ a.hi = _cairo_uint64_not (a.hi);
+ return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1));
+}
+
+const cairo_int128_t
+_cairo_int128_not (cairo_int128_t a)
+{
+ a.lo = _cairo_uint64_not (a.lo);
+ a.hi = _cairo_uint64_not (a.hi);
+ return a;
+}
+
+#endif /* !HAVE_UINT128_T */
+
+const cairo_quorem128_t
+_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den)
+{
+ int num_neg = _cairo_int128_negative (num);
+ int den_neg = _cairo_int128_negative (den);
+ cairo_uquorem128_t uqr;
+ cairo_quorem128_t qr;
+
+ if (num_neg)
+ num = _cairo_int128_negate (num);
+ if (den_neg)
+ den = _cairo_int128_negate (den);
+ uqr = _cairo_uint128_divrem (num, den);
+ if (num_neg)
+ qr.rem = _cairo_int128_negate (uqr.rem);
+ else
+ qr.rem = uqr.rem;
+ if (num_neg != den_neg)
+ qr.quo = _cairo_int128_negate (uqr.quo);
+ else
+ qr.quo = uqr.quo;
+ return qr;
+}
diff --git a/src/cairo_wideint.h b/src/cairo_wideint.h
new file mode 100644
index 000000000..c634ce081
--- /dev/null
+++ b/src/cairo_wideint.h
@@ -0,0 +1,272 @@
+/*
+ * $Id: cairo_wideint.h,v 1.1 2004-05-28 19:37:15 keithp Exp $
+ *
+ * Copyright © 2004 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.
+ *
+ * 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.
+ */
+
+#ifndef CAIRO_WIDEINT_H
+#define CAIRO_WIDEINT_H
+
+#include <stdint.h>
+
+/*
+ * 64-bit datatypes. Two separate implementations, one using
+ * built-in 64-bit signed/unsigned types another implemented
+ * as a pair of 32-bit ints
+ */
+
+#define I __internal_linkage
+
+#if !HAVE_UINT64_T
+
+typedef struct _cairo_uint64 {
+ uint32_t lo, hi;
+} cairo_uint64_t, cairo_int64_t;
+
+const cairo_uint64_t I _cairo_uint32_to_uint64 (uint32_t i);
+#define _cairo_uint64_to_uint32(a) ((a).lo)
+const cairo_uint64_t I _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b);
+const cairo_uint64_t I _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b);
+const cairo_uint64_t I _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b);
+const cairo_uint64_t I _cairo_uint32x32_64_mul (uint32_t a, uint32_t b);
+const cairo_uint64_t I _cairo_uint64_lsl (cairo_uint64_t a, int shift);
+const cairo_uint64_t I _cairo_uint64_rsl (cairo_uint64_t a, int shift);
+const cairo_uint64_t I _cairo_uint64_rsa (cairo_uint64_t a, int shift);
+const int _cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b);
+const int _cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b);
+const cairo_uint64_t I _cairo_uint64_negate (cairo_uint64_t a);
+#define _cairo_uint64_negative(a) (((int32_t) ((a).hi)) < 0)
+const cairo_uint64_t I _cairo_uint64_not (cairo_uint64_t a);
+
+#define _cairo_uint64_to_int64(i) (i)
+#define _cairo_int64_to_uint64(i) (i)
+
+const cairo_int64_t I _cairo_int32_to_int64(int32_t i);
+#define _cairo_int64_to_int32(a) ((int32_t) _cairo_uint64_to_uint32(a))
+#define _cairo_int64_add(a,b) _cairo_uint64_add (a,b)
+#define _cairo_int64_sub(a,b) _cairo_uint64_sub (a,b)
+#define _cairo_int64_mul(a,b) _cairo_uint64_mul (a,b)
+#define _cairo_int32x32_64_mul(a,b) _cairo_uint32x32_64_mul ((uint32_t) (a), (uint32_t) (b)))
+const int _cairo_int64_lt (cairo_uint64_t a, cairo_uint64_t b);
+#define _cairo_int64_eq(a,b) _cairo_uint64_eq (a,b)
+#define _cairo_int64_lsl(a,b) _cairo_uint64_lsl (a,b)
+#define _cairo_int64_rsl(a,b) _cairo_uint64_rsl (a,b)
+#define _cairo_int64_rsa(a,b) _cairo_uint64_rsa (a,b)
+#define _cairo_int64_negate(a) _cairo_uint64_negate(a)
+#define _cairo_int64_negative(a) (((int32_t) ((a).hi)) < 0)
+#define _cairo_int64_not(a) _cairo_uint64_not(a)
+
+#else
+
+typedef uint64_t cairo_uint64_t;
+typedef int64_t cairo_int64_t;
+
+#define _cairo_uint32_to_uint64(i) ((uint64_t) (i))
+#define _cairo_uint64_to_uint32(i) ((uint32_t) (i))
+#define _cairo_uint64_add(a,b) ((a) + (b))
+#define _cairo_uint64_sub(a,b) ((a) - (b))
+#define _cairo_uint64_mul(a,b) ((a) * (b))
+#define _cairo_uint32x32_64_mul(a,b) ((uint64_t) (a) * (b))
+#define _cairo_uint64_lsl(a,b) ((a) << (b))
+#define _cairo_uint64_rsl(a,b) ((uint64_t) (a) >> (b))
+#define _cairo_uint64_rsa(a,b) ((uint64_t) ((int64_t) (a) >> (b)))
+#define _cairo_uint64_lt(a,b) ((a) < (b))
+#define _cairo_uint64_eq(a,b) ((a) == (b))
+#define _cairo_uint64_negate(a) ((uint64_t) -((int64_t) (a)))
+#define _cairo_uint64_negative(a) ((int64_t) (a) < 0)
+#define _cairo_uint64_not(a) (~(a))
+
+#define _cairo_uint64_to_int64(i) ((int64_t) (i))
+#define _cairo_int64_to_uint64(i) ((uint64_t) (i))
+
+#define _cairo_int32_to_int64(i) ((int64_t) (i))
+#define _cairo_int64_to_int32(i) ((int32_t) (i))
+#define _cairo_int64_add(a,b) ((a) + (b))
+#define _cairo_int64_sub(a,b) ((a) - (b))
+#define _cairo_int64_mul(a,b) ((a) * (b))
+#define _cairo_int32x32_64_mul(a,b) ((int64_t) (a) * (b))
+#define _cairo_int64_lt(a,b) ((a) < (b))
+#define _cairo_int64_eq(a,b) ((a) == (b))
+#define _cairo_int64_lsl(a,b) ((a) << (b))
+#define _cairo_int64_rsl(a,b) ((int64_t) ((uint64_t) (a) >> (b)))
+#define _cairo_int64_rsa(a,b) ((int64_t) (a) >> (b))
+#define _cairo_int64_negate(a) (-(a))
+#define _cairo_int64_negative(a) ((a) < 0)
+#define _cairo_int64_not(a) (~(a))
+
+#endif
+
+/*
+ * 64-bit comparisions derived from lt or eq
+ */
+#define _cairo_uint64_le(a,b) (!_cairo_uint64_gt(a,b))
+#define _cairo_uint64_ne(a,b) (!_cairo_uint64_eq(a,b))
+#define _cairo_uint64_ge(a,b) (!_cairo_uint64_lt(a,b))
+#define _cairo_uint64_gt(a,b) _cairo_uint64_lt(b,a)
+
+#define _cairo_int64_le(a,b) (!_cairo_int64_gt(a,b))
+#define _cairo_int64_ne(a,b) (!_cairo_int64_eq(a,b))
+#define _cairo_int64_ge(a,b) (!_cairo_int64_lt(a,b))
+#define _cairo_int64_gt(a,b) _cairo_int64_lt(b,a)
+
+/*
+ * As the C implementation always computes both, create
+ * a function which returns both for the 'native' type as well
+ */
+
+typedef struct _cairo_uquorem64 {
+ cairo_uint64_t quo;
+ cairo_uint64_t rem;
+} cairo_uquorem64_t;
+
+typedef struct _cairo_quorem64 {
+ cairo_int64_t quo;
+ cairo_int64_t rem;
+} cairo_quorem64_t;
+
+const cairo_uquorem64_t I
+_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den);
+
+const cairo_quorem64_t I
+_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den);
+
+/*
+ * 128-bit datatypes. Again, provide two implementations in
+ * case the machine has a native 128-bit datatype. GCC supports int128_t
+ * on ia64
+ */
+
+#if !HAVE_UINT128_T
+
+typedef struct cairo_uint128 {
+ cairo_uint64_t lo, hi;
+} cairo_uint128_t, cairo_int128_t;
+
+const cairo_uint128_t I _cairo_uint32_to_uint128 (uint32_t i);
+const cairo_uint128_t I _cairo_uint64_to_uint128 (cairo_uint64_t i);
+#define _cairo_uint128_to_uint64(a) ((a).lo)
+#define _cairo_uint128_to_uint32(a) _cairo_uint64_to_uint32(_cairo_uint128_to_uint64(a))
+const cairo_uint128_t I _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b);
+const cairo_uint128_t I _cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b);
+const cairo_uint128_t I _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b);
+const cairo_uint128_t I _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b);
+const cairo_uint128_t I _cairo_uint128_lsl (cairo_uint128_t a, int shift);
+const cairo_uint128_t I _cairo_uint128_rsl (cairo_uint128_t a, int shift);
+const cairo_uint128_t I _cairo_uint128_rsa (cairo_uint128_t a, int shift);
+const int _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b);
+const int _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b);
+const cairo_uint128_t I _cairo_uint128_negate (cairo_uint128_t a);
+#define _cairo_uint128_negative(a) (_cairo_uint64_negative(a.hi))
+const cairo_uint128_t I _cairo_uint128_not (cairo_uint128_t a);
+
+#define _cairo_uint128_to_int128_(i) (i)
+#define _cairo_int128_to_uint128(i) (i)
+
+const cairo_int128_t I _cairo_int32_to_int128 (int32_t i);
+const cairo_int128_t I _cairo_int64_to_int128 (cairo_int64_t i);
+#define _cairo_int128_to_int64(a) ((cairo_int64_t) (a).lo);
+#define _cairo_int128_to_int32(a) _cairo_int64_to_int32(_cairo_int128_to_int64(a))
+#define _cairo_int128_add(a,b) _cairo_uint128_add(a,b)
+#define _cairo_int128_sub(a,b) _cairo_uint128_sub(a,b)
+#define _cairo_int128_mul(a,b) _cairo_uint128_mul(a,b)
+#define _cairo_int64x64_128_mul(a,b) _cairo_uint64x64_128_mul ((cairo_uint64_t) (a), (cairo_uint64_t) (b))
+#define _cairo_int128_lsl(a,b) _cairo_uint128_lsl(a,b)
+#define _cairo_int128_rsl(a,b) _cairo_uint128_rsl(a,b)
+#define _cairo_int128_rsa(a,b) _cairo_uint128_rsa(a,b)
+const int _cairo_int128_lt (cairo_int128_t a, cairo_int128_t b);
+#define _cairo_int128_eq(a,b) _cairo_uint128_eq (a,b)
+#define _cairo_int128_negate(a) _cairo_uint128_negate(a)
+#define _cairo_int128_negative(a) (_cairo_uint128_negative(a))
+#define _cairo_int128_not(a) _cairo_uint128_not(a)
+
+#else /* !HAVE_UINT128_T */
+
+typedef uint128_t cairo_uint128_t;
+typedef int128_t cairo_int128_t;
+
+#define _cairo_uint32_to_uint128(i) ((uint128_t) (i))
+#define _cairo_uint64_to_uint128(i) ((uint128_t) (i))
+#define _cairo_uint128_to_uint64(i) ((uint64_t) (i))
+#define _cairo_uint128_to_uint32(i) ((uint32_t) (i))
+#define _cairo_uint128_add(a,b) ((a) + (b))
+#define _cairo_uint128_sub(a,b) ((a) - (b))
+#define _cairo_uint128_mul(a,b) ((a) * (b))
+#define _cairo_uint64x64_128_mul(a,b) ((uint128_t) (a) * (b))
+#define _cairo_uint128_lsl(a,b) ((a) << (b))
+#define _cairo_uint128_rsl(a,b) ((uint128_t) (a) >> (b))
+#define _cairo_uint128_rsa(a,b) ((uint128_t) ((int128_t) (a) >> (b)))
+#define _cairo_uint128_lt(a,b) ((a) < (b))
+#define _cairo_uint128_eq(a,b) ((a) == (b))
+#define _cairo_uint128_negate(a) ((uint128_t) -((int128_t) (a)))
+#define _cairo_uint128_negative(a) ((int128_t) (a) < 0)
+#define _cairo_uint128_not(a) (~(a))
+
+#define _cairo_uint128_to_int128(i) ((int128_t) (i))
+#define _cairo_int128_to_uint128(i) ((uint128_t) (i))
+
+#define _cairo_int32_to_int128(i) ((int128_t) (i))
+#define _cairo_int64_to_int128(i) ((int128_t) (i))
+#define _cairo_int128_to_int64(i) ((int64_t) (i))
+#define _cairo_int128_to_int32(i) ((int32_t) (i))
+#define _cairo_int128_add(a,b) ((a) + (b))
+#define _cairo_int128_sub(a,b) ((a) - (b))
+#define _cairo_int128_mul(a,b) ((a) * (b))
+#define _cairo_int64x64_128_mul(a,b) ((int128_t) (a) * (b))
+#define _cairo_int128_lt(a,b) ((a) < (b))
+#define _cairo_int128_eq(a,b) ((a) == (b))
+#define _cairo_int128_lsl(a,b) ((a) << (b))
+#define _cairo_int128_rsl(a,b) ((int128_t) ((uint128_t) (a) >> (b)))
+#define _cairo_int128_rsa(a,b) ((int128_t) (a) >> (b))
+#define _cairo_int128_negate(a) (-(a))
+#define _cairo_int128_negative(a) ((a) < 0)
+#define _cairo_int128_not(a) (~(a))
+
+#endif /* HAVE_UINT128_T */
+
+typedef struct _cairo_uquorem128 {
+ cairo_uint128_t quo;
+ cairo_uint128_t rem;
+} cairo_uquorem128_t;
+
+typedef struct _cairo_quorem128 {
+ cairo_int128_t quo;
+ cairo_int128_t rem;
+} cairo_quorem128_t;
+
+const cairo_uquorem128_t I
+_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den);
+
+const cairo_quorem128_t I
+_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den);
+
+#define _cairo_uint128_le(a,b) (!_cairo_uint128_gt(a,b))
+#define _cairo_uint128_ne(a,b) (!_cairo_uint128_eq(a,b))
+#define _cairo_uint128_ge(a,b) (!_cairo_uint128_lt(a,b))
+#define _cairo_uint128_gt(a,b) _cairo_uint128_lt(b,a)
+
+#define _cairo_int128_le(a,b) (!_cairo_int128_gt(a,b))
+#define _cairo_int128_ne(a,b) (!_cairo_int128_eq(a,b))
+#define _cairo_int128_ge(a,b) (!_cairo_int128_lt(a,b))
+#define _cairo_int128_gt(a,b) _cairo_int128_lt(b,a)
+
+#undef I
+
+#endif /* CAIRO_WIDEINT_H */
diff --git a/src/cairo_xcb_surface.c b/src/cairo_xcb_surface.c
index ea1f72e16..f34a62594 100644
--- a/src/cairo_xcb_surface.c
+++ b/src/cairo_xcb_surface.c
@@ -48,9 +48,9 @@ format_from_visual(XCBConnection *c, XCBVISUALID visual)
if(!r)
return nil;
- for(si = XCBRenderQueryPictFormatsScreens(r); si.rem; XCBRenderPICTSCREENNext(&si))
- for(di = XCBRenderPICTSCREENDepths(si.data); di.rem; XCBRenderPICTDEPTHNext(&di))
- for(vi = XCBRenderPICTDEPTHVisuals(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi))
+ for(si = XCBRenderQueryPictFormatsScreensIter(r); si.rem; XCBRenderPICTSCREENNext(&si))
+ for(di = XCBRenderPICTSCREENDepthsIter(si.data); di.rem; XCBRenderPICTDEPTHNext(&di))
+ for(vi = XCBRenderPICTDEPTHVisualsIter(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi))
if(vi.data->visual.id == visual.id)
{
XCBRenderPICTFORMAT ret = vi.data->format;
@@ -123,7 +123,7 @@ format_from_cairo(XCBConnection *c, cairo_format_t fmt)
if(!r)
return ret;
- for(fi = XCBRenderQueryPictFormatsFormats(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
+ for(fi = XCBRenderQueryPictFormatsFormatsIter(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
{
const XCBRenderDIRECTFORMAT *t, *f;
if(fi.data->type != XCBRenderPictTypeDirect)
@@ -231,6 +231,7 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
static cairo_surface_t *
_cairo_xcb_surface_create_similar (void *abstract_src,
cairo_format_t format,
+ int drawable,
int width,
int height)
{
@@ -314,7 +315,7 @@ static int
bytes_per_line(XCBConnection *c, int width, int bpp)
{
int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
- return (bpp * width + bitmap_pad - 1) & -bitmap_pad;
+ return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
}
static cairo_image_surface_t *
@@ -400,7 +401,7 @@ _cairo_xcb_surface_set_image (void *abstract_surface,
_cairo_xcb_surface_ensure_gc (surface);
bpp = bits_per_pixel(surface->dpy, image->depth);
- data_len = bytes_per_line(surface->dpy, surface->width, bpp) * surface->height;
+ data_len = bytes_per_line(surface->dpy, image->width, bpp) * image->height;
XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
image->width,
image->height,
@@ -508,7 +509,7 @@ _cairo_xcb_surface_clone_similar (cairo_surface_t *src,
src_image = _cairo_surface_get_image (src);
clone = (cairo_xcb_surface_t *)
- _cairo_xcb_surface_create_similar (template, format,
+ _cairo_xcb_surface_create_similar (template, format, 0,
src_image->width,
src_image->height);
if (clone == NULL)
diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c
index 19dfde503..4f4425940 100644
--- a/src/cairo_xlib_surface.c
+++ b/src/cairo_xlib_surface.c
@@ -111,6 +111,7 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
static cairo_surface_t *
_cairo_xlib_surface_create_similar (void *abstract_src,
cairo_format_t format,
+ int drawable,
int width,
int height)
{
@@ -382,7 +383,7 @@ _cairo_xlib_surface_clone_similar (cairo_surface_t *src,
src_image = _cairo_surface_get_image (src);
clone = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_similar (template, format,
+ _cairo_xlib_surface_create_similar (template, format, 0,
src_image->width,
src_image->height);
if (clone == NULL)
@@ -455,7 +456,8 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
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;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -475,6 +477,28 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
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,
@@ -484,6 +508,7 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
mask_x, mask_y,
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. */
@@ -577,8 +602,11 @@ static cairo_int_status_t
_cairo_xlib_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
+
Region xregion;
XRectangle xr;
+ XRectangle *rects = NULL;
+ XGCValues gc_values;
pixman_box16_t *box;
cairo_xlib_surface_t *surf;
int n, m;
@@ -593,13 +621,17 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
xr.width = surf->width;
xr.height = surf->height;
XUnionRectWithRegion (&xr, xregion, xregion);
+ rects = malloc(sizeof(XRectangle));
+ rects[0] = xr;
+ m = 1;
+
} else {
n = pixman_region_num_rects (region);
/* XXX: Are we sure these are the semantics we want for an
* empty, (not null) region? */
if (n == 0)
return CAIRO_STATUS_SUCCESS;
-
+ rects = malloc(sizeof(XRectangle) * n);
box = pixman_region_rects (region);
xregion = XCreateRegion();
@@ -609,13 +641,20 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
xr.y = (short) box->y1;
xr.width = (unsigned short) (box->x2 - box->x1);
xr.height = (unsigned short) (box->y2 - box->y1);
+ rects[n-1] = xr;
XUnionRectWithRegion (&xr, xregion, xregion);
}
}
+ _cairo_xlib_surface_ensure_gc (surf);
+ XGetGCValues(surf->dpy, surf->gc, GCGraphicsExposures, &gc_values);
+ XSetGraphicsExposures(surf->dpy, surf->gc, False);
+ XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
+ free(rects);
+ if (surf->picture)
XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
XDestroyRegion(xregion);
-
+ XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
return CAIRO_STATUS_SUCCESS;
}
@@ -654,6 +693,8 @@ cairo_xlib_surface_create (Display *dpy,
{
cairo_xlib_surface_t *surface;
int render_standard;
+ Window w;
+ unsigned int ignore;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@@ -692,6 +733,12 @@ cairo_xlib_surface_create (Display *dpy,
break;
}
+ XGetGeometry(dpy, drawable,
+ &w, &ignore, &ignore,
+ &surface->width,
+ &surface->height,
+ &ignore, &ignore);
+
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
diff --git a/src/cairoint.h b/src/cairoint.h
index 97db3be5b..eef9accc7 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -36,11 +36,16 @@
#ifndef _CAIROINT_H_
#define _CAIROINT_H_
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <limits.h>
+#include <stdint.h>
#include "cairo.h"
@@ -95,27 +100,13 @@
#define __attribute__(x)
#endif
-#ifdef WIN32
-typedef __int64 cairo_fixed_32_32_t;
-#else
-# if defined(__alpha__) || defined(__alpha) || \
- defined(ia64) || defined(__ia64__) || \
- defined(__sparc64__) || \
- defined(__s390x__) || \
- defined(x86_64) || defined (__x86_64__)
-typedef long cairo_fixed_32_32_t;
-# else
-# if defined(__GNUC__) && \
- ((__GNUC__ > 2) || \
- ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ > 7)))
-__extension__
-# endif
-typedef long long int cairo_fixed_32_32_t;
-# endif
-#endif
+#include "cairo_wideint.h"
-typedef cairo_fixed_32_32_t cairo_fixed_48_16_t;
-typedef int32_t cairo_fixed_16_16_t;
+typedef int32_t cairo_fixed_16_16_t;
+typedef cairo_int64_t cairo_fixed_32_32_t;
+typedef cairo_int64_t cairo_fixed_48_16_t;
+typedef cairo_int128_t cairo_fixed_64_64_t;
+typedef cairo_int128_t cairo_fixed_96_32_t;
/* The common 16.16 format gets a shorter name */
typedef cairo_fixed_16_16_t cairo_fixed_t;
@@ -157,7 +148,7 @@ typedef struct cairo_trapezoid {
typedef struct cairo_rectangle_int {
short x, y;
unsigned short width, height;
-} cairo_rectangle_t;
+} cairo_rectangle_t, cairo_glyph_size_t;
/* Sure wish C had a real enum type so that this would be distinct
from cairo_status_t. Oh well, without that, I'll use this bogus 1000
@@ -274,11 +265,26 @@ typedef struct cairo_font_backend {
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
+
+ cairo_status_t (*text_bbox) (void *font,
+ cairo_surface_t *surface,
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_box_t *bbox);
+
+ cairo_status_t (*glyph_bbox) (void *font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox);
cairo_status_t (*show_text) (void *font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
+ int source_x,
+ int source_y,
double x,
double y,
const unsigned char *utf8);
@@ -287,6 +293,8 @@ typedef struct cairo_font_backend {
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
+ int source_x,
+ int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs);
@@ -300,6 +308,9 @@ typedef struct cairo_font_backend {
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_t *path);
+ cairo_surface_t *(*create_glyph) (void *font,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_size_t *return_size);
} cairo_font_backend_t;
/* concrete font backends */
@@ -311,6 +322,7 @@ typedef struct cairo_surface_backend {
cairo_surface_t *
(*create_similar) (void *surface,
cairo_format_t format,
+ int drawable,
int width,
int height);
@@ -447,7 +459,7 @@ struct cairo_color {
};
#define CAIRO_EXTEND_DEFAULT CAIRO_EXTEND_NONE
-#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_NEAREST
+#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_BEST
typedef enum {
CAIRO_PATTERN_SOLID,
@@ -460,7 +472,6 @@ typedef struct cairo_color_stop {
cairo_fixed_t offset;
cairo_fixed_48_16_t scale;
int id;
- cairo_color_t color;
unsigned char color_char[4];
} cairo_color_stop_t;
@@ -527,9 +538,38 @@ typedef struct cairo_traps {
/* XXX: Platform-specific. Other platforms may want a different default */
#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend
+#define CAIRO_FONT_CACHE_SIZE_DEFAULT 256
+
+typedef struct {
+ unsigned long index;
+ double matrix[2][2];
+
+ unsigned int time;
+
+ cairo_surface_t *surface;
+ cairo_glyph_size_t size;
+} cairo_glyph_surface_t;
+
+typedef struct cairo_glyph_surface_node {
+ struct cairo_glyph_surface_node *next;
+ struct cairo_glyph_surface_node *prev;
+
+ cairo_glyph_surface_t s;
+} cairo_glyph_surface_node_t;
+
+typedef struct {
+ cairo_glyph_surface_node_t *first;
+ cairo_glyph_surface_node_t *last;
+ unsigned int n_nodes;
+
+ unsigned int ref_count;
+ unsigned int cache_size;
+} cairo_glyph_cache_t;
+
struct cairo_font {
int refcount;
cairo_matrix_t matrix;
+ cairo_glyph_cache_t *glyph_cache;
const struct cairo_font_backend *backend;
};
@@ -574,7 +614,6 @@ typedef struct cairo_gstate {
cairo_surface_t *surface;
cairo_pattern_t *pattern;
- cairo_point_double_t pattern_offset;
double alpha;
cairo_clip_rec_t clip;
@@ -621,6 +660,12 @@ _cairo_fixed_from_26_6 (uint32_t i);
extern double
_cairo_fixed_to_double (cairo_fixed_t f);
+extern int __internal_linkage
+_cairo_fixed_is_integer (cairo_fixed_t f);
+
+extern int __internal_linkage
+_cairo_fixed_integer_part (cairo_fixed_t f);
+
/* cairo_gstate.c */
extern cairo_gstate_t * __internal_linkage
_cairo_gstate_create (void);
@@ -972,10 +1017,27 @@ _cairo_font_glyph_extents (cairo_font_t *font,
cairo_text_extents_t *extents);
extern cairo_status_t __internal_linkage
+_cairo_font_text_bbox (cairo_font_t *font,
+ cairo_surface_t *surface,
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_box_t *bbox);
+
+extern cairo_status_t __internal_linkage
+_cairo_font_glyph_bbox (cairo_font_t *font,
+ cairo_surface_t *surface,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox);
+
+extern cairo_status_t __internal_linkage
_cairo_font_show_text (cairo_font_t *font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
+ int source_x,
+ int source_y,
double x,
double y,
const unsigned char *utf8);
@@ -986,6 +1048,8 @@ _cairo_font_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
+ int source_x,
+ int source_y,
cairo_glyph_t *glyphs,
int num_glyphs);
@@ -1003,6 +1067,12 @@ _cairo_font_glyph_path (cairo_font_t *font,
int num_glyphs,
cairo_path_t *path);
+extern cairo_surface_t *__internal_linkage
+_cairo_font_lookup_glyph (cairo_font_t *font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_size_t *return_size);
+
/* cairo_hull.c */
extern cairo_status_t
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices);
@@ -1082,6 +1152,13 @@ _cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_t
/* cairo_surface.c */
extern cairo_surface_t * __internal_linkage
+_cairo_surface_create_similar_scratch (cairo_surface_t *other,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height);
+
+extern cairo_surface_t * __internal_linkage
_cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_format_t format,
int width,
@@ -1288,6 +1365,9 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
extern cairo_status_t __internal_linkage
_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy);
+extern int __internal_linkage
+_cairo_matrix_is_integer_translation(cairo_matrix_t *matrix, int *itx, int *ity);
+
/* cairo_traps.c */
extern void __internal_linkage
_cairo_traps_init (cairo_traps_t *traps);