diff options
author | Carl Worth <cworth@cworth.org> | 2006-02-13 16:46:17 -0800 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2006-02-13 16:46:17 -0800 |
commit | b8f6633e9547ece19f73b85fdb1cb4f8625f1332 (patch) | |
tree | 3caaee720fc0d2cc63c7dd4b7803f5d21a541643 | |
parent | 1d28eecd8b8dd5b3082bcdbb0455df1ad825bba7 (diff) | |
parent | b0a6de8f0b3830fd0af521945dcaa98d62ac69d2 (diff) |
Remove pixman from LGPL_CHANGE_BEFORELGPL_CHANGE_BEFORE
40 files changed, 5396 insertions, 695 deletions
@@ -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 @@ -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. @@ -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); |