summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Worth <cworth@cworth.org>2006-02-13 16:46:47 -0800
committerCarl Worth <cworth@cworth.org>2006-02-13 16:46:47 -0800
commit0b5ac24b1522b3287903c04fb894bfae4fc67403 (patch)
treeb8256ae476f183ba07c4f4ef031d31bc31927910
parentdb163fcc882251188e0ce63d0b9606cb59664da0 (diff)
parent90689370267f3c02d6be62e3e8c85cccdad6f577 (diff)
Remove pixman and revert tessellation bug from SNAPSHOT_0_3_0SNAPSHOT_0_3_0
-rw-r--r--AUTHORS2
-rw-r--r--BUGS44
-rw-r--r--COPYING2
-rw-r--r--ChangeLog556
-rw-r--r--Makefile.am17
-rw-r--r--NEWS171
-rw-r--r--RELEASING16
-rw-r--r--TODO73
-rwxr-xr-xautogen.sh6
-rw-r--r--cairo.pc.in5
-rw-r--r--configure.in156
-rw-r--r--src/Makefile.am51
-rw-r--r--src/cairo-array.c134
-rw-r--r--src/cairo-atsui-font.c807
-rw-r--r--src/cairo-atsui.h50
-rw-r--r--src/cairo-cache.c30
-rw-r--r--src/cairo-color.c13
-rw-r--r--src/cairo-features.h.in14
-rw-r--r--src/cairo-fixed.c18
-rw-r--r--src/cairo-font.c16
-rw-r--r--src/cairo-ft-font.c176
-rw-r--r--src/cairo-ft.h62
-rw-r--r--src/cairo-glitz-surface.c233
-rw-r--r--src/cairo-glitz.h53
-rw-r--r--src/cairo-gstate.c490
-rw-r--r--src/cairo-hash.c30
-rw-r--r--src/cairo-image-surface.c6
-rw-r--r--src/cairo-matrix.c73
-rw-r--r--src/cairo-pdf-surface.c2208
-rw-r--r--src/cairo-pdf.h62
-rw-r--r--src/cairo-png.h59
-rw-r--r--src/cairo-polygon.c5
-rw-r--r--src/cairo-ps-surface.c3
-rw-r--r--src/cairo-ps.h63
-rw-r--r--src/cairo-quartz-surface.c392
-rw-r--r--src/cairo-quartz.h58
-rw-r--r--src/cairo-spline.c5
-rw-r--r--src/cairo-wideint.c148
-rw-r--r--src/cairo-wideint.h123
-rw-r--r--src/cairo-xcb-surface.c2
-rw-r--r--src/cairo-xcb.h54
-rw-r--r--src/cairo-xlib-surface.c157
-rw-r--r--src/cairo-xlib.h71
-rw-r--r--src/cairo.c11
-rw-r--r--src/cairo.h153
-rw-r--r--src/cairo_array.c134
-rw-r--r--src/cairo_atsui_font.c807
-rw-r--r--src/cairo_cache.c30
-rw-r--r--src/cairo_color.c13
-rw-r--r--src/cairo_fixed.c18
-rw-r--r--src/cairo_font.c16
-rw-r--r--src/cairo_ft_font.c176
-rw-r--r--src/cairo_gdip_font.cpp665
-rw-r--r--src/cairo_gdip_surface.cpp727
-rw-r--r--src/cairo_glitz_surface.c233
-rw-r--r--src/cairo_gstate.c490
-rw-r--r--src/cairo_image_surface.c6
-rw-r--r--src/cairo_matrix.c73
-rw-r--r--src/cairo_pdf_surface.c2208
-rw-r--r--src/cairo_png_surface.c1
-rw-r--r--src/cairo_polygon.c5
-rw-r--r--src/cairo_ps_surface.c3
-rw-r--r--src/cairo_quartz_surface.c392
-rw-r--r--src/cairo_spline.c5
-rw-r--r--src/cairo_wideint.c148
-rw-r--r--src/cairo_wideint.h272
-rw-r--r--src/cairo_xcb_surface.c2
-rw-r--r--src/cairo_xlib_surface.c157
-rw-r--r--src/cairoint.h570
-rw-r--r--test/.cvsignore3
-rw-r--r--test/Makefile.am17
-rw-r--r--test/cairo-test.c13
-rw-r--r--test/cairo-test.h1
-rw-r--r--test/cairo_test.c13
-rw-r--r--test/cairo_test.h1
-rw-r--r--test/fill-rule-ref.pngbin408 -> 1979 bytes
-rw-r--r--test/fill-rule.c58
-rw-r--r--test/fill_rule-ref.pngbin408 -> 1979 bytes
-rw-r--r--test/fill_rule.c58
-rw-r--r--test/leaky-polygon-ref.pngbin0 -> 255 bytes
-rw-r--r--test/leaky-polygon.c82
-rw-r--r--test/leaky_polygon-ref.pngbin0 -> 255 bytes
-rw-r--r--test/leaky_polygon.c82
-rw-r--r--test/line-width-ref.pngbin167 -> 171 bytes
-rw-r--r--test/line_width-ref.pngbin167 -> 171 bytes
-rw-r--r--test/text-cache-crash.c133
-rw-r--r--test/text-rotate.c117
-rw-r--r--test/text_cache_crash.c133
-rw-r--r--test/text_rotate.c117
89 files changed, 13213 insertions, 1644 deletions
diff --git a/AUTHORS b/AUTHORS
index 3be11047e..43b265f79 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -7,6 +7,8 @@ Richard Henderson <rth@twiddle.net> "slim" macros for better shared libraries
James Henstridge <james@daa.com.au> Build fixes related to freetype
Graydon Hoare <graydon@redhat.com> Support for non-render X server, first real text support
Thomas Hunger <info@teh-web.de> Initial version of cairo_in_stroke/fill
+Kristian Høgsberg <krh@redhat.com> PDF backend
+Alexander Larsson <alexl@redhat.com> Profiling and performance fixes.
Jordi Mas <jordi@ximian.com> Bug fix for cairo_show_text
Keith Packard <keithp@keithp.com> Original concept, polygon tessellation, dashing
Christof Petig <christof@petig-baender.de> Build fixes related to freetype
diff --git a/BUGS b/BUGS
index 31690e6cc..fa754e98d 100644
--- a/BUGS
+++ b/BUGS
@@ -1,3 +1,35 @@
+cairo_surface_create_for_image is claiming ownership of the user's data.
+
+--
+
+cairo_font_set_transform should be renamed cairo_font_set_matrix
+cairo_font_current_transform should be renamed cairo_font_get_matrix
+
+--
+
+Alexis Georges reports a segfault on AMD64 with a simple program,
+(that works in a 32bit chroot).
+
+--
+
+The caches need to have some locking (see: [cairo] Static caches and thread-safety)
+
+--
+
+Scaling of surface patterns is all broken, (try xsvg
+gradPatt-pattern-BE-07.svg and zoom in and out).
+
+--
+
+centi_unfinished.svg has big black portions when drawn with svg2png,
+(but not when drawn with xsvg).
+
+--
+
+The caches need to be invalidated at font destruction time.
+
+--
+
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.
@@ -92,3 +124,15 @@ move_to_show_surface (see cairo/test):
* call to cairo_move_to to any coordinate other than 0,0. A little
* bit of poking around suggests this isn't a regression, (at least
* not since the last pixman snapshot).
+
+--
+
+cairo falls over with XFree86 4.2 (probably braindead depth handling
+somewhere).
+
+--
+
+The caches abort when asked for a too-large item, (should be possible
+to trigger by asking for a giant font, "cairo_scale_font (cr, 2000)"
+perhaps). Even if the caches don't want to hold them, we need to be
+able to allocate these objects.
diff --git a/COPYING b/COPYING
index 66cf5f2b3..145e62966 100644
--- a/COPYING
+++ b/COPYING
@@ -2,7 +2,7 @@ Cairo is free software.
Every source file in the implementation of cairo is available to be
redistributed and/or modified under the terms of either the GNU Lesser
-General Public License (LPGL) version 2.1 or the Mozilla Public
+General Public License (LGPL) version 2.1 or the Mozilla Public
License (MPL) version 1.1. Some files are available under more
liberal terms, but we believe that in all cases, each file may be used
under either the LGPL or the MPL.
diff --git a/ChangeLog b/ChangeLog
index db326ebe8..48c0cb466 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,551 @@
+2005-01-21 Carl Worth <cworth@cworth.org>
+
+ * configure.in: Increment CAIRO_VERSION to 0.3.0
+
+ * NEWS: Add notes for snapshot 0.3.0
+
+ * test/fill_rule-ref.png:
+ * test/leaky_polygon-ref.png:
+ * test/line_width-ref.png: Update reference images for new
+ rasterization in libpixman 0.1.3.
+
+ * Makefile.am (RELEASE_UPLOAD_DIR): Update since directory changed
+ after server compromise.
+
+2005-01-20 Carl Worth <cworth@cworth.org>
+
+ * test/cairo_test.c: Add a bunch of missing include directives,
+ (now that cairo.h has been cleaned up).
+
+2005-01-20 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-atsui.h: Created new public header cairo-atsui.h.
+
+ Build fixes for Quartz backend courtesy of
+ Geoff Norton <gnorton@customerdna.com>:
+
+ * configure.in: Fix check for atsui font backend.
+
+ * src/Makefile.am: Add conditional compilation for
+ cairo_atsui_font.c and cairo_ft_font.c.
+
+ * src/cairo_quartz_surface.c: Add missing include of
+ cairo-quartz.h.
+
+ * src/cairo-quartz.h: Add include of Carbon/Carbon.h.
+
+ * src/cairo-features.h.in: Advertise availability of Quartz
+ surface.
+
+ * src/Makefile.am: Install cairo-quartz.h, and conditionally
+ compile cairo_quartz_surface.c.
+
+ * configure.in: Add autofoo checks to detect quartz
+ backend.
+
+2005-01-20 Carl Worth <cworth@cworth.org>
+
+ * src/cairoint.h: Track various renamings.
+
+ * src/cairo_xlib_surface.c:
+ * src/cairo_ps_surface.c:
+ * src/cairo_png_surface.c:
+ * src/cairo_pdf_surface.c:
+ * src/cairo_glitz_surface.c:
+ * src/cairo_ft_font.c: Insert new includes for backend-specific
+ header files.
+
+ * src/cairo_gdip_surface.cpp:
+ * src/cairo_gdip_font.cpp: Remove redundant include of
+ cairo-features.h.
+
+ * src/cairo.h (CAIRO_H): Rename header-exclusion macro from
+ _CAIRO_H_ to CAIRO_H.
+ Remove platform-specific grubbing for cairo-features.h and
+ pixman.h in odd places.
+
+ Remove all backend-specific prototypes, (as they are now in their
+ own header files).
+
+ * src/cairo.c (cairo_sane_state): Remove printf.
+
+ * src/cairo-features.h.in: Convert to utf-8. Use the proper name
+ for multiple-header exclusion (CAIRO_FEATURES_H). Track rename of
+ FREETYPE_FONT_FEATURE to FT_FONT_FEATURE.
+
+ * src/Makefile.am (cairoinclude_HEADERS): Split cairo.h up into
+ cairo.h, cairo-ft.h, cairo-glitz.h, cairo-pdf.h, cairo-png.h,
+ cairo-ps.h, cairo-xcb.h, cairo-xlib.h.
+ Update for rename of cairo_wideint.h to cairo-wideint.h.
+
+ * configure.in: Rename CAIRO_HAS_FREETYPE_FONT to
+ CAIRO_HAS_FT_FONT, (to match cairo_ft_font functions and
+ cairo-ft.h).
+
+ * cairo.pc.in (Cflags): Update for public header files now in
+ ${includedir}/cairo.
+
+2005-01-19 Carl Worth <cworth@cworth.org>
+
+ * src/cairo_matrix.c (cairo_matrix_get_affine):
+ * src/cairo_gstate.c (_cairo_gstate_current_point):
+ * src/cairo_color.c (_cairo_color_get_rgb): Allow NULL values for
+ return pointers so that the user can easily get partial results
+ from cairo_matrix_get_affine, cairo_current_point, and
+ cairo_current_color_rgb as needed.
+
+ * src/cairo_ft_font.c (_utf8_to_ucs4): Fix int* vs. size_t*
+ confusion, (currently in favor of int* but only because that's
+ easier to implement). Thanks to John Ellson
+ <ellson@research.att.com>. Closes bug #2328.
+
+2005-01-19 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo_pdf_surface.c: Add byteswap macros missing for
+ bigendian architectures.
+
+2005-01-19 Carl Worth <cworth@cworth.org>
+
+ * test/Makefile.am (XFAIL_TESTS): Remove fill_rule and
+ leaky_polygon from expected failures list. Both of these bugs have
+ fixes, (fill_rule is fixed by reverting cairo_traps.c to 1.16, and
+ leaky_polygon is fixed in a newer libpixman).
+
+ * src/cairo_wideint.h: Remove const qualifiers from the header
+ file as well.
+
+ * src/cairo_wideint.c: Remove useless const qualifier from
+ functions returning simple values, (quiets the warning in
+ gcc4). Thanks to John Ellson <ellson@research.att.com>. Closes bug
+ #2299.
+
+ * BUGS: Add bugs on cairo_surface_create_for_image, bad names for
+ cairo_font_set_transform and cairo_font_current_transform,
+ segfault on AMD64.
+
+2005-01-17 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo_pdf_surface.c (_cairo_pdf_document_get_font): Fix
+ double free in error path.
+ (cairo_pdf_ft_font_create): Reference the unscaled font to keep
+ the FT_Face around.
+ (cairo_pdf_ft_font_generate): Initialize end to avoid compiler
+ warning; bail out if table write fails. Fixes from Owen.
+
+2005-01-17 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo_pdf_surface.c: Add preliminary text support, including
+ support for truetype font subsetting.
+
+ * src/cairoint.h: Change type of 'surface' argument in show_glyphs
+ to void * as it is for all other surface virtual functions.
+ * src/cairo_xlib_surface.c (_cairo_xlib_surface_show_glyphs):
+ Update accordingly.
+
+ * configure.in: Add check for endianess.
+
+ * src/cairo_array.c (_cairo_array_grow_by): Fix bug in array
+ growing loop.
+ (_cairo_array_append): Accept NULL for elements argument, in which
+ case we just allocate space in the array.
+
+2005-01-17 Kristian Høgsberg <krh@redhat.com>
+
+ * test/Makefile.am (EXTRA_DIST): Take image_rotate-ref.png out of
+ EXTRA_DIST until we can actually render it correctly.
+ (XFAIL_TESTS): Update with new known bugs.
+
+ * src/cairo-features.h.in:
+ * src/cairo.h:
+ * src/cairoint.h:
+ * configure.in: Add font backend selection options.
+
+2005-01-15 John Ellson <ellson@research.att.com>
+
+ reviewed by: Keith Packard <keithp@keithp.com>
+
+ * src/cairo_gstate.c: (_cairo_gstate_glyph_extents):
+ Was using the wrong extents variable.
+
+2005-01-13 David Reveman <c99drn@cs.umu.se>
+
+ * src/cairo_xcb_surface.c: Replace struct cairo_surface_backend with
+ cairo_surface_backend_t.
+
+2005-01-13 Carl Worth <cworth@cworth.org>
+
+ * test/leaky_polygon.c:
+ * test/Makefile.am
+ * test/.cvsignore: Add leaky_polygon test for trapezoid
+ rasterization corner case.
+
+ * src/cairo_xlib_surface.c:
+ * src/cairo_glitz_surface.c:
+ * src/cairo_ft_font.c:
+ * src/cairo_font.c:
+ * src/cairoint.h:
+ * src/cairo.h: Replace all structure tags to have _ prefix.
+ struct cairo_foo -> struct _cairo_foo
+ Also, prefer cairo_foo_t over struct _cairo_foo in .c files.
+
+2005-01-12 Carl Worth <cworth@cworth.org>
+
+ * test/fill_rule.c: Add big_star_path which shows we still have
+ fill bugs, (even now that little_star_path is working).
+
+ * src/cairo.c (cairo_sane_state): A NULL cairo_t * is not sane.
+
+ * cairo.pc.in (Libs,Cflags): Add freetype flags so that things
+ work with freetype in a non-standard location, (a little extra
+ work here since freetype doesn't use pkg-config).
+
+ * TODO: Add several items culled from recent mailing list
+ discussions.
+
+ * BUGS: Add bugs on cache locking and surface pattern scaling.
+
+2005-01-11 Keith Packard <keithp@keithp.com>
+
+ * src/cairo_matrix.c: (_cairo_matrix_compute_scale_factors):
+ Scale factors shouldn't include mirroring.
+
+ * src/cairo_wideint.c: (_cairo_int32x32_64_mul),
+ (_cairo_int64x64_128_mul):
+ * src/cairo_wideint.h:
+ int32x32_64_mul and int64x64_128_mul are different from their
+ unsigned compatriots
+
+2005-01-11 Øyvind Kolås <pippin@freedesktop.org>
+
+ * src/cairo_color.c: renamed CAIRO_COLOR_DEFAULT to CAIRO_COLOR_WHITE,
+ and made it white again.
+
+2005-01-11 Øyvind Kolås <pippin@freedesktop.org>
+
+ * src/cairo_xlib_surface.c: (_cairo_xlib_surface_composite): removed
+ accidental addition of debug printf in previous commit.
+
+2005-01-11 Øyvind Kolås <pippin@freedesktop.org>
+
+ * src/cairo_color.c:
+ * src/cairo_gstate.c: (_cairo_gstate_init):
+ Changed default paint color from opaque white to opaque black.
+
+
+2005-01-11 Keith Packard <keithp@keithp.com>
+
+ * cairo.pc.in:
+ * configure.in:
+ * src/Makefile.am:
+ Fix math library detection to use autotools helper
+
+ * src/cairo_cache.c: (_cache_sane_state), (_cairo_cache_lookup):
+ Remove cache memory usage assertions as single objects can
+ be larger than the cache size
+
+ * src/cairo_ft_font.c: (_cairo_ft_font_compute_transform),
+ (_cairo_ft_font_install_transform), (_install_font_scale),
+ (_cairo_ft_font_font_extents), (_cairo_ft_font_glyph_extents),
+ (_cairo_ft_font_create_glyph):
+ Decompose font matrix transformations into a couple of
+ helper routines.
+ Return all metrics in font space.
+
+ * src/cairo_glitz_surface.c: (_glitz_format):
+ Eliminate compiler warning
+
+ * src/cairo_gstate.c: (_cairo_gstate_current_font_extents),
+ (_cairo_gstate_text_to_glyphs), (_cairo_gstate_glyph_extents):
+ Expect glyph metrics to be in font space. Compute text extents
+ by fetching one glyph metric at a time, transforming to user
+ space and computing the overall bounding box.
+
+ * src/cairo_matrix.c: (_cairo_matrix_set_rotate),
+ (_cairo_matrix_compute_scale_factors):
+ use 'sincos' where available.
+ Scale factors now ensure the non-scale transform is area preserving.
+ Scale factors requires another parameter to mark the fixed axis.
+
+ * src/cairo_wideint.c:
+ * src/cairo_wideint.h:
+ Change license to LGPL
+ Mark int32x32_64_mul as broken (which it still is)
+
+ * src/cairo_xlib_surface.c: (_cairo_xlib_surface_show_glyphs32),
+ (_cairo_xlib_surface_show_glyphs16),
+ (_cairo_xlib_surface_show_glyphs8):
+ Ensure each glyph is located as close to the specified position
+ as possible
+
+ * src/cairoint.h:
+ interface change to _cairo_matrix_compute_scale_factors
+
+2005-01-07 Kristian Høgsberg <krh@redhat.com>
+
+ * configure.in: Add -lz to CAIRO_LIBS when compiling the PDF
+ backend.
+
+ * src/cairo_pdf_surface.c (emit_image_data): Don't use
+ compressBound, since it's only available in zlib 1.2 and newer.
+
+2005-01-07 Carl Worth <cworth@cworth.org>
+
+ * TODO: Add Owen's new equation to fix clipping:
+ ((src Op dest) In clip) Add (dest Out clip)
+
+2005-01-06 Carl Worth <cworth@cworth.org>
+
+ * TODO: Added some TODO items from mailing list traffic.
+ Added cairo_show_surface_mask and note about clipping problems.
+
+2005-01-05 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo_pdf_surface.c: (emit_image_data): Implement image
+ compression (taken from cairo_ps_surface.c).
+
+ * src/cairo_pdf_surface.c: New PDF backend.
+ * src/cairo.h: Add PDF surface constructors.
+ * src/cairo_array.c: New file - generic array implementation.
+ * src/cairoint.h: Add cairo_array prototypes.
+ * src/Makefile.am (libcairo_la_SOURCES):
+ Add cairo_array.c and cairo_pdf_surface.c.
+
+2004-12-23 Carl Worth <cworth@cworth.org>
+
+ * src/cairo_traps.c: Remove unused CAIRO_TRAPS_GROWTH_INC.
+
+ * src/cairo_spline.c (_cairo_spline_add_point):
+ * src/cairo_polygon.c (_cairo_polygon_add_edge): Resize arrays by
+ doubling rather than by linear increments.
+
+ * BUGS: Add new bug exposed centi_unfinished.svg.
+
+2004-12-21 Carl Worth <cworth@cworth.org>
+
+ * src/cairoint.h:
+ * src/cairo_wideint.h: Rename __internal_linkage to cairo_private
+ and move it to the beginning of the line for function
+ declarations. Also, drop unneeded "extern" from function
+ declarations.
+
+2004-12-21 Carl Worth <cworth@cworth.org>
+
+ With thanks to Kristian Høgsberg <krh@bitplanet.net>:
+ * src/cairoint.h:
+ * src/cairo_wideint.h: Tag a few private functions/data that were
+ missing __internal_linkage.
+
+ * src/cairo_xlib_surface.c:
+ * src/cairo_ft_font.c:
+ * src/cairo_font.c: Mark cache backends as static.
+
+2004-12-20 Carl Worth <cworth@cworth.org>
+
+ * autogen.sh (LANG): Change "head -1" to more standard "head -n
+ 1".
+
+2004-12-20 Alexander Larsson <alexl@redhat.com>
+
+ * src/cairo_xlib_surface.c (_cairo_xlib_surface_create_with_size):
+ Fix bug in earlier change.
+
+2004-12-20 Carl Worth <cworth@cworth.org>
+
+ * src/cairoint.h: Re-enabled __internal_linkage for all internal
+ functions. Now avoid the warning by moving the * from the return
+ type after the __internal_linkage macro. It looks awaful, but it
+ keeps the compiler quiet.
+
+2004-12-20 Alexander Larsson <alexl@redhat.com>
+
+ * src/cairoint.h:
+ Add _cairo_gstate_restore_external_state, _cairo_fixed_integer_floor
+ and _cairo_fixed_integer_ceil.
+
+ * src/cairo.c: (cairo_restore):
+ Call _cairo_gstate_restore_external_state on restore.
+
+ * src/cairo_cache.c: (_cache_lookup):
+ Fix cache-misses.
+
+ * src/cairo_fixed.c: (_cairo_fixed_integer_floor),
+ (_cairo_fixed_integer_ceil):
+ Implement floor and ceil
+
+ * src/cairo_gstate.c:
+ (_cairo_gstate_restore_external_state):
+ Restore surface clip region on restroe.
+
+ (_calculate_region_for_intermediate_clip_surface),
+ (_cairo_gstate_clip_and_composite_trapezoids),
+ (_cairo_gstate_show_surface), (_cairo_gstate_show_glyphs):
+ Create intermediate clip surfaces of the minimal required
+ size.
+
+2004-12-20 Carl Worth <cworth@cworth.org>
+
+ * AUTHORS: Add Alexander Larsson to AUTHORS list.
+
+ * src/cairo_xlib_surface.c (_cairo_xlib_surface_create_with_size):
+ Split off from _cairo_xlib_surface_create to avoid roundtrip when
+ size is already known.
+ (cairo_xlib_surface_create): Simplified to just call XGetGeometry
+ that defer to _cairo_xlib_surface_create_with_size. Add comment
+ about remaining roundtrip and possible plans to eliminate it later
+ with a new interface requiring width/height.
+ Thanks to Alexander Larsson <alexl@redhat.com>.
+
+ * test/text_cache_crash.c (draw): Disabled test that was killing
+ my machine for some reason. Scary.
+
+2004-12-20 Carl Worth <cworth@cworth.org>
+
+ * src/cairo_image_surface.c
+ (_cairo_image_abstract_surface_create_pattern): Change return
+ value from cairo_status_t to cairo_int_status_t to match
+ definition in cairo_surface_backend_t.
+
+ * BUGS: Add bug about gcc 3.4 warning: '__visibility__' attribute
+ ignored on non-class types.
+
+ * src/cairoint.h: Remove __internal_linkage macro from all
+ functions returning pointers to shut up warning from gcc 3.4.
+
+2004-12-17 Carl Worth <cworth@cworth.org>
+
+ * test/cairo_test.c (cairo_test): Fix to find reference images in
+ local directory when run directly, (rather than by "make check").
+
+ * BUGS: Add bug about invalidating font caches.
+
+2004-12-02 David Reveman <c99drn@cs.umu.se>
+
+ * src/cairo_gstate.c (_cairo_gstate_clip): Revert the "return early"
+ change so that rectangular clipping works with backends that
+ don't support clipping regions.
+
+2004-11-29 Carl Worth <cworth@cworth.org>
+
+ * COPYING: Fix typo: LPGL->LGPL.
+
+ * src/cairo_ps_surface.c (cairo_ps_surface_create): Remove
+ unintentional copyright statement from user-generated output
+ image.
+
+2004-11-23 Carl Worth <cworth@cworth.org>
+
+ * test/Makefile.am (XFAIL_TESTS): Note that text_cache_crash is
+ expected to fail.
+
+ * test/text_cache_crash.c (draw): Add test to demonstrate bug when
+ item is too big for cache.
+
+ * src/cairo_cache.c (_cache_sane_state): Really remove that
+ refcount assertion this time.
+
+ * test/text_cache_crash.c: Add note that bug has been fixed.
+ (main): Instrumentation code for testing cache destruction.
+
+ * test/cairo_test.c (cairo_test): Support tests that produce no
+ output, (don't check image if (width,height) == (0,0)).
+
+ * src/cairoint.h: Add #include <assert.h> here rather than in
+ multiple .c files.
+
+ * src/cairo_cache.c: Add const qualifier to static
+ cache_arrangements table.
+ (_cache_sane_state): Remove refcount assertion as it it false
+ during the cairo_cache_destroy.
+ (_cache_sane_state): #include <assert.h> moved up to cairoint.h
+ (_entry_destroy): Fix bug in assertion (used_memory >=
+ entry->memory), not >.
+ (_cairo_cache_destroy): Fix timing of refcount decrement so that
+ the destroy function actually works.
+
+2004-11-14 Carl Worth <cworth@cworth.org>
+
+ * src/cairo_gstate.c (_cairo_gstate_select_font): Don't destroy a
+ NULL font.
+
+2004-11-13 Carl Worth <cworth@cworth.org>
+
+ * src/cairo_gstate.c (_cairo_gstate_select_font): Unconditionally
+ destroy the old font, (otherwise, if the same font was selected
+ twice in a row, a reference was lost to it, leading to assertion
+ failures).
+
+2004-11-12 Stuart Parmenter <pavlov@pavlov.net>
+ * src/cairo_gdip_font.cpp:
+ * src/cairo_gdip_surface.cpp: Added GDI+ backend to Cairo.
+
+2004-11-12 Carl Worth <cworth@cworth.org>
+
+ * src/cairo_font.c (_font_cache_hash, _font_cache_create_entry):
+ * src/cairo_ft_font.c (_cairo_ft_font_text_to_glyphs): Move
+ declarations above statements to satisfy pre-C99 compilers. Thanks
+ to Michael Johnson <ahze@ahze.net>.
+
+2004-11-09 Carl Worth <cworth@cworth.org>
+
+ * test/text_rotate.c (NUM_TEXT): Increase size and increase number
+ of different angles drawn.
+ (draw): Fix broken usage of extents (missing bearings), add
+ stroked bounding box (shifted out by 0.5 units to just abut the
+ text), and increase position adjustments to make room for this
+ larger box.
+ (draw): Move x_off, y_off calculation outside of loop to emphasize
+ loop-independence.
+
+2004-11-08 Dave Beckett <Dave.Beckett@bristol.ac.uk>
+
+ * configure.in: require libpixman 0.1.2 since
+ src/cairo_glitz_surface.c depends on two new functions of 0.1.2 -
+ pixman_format_get_masks and pixman_image_get_format
+
+2004-11-05 Graydon Hoare <graydon@redhat.com>
+
+ * src/cairo_ft_font.c: Change the signs of a variety of
+ metrics, which were backwards.
+ * src/cairo_gstate.c (_cairo_gstate_clip): Return early if we
+ found a rectangular clip at all, not just in error case.
+ * src/cairo_xlib_surface.c
+ (_xlib_glyphset_cache_create_entry): Give render glyphset entry the
+ negative bbox offsets it wants, not the bearings.
+
+2004-11-04 Carl Worth <cworth@cworth.org>
+
+ * test/text_cache_crash.c: Add new test demonstrating assertion
+ failure in cairo_cache_lookup.
+
+ * test/text_rotate.c: Add new test showing problems with rotated
+ text.
+
+2004-11-04 David Reveman <c99drn@cs.umu.se>
+
+ * src/cairo_glitz_surface.c (cairo_set_target_glitz):
+ cairo_glitz_surface_create now takes a reference to the glitz
+ surface, so it shouldn't be done here anymore.
+ Removed feature_mask from cairo_glitz_surface_t.
+ Removed support for CAIRO_OPERATOR_SATURATE.
+ (cairo_glitz_surface_create): Take a reference to the glitz
+ surface and no need to get surface features anymore.
+ Tracking changes to glitz.
+
+ * configure.in: Require version 0.3.0 of glitz.
+
+ * src/cairo_gstate.c (_cairo_gstate_clip): Fixed return status.
+
+2004-11-01 Olivier Andrieu <oliv__a@users.sourceforge.net>
+
+ * src/cairo.h: remove cairo_ft_font_destroy() prototype.
+
+2004-10-28 Carl Worth <cworth@cworth.org>
+
+ * Makefile.am (release-verify-newer): Abort release-publish if
+ there's already a published tar file with the current version.
+ (release-publish): Add code to update the LATEST-package-version
+ file.
+
2004-10-27 Carl Worth <cworth@cworth.org>
* configure.in: Increment CAIRO_VERSION to 0.2.0.
@@ -479,7 +1027,7 @@
* src/cairo.h: replaced ct with cr in public headers to keep
usage consistent.
-2004-07-24 Jamey Sharp <jamey@minilop.net>
+2004-07-24 Jamey Sharp <jamey@minilop.net>
* src/cairo_xcb_surface.c:
Updating for XCB API change around iterators.
@@ -2062,7 +2610,7 @@
(_cairo_font_font_extents): These internal functions can never be
called with a NULL font.
-2003-10-23 Graydon Hoare <graydon@redhat.com>
+2003-10-23 Graydon Hoare <graydon@redhat.com>
* src/cairo_ft_font.c: New file.
* src/Makefile.am: Add cairo_ft_font.c
@@ -2312,7 +2860,7 @@
* src/Makefile.am (libcairo_la_SOURCES): Added cairo_fixed.c
-2003-09-05 Keith Packard <keithp@keithp.com>
+2003-09-05 Keith Packard <keithp@keithp.com>
* src/cairo_path_stroke.c: comment face computations, check for
reflecting transformation to select correct face orientations
@@ -2368,7 +2916,7 @@
called before cairo_set_target and SEGV if cairo_fill called
before cairo_set_rgb_color)
-2003-09-04 Keith Packard <keithp@keithp.com>
+2003-09-04 Keith Packard <keithp@keithp.com>
* src/cairo_path_stroke.c: added comments describing miter
join code and miter limit computation. Replace XFoo with cairo_foo
diff --git a/Makefile.am b/Makefile.am
index 6dfc4ab3d..3a33e9a7c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,7 +14,8 @@ pkgconfig_DATA = cairo.pc
# make release-check
# or make release-publish
-RELEASE_UPLOAD_DIR = cairographics.org:/home/www/cairo/snapshots
+RELEASE_UPLOAD_HOST = cairographics.org
+RELEASE_UPLOAD_DIR = /srv/cairo.freedesktop.org/www/snapshots
RELEASE_URL_BASE = http://cairographics.org/snapshots
RELEASE_ANNOUNCE_LIST = cairo-announce@cairographics.org
@@ -29,10 +30,19 @@ release-remove-old:
release-check: release-remove-old distcheck $(md5_file)
-release-publish: release-check
+release-verify-newer:
+ @echo -n "Checking that no $(VERSION) release already exists..."
+ @ssh $(RELEASE_UPLOAD_HOST) test ! -e $(RELEASE_UPLOAD_DIR)/$(tar_file) \
+ || (echo "Ouch." && echo "Found: $(RELEASE_UPLOAD_HOST):$(RELEASE_UPLOAD_DIR)/$(tar_file)" \
+ && echo "The version in configure.in must be incremented before a new release." \
+ && false)
+ @echo "Good."
+
+release-publish: release-verify-newer release-check
mkdir -p releases
- scp $(tar_file) $(md5_file) $(RELEASE_UPLOAD_DIR)
+ scp $(tar_file) $(md5_file) $(RELEASE_UPLOAD_HOST):$(RELEASE_UPLOAD_DIR)
mv $(tar_file) $(md5_file) releases
+ ssh $(RELEASE_UPLOAD_HOST) "rm -f $(RELEASE_UPLOAD_DIR)/LATEST-$(PACKAGE)-[0-9]* && touch $(RELEASE_UPLOAD_DIR)/LATEST-$(PACKAGE)-$(VERSION)"
@echo ""
@echo "Please send an announcement to $(RELEASE_ANNOUNCE_LIST)"
@echo "including the following:"
@@ -47,4 +57,3 @@ release-publish: release-check
@cat releases/$(md5_file)
@echo ""
@echo "Also, please include the new entries from the NEWS file."
-
diff --git a/NEWS b/NEWS
index 8465aaa3f..6bb4c13c7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,174 @@
+Snapshot 0.3.0 (2005-01-21 Carl Worth <cworth@cworth.org>)
+==========================================================
+Major API changes
+-----------------
+1) The public header files will no longer be directly installed into
+ the system include directory. They will now be installed in a
+ subdirectory named "cairo", (eg. in /usr/include/cairo rather than
+ in /usr/include).
+
+ As always, the easiest way for applications to discover the
+ location of the header file is to let pkg-config generate the
+ necessary -I CFLAGS and -L/-l LDFLAGS. For example:
+
+ cc `pkg-config --cflags --libs cairo` -o foo foo.c
+
+ IMPORTANT: Users with old versions of cairo installed will need to
+ manually remove cairo.h and cairo-features.h from the
+ system include directories in order to prevent the old
+ headers from being used in preference to the new ones.
+
+2) The backend-specific portions of the old monolithic cairo.h have
+ been split out into individual public header files. The new files
+ are:
+
+ cairo-atsui.h
+ cairo-ft.h
+ cairo-glitz.h
+ cairo-pdf.h
+ cairo-png.h
+ cairo-ps.h
+ cairo-quartz.h
+ cairo-xcb.h
+ cairo-xlib.h
+
+ Applications will need to be modified to explicitly include the new
+ header files where appropriate.
+
+3) There are two new graphics backends in this snapshot, a PDF
+ backend, and a Quartz backend. There is also one new font backend,
+ ATSUI.
+
+PDF backend
+-----------
+Kristian Høgsberg has contributed a new backend to allow cairo-based
+applications to generate PDF output. The interface for creating a PDF
+surface is similar to that of the PS backend, as can be seen in
+cairo-pdf.h:
+
+ void
+ cairo_set_target_pdf (cairo_t *cr,
+ FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch);
+
+ cairo_surface_t *
+ cairo_pdf_surface_create (FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch);
+
+Once a PDF surface has been created, applications can draw to it as
+any other cairo surface.
+
+This code is still a bit rough around the edges, and does not yet
+support clipping, surface patterns, or transparent gradients. Text
+only works with TrueType fonts at this point and only black text is
+supported. Also, the size of the generated PDF files is currently
+quite big.
+
+Kristian is still actively developing this backend, so watch this
+space for future progress.
+
+Quartz backend
+--------------
+Calum Robinson has contributed a new backend to allow cairo
+applications to target native Mac OS X windows through the Quartz
+API. Geoff Norton integrated this backend into the current
+configure-based build system, while Calum also provided Xcode build
+support in the separate "macosx" module available in CVS.
+
+The new interface, available in cairo-quartz.h, is as follows:
+
+ void
+ cairo_set_target_quartz_context (cairo_t *cr,
+ CGContextRef context,
+ int width,
+ int height);
+
+ cairo_surface_t *
+ cairo_quartz_surface_create (CGContextRef context,
+ int width,
+ int height);
+
+There is an example program available in CVS in cairo-demo/quartz. It
+is a port of Keith Packard's fdclock program originally written for
+the xlib backend. A screenshot of this program running on Mac OS X is
+available here:
+
+ http://cairographics.org/~cworth/images/fdclock-quartz.png
+
+ATSUI font backend
+------------------
+This new font backend complements the Quartz backend by allowing
+applications to use native font selection on Mac OS X. The interface
+is a single new function:
+
+ cairo_font_t *
+ cairo_atsui_font_create (ATSUStyle style);
+
+Minor API changes
+-----------------
+Prototype for non-existent function "cairo_ft_font_destroy" removed.
+
+Now depends on libpixman 0.1.2 or newer, (0.1.3 is being released
+concurrently and has some useful performance improvements).
+
+Default paint color is now opaque black, (was opaque white). Default
+background color is transparent (as before).
+
+Renamed "struct cairo" to "struct _cairo" to free up the word "cairo"
+from the C++ identifier name space.
+
+Functions returning multiple return values through provided pointers,
+(cairo_matrix_get_affine, cairo_current_point, and
+cairo_current_color_rgb), will now accept NULL for values the user
+wants to ignore.
+
+CAIRO_HAS_FREETYPE_FONT has now been renamed to CAIRO_HAS_FT_FONT.
+
+Performance improvements
+------------------------
+Alexander Larsson provided some fantastic performance improvements
+yielding a 10000% performance improvement in his application, (when
+also including his performance work in libpixman-0.1.3). These include
+
+ * Fixed handling of cache misses.
+
+ * Creating intermediate clip surfaces at the minimal size required.
+
+ * Eliminating roundtrips when creating intermediate Xlib surfaces.
+
+Implementation
+--------------
+Major re-work of font metrics system by Keith Packard. Font metrics
+should now be much more reliable.
+
+Glitz backend
+-------------
+Updated for glitz-0.3.0.
+Bug fixes in reference counting.
+
+Test suite
+----------
+New tests for cache crashing, rotating text, improper filling of
+complex polygons, and leaky rasterization.
+
+Bug fixes
+---------
+Fixed assertion failure when selecting the same font multiple times in
+sequence.
+
+Fixed reference counting so cache_destroy functions work.
+
+Remove unintended copyright statement from files generated with
+PostScript backend.
+
+Fixed to eliminate new warnings from gcc 3.4 and gcc 4.
+
Snapshot 0.2.0 (2004-10-27 Carl Worth <cworth@cworth.org>)
===========================================================
New license: LGPL/MPL
diff --git a/RELEASING b/RELEASING
index 8cc5f021b..9088f9b5d 100644
--- a/RELEASING
+++ b/RELEASING
@@ -32,8 +32,8 @@ fixes are committed. Here are the steps to follow:
to other entries in NEWS. Take special care to note any
incompatible changes in the API. These should be easy to find
by looking for cairo.h in the ChangeLog. Additionally, the
- output following command should be examined using the previous
- snapshot tag:
+ output of the following command should be examined using the
+ previous snapshot tag:
cvs diff -r SNAPSHOT_X_Y_Z src/cairo.h
@@ -58,17 +58,19 @@ fixes are committed. Here are the steps to follow:
6) Run "make release-publish" which will perform the following steps
for you:
+ * Check that no release exists with the current version
* Verify that make distcheck completes successfully
- * Generate the final tar file with the correct version number
+ * Generate the final tar file
* Generate an md5sum file
- * scp both files to cairographics.org:/home/www/cairo/snapshots
+ * scp both files to appear on http://cairographics.org/snapshots
+ * Create a LATEST-package-version file (after deleting any old one)
* Place local copies of both files in the releases directory
- * Provide some text for the release announcement
+ * Provide some text for the release announcement (see below).
7) Tag the entire source tree with a tag of the form SNAPSHOT_X_Y_Z:
cvs tag SNAPSHOT_X_Y_Z
-8) Send a message to cairo-announce@cairographics.org to announce the
- new snapshot using the text provided by the previous step.
+9) Send a message to cairo-announce@cairographics.org to announce the
+ new snapshot using the text provided from "make release-publish".
diff --git a/TODO b/TODO
index 2f594ec5b..bbd549f99 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,47 @@
+* Add support for non-antialiased rendering. API ?
+
+* Cleanup cairo_snippets so they operate in a more default cairo
+ environment, (particularly with a default CTM).
+
+* Add one of cairo_surface_finish/_finalize/_close to resolve the
+ "reference counting vs garbage collection" thread.
+
+* Shove experimental snapping code from libsvg-cairo down int cairo
+ proper.
+
+* Clean up the cache code a bit, (there is at least one redundant
+ level of cacheing, and there are some minor style issues).
+
+* Implement the parallel install stuff, (most importantly, push
+ cairo.h down into into one directory below $(includedir)).
+
+* Add CAIRO_FILL_RULE_INVERSE_WINDING and CAIRO_FILL_RULE_INVERSE_EVEN_ODD
+
+* Simplifying the operator set?
+
+* Fix clipping to work for all operators. The equation we have come up
+ with is:
+
+ ((src Op dest) In clip) Add (dest Out clip)
+
+* Resolve the rest of the rendering equation. We need a fundamental
+ equation upon which more convenient operations are based, (at least
+ formally). Some of the common operations that should be convenient:
+
+ * display surface
+ * display surface multiplied by constant alpha
+ * display pattern masked by surface
+
+ So this involves deciding whether to expose a new mask object in the
+ graphics state, and deciding exactly what set_alpha means. It almost
+ certainly means adding cairo_show_surface_mask.
+
+* Implement a hidden transform, (as per the result of the hidden
+ offset thread on the mailing list).
+
+* Replace PNG backend with an image_surface function to save a PNG
+ image.
+
* Clean up the API in preparation for freezing and release.
* Implement a PDF backend.
@@ -69,11 +113,40 @@ functions:
current path. We may also need to provide the coordinates of the
faces of every dash as well.
+* Should add geometry pruning as appropriate.
+
* We need a way to get at the image data after something
like cairo_surface_create_similar with the image backend.
+* Three suggestions from Owen that will help GTK+ performance:
+
+ - The ability have an additional rectangle-list clip in the
+ Xlib surface. Frequently during an expose event, GTK+ is
+ drawing L shaped areas
+
+ XXXXXX
+ X.....
+ X.....
+
+ And passing the real clip to the server is going to save
+ a lot of pixel operations that will be thrown away.
+
+ - The ability to pass in a width/height to cairo_xlib_surface_create()
+ to avoid a round-trip. (Round-trips are bad to the point where
+ querying the the server is something you don't want to do in
+ production software)
+
+ - More of a future thing, the ability to hint to to cairo that
+ the contents of the Xlib surface passed to
+ cairo_xlib_surface_create() are a solid fill ... this is
+ very much the normal case for GTK+ usage and allows for
+ big optimization in the no-RENDER case.
+ (see http://mail.gnome.org/archives/gtk-devel-list/2003-March/msg00045.html
+
* Verification, profiling, optimization.
+ centi_unfinished.svg may provide a good test case.
+
A comparison with PostScript
============================
diff --git a/autogen.sh b/autogen.sh
index dbe36ddf6..46ca3422b 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -26,7 +26,7 @@ LANG=C
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') \
+ if ($AUTOCONF --version | head -n 1 | awk 'NR==1 { if( $(NF) >= '$autoconf_min_vers') \
exit 1; exit 0; }');
then
echo "$ARGV0: ERROR: \`$AUTOCONF' is too old."
@@ -43,7 +43,7 @@ else
fi
if ($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 ; then
- if ($AUTOMAKE --version | head -1 | awk 'NR==1 { if( $(NF) >= '$automake_min_vers') \
+ if ($AUTOMAKE --version | head -n 1 | awk 'NR==1 { if( $(NF) >= '$automake_min_vers') \
exit 1; exit 0; }');
then
echo "$ARGV0: ERROR: \`$AUTOMAKE' is too old."
@@ -52,7 +52,7 @@ if ($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 ; then
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' ) \
+ if ($ACLOCAL --version | head -n 1 | awk 'NR==1 { if( $(NF) >= '$aclocal_min_vers' ) \
exit 1; exit 0; }' );
then
echo "$ARGV0: ERROR: \`$ACLOCAL' is too old."
diff --git a/cairo.pc.in b/cairo.pc.in
index 339d576b2..4e420b202 100644
--- a/cairo.pc.in
+++ b/cairo.pc.in
@@ -8,6 +8,5 @@ Description: Multi-platform 2D graphics library
Version: @VERSION@
Requires: fontconfig libpixman @XRENDER_REQUIRES@ @PNG_REQUIRES@ @GLITZ_REQUIRES@
-Libs: -L${libdir} -lcairo -lm
-Cflags: -I${includedir} @FREETYPE_CFLAGS@
-
+Libs: @FREETYPE_LIBS@ -L${libdir} -lcairo
+Cflags: @FREETYPE_CFLAGS@ -I${includedir}/cairo
diff --git a/configure.in b/configure.in
index b17c91006..61d9adbae 100644
--- a/configure.in
+++ b/configure.in
@@ -3,7 +3,7 @@ AC_INIT(src/cairo.h)
dnl ===========================================================================
# Package version number, (as distinct from shared library version)
-CAIRO_VERSION=0.2.0
+CAIRO_VERSION=0.3.0
# libtool shared library version
@@ -33,6 +33,13 @@ AC_PROG_CC
AC_PROG_CPP
AM_PROG_LIBTOOL
AC_STDC_HEADERS
+AC_C_BIGENDIAN
+
+AC_CHECK_LIBM
+
+LIBS="$LIBS $LIBM"
+
+AC_CHECK_FUNCS(sincos)
dnl ===========================================================================
@@ -60,11 +67,32 @@ else
AM_CONDITIONAL(CAIRO_HAS_XLIB_SURFACE, true)
fi
+AC_SUBST(XLIB_SURFACE_FEATURE)
+AC_SUBST(XRENDER_REQUIRES)
+
CAIRO_CFLAGS="$CAIRO_CFLAGS $XRENDER_CFLAGS"
CAIRO_LIBS="$CAIRO_LIBS $XRENDER_LIBS"
-AC_SUBST(XLIB_SURFACE_FEATURE)
-AC_SUBST(XRENDER_REQUIRES)
+AC_ARG_ENABLE(quartz,
+ [ --disable-quartz Disable cairo's quartz backend],
+ [use_quartz=$enableval], [use_quartz=yes])
+
+if test "x$use_quartz" = "xyes"; then
+ dnl There is no pkgconfig for quartz; lets do a header check
+ AC_CHECK_HEADER(Carbon/Carbon.h, [use_quartz=yes], [use_quartz=no])
+fi
+
+if test "x$use_quartz" != "xyes"; then
+ QUARTZ_SURFACE_FEATURE=CAIRO_HAS_NO_QUARTZ_SURFACE
+ AM_CONDITIONAL(CAIRO_HAS_QUARTZ_SURFACE, false)
+else
+ QUARTZ_SURFACE_FEATURE=CAIRO_HAS_QUARTZ_SURFACE
+ QUARTZ_LIBS="-Xlinker -framework -Xlinker Carbon"
+ AM_CONDITIONAL(CAIRO_HAS_QUARTZ_SURFACE, true)
+fi
+
+AC_SUBST(QUARTZ_SURFACE_FEATURE)
+CAIRO_LIBS="$CAIRO_LIBS $QUARTZ_LIBS"
dnl ===========================================================================
@@ -112,6 +140,26 @@ AC_SUBST(PS_LIBS)
dnl ===========================================================================
+AC_ARG_ENABLE(pdf,
+ [ --disable-pdf Disable cairo's PDF backend],
+ [use_pdf=$enableval], [use_pdf=yes])
+
+if test "x$use_pdf" != "xyes"; then
+ PDF_SURFACE_FEATURE=CAIRO_HAS_NO_PDF_SURFACE
+ AM_CONDITIONAL(CAIRO_HAS_PDF_SURFACE, false)
+else
+ PDF_SURFACE_FEATURE=CAIRO_HAS_PDF_SURFACE
+ PDF_LIBS=-lz
+ AM_CONDITIONAL(CAIRO_HAS_PDF_SURFACE, true)
+fi
+
+CAIRO_LIBS="$CAIRO_LIBS $PDF_LIBS"
+
+AC_SUBST(PDF_SURFACE_FEATURE)
+AC_SUBST(PDF_LIBS)
+
+dnl ===========================================================================
+
AC_ARG_ENABLE(png,
[ --disable-png Disable cairo's PNG backend],
[use_png=$enableval], [use_png=yes])
@@ -146,7 +194,7 @@ AC_ARG_ENABLE(glitz,
[use_glitz=$enableval], [use_glitz=yes])
if test "x$use_glitz" = "xyes"; then
- PKG_CHECK_MODULES(GLITZ, glitz >= 0.2.3, [
+ PKG_CHECK_MODULES(GLITZ, glitz >= 0.3.0, [
GLITZ_REQUIRES=glitz
use_glitz=yes], [use_glitz="no (requires glitz http://freedesktop.org/software/glitz)"])
fi
@@ -181,14 +229,24 @@ AC_SUBST(SANITY_CHECKING_FEATURE)
dnl ===========================================================================
-PKG_CHECK_MODULES(FONTCONFIG, fontconfig)
-CAIRO_CFLAGS="$CAIRO_CFLAGS $FONTCONFIG_CFLAGS"
-CAIRO_LIBS="$CAIRO_LIBS $FONTCONFIG_LIBS"
-
-PKG_CHECK_MODULES(PIXMAN, libpixman >= 0.1.1)
+PKG_CHECK_MODULES(PIXMAN, libpixman >= 0.1.2)
CAIRO_CFLAGS="$CAIRO_CFLAGS $PIXMAN_CFLAGS"
CAIRO_LIBS="$CAIRO_LIBS $PIXMAN_LIBS"
+dnl ===========================================================================
+
+AC_ARG_ENABLE(freetype,
+ [ --disable-freetype Disable cairo's freetype font backend],
+ [use_freetype=$enableval], [use_freetype=yes])
+
+if test "x$use_freetype" = "xyes"; then
+ PKG_CHECK_MODULES(FONTCONFIG, fontconfig,
+ [use_freetype=yes], [use_freetype=no])
+fi
+
+CAIRO_CFLAGS="$CAIRO_CFLAGS $FONTCONFIG_CFLAGS"
+CAIRO_LIBS="$CAIRO_LIBS $FONTCONFIG_LIBS"
+
# Test for freetype2 separate from pkg-config since at least up to
# 2003-06-07, there was no freetype2.pc in the release.
#
@@ -206,34 +264,68 @@ FREETYPE_MIN_RELEASE=2.1.0
# libtool-specific version - this is what is checked
FREETYPE_MIN_VERSION=8.0.2
-if test -z "$FREETYPE_CONFIG"; then
- AC_PATH_PROG(FREETYPE_CONFIG, freetype-config, no)
-fi
-if test "$FREETYPE_CONFIG" = "no" ; then
- AC_MSG_ERROR(No freetype-config script found in path or FREETYPE_CONFIG)
-fi
+if test "x$use_freetype" = "xyes"; then
-AC_MSG_CHECKING(freetype2 libtool version)
+ if test -z "$FREETYPE_CONFIG"; then
+ AC_PATH_PROG(FREETYPE_CONFIG, freetype-config, no)
+ fi
+ if test "$FREETYPE_CONFIG" = "no" ; then
+ AC_MSG_ERROR(No freetype-config script found in path or FREETYPE_CONFIG)
+ fi
-FREETYPE_VERSION=`$FREETYPE_CONFIG --version`
+ AC_MSG_CHECKING(freetype2 libtool version)
-VERSION_DEC=`echo $FREETYPE_VERSION | awk -F. '{printf("%d\n", 10000*$1 + 100*$2 + $3)};'`
-MIN_VERSION_DEC=`echo $FREETYPE_MIN_VERSION | awk -F. '{printf("%d\n", 10000*$1 + 100*$2 + $3)};'`
-if test $VERSION_DEC -lt $MIN_VERSION_DEC; then
- AC_MSG_ERROR($FREETYPE_VERSION - version $FREETYPE_MIN_VERSION from release $FREETYPE_MIN_RELEASE required)
-fi
-AC_MSG_RESULT($FREETYPE_VERSION - OK)
+ FREETYPE_VERSION=`$FREETYPE_CONFIG --version`
+
+ VERSION_DEC=`echo $FREETYPE_VERSION | awk -F. '{printf("%d\n", 10000*$1 + 100*$2 + $3)};'`
+ MIN_VERSION_DEC=`echo $FREETYPE_MIN_VERSION | awk -F. '{printf("%d\n", 10000*$1 + 100*$2 + $3)};'`
+ if test $VERSION_DEC -lt $MIN_VERSION_DEC; then
+ AC_MSG_ERROR($FREETYPE_VERSION - version $FREETYPE_MIN_VERSION from release $FREETYPE_MIN_RELEASE required)
+ fi
+ AC_MSG_RESULT($FREETYPE_VERSION - OK)
-FREETYPE_CFLAGS=`$FREETYPE_CONFIG --cflags`
-FREETYPE_LIBS=`$FREETYPE_CONFIG --libs`
-AC_SUBST(FREETYPE_CFLAGS)
-AC_SUBST(FREETYPE_LIBS)
+ FREETYPE_CFLAGS=`$FREETYPE_CONFIG --cflags`
+ FREETYPE_LIBS=`$FREETYPE_CONFIG --libs`
+ AC_SUBST(FREETYPE_CFLAGS)
+ AC_SUBST(FREETYPE_LIBS)
+fi
CAIRO_CFLAGS="$CAIRO_CFLAGS $FREETYPE_CFLAGS"
CAIRO_LIBS="$CAIRO_LIBS $FREETYPE_LIBS"
+if test "x$use_freetype" != "xyes"; then
+ FT_FONT_FEATURE=CAIRO_HAS_NO_FT_FONT
+ AM_CONDITIONAL(CAIRO_HAS_FT_FONT, false)
+else
+ FT_FONT_FEATURE=CAIRO_HAS_FT_FONT
+ AM_CONDITIONAL(CAIRO_HAS_FT_FONT, true)
+fi
+AC_SUBST(FT_FONT_FEATURE)
+
dnl ===========================================================================
+dnl This check should default to 'yes' once we have code to actually
+dnl check for the atsui font backend.
+
+AC_ARG_ENABLE(atsui,
+ [ --disable-atsui Disable cairo's atsui font backend],
+ [use_atsui=$enableval], [use_atsui=yes])
+
+if test "x$use_atsui" = "xyes"; then
+ dnl There is no pkgconfig for atsui; lets do a header check
+ AC_CHECK_HEADER(Carbon/Carbon.h, [use_atsui=yes], [use_atsui=no])
+fi
+
+if test "x$use_atsui" != "xyes"; then
+ ATSUI_FONT_FEATURE=CAIRO_HAS_NO_ATSUI_FONT
+ AM_CONDITIONAL(CAIRO_HAS_ATSUI_FONT, false)
+else
+ ATSUI_FONT_FEATURE=CAIRO_HAS_ATSUI_FONT
+ AM_CONDITIONAL(CAIRO_HAS_ATSUI_FONT, true)
+fi
+AC_SUBST(ATSUI_FONT_FEATURE)
+
+dnl ===========================================================================
dnl Checks for precise integer types
AC_CHECK_TYPES([uint64_t, uint128_t])
@@ -248,7 +340,7 @@ if test "x$GCC" = "xyes"; then
fi
CAIRO_CFLAGS="$CAIRO_CFLAGS $WARN_CFLAGS"
-CAIRO_LIBS="$CAIRO_LIBS -lm"
+CAIRO_LIBS="$CAIRO_LIBS"
AC_SUBST(CAIRO_CFLAGS)
AC_SUBST(CAIRO_LIBS)
@@ -266,11 +358,17 @@ test/Makefile
dnl ===========================================================================
echo ""
-echo "cairo will be compiled with the following backends:"
+echo "cairo will be compiled with the following surface backends:"
echo " Xlib: $use_xlib"
+echo " Quartz: $use_quartz"
echo " XCB: $use_xcb"
echo " PostScript: $use_ps"
+echo " PDF: $use_pdf"
echo " PNG: $use_png"
echo " glitz: $use_glitz"
echo ""
+echo "and the following font backends:"
+echo " freetype: $use_freetype"
+echo " atsui: $use_atsui"
+echo ""
diff --git a/src/Makefile.am b/src/Makefile.am
index 8343cb1ce..d4155e817 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,24 +1,53 @@
+cairoincludedir = $(includedir)/cairo
+cairoinclude_HEADERS = \
+ cairo.h \
+ cairo-atsui.h \
+ cairo-features.h\
+ cairo-ft.h \
+ cairo-glitz.h \
+ cairo-pdf.h \
+ cairo-png.h \
+ cairo-ps.h \
+ cairo-quartz.h \
+ cairo-xcb.h \
+ cairo-xlib.h
+
lib_LTLIBRARIES = libcairo.la
-include_HEADERS = cairo.h cairo-features.h
if CAIRO_HAS_PS_SURFACE
-libcairo_ps_sources = cairo_ps_surface.c
+libcairo_ps_sources = cairo_ps_surface.c cairo-ps.h
+endif
+
+if CAIRO_HAS_PDF_SURFACE
+libcairo_pdf_sources = cairo_pdf_surface.c cairo-pdf.h
endif
if CAIRO_HAS_PNG_SURFACE
-libcairo_png_sources = cairo_png_surface.c
+libcairo_png_sources = cairo_png_surface.c cairo-png.h
endif
if CAIRO_HAS_XLIB_SURFACE
-libcairo_xlib_sources = cairo_xlib_surface.c
+libcairo_xlib_sources = cairo_xlib_surface.c cairo-xlib.h
+endif
+
+if CAIRO_HAS_QUARTZ_SURFACE
+libcairo_quartz_sources = cairo_quartz_surface.c cairo-quartz.h
endif
if CAIRO_HAS_XCB_SURFACE
-libcairo_xcb_sources = cairo_xcb_surface.c
+libcairo_xcb_sources = cairo_xcb_surface.c cairo-xcb.h
endif
if CAIRO_HAS_GLITZ_SURFACE
-libcairo_glitz_sources = cairo_glitz_surface.c
+libcairo_glitz_sources = cairo_glitz_surface.c cairo-glitz.h
+endif
+
+if CAIRO_HAS_ATSUI_FONT
+libcairo_atsui_sources = cairo_atsui_font.c cairo-atsui.h
+endif
+
+if CAIRO_HAS_FT_FONT
+libcairo_ft_sources = cairo_ft_font.c cairo-ft.h
endif
# These names match automake style variable definition conventions so
@@ -31,11 +60,11 @@ XRENDER_LIBS=@XRENDER_LIBS@
libcairo_la_SOURCES = \
cairo.c \
cairo.h \
+ cairo_array.c \
cairo_cache.c \
cairo_color.c \
cairo_fixed.c \
cairo_font.c \
- cairo_ft_font.c \
cairo_gstate.c \
cairo_hull.c \
cairo_image_surface.c \
@@ -52,10 +81,14 @@ libcairo_la_SOURCES = \
cairo_traps.c \
cairo_pattern.c \
cairo_wideint.c \
- cairo_wideint.h \
+ cairo-wideint.h \
+ $(libcairo_atsui_sources)\
+ $(libcairo_ft_sources)\
$(libcairo_ps_sources) \
+ $(libcairo_pdf_sources) \
$(libcairo_png_sources) \
$(libcairo_xlib_sources)\
+ $(libcairo_quartz_sources)\
$(libcairo_xcb_sources) \
$(libcairo_glitz_sources)\
cairoint.h
@@ -64,4 +97,4 @@ libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined
INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS)
-libcairo_la_LIBADD = $(CAIRO_LIBS) -lm
+libcairo_la_LIBADD = $(CAIRO_LIBS)
diff --git a/src/cairo-array.c b/src/cairo-array.c
new file mode 100644
index 000000000..2b1cf9d61
--- /dev/null
+++ b/src/cairo-array.c
@@ -0,0 +1,134 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include "cairoint.h"
+
+void
+_cairo_array_init (cairo_array_t *array, int element_size)
+{
+ array->size = 0;
+ array->num_elements = 0;
+ array->element_size = element_size;
+ array->elements = NULL;
+}
+
+void
+_cairo_array_fini (cairo_array_t *array)
+{
+ free (array->elements);
+}
+
+cairo_status_t
+_cairo_array_grow_by (cairo_array_t *array, int additional)
+{
+ char *new_elements;
+ int old_size = array->size;
+ int required_size = array->num_elements + additional;
+ int new_size;
+
+ if (required_size <= old_size)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (old_size == 0)
+ new_size = 1;
+ else
+ new_size = old_size * 2;
+
+ while (new_size < required_size)
+ new_size = new_size * 2;
+
+ array->size = new_size;
+ new_elements = realloc (array->elements,
+ array->size * array->element_size);
+
+ if (new_elements == NULL) {
+ array->size = old_size;
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ array->elements = new_elements;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_array_truncate (cairo_array_t *array, int num_elements)
+{
+ if (num_elements < array->num_elements)
+ array->num_elements = num_elements;
+}
+
+void *
+_cairo_array_index (cairo_array_t *array, int index)
+{
+ assert (0 <= index && index < array->num_elements);
+
+ return (void *) &array->elements[index * array->element_size];
+}
+
+void
+_cairo_array_copy_element (cairo_array_t *array, int index, void *dst)
+{
+ memcpy (dst, _cairo_array_index (array, index), array->element_size);
+}
+
+void *
+_cairo_array_append (cairo_array_t *array,
+ const void *elements, int num_elements)
+{
+ cairo_status_t status;
+ void *dest;
+
+ status = _cairo_array_grow_by (array, num_elements);
+ if (status != CAIRO_STATUS_SUCCESS)
+ return NULL;
+
+ assert (array->num_elements + num_elements <= array->size);
+
+ dest = &array->elements[array->num_elements * array->element_size];
+ array->num_elements += num_elements;
+
+ if (elements != NULL)
+ memcpy (dest, elements, num_elements * array->element_size);
+
+ return dest;
+}
+
+int
+_cairo_array_num_elements (cairo_array_t *array)
+{
+ return array->num_elements;
+}
diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c
new file mode 100644
index 000000000..52cfc6bd8
--- /dev/null
+++ b/src/cairo-atsui-font.c
@@ -0,0 +1,807 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Calum Robinson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Calum Robinson
+ *
+ * Contributor(s):
+ * Calum Robinson <calumr@mac.com>
+ */
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "cairo-atsui.h"
+#include "cairoint.h"
+
+
+
+
+
+#pragma mark Types
+
+
+
+
+
+typedef struct {
+ cairo_unscaled_font_t base;
+
+ ATSUStyle style;
+ ATSUFontID fontID;
+} cairo_atsui_font_t;
+
+
+typedef struct cairo_ATSUI_glyph_path_callback_info_t {
+ cairo_path_t *path;
+ cairo_matrix_t scale;
+} cairo_ATSUI_glyph_path_callback_info_t;
+
+
+
+
+
+#pragma mark Private Functions
+
+
+
+
+
+static CGAffineTransform CGAffineTransformMakeWithCairoFontScale(cairo_font_scale_t scale)
+{
+ return CGAffineTransformMake( scale.matrix[0][0], scale.matrix[0][1],
+ scale.matrix[1][0], scale.matrix[1][1],
+ 0, 0);
+}
+
+
+static ATSUStyle CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_font_scale_t *scale)
+{
+ ATSUStyle style;
+ OSStatus err;
+
+
+ // Set the style's size
+ CGAffineTransform theTransform = CGAffineTransformMakeWithCairoFontScale(*scale);
+ Fixed theSize = FloatToFixed(CGSizeApplyAffineTransform(CGSizeMake(1.0, 1.0), theTransform).height);
+ const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag };
+ const ByteCount theFontStyleSizes[] = { sizeof(Fixed) };
+ ATSUAttributeValuePtr theFontStyleValues[] = { &theSize };
+
+ err = ATSUCreateAndCopyStyle(inStyle, &style);
+
+ err = ATSUSetAttributes( style,
+ sizeof(theFontStyleTags) / sizeof(ATSUAttributeTag),
+ theFontStyleTags, theFontStyleSizes, theFontStyleValues);
+
+
+ return style;
+}
+
+
+
+
+
+#pragma mark Public Functions
+
+
+
+
+
+static cairo_unscaled_font_t *
+_cairo_atsui_font_create( const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight)
+{
+ cairo_atsui_font_t *font = NULL;
+ ATSUStyle style;
+ ATSUFontID fontID;
+ OSStatus err;
+ Boolean isItalic, isBold;
+
+
+ err = ATSUCreateStyle(&style);
+
+
+ switch (weight)
+ {
+ case CAIRO_FONT_WEIGHT_BOLD:
+ isBold = true;
+ break;
+ case CAIRO_FONT_WEIGHT_NORMAL:
+ default:
+ isBold = false;
+ break;
+ }
+
+ switch (slant)
+ {
+ case CAIRO_FONT_SLANT_ITALIC:
+ isItalic = true;
+ break;
+ case CAIRO_FONT_SLANT_OBLIQUE:
+ isItalic = false;
+ break;
+ case CAIRO_FONT_SLANT_NORMAL:
+ default:
+ isItalic = false;
+ break;
+ }
+
+ err = ATSUFindFontFromName( family, strlen(family),
+ kFontFamilyName,
+ kFontNoPlatformCode,
+ kFontRomanScript,
+ kFontNoLanguageCode,
+ &fontID);
+
+
+ ATSUAttributeTag styleTags[] = {kATSUQDItalicTag, kATSUQDBoldfaceTag, kATSUFontTag};
+ ATSUAttributeValuePtr styleValues[] = {&isItalic, &isBold, &fontID};
+ ByteCount styleSizes[] = {sizeof(Boolean), sizeof(Boolean), sizeof(ATSUFontID)};
+
+
+ err = ATSUSetAttributes( style,
+ sizeof(styleTags) / sizeof(styleTags[0]),
+ styleTags,
+ styleSizes,
+ styleValues);
+
+
+
+ font = malloc(sizeof(cairo_atsui_font_t));
+
+ if (_cairo_unscaled_font_init(&font->base, &cairo_atsui_font_backend) == CAIRO_STATUS_SUCCESS)
+ {
+ font->style = style;
+ font->fontID = fontID;
+
+
+ return &font->base;
+ }
+
+
+ free(font);
+
+ return NULL;
+}
+
+
+static void
+_cairo_atsui_font_destroy(void *abstract_font)
+{
+ cairo_atsui_font_t *font = abstract_font;
+
+
+ if (font == NULL)
+ return;
+
+ if (font->style)
+ ATSUDisposeStyle(font->style);
+
+ free(font);
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_text_to_glyphs( void *abstract_font,
+ cairo_font_scale_t *sc,
+ const unsigned char *utf8,
+ cairo_glyph_t **glyphs,
+ int *nglyphs)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ size_t i;
+ OSStatus err;
+ ATSUTextLayout textLayout;
+ ATSLayoutRecord *layoutRecords;
+ ItemCount glyphCount, charCount;
+ UniChar *theText;
+ ATSUStyle style;
+
+
+ charCount = strlen(utf8);
+
+
+ err = ATSUCreateTextLayout(&textLayout);
+
+
+ // Set the text in the text layout object, so we can measure it
+ theText = (UniChar *)malloc(charCount * sizeof(UniChar));
+
+ for (i = 0; i < charCount; i++)
+ {
+ theText[i] = utf8[i];
+ }
+
+ err = ATSUSetTextPointerLocation( textLayout,
+ theText,
+ 0,
+ charCount,
+ charCount);
+
+
+ style = CreateSizedCopyOfStyle(font->style, sc);
+
+
+ // Set the style for all of the text
+ err = ATSUSetRunStyle( textLayout,
+ style,
+ kATSUFromTextBeginning,
+ kATSUToTextEnd);
+
+
+
+ // Get the glyphs from the text layout object
+ err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout( textLayout,
+ 0,
+ kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
+ (void *)&layoutRecords,
+ &glyphCount);
+
+ *nglyphs = glyphCount;
+
+
+ *glyphs = (cairo_glyph_t *)malloc(glyphCount * (sizeof(cairo_glyph_t)));
+ if (*glyphs == NULL)
+ {
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < glyphCount; i++)
+ {
+ (*glyphs)[i].index = layoutRecords[i].glyphID;
+ (*glyphs)[i].x = FixedToFloat(layoutRecords[i].realPos);
+ (*glyphs)[i].y = 0;
+ }
+
+
+ free(theText);
+
+ ATSUDirectReleaseLayoutDataArrayPtr( NULL,
+ kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
+ (void *)&layoutRecords);
+
+ ATSUDisposeTextLayout(textLayout);
+
+ ATSUDisposeStyle(style);
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_font_extents( void *abstract_font,
+ cairo_font_scale_t *sc,
+ cairo_font_extents_t *extents)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ ATSFontRef atsFont;
+ ATSFontMetrics metrics;
+ OSStatus err;
+
+
+ // TODO - test this
+
+ atsFont = FMGetATSFontRefFromFont(font->fontID);
+
+ if (atsFont)
+ {
+ err = ATSFontGetHorizontalMetrics(atsFont, kATSOptionFlagsDefault, &metrics);
+
+ if (err == noErr)
+ {
+ extents->ascent = metrics.ascent;
+ extents->descent = metrics.descent;
+ extents->height = metrics.capHeight;
+ extents->max_x_advance = metrics.maxAdvanceWidth;
+
+ // The FT backend doesn't handle max_y_advance either, so we'll ignore it for now.
+ extents->max_y_advance = 0.0;
+
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+
+ return CAIRO_STATUS_NULL_POINTER;
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_glyph_extents( void *abstract_font,
+ cairo_font_scale_t *sc,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ cairo_point_double_t origin;
+ cairo_point_double_t glyph_min, glyph_max;
+ cairo_point_double_t total_min, total_max;
+ OSStatus err;
+ ATSUStyle style;
+ int i;
+
+
+ if (num_glyphs == 0)
+ {
+ extents->x_bearing = 0.0;
+ extents->y_bearing = 0.0;
+ extents->width = 0.0;
+ extents->height = 0.0;
+ extents->x_advance = 0.0;
+ extents->y_advance = 0.0;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ origin.x = glyphs[0].x;
+ origin.y = glyphs[0].y;
+
+
+ style = CreateSizedCopyOfStyle(font->style, sc);
+
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ GlyphID theGlyph = glyphs[i].index;
+ double minX, maxX, ascent, descent;
+ ATSGlyphIdealMetrics metricsH, metricsV;
+
+
+ err = ATSUGlyphGetIdealMetrics( style,
+ 1,
+ &theGlyph,
+ 0,
+ &metricsH);
+
+
+ ATSUVerticalCharacterType verticalType = kATSUStronglyVertical;
+ ATSUAttributeTag theTag = kATSUVerticalCharacterTag;
+ ByteCount theSize = sizeof(ATSUVerticalCharacterType);
+
+ err = ATSUSetAttributes(style, 1, &theTag, &theSize, (ATSUAttributeValuePtr)&verticalType);
+
+ err = ATSUGlyphGetIdealMetrics( style,
+ 1,
+ &theGlyph,
+ 0,
+ &metricsV);
+
+ minX = metricsH.otherSideBearing.x;
+ maxX = metricsH.advance.x;
+
+ ascent = metricsV.advance.x;
+ descent = metricsV.otherSideBearing.x;
+
+ glyph_min.x = glyphs[i].x + minX;
+ glyph_min.y = glyphs[i].y + descent;
+ glyph_max.x = glyphs[i].x + maxX;
+ glyph_max.y = glyphs[i].y + ascent;
+
+ if (i==0)
+ {
+ total_min = glyph_min;
+ total_max = glyph_max;
+ }
+ else
+ {
+ if (glyph_min.x < total_min.x)
+ total_min.x = glyph_min.x;
+ if (glyph_min.y < total_min.y)
+ total_min.y = glyph_min.y;
+
+ if (glyph_max.x > total_max.x)
+ total_max.x = glyph_max.x;
+ if (glyph_max.y > total_max.y)
+ total_max.y = glyph_max.y;
+ }
+ }
+
+
+ extents->x_bearing = total_min.x - origin.x;
+ extents->y_bearing = total_min.y - origin.y;
+ extents->width = total_max.x - total_min.x;
+ extents->height = total_max.y - total_min.y;
+ extents->x_advance = glyphs[i-1].x - origin.x;
+ extents->y_advance = glyphs[i-1].y - origin.y;
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_glyph_bbox( void *abstract_font,
+ cairo_font_scale_t *sc,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ cairo_fixed_t x1, y1, x2, y2;
+ int i;
+ OSStatus err;
+ ATSUStyle style;
+
+
+ bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16;
+ bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16;
+
+
+ style = CreateSizedCopyOfStyle(font->style, sc);
+
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ GlyphID theGlyph = glyphs[i].index;
+ ATSGlyphIdealMetrics metrics;
+
+
+ err = ATSUGlyphGetIdealMetrics( style,
+ 1,
+ &theGlyph,
+ 0,
+ &metrics);
+
+ x1 = _cairo_fixed_from_double(glyphs[i].x);
+ y1 = _cairo_fixed_from_double(glyphs[i].y);
+ x2 = x1 + _cairo_fixed_from_double(metrics.advance.x);
+ y2 = y1 + _cairo_fixed_from_double(metrics.advance.y);
+
+ 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;
+ }
+
+
+ ATSUDisposeStyle(style);
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_show_glyphs( void *abstract_font,
+ cairo_font_scale_t *sc,
+ cairo_operator_t operator,
+ cairo_surface_t *source,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ CGContextRef myBitmapContext;
+ CGColorSpaceRef colorSpace;
+ cairo_image_surface_t *destImageSurface;
+ int i;
+
+
+ destImageSurface = _cairo_surface_get_image(surface);
+
+
+ // Create a CGBitmapContext for the dest surface for drawing into
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+
+ myBitmapContext = CGBitmapContextCreate( destImageSurface->data,
+ destImageSurface->width,
+ destImageSurface->height,
+ destImageSurface->depth / 4,
+ destImageSurface->stride,
+ colorSpace,
+ kCGImageAlphaPremultipliedFirst);
+
+
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(font->fontID);
+ CGFontRef cgFont = CGFontCreateWithPlatformFont(&atsFont);
+
+ CGContextSetFont(myBitmapContext, cgFont);
+
+
+ CGAffineTransform textTransform = CGAffineTransformMakeWithCairoFontScale(*sc);
+ CGSize textSize = CGSizeMake(1.0, 1.0);
+
+ textSize = CGSizeApplyAffineTransform(textSize, textTransform);
+
+ CGContextSetFontSize(myBitmapContext, textSize.width);
+
+
+ // TODO - bold and italic text
+ //
+ // We could draw the text using ATSUI and get bold, italics
+ // etc. for free, but ATSUI does a lot of text layout work
+ // that we don't really need...
+
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ CGGlyph theGlyph = glyphs[i].index;
+
+ CGContextShowGlyphsAtPoint(myBitmapContext, source_x + glyphs[i].x, destImageSurface->height - (source_y + glyphs[i].y), &theGlyph, 1);
+ }
+
+
+ CGColorSpaceRelease(colorSpace);
+ CGContextRelease(myBitmapContext);
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+#pragma mark -
+
+
+static OSStatus MyATSCubicMoveToCallback(const Float32Point *pt, void *callBackDataPtr)
+{
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ double scaledPt[2];
+ cairo_point_t point;
+
+
+ scaledPt[0] = pt->x;
+ scaledPt[1] = pt->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ point.x = _cairo_fixed_from_double(scaledPt[0]);
+ point.y = _cairo_fixed_from_double(scaledPt[1]);
+
+ _cairo_path_move_to(info->path, &point);
+
+
+ return noErr;
+}
+
+
+static OSStatus MyATSCubicLineToCallback(const Float32Point *pt, void *callBackDataPtr)
+{
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ cairo_point_t point;
+ double scaledPt[2];
+
+
+ scaledPt[0] = pt->x;
+ scaledPt[1] = pt->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ point.x = _cairo_fixed_from_double(scaledPt[0]);
+ point.y = _cairo_fixed_from_double(scaledPt[1]);
+
+ _cairo_path_line_to(info->path, &point);
+
+
+ return noErr;
+}
+
+
+static OSStatus MyATSCubicCurveToCallback( const Float32Point *pt1,
+ const Float32Point *pt2,
+ const Float32Point *pt3,
+ void *callBackDataPtr)
+{
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ cairo_point_t p0, p1, p2;
+ double scaledPt[2];
+
+
+ scaledPt[0] = pt1->x;
+ scaledPt[1] = pt1->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ p0.x = _cairo_fixed_from_double(scaledPt[0]);
+ p0.y = _cairo_fixed_from_double(scaledPt[1]);
+
+
+ scaledPt[0] = pt2->x;
+ scaledPt[1] = pt2->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ p1.x = _cairo_fixed_from_double(scaledPt[0]);
+ p1.y = _cairo_fixed_from_double(scaledPt[1]);
+
+
+ scaledPt[0] = pt3->x;
+ scaledPt[1] = pt3->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ p2.x = _cairo_fixed_from_double(scaledPt[0]);
+ p2.y = _cairo_fixed_from_double(scaledPt[1]);
+
+
+ _cairo_path_curve_to(info->path, &p0, &p1, &p2);
+
+
+ return noErr;
+}
+
+
+static OSStatus MyCubicClosePathProc(void * callBackDataPtr)
+{
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+
+
+ _cairo_path_close_path(info->path);
+
+
+ return noErr;
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_glyph_path( void *abstract_font,
+ cairo_font_scale_t *sc,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path)
+{
+ int i;
+ cairo_atsui_font_t *font = abstract_font;
+ OSStatus err;
+ cairo_ATSUI_glyph_path_callback_info_t info;
+ ATSUStyle style;
+
+
+ static ATSCubicMoveToUPP moveProc = NULL;
+ static ATSCubicLineToUPP lineProc = NULL;
+ static ATSCubicCurveToUPP curveProc = NULL;
+ static ATSCubicClosePathUPP closePathProc = NULL;
+
+
+ if (moveProc == NULL)
+ {
+ moveProc = NewATSCubicMoveToUPP(MyATSCubicMoveToCallback);
+ lineProc = NewATSCubicLineToUPP(MyATSCubicLineToCallback);
+ curveProc = NewATSCubicCurveToUPP(MyATSCubicCurveToCallback);
+ closePathProc = NewATSCubicClosePathUPP(MyCubicClosePathProc);
+ }
+
+
+ info.path = path;
+
+
+ style = CreateSizedCopyOfStyle(font->style, sc);
+
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ GlyphID theGlyph = glyphs[i].index;
+
+
+ cairo_matrix_set_affine( &info.scale,
+ 1.0, 0.0,
+ 0.0, 1.0,
+ glyphs[i].x, glyphs[i].y);
+
+
+ err = ATSUGlyphGetCubicPaths( style,
+ theGlyph,
+ moveProc,
+ lineProc,
+ curveProc,
+ closePathProc,
+ (void *)&info,
+ &err);
+ }
+
+
+ err = ATSUDisposeStyle(style);
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+#pragma mark -
+
+
+static cairo_status_t
+_cairo_atsui_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
+{
+ // TODO
+ printf("_cairo_atsui_font_create_glyph is unimplemented\n");
+
+ // I'm not sure if we need this, given that the ATSUI backend does no caching(?)
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+cairo_font_t *
+cairo_atsui_font_create(ATSUStyle style)
+{
+ cairo_font_scale_t scale;
+ cairo_font_t *scaled;
+ cairo_atsui_font_t *f = NULL;
+
+
+ scaled = malloc(sizeof(cairo_font_t));
+ if (scaled == NULL)
+ return NULL;
+
+
+ f = malloc(sizeof(cairo_atsui_font_t));
+ if (f)
+ {
+ if (_cairo_unscaled_font_init(&f->base, &cairo_atsui_font_backend) == CAIRO_STATUS_SUCCESS)
+ {
+ f->style = style;
+
+ _cairo_font_init(scaled, &scale, &f->base);
+
+ return scaled;
+ }
+ }
+
+
+ free(scaled);
+
+
+ return NULL;
+}
+
+
+
+
+
+#pragma mark Backend
+
+
+
+
+
+const cairo_font_backend_t cairo_atsui_font_backend = {
+ _cairo_atsui_font_create,
+ _cairo_atsui_font_destroy,
+ _cairo_atsui_font_font_extents,
+ _cairo_atsui_font_text_to_glyphs,
+ _cairo_atsui_font_glyph_extents,
+ _cairo_atsui_font_glyph_bbox,
+ _cairo_atsui_font_show_glyphs,
+ _cairo_atsui_font_glyph_path,
+ _cairo_atsui_font_create_glyph
+};
diff --git a/src/cairo-atsui.h b/src/cairo-atsui.h
new file mode 100644
index 000000000..94b30432a
--- /dev/null
+++ b/src/cairo-atsui.h
@@ -0,0 +1,50 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Calum Robinson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Calum Robinson
+ *
+ * Contributor(s):
+ * Calum Robinson <calumr@mac.com>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_ATSUI_H
+#define CAIRO_ATSUI_H
+#ifdef CAIRO_HAS_ATSUI_FONT
+
+/* ATSUI platform-specific font interface */
+
+#include <Carbon/Carbon.h>
+
+cairo_font_t *
+cairo_atsui_font_create(ATSUStyle style);
+
+#endif /* CAIRO_HAS_ATSUI_FONT */
+#endif /* CAIRO_ATSUI_H */
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index a33d69a04..b097b609b 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -43,7 +43,7 @@
* Packard.
*/
-static cairo_cache_arrangement_t cache_arrangements [] = {
+static const cairo_cache_arrangement_t cache_arrangements [] = {
{ 16, 43, 41 },
{ 32, 73, 71 },
{ 64, 151, 149 },
@@ -114,7 +114,6 @@ static cairo_cache_arrangement_t cache_arrangements [] = {
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
#ifdef CAIRO_DO_SANITY_CHECKING
-#include <assert.h>
static void
_cache_sane_state (cairo_cache_t *cache)
{
@@ -122,13 +121,12 @@ _cache_sane_state (cairo_cache_t *cache)
assert (cache->entries != NULL);
assert (cache->backend != NULL);
assert (cache->arrangement != NULL);
- assert (cache->refcount > 0);
- assert (cache->used_memory <= cache->max_memory);
+ /* Cannot check this, a single object may larger */
+ /* assert (cache->used_memory <= cache->max_memory); */
assert (cache->live_entries <= cache->arrangement->size);
}
#else
#define _cache_sane_state(c)
-#define assert(x)
#endif
static void
@@ -140,7 +138,7 @@ _entry_destroy (cairo_cache_t *cache, unsigned long i)
{
cairo_cache_entry_base_t *entry = cache->entries[i];
assert(cache->live_entries > 0);
- assert(cache->used_memory > entry->memory);
+ assert(cache->used_memory >= entry->memory);
cache->live_entries--;
cache->used_memory -= entry->memory;
@@ -183,10 +181,12 @@ _cache_lookup (cairo_cache_t *cache,
if (predicate != NULL)
{
/* We are looking up an exact entry. */
- if (*probe != NULL
- && *probe != DEAD_ENTRY
- && (*probe)->hashcode == hash
- && predicate (cache, key, *probe))
+ if (*probe == NULL)
+ /* Found an empty spot, there can't be a match */
+ break;
+ else if (*probe != DEAD_ENTRY
+ && (*probe)->hashcode == hash
+ && predicate (cache, key, *probe))
return probe;
}
else
@@ -230,8 +230,7 @@ _find_exact_live_entry_for (cairo_cache_t *cache,
return _cache_lookup (cache, key, cache->backend->keys_equal);
}
-
-static cairo_cache_arrangement_t *
+static const cairo_cache_arrangement_t *
_find_cache_arrangement (unsigned long proposed_size)
{
unsigned long idx;
@@ -302,7 +301,7 @@ _cairo_cache_init (cairo_cache_t *cache,
const cairo_cache_backend_t *backend,
unsigned long max_memory)
{
- assert(backend != NULL);
+ assert (backend != NULL);
if (cache != NULL){
cache->arrangement = &cache_arrangements[0];
@@ -342,7 +341,7 @@ _cairo_cache_destroy (cairo_cache_t *cache)
_cache_sane_state (cache);
- if (cache->refcount-- > 0)
+ if (--cache->refcount > 0)
return;
for (i = 0; i < cache->arrangement->size; ++i) {
@@ -419,7 +418,8 @@ _cairo_cache_lookup (cairo_cache_t *cache,
_entry_destroy (cache, idx);
}
- assert(cache->max_memory >= (cache->used_memory + new_entry->memory));
+ /* Can't assert this; new_entry->memory may be larger than max_memory */
+ /* assert(cache->max_memory >= (cache->used_memory + new_entry->memory)); */
/* Make room in the table for a new slot. */
status = _resize_cache (cache, cache->live_entries + 1);
diff --git a/src/cairo-color.c b/src/cairo-color.c
index 2fe793ac8..899b1e3d5 100644
--- a/src/cairo-color.c
+++ b/src/cairo-color.c
@@ -36,7 +36,7 @@
#include "cairoint.h"
-static cairo_color_t const CAIRO_COLOR_DEFAULT = {
+static cairo_color_t const CAIRO_COLOR_WHITE = {
1.0, 1.0, 1.0, 1.0,
0xffff, 0xffff, 0xffff, 0xffff
};
@@ -47,7 +47,7 @@ _cairo_color_compute_shorts (cairo_color_t *color);
void
_cairo_color_init (cairo_color_t *color)
{
- *color = CAIRO_COLOR_DEFAULT;
+ *color = CAIRO_COLOR_WHITE;
}
void
@@ -69,9 +69,12 @@ _cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blu
void
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue)
{
- *red = color->red;
- *green = color->green;
- *blue = color->blue;
+ if (red)
+ *red = color->red;
+ if (green)
+ *green = color->green;
+ if (blue)
+ *blue = color->blue;
}
void
diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in
index 632ad8d72..e2a62ba66 100644
--- a/src/cairo-features.h.in
+++ b/src/cairo-features.h.in
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2003 University of Southern California
+ * Copyright © 2003 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -34,19 +34,27 @@
* Carl Worth <cworth@east.isi.edu>
*/
-#ifndef _CAIRO_CONFIG_H_
-#define _CAIRO_CONFIG_H_
+#ifndef CAIRO_FEATURES_H
+#define CAIRO_FEATURES_H
#define @PS_SURFACE_FEATURE@
+#define @PDF_SURFACE_FEATURE@
+
#define @PNG_SURFACE_FEATURE@
#define @XLIB_SURFACE_FEATURE@
+#define @QUARTZ_SURFACE_FEATURE@
+
#define @XCB_SURFACE_FEATURE@
#define @GLITZ_SURFACE_FEATURE@
+#define @FT_FONT_FEATURE@
+
+#define @ATSUI_FONT_FEATURE@
+
#define @SANITY_CHECKING_FEATURE@
#endif
diff --git a/src/cairo-fixed.c b/src/cairo-fixed.c
index 32368d7fc..ee31718ef 100644
--- a/src/cairo-fixed.c
+++ b/src/cairo-fixed.c
@@ -71,3 +71,21 @@ _cairo_fixed_integer_part (cairo_fixed_t f)
{
return f >> 16;
}
+
+int
+_cairo_fixed_integer_floor (cairo_fixed_t f)
+{
+ if (f >= 0)
+ return f >> 16;
+ else
+ return -((-f - 1) >> 16) - 1;
+}
+
+int
+_cairo_fixed_integer_ceil (cairo_fixed_t f)
+{
+ if (f >= 0)
+ return ((f - 1)>>16) + 1;
+ else
+ return - (-f >> 16);
+}
diff --git a/src/cairo-font.c b/src/cairo-font.c
index 5ad9f0417..f5fc0e981 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -36,7 +36,6 @@
#include "cairoint.h"
-
/* First we implement a global font cache for named fonts. */
typedef struct {
@@ -54,9 +53,9 @@ typedef struct {
static unsigned long
_font_cache_hash (void *cache, void *key)
{
+ unsigned long hash;
cairo_font_cache_key_t *in;
in = (cairo_font_cache_key_t *) key;
- unsigned long hash;
/* 1607 and 1451 are just a couple random primes. */
hash = _cairo_hash_string (in->family);
@@ -86,12 +85,11 @@ _font_cache_create_entry (void *cache,
void *key,
void **return_value)
{
+ const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
cairo_font_cache_key_t *k;
cairo_font_cache_entry_t *entry;
k = (cairo_font_cache_key_t *) key;
- const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT;
-
/* XXX: The current freetype backend may return NULL, (for example
* if no fonts are installed), but I would like to guarantee that
* the toy API always returns at least *some* font, so I would
@@ -145,7 +143,7 @@ _font_cache_destroy_cache (void *cache)
free (cache);
}
-const struct cairo_cache_backend cairo_font_cache_backend = {
+static const cairo_cache_backend_t cairo_font_cache_backend = {
_font_cache_hash,
_font_cache_keys_equal,
_font_cache_create_entry,
@@ -153,7 +151,6 @@ const struct cairo_cache_backend cairo_font_cache_backend = {
_font_cache_destroy_cache
};
-
static void
_lock_global_font_cache (void)
{
@@ -239,8 +236,8 @@ _cairo_font_init (cairo_font_t *scaled,
}
cairo_status_t
-_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const struct cairo_font_backend *backend)
+_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
+ const cairo_font_backend_t *backend)
{
font->refcount = 1;
font->backend = backend;
@@ -476,7 +473,7 @@ _image_glyph_cache_destroy_cache (void *cache)
free (cache);
}
-const cairo_cache_backend_t cairo_image_cache_backend = {
+static const cairo_cache_backend_t cairo_image_cache_backend = {
_cairo_glyph_cache_hash,
_cairo_glyph_cache_keys_equal,
_image_glyph_cache_create_entry,
@@ -484,7 +481,6 @@ const cairo_cache_backend_t cairo_image_cache_backend = {
_image_glyph_cache_destroy_cache
};
-
void
_cairo_lock_global_image_glyph_cache()
{
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index f757db09c..b928b04fc 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -23,6 +23,8 @@
*/
#include "cairoint.h"
+#include "cairo-ft.h"
+
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
@@ -50,6 +52,16 @@ typedef struct {
} ft_font_val_t;
+/*
+ * The simple 2x2 matrix is converted into separate scale and shape
+ * factors so that hinting works right
+ */
+
+typedef struct {
+ double x_scale, y_scale;
+ double shape[2][2];
+} ft_font_transform_t;
+
static ft_font_val_t *
_create_from_face (FT_Face face, int owns_face)
{
@@ -246,7 +258,7 @@ _ft_font_cache_destroy_cache (void *cache)
free (fc);
}
-const struct cairo_cache_backend _ft_font_cache_backend = {
+static const cairo_cache_backend_t _ft_font_cache_backend = {
_ft_font_cache_hash,
_ft_font_cache_keys_equal,
_ft_font_cache_create_entry,
@@ -254,7 +266,6 @@ const struct cairo_cache_backend _ft_font_cache_backend = {
_ft_font_cache_destroy_cache
};
-
static ft_cache_t *_global_ft_cache = NULL;
static void
@@ -297,7 +308,7 @@ _get_global_ft_cache (void)
/* implement the backend interface */
-const struct cairo_font_backend cairo_ft_font_backend;
+const cairo_font_backend_t cairo_ft_font_backend;
static cairo_unscaled_font_t *
_cairo_ft_font_create (const char *family,
@@ -402,10 +413,10 @@ _cairo_ft_font_destroy (void *abstract_font)
static void
_utf8_to_ucs4 (char const *utf8,
FT_ULong **ucs4,
- size_t *nchars)
+ int *nchars)
{
int len = 0, step = 0;
- size_t n = 0, alloc = 0;
+ int n = 0, alloc = 0;
FcChar32 u = 0;
if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
@@ -433,11 +444,67 @@ _utf8_to_ucs4 (char const *utf8,
*nchars = n;
}
+/*
+ * Split a matrix into the component pieces of scale and shape
+ */
+
+static void
+_cairo_ft_font_compute_transform (ft_font_transform_t *sf, cairo_font_scale_t *sc)
+{
+ cairo_matrix_t normalized;
+ double tx, ty;
+
+ /* The font matrix has x and y "scale" components which we extract and
+ * use as character scale values. These influence the way freetype
+ * chooses hints, as well as selecting different bitmaps in
+ * hand-rendered fonts. We also copy the normalized matrix to
+ * freetype's transformation.
+ */
+
+ cairo_matrix_set_affine (&normalized,
+ sc->matrix[0][0],
+ sc->matrix[0][1],
+ sc->matrix[1][0],
+ sc->matrix[1][1],
+ 0, 0);
+
+ _cairo_matrix_compute_scale_factors (&normalized,
+ &sf->x_scale, &sf->y_scale,
+ /* XXX */ 1);
+ cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
+ cairo_matrix_get_affine (&normalized,
+ &sf->shape[0][0], &sf->shape[0][1],
+ &sf->shape[1][0], &sf->shape[1][1],
+ &tx, &ty);
+}
+
+/*
+ * Set the font transformation
+ */
+
+static void
+_cairo_ft_font_install_transform (ft_font_transform_t *sf, FT_Face face)
+{
+ FT_Matrix mat;
+
+ mat.xx = DOUBLE_TO_16_16(sf->shape[0][0]);
+ mat.yx = -DOUBLE_TO_16_16(sf->shape[0][1]);
+ mat.xy = -DOUBLE_TO_16_16(sf->shape[1][0]);
+ mat.yy = DOUBLE_TO_16_16(sf->shape[1][1]);
+
+ FT_Set_Transform(face, &mat, NULL);
+
+ FT_Set_Char_Size(face,
+ (FT_F26Dot6) (sf->x_scale * 64.0),
+ (FT_F26Dot6) (sf->y_scale * 64.0),
+ 0, 0);
+}
+
static void
_install_font_scale (cairo_font_scale_t *sc, FT_Face face)
{
cairo_matrix_t normalized;
- double scale_x, scale_y;
+ double x_scale, y_scale;
double xx, xy, yx, yy, tx, ty;
FT_Matrix mat;
@@ -455,8 +522,9 @@ _install_font_scale (cairo_font_scale_t *sc, FT_Face face)
sc->matrix[1][1],
0, 0);
- _cairo_matrix_compute_scale_factors (&normalized, &scale_x, &scale_y);
- cairo_matrix_scale (&normalized, 1.0 / scale_x, 1.0 / scale_y);
+ _cairo_matrix_compute_scale_factors (&normalized, &x_scale, &y_scale,
+ /* XXX */ 1);
+ cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale);
cairo_matrix_get_affine (&normalized,
&xx /* 00 */ , &yx /* 01 */,
&xy /* 10 */, &yy /* 11 */,
@@ -470,8 +538,8 @@ _install_font_scale (cairo_font_scale_t *sc, FT_Face face)
FT_Set_Transform(face, &mat, NULL);
FT_Set_Pixel_Sizes(face,
- (FT_UInt) scale_x,
- (FT_UInt) scale_y);
+ (FT_UInt) x_scale,
+ (FT_UInt) y_scale);
}
static cairo_status_t
@@ -481,6 +549,9 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
cairo_glyph_t **glyphs,
int *nglyphs)
{
+ double x = 0., y = 0.;
+ size_t i;
+ FT_ULong *ucs4 = NULL;
cairo_ft_font_t *font = abstract_font;
FT_Face face = font->val->face;
cairo_glyph_cache_key_t key;
@@ -490,10 +561,6 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
key.unscaled = &font->base;
key.scale = *sc;
- double x = 0., y = 0.;
- size_t i;
- FT_ULong *ucs4 = NULL;
-
_utf8_to_ucs4 (utf8, &ucs4, nglyphs);
if (ucs4 == NULL)
@@ -527,7 +594,7 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
continue;
x += val->extents.x_advance;
- y -= val->extents.y_advance;
+ y += val->extents.y_advance;
}
_cairo_unlock_global_image_glyph_cache ();
@@ -544,13 +611,19 @@ _cairo_ft_font_font_extents (void *abstract_font,
cairo_ft_font_t *font = abstract_font;
FT_Face face = font->val->face;
FT_Size_Metrics *metrics = &face->size->metrics;
+ ft_font_transform_t sf;
- _install_font_scale (sc, face);
+ _cairo_ft_font_compute_transform (&sf, sc);
+ _cairo_ft_font_install_transform (&sf, face);
- extents->ascent = DOUBLE_FROM_26_6(metrics->ascender);
- extents->descent = DOUBLE_FROM_26_6(metrics->descender);
- extents->height = DOUBLE_FROM_26_6(metrics->height);
- extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance);
+ /*
+ * Get to unscaled metrics so that the upper level can get back to
+ * user space
+ */
+ extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / sf.y_scale;
+ extents->descent = DOUBLE_FROM_26_6(metrics->descender) / sf.y_scale;
+ extents->height = DOUBLE_FROM_26_6(metrics->height) / sf.y_scale;
+ extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / sf.x_scale;
/* FIXME: this doesn't do vertical layout atm. */
extents->max_y_advance = 0.0;
@@ -614,7 +687,7 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
cairo_ft_font_create_for_ft_face accept an
FcPattern. */
glyph_min.x = glyphs[i].x + img->extents.x_bearing;
- glyph_min.y = glyphs[i].y - img->extents.y_bearing;
+ glyph_min.y = glyphs[i].y + img->extents.y_bearing;
glyph_max.x = glyph_min.x + img->extents.width;
glyph_max.y = glyph_min.y + img->extents.height;
@@ -635,12 +708,12 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
}
_cairo_unlock_global_image_glyph_cache ();
- extents->x_bearing = total_min.x - origin.x;
- extents->y_bearing = total_min.y - origin.y;
- extents->width = total_max.x - total_min.x;
- extents->height = total_max.y - total_min.y;
+ extents->x_bearing = (total_min.x - origin.x);
+ extents->y_bearing = (total_min.y - origin.y);
+ extents->width = (total_max.x - total_min.x);
+ extents->height = (total_max.y - total_min.y);
extents->x_advance = glyphs[i-1].x + (img == NULL ? 0 : img->extents.x_advance) - origin.x;
- extents->y_advance = glyphs[i-1].y + 0 - origin.y;
+ extents->y_advance = glyphs[i-1].y + (img == NULL ? 0 : img->extents.y_advance) - origin.y;
return CAIRO_STATUS_SUCCESS;
}
@@ -688,7 +761,7 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
continue;
x1 = _cairo_fixed_from_double (glyphs[i].x + img->size.x);
- y1 = _cairo_fixed_from_double (glyphs[i].y - img->size.y);
+ y1 = _cairo_fixed_from_double (glyphs[i].y + img->size.y);
x2 = x1 + _cairo_fixed_from_double (img->size.width);
y2 = y1 + _cairo_fixed_from_double (img->size.height);
@@ -763,10 +836,10 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
&(img->image->base),
surface,
source_x + x + img->size.x,
- source_y + y - img->size.y,
+ source_y + y + img->size.y,
0, 0,
x + img->size.x,
- y - img->size.y,
+ y + img->size.y,
(double) img->size.width,
(double) img->size.height);
@@ -919,21 +992,39 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
FT_BBox cbox;
FT_Bitmap bitmap;
FT_Glyph_Metrics *metrics;
+ ft_font_transform_t sf;
glyphslot = font->val->face->glyph;
metrics = &glyphslot->metrics;
- _install_font_scale (&val->key.scale, font->val->face);
+ _cairo_ft_font_compute_transform (&sf, &val->key.scale);
+ _cairo_ft_font_install_transform (&sf, font->val->face);
if (FT_Load_Glyph (font->val->face, val->key.index, FT_LOAD_DEFAULT) != 0)
return CAIRO_STATUS_NO_MEMORY;
- val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX);
- val->extents.y_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingY);
- val->extents.width = DOUBLE_FROM_26_6 (metrics->width);
- val->extents.height = DOUBLE_FROM_26_6 (metrics->height);
- val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.x);
- val->extents.y_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.y);
+ /*
+ * Note: the font's coordinate system is upside down from ours, so the
+ * Y coordinates of the bearing and advance need to be negated.
+ *
+ * Scale metrics back to glyph space from the scaled glyph space returned
+ * by FreeType
+ */
+
+ val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / sf.x_scale;
+ val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / sf.y_scale;
+
+ val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / sf.x_scale;
+ val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / sf.y_scale;
+
+ /*
+ * use untransformed advance values
+ * XXX uses horizontal advance only at present;
+ should provide FT_LOAD_VERTICAL_LAYOUT
+ */
+
+ val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->metrics.horiAdvance) / sf.x_scale;
+ val->extents.y_advance = 0 / sf.y_scale;
outline = &glyphslot->outline;
@@ -982,16 +1073,21 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
_cairo_image_surface_assume_ownership_of_data (val->image);
}
-
+
+ /*
+ * Note: the font's coordinate system is upside down from ours, so the
+ * Y coordinate of the control box needs to be negated.
+ */
+
val->size.width = (unsigned short) width;
val->size.height = (unsigned short) height;
- val->size.x = (short) (cbox.xMin >> 6);
- val->size.y = (short) (cbox.yMax >> 6);
+ val->size.x = (short) (cbox.xMin >> 6);
+ val->size.y = - (short) (cbox.yMax >> 6);
return CAIRO_STATUS_SUCCESS;
}
-const struct cairo_font_backend cairo_ft_font_backend = {
+const cairo_font_backend_t cairo_ft_font_backend = {
_cairo_ft_font_create,
_cairo_ft_font_destroy,
_cairo_ft_font_font_extents,
diff --git a/src/cairo-ft.h b/src/cairo-ft.h
new file mode 100644
index 000000000..57d439ab2
--- /dev/null
+++ b/src/cairo-ft.h
@@ -0,0 +1,62 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_FT_H
+#define CAIRO_FT_H
+#ifdef CAIRO_HAS_FT_FONT
+
+/* Fontconfig/Freetype platform-specific font interface */
+
+#include <fontconfig/fontconfig.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+cairo_font_t *
+cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern);
+
+cairo_font_t *
+cairo_ft_font_create_for_ft_face (FT_Face face);
+
+FT_Face
+cairo_ft_font_face (cairo_font_t *ft_font);
+
+FcPattern *
+cairo_ft_font_pattern (cairo_font_t *ft_font);
+
+#endif /* CAIRO_HAS_FT_FONT */
+#endif /* CAIRO_FT_H */
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 21e889204..69fc82f2e 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -25,6 +25,7 @@
*/
#include "cairoint.h"
+#include "cairo-glitz.h"
#define GLITZ_FIXED_TO_FLOAT(f) \
(((glitz_float_t) (f)) / 65536)
@@ -52,8 +53,6 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
return;
- glitz_surface_reference (surface);
-
crsurface = cairo_glitz_surface_create (surface);
if (crsurface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
@@ -65,10 +64,9 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
cairo_surface_destroy (crsurface);
}
-typedef struct cairo_glitz_surface {
+typedef struct _cairo_glitz_surface {
cairo_surface_t base;
- unsigned long features;
glitz_surface_t *surface;
glitz_format_t *format;
@@ -119,21 +117,29 @@ _cairo_glitz_surface_get_image (void *abstract_surface)
width = glitz_surface_get_width (surface->surface);
height = glitz_surface_get_height (surface->surface);
- if (surface->format->red_size > 0) {
+ if (surface->format->type == GLITZ_FORMAT_TYPE_COLOR) {
+ if (surface->format->color.red_size > 0) {
+ format.bpp = 32;
+
+ if (surface->format->color.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;
+ }
+ } else {
format.bpp = 32;
-
- if (surface->format->alpha_size > 0)
- format.alpha_mask = 0xff000000;
- else
- format.alpha_mask = 0x0;
-
+ format.alpha_mask = 0xff000000;
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;
}
pf.masks.bpp = format.bpp;
@@ -306,8 +312,6 @@ _glitz_operator (cairo_operator_t op)
return GLITZ_OPERATOR_XOR;
case CAIRO_OPERATOR_ADD:
return GLITZ_OPERATOR_ADD;
- case CAIRO_OPERATOR_SATURATE:
- return GLITZ_OPERATOR_SATURATE;
case CAIRO_OPERATOR_OVER:
default:
return GLITZ_OPERATOR_OVER;
@@ -319,14 +323,17 @@ _glitz_surface_create_solid (glitz_surface_t *other,
glitz_format_name_t format_name,
glitz_color_t *color)
{
- glitz_surface_t *surface;
+ glitz_drawable_t *drawable;
glitz_format_t *format;
+ glitz_surface_t *surface;
+
+ drawable = glitz_surface_get_drawable (other);
- format = glitz_surface_find_similar_standard_format (other, format_name);
+ format = glitz_find_standard_format (drawable, format_name);
if (format == NULL)
return NULL;
- surface = glitz_surface_create_similar (other, format, 1, 1);
+ surface = glitz_surface_create (drawable, format, 1, 1);
if (surface == NULL)
return NULL;
@@ -337,70 +344,126 @@ _glitz_surface_create_solid (glitz_surface_t *other,
return surface;
}
+static glitz_status_t
+_glitz_ensure_target (glitz_surface_t *surface)
+{
+ glitz_drawable_t *drawable;
+
+ drawable = glitz_surface_get_attached_drawable (surface);
+ if (!drawable) {
+ glitz_drawable_format_t *dformat;
+ glitz_drawable_format_t templ;
+ glitz_format_t *format;
+ glitz_drawable_t *pbuffer;
+ glitz_pbuffer_attributes_t attributes;
+ unsigned long mask;
+ int i;
+
+ format = glitz_surface_get_format (surface);
+ if (format->type != GLITZ_FORMAT_TYPE_COLOR)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ drawable = glitz_surface_get_drawable (surface);
+ dformat = glitz_drawable_get_format (drawable);
+
+ templ.types.pbuffer = 1;
+ mask = GLITZ_FORMAT_PBUFFER_MASK;
+
+ templ.samples = dformat->samples;
+ mask |= GLITZ_FORMAT_SAMPLES_MASK;
+
+ i = 0;
+ do {
+ dformat = glitz_find_similar_drawable_format (drawable,
+ mask, &templ, i++);
+
+ if (dformat) {
+ int sufficient = 1;
+
+ if (format->color.red_size) {
+ if (dformat->color.red_size < format->color.red_size)
+ sufficient = 0;
+ }
+ if (format->color.alpha_size) {
+ if (dformat->color.alpha_size < format->color.alpha_size)
+ sufficient = 0;
+ }
+
+ if (sufficient)
+ break;
+ }
+ } while (dformat);
+
+ if (!dformat)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ attributes.width = glitz_surface_get_width (surface);
+ attributes.height = glitz_surface_get_height (surface);
+ mask = GLITZ_PBUFFER_WIDTH_MASK | GLITZ_PBUFFER_HEIGHT_MASK;
+
+ pbuffer = glitz_create_pbuffer_drawable (drawable, dformat,
+ &attributes, mask);
+ if (!pbuffer)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (glitz_drawable_get_width (pbuffer) < attributes.width ||
+ glitz_drawable_get_height (pbuffer) < attributes.height) {
+ glitz_drawable_destroy (pbuffer);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ glitz_surface_attach (surface, pbuffer,
+ GLITZ_DRAWABLE_BUFFER_FRONT_COLOR,
+ 0, 0);
+
+ glitz_drawable_destroy (pbuffer);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static glitz_format_name_t
+_glitz_format (cairo_format_t format)
+{
+ switch (format) {
+ default:
+ case CAIRO_FORMAT_ARGB32:
+ return GLITZ_STANDARD_ARGB32;
+ case CAIRO_FORMAT_RGB24:
+ return GLITZ_STANDARD_RGB24;
+ case CAIRO_FORMAT_A8:
+ return GLITZ_STANDARD_A8;
+ case CAIRO_FORMAT_A1:
+ return GLITZ_STANDARD_A1;
+ }
+}
+
static cairo_surface_t *
_cairo_glitz_surface_create_similar (void *abstract_src,
cairo_format_t format,
- int drawable,
+ int draw,
int width,
int height)
{
cairo_glitz_surface_t *src = abstract_src;
- glitz_surface_t *surface;
cairo_surface_t *crsurface;
- glitz_format_t *glitz_format;
- glitz_format_t templ;
- unsigned long mask;
+ glitz_drawable_t *drawable;
+ glitz_surface_t *surface;
+ glitz_format_t *gformat;
+
+ drawable = glitz_surface_get_drawable (src->surface);
- templ.read.offscreen = 1;
- mask = GLITZ_FORMAT_READ_OFFSCREEN_MASK;
+ gformat = glitz_find_standard_format (drawable, _glitz_format (format));
+ if (gformat == NULL)
+ return NULL;
- if (drawable) {
- templ.draw.offscreen = 1;
- if (src->features & GLITZ_FEATURE_OFFSCREEN_MULTISAMPLE_MASK) {
- templ.multisample.samples = src->format->multisample.samples;
- mask |= GLITZ_FORMAT_MULTISAMPLE_SAMPLES_MASK;
- }
- } else
- templ.draw.offscreen = 0;
-
- mask |= GLITZ_FORMAT_DRAW_OFFSCREEN_MASK;
-
- switch (format) {
- case CAIRO_FORMAT_A1:
- case CAIRO_FORMAT_A8:
- templ.alpha_size = 8;
- mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
- break;
- case CAIRO_FORMAT_RGB24:
- templ.red_size = 8;
- mask |= GLITZ_FORMAT_RED_SIZE_MASK;
- break;
- case CAIRO_FORMAT_ARGB32:
- default:
- templ.alpha_size = templ.red_size = 8;
- mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
- mask |= GLITZ_FORMAT_RED_SIZE_MASK;
- break;
- }
-
- glitz_format =
- glitz_surface_find_similar_format (src->surface, mask, &templ, 0);
- if (glitz_format == NULL) {
- mask &= ~GLITZ_FORMAT_DRAW_OFFSCREEN_MASK;
- glitz_format =
- glitz_surface_find_similar_format (src->surface, mask, &templ, 0);
- if (glitz_format == NULL)
- return NULL;
- }
-
- surface = glitz_surface_create_similar (src->surface, glitz_format,
- width, height);
+ surface = glitz_surface_create (drawable, gformat, width, height);
if (surface == NULL)
return NULL;
crsurface = cairo_glitz_surface_create (surface);
- if (crsurface == NULL)
- glitz_surface_destroy (surface);
+
+ glitz_surface_destroy (surface);
return crsurface;
}
@@ -449,6 +512,9 @@ _glitz_composite (glitz_operator_t op,
glitz_buffer_t *geometry,
glitz_geometry_format_t *format)
{
+ if (_glitz_ensure_target (dst))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (glitz_surface_get_status (dst))
return CAIRO_STATUS_NO_TARGET_SURFACE;
@@ -494,6 +560,9 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
cairo_glitz_surface_t *mask_clone = NULL;
cairo_int_status_t status;
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (generic_src->backend != dst->base.backend) {
src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src,
CAIRO_FORMAT_ARGB32);
@@ -540,6 +609,9 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
{
cairo_glitz_surface_t *dst = abstract_dst;
glitz_color_t glitz_color;
+
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
glitz_color.red = color->red_short;
glitz_color.green = color->green_short;
@@ -613,9 +685,16 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
free (data);
return status;
- } else
+ } else {
+ if (glitz_surface_get_width (dst->surface) != 1 ||
+ glitz_surface_get_height (dst->surface) != 1) {
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
glitz_set_rectangles (dst->surface, &glitz_color,
(glitz_rectangle_t *) rects, n_rects);
+ }
return CAIRO_STATUS_SUCCESS;
}
@@ -639,6 +718,9 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
int x_dst, y_dst, x_rel, y_rel, width, height;
void *data;
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (generic_src->backend != dst->base.backend)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -764,10 +846,13 @@ _cairo_glitz_surface_create_pattern (void *abstract_dst,
break;
/* fall-through */
case CAIRO_PATTERN_LINEAR: {
+ glitz_drawable_t *drawable;
glitz_fixed16_16_t *params;
int i, n_params;
- if (!(dst->features & GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
+ drawable = glitz_surface_get_drawable (dst->surface);
+ if (!(glitz_drawable_get_features (drawable) &
+ GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
break;
if (pattern->filter != CAIRO_FILTER_BILINEAR)
@@ -885,7 +970,7 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static const struct cairo_surface_backend cairo_glitz_surface_backend = {
+static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_create_similar,
_cairo_glitz_surface_destroy,
_cairo_glitz_surface_pixels_per_inch,
@@ -918,8 +1003,8 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
_cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend);
+ glitz_surface_reference (surface);
crsurface->surface = surface;
- crsurface->features = glitz_surface_get_features (surface);
crsurface->format = glitz_surface_get_format (surface);
_cairo_pattern_init (&crsurface->pattern);
diff --git a/src/cairo-glitz.h b/src/cairo-glitz.h
new file mode 100644
index 000000000..350d10233
--- /dev/null
+++ b/src/cairo-glitz.h
@@ -0,0 +1,53 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_GLITZ_H
+#define CAIRO_GLITZ_H
+#ifdef CAIRO_HAS_GLITZ_SURFACE
+
+#include <glitz.h>
+
+void
+cairo_set_target_glitz (cairo_t *cr,
+ glitz_surface_t *surface);
+
+cairo_surface_t *
+cairo_glitz_surface_create (glitz_surface_t *surface);
+
+#endif /* CAIRO_HAS_GLITZ_SURFACE */
+#endif /* CAIRO_GLITZ_H */
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 9f9de69e1..e855a7a66 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -86,7 +86,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->clip.region = NULL;
gstate->clip.surface = NULL;
- gstate->pattern = _cairo_pattern_create_solid (1.0, 1.0, 1.0);
+ gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0);
gstate->alpha = 1.0;
gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
@@ -1096,8 +1096,10 @@ _cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_re
cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
}
- *x_ret = x;
- *y_ret = y;
+ if (x_ret)
+ *x_ret = x;
+ if (y_ret)
+ *y_ret = y;
return CAIRO_STATUS_SUCCESS;
}
@@ -1363,6 +1365,54 @@ BAIL:
return status;
}
+static cairo_status_t
+_calculate_region_for_intermediate_clip_surface (pixman_region16_t *out,
+ cairo_box_t *extents,
+ cairo_clip_rec_t *clip_rect)
+{
+ cairo_status_t status;
+ pixman_region16_t *extents_region, *clip_region;
+ pixman_box16_t clip_box, pixman_extents;
+
+ pixman_extents.x1 = _cairo_fixed_integer_floor (extents->p1.x);
+ pixman_extents.y1 = _cairo_fixed_integer_floor (extents->p1.y);
+ pixman_extents.x2 = _cairo_fixed_integer_ceil (extents->p2.x);
+ pixman_extents.y2 = _cairo_fixed_integer_ceil (extents->p2.y);
+ extents_region = pixman_region_create_simple (&pixman_extents);
+ if (extents_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ clip_box.x1 = clip_rect->x;
+ clip_box.y1 = clip_rect->y;
+ clip_box.x2 = clip_rect->x + clip_rect->width;
+ clip_box.y2 = clip_rect->y + clip_rect->height;
+ clip_region = pixman_region_create_simple (&clip_box);
+ if (clip_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL1;
+ }
+
+ if (pixman_region_intersect (out,
+ extents_region,
+ clip_region)
+ == PIXMAN_REGION_STATUS_FAILURE)
+ status = CAIRO_STATUS_NO_MEMORY;
+ else
+ status = CAIRO_STATUS_SUCCESS;
+
+ pixman_region_destroy (extents_region);
+ BAIL1:
+ pixman_region_destroy (clip_region);
+
+ BAIL0:
+ return status;
+}
+
+
/* Warning: This call modifies the coordinates of traps */
static cairo_status_t
_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
@@ -1385,25 +1435,38 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
int i;
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, 0.);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
- &empty_color);
- if (intermediate == NULL) {
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
status = CAIRO_STATUS_NO_MEMORY;
goto BAIL0;
}
+
+ _cairo_traps_extents (traps, &extents);
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &extents,
+ &gstate->clip);
+ if (status)
+ goto BAIL1;
+
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
/* Ugh. The cairo_composite/(Render) interface doesn't allow
an offset for the trapezoids. Need to manually shift all
- the coordinates to align with the offset origin of the clip
- surface. */
- xoff = _cairo_fixed_from_double (gstate->clip.x);
- yoff = _cairo_fixed_from_double (gstate->clip.y);
+ the coordinates to align with the offset origin of the
+ intermediate surface. */
+ xoff = _cairo_fixed_from_int (draw_extents->x1);
+ yoff = _cairo_fixed_from_int (draw_extents->y1);
for (i=0, t=traps->traps; i < traps->num_traps; i++, t++) {
t->top -= yoff;
t->bottom -= yoff;
@@ -1428,11 +1491,22 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
_cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0);
_cairo_pattern_set_alpha (&pattern, 1.0);
- _cairo_traps_extents (traps, &extents);
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
goto BAIL1;
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, 0.);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
+ &empty_color);
+ if (intermediate == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL2;
+ }
+
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
pattern.source, intermediate,
x_src,
@@ -1440,30 +1514,32 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
traps->traps,
traps->num_traps);
if (status)
- goto BAIL2;
+ goto BAIL3;
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
gstate->clip.surface,
NULL,
intermediate,
- 0, 0, 0, 0, 0, 0,
- gstate->clip.width, gstate->clip.height);
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
+ 0, 0,
+ 0, 0,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
if (status)
- goto BAIL2;
+ goto BAIL3;
_cairo_pattern_fini (&pattern);
_cairo_pattern_init_copy (&pattern, src);
- extents.p1.x = _cairo_fixed_from_int (gstate->clip.x);
- extents.p1.y = _cairo_fixed_from_int (gstate->clip.y);
- extents.p2.x =
- _cairo_fixed_from_int (gstate->clip.x + gstate->clip.width);
- extents.p2.y =
- _cairo_fixed_from_int (gstate->clip.y + gstate->clip.height);
+ extents.p1.x = _cairo_fixed_from_int (draw_extents->x1);
+ extents.p1.y = _cairo_fixed_from_int (draw_extents->y1);
+ extents.p2.x = _cairo_fixed_from_int (draw_extents->x2);
+ extents.p2.y = _cairo_fixed_from_int (draw_extents->y2);
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
- goto BAIL2;
+ goto BAIL3;
if (dst == gstate->clip.surface)
xoff = yoff = 0;
@@ -1474,13 +1550,16 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
0, 0,
xoff >> 16,
yoff >> 16,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+
- BAIL2:
+ BAIL3:
cairo_surface_destroy (intermediate);
- BAIL1:
+ BAIL2:
_cairo_pattern_fini (&pattern);
+ BAIL1:
+ pixman_region_destroy (draw_region);
BAIL0:
if (status)
@@ -1705,6 +1784,25 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
return 0;
}
+/* Reset surface clip region to the one in the gstate */
+cairo_status_t
+_cairo_gstate_restore_external_state (cairo_gstate_t *gstate)
+{
+ cairo_status_t status;
+
+ status = CAIRO_STATUS_SUCCESS;
+
+ if (gstate->surface)
+ status = _cairo_surface_set_clip_region (gstate->surface,
+ gstate->clip.region);
+
+ /* If not supported we're already using surface clipping */
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ status = CAIRO_STATUS_SUCCESS;
+
+ return status;
+}
+
cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate)
{
@@ -1762,6 +1860,10 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_traps_fini (&traps);
return status;
}
+
+ /* Fall through as status == CAIRO_INT_STATUS_UNSUPPORTED
+ means that backend doesn't support clipping regions and
+ mask surface clipping should be used instead. */
}
/* Otherwise represent the clip as a mask surface. */
@@ -1799,7 +1901,7 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_traps_fini (&traps);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@@ -1809,7 +1911,7 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
int height)
{
- /* We are dealing with 5 coordinate spaces in this function. this makes
+ /* We are dealing with 6 coordinate spaces in this function. this makes
* it ugly.
*
* - "Image" space is the space of the surface we're reading pixels from.
@@ -1833,12 +1935,16 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
* a bounding box around the "clip path", situated somewhere in device
* space. The clip path is already painted on the clip surface.
*
+ * - "Intermediate" space is the subset of the Clip space that the
+ * drawing will affect, and we allocate an intermediate surface
+ * of this size so that we can paint in it.
+ *
* - "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
+ * (in fact, there is a 7th 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
@@ -1897,15 +2003,16 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
_cairo_pattern_init (&pattern);
+ pattern_extents.p1.x = _cairo_fixed_from_double (device_x);
+ pattern_extents.p1.y = _cairo_fixed_from_double (device_y);
+ pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
+ pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
+
if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) ||
(gstate->alpha != 1.0)) {
/* I'm allowing any type of pattern for the mask right now.
Maybe this is bad. Will allow for some cool effects though. */
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- 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;
@@ -1915,13 +2022,36 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
{
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &pattern_extents,
+ &gstate->clip);
+ if (status)
+ goto BAIL1;
+
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
+
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, .0);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
&empty_color);
/* it is not completely clear what the "right" way to combine the
@@ -1935,27 +2065,33 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
gstate->clip.surface,
pattern.source,
intermediate,
- 0, 0,
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
0, 0,
0, 0,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (gstate->operator,
surface,
intermediate,
gstate->surface,
- gstate->clip.x, gstate->clip.y,
+ draw_extents->x1, draw_extents->y1,
0, 0,
- gstate->clip.x, gstate->clip.y,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x1, draw_extents->y1,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
- BAIL:
+ BAIL2:
cairo_surface_destroy (intermediate);
+ BAIL1:
+ pixman_region_destroy (draw_region);
+ BAIL0:
+ ;
}
else
{
@@ -1992,21 +2128,14 @@ _cairo_gstate_select_font (cairo_gstate_t *gstate,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
- cairo_unscaled_font_t *tmp;
-
- tmp = _cairo_unscaled_font_create (family, slant, weight);
+ if (gstate->font)
+ _cairo_unscaled_font_destroy (gstate->font);
- if (tmp == NULL)
+ gstate->font = _cairo_unscaled_font_create (family, slant, weight);
+ if (gstate->font == NULL)
return CAIRO_STATUS_NO_MEMORY;
- if (gstate->font != tmp)
- {
- if (gstate->font != NULL)
- _cairo_unscaled_font_destroy (gstate->font);
-
- cairo_matrix_set_identity (&gstate->font_matrix);
- gstate->font = tmp;
- }
+ cairo_matrix_set_identity (&gstate->font_matrix);
return CAIRO_STATUS_SUCCESS;
}
@@ -2171,30 +2300,27 @@ _cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
{
cairo_int_status_t status;
cairo_font_scale_t sc;
- double dummy = 0.0;
+ double font_scale_x, font_scale_y;
_build_font_scale (gstate, &sc);
status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents);
- /* The font responded in device space; convert to user space. */
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->ascent);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->descent);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->height);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->max_x_advance,
- &extents->max_y_advance);
-
+ _cairo_matrix_compute_scale_factors (&gstate->font_matrix,
+ &font_scale_x, &font_scale_y,
+ /* XXX */ 1);
+
+ /*
+ * The font responded in unscaled units, scale by the font
+ * matrix scale factors to get to user space
+ */
+
+ extents->ascent *= font_scale_y;
+ extents->descent *= font_scale_y;
+ extents->height *= font_scale_y;
+ extents->max_x_advance *= font_scale_x;
+ extents->max_y_advance *= font_scale_y;
+
return status;
}
@@ -2208,18 +2334,20 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
cairo_font_scale_t sc;
cairo_point_t point;
- double dev_x, dev_y;
+ double origin_x, origin_y;
int i;
_build_font_scale (gstate, &sc);
status = _cairo_path_current_point (&gstate->path, &point);
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- dev_x = 0.0;
- dev_y = 0.0;
+ origin_x = 0.0;
+ origin_y = 0.0;
} else {
- dev_x = _cairo_fixed_to_double (point.x);
- dev_y = _cairo_fixed_to_double (point.y);
+ origin_x = _cairo_fixed_to_double (point.x);
+ origin_y = _cairo_fixed_to_double (point.y);
+ cairo_matrix_transform_point (&gstate->ctm_inverse,
+ &origin_x, &origin_y);
}
status = _cairo_unscaled_font_text_to_glyphs (gstate->font,
@@ -2228,15 +2356,16 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
return status;
- /* The font responded in device space, starting from (0,0); add any
- current point offset in device space, and convert to user space. */
+ /* The font responded in glyph space, starting from (0,0). Convert to
+ user space by applying the font transform, then add any current point
+ offset. */
for (i = 0; i < *nglyphs; ++i) {
- (*glyphs)[i].x += dev_x;
- (*glyphs)[i].y += dev_y;
- cairo_matrix_transform_point (&gstate->ctm_inverse,
- &((*glyphs)[i].x),
- &((*glyphs)[i].y));
+ cairo_matrix_transform_point (&gstate->font_matrix,
+ &((*glyphs)[i].x),
+ &((*glyphs)[i].y));
+ (*glyphs)[i].x += origin_x;
+ (*glyphs)[i].y += origin_y;
}
return CAIRO_STATUS_SUCCESS;
@@ -2265,44 +2394,88 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
int num_glyphs,
cairo_text_extents_t *extents)
{
- cairo_status_t status;
- cairo_glyph_t *transformed_glyphs;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_glyph_t origin_glyph;
+ cairo_text_extents_t origin_extents;
cairo_font_scale_t sc;
int i;
+ double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
+ double x_pos = 0.0, y_pos = 0.0;
+ int set = 0;
- _build_font_scale (gstate, &sc);
-
- transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
- if (transformed_glyphs == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < num_glyphs; ++i)
+ if (!num_glyphs)
{
- transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &transformed_glyphs[i].x,
- &transformed_glyphs[i].y);
+ extents->x_bearing = 0.0;
+ extents->y_bearing = 0.0;
+ extents->width = 0.0;
+ extents->height = 0.0;
+ extents->x_advance = 0.0;
+ extents->y_advance = 0.0;
+ return CAIRO_STATUS_SUCCESS;
}
- status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc,
- transformed_glyphs, num_glyphs,
- extents);
-
- /* The font responded in device space; convert to user space. */
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->x_bearing,
- &extents->y_bearing);
+ _build_font_scale (gstate, &sc);
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->width,
- &extents->height);
+ for (i = 0; i < num_glyphs; i++)
+ {
+ double x, y;
+ double wm, hm;
+
+ origin_glyph = glyphs[i];
+ origin_glyph.x = 0.0;
+ origin_glyph.y = 0.0;
+ status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc,
+ &origin_glyph, 1,
+ &origin_extents);
+
+ /*
+ * Transform font space metrics into user space metrics
+ * by running the corners through the font matrix and
+ * expanding the bounding box as necessary
+ */
+ x = origin_extents.x_bearing;
+ y = origin_extents.y_bearing;
+ cairo_matrix_transform_point (&gstate->font_matrix,
+ &x, &y);
+
+ for (hm = 0.0; hm <= 1.0; hm += 1.0)
+ for (wm = 0.0; wm <= 1.0; wm += 1.0)
+ {
+ x = origin_extents.x_bearing + origin_extents.width * wm;
+ y = origin_extents.y_bearing + origin_extents.height * hm;
+ cairo_matrix_transform_point (&gstate->font_matrix,
+ &x, &y);
+ x += glyphs[i].x;
+ y += glyphs[i].y;
+ if (!set)
+ {
+ min_x = max_x = x;
+ min_y = max_y = y;
+ set = 1;
+ }
+ else
+ {
+ if (x < min_x) min_x = x;
+ if (x > max_x) max_x = x;
+ if (y < min_y) min_y = y;
+ if (y > max_y) max_y = y;
+ }
+ }
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->x_advance,
- &extents->y_advance);
+ x = origin_extents.x_advance;
+ y = origin_extents.y_advance;
+ cairo_matrix_transform_point (&gstate->font_matrix,
+ &x, &y);
+ x_pos = glyphs[i].x + x;
+ y_pos = glyphs[i].y + y;
+ }
- free (transformed_glyphs);
+ extents->x_bearing = min_x - glyphs[0].x;
+ extents->y_bearing = min_y - glyphs[0].y;
+ extents->width = max_x - min_x;
+ extents->height = max_y - min_y;
+ extents->x_advance = x_pos - glyphs[0].x;
+ extents->y_advance = y_pos - glyphs[0].y;
return status;
}
@@ -2338,55 +2511,84 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
&bbox);
if (status)
- return status;
+ goto CLEANUP_GLYPHS;
status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
if (status)
- return status;
+ goto CLEANUP_GLYPHS;
if (gstate->clip.surface)
{
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
+
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &bbox,
+ &gstate->clip);
+ if (status) {
+ goto BAIL1;
+ }
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
+
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, .0);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
&empty_color);
+ if (intermediate == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL1;
+ }
- /* move the glyphs again, from dev space to clip space */
+ /* move the glyphs again, from dev space to intermediate space */
for (i = 0; i < num_glyphs; ++i)
{
- transformed_glyphs[i].x -= gstate->clip.x;
- transformed_glyphs[i].y -= gstate->clip.y;
+ transformed_glyphs[i].x -= draw_extents->x1;
+ transformed_glyphs[i].y -= draw_extents->y1;
}
status = _cairo_unscaled_font_show_glyphs (gstate->font,
&sc,
CAIRO_OPERATOR_ADD,
pattern.source, intermediate,
- gstate->clip.x - pattern.source_offset.x,
- gstate->clip.y - pattern.source_offset.y,
+ draw_extents->x1 - pattern.source_offset.x,
+ draw_extents->y1 - pattern.source_offset.y,
transformed_glyphs, num_glyphs);
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
gstate->clip.surface,
NULL,
intermediate,
- 0, 0,
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
0, 0,
0, 0,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (gstate->operator,
pattern.source,
@@ -2394,14 +2596,17 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
gstate->surface,
0, 0,
0, 0,
- gstate->clip.x,
- gstate->clip.y,
- gstate->clip.width,
- gstate->clip.height);
-
- BAIL:
- cairo_surface_destroy (intermediate);
+ draw_extents->x1,
+ draw_extents->y1,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+ BAIL2:
+ cairo_surface_destroy (intermediate);
+ BAIL1:
+ pixman_region_destroy (draw_region);
+ BAIL0:
+ ;
}
else
{
@@ -2416,6 +2621,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
_cairo_pattern_fini (&pattern);
+ CLEANUP_GLYPHS:
free (transformed_glyphs);
return status;
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index a33d69a04..b097b609b 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -43,7 +43,7 @@
* Packard.
*/
-static cairo_cache_arrangement_t cache_arrangements [] = {
+static const cairo_cache_arrangement_t cache_arrangements [] = {
{ 16, 43, 41 },
{ 32, 73, 71 },
{ 64, 151, 149 },
@@ -114,7 +114,6 @@ static cairo_cache_arrangement_t cache_arrangements [] = {
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
#ifdef CAIRO_DO_SANITY_CHECKING
-#include <assert.h>
static void
_cache_sane_state (cairo_cache_t *cache)
{
@@ -122,13 +121,12 @@ _cache_sane_state (cairo_cache_t *cache)
assert (cache->entries != NULL);
assert (cache->backend != NULL);
assert (cache->arrangement != NULL);
- assert (cache->refcount > 0);
- assert (cache->used_memory <= cache->max_memory);
+ /* Cannot check this, a single object may larger */
+ /* assert (cache->used_memory <= cache->max_memory); */
assert (cache->live_entries <= cache->arrangement->size);
}
#else
#define _cache_sane_state(c)
-#define assert(x)
#endif
static void
@@ -140,7 +138,7 @@ _entry_destroy (cairo_cache_t *cache, unsigned long i)
{
cairo_cache_entry_base_t *entry = cache->entries[i];
assert(cache->live_entries > 0);
- assert(cache->used_memory > entry->memory);
+ assert(cache->used_memory >= entry->memory);
cache->live_entries--;
cache->used_memory -= entry->memory;
@@ -183,10 +181,12 @@ _cache_lookup (cairo_cache_t *cache,
if (predicate != NULL)
{
/* We are looking up an exact entry. */
- if (*probe != NULL
- && *probe != DEAD_ENTRY
- && (*probe)->hashcode == hash
- && predicate (cache, key, *probe))
+ if (*probe == NULL)
+ /* Found an empty spot, there can't be a match */
+ break;
+ else if (*probe != DEAD_ENTRY
+ && (*probe)->hashcode == hash
+ && predicate (cache, key, *probe))
return probe;
}
else
@@ -230,8 +230,7 @@ _find_exact_live_entry_for (cairo_cache_t *cache,
return _cache_lookup (cache, key, cache->backend->keys_equal);
}
-
-static cairo_cache_arrangement_t *
+static const cairo_cache_arrangement_t *
_find_cache_arrangement (unsigned long proposed_size)
{
unsigned long idx;
@@ -302,7 +301,7 @@ _cairo_cache_init (cairo_cache_t *cache,
const cairo_cache_backend_t *backend,
unsigned long max_memory)
{
- assert(backend != NULL);
+ assert (backend != NULL);
if (cache != NULL){
cache->arrangement = &cache_arrangements[0];
@@ -342,7 +341,7 @@ _cairo_cache_destroy (cairo_cache_t *cache)
_cache_sane_state (cache);
- if (cache->refcount-- > 0)
+ if (--cache->refcount > 0)
return;
for (i = 0; i < cache->arrangement->size; ++i) {
@@ -419,7 +418,8 @@ _cairo_cache_lookup (cairo_cache_t *cache,
_entry_destroy (cache, idx);
}
- assert(cache->max_memory >= (cache->used_memory + new_entry->memory));
+ /* Can't assert this; new_entry->memory may be larger than max_memory */
+ /* assert(cache->max_memory >= (cache->used_memory + new_entry->memory)); */
/* Make room in the table for a new slot. */
status = _resize_cache (cache, cache->live_entries + 1);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index cbdc018a1..14e30f695 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -169,7 +169,7 @@ cairo_image_surface_create_for_data (char *data,
pixman_format = _create_pixman_format (format);
if (pixman_format == NULL)
return NULL;
-
+
pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
width, height,
_cairo_format_bpp (format),
@@ -199,7 +199,7 @@ static void
_cairo_image_abstract_surface_destroy (void *abstract_surface)
{
cairo_image_surface_t *surface = abstract_surface;
-
+
if (surface->pixman_image)
pixman_image_destroy (surface->pixman_image);
@@ -490,7 +490,7 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
+static cairo_int_status_t
_cairo_image_abstract_surface_create_pattern (void *abstract_surface,
cairo_pattern_t *pattern,
cairo_box_t *box)
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index 7fc2694f3..b964b688c 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -34,6 +34,7 @@
* Carl D. Worth <cworth@isi.edu>
*/
+#define _GNU_SOURCE
#include <stdlib.h>
#include <math.h>
@@ -124,9 +125,20 @@ cairo_matrix_get_affine (cairo_matrix_t *matrix,
double *c, double *d,
double *tx, double *ty)
{
- *a = matrix->m[0][0]; *b = matrix->m[0][1];
- *c = matrix->m[1][0]; *d = matrix->m[1][1];
- *tx = matrix->m[2][0]; *ty = matrix->m[2][1];
+ if (a)
+ *a = matrix->m[0][0];
+ if (b)
+ *b = matrix->m[0][1];
+
+ if (c)
+ *c = matrix->m[1][0];
+ if (d)
+ *d = matrix->m[1][1];
+
+ if (tx)
+ *tx = matrix->m[2][0];
+ if (ty)
+ *ty = matrix->m[2][1];
return CAIRO_STATUS_SUCCESS;
}
@@ -176,9 +188,17 @@ cairo_status_t
_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
double radians)
{
+ double s;
+ double c;
+#if HAVE_SINCOS
+ sincos (radians, &s, &c);
+#else
+ s = sin (radians);
+ c = cos (radians);
+#endif
return cairo_matrix_set_affine (matrix,
- cos (radians), sin (radians),
- -sin (radians), cos (radians),
+ c, s,
+ -s, c,
0, 0);
}
@@ -398,19 +418,42 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
/* Compute the amount that each basis vector is scaled by. */
cairo_status_t
-_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy)
+_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major)
{
- double x, y;
+ double det;
- x = 1.0;
- y = 0.0;
- cairo_matrix_transform_distance (matrix, &x, &y);
- *sx = sqrt(x*x + y*y);
+ _cairo_matrix_compute_determinant (matrix, &det);
- x = 0.0;
- y = 1.0;
- cairo_matrix_transform_distance (matrix, &x, &y);
- *sy = sqrt(x*x + y*y);
+ if (det == 0)
+ *sx = *sy = 0;
+ else
+ {
+ double x = x_major != 0;
+ double y = x == 0;
+ double major, minor;
+
+ cairo_matrix_transform_distance (matrix, &x, &y);
+ major = sqrt(x*x + y*y);
+ /*
+ * ignore mirroring
+ */
+ if (det < 0)
+ det = -det;
+ if (major)
+ minor = det / major;
+ else
+ minor = 0.0;
+ if (x_major)
+ {
+ *sx = major;
+ *sy = minor;
+ }
+ else
+ {
+ *sx = minor;
+ *sy = major;
+ }
+ }
return CAIRO_STATUS_SUCCESS;
}
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
new file mode 100644
index 000000000..23230aa74
--- /dev/null
+++ b/src/cairo-pdf-surface.c
@@ -0,0 +1,2208 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-pdf.h"
+/* XXX: This seems broken to me. What about users without freetype
+ * that want to use a cairo PDF surface? */
+#include "cairo-ft.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_TRUETYPE_TABLES_H
+
+#include <time.h>
+#include <zlib.h>
+
+/* Issues:
+ *
+ * - Why doesn't pages inherit /alpha%d GS dictionaries from the Pages
+ * object?
+ *
+ * - Why isn't the pattern passed to composite traps instead of
+ * pattern->source? If composite traps needs an image or a surface it
+ * can call create_pattern().
+ *
+ * - We embed an image in the stream each time it's composited. We
+ * could add generation counters to surfaces and remember the stream
+ * ID for a particular generation for a particular surface.
+ *
+ * - Multi stop gradients. What are the exponential interpolation
+ * functions, could they be used for gradients?
+ *
+ * - Clipping: must be able to reset clipping
+ *
+ * - Images of other formats than 8 bit RGBA.
+ *
+ * - Backend specific meta data.
+ *
+ * - Surface patterns.
+ *
+ * - Alpha channels in gradients.
+ *
+ * - Should/does cairo support drawing into a scratch surface and then
+ * using that as a fill pattern? For this backend, that would involve
+ * using a tiling pattern (4.6.2). How do you create such a scratch
+ * surface? cairo_surface_create_similar() ?
+ *
+ * - What if you create a similiar surface and does show_page and then
+ * does show_surface on another surface?
+ *
+ * - Output TM so page scales to the right size - PDF default user
+ * space has 1 unit = 1 / 72 inch.
+ *
+ * - Add test case for RGBA images.
+ *
+ * - Add test case for RGBA gradients.
+ *
+ * - Pattern extend isn't honoured by image backend.
+ *
+ * - Coordinate space for create_similar() args?
+ *
+ * - Investigate /Matrix entry in content stream dicts for pages
+ * instead of outputting the cm operator in every page.
+ */
+
+typedef struct ft_subset_glyph ft_subset_glyph_t;
+struct ft_subset_glyph {
+ int parent_index;
+ unsigned long location;
+};
+
+typedef struct cairo_pdf_font_backend cairo_pdf_font_backend_t;
+struct cairo_pdf_font_backend {
+ int (*use_glyph) (void *abstract_font,
+ int glyph);
+ cairo_status_t (*generate) (void *abstract_font,
+ const char **data,
+ unsigned long *length);
+ void (*destroy) (void *abstract_font);
+};
+
+typedef struct cairo_pdf_font cairo_pdf_font_t;
+struct cairo_pdf_font {
+ cairo_pdf_font_backend_t *backend;
+ cairo_unscaled_font_t *unscaled_font;
+ unsigned int font_id;
+ char *base_font;
+ int num_glyphs;
+ int *widths;
+ long x_min, y_min, x_max, y_max;
+ long ascent, descent;
+};
+
+typedef struct cairo_pdf_ft_font cairo_pdf_ft_font_t;
+struct cairo_pdf_ft_font {
+ cairo_pdf_font_t base;
+ ft_subset_glyph_t *glyphs;
+ FT_Face face;
+ unsigned long *checksum_location;
+ cairo_array_t output;
+ int *parent_to_subset;
+ cairo_status_t status;
+};
+
+typedef struct cairo_pdf_object cairo_pdf_object_t;
+typedef struct cairo_pdf_resource cairo_pdf_resource_t;
+typedef struct cairo_pdf_stream cairo_pdf_stream_t;
+typedef struct cairo_pdf_document cairo_pdf_document_t;
+typedef struct cairo_pdf_surface cairo_pdf_surface_t;
+
+struct cairo_pdf_object {
+ long offset;
+};
+
+struct cairo_pdf_resource {
+ unsigned int id;
+};
+
+struct cairo_pdf_stream {
+ unsigned int id;
+ unsigned int length_id;
+ long start_offset;
+};
+
+struct cairo_pdf_document {
+ FILE *file;
+ unsigned long refcount;
+
+ double width_inches;
+ double height_inches;
+ double x_ppi;
+ double y_ppi;
+
+ unsigned int next_available_id;
+ unsigned int pages_id;
+
+ cairo_pdf_stream_t *current_stream;
+
+ cairo_array_t objects;
+ cairo_array_t pages;
+
+ cairo_array_t fonts;
+};
+
+struct cairo_pdf_surface {
+ cairo_surface_t base;
+
+ double width_inches;
+ double height_inches;
+
+ /* HACK: Non-null if this surface was created for a pattern. */
+ cairo_pattern_t *pattern;
+
+ cairo_pdf_document_t *document;
+ cairo_pdf_stream_t *current_stream;
+
+ cairo_array_t patterns;
+ cairo_array_t xobjects;
+ cairo_array_t streams;
+ cairo_array_t alphas;
+ cairo_array_t fonts;
+};
+
+
+static cairo_pdf_document_t *
+_cairo_pdf_document_create (FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch);
+
+static void
+_cairo_pdf_document_destroy (cairo_pdf_document_t *document);
+
+static void
+_cairo_pdf_document_reference (cairo_pdf_document_t *document);
+
+static unsigned int
+_cairo_pdf_document_new_object (cairo_pdf_document_t *document);
+
+static cairo_status_t
+_cairo_pdf_document_add_page (cairo_pdf_document_t *document,
+ cairo_pdf_surface_t *surface);
+
+static void
+_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
+
+static cairo_pdf_stream_t *
+_cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
+ const char *extra_entries);
+static cairo_surface_t *
+_cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
+ double width_inches,
+ double height_inches);
+static void
+_cairo_pdf_surface_add_stream (cairo_pdf_surface_t *surface,
+ cairo_pdf_stream_t *stream);
+static void
+_cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface);
+
+static const cairo_surface_backend_t cairo_pdf_surface_backend;
+
+/* Truetype font subsetting code */
+
+#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) )
+
+#define SFNT_VERSION 0x00010000
+#define OFFSET_TABLE_SIZE 12
+#define TABLE_DIRECTORY_ENTRY_SIZE 16
+
+#ifdef WORDS_BIGENDIAN
+
+#define cpu_to_be16(v) (v)
+#define be16_to_cpu(v) (v)
+#define cpu_to_be32(v) (v)
+#define be32_to_cpu(v) (v)
+
+#else
+
+static inline unsigned short
+cpu_to_be16(unsigned short v)
+{
+ return (v << 8) | (v >> 8);
+}
+
+static inline unsigned short
+be16_to_cpu(unsigned short v)
+{
+ return cpu_to_be16 (v);
+}
+
+static inline unsigned long
+cpu_to_be32(unsigned long v)
+{
+ return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16);
+}
+
+static inline unsigned long
+be32_to_cpu(unsigned long v)
+{
+ return cpu_to_be32 (v);
+}
+
+#endif
+
+static cairo_pdf_font_backend_t cairo_pdf_ft_font_backend;
+
+static int
+cairo_pdf_font_use_glyph (cairo_pdf_font_t *font, int glyph)
+{
+ return font->backend->use_glyph (font, glyph);
+}
+
+static cairo_status_t
+cairo_pdf_font_generate (cairo_pdf_font_t *font,
+ const char **data, unsigned long *length)
+{
+ return font->backend->generate (font, data, length);
+}
+
+static void
+cairo_pdf_font_destroy (cairo_pdf_font_t *font)
+{
+ font->backend->destroy (font);
+}
+
+static cairo_pdf_font_t *
+cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
+ cairo_unscaled_font_t *unscaled_font,
+ cairo_font_scale_t *scale)
+{
+ cairo_font_t scaled_font;
+ FT_Face face;
+ cairo_pdf_ft_font_t *font;
+ unsigned long size;
+ int i, j;
+
+ /* FIXME: Why do I have to pass a scaled font to get the FT_Face? */
+ _cairo_font_init (&scaled_font, scale, unscaled_font);
+ face = cairo_ft_font_face (&scaled_font);
+
+ /* We currently only support freetype truetype fonts. */
+ size = 0;
+ if (!FT_IS_SFNT (face) ||
+ FT_Load_Sfnt_Table (face, TTAG_glyf, 0, NULL, &size) != 0)
+ return NULL;
+
+ font = malloc (sizeof (cairo_pdf_ft_font_t));
+ if (font == NULL)
+ return NULL;
+
+ font->base.unscaled_font = unscaled_font;
+ _cairo_unscaled_font_reference (unscaled_font);
+ font->base.backend = &cairo_pdf_ft_font_backend;
+ font->base.font_id = _cairo_pdf_document_new_object (document);
+
+ _cairo_array_init (&font->output, sizeof (char));
+ if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
+ goto fail1;
+
+ font->face = face;
+ font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
+ if (font->glyphs == NULL)
+ goto fail2;
+
+ font->parent_to_subset = calloc (face->num_glyphs, sizeof (int));
+ if (font->parent_to_subset == NULL)
+ goto fail3;
+
+ font->base.num_glyphs = 1;
+ font->base.x_min = face->bbox.xMin;
+ font->base.y_min = face->bbox.yMin;
+ font->base.x_max = face->bbox.xMax;
+ font->base.y_max = face->bbox.yMax;
+ font->base.ascent = face->ascender;
+ font->base.descent = face->descender;
+ font->base.base_font = strdup (face->family_name);
+ if (font->base.base_font == NULL)
+ goto fail4;
+
+ for (i = 0, j = 0; font->base.base_font[j]; j++) {
+ if (font->base.base_font[j] == ' ')
+ continue;
+ font->base.base_font[i++] = font->base.base_font[j];
+ }
+ font->base.base_font[i] = '\0';
+
+ font->base.widths = calloc (face->num_glyphs, sizeof (int));
+ if (font->base.widths == NULL)
+ goto fail5;
+
+ font->status = CAIRO_STATUS_SUCCESS;
+
+ return &font->base;
+
+ fail5:
+ free (font->base.base_font);
+ fail4:
+ free (font->parent_to_subset);
+ fail3:
+ free (font->glyphs);
+ fail2:
+ _cairo_array_fini (&font->output);
+ fail1:
+ free (font);
+ return NULL;
+}
+
+static void
+cairo_pdf_ft_font_destroy (void *abstract_font)
+{
+ cairo_pdf_ft_font_t *font = abstract_font;
+
+ _cairo_unscaled_font_destroy (font->base.unscaled_font);
+ free (font->base.base_font);
+ free (font->parent_to_subset);
+ free (font->glyphs);
+ _cairo_array_fini (&font->output);
+ free (font);
+}
+
+static void *
+cairo_pdf_ft_font_write (cairo_pdf_ft_font_t *font,
+ const void *data, size_t length)
+{
+ void *p;
+
+ p = _cairo_array_append (&font->output, data, length);
+ if (p == NULL)
+ font->status = CAIRO_STATUS_NO_MEMORY;
+
+ return p;
+}
+
+static void
+cairo_pdf_ft_font_write_be16 (cairo_pdf_ft_font_t *font,
+ unsigned short value)
+{
+ unsigned short be16_value;
+
+ be16_value = cpu_to_be16 (value);
+ cairo_pdf_ft_font_write (font, &be16_value, sizeof be16_value);
+}
+
+static void
+cairo_pdf_ft_font_write_be32 (cairo_pdf_ft_font_t *font, unsigned long value)
+{
+ unsigned long be32_value;
+
+ be32_value = cpu_to_be32 (value);
+ cairo_pdf_ft_font_write (font, &be32_value, sizeof be32_value);
+}
+
+static unsigned long
+cairo_pdf_ft_font_align_output (cairo_pdf_ft_font_t *font)
+{
+ int length, aligned;
+ static const char pad[4];
+
+ length = _cairo_array_num_elements (&font->output);
+ aligned = (length + 3) & ~3;
+ cairo_pdf_ft_font_write (font, pad, aligned - length);
+
+ return aligned;
+}
+
+static int
+cairo_pdf_ft_font_write_cmap_table (cairo_pdf_ft_font_t *font, unsigned long tag)
+{
+ int i;
+
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 1);
+
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be32 (font, 12);
+
+ /* Output a format 6 encoding table. */
+
+ cairo_pdf_ft_font_write_be16 (font, 6);
+ cairo_pdf_ft_font_write_be16 (font, 10 + 2 * (font->base.num_glyphs - 1));
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 1); /* First glyph */
+ cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs - 1);
+ for (i = 1; i < font->base.num_glyphs; i++)
+ cairo_pdf_ft_font_write_be16 (font, i);
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_generic_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ char *buffer;
+ unsigned long size;
+
+ size = 0;
+ FT_Load_Sfnt_Table (font->face, tag, 0, NULL, &size);
+ buffer = cairo_pdf_ft_font_write (font, NULL, size);
+ FT_Load_Sfnt_Table (font->face, tag, 0, buffer, &size);
+
+ return 0;
+}
+
+static int
+cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ unsigned long start_offset, index, size;
+ TT_Header *header;
+ unsigned long begin, end;
+ char *buffer;
+ int i;
+ union {
+ unsigned char *bytes;
+ unsigned short *short_offsets;
+ unsigned long *long_offsets;
+ } u;
+
+ header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
+ if (header->Index_To_Loc_Format == 0)
+ size = sizeof (short) * (font->face->num_glyphs + 1);
+ else
+ size = sizeof (long) * (font->face->num_glyphs + 1);
+
+ u.bytes = malloc (size);
+ if (u.bytes == NULL) {
+ font->status = CAIRO_STATUS_NO_MEMORY;
+ return font->status;
+ }
+ FT_Load_Sfnt_Table (font->face, TTAG_loca, 0, u.bytes, &size);
+
+ start_offset = _cairo_array_num_elements (&font->output);
+ for (i = 0; i < font->base.num_glyphs; i++) {
+ index = font->glyphs[i].parent_index;
+ if (header->Index_To_Loc_Format == 0) {
+ begin = be16_to_cpu (u.short_offsets[index]) * 2;
+ end = be16_to_cpu (u.short_offsets[index + 1]) * 2;
+ }
+ else {
+ begin = be32_to_cpu (u.long_offsets[index]);
+ end = be32_to_cpu (u.long_offsets[index + 1]);
+ }
+
+ size = end - begin;
+
+ font->glyphs[i].location =
+ cairo_pdf_ft_font_align_output (font) - start_offset;
+ buffer = cairo_pdf_ft_font_write (font, NULL, size);
+ if (buffer == NULL)
+ break;
+ FT_Load_Sfnt_Table (font->face, TTAG_glyf, begin, buffer, &size);
+ /* FIXME: remap composite glyphs */
+ }
+
+ font->glyphs[i].location =
+ cairo_pdf_ft_font_align_output (font) - start_offset;
+
+ free (u.bytes);
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_head_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ TT_Header *head;
+
+ head = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
+
+ cairo_pdf_ft_font_write_be32 (font, head->Table_Version);
+ cairo_pdf_ft_font_write_be32 (font, head->Font_Revision);
+
+ font->checksum_location =
+ (unsigned long *) _cairo_array_index (&font->output, 0) +
+ _cairo_array_num_elements (&font->output) / sizeof (long);
+ cairo_pdf_ft_font_write_be32 (font, 0);
+ cairo_pdf_ft_font_write_be32 (font, head->Magic_Number);
+
+ cairo_pdf_ft_font_write_be16 (font, head->Flags);
+ cairo_pdf_ft_font_write_be16 (font, head->Units_Per_EM);
+
+ cairo_pdf_ft_font_write_be32 (font, head->Created[0]);
+ cairo_pdf_ft_font_write_be32 (font, head->Created[1]);
+ cairo_pdf_ft_font_write_be32 (font, head->Modified[0]);
+ cairo_pdf_ft_font_write_be32 (font, head->Modified[1]);
+
+ cairo_pdf_ft_font_write_be16 (font, head->xMin);
+ cairo_pdf_ft_font_write_be16 (font, head->yMin);
+ cairo_pdf_ft_font_write_be16 (font, head->xMax);
+ cairo_pdf_ft_font_write_be16 (font, head->yMax);
+
+ cairo_pdf_ft_font_write_be16 (font, head->Mac_Style);
+ cairo_pdf_ft_font_write_be16 (font, head->Lowest_Rec_PPEM);
+
+ cairo_pdf_ft_font_write_be16 (font, head->Font_Direction);
+ cairo_pdf_ft_font_write_be16 (font, head->Index_To_Loc_Format);
+ cairo_pdf_ft_font_write_be16 (font, head->Glyph_Data_Format);
+
+ return font->status;
+}
+
+static int cairo_pdf_ft_font_write_hhea_table (cairo_pdf_ft_font_t *font, unsigned long tag)
+{
+ TT_HoriHeader *hhea;
+
+ hhea = FT_Get_Sfnt_Table (font->face, ft_sfnt_hhea);
+
+ cairo_pdf_ft_font_write_be32 (font, hhea->Version);
+ cairo_pdf_ft_font_write_be16 (font, hhea->Ascender);
+ cairo_pdf_ft_font_write_be16 (font, hhea->Descender);
+ cairo_pdf_ft_font_write_be16 (font, hhea->Line_Gap);
+
+ cairo_pdf_ft_font_write_be16 (font, hhea->advance_Width_Max);
+
+ cairo_pdf_ft_font_write_be16 (font, hhea->min_Left_Side_Bearing);
+ cairo_pdf_ft_font_write_be16 (font, hhea->min_Right_Side_Bearing);
+ cairo_pdf_ft_font_write_be16 (font, hhea->xMax_Extent);
+ cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Rise);
+ cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Run);
+ cairo_pdf_ft_font_write_be16 (font, hhea->caret_Offset);
+
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+
+ cairo_pdf_ft_font_write_be16 (font, hhea->metric_Data_Format);
+ cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs);
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_hmtx_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ unsigned long entry_size;
+ short *p;
+ int i;
+
+ for (i = 0; i < font->base.num_glyphs; i++) {
+ entry_size = 2 * sizeof (short);
+ p = cairo_pdf_ft_font_write (font, NULL, entry_size);
+ FT_Load_Sfnt_Table (font->face, TTAG_hmtx,
+ font->glyphs[i].parent_index * entry_size,
+ (FT_Byte *) p, &entry_size);
+ font->base.widths[i] = be16_to_cpu (p[0]);
+ }
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_loca_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ int i;
+ TT_Header *header;
+
+ header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
+
+ if (header->Index_To_Loc_Format == 0) {
+ for (i = 0; i < font->base.num_glyphs + 1; i++)
+ cairo_pdf_ft_font_write_be16 (font, font->glyphs[i].location / 2);
+ }
+ else {
+ for (i = 0; i < font->base.num_glyphs + 1; i++)
+ cairo_pdf_ft_font_write_be32 (font, font->glyphs[i].location);
+ }
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_maxp_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ TT_MaxProfile *maxp;
+
+ maxp = FT_Get_Sfnt_Table (font->face, ft_sfnt_maxp);
+
+ cairo_pdf_ft_font_write_be32 (font, maxp->version);
+ cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxPoints);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxContours);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositePoints);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositeContours);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxZones);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxTwilightPoints);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxStorage);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxFunctionDefs);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxInstructionDefs);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxStackElements);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxSizeOfInstructions);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentElements);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentDepth);
+
+ return font->status;
+}
+
+typedef struct table table_t;
+struct table {
+ unsigned long tag;
+ int (*write) (cairo_pdf_ft_font_t *font, unsigned long tag);
+};
+
+static const table_t truetype_tables[] = {
+ { TTAG_cmap, cairo_pdf_ft_font_write_cmap_table },
+ { TTAG_cvt, cairo_pdf_ft_font_write_generic_table },
+ { TTAG_fpgm, cairo_pdf_ft_font_write_generic_table },
+ { TTAG_glyf, cairo_pdf_ft_font_write_glyf_table },
+ { TTAG_head, cairo_pdf_ft_font_write_head_table },
+ { TTAG_hhea, cairo_pdf_ft_font_write_hhea_table },
+ { TTAG_hmtx, cairo_pdf_ft_font_write_hmtx_table },
+ { TTAG_loca, cairo_pdf_ft_font_write_loca_table },
+ { TTAG_maxp, cairo_pdf_ft_font_write_maxp_table },
+ { TTAG_name, cairo_pdf_ft_font_write_generic_table },
+ { TTAG_prep, cairo_pdf_ft_font_write_generic_table },
+};
+
+static cairo_status_t
+cairo_pdf_ft_font_write_offset_table (cairo_pdf_ft_font_t *font)
+{
+ unsigned short search_range, entry_selector, range_shift;
+ int num_tables;
+
+ num_tables = ARRAY_LENGTH (truetype_tables);
+ search_range = 1;
+ entry_selector = 0;
+ while (search_range * 2 <= num_tables) {
+ search_range *= 2;
+ entry_selector++;
+ }
+ search_range *= 16;
+ range_shift = num_tables * 16 - search_range;
+
+ cairo_pdf_ft_font_write_be32 (font, SFNT_VERSION);
+ cairo_pdf_ft_font_write_be16 (font, num_tables);
+ cairo_pdf_ft_font_write_be16 (font, search_range);
+ cairo_pdf_ft_font_write_be16 (font, entry_selector);
+ cairo_pdf_ft_font_write_be16 (font, range_shift);
+
+ cairo_pdf_ft_font_write (font, NULL, ARRAY_LENGTH (truetype_tables) * 16);
+
+ return font->status;
+}
+
+static unsigned long
+cairo_pdf_ft_font_calculate_checksum (cairo_pdf_ft_font_t *font,
+ unsigned long start, unsigned long end)
+{
+ unsigned long *padded_end;
+ unsigned long *p;
+ unsigned long checksum;
+ char *data;
+
+ checksum = 0;
+ data = _cairo_array_index (&font->output, 0);
+ p = (unsigned long *) (data + start);
+ padded_end = (unsigned long *) (data + ((end + 3) & ~3));
+ while (p < padded_end)
+ checksum += *p++;
+
+ return checksum;
+}
+
+static void
+cairo_pdf_ft_font_update_entry (cairo_pdf_ft_font_t *font, int index, unsigned long tag,
+ unsigned long start, unsigned long end)
+{
+ unsigned long *entry;
+
+ entry = _cairo_array_index (&font->output, 12 + 16 * index);
+ entry[0] = cpu_to_be32 (tag);
+ entry[1] = cpu_to_be32 (cairo_pdf_ft_font_calculate_checksum (font, start, end));
+ entry[2] = cpu_to_be32 (start);
+ entry[3] = cpu_to_be32 (end - start);
+}
+
+static cairo_status_t
+cairo_pdf_ft_font_generate (void *abstract_font,
+ const char **data, unsigned long *length)
+{
+ cairo_pdf_ft_font_t *font = abstract_font;
+ unsigned long start, end, next, checksum;
+ int i;
+
+ if (cairo_pdf_ft_font_write_offset_table (font))
+ return font->status;
+
+ start = cairo_pdf_ft_font_align_output (font);
+ end = start;
+
+ for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) {
+ if (truetype_tables[i].write (font, truetype_tables[i].tag))
+ goto fail;
+
+ end = _cairo_array_num_elements (&font->output);
+ next = cairo_pdf_ft_font_align_output (font);
+ cairo_pdf_ft_font_update_entry (font, i, truetype_tables[i].tag,
+ start, end);
+ start = next;
+ }
+
+ checksum =
+ 0xb1b0afba - cairo_pdf_ft_font_calculate_checksum (font, 0, end);
+ *font->checksum_location = cpu_to_be32 (checksum);
+
+ *data = _cairo_array_index (&font->output, 0);
+ *length = _cairo_array_num_elements (&font->output);
+
+ fail:
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph)
+{
+ cairo_pdf_ft_font_t *font = abstract_font;
+
+ if (font->parent_to_subset[glyph] == 0) {
+ font->parent_to_subset[glyph] = font->base.num_glyphs;
+ font->glyphs[font->base.num_glyphs].parent_index = glyph;
+ font->base.num_glyphs++;
+ }
+
+ return font->parent_to_subset[glyph];
+}
+
+static cairo_pdf_font_backend_t cairo_pdf_ft_font_backend = {
+ cairo_pdf_ft_font_use_glyph,
+ cairo_pdf_ft_font_generate,
+ cairo_pdf_ft_font_destroy
+};
+
+/* PDF Generation */
+
+static unsigned int
+_cairo_pdf_document_new_object (cairo_pdf_document_t *document)
+{
+ cairo_pdf_object_t object;
+
+ object.offset = ftell (document->file);
+ if (_cairo_array_append (&document->objects, &object, 1) == NULL)
+ return 0;
+
+ return document->next_available_id++;
+}
+
+static void
+_cairo_pdf_document_update_object (cairo_pdf_document_t *document,
+ unsigned int id)
+{
+ cairo_pdf_object_t *object;
+
+ object = _cairo_array_index (&document->objects, id - 1);
+ object->offset = ftell (document->file);
+}
+
+static void
+_cairo_pdf_surface_add_stream (cairo_pdf_surface_t *surface,
+ cairo_pdf_stream_t *stream)
+{
+ _cairo_array_append (&surface->streams, &stream, 1);
+ surface->current_stream = stream;
+}
+
+static void
+_cairo_pdf_surface_add_pattern (cairo_pdf_surface_t *surface, unsigned int id)
+{
+ cairo_pdf_resource_t resource;
+
+ resource.id = id;
+ _cairo_array_append (&surface->patterns, &resource, 1);
+}
+
+static void
+_cairo_pdf_surface_add_xobject (cairo_pdf_surface_t *surface, unsigned int id)
+{
+ cairo_pdf_resource_t resource;
+ int i, num_resources;
+
+ num_resources = _cairo_array_num_elements (&surface->xobjects);
+ for (i = 0; i < num_resources; i++) {
+ _cairo_array_copy_element (&surface->xobjects, i, &resource);
+ if (resource.id == id)
+ return;
+ }
+
+ resource.id = id;
+ _cairo_array_append (&surface->xobjects, &resource, 1);
+}
+
+static unsigned int
+_cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface, double alpha)
+{
+ int num_alphas, i;
+ double other;
+
+ num_alphas = _cairo_array_num_elements (&surface->alphas);
+ for (i = 0; i < num_alphas; i++) {
+ _cairo_array_copy_element (&surface->alphas, i, &other);
+ if (alpha == other)
+ return i;
+ }
+
+ _cairo_array_append (&surface->alphas, &alpha, 1);
+ return _cairo_array_num_elements (&surface->alphas) - 1;
+}
+
+static void
+_cairo_pdf_surface_add_font (cairo_pdf_surface_t *surface, unsigned int id)
+{
+ cairo_pdf_resource_t resource;
+ int i, num_fonts;
+
+ num_fonts = _cairo_array_num_elements (&surface->fonts);
+ for (i = 0; i < num_fonts; i++) {
+ _cairo_array_copy_element (&surface->fonts, i, &resource);
+ if (resource.id == id)
+ return;
+ }
+
+ resource.id = id;
+ _cairo_array_append (&surface->fonts, &resource, 1);
+}
+
+cairo_surface_t *
+cairo_pdf_surface_create (FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch)
+{
+ cairo_pdf_document_t *document;
+ cairo_surface_t *surface;
+
+ document = _cairo_pdf_document_create (file,
+ width_inches,
+ height_inches,
+ x_pixels_per_inch,
+ y_pixels_per_inch);
+ if (document == NULL)
+ return NULL;
+
+ surface = _cairo_pdf_surface_create_for_document (document,
+ width_inches,
+ height_inches);
+
+ _cairo_pdf_document_destroy (document);
+
+ return surface;
+}
+
+static cairo_surface_t *
+_cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
+ double width_inches,
+ double height_inches)
+{
+ cairo_pdf_surface_t *surface;
+
+ surface = malloc (sizeof (cairo_pdf_surface_t));
+ if (surface == NULL)
+ return NULL;
+
+ _cairo_surface_init (&surface->base, &cairo_pdf_surface_backend);
+
+ surface->width_inches = width_inches;
+ surface->height_inches = height_inches;
+
+ surface->pattern = NULL;
+ _cairo_pdf_document_reference (document);
+ surface->document = document;
+ _cairo_array_init (&surface->streams, sizeof (cairo_pdf_stream_t *));
+ _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_resource_t));
+ _cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t));
+ _cairo_array_init (&surface->alphas, sizeof (double));
+ _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
+
+ return &surface->base;
+}
+
+static void
+_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
+{
+ int num_streams, i;
+ cairo_pdf_stream_t *stream;
+
+ num_streams = _cairo_array_num_elements (&surface->streams);
+ for (i = 0; i < num_streams; i++) {
+ _cairo_array_copy_element (&surface->streams, i, &stream);
+ free (stream);
+ }
+
+ _cairo_array_truncate (&surface->streams, 0);
+ _cairo_array_truncate (&surface->patterns, 0);
+ _cairo_array_truncate (&surface->xobjects, 0);
+ _cairo_array_truncate (&surface->alphas, 0);
+ _cairo_array_truncate (&surface->fonts, 0);
+}
+
+static cairo_surface_t *
+_cairo_pdf_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ cairo_pdf_surface_t *template = abstract_src;
+
+ return _cairo_pdf_surface_create_for_document (template->document,
+ width, height);
+}
+
+static cairo_pdf_stream_t *
+_cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
+ const char *extra_entries)
+{
+ FILE *file = document->file;
+ cairo_pdf_stream_t *stream;
+
+ stream = malloc (sizeof (cairo_pdf_stream_t));
+ if (stream == NULL) {
+ return NULL;
+ }
+
+ stream->id = _cairo_pdf_document_new_object (document);
+ stream->length_id = _cairo_pdf_document_new_object (document);
+
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Length %d 0 R\r\n"
+ "%s"
+ ">>\r\n"
+ "stream\r\n",
+ stream->id,
+ stream->length_id,
+ extra_entries);
+
+ stream->start_offset = ftell (file);
+
+ document->current_stream = stream;
+
+ return stream;
+}
+
+static void
+_cairo_pdf_document_close_stream (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ long length;
+ cairo_pdf_stream_t *stream;
+
+ stream = document->current_stream;
+ if (stream == NULL)
+ return;
+
+ length = ftell(file) - stream->start_offset;
+ fprintf (file,
+ "\r\n"
+ "endstream\r\n"
+ "endobj\r\n");
+
+ _cairo_pdf_document_update_object (document, stream->length_id);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ " %ld\r\n"
+ "endobj\r\n",
+ stream->length_id,
+ length);
+
+ document->current_stream = NULL;
+}
+
+static void
+_cairo_pdf_surface_destroy (void *abstract_surface)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_document_t *document = surface->document;
+
+ if (surface->current_stream == document->current_stream)
+ _cairo_pdf_document_close_stream (document);
+
+ _cairo_pdf_document_destroy (document);
+
+ free (surface);
+}
+
+/* XXX: We should re-work this interface to return both X/Y ppi values. */
+static double
+_cairo_pdf_surface_pixels_per_inch (void *abstract_surface)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ return surface->document->y_ppi;
+}
+
+static void
+_cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface)
+{
+ cairo_pdf_document_t *document = surface->document;
+ cairo_pdf_stream_t *stream;
+ FILE *file = document->file;
+ char extra[200];
+
+ if (document->current_stream == NULL ||
+ document->current_stream != surface->current_stream) {
+ _cairo_pdf_document_close_stream (document);
+ snprintf (extra, sizeof extra,
+ " /Type /XObject\r\n"
+ " /Subtype /Form\r\n"
+ " /BBox [ 0 0 %f %f ]\r\n",
+ surface->width_inches * document->x_ppi,
+ surface->height_inches * document->y_ppi);
+ stream = _cairo_pdf_document_open_stream (document, extra);
+ _cairo_pdf_surface_add_stream (surface, stream);
+
+ /* If this is the first stream we open for this surface,
+ * output the cairo to PDF transformation matrix. */
+ if (_cairo_array_num_elements (&surface->streams) == 1)
+ fprintf (file, "1 0 0 -1 0 %f cm\r\n",
+ document->height_inches * document->y_ppi);
+ }
+}
+
+static cairo_image_surface_t *
+_cairo_pdf_surface_get_image (void *abstract_surface)
+{
+ return NULL;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_image (void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_matrix (void *abstract_surface,
+ cairo_matrix_t *matrix)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_filter (void *abstract_surface,
+ cairo_filter_t filter)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_repeat (void *abstract_surface,
+ int repeat)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void *
+compress_dup (const void *data, unsigned long data_size,
+ unsigned long *compressed_size)
+{
+ void *compressed;
+
+ /* Bound calculation taken from zlib. */
+ *compressed_size = data_size + (data_size >> 12) + (data_size >> 14) + 11;
+ compressed = malloc (*compressed_size);
+ if (compressed == NULL)
+ return NULL;
+
+ compress (compressed, compressed_size, data, data_size);
+
+ return compressed;
+}
+
+static unsigned int
+emit_image_data (cairo_pdf_document_t *document,
+ cairo_image_surface_t *image)
+{
+ FILE *file = document->file;
+ cairo_pdf_stream_t *stream;
+ char entries[200];
+ char *rgb, *compressed;
+ int i, x, y;
+ unsigned long rgb_size, compressed_size;
+ pixman_bits_t *pixel;
+
+ rgb_size = image->height * image->width * 3;
+ rgb = malloc (rgb_size);
+ if (rgb == NULL)
+ return 0;
+
+ i = 0;
+ for (y = 0; y < image->height; y++) {
+ pixel = (pixman_bits_t *) (image->data + y * image->stride);
+
+ for (x = 0; x < image->width; x++, pixel++) {
+ rgb[i++] = (*pixel & 0x00ff0000) >> 16;
+ rgb[i++] = (*pixel & 0x0000ff00) >> 8;
+ rgb[i++] = (*pixel & 0x000000ff) >> 0;
+ }
+ }
+
+ compressed = compress_dup (rgb, rgb_size, &compressed_size);
+ if (compressed == NULL) {
+ free (rgb);
+ return 0;
+ }
+
+ _cairo_pdf_document_close_stream (document);
+
+ snprintf (entries, sizeof entries,
+ " /Type /XObject\r\n"
+ " /Subtype /Image\r\n"
+ " /Width %d\r\n"
+ " /Height %d\r\n"
+ " /ColorSpace /DeviceRGB\r\n"
+ " /BitsPerComponent 8\r\n"
+ " /Filter /FlateDecode\r\n",
+ image->width, image->height);
+
+ stream = _cairo_pdf_document_open_stream (document, entries);
+ fwrite (compressed, 1, compressed_size, file);
+ _cairo_pdf_document_close_stream (document);
+
+ free (rgb);
+ free (compressed);
+
+ return stream->id;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
+ cairo_image_surface_t *image)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ unsigned id;
+ cairo_matrix_t i2u;
+
+ id = emit_image_data (dst->document, image);
+ if (id == 0)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_pdf_surface_add_xobject (dst, id);
+
+ _cairo_pdf_surface_ensure_stream (dst);
+
+ cairo_matrix_copy (&i2u, &image->base.matrix);
+ cairo_matrix_invert (&i2u);
+ cairo_matrix_translate (&i2u, 0, image->height);
+ cairo_matrix_scale (&i2u, image->width, -image->height);
+
+ fprintf (file,
+ "q %f %f %f %f %f %f cm /res%d Do Q\r\n",
+ i2u.m[0][0], i2u.m[0][1],
+ i2u.m[1][0], i2u.m[1][1],
+ i2u.m[2][0], i2u.m[2][1],
+ id);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* The contents of the surface is already transformed into PDF units,
+ * but when we composite the surface we may want to use a different
+ * space. The problem I see now is that the show_surface snippet
+ * creates a surface 1x1, which in the snippet environment is the
+ * entire surface. When compositing the surface, cairo gives us the
+ * 1x1 to 256x256 matrix. This would be fine if cairo didn't actually
+ * also transform the drawing to the surface. Should the CTM be part
+ * of the current target surface?
+ */
+
+static cairo_int_status_t
+_cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
+ cairo_pdf_surface_t *src,
+ int width, int height)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ cairo_matrix_t i2u;
+ cairo_pdf_stream_t *stream;
+ int num_streams, i;
+
+ if (src->pattern != NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_pdf_surface_ensure_stream (dst);
+
+ cairo_matrix_copy (&i2u, &src->base.matrix);
+ cairo_matrix_invert (&i2u);
+ cairo_matrix_scale (&i2u,
+ 1.0 / (src->width_inches * document->x_ppi),
+ 1.0 / (src->height_inches * document->y_ppi));
+
+ fprintf (file,
+ "q %f %f %f %f %f %f cm",
+ i2u.m[0][0], i2u.m[0][1],
+ i2u.m[1][0], i2u.m[1][1],
+ i2u.m[2][0], i2u.m[2][1]);
+
+ num_streams = _cairo_array_num_elements (&src->streams);
+ for (i = 0; i < num_streams; i++) {
+ _cairo_array_copy_element (&src->streams, i, &stream);
+ fprintf (file,
+ " /res%d Do",
+ stream->id);
+
+ _cairo_pdf_surface_add_xobject (dst, stream->id);
+
+ }
+
+ fprintf (file, " Q\r\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_composite (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ cairo_surface_t *generic_mask,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ cairo_pdf_surface_t *dst = abstract_dst;
+ cairo_pdf_surface_t *src;
+ cairo_image_surface_t *image;
+
+ if (generic_src->backend == &cairo_pdf_surface_backend) {
+ src = (cairo_pdf_surface_t *) generic_src;
+ return _cairo_pdf_surface_composite_pdf (dst, src, width, height);
+ }
+ else {
+ image = _cairo_surface_get_image (generic_src);
+ return _cairo_pdf_surface_composite_image (dst, image);
+ }
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_fill_rectangles (void *abstract_surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ int i;
+
+ if (surface->pattern != NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_pdf_surface_ensure_stream (surface);
+
+ fprintf (file,
+ "%f %f %f rg\r\n",
+ color->red, color->green, color->blue);
+
+ for (i = 0; i < num_rects; i++) {
+ fprintf (file,
+ "%d %d %d %d re f\r\n",
+ rects[i].x, rects[i].y,
+ rects[i].width, rects[i].height);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+emit_tiling_pattern (cairo_operator_t operator,
+ cairo_pdf_surface_t *dst,
+ cairo_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ cairo_pdf_stream_t *stream;
+ cairo_image_surface_t *image;
+ char entries[250];
+ unsigned int id, alpha;
+ cairo_matrix_t pm;
+
+ if (pattern->u.surface.surface->backend == &cairo_pdf_surface_backend) {
+ return;
+ }
+
+ image = _cairo_surface_get_image (pattern->u.surface.surface);
+
+ _cairo_pdf_document_close_stream (document);
+
+ id = emit_image_data (dst->document, image);
+
+ /* BBox must be smaller than XStep by YStep or acroread wont
+ * display the pattern. */
+
+ cairo_matrix_set_identity (&pm);
+ cairo_matrix_scale (&pm, image->width, image->height);
+ cairo_matrix_copy (&pm, &pattern->matrix);
+ cairo_matrix_invert (&pm);
+
+ snprintf (entries, sizeof entries,
+ " /BBox [ 0 0 256 256 ]\r\n"
+ " /XStep 256\r\n"
+ " /YStep 256\r\n"
+ " /PatternType 1\r\n"
+ " /TilingType 1\r\n"
+ " /PaintType 1\r\n"
+ " /Resources << /XObject << /res%d %d 0 R >> >>\r\n"
+ " /Matrix [ %f %f %f %f %f %f ]\r\n",
+ id, id,
+ pm.m[0][0], pm.m[0][1],
+ pm.m[1][0], pm.m[1][1],
+ pm.m[2][0], pm.m[2][1]);
+
+ stream = _cairo_pdf_document_open_stream (document, entries);
+
+ _cairo_pdf_surface_add_pattern (dst, stream->id);
+
+ _cairo_pdf_surface_ensure_stream (dst);
+ alpha = _cairo_pdf_surface_add_alpha (dst, 1.0);
+ fprintf (file,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ stream->id, alpha);
+}
+
+static unsigned int
+emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ unsigned int function_id;
+
+ function_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /FunctionType 0\r\n"
+ " /Domain [ 0.0 1.0 ]\r\n"
+ " /Size [ 2 ]\r\n"
+ " /BitsPerSample 8\r\n"
+ " /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n"
+ " /Length 6\r\n"
+ ">>\r\n"
+ "stream\r\n",
+ function_id);
+
+ fputc (pattern->stops[0].color_char[0], file);
+ fputc (pattern->stops[0].color_char[1], file);
+ fputc (pattern->stops[0].color_char[2], file);
+ fputc (pattern->stops[1].color_char[0], file);
+ fputc (pattern->stops[1].color_char[1], file);
+ fputc (pattern->stops[1].color_char[2], file);
+
+ fprintf (file,
+ "\r\n"
+ "endstream\r\n"
+ "endobj\r\n");
+
+ return function_id;
+}
+
+static void
+emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ unsigned int function_id, pattern_id, alpha;
+ double x0, y0, x1, y1;
+ cairo_matrix_t p2u;
+
+ _cairo_pdf_document_close_stream (document);
+
+ function_id = emit_pattern_stops (surface, pattern);
+
+ cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_invert (&p2u);
+
+ x0 = pattern->u.linear.point0.x;
+ y0 = pattern->u.linear.point0.y;
+ cairo_matrix_transform_point (&p2u, &x0, &y0);
+ x1 = pattern->u.linear.point1.x;
+ y1 = pattern->u.linear.point1.y;
+ cairo_matrix_transform_point (&p2u, &x1, &y1);
+
+ pattern_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Pattern\r\n"
+ " /PatternType 2\r\n"
+ " /Matrix [ 1 0 0 -1 0 %f ]\r\n"
+ " /Shading\r\n"
+ " << /ShadingType 2\r\n"
+ " /ColorSpace /DeviceRGB\r\n"
+ " /Coords [ %f %f %f %f ]\r\n"
+ " /Function %d 0 R\r\n"
+ " /Extend [ %s %s ]\r\n"
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ pattern_id,
+ document->height_inches * document->y_ppi,
+ x0, y0, x1, y1,
+ function_id,
+ (1 || pattern->extend) ? "true" : "false",
+ (1 || pattern->extend) ? "true" : "false");
+
+ _cairo_pdf_surface_add_pattern (surface, pattern_id);
+
+ _cairo_pdf_surface_ensure_stream (surface);
+ alpha = _cairo_pdf_surface_add_alpha (surface, 1.0);
+
+ /* Use pattern */
+ fprintf (file,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ pattern_id, alpha);
+}
+
+static void
+emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ unsigned int function_id, pattern_id, alpha;
+ double x0, y0, x1, y1, r0, r1;
+ cairo_matrix_t p2u;
+
+ _cairo_pdf_document_close_stream (document);
+
+ function_id = emit_pattern_stops (surface, pattern);
+
+ cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_invert (&p2u);
+
+ x0 = pattern->u.radial.center0.x;
+ y0 = pattern->u.radial.center0.y;
+ r0 = pattern->u.radial.radius0;
+ cairo_matrix_transform_point (&p2u, &x0, &y0);
+ x1 = pattern->u.radial.center1.x;
+ y1 = pattern->u.radial.center1.y;
+ r1 = pattern->u.radial.radius1;
+ cairo_matrix_transform_point (&p2u, &x1, &y1);
+
+ /* FIXME: This is surely crack, but how should you scale a radius
+ * in a non-orthogonal coordinate system? */
+ cairo_matrix_transform_distance (&p2u, &r0, &r1);
+
+ pattern_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Pattern\r\n"
+ " /PatternType 2\r\n"
+ " /Matrix [ 1 0 0 -1 0 %f ]\r\n"
+ " /Shading\r\n"
+ " << /ShadingType 3\r\n"
+ " /ColorSpace /DeviceRGB\r\n"
+ " /Coords [ %f %f %f %f %f %f ]\r\n"
+ " /Function %d 0 R\r\n"
+ " /Extend [ %s %s ]\r\n"
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ pattern_id,
+ document->height_inches * document->y_ppi,
+ x0, y0, r0, x1, y1, r1,
+ function_id,
+ (1 || pattern->extend) ? "true" : "false",
+ (1 || pattern->extend) ? "true" : "false");
+
+ _cairo_pdf_surface_add_pattern (surface, pattern_id);
+
+ _cairo_pdf_surface_ensure_stream (surface);
+ alpha = _cairo_pdf_surface_add_alpha (surface, 1.0);
+
+ /* Use pattern */
+ fprintf (file,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ pattern_id, alpha);
+}
+
+static double
+intersect (cairo_line_t *line, cairo_fixed_t y)
+{
+ return _cairo_fixed_to_double (line->p1.x) +
+ _cairo_fixed_to_double (line->p2.x - line->p1.x) *
+ _cairo_fixed_to_double (y - line->p1.y) /
+ _cairo_fixed_to_double (line->p2.y - line->p1.y);
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ void *abstract_dst,
+ int x_src,
+ int y_src,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ cairo_pdf_surface_t *surface = abstract_dst;
+ cairo_pdf_surface_t *source = (cairo_pdf_surface_t *) generic_src;
+ cairo_pdf_document_t *document = surface->document;
+ cairo_pattern_t *pattern;
+ FILE *file = document->file;
+ int i;
+ unsigned int alpha;
+
+ /* FIXME: we really just want the original pattern here, not a
+ * source surface. */
+ pattern = source->pattern;
+
+ if (source->base.backend != &cairo_pdf_surface_backend) {
+ printf ("_cairo_pdf_surface_composite_trapezoids: not a pdf source\r");
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (pattern == NULL) {
+ printf ("_cairo_pdf_surface_composite_trapezoids: "
+ "non-pattern pdf source\r");
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SOLID:
+ alpha = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha);
+ _cairo_pdf_surface_ensure_stream (surface);
+ fprintf (file,
+ "%f %f %f rg /a%d gs\r\n",
+ pattern->color.red,
+ pattern->color.green,
+ pattern->color.blue,
+ alpha);
+ break;
+
+ case CAIRO_PATTERN_SURFACE:
+ emit_tiling_pattern (operator, surface, pattern);
+ break;
+
+ case CAIRO_PATTERN_LINEAR:
+ emit_linear_pattern (surface, pattern);
+ break;
+
+ case CAIRO_PATTERN_RADIAL:
+ emit_radial_pattern (surface, pattern );
+ break;
+ }
+
+ /* After the above switch the current stream should belong to this
+ * surface, so no need to _cairo_pdf_surface_ensure_stream() */
+ assert (document->current_stream != NULL &&
+ document->current_stream == surface->current_stream);
+
+ for (i = 0; i < num_traps; i++) {
+ double left_x1, left_x2, right_x1, right_x2;
+
+ left_x1 = intersect (&traps[i].left, traps[i].top);
+ left_x2 = intersect (&traps[i].left, traps[i].bottom);
+ right_x1 = intersect (&traps[i].right, traps[i].top);
+ right_x2 = intersect (&traps[i].right, traps[i].bottom);
+
+ fprintf (file,
+ "%f %f m %f %f l %f %f l %f %f l h\r\n",
+ left_x1, _cairo_fixed_to_double (traps[i].top),
+ left_x2, _cairo_fixed_to_double (traps[i].bottom),
+ right_x2, _cairo_fixed_to_double (traps[i].bottom),
+ right_x1, _cairo_fixed_to_double (traps[i].top));
+ }
+
+ fprintf (file,
+ "f\r\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_copy_page (void *abstract_surface)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_document_t *document = surface->document;
+
+ return _cairo_pdf_document_add_page (document, surface);
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_show_page (void *abstract_surface)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_document_t *document = surface->document;
+ cairo_int_status_t status;
+
+ status = _cairo_pdf_document_add_page (document, surface);
+ if (status == CAIRO_STATUS_SUCCESS)
+ _cairo_pdf_surface_clear (surface);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_create_pattern (void *abstract_surface,
+ cairo_pattern_t *pattern,
+ cairo_box_t *extents)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_surface_t *source;
+
+ source = (cairo_pdf_surface_t *)
+ _cairo_pdf_surface_create_for_document (surface->document, 0, 0);
+ source->pattern = pattern;
+ pattern->source = &source->base;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_pdf_font_t *
+_cairo_pdf_document_get_font (cairo_pdf_document_t *document,
+ cairo_unscaled_font_t *unscaled_font,
+ cairo_font_scale_t *scale)
+{
+ cairo_pdf_font_t *font;
+ unsigned int num_fonts, i;
+
+ num_fonts = _cairo_array_num_elements (&document->fonts);
+ for (i = 0; i < num_fonts; i++) {
+ _cairo_array_copy_element (&document->fonts, i, &font);
+ if (font->unscaled_font == unscaled_font)
+ return font;
+ }
+
+ /* FIXME: Figure out here which font backend is in use and call
+ * the appropriate constructor. */
+ font = cairo_pdf_ft_font_create (document, unscaled_font, scale);
+ if (font == NULL)
+ return NULL;
+
+ if (_cairo_array_append (&document->fonts, &font, 1) == NULL) {
+ cairo_pdf_font_destroy (font);
+ return NULL;
+ }
+
+ return font;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font,
+ cairo_font_scale_t *scale,
+ cairo_operator_t operator,
+ cairo_surface_t *source,
+ void *abstract_surface,
+ int source_x,
+ int source_y,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ cairo_pdf_font_t *pdf_font;
+ int i, index;
+
+ pdf_font = _cairo_pdf_document_get_font (document, font, scale);
+ if (pdf_font == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_pdf_surface_ensure_stream (surface);
+
+ fprintf (file, "0 0 0 rg BT /res%u 1 Tf", pdf_font->font_id);
+ for (i = 0; i < num_glyphs; i++) {
+
+ index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index);
+
+ fprintf (file,
+ " %f %f %f %f %f %f Tm (%c) Tj",
+ scale->matrix[0][0],
+ scale->matrix[0][1],
+ scale->matrix[1][0],
+ -scale->matrix[1][1],
+ glyphs[i].x,
+ glyphs[i].y,
+ index);
+ }
+ fprintf (file, " ET\r\n");
+
+ _cairo_pdf_surface_add_font (surface, pdf_font->font_id);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_pdf_surface_backend = {
+ _cairo_pdf_surface_create_similar,
+ _cairo_pdf_surface_destroy,
+ _cairo_pdf_surface_pixels_per_inch,
+ _cairo_pdf_surface_get_image,
+ _cairo_pdf_surface_set_image,
+ _cairo_pdf_surface_set_matrix,
+ _cairo_pdf_surface_set_filter,
+ _cairo_pdf_surface_set_repeat,
+ _cairo_pdf_surface_composite,
+ _cairo_pdf_surface_fill_rectangles,
+ _cairo_pdf_surface_composite_trapezoids,
+ _cairo_pdf_surface_copy_page,
+ _cairo_pdf_surface_show_page,
+ _cairo_pdf_surface_set_clip_region,
+ _cairo_pdf_surface_create_pattern,
+ _cairo_pdf_surface_show_glyphs
+};
+
+static cairo_pdf_document_t *
+_cairo_pdf_document_create (FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch)
+{
+ cairo_pdf_document_t *document;
+
+ document = malloc (sizeof (cairo_pdf_document_t));
+ if (document == NULL)
+ return NULL;
+
+ document->file = file;
+ document->refcount = 1;
+ document->width_inches = width_inches;
+ document->height_inches = height_inches;
+ document->x_ppi = x_pixels_per_inch;
+ document->y_ppi = y_pixels_per_inch;
+
+ _cairo_array_init (&document->objects, sizeof (cairo_pdf_object_t));
+ _cairo_array_init (&document->pages, sizeof (unsigned int));
+ document->next_available_id = 1;
+
+ document->current_stream = NULL;
+
+ document->pages_id = _cairo_pdf_document_new_object (document);
+
+ _cairo_array_init (&document->fonts, sizeof (cairo_pdf_font_t *));
+
+ /* Document header */
+ fprintf (file, "%%PDF-1.4\r\n");
+
+ return document;
+}
+
+static unsigned int
+_cairo_pdf_document_write_info (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ unsigned int id;
+
+ id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Creator (cairographics.org)\r\n"
+ " /Producer (cairographics.org)\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ id);
+
+ return id;
+}
+
+static void
+_cairo_pdf_document_write_pages (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ unsigned int page_id;
+ int num_pages, i;
+
+ _cairo_pdf_document_update_object (document, document->pages_id);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Pages\r\n"
+ " /Kids [ ",
+ document->pages_id);
+
+ num_pages = _cairo_array_num_elements (&document->pages);
+ for (i = 0; i < num_pages; i++) {
+ _cairo_array_copy_element (&document->pages, i, &page_id);
+ fprintf (file, "%d 0 R ", page_id);
+ }
+
+ fprintf (file, "]\r\n");
+ fprintf (file, " /Count %d\r\n", num_pages);
+
+ /* TODO: Figure out wich other defaults to be inherited by /Page
+ * objects. */
+ fprintf (file,
+ " /MediaBox [ 0 0 %f %f ]\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ document->width_inches * document->x_ppi,
+ document->height_inches * document->y_ppi);
+}
+
+static cairo_status_t
+_cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ cairo_pdf_font_t *font;
+ int num_fonts, i, j;
+ const char *data;
+ char *compressed;
+ unsigned long data_size, compressed_size;
+ unsigned int stream_id, descriptor_id;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ num_fonts = _cairo_array_num_elements (&document->fonts);
+ for (i = 0; i < num_fonts; i++) {
+ _cairo_array_copy_element (&document->fonts, i, &font);
+
+ status = cairo_pdf_font_generate (font, &data, &data_size);
+ if (status)
+ goto fail;
+
+ compressed = compress_dup (data, data_size, &compressed_size);
+ if (compressed == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ stream_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Filter /FlateDecode\r\n"
+ " /Length %lu\r\n"
+ " /Length1 %lu\r\n"
+ ">>\r\n"
+ "stream\r\n",
+ stream_id,
+ compressed_size,
+ data_size);
+ fwrite (compressed, 1, compressed_size, file);
+ fprintf (file,
+ "\r\n"
+ "endstream\r\n"
+ "endobj\r\n");
+ free (compressed);
+
+ descriptor_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /FontDescriptor\r\n"
+ " /FontName /%s\r\n"
+ " /Flags 32\r\n"
+ " /FontBBox [ %ld %ld %ld %ld ]\r\n"
+ " /ItalicAngle 0\r\n"
+ " /Ascent %ld\r\n"
+ " /Descent %ld\r\n"
+ " /CapHeight 500\r\n"
+ " /StemV 80\r\n"
+ " /StemH 80\r\n"
+ " /FontFile2 %u 0 R\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ descriptor_id,
+ font->base_font,
+ font->x_min,
+ font->y_min,
+ font->x_max,
+ font->y_max,
+ font->ascent,
+ font->descent,
+ stream_id);
+
+ _cairo_pdf_document_update_object (document, font->font_id);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Font\r\n"
+ " /Subtype /TrueType\r\n"
+ " /BaseFont /%s\r\n"
+ " /FirstChar 0\r\n"
+ " /LastChar %d\r\n"
+ " /FontDescriptor %d 0 R\r\n"
+ " /Widths ",
+ font->font_id,
+ font->base_font,
+ font->num_glyphs,
+ descriptor_id);
+
+ fprintf (file,
+ "[");
+
+ for (j = 0; j < font->num_glyphs; j++)
+ fprintf (file,
+ " %d",
+ font->widths[j]);
+
+ fprintf (file,
+ " ]\r\n"
+ ">>\r\n"
+ "endobj\r\n");
+
+ fail:
+ cairo_pdf_ft_font_destroy (font);
+ }
+
+ return status;
+}
+
+static unsigned int
+_cairo_pdf_document_write_catalog (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ unsigned int id;
+
+ id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Catalog\r\n"
+ " /Pages %d 0 R\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ id, document->pages_id);
+
+ return id;
+}
+
+static long
+_cairo_pdf_document_write_xref (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ cairo_pdf_object_t *object;
+ int num_objects, i;
+ long offset;
+
+ num_objects = _cairo_array_num_elements (&document->objects);
+
+ offset = ftell(file);
+ fprintf (document->file,
+ "xref\r\n"
+ "%d %d\r\n",
+ 0, num_objects + 1);
+
+ fprintf (file, "0000000000 65535 f\r\n");
+ for (i = 0; i < num_objects; i++) {
+ object = _cairo_array_index (&document->objects, i);
+ fprintf (file, "%010ld 00000 n\r\n", object->offset);
+ }
+
+ return offset;
+}
+
+static void
+_cairo_pdf_document_reference (cairo_pdf_document_t *document)
+{
+ document->refcount++;
+}
+
+static void
+_cairo_pdf_document_destroy (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ long offset;
+ unsigned int info_id, catalog_id;
+
+ document->refcount--;
+ if (document->refcount > 0)
+ return;
+
+ _cairo_pdf_document_close_stream (document);
+ _cairo_pdf_document_write_pages (document);
+ _cairo_pdf_document_write_fonts (document);
+ info_id = _cairo_pdf_document_write_info (document);
+ catalog_id = _cairo_pdf_document_write_catalog (document);
+ offset = _cairo_pdf_document_write_xref (document);
+
+ fprintf (file,
+ "trailer\r\n"
+ "<< /Size %d\r\n"
+ " /Root %d 0 R\r\n"
+ " /Info %d 0 R\r\n"
+ ">>\r\n",
+ document->next_available_id,
+ catalog_id,
+ info_id);
+
+ fprintf (file,
+ "startxref\r\n"
+ "%ld\r\n"
+ "%%%%EOF\r\n",
+ offset);
+
+ free (document);
+}
+
+static cairo_status_t
+_cairo_pdf_document_add_page (cairo_pdf_document_t *document,
+ cairo_pdf_surface_t *surface)
+{
+ cairo_pdf_stream_t *stream;
+ cairo_pdf_resource_t *res;
+ FILE *file = document->file;
+ unsigned int page_id;
+ double alpha;
+ int num_streams, num_alphas, num_resources, i;
+
+ _cairo_pdf_document_close_stream (document);
+
+ page_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Page\r\n"
+ " /Parent %d 0 R\r\n"
+ " /Contents [",
+ page_id,
+ document->pages_id);
+
+ num_streams = _cairo_array_num_elements (&surface->streams);
+ for (i = 0; i < num_streams; i++) {
+ _cairo_array_copy_element (&surface->streams, i, &stream);
+ fprintf (file,
+ " %d 0 R",
+ stream->id);
+ }
+
+ fprintf (file,
+ " ]\r\n"
+ " /Resources <<\r\n");
+
+ num_resources = _cairo_array_num_elements (&surface->fonts);
+ if (num_resources > 0) {
+ fprintf (file,
+ " /Font <<");
+
+ for (i = 0; i < num_resources; i++) {
+ res = _cairo_array_index (&surface->fonts, i);
+ fprintf (file,
+ " /res%d %d 0 R",
+ res->id, res->id);
+ }
+
+ fprintf (file,
+ " >>\r\n");
+ }
+
+ num_alphas = _cairo_array_num_elements (&surface->alphas);
+ if (num_alphas > 0) {
+ fprintf (file,
+ " /ExtGState <<\r\n");
+
+ for (i = 0; i < num_alphas; i++) {
+ _cairo_array_copy_element (&surface->alphas, i, &alpha);
+ fprintf (file,
+ " /a%d << /ca %f >>\r\n",
+ i, alpha);
+ }
+
+ fprintf (file,
+ " >>\r\n");
+ }
+
+ num_resources = _cairo_array_num_elements (&surface->patterns);
+ if (num_resources > 0) {
+ fprintf (file,
+ " /Pattern <<");
+ for (i = 0; i < num_resources; i++) {
+ res = _cairo_array_index (&surface->patterns, i);
+ fprintf (file,
+ " /res%d %d 0 R",
+ res->id, res->id);
+ }
+
+ fprintf (file,
+ " >>\r\n");
+ }
+
+ num_resources = _cairo_array_num_elements (&surface->xobjects);
+ if (num_resources > 0) {
+ fprintf (file,
+ " /XObject <<");
+
+ for (i = 0; i < num_resources; i++) {
+ res = _cairo_array_index (&surface->xobjects, i);
+ fprintf (file,
+ " /res%d %d 0 R",
+ res->id, res->id);
+ }
+
+ fprintf (file,
+ " >>\r\n");
+ }
+
+ fprintf (file,
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n");
+
+ _cairo_array_append (&document->pages, &page_id, 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+cairo_set_target_pdf (cairo_t *cr,
+ FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch)
+{
+ cairo_surface_t *surface;
+
+ surface = cairo_pdf_surface_create (file,
+ width_inches,
+ height_inches,
+ x_pixels_per_inch,
+ y_pixels_per_inch);
+
+ if (surface == NULL) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_set_target_surface (cr, surface);
+
+ /* cairo_set_target_surface takes a reference, so we must destroy ours */
+ cairo_surface_destroy (surface);
+}
diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h
new file mode 100644
index 000000000..0f624af31
--- /dev/null
+++ b/src/cairo-pdf.h
@@ -0,0 +1,62 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_PDF_H
+#define CAIRO_PDF_H
+#ifdef CAIRO_HAS_PDF_SURFACE
+
+#include <stdio.h>
+
+void
+cairo_set_target_pdf (cairo_t *cr,
+ FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch);
+
+
+cairo_surface_t *
+cairo_pdf_surface_create (FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch);
+
+#endif /* CAIRO_HAS_PDF_SURFACE */
+#endif /* CAIRO_PDF_H */
diff --git a/src/cairo-png.h b/src/cairo-png.h
new file mode 100644
index 000000000..766d6f91f
--- /dev/null
+++ b/src/cairo-png.h
@@ -0,0 +1,59 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_PNG_H
+#define CAIRO_PNG_H
+#ifdef CAIRO_HAS_PNG_SURFACE
+
+#include <stdio.h>
+
+void
+cairo_set_target_png (cairo_t *cr,
+ FILE *file,
+ cairo_format_t format,
+ int width,
+ int height);
+
+cairo_surface_t *
+cairo_png_surface_create (FILE *file,
+ cairo_format_t format,
+ int width,
+ int height);
+
+#endif /* CAIRO_HAS_PNG_SURFACE */
+#endif /* CAIRO_PNG_H */
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index 8fa32f9f6..e85858033 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -37,8 +37,6 @@
#include <stdlib.h>
#include "cairoint.h"
-#define CAIRO_POLYGON_GROWTH_INC 10
-
/* private functions */
static cairo_status_t
@@ -104,7 +102,8 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_poin
}
if (polygon->num_edges >= polygon->edges_size) {
- status = _cairo_polygon_grow_by (polygon, CAIRO_POLYGON_GROWTH_INC);
+ int additional = polygon->edges_size ? polygon->edges_size : 16;
+ status = _cairo_polygon_grow_by (polygon, additional);
if (status) {
return status;
}
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index bfdfada38..4da8162c7 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-ps.h"
#include <time.h>
#include <zlib.h>
@@ -130,8 +131,6 @@ cairo_ps_surface_create (FILE *file,
"%%%%CreationDate: %s",
ctime (&now));
fprintf (file,
- "%%%%Copyright: 2003 Carl Worth and Keith Packard\n");
- fprintf (file,
"%%%%BoundingBox: %d %d %d %d\n",
0, 0, (int) (surface->width_inches * 72.0), (int) (surface->height_inches * 72.0));
/* The "/FlateDecode filter" currently used is a feature of LanguageLevel 3 */
diff --git a/src/cairo-ps.h b/src/cairo-ps.h
new file mode 100644
index 000000000..ae8e72192
--- /dev/null
+++ b/src/cairo-ps.h
@@ -0,0 +1,63 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_PS_H
+#define CAIRO_PS_H
+#ifdef CAIRO_HAS_PS_SURFACE
+
+#include <stdio.h>
+
+void
+cairo_set_target_ps (cairo_t *cr,
+ FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch);
+
+/* PS-surface functions */
+
+cairo_surface_t *
+cairo_ps_surface_create (FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch);
+
+#endif /* CAIRO_HAS_PS_SURFACE */
+#endif /* CAIRO_PS_H */
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
new file mode 100644
index 000000000..b7103b051
--- /dev/null
+++ b/src/cairo-quartz-surface.c
@@ -0,0 +1,392 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Calum Robinson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Calum Robinson
+ *
+ * Contributor(s):
+ * Calum Robinson <calumr@mac.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-quartz.h"
+
+#pragma mark Types
+
+typedef struct cairo_quartz_surface {
+ cairo_surface_t base;
+
+ CGContextRef context;
+
+ int width;
+ int height;
+
+ cairo_image_surface_t *image;
+
+ CGImageRef cgImage;
+} cairo_quartz_surface_t;
+
+
+
+
+
+#pragma mark Private functions
+
+
+
+
+void ImageDataReleaseFunc(void *info, const void *data, size_t size)
+{
+ if (data != NULL)
+ {
+ free((void *)data);
+ }
+}
+
+
+
+
+#pragma mark Public functions
+
+
+
+
+
+void
+cairo_set_target_quartz_context( cairo_t *cr,
+ CGContextRef context,
+ int width,
+ int height)
+{
+ cairo_surface_t *surface;
+
+
+ if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
+ return;
+
+ surface = cairo_quartz_surface_create(context, width, height);
+ if (surface == NULL)
+ {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_set_target_surface(cr, surface);
+
+ /* cairo_set_target_surface takes a reference, so we must destroy ours */
+ cairo_surface_destroy(surface);
+}
+
+
+static cairo_surface_t *
+_cairo_quartz_surface_create_similar( void *abstract_src,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ return NULL;
+}
+
+
+static void
+_cairo_quartz_surface_destroy(void *abstract_surface)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+
+
+ if (surface->cgImage)
+ {
+ CGImageRelease(surface->cgImage);
+ }
+
+
+ free(surface);
+}
+
+
+static double
+_cairo_quartz_surface_pixels_per_inch(void *abstract_surface)
+{
+
+
+ // TODO - get this from CGDirectDisplay somehow?
+ return 96.0;
+}
+
+
+static cairo_image_surface_t *
+_cairo_quartz_surface_get_image(void *abstract_surface)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+ CGColorSpaceRef colorSpace;
+ void *imageData;
+ UInt32 imageDataSize, rowBytes;
+ CGDataProviderRef dataProvider;
+
+
+ // We keep a cached (cairo_image_surface_t *) in the cairo_quartz_surface_t
+ // struct. If the window is ever drawn to without going through Cairo, then
+ // we would need to refetch the pixel data from the window into the cached
+ // image surface.
+ if (surface->image)
+ {
+ cairo_surface_reference(&surface->image->base);
+
+ return surface->image;
+ }
+
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+
+
+ rowBytes = surface->width * 4;
+ imageDataSize = rowBytes * surface->height;
+ imageData = malloc(imageDataSize);
+
+ dataProvider = CGDataProviderCreateWithData(NULL, imageData, imageDataSize, ImageDataReleaseFunc);
+
+ surface->cgImage = CGImageCreate( surface->width,
+ surface->height,
+ 8,
+ 32,
+ rowBytes,
+ colorSpace,
+ kCGImageAlphaPremultipliedFirst,
+ dataProvider,
+ NULL,
+ false,
+ kCGRenderingIntentDefault);
+
+
+ CGColorSpaceRelease(colorSpace);
+ CGDataProviderRelease(dataProvider);
+
+
+ surface->image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data( imageData,
+ CAIRO_FORMAT_ARGB32,
+ surface->width,
+ surface->height,
+ rowBytes);
+
+
+ // Set the image surface Cairo state to match our own.
+ _cairo_image_surface_set_repeat(surface->image, surface->base.repeat);
+ _cairo_image_surface_set_matrix(surface->image, &(surface->base.matrix));
+
+
+ return surface->image;
+}
+
+
+static cairo_status_t
+_cairo_quartz_surface_set_image( void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+
+ if (surface->image == image)
+ {
+ CGRect rect;
+
+
+ rect = CGRectMake(0, 0, surface->width, surface->height);
+
+ CGContextDrawImage(surface->context, rect, surface->cgImage);
+
+
+ status = CAIRO_STATUS_SUCCESS;
+ }
+ else
+ {
+ // TODO - set_image from something other than what we returned from get_image
+ status = CAIRO_STATUS_NO_TARGET_SURFACE;
+ }
+
+
+ return status;
+}
+
+
+static cairo_status_t
+_cairo_quartz_surface_set_matrix(void *abstract_surface, cairo_matrix_t *matrix)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_set_matrix(surface->image, matrix);
+}
+
+
+static cairo_status_t
+_cairo_quartz_surface_set_filter(void *abstract_surface, cairo_filter_t filter)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_set_filter(surface->image, filter);
+}
+
+
+static cairo_status_t
+_cairo_quartz_surface_set_repeat(void *abstract_surface, int repeat)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_set_repeat(surface->image, repeat);
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_composite( cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ cairo_surface_t *generic_mask,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_fill_rectangles( void *abstract_surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_composite_trapezoids( cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ void *abstract_dst,
+ int xSrc,
+ int ySrc,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_copy_page(void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_show_page(void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_set_clip_region( void *abstract_surface,
+ pixman_region16_t *region)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_set_clip_region(surface->image, region);
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_create_pattern( void *abstract_surface,
+ cairo_pattern_t *pattern,
+ cairo_box_t *extents)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
+ _cairo_quartz_surface_create_similar,
+ _cairo_quartz_surface_destroy,
+ _cairo_quartz_surface_pixels_per_inch,
+ _cairo_quartz_surface_get_image,
+ _cairo_quartz_surface_set_image,
+ _cairo_quartz_surface_set_matrix,
+ _cairo_quartz_surface_set_filter,
+ _cairo_quartz_surface_set_repeat,
+ _cairo_quartz_surface_composite,
+ _cairo_quartz_surface_fill_rectangles,
+ _cairo_quartz_surface_composite_trapezoids,
+ _cairo_quartz_surface_copy_page,
+ _cairo_quartz_surface_show_page,
+ _cairo_quartz_surface_set_clip_region,
+ _cairo_quartz_surface_create_pattern
+};
+
+
+cairo_surface_t *
+cairo_quartz_surface_create( CGContextRef context,
+ int width,
+ int height)
+{
+ cairo_quartz_surface_t *surface;
+
+
+ surface = malloc(sizeof(cairo_quartz_surface_t));
+ if (surface == NULL)
+ return NULL;
+
+ _cairo_surface_init(&surface->base, &cairo_quartz_surface_backend);
+
+
+ surface->context = context;
+
+ surface->width = width;
+ surface->height = height;
+
+ surface->image = NULL;
+
+ surface->cgImage = NULL;
+
+
+ // Set up the image surface which Cairo draws into and we blit to & from.
+ surface->image = _cairo_quartz_surface_get_image(surface);
+
+
+ return (cairo_surface_t *)surface;
+}
+
+
+DEPRECATE (cairo_surface_create_for_drawable, cairo_quartz_surface_create);
diff --git a/src/cairo-quartz.h b/src/cairo-quartz.h
new file mode 100644
index 000000000..918bc18d7
--- /dev/null
+++ b/src/cairo-quartz.h
@@ -0,0 +1,58 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_QUARTZ_H
+#define CAIRO_QUARTZ_H
+#ifdef CAIRO_HAS_QUARTZ_SURFACE
+
+#include <Carbon/Carbon.h>
+
+void
+cairo_set_target_quartz_context( cairo_t *cr,
+ CGContextRef context,
+ int width,
+ int height);
+
+cairo_surface_t *
+cairo_quartz_surface_create ( CGContextRef context,
+ int width,
+ int height);
+
+#endif /* CAIRO_HAS_QUARTZ_SURFACE */
+#endif /* CAIRO_QUARTZ_H */
+
diff --git a/src/cairo-spline.c b/src/cairo-spline.c
index bed351ef4..ff290d9dd 100644
--- a/src/cairo-spline.c
+++ b/src/cairo-spline.c
@@ -54,8 +54,6 @@ _cairo_spline_error_squared (cairo_spline_t *spline);
static cairo_status_t
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result);
-#define CAIRO_SPLINE_GROWTH_INC 100
-
cairo_int_status_t
_cairo_spline_init (cairo_spline_t *spline,
cairo_point_t *a, cairo_point_t *b,
@@ -136,7 +134,8 @@ _cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point)
}
if (spline->num_points >= spline->points_size) {
- status = _cairo_spline_grow_by (spline, CAIRO_SPLINE_GROWTH_INC);
+ int additional = spline->points_size ? spline->points_size : 32;
+ status = _cairo_spline_grow_by (spline, additional);
if (status)
return status;
}
diff --git a/src/cairo-wideint.c b/src/cairo-wideint.c
index 67ba3f9b9..953108339 100644
--- a/src/cairo-wideint.c
+++ b/src/cairo-wideint.c
@@ -1,25 +1,37 @@
/*
- * $Id: cairo-wideint.c,v 1.1 2004-05-28 19:37:15 keithp Exp $
+ * $Id: cairo-wideint.c,v 1.4 2005-01-19 15:07:00 cworth 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.
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
*
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Keith Packard
+ *
+ * Contributor(s):
+ * Keith R. Packard <keithp@keithp.com>
*/
#include "cairoint.h"
@@ -44,7 +56,7 @@ static const unsigned char top_bit[256] =
#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
-const cairo_uquorem64_t
+cairo_uquorem64_t
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
{
cairo_uquorem64_t qr;
@@ -56,7 +68,7 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
#else
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint32_to_uint64 (uint32_t i)
{
cairo_uint64_t q;
@@ -66,7 +78,7 @@ _cairo_uint32_to_uint64 (uint32_t i)
return q;
}
-const cairo_int64_t
+cairo_int64_t
_cairo_int32_to_int64 (int32_t i)
{
cairo_uint64_t q;
@@ -86,7 +98,7 @@ _cairo_uint32s_to_uint64 (uint32_t h, uint32_t l)
return q;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
@@ -98,7 +110,7 @@ _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
@@ -114,7 +126,7 @@ _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
#define uint32_hi(i) ((i) >> 16)
#define uint32_carry16 ((1) << 16)
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
{
cairo_uint64_t s;
@@ -142,7 +154,18 @@ _cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
return s;
}
-const cairo_uint64_t
+cairo_int64_t
+_cairo_int32x32_64_mul (int32_t a, int32_t b)
+{
+ s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t b));
+ if (a < 0)
+ s.hi -= b;
+ if (b < 0)
+ s.hi -= a;
+ return s;
+}
+
+cairo_uint64_t
_cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
@@ -152,7 +175,7 @@ _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_lsl (cairo_uint64_t a, int shift)
{
if (shift >= 32)
@@ -169,7 +192,7 @@ _cairo_uint64_lsl (cairo_uint64_t a, int shift)
return a;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_rsl (cairo_uint64_t a, int shift)
{
if (shift >= 32)
@@ -188,7 +211,7 @@ _cairo_uint64_rsl (cairo_uint64_t a, int shift)
#define _cairo_uint32_rsa(a,n) ((uint32_t) (((int32_t) (a)) >> (n)))
-const cairo_int64_t
+cairo_int64_t
_cairo_uint64_rsa (cairo_int64_t a, int shift)
{
if (shift >= 32)
@@ -205,20 +228,20 @@ _cairo_uint64_rsa (cairo_int64_t a, int shift)
return a;
}
-const int
+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
+int
_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b)
{
return a.hi == b.hi && a.lo == b.lo;
}
-const int
+int
_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
{
if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
@@ -228,7 +251,7 @@ _cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
return _cairo_uint64_lt (a, b);
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_not (cairo_uint64_t a)
{
a.lo = ~a.lo;
@@ -236,7 +259,7 @@ _cairo_uint64_not (cairo_uint64_t a)
return a;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_negate (cairo_uint64_t a)
{
a.lo = ~a.lo;
@@ -325,7 +348,7 @@ _cairo_uint64x32_normalized_divrem (cairo_uint64_t num, uint32_t den)
return qr;
}
-const cairo_uquorem64_t
+cairo_uquorem64_t
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
{
cairo_uquorem32_t qr32;
@@ -444,7 +467,7 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
#endif /* !HAVE_UINT64_T */
-const cairo_quorem64_t
+cairo_quorem64_t
_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
{
int num_neg = _cairo_int64_negative (num);
@@ -470,7 +493,7 @@ _cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
#if HAVE_UINT128_T
-const cairo_uquorem128_t
+cairo_uquorem128_t
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
{
cairo_uquorem128_t qr;
@@ -482,7 +505,7 @@ _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
#else
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint32_to_uint128 (uint32_t i)
{
cairo_uint128_t q;
@@ -492,7 +515,7 @@ _cairo_uint32_to_uint128 (uint32_t i)
return q;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int32_to_int128 (int32_t i)
{
cairo_int128_t q;
@@ -502,7 +525,7 @@ _cairo_int32_to_int128 (int32_t i)
return q;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint64_to_uint128 (cairo_uint64_t i)
{
cairo_uint128_t q;
@@ -512,7 +535,7 @@ _cairo_uint64_to_uint128 (cairo_uint64_t i)
return q;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int64_to_int128 (cairo_int64_t i)
{
cairo_int128_t q;
@@ -522,7 +545,7 @@ _cairo_int64_to_int128 (cairo_int64_t i)
return q;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
@@ -534,7 +557,7 @@ _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
return s;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
@@ -594,7 +617,7 @@ static const cairo_uint64_t uint64_carry32 = { 0, 1 };
#endif
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint128_t s;
@@ -622,7 +645,22 @@ _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint128_t
+cairo_int128_t
+_cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b)
+{
+ cairo_int128_t s;
+ s = _cairo_uint64x64_128_mul (_cairo_int64_to_uint64(a),
+ _cairo_int64_to_uint64(b));
+ if (_cairo_int64_negative (a))
+ s.hi = _cairo_uint64_sub (s.hi,
+ _cairo_int64_to_uint64 (b));
+ if (_cairo_int64_negative (b))
+ s.hi = _cairo_uint64_sub (s.hi,
+ _cairo_int64_to_uint64 (a));
+ return s;
+}
+
+cairo_uint128_t
_cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
@@ -635,7 +673,7 @@ _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b)
return s;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_lsl (cairo_uint128_t a, int shift)
{
if (shift >= 64)
@@ -653,7 +691,7 @@ _cairo_uint128_lsl (cairo_uint128_t a, int shift)
return a;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_rsl (cairo_uint128_t a, int shift)
{
if (shift >= 64)
@@ -671,7 +709,7 @@ _cairo_uint128_rsl (cairo_uint128_t a, int shift)
return a;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_rsa (cairo_int128_t a, int shift)
{
if (shift >= 64)
@@ -689,7 +727,7 @@ _cairo_uint128_rsa (cairo_int128_t a, int shift)
return a;
}
-const int
+int
_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
{
return (_cairo_uint64_lt (a.hi, b.hi) ||
@@ -697,7 +735,7 @@ _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
_cairo_uint64_lt (a.lo, b.lo)));
}
-const int
+int
_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
{
if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
@@ -707,7 +745,7 @@ _cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
return _cairo_uint128_lt (a, b);
}
-const int
+int
_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
{
return (_cairo_uint64_eq (a.hi, b.hi) &&
@@ -722,7 +760,7 @@ _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
/*
* den >= num.hi
*/
-static const cairo_uquorem64_t
+static cairo_uquorem64_t
_cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
{
cairo_uquorem64_t qr64;
@@ -786,7 +824,7 @@ _cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
#if HAVE_UINT64_T
-static const int
+static int
_cairo_leading_zeros64 (cairo_uint64_t q)
{
int top = 0;
@@ -823,7 +861,7 @@ _cairo_leading_zeros64 (cairo_uint64_t d)
#endif
-const cairo_uquorem128_t
+cairo_uquorem128_t
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
{
cairo_uquorem64_t qr64;
@@ -943,7 +981,7 @@ _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
return qr;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int128_negate (cairo_int128_t a)
{
a.lo = _cairo_uint64_not (a.lo);
@@ -951,7 +989,7 @@ _cairo_int128_negate (cairo_int128_t a)
return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1));
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int128_not (cairo_int128_t a)
{
a.lo = _cairo_uint64_not (a.lo);
@@ -961,7 +999,7 @@ _cairo_int128_not (cairo_int128_t a)
#endif /* !HAVE_UINT128_T */
-const cairo_quorem128_t
+cairo_quorem128_t
_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den)
{
int num_neg = _cairo_int128_negative (num);
diff --git a/src/cairo-wideint.h b/src/cairo-wideint.h
index d08e039f1..abe36f9d4 100644
--- a/src/cairo-wideint.h
+++ b/src/cairo-wideint.h
@@ -1,25 +1,38 @@
/*
- * $Id: cairo-wideint.h,v 1.1 2004-05-28 19:37:15 keithp Exp $
+ * $Id: cairo-wideint.h,v 1.6 2005-01-19 15:11:14 cworth 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.
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Keith Packard
+ *
+ * Contributor(s):
+ * Keith R. Packard <keithp@keithp.com>
*
- * 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
@@ -33,7 +46,7 @@
* as a pair of 32-bit ints
*/
-#define I __internal_linkage
+#define I cairo_private
#if !HAVE_UINT64_T
@@ -41,31 +54,31 @@ 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);
+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);
+cairo_uint64_t I _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint64_t I _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint64_t I _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint64_t I _cairo_uint32x32_64_mul (uint32_t a, uint32_t b);
+cairo_uint64_t I _cairo_uint64_lsl (cairo_uint64_t a, int shift);
+cairo_uint64_t I _cairo_uint64_rsl (cairo_uint64_t a, int shift);
+cairo_uint64_t I _cairo_uint64_rsa (cairo_uint64_t a, int shift);
+int I _cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b);
+int I _cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b);
+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);
+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);
+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);
+int I _cairo_int32x32_64_mul (int32_t a, int32_t b);
+int I _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)
@@ -142,10 +155,10 @@ typedef struct _cairo_quorem64 {
cairo_int64_t rem;
} cairo_quorem64_t;
-const cairo_uquorem64_t I
+cairo_uquorem64_t I
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den);
-const cairo_quorem64_t I
+cairo_quorem64_t I
_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den);
/*
@@ -160,38 +173,38 @@ 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);
+cairo_uint128_t I _cairo_uint32_to_uint128 (uint32_t i);
+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);
+cairo_uint128_t I _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b);
+cairo_uint128_t I _cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b);
+cairo_uint128_t I _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b);
+cairo_uint128_t I _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b);
+cairo_uint128_t I _cairo_uint128_lsl (cairo_uint128_t a, int shift);
+cairo_uint128_t I _cairo_uint128_rsl (cairo_uint128_t a, int shift);
+cairo_uint128_t I _cairo_uint128_rsa (cairo_uint128_t a, int shift);
+int I _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b);
+int I _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b);
+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);
+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);
+cairo_int128_t I _cairo_int32_to_int128 (int32_t i);
+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))
+cairo_uint128_t I _cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_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);
+int I _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))
@@ -251,10 +264,10 @@ typedef struct _cairo_quorem128 {
cairo_int128_t rem;
} cairo_quorem128_t;
-const cairo_uquorem128_t I
+cairo_uquorem128_t I
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den);
-const cairo_quorem128_t I
+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))
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 21760d764..758cf26de 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -730,7 +730,7 @@ _cairo_xcb_surface_create_pattern (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static const struct cairo_surface_backend cairo_xcb_surface_backend = {
+static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_destroy,
_cairo_xcb_surface_pixels_per_inch,
diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h
new file mode 100644
index 000000000..27ebad523
--- /dev/null
+++ b/src/cairo-xcb.h
@@ -0,0 +1,54 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_XCB_H
+#define CAIRO_XCB_H
+#ifdef CAIRO_HAS_XCB_SURFACE
+
+#include <X11/XCB/xcb.h>
+#include <X11/XCB/render.h>
+
+void
+cairo_set_target_xcb (cairo_t *cr,
+ XCBConnection *dpy,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ cairo_format_t format);
+
+#endif /* CAIRO_HAS_XCB_SURFACE */
+#endif /* CAIRO_XCB_H */
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index dda7995bd..d9d74f583 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-xlib.h"
void
cairo_set_target_drawable (cairo_t *cr,
@@ -61,7 +62,7 @@ cairo_set_target_drawable (cairo_t *cr,
cairo_surface_destroy (surface);
}
-typedef struct cairo_xlib_surface {
+typedef struct _cairo_xlib_surface {
cairo_surface_t base;
Display *dpy;
@@ -118,6 +119,16 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
}
static cairo_surface_t *
+_cairo_xlib_surface_create_with_size (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ cairo_format_t format,
+ Colormap colormap,
+ int width,
+ int height);
+
+
+static cairo_surface_t *
_cairo_xlib_surface_create_similar (void *abstract_src,
cairo_format_t format,
int drawable,
@@ -149,7 +160,9 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
_CAIRO_FORMAT_DEPTH (format));
surface = (cairo_xlib_surface_t *)
- cairo_xlib_surface_create (dpy, pix, NULL, format, DefaultColormap (dpy, scr));
+ _cairo_xlib_surface_create_with_size (dpy, pix, NULL, format,
+ DefaultColormap (dpy, scr),
+ width, height);
surface->owns_pixmap = 1;
surface->width = width;
@@ -199,6 +212,7 @@ _cairo_xlib_surface_get_image (void *abstract_surface)
&surface->width, &surface->height,
&bwidth_ignore, &depth_ignore);
+ /* XXX: This should try to use the XShm extension if availible */
ximage = XGetImage (surface->dpy,
surface->drawable,
0, 0,
@@ -684,13 +698,13 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ void *abstract_surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs);
-static const struct cairo_surface_backend cairo_xlib_surface_backend = {
+static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_create_similar,
_cairo_xlib_surface_destroy,
_cairo_xlib_surface_pixels_per_inch,
@@ -709,17 +723,17 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = {
_cairo_xlib_surface_show_glyphs
};
-cairo_surface_t *
-cairo_xlib_surface_create (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap)
+static cairo_surface_t *
+_cairo_xlib_surface_create_with_size (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ cairo_format_t format,
+ Colormap colormap,
+ int width,
+ int height)
{
cairo_xlib_surface_t *surface;
int render_standard;
- Window w;
- unsigned int ignore;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@@ -736,7 +750,9 @@ cairo_xlib_surface_create (Display *dpy,
surface->drawable = drawable;
surface->owns_pixmap = 0;
surface->visual = visual;
-
+ surface->width = width;
+ surface->height = height;
+
if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
surface->render_major = -1;
surface->render_minor = -1;
@@ -758,12 +774,6 @@ 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,
@@ -776,8 +786,31 @@ cairo_xlib_surface_create (Display *dpy,
return (cairo_surface_t *) surface;
}
-DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
+cairo_surface_t *
+cairo_xlib_surface_create (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ cairo_format_t format,
+ Colormap colormap)
+{
+ Window window_ignore;
+ unsigned int int_ignore;
+ unsigned int width, height;
+
+ /* XXX: This call is a round-trip. We probably want to instead (or
+ * also?) export a version that accepts width/height. Then, we'll
+ * likely also need a resize function too.
+ */
+ XGetGeometry(dpy, drawable,
+ &window_ignore, &int_ignore, &int_ignore,
+ &width, &height,
+ &int_ignore, &int_ignore);
+
+ return _cairo_xlib_surface_create_with_size (dpy, drawable, visual, format,
+ colormap, width, height);
+}
+DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
/* RENDER glyphset cache code */
@@ -839,8 +872,45 @@ _xlib_glyphset_cache_create_entry (void *cache,
v->info.width = im->image ? im->image->stride : im->size.width;
v->info.height = im->size.height;
- v->info.x = - im->extents.x_bearing;
- v->info.y = im->extents.y_bearing;
+
+ /*
+ * Most of the font rendering system thinks of glyph tiles as having
+ * an origin at (0,0) and an x and y bounding box "offset" which
+ * extends possibly off into negative coordinates, like so:
+ *
+ *
+ * (x,y) <-- probably negative numbers
+ * +----------------+
+ * | . |
+ * | . |
+ * |......(0,0) |
+ * | |
+ * | |
+ * +----------------+
+ * (width+x,height+y)
+ *
+ * This is a postscript-y model, where each glyph has its own
+ * coordinate space, so it's what we expose in terms of metrics. It's
+ * apparantly what everyone's expecting. Everyone except the Render
+ * extension. Render wants to see a glyph tile starting at (0,0), with
+ * an origin offset inside, like this:
+ *
+ * (0,0)
+ * +---------------+
+ * | . |
+ * | . |
+ * |......(x,y) |
+ * | |
+ * | |
+ * +---------------+
+ * (width,height)
+ *
+ * Luckily, this is just the negation of the numbers we already have
+ * sitting around for x and y.
+ */
+
+ v->info.x = -im->size.x;
+ v->info.y = -im->size.y;
v->info.xOff = 0;
v->info.yOff = 0;
@@ -875,7 +945,7 @@ _xlib_glyphset_cache_destroy_entry (void *cache, void *entry)
free (v);
}
-const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
+static const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
_cairo_glyph_cache_hash,
_cairo_glyph_cache_keys_equal,
_xlib_glyphset_cache_create_entry,
@@ -964,6 +1034,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
unsigned int stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -987,10 +1058,12 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ thisX = (int) floor (glyphs[i].x + 0.5);
+ thisY = (int) floor (glyphs[i].y + 0.5);
+ elts[i].xOff = thisX - lastX;
+ elts[i].yOff = thisY - lastY;
+ lastX = thisX;
+ lastY = thisY;
}
XRenderCompositeText32 (self->dpy,
@@ -1039,6 +1112,7 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
unsigned short stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -1062,10 +1136,12 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ thisX = (int) floor (glyphs[i].x + 0.5);
+ thisY = (int) floor (glyphs[i].y + 0.5);
+ elts[i].xOff = thisX - lastX;
+ elts[i].yOff = thisY - lastY;
+ lastX = thisX;
+ lastY = thisY;
}
XRenderCompositeText16 (self->dpy,
@@ -1113,6 +1189,7 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
char stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -1136,10 +1213,12 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ thisX = (int) floor (glyphs[i].x + 0.5);
+ thisY = (int) floor (glyphs[i].y + 0.5);
+ elts[i].xOff = thisX - lastX;
+ elts[i].yOff = thisY - lastY;
+ lastX = thisX;
+ lastY = thisY;
}
XRenderCompositeText8 (self->dpy,
@@ -1172,14 +1251,14 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ void *abstract_surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
unsigned int elt_size;
- cairo_xlib_surface_t *self = (cairo_xlib_surface_t *) surface;
+ cairo_xlib_surface_t *self = abstract_surface;
cairo_image_surface_t *tmp = NULL;
cairo_xlib_surface_t *src = NULL;
glyphset_cache_t *g;
@@ -1200,7 +1279,7 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
}
/* prep the source surface. */
- if (source->backend == surface->backend) {
+ if (source->backend == self->base.backend) {
src = (cairo_xlib_surface_t *) source;
} else {
@@ -1209,7 +1288,7 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
goto FREE_ENTRIES;
src = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (surface, self->format, 1,
+ _cairo_surface_create_similar_scratch (&self->base, self->format, 1,
tmp->width, tmp->height);
if (src == NULL)
diff --git a/src/cairo-xlib.h b/src/cairo-xlib.h
new file mode 100644
index 000000000..4f241b034
--- /dev/null
+++ b/src/cairo-xlib.h
@@ -0,0 +1,71 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@isi.edu>
+ */
+
+#include <cairo.h>
+
+#ifndef CAIRO_XLIB_H
+#define CAIRO_XLIB_H
+#ifdef CAIRO_HAS_XLIB_SURFACE
+
+#include <X11/extensions/Xrender.h>
+
+/* XXX: This shold be renamed to cairo_set_target_xlib to match the
+ * other backends */
+void
+cairo_set_target_drawable (cairo_t *cr,
+ Display *dpy,
+ Drawable drawable);
+
+/* XXX: This is a mess from the user's POV. Should the Visual or the
+ cairo_format_t control what render format is used? Maybe I can have
+ cairo_surface_create_for_window with a visual, and
+ cairo_surface_create_for_pixmap with a cairo_format_t. Would that work?
+*/
+cairo_surface_t *
+cairo_xlib_surface_create (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ cairo_format_t format,
+ Colormap colormap);
+
+/* XXX: This has been proposed
+cairo_status_t
+cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height);
+*/
+
+#endif /* CAIRO_HAS_XLIB_SURFACE */
+#endif /* CAIRO_XLIB_H */
+
diff --git a/src/cairo.c b/src/cairo.c
index 7e6f1d7b4..20d94938c 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -39,12 +39,14 @@
#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)
{
+ if (cr == NULL)
+ return 0;
+
switch (cr->status) {
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_NO_MEMORY:
@@ -56,7 +58,6 @@ cairo_sane_state (cairo_t *cr)
case CAIRO_STATUS_NULL_POINTER:
break;
default:
- printf ("cairo status is bad: %d\n", cr->status);
return 0;
}
return 1;
@@ -159,6 +160,12 @@ cairo_restore (cairo_t *cr)
if (cr->gstate == NULL)
cr->status = CAIRO_STATUS_INVALID_RESTORE;
+
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_restore_external_state (cr->gstate);
+
CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_restore);
diff --git a/src/cairo.h b/src/cairo.h
index 25dfd4d6b..b7bcc1dbb 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -34,18 +34,16 @@
* Carl D. Worth <cworth@isi.edu>
*/
-#ifndef _CAIRO_H_
-#define _CAIRO_H_
+#ifndef CAIRO_H
+#define CAIRO_H
#include <cairo-features.h>
-
#include <pixman.h>
-#include <stdio.h>
-typedef struct cairo cairo_t;
-typedef struct cairo_surface cairo_surface_t;
-typedef struct cairo_matrix cairo_matrix_t;
-typedef struct cairo_pattern cairo_pattern_t;
+typedef struct _cairo cairo_t;
+typedef struct _cairo_surface cairo_surface_t;
+typedef struct _cairo_matrix cairo_matrix_t;
+typedef struct _cairo_pattern cairo_pattern_t;
#ifdef __cplusplus
extern "C" {
@@ -98,67 +96,6 @@ cairo_set_target_image (cairo_t *cr,
int height,
int stride);
-#ifdef CAIRO_HAS_PS_SURFACE
-
-#include <stdio.h>
-
-void
-cairo_set_target_ps (cairo_t *cr,
- FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch);
-
-#endif /* CAIRO_HAS_PS_SURFACE */
-
-#ifdef CAIRO_HAS_PNG_SURFACE
-
-#include <stdio.h>
-
-void
-cairo_set_target_png (cairo_t *cr,
- FILE *file,
- cairo_format_t format,
- int width,
- int height);
-
-#endif /* CAIRO_HAS_PNG_SURFACE */
-
-#ifdef CAIRO_HAS_XLIB_SURFACE
-
-#include <X11/extensions/Xrender.h>
-
-/* XXX: This shold be renamed to cairo_set_target_xlib to match the
- * other backends */
-void
-cairo_set_target_drawable (cairo_t *cr,
- Display *dpy,
- Drawable drawable);
-#endif /* CAIRO_HAS_XLIB_SURFACE */
-
-#ifdef CAIRO_HAS_XCB_SURFACE
-
-#include <X11/XCB/xcb.h>
-#include <X11/XCB/render.h>
-
-void
-cairo_set_target_xcb (cairo_t *cr,
- XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format);
-#endif /* CAIRO_HAS_XCB_SURFACE */
-
-#ifdef CAIRO_HAS_GLITZ_SURFACE
-
-#include <glitz.h>
-
-void
-cairo_set_target_glitz (cairo_t *cr,
- glitz_surface_t *surface);
-#endif /* CAIRO_HAS_GLITZ_SURFACE */
-
typedef enum cairo_operator {
CAIRO_OPERATOR_CLEAR,
CAIRO_OPERATOR_SRC,
@@ -393,7 +330,7 @@ cairo_clip (cairo_t *cr);
/* Font/Text functions */
-typedef struct cairo_font cairo_font_t;
+typedef struct _cairo_font cairo_font_t;
typedef struct {
unsigned long index;
@@ -493,27 +430,6 @@ void
cairo_font_current_transform (cairo_font_t *font,
cairo_matrix_t *matrix);
-/* Fontconfig/Freetype platform-specific font interface */
-
-#include <fontconfig/fontconfig.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-cairo_font_t *
-cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern);
-
-cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face);
-
-void
-cairo_ft_font_destroy (cairo_font_t *ft_font);
-
-FT_Face
-cairo_ft_font_face (cairo_font_t *ft_font);
-
-FcPattern *
-cairo_ft_font_pattern (cairo_font_t *ft_font);
-
/* Image functions */
/* XXX: Eliminate width/height here */
@@ -738,59 +654,6 @@ cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter);
cairo_filter_t
cairo_pattern_get_filter (cairo_pattern_t *pattern);
-#ifdef CAIRO_HAS_PS_SURFACE
-
-/* PS-surface functions */
-
-cairo_surface_t *
-cairo_ps_surface_create (FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch);
-
-#endif /* CAIRO_HAS_PS_SURFACE */
-
-#ifdef CAIRO_HAS_PNG_SURFACE
-
-/* PNG-surface functions */
-
-cairo_surface_t *
-cairo_png_surface_create (FILE *file,
- cairo_format_t format,
- int width,
- int height);
-
-#endif /* CAIRO_HAS_PNG_SURFACE */
-
-#ifdef CAIRO_HAS_XLIB_SURFACE
-
-/* XXX: This is a mess from the user's POV. Should the Visual or the
- cairo_format_t control what render format is used? Maybe I can have
- cairo_surface_create_for_window with a visual, and
- cairo_surface_create_for_pixmap with a cairo_format_t. Would that work?
-*/
-cairo_surface_t *
-cairo_xlib_surface_create (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap);
-
-/* XXX: This has been proposed
-cairo_status_t
-cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height);
-*/
-
-#endif /* CAIRO_HAS_XLIB_SURFACE */
-
-#ifdef CAIRO_HAS_GLITZ_SURFACE
-
-cairo_surface_t *
-cairo_glitz_surface_create (glitz_surface_t *surface);
-
-#endif /* CAIRO_HAS_GLITZ_SURFACE */
-
/* Matrix functions */
/* XXX: Rename all of these to cairo_transform_t */
@@ -865,4 +728,4 @@ cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y);
}
#endif
-#endif
+#endif /* CAIRO_H */
diff --git a/src/cairo_array.c b/src/cairo_array.c
new file mode 100644
index 000000000..2b1cf9d61
--- /dev/null
+++ b/src/cairo_array.c
@@ -0,0 +1,134 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include "cairoint.h"
+
+void
+_cairo_array_init (cairo_array_t *array, int element_size)
+{
+ array->size = 0;
+ array->num_elements = 0;
+ array->element_size = element_size;
+ array->elements = NULL;
+}
+
+void
+_cairo_array_fini (cairo_array_t *array)
+{
+ free (array->elements);
+}
+
+cairo_status_t
+_cairo_array_grow_by (cairo_array_t *array, int additional)
+{
+ char *new_elements;
+ int old_size = array->size;
+ int required_size = array->num_elements + additional;
+ int new_size;
+
+ if (required_size <= old_size)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (old_size == 0)
+ new_size = 1;
+ else
+ new_size = old_size * 2;
+
+ while (new_size < required_size)
+ new_size = new_size * 2;
+
+ array->size = new_size;
+ new_elements = realloc (array->elements,
+ array->size * array->element_size);
+
+ if (new_elements == NULL) {
+ array->size = old_size;
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ array->elements = new_elements;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_array_truncate (cairo_array_t *array, int num_elements)
+{
+ if (num_elements < array->num_elements)
+ array->num_elements = num_elements;
+}
+
+void *
+_cairo_array_index (cairo_array_t *array, int index)
+{
+ assert (0 <= index && index < array->num_elements);
+
+ return (void *) &array->elements[index * array->element_size];
+}
+
+void
+_cairo_array_copy_element (cairo_array_t *array, int index, void *dst)
+{
+ memcpy (dst, _cairo_array_index (array, index), array->element_size);
+}
+
+void *
+_cairo_array_append (cairo_array_t *array,
+ const void *elements, int num_elements)
+{
+ cairo_status_t status;
+ void *dest;
+
+ status = _cairo_array_grow_by (array, num_elements);
+ if (status != CAIRO_STATUS_SUCCESS)
+ return NULL;
+
+ assert (array->num_elements + num_elements <= array->size);
+
+ dest = &array->elements[array->num_elements * array->element_size];
+ array->num_elements += num_elements;
+
+ if (elements != NULL)
+ memcpy (dest, elements, num_elements * array->element_size);
+
+ return dest;
+}
+
+int
+_cairo_array_num_elements (cairo_array_t *array)
+{
+ return array->num_elements;
+}
diff --git a/src/cairo_atsui_font.c b/src/cairo_atsui_font.c
new file mode 100644
index 000000000..52cfc6bd8
--- /dev/null
+++ b/src/cairo_atsui_font.c
@@ -0,0 +1,807 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Calum Robinson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Calum Robinson
+ *
+ * Contributor(s):
+ * Calum Robinson <calumr@mac.com>
+ */
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "cairo-atsui.h"
+#include "cairoint.h"
+
+
+
+
+
+#pragma mark Types
+
+
+
+
+
+typedef struct {
+ cairo_unscaled_font_t base;
+
+ ATSUStyle style;
+ ATSUFontID fontID;
+} cairo_atsui_font_t;
+
+
+typedef struct cairo_ATSUI_glyph_path_callback_info_t {
+ cairo_path_t *path;
+ cairo_matrix_t scale;
+} cairo_ATSUI_glyph_path_callback_info_t;
+
+
+
+
+
+#pragma mark Private Functions
+
+
+
+
+
+static CGAffineTransform CGAffineTransformMakeWithCairoFontScale(cairo_font_scale_t scale)
+{
+ return CGAffineTransformMake( scale.matrix[0][0], scale.matrix[0][1],
+ scale.matrix[1][0], scale.matrix[1][1],
+ 0, 0);
+}
+
+
+static ATSUStyle CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_font_scale_t *scale)
+{
+ ATSUStyle style;
+ OSStatus err;
+
+
+ // Set the style's size
+ CGAffineTransform theTransform = CGAffineTransformMakeWithCairoFontScale(*scale);
+ Fixed theSize = FloatToFixed(CGSizeApplyAffineTransform(CGSizeMake(1.0, 1.0), theTransform).height);
+ const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag };
+ const ByteCount theFontStyleSizes[] = { sizeof(Fixed) };
+ ATSUAttributeValuePtr theFontStyleValues[] = { &theSize };
+
+ err = ATSUCreateAndCopyStyle(inStyle, &style);
+
+ err = ATSUSetAttributes( style,
+ sizeof(theFontStyleTags) / sizeof(ATSUAttributeTag),
+ theFontStyleTags, theFontStyleSizes, theFontStyleValues);
+
+
+ return style;
+}
+
+
+
+
+
+#pragma mark Public Functions
+
+
+
+
+
+static cairo_unscaled_font_t *
+_cairo_atsui_font_create( const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight)
+{
+ cairo_atsui_font_t *font = NULL;
+ ATSUStyle style;
+ ATSUFontID fontID;
+ OSStatus err;
+ Boolean isItalic, isBold;
+
+
+ err = ATSUCreateStyle(&style);
+
+
+ switch (weight)
+ {
+ case CAIRO_FONT_WEIGHT_BOLD:
+ isBold = true;
+ break;
+ case CAIRO_FONT_WEIGHT_NORMAL:
+ default:
+ isBold = false;
+ break;
+ }
+
+ switch (slant)
+ {
+ case CAIRO_FONT_SLANT_ITALIC:
+ isItalic = true;
+ break;
+ case CAIRO_FONT_SLANT_OBLIQUE:
+ isItalic = false;
+ break;
+ case CAIRO_FONT_SLANT_NORMAL:
+ default:
+ isItalic = false;
+ break;
+ }
+
+ err = ATSUFindFontFromName( family, strlen(family),
+ kFontFamilyName,
+ kFontNoPlatformCode,
+ kFontRomanScript,
+ kFontNoLanguageCode,
+ &fontID);
+
+
+ ATSUAttributeTag styleTags[] = {kATSUQDItalicTag, kATSUQDBoldfaceTag, kATSUFontTag};
+ ATSUAttributeValuePtr styleValues[] = {&isItalic, &isBold, &fontID};
+ ByteCount styleSizes[] = {sizeof(Boolean), sizeof(Boolean), sizeof(ATSUFontID)};
+
+
+ err = ATSUSetAttributes( style,
+ sizeof(styleTags) / sizeof(styleTags[0]),
+ styleTags,
+ styleSizes,
+ styleValues);
+
+
+
+ font = malloc(sizeof(cairo_atsui_font_t));
+
+ if (_cairo_unscaled_font_init(&font->base, &cairo_atsui_font_backend) == CAIRO_STATUS_SUCCESS)
+ {
+ font->style = style;
+ font->fontID = fontID;
+
+
+ return &font->base;
+ }
+
+
+ free(font);
+
+ return NULL;
+}
+
+
+static void
+_cairo_atsui_font_destroy(void *abstract_font)
+{
+ cairo_atsui_font_t *font = abstract_font;
+
+
+ if (font == NULL)
+ return;
+
+ if (font->style)
+ ATSUDisposeStyle(font->style);
+
+ free(font);
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_text_to_glyphs( void *abstract_font,
+ cairo_font_scale_t *sc,
+ const unsigned char *utf8,
+ cairo_glyph_t **glyphs,
+ int *nglyphs)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ size_t i;
+ OSStatus err;
+ ATSUTextLayout textLayout;
+ ATSLayoutRecord *layoutRecords;
+ ItemCount glyphCount, charCount;
+ UniChar *theText;
+ ATSUStyle style;
+
+
+ charCount = strlen(utf8);
+
+
+ err = ATSUCreateTextLayout(&textLayout);
+
+
+ // Set the text in the text layout object, so we can measure it
+ theText = (UniChar *)malloc(charCount * sizeof(UniChar));
+
+ for (i = 0; i < charCount; i++)
+ {
+ theText[i] = utf8[i];
+ }
+
+ err = ATSUSetTextPointerLocation( textLayout,
+ theText,
+ 0,
+ charCount,
+ charCount);
+
+
+ style = CreateSizedCopyOfStyle(font->style, sc);
+
+
+ // Set the style for all of the text
+ err = ATSUSetRunStyle( textLayout,
+ style,
+ kATSUFromTextBeginning,
+ kATSUToTextEnd);
+
+
+
+ // Get the glyphs from the text layout object
+ err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout( textLayout,
+ 0,
+ kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
+ (void *)&layoutRecords,
+ &glyphCount);
+
+ *nglyphs = glyphCount;
+
+
+ *glyphs = (cairo_glyph_t *)malloc(glyphCount * (sizeof(cairo_glyph_t)));
+ if (*glyphs == NULL)
+ {
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < glyphCount; i++)
+ {
+ (*glyphs)[i].index = layoutRecords[i].glyphID;
+ (*glyphs)[i].x = FixedToFloat(layoutRecords[i].realPos);
+ (*glyphs)[i].y = 0;
+ }
+
+
+ free(theText);
+
+ ATSUDirectReleaseLayoutDataArrayPtr( NULL,
+ kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
+ (void *)&layoutRecords);
+
+ ATSUDisposeTextLayout(textLayout);
+
+ ATSUDisposeStyle(style);
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_font_extents( void *abstract_font,
+ cairo_font_scale_t *sc,
+ cairo_font_extents_t *extents)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ ATSFontRef atsFont;
+ ATSFontMetrics metrics;
+ OSStatus err;
+
+
+ // TODO - test this
+
+ atsFont = FMGetATSFontRefFromFont(font->fontID);
+
+ if (atsFont)
+ {
+ err = ATSFontGetHorizontalMetrics(atsFont, kATSOptionFlagsDefault, &metrics);
+
+ if (err == noErr)
+ {
+ extents->ascent = metrics.ascent;
+ extents->descent = metrics.descent;
+ extents->height = metrics.capHeight;
+ extents->max_x_advance = metrics.maxAdvanceWidth;
+
+ // The FT backend doesn't handle max_y_advance either, so we'll ignore it for now.
+ extents->max_y_advance = 0.0;
+
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+
+ return CAIRO_STATUS_NULL_POINTER;
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_glyph_extents( void *abstract_font,
+ cairo_font_scale_t *sc,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ cairo_point_double_t origin;
+ cairo_point_double_t glyph_min, glyph_max;
+ cairo_point_double_t total_min, total_max;
+ OSStatus err;
+ ATSUStyle style;
+ int i;
+
+
+ if (num_glyphs == 0)
+ {
+ extents->x_bearing = 0.0;
+ extents->y_bearing = 0.0;
+ extents->width = 0.0;
+ extents->height = 0.0;
+ extents->x_advance = 0.0;
+ extents->y_advance = 0.0;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ origin.x = glyphs[0].x;
+ origin.y = glyphs[0].y;
+
+
+ style = CreateSizedCopyOfStyle(font->style, sc);
+
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ GlyphID theGlyph = glyphs[i].index;
+ double minX, maxX, ascent, descent;
+ ATSGlyphIdealMetrics metricsH, metricsV;
+
+
+ err = ATSUGlyphGetIdealMetrics( style,
+ 1,
+ &theGlyph,
+ 0,
+ &metricsH);
+
+
+ ATSUVerticalCharacterType verticalType = kATSUStronglyVertical;
+ ATSUAttributeTag theTag = kATSUVerticalCharacterTag;
+ ByteCount theSize = sizeof(ATSUVerticalCharacterType);
+
+ err = ATSUSetAttributes(style, 1, &theTag, &theSize, (ATSUAttributeValuePtr)&verticalType);
+
+ err = ATSUGlyphGetIdealMetrics( style,
+ 1,
+ &theGlyph,
+ 0,
+ &metricsV);
+
+ minX = metricsH.otherSideBearing.x;
+ maxX = metricsH.advance.x;
+
+ ascent = metricsV.advance.x;
+ descent = metricsV.otherSideBearing.x;
+
+ glyph_min.x = glyphs[i].x + minX;
+ glyph_min.y = glyphs[i].y + descent;
+ glyph_max.x = glyphs[i].x + maxX;
+ glyph_max.y = glyphs[i].y + ascent;
+
+ if (i==0)
+ {
+ total_min = glyph_min;
+ total_max = glyph_max;
+ }
+ else
+ {
+ if (glyph_min.x < total_min.x)
+ total_min.x = glyph_min.x;
+ if (glyph_min.y < total_min.y)
+ total_min.y = glyph_min.y;
+
+ if (glyph_max.x > total_max.x)
+ total_max.x = glyph_max.x;
+ if (glyph_max.y > total_max.y)
+ total_max.y = glyph_max.y;
+ }
+ }
+
+
+ extents->x_bearing = total_min.x - origin.x;
+ extents->y_bearing = total_min.y - origin.y;
+ extents->width = total_max.x - total_min.x;
+ extents->height = total_max.y - total_min.y;
+ extents->x_advance = glyphs[i-1].x - origin.x;
+ extents->y_advance = glyphs[i-1].y - origin.y;
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_glyph_bbox( void *abstract_font,
+ cairo_font_scale_t *sc,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ cairo_fixed_t x1, y1, x2, y2;
+ int i;
+ OSStatus err;
+ ATSUStyle style;
+
+
+ bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16;
+ bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16;
+
+
+ style = CreateSizedCopyOfStyle(font->style, sc);
+
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ GlyphID theGlyph = glyphs[i].index;
+ ATSGlyphIdealMetrics metrics;
+
+
+ err = ATSUGlyphGetIdealMetrics( style,
+ 1,
+ &theGlyph,
+ 0,
+ &metrics);
+
+ x1 = _cairo_fixed_from_double(glyphs[i].x);
+ y1 = _cairo_fixed_from_double(glyphs[i].y);
+ x2 = x1 + _cairo_fixed_from_double(metrics.advance.x);
+ y2 = y1 + _cairo_fixed_from_double(metrics.advance.y);
+
+ 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;
+ }
+
+
+ ATSUDisposeStyle(style);
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_show_glyphs( void *abstract_font,
+ cairo_font_scale_t *sc,
+ cairo_operator_t operator,
+ cairo_surface_t *source,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ CGContextRef myBitmapContext;
+ CGColorSpaceRef colorSpace;
+ cairo_image_surface_t *destImageSurface;
+ int i;
+
+
+ destImageSurface = _cairo_surface_get_image(surface);
+
+
+ // Create a CGBitmapContext for the dest surface for drawing into
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+
+ myBitmapContext = CGBitmapContextCreate( destImageSurface->data,
+ destImageSurface->width,
+ destImageSurface->height,
+ destImageSurface->depth / 4,
+ destImageSurface->stride,
+ colorSpace,
+ kCGImageAlphaPremultipliedFirst);
+
+
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(font->fontID);
+ CGFontRef cgFont = CGFontCreateWithPlatformFont(&atsFont);
+
+ CGContextSetFont(myBitmapContext, cgFont);
+
+
+ CGAffineTransform textTransform = CGAffineTransformMakeWithCairoFontScale(*sc);
+ CGSize textSize = CGSizeMake(1.0, 1.0);
+
+ textSize = CGSizeApplyAffineTransform(textSize, textTransform);
+
+ CGContextSetFontSize(myBitmapContext, textSize.width);
+
+
+ // TODO - bold and italic text
+ //
+ // We could draw the text using ATSUI and get bold, italics
+ // etc. for free, but ATSUI does a lot of text layout work
+ // that we don't really need...
+
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ CGGlyph theGlyph = glyphs[i].index;
+
+ CGContextShowGlyphsAtPoint(myBitmapContext, source_x + glyphs[i].x, destImageSurface->height - (source_y + glyphs[i].y), &theGlyph, 1);
+ }
+
+
+ CGColorSpaceRelease(colorSpace);
+ CGContextRelease(myBitmapContext);
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+#pragma mark -
+
+
+static OSStatus MyATSCubicMoveToCallback(const Float32Point *pt, void *callBackDataPtr)
+{
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ double scaledPt[2];
+ cairo_point_t point;
+
+
+ scaledPt[0] = pt->x;
+ scaledPt[1] = pt->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ point.x = _cairo_fixed_from_double(scaledPt[0]);
+ point.y = _cairo_fixed_from_double(scaledPt[1]);
+
+ _cairo_path_move_to(info->path, &point);
+
+
+ return noErr;
+}
+
+
+static OSStatus MyATSCubicLineToCallback(const Float32Point *pt, void *callBackDataPtr)
+{
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ cairo_point_t point;
+ double scaledPt[2];
+
+
+ scaledPt[0] = pt->x;
+ scaledPt[1] = pt->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ point.x = _cairo_fixed_from_double(scaledPt[0]);
+ point.y = _cairo_fixed_from_double(scaledPt[1]);
+
+ _cairo_path_line_to(info->path, &point);
+
+
+ return noErr;
+}
+
+
+static OSStatus MyATSCubicCurveToCallback( const Float32Point *pt1,
+ const Float32Point *pt2,
+ const Float32Point *pt3,
+ void *callBackDataPtr)
+{
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ cairo_point_t p0, p1, p2;
+ double scaledPt[2];
+
+
+ scaledPt[0] = pt1->x;
+ scaledPt[1] = pt1->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ p0.x = _cairo_fixed_from_double(scaledPt[0]);
+ p0.y = _cairo_fixed_from_double(scaledPt[1]);
+
+
+ scaledPt[0] = pt2->x;
+ scaledPt[1] = pt2->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ p1.x = _cairo_fixed_from_double(scaledPt[0]);
+ p1.y = _cairo_fixed_from_double(scaledPt[1]);
+
+
+ scaledPt[0] = pt3->x;
+ scaledPt[1] = pt3->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ p2.x = _cairo_fixed_from_double(scaledPt[0]);
+ p2.y = _cairo_fixed_from_double(scaledPt[1]);
+
+
+ _cairo_path_curve_to(info->path, &p0, &p1, &p2);
+
+
+ return noErr;
+}
+
+
+static OSStatus MyCubicClosePathProc(void * callBackDataPtr)
+{
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+
+
+ _cairo_path_close_path(info->path);
+
+
+ return noErr;
+}
+
+
+static cairo_status_t
+_cairo_atsui_font_glyph_path( void *abstract_font,
+ cairo_font_scale_t *sc,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path)
+{
+ int i;
+ cairo_atsui_font_t *font = abstract_font;
+ OSStatus err;
+ cairo_ATSUI_glyph_path_callback_info_t info;
+ ATSUStyle style;
+
+
+ static ATSCubicMoveToUPP moveProc = NULL;
+ static ATSCubicLineToUPP lineProc = NULL;
+ static ATSCubicCurveToUPP curveProc = NULL;
+ static ATSCubicClosePathUPP closePathProc = NULL;
+
+
+ if (moveProc == NULL)
+ {
+ moveProc = NewATSCubicMoveToUPP(MyATSCubicMoveToCallback);
+ lineProc = NewATSCubicLineToUPP(MyATSCubicLineToCallback);
+ curveProc = NewATSCubicCurveToUPP(MyATSCubicCurveToCallback);
+ closePathProc = NewATSCubicClosePathUPP(MyCubicClosePathProc);
+ }
+
+
+ info.path = path;
+
+
+ style = CreateSizedCopyOfStyle(font->style, sc);
+
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ GlyphID theGlyph = glyphs[i].index;
+
+
+ cairo_matrix_set_affine( &info.scale,
+ 1.0, 0.0,
+ 0.0, 1.0,
+ glyphs[i].x, glyphs[i].y);
+
+
+ err = ATSUGlyphGetCubicPaths( style,
+ theGlyph,
+ moveProc,
+ lineProc,
+ curveProc,
+ closePathProc,
+ (void *)&info,
+ &err);
+ }
+
+
+ err = ATSUDisposeStyle(style);
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+#pragma mark -
+
+
+static cairo_status_t
+_cairo_atsui_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
+{
+ // TODO
+ printf("_cairo_atsui_font_create_glyph is unimplemented\n");
+
+ // I'm not sure if we need this, given that the ATSUI backend does no caching(?)
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+cairo_font_t *
+cairo_atsui_font_create(ATSUStyle style)
+{
+ cairo_font_scale_t scale;
+ cairo_font_t *scaled;
+ cairo_atsui_font_t *f = NULL;
+
+
+ scaled = malloc(sizeof(cairo_font_t));
+ if (scaled == NULL)
+ return NULL;
+
+
+ f = malloc(sizeof(cairo_atsui_font_t));
+ if (f)
+ {
+ if (_cairo_unscaled_font_init(&f->base, &cairo_atsui_font_backend) == CAIRO_STATUS_SUCCESS)
+ {
+ f->style = style;
+
+ _cairo_font_init(scaled, &scale, &f->base);
+
+ return scaled;
+ }
+ }
+
+
+ free(scaled);
+
+
+ return NULL;
+}
+
+
+
+
+
+#pragma mark Backend
+
+
+
+
+
+const cairo_font_backend_t cairo_atsui_font_backend = {
+ _cairo_atsui_font_create,
+ _cairo_atsui_font_destroy,
+ _cairo_atsui_font_font_extents,
+ _cairo_atsui_font_text_to_glyphs,
+ _cairo_atsui_font_glyph_extents,
+ _cairo_atsui_font_glyph_bbox,
+ _cairo_atsui_font_show_glyphs,
+ _cairo_atsui_font_glyph_path,
+ _cairo_atsui_font_create_glyph
+};
diff --git a/src/cairo_cache.c b/src/cairo_cache.c
index a33d69a04..b097b609b 100644
--- a/src/cairo_cache.c
+++ b/src/cairo_cache.c
@@ -43,7 +43,7 @@
* Packard.
*/
-static cairo_cache_arrangement_t cache_arrangements [] = {
+static const cairo_cache_arrangement_t cache_arrangements [] = {
{ 16, 43, 41 },
{ 32, 73, 71 },
{ 64, 151, 149 },
@@ -114,7 +114,6 @@ static cairo_cache_arrangement_t cache_arrangements [] = {
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
#ifdef CAIRO_DO_SANITY_CHECKING
-#include <assert.h>
static void
_cache_sane_state (cairo_cache_t *cache)
{
@@ -122,13 +121,12 @@ _cache_sane_state (cairo_cache_t *cache)
assert (cache->entries != NULL);
assert (cache->backend != NULL);
assert (cache->arrangement != NULL);
- assert (cache->refcount > 0);
- assert (cache->used_memory <= cache->max_memory);
+ /* Cannot check this, a single object may larger */
+ /* assert (cache->used_memory <= cache->max_memory); */
assert (cache->live_entries <= cache->arrangement->size);
}
#else
#define _cache_sane_state(c)
-#define assert(x)
#endif
static void
@@ -140,7 +138,7 @@ _entry_destroy (cairo_cache_t *cache, unsigned long i)
{
cairo_cache_entry_base_t *entry = cache->entries[i];
assert(cache->live_entries > 0);
- assert(cache->used_memory > entry->memory);
+ assert(cache->used_memory >= entry->memory);
cache->live_entries--;
cache->used_memory -= entry->memory;
@@ -183,10 +181,12 @@ _cache_lookup (cairo_cache_t *cache,
if (predicate != NULL)
{
/* We are looking up an exact entry. */
- if (*probe != NULL
- && *probe != DEAD_ENTRY
- && (*probe)->hashcode == hash
- && predicate (cache, key, *probe))
+ if (*probe == NULL)
+ /* Found an empty spot, there can't be a match */
+ break;
+ else if (*probe != DEAD_ENTRY
+ && (*probe)->hashcode == hash
+ && predicate (cache, key, *probe))
return probe;
}
else
@@ -230,8 +230,7 @@ _find_exact_live_entry_for (cairo_cache_t *cache,
return _cache_lookup (cache, key, cache->backend->keys_equal);
}
-
-static cairo_cache_arrangement_t *
+static const cairo_cache_arrangement_t *
_find_cache_arrangement (unsigned long proposed_size)
{
unsigned long idx;
@@ -302,7 +301,7 @@ _cairo_cache_init (cairo_cache_t *cache,
const cairo_cache_backend_t *backend,
unsigned long max_memory)
{
- assert(backend != NULL);
+ assert (backend != NULL);
if (cache != NULL){
cache->arrangement = &cache_arrangements[0];
@@ -342,7 +341,7 @@ _cairo_cache_destroy (cairo_cache_t *cache)
_cache_sane_state (cache);
- if (cache->refcount-- > 0)
+ if (--cache->refcount > 0)
return;
for (i = 0; i < cache->arrangement->size; ++i) {
@@ -419,7 +418,8 @@ _cairo_cache_lookup (cairo_cache_t *cache,
_entry_destroy (cache, idx);
}
- assert(cache->max_memory >= (cache->used_memory + new_entry->memory));
+ /* Can't assert this; new_entry->memory may be larger than max_memory */
+ /* assert(cache->max_memory >= (cache->used_memory + new_entry->memory)); */
/* Make room in the table for a new slot. */
status = _resize_cache (cache, cache->live_entries + 1);
diff --git a/src/cairo_color.c b/src/cairo_color.c
index 2fe793ac8..899b1e3d5 100644
--- a/src/cairo_color.c
+++ b/src/cairo_color.c
@@ -36,7 +36,7 @@
#include "cairoint.h"
-static cairo_color_t const CAIRO_COLOR_DEFAULT = {
+static cairo_color_t const CAIRO_COLOR_WHITE = {
1.0, 1.0, 1.0, 1.0,
0xffff, 0xffff, 0xffff, 0xffff
};
@@ -47,7 +47,7 @@ _cairo_color_compute_shorts (cairo_color_t *color);
void
_cairo_color_init (cairo_color_t *color)
{
- *color = CAIRO_COLOR_DEFAULT;
+ *color = CAIRO_COLOR_WHITE;
}
void
@@ -69,9 +69,12 @@ _cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blu
void
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue)
{
- *red = color->red;
- *green = color->green;
- *blue = color->blue;
+ if (red)
+ *red = color->red;
+ if (green)
+ *green = color->green;
+ if (blue)
+ *blue = color->blue;
}
void
diff --git a/src/cairo_fixed.c b/src/cairo_fixed.c
index 32368d7fc..ee31718ef 100644
--- a/src/cairo_fixed.c
+++ b/src/cairo_fixed.c
@@ -71,3 +71,21 @@ _cairo_fixed_integer_part (cairo_fixed_t f)
{
return f >> 16;
}
+
+int
+_cairo_fixed_integer_floor (cairo_fixed_t f)
+{
+ if (f >= 0)
+ return f >> 16;
+ else
+ return -((-f - 1) >> 16) - 1;
+}
+
+int
+_cairo_fixed_integer_ceil (cairo_fixed_t f)
+{
+ if (f >= 0)
+ return ((f - 1)>>16) + 1;
+ else
+ return - (-f >> 16);
+}
diff --git a/src/cairo_font.c b/src/cairo_font.c
index 5ad9f0417..f5fc0e981 100644
--- a/src/cairo_font.c
+++ b/src/cairo_font.c
@@ -36,7 +36,6 @@
#include "cairoint.h"
-
/* First we implement a global font cache for named fonts. */
typedef struct {
@@ -54,9 +53,9 @@ typedef struct {
static unsigned long
_font_cache_hash (void *cache, void *key)
{
+ unsigned long hash;
cairo_font_cache_key_t *in;
in = (cairo_font_cache_key_t *) key;
- unsigned long hash;
/* 1607 and 1451 are just a couple random primes. */
hash = _cairo_hash_string (in->family);
@@ -86,12 +85,11 @@ _font_cache_create_entry (void *cache,
void *key,
void **return_value)
{
+ const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
cairo_font_cache_key_t *k;
cairo_font_cache_entry_t *entry;
k = (cairo_font_cache_key_t *) key;
- const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT;
-
/* XXX: The current freetype backend may return NULL, (for example
* if no fonts are installed), but I would like to guarantee that
* the toy API always returns at least *some* font, so I would
@@ -145,7 +143,7 @@ _font_cache_destroy_cache (void *cache)
free (cache);
}
-const struct cairo_cache_backend cairo_font_cache_backend = {
+static const cairo_cache_backend_t cairo_font_cache_backend = {
_font_cache_hash,
_font_cache_keys_equal,
_font_cache_create_entry,
@@ -153,7 +151,6 @@ const struct cairo_cache_backend cairo_font_cache_backend = {
_font_cache_destroy_cache
};
-
static void
_lock_global_font_cache (void)
{
@@ -239,8 +236,8 @@ _cairo_font_init (cairo_font_t *scaled,
}
cairo_status_t
-_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const struct cairo_font_backend *backend)
+_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
+ const cairo_font_backend_t *backend)
{
font->refcount = 1;
font->backend = backend;
@@ -476,7 +473,7 @@ _image_glyph_cache_destroy_cache (void *cache)
free (cache);
}
-const cairo_cache_backend_t cairo_image_cache_backend = {
+static const cairo_cache_backend_t cairo_image_cache_backend = {
_cairo_glyph_cache_hash,
_cairo_glyph_cache_keys_equal,
_image_glyph_cache_create_entry,
@@ -484,7 +481,6 @@ const cairo_cache_backend_t cairo_image_cache_backend = {
_image_glyph_cache_destroy_cache
};
-
void
_cairo_lock_global_image_glyph_cache()
{
diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c
index f757db09c..b928b04fc 100644
--- a/src/cairo_ft_font.c
+++ b/src/cairo_ft_font.c
@@ -23,6 +23,8 @@
*/
#include "cairoint.h"
+#include "cairo-ft.h"
+
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
@@ -50,6 +52,16 @@ typedef struct {
} ft_font_val_t;
+/*
+ * The simple 2x2 matrix is converted into separate scale and shape
+ * factors so that hinting works right
+ */
+
+typedef struct {
+ double x_scale, y_scale;
+ double shape[2][2];
+} ft_font_transform_t;
+
static ft_font_val_t *
_create_from_face (FT_Face face, int owns_face)
{
@@ -246,7 +258,7 @@ _ft_font_cache_destroy_cache (void *cache)
free (fc);
}
-const struct cairo_cache_backend _ft_font_cache_backend = {
+static const cairo_cache_backend_t _ft_font_cache_backend = {
_ft_font_cache_hash,
_ft_font_cache_keys_equal,
_ft_font_cache_create_entry,
@@ -254,7 +266,6 @@ const struct cairo_cache_backend _ft_font_cache_backend = {
_ft_font_cache_destroy_cache
};
-
static ft_cache_t *_global_ft_cache = NULL;
static void
@@ -297,7 +308,7 @@ _get_global_ft_cache (void)
/* implement the backend interface */
-const struct cairo_font_backend cairo_ft_font_backend;
+const cairo_font_backend_t cairo_ft_font_backend;
static cairo_unscaled_font_t *
_cairo_ft_font_create (const char *family,
@@ -402,10 +413,10 @@ _cairo_ft_font_destroy (void *abstract_font)
static void
_utf8_to_ucs4 (char const *utf8,
FT_ULong **ucs4,
- size_t *nchars)
+ int *nchars)
{
int len = 0, step = 0;
- size_t n = 0, alloc = 0;
+ int n = 0, alloc = 0;
FcChar32 u = 0;
if (utf8 == NULL || ucs4 == NULL || nchars == NULL)
@@ -433,11 +444,67 @@ _utf8_to_ucs4 (char const *utf8,
*nchars = n;
}
+/*
+ * Split a matrix into the component pieces of scale and shape
+ */
+
+static void
+_cairo_ft_font_compute_transform (ft_font_transform_t *sf, cairo_font_scale_t *sc)
+{
+ cairo_matrix_t normalized;
+ double tx, ty;
+
+ /* The font matrix has x and y "scale" components which we extract and
+ * use as character scale values. These influence the way freetype
+ * chooses hints, as well as selecting different bitmaps in
+ * hand-rendered fonts. We also copy the normalized matrix to
+ * freetype's transformation.
+ */
+
+ cairo_matrix_set_affine (&normalized,
+ sc->matrix[0][0],
+ sc->matrix[0][1],
+ sc->matrix[1][0],
+ sc->matrix[1][1],
+ 0, 0);
+
+ _cairo_matrix_compute_scale_factors (&normalized,
+ &sf->x_scale, &sf->y_scale,
+ /* XXX */ 1);
+ cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
+ cairo_matrix_get_affine (&normalized,
+ &sf->shape[0][0], &sf->shape[0][1],
+ &sf->shape[1][0], &sf->shape[1][1],
+ &tx, &ty);
+}
+
+/*
+ * Set the font transformation
+ */
+
+static void
+_cairo_ft_font_install_transform (ft_font_transform_t *sf, FT_Face face)
+{
+ FT_Matrix mat;
+
+ mat.xx = DOUBLE_TO_16_16(sf->shape[0][0]);
+ mat.yx = -DOUBLE_TO_16_16(sf->shape[0][1]);
+ mat.xy = -DOUBLE_TO_16_16(sf->shape[1][0]);
+ mat.yy = DOUBLE_TO_16_16(sf->shape[1][1]);
+
+ FT_Set_Transform(face, &mat, NULL);
+
+ FT_Set_Char_Size(face,
+ (FT_F26Dot6) (sf->x_scale * 64.0),
+ (FT_F26Dot6) (sf->y_scale * 64.0),
+ 0, 0);
+}
+
static void
_install_font_scale (cairo_font_scale_t *sc, FT_Face face)
{
cairo_matrix_t normalized;
- double scale_x, scale_y;
+ double x_scale, y_scale;
double xx, xy, yx, yy, tx, ty;
FT_Matrix mat;
@@ -455,8 +522,9 @@ _install_font_scale (cairo_font_scale_t *sc, FT_Face face)
sc->matrix[1][1],
0, 0);
- _cairo_matrix_compute_scale_factors (&normalized, &scale_x, &scale_y);
- cairo_matrix_scale (&normalized, 1.0 / scale_x, 1.0 / scale_y);
+ _cairo_matrix_compute_scale_factors (&normalized, &x_scale, &y_scale,
+ /* XXX */ 1);
+ cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale);
cairo_matrix_get_affine (&normalized,
&xx /* 00 */ , &yx /* 01 */,
&xy /* 10 */, &yy /* 11 */,
@@ -470,8 +538,8 @@ _install_font_scale (cairo_font_scale_t *sc, FT_Face face)
FT_Set_Transform(face, &mat, NULL);
FT_Set_Pixel_Sizes(face,
- (FT_UInt) scale_x,
- (FT_UInt) scale_y);
+ (FT_UInt) x_scale,
+ (FT_UInt) y_scale);
}
static cairo_status_t
@@ -481,6 +549,9 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
cairo_glyph_t **glyphs,
int *nglyphs)
{
+ double x = 0., y = 0.;
+ size_t i;
+ FT_ULong *ucs4 = NULL;
cairo_ft_font_t *font = abstract_font;
FT_Face face = font->val->face;
cairo_glyph_cache_key_t key;
@@ -490,10 +561,6 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
key.unscaled = &font->base;
key.scale = *sc;
- double x = 0., y = 0.;
- size_t i;
- FT_ULong *ucs4 = NULL;
-
_utf8_to_ucs4 (utf8, &ucs4, nglyphs);
if (ucs4 == NULL)
@@ -527,7 +594,7 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
continue;
x += val->extents.x_advance;
- y -= val->extents.y_advance;
+ y += val->extents.y_advance;
}
_cairo_unlock_global_image_glyph_cache ();
@@ -544,13 +611,19 @@ _cairo_ft_font_font_extents (void *abstract_font,
cairo_ft_font_t *font = abstract_font;
FT_Face face = font->val->face;
FT_Size_Metrics *metrics = &face->size->metrics;
+ ft_font_transform_t sf;
- _install_font_scale (sc, face);
+ _cairo_ft_font_compute_transform (&sf, sc);
+ _cairo_ft_font_install_transform (&sf, face);
- extents->ascent = DOUBLE_FROM_26_6(metrics->ascender);
- extents->descent = DOUBLE_FROM_26_6(metrics->descender);
- extents->height = DOUBLE_FROM_26_6(metrics->height);
- extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance);
+ /*
+ * Get to unscaled metrics so that the upper level can get back to
+ * user space
+ */
+ extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / sf.y_scale;
+ extents->descent = DOUBLE_FROM_26_6(metrics->descender) / sf.y_scale;
+ extents->height = DOUBLE_FROM_26_6(metrics->height) / sf.y_scale;
+ extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / sf.x_scale;
/* FIXME: this doesn't do vertical layout atm. */
extents->max_y_advance = 0.0;
@@ -614,7 +687,7 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
cairo_ft_font_create_for_ft_face accept an
FcPattern. */
glyph_min.x = glyphs[i].x + img->extents.x_bearing;
- glyph_min.y = glyphs[i].y - img->extents.y_bearing;
+ glyph_min.y = glyphs[i].y + img->extents.y_bearing;
glyph_max.x = glyph_min.x + img->extents.width;
glyph_max.y = glyph_min.y + img->extents.height;
@@ -635,12 +708,12 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
}
_cairo_unlock_global_image_glyph_cache ();
- extents->x_bearing = total_min.x - origin.x;
- extents->y_bearing = total_min.y - origin.y;
- extents->width = total_max.x - total_min.x;
- extents->height = total_max.y - total_min.y;
+ extents->x_bearing = (total_min.x - origin.x);
+ extents->y_bearing = (total_min.y - origin.y);
+ extents->width = (total_max.x - total_min.x);
+ extents->height = (total_max.y - total_min.y);
extents->x_advance = glyphs[i-1].x + (img == NULL ? 0 : img->extents.x_advance) - origin.x;
- extents->y_advance = glyphs[i-1].y + 0 - origin.y;
+ extents->y_advance = glyphs[i-1].y + (img == NULL ? 0 : img->extents.y_advance) - origin.y;
return CAIRO_STATUS_SUCCESS;
}
@@ -688,7 +761,7 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
continue;
x1 = _cairo_fixed_from_double (glyphs[i].x + img->size.x);
- y1 = _cairo_fixed_from_double (glyphs[i].y - img->size.y);
+ y1 = _cairo_fixed_from_double (glyphs[i].y + img->size.y);
x2 = x1 + _cairo_fixed_from_double (img->size.width);
y2 = y1 + _cairo_fixed_from_double (img->size.height);
@@ -763,10 +836,10 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
&(img->image->base),
surface,
source_x + x + img->size.x,
- source_y + y - img->size.y,
+ source_y + y + img->size.y,
0, 0,
x + img->size.x,
- y - img->size.y,
+ y + img->size.y,
(double) img->size.width,
(double) img->size.height);
@@ -919,21 +992,39 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
FT_BBox cbox;
FT_Bitmap bitmap;
FT_Glyph_Metrics *metrics;
+ ft_font_transform_t sf;
glyphslot = font->val->face->glyph;
metrics = &glyphslot->metrics;
- _install_font_scale (&val->key.scale, font->val->face);
+ _cairo_ft_font_compute_transform (&sf, &val->key.scale);
+ _cairo_ft_font_install_transform (&sf, font->val->face);
if (FT_Load_Glyph (font->val->face, val->key.index, FT_LOAD_DEFAULT) != 0)
return CAIRO_STATUS_NO_MEMORY;
- val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX);
- val->extents.y_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingY);
- val->extents.width = DOUBLE_FROM_26_6 (metrics->width);
- val->extents.height = DOUBLE_FROM_26_6 (metrics->height);
- val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.x);
- val->extents.y_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->advance.y);
+ /*
+ * Note: the font's coordinate system is upside down from ours, so the
+ * Y coordinates of the bearing and advance need to be negated.
+ *
+ * Scale metrics back to glyph space from the scaled glyph space returned
+ * by FreeType
+ */
+
+ val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / sf.x_scale;
+ val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / sf.y_scale;
+
+ val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / sf.x_scale;
+ val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / sf.y_scale;
+
+ /*
+ * use untransformed advance values
+ * XXX uses horizontal advance only at present;
+ should provide FT_LOAD_VERTICAL_LAYOUT
+ */
+
+ val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->metrics.horiAdvance) / sf.x_scale;
+ val->extents.y_advance = 0 / sf.y_scale;
outline = &glyphslot->outline;
@@ -982,16 +1073,21 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val)
_cairo_image_surface_assume_ownership_of_data (val->image);
}
-
+
+ /*
+ * Note: the font's coordinate system is upside down from ours, so the
+ * Y coordinate of the control box needs to be negated.
+ */
+
val->size.width = (unsigned short) width;
val->size.height = (unsigned short) height;
- val->size.x = (short) (cbox.xMin >> 6);
- val->size.y = (short) (cbox.yMax >> 6);
+ val->size.x = (short) (cbox.xMin >> 6);
+ val->size.y = - (short) (cbox.yMax >> 6);
return CAIRO_STATUS_SUCCESS;
}
-const struct cairo_font_backend cairo_ft_font_backend = {
+const cairo_font_backend_t cairo_ft_font_backend = {
_cairo_ft_font_create,
_cairo_ft_font_destroy,
_cairo_ft_font_font_extents,
diff --git a/src/cairo_gdip_font.cpp b/src/cairo_gdip_font.cpp
new file mode 100644
index 000000000..e932e3bac
--- /dev/null
+++ b/src/cairo_gdip_font.cpp
@@ -0,0 +1,665 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Stuart Parmenter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Stuart Parmenter.
+ *
+ * Contributor(s):
+ * Stuart Parmenter <pavlov@pavlov.net>
+ */
+
+extern "C" {
+#include "cairoint.h"
+}
+
+#include <windows.h>
+
+#include <gdiplus.h>
+using namespace Gdiplus;
+
+#if 0
+#include <fontconfig/fontconfig.h>
+#include <fontconfig/fcfreetype.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include FT_IMAGE_H
+#endif
+
+typedef struct {
+ cairo_font_t base;
+ HDC hdc;
+ HFONT hfont;
+} cairo_win32_font_t;
+
+
+
+static int
+_utf8_to_glyphs (cairo_win32_font_t *font,
+ const unsigned char *utf8,
+ double x0,
+ double y0,
+ cairo_glyph_t **glyphs,
+ size_t *nglyphs)
+{
+ /* XXX implement me */
+ *glyphs = NULL;
+ *nglyphs = 0;
+
+ return 0;
+}
+
+/* implement the platform-specific interface */
+
+cairo_font_t *
+cairo_win32_font_create (HFONT hfont)
+{
+ cairo_win32_font_t *f = (cairo_win32_font_t*)malloc(sizeof(cairo_win32_font_t));
+ if (f == NULL)
+ return NULL;
+
+ f->hfont = hfont;
+
+ _cairo_font_init (&f->base, &cairo_win32_font_backend);
+
+ return (cairo_font_t *) f;
+}
+
+#if 0
+FT_Face
+cairo_win32_font_face (cairo_font_t *abstract_font)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t *) abstract_font;
+
+ if (font == NULL)
+ return NULL;
+
+ return font->face;
+}
+
+FcPattern *
+cairo_win32_font_pattern (cairo_font_t *abstract_font)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t *) abstract_font;
+
+ if (font == NULL)
+ return NULL;
+
+ return font->pattern;
+}
+#endif
+
+/* implement the backend interface */
+
+static cairo_font_t *
+_cairo_win32_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight)
+{
+ int fontHeight = 60; // in Pixels in this case
+ int fontWidth = 0;
+ int italic = 0;
+ int bold = FW_REGULAR;
+
+ switch (slant) {
+ case CAIRO_FONT_SLANT_ITALIC:
+ italic = 1;
+ case CAIRO_FONT_SLANT_OBLIQUE:
+ case CAIRO_FONT_SLANT_NORMAL:
+ default:
+ break;
+ }
+
+ if (weight == CAIRO_FONT_WEIGHT_BOLD)
+ bold = FW_BOLD;
+
+ HFONT hfont = CreateFont(fontHeight, // height of font
+ fontWidth, // average character width
+ 0, // angle of escapement
+ 0, // base-line orientation angle
+ bold, // font weight
+ italic, // italic attribute option
+ FALSE, // underline attribute option
+ FALSE, // strikeout attribute option
+ ANSI_CHARSET, // character set identifier
+ OUT_DEFAULT_PRECIS, // output precision
+ CLIP_DEFAULT_PRECIS, // clipping precision
+ ANTIALIASED_QUALITY, // output quality
+ FF_DONTCARE, // pitch and family
+ family); // typeface name
+
+ return cairo_win32_font_create(hfont);
+}
+
+static cairo_font_t *
+_cairo_win32_font_copy (void *abstract_font)
+{
+ cairo_win32_font_t *font_new = NULL;
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ if (font->base.backend != &cairo_win32_font_backend)
+ return NULL;
+
+ font_new = (cairo_win32_font_t *) cairo_win32_font_create(font->hfont);
+ if (font_new == NULL)
+ return NULL;
+
+ return (cairo_font_t *) font_new;
+}
+
+static void
+_cairo_win32_font_destroy (void *abstract_font)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ //delete font->font;
+
+ free (font);
+}
+
+static cairo_status_t
+_cairo_win32_font_font_extents (void *abstract_font,
+ cairo_font_extents_t *extents)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ TEXTMETRIC metrics;
+ GetTextMetrics(font->hdc, &metrics);
+
+ extents->ascent = metrics.tmAscent;
+ extents->descent = metrics.tmDescent;
+ extents->height = metrics.tmHeight;
+ extents->max_x_advance = 0; /* XXX */
+ extents->max_y_advance = 0; /* XXX */
+
+
+#if 0
+ FT_Face face = font->face;
+ double scale_x, scale_y;
+
+ double upm = face->units_per_EM;
+
+ _cairo_matrix_compute_scale_factors (&font->base.matrix, &scale_x, &scale_y);
+
+ extents->ascent = face->ascender / upm * scale_y;
+ extents->descent = face->descender / upm * scale_y;
+ extents->height = face->height / upm * scale_y;
+ extents->max_x_advance = face->max_advance_width / upm * scale_x;
+ extents->max_y_advance = face->max_advance_height / upm * scale_y;
+#endif
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_font_glyph_extents (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ int i;
+ for (i = 0; i < num_glyphs; ++i) {
+ GLYPHMETRICS metrics;
+ GetGlyphOutline(font->hdc, 'a', GGO_METRICS, &metrics, 0, NULL, NULL);
+
+ extents->width += metrics.gmBlackBoxX;
+ extents->height += metrics.gmBlackBoxY;
+ /* metrics has:
+ UINT gmBlackBoxX;
+ UINT gmBlackBoxY;
+ POINT gmptGlyphOrigin;
+ short gmCellIncX;
+ short gmCellIncY;
+
+ extents has:
+ double x_bearing;
+ double y_bearing;
+ double width;
+ double height;
+ double x_advance;
+ double y_advance;
+ */
+ }
+
+#if 0
+ int i;
+ cairo_win32_font_t *font = abstract_font;
+ cairo_point_double_t origin;
+ cairo_point_double_t glyph_min, glyph_max;
+ cairo_point_double_t total_min, total_max;
+ FT_Error error;
+ FT_Face face = font->face;
+ FT_GlyphSlot glyph = face->glyph;
+ FT_Glyph_Metrics *metrics = &glyph->metrics;
+
+ if (num_glyphs == 0)
+ {
+ extents->x_bearing = 0.0;
+ extents->y_bearing = 0.0;
+ extents->width = 0.0;
+ extents->height = 0.0;
+ extents->x_advance = 0.0;
+ extents->y_advance = 0.0;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ origin.x = glyphs[0].x;
+ origin.y = glyphs[0].y;
+
+ _install_font_matrix (&font->base.matrix, face);
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ error = FT_Load_Glyph (face, glyphs[i].index, FT_LOAD_DEFAULT);
+ /* XXX: What to do in this error case? */
+ if (error)
+ continue;
+
+ /* XXX: Need to add code here to check the font's FcPattern
+ for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y
+ instead. This will require that
+ cairo_win32_font_create_for_ft_face accept an
+ FcPattern. */
+ glyph_min.x = glyphs[i].x + DOUBLE_FROM_26_6 (metrics->horiBearingX);
+ glyph_min.y = glyphs[i].y - DOUBLE_FROM_26_6 (metrics->horiBearingY);
+ glyph_max.x = glyph_min.x + DOUBLE_FROM_26_6 (metrics->width);
+ glyph_max.y = glyph_min.y + DOUBLE_FROM_26_6 (metrics->height);
+
+ if (i==0) {
+ total_min = glyph_min;
+ total_max = glyph_max;
+ } else {
+ if (glyph_min.x < total_min.x)
+ total_min.x = glyph_min.x;
+ if (glyph_min.y < total_min.y)
+ total_min.y = glyph_min.y;
+
+ if (glyph_max.x > total_max.x)
+ total_max.x = glyph_max.x;
+ if (glyph_max.y > total_max.y)
+ total_max.y = glyph_max.y;
+ }
+ }
+
+ extents->x_bearing = total_min.x - origin.x;
+ extents->y_bearing = total_min.y - origin.y;
+ extents->width = total_max.x - total_min.x;
+ extents->height = total_max.y - total_min.y;
+ extents->x_advance = glyphs[i-1].x + DOUBLE_FROM_26_6 (metrics->horiAdvance) - origin.x;
+ extents->y_advance = glyphs[i-1].y + 0 - origin.y;
+#endif
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_cairo_win32_font_text_extents (void *abstract_font,
+ const unsigned char *utf8,
+ cairo_text_extents_t *extents)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ cairo_glyph_t *glyphs;
+ size_t nglyphs;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ if (_utf8_to_glyphs (font, utf8, 0, 0, &glyphs, &nglyphs))
+ {
+ status = _cairo_win32_font_glyph_extents (font, glyphs, nglyphs,
+ extents);
+ free (glyphs);
+ }
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_win32_font_glyph_bbox (void *abstract_font,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+#if 0
+ cairo_surface_t *mask = NULL;
+ cairo_glyph_size_t size;
+
+ cairo_fixed_t x1, y1, x2, y2;
+ int i;
+
+ bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16;
+ bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16;
+
+ if (font == NULL
+ || surface == NULL
+ || glyphs == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ mask = _cairo_font_lookup_glyph (&font->base, surface,
+ &glyphs[i], &size);
+ if (mask == NULL)
+ continue;
+
+ x1 = _cairo_fixed_from_double (glyphs[i].x + size.x);
+ y1 = _cairo_fixed_from_double (glyphs[i].y - size.y);
+ x2 = x1 + _cairo_fixed_from_double (size.width);
+ y2 = y1 + _cairo_fixed_from_double (size.height);
+
+ if (x1 < bbox->p1.x)
+ bbox->p1.x = x1;
+
+ if (y1 < bbox->p1.y)
+ bbox->p1.y = y1;
+
+ if (x2 > bbox->p2.x)
+ bbox->p2.x = x2;
+
+ if (y2 > bbox->p2.y)
+ bbox->p2.y = y2;
+
+ if (mask)
+ cairo_surface_destroy (mask);
+ }
+#endif
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_font_text_bbox (void *abstract_font,
+ cairo_surface_t *surface,
+ double x0,
+ double y0,
+ const unsigned char *utf8,
+ cairo_box_t *bbox)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ cairo_glyph_t *glyphs;
+ size_t num_glyphs;
+
+ if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs))
+ {
+ cairo_status_t res;
+ res = _cairo_win32_font_glyph_bbox (font, surface,
+ glyphs, num_glyphs, bbox);
+ free (glyphs);
+ return res;
+ }
+ else
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+static cairo_status_t
+_cairo_win32_font_show_glyphs (void *abstract_font,
+ cairo_operator_t op,
+ cairo_surface_t *source,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+#if 0
+ cairo_status_t status;
+ cairo_surface_t *mask = NULL;
+ cairo_glyph_size_t size;
+
+ double x, y;
+ int i;
+
+ if (font == NULL
+ || source == NULL
+ || surface == NULL
+ || glyphs == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ mask = _cairo_font_lookup_glyph (&font->base, surface,
+ &glyphs[i], &size);
+ if (mask == NULL)
+ continue;
+
+ x = glyphs[i].x;
+ y = glyphs[i].y;
+
+ status = _cairo_surface_composite (operator, source, mask, surface,
+ source_x + x + size.x,
+ source_y + y - size.y,
+ 0, 0,
+ x + size.x,
+ y - size.y,
+ (double) size.width,
+ (double) size.height);
+
+ cairo_surface_destroy (mask);
+
+ if (status)
+ return status;
+ }
+#endif
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_font_show_text (void *abstract_font,
+ cairo_operator_t op,
+ cairo_surface_t *source,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ double x0,
+ double y0,
+ const unsigned char *utf8)
+{
+ cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font;
+
+ cairo_glyph_t *glyphs;
+ size_t num_glyphs;
+
+ if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs))
+ {
+ cairo_status_t res;
+ res = _cairo_win32_font_show_glyphs (font, op,
+ source, surface,
+ source_x, source_y,
+ glyphs, num_glyphs);
+ free (glyphs);
+ return res;
+ }
+ else
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+static cairo_status_t
+_cairo_win32_font_glyph_path (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path)
+{
+#if 0
+ int i;
+ cairo_win32_font_t *font = abstract_font;
+ FT_GlyphSlot glyph;
+ FT_Error error;
+ FT_Outline_Funcs outline_funcs = {
+ _move_to,
+ _line_to,
+ _conic_to,
+ _cubic_to,
+ 0, /* shift */
+ 0, /* delta */
+ };
+
+ glyph = font->face->glyph;
+ _install_font_matrix (&font->base.matrix, font->face);
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ FT_Matrix invert_y = {
+ DOUBLE_TO_16_16 (1.0), 0,
+ 0, DOUBLE_TO_16_16 (-1.0),
+ };
+
+ error = FT_Load_Glyph (font->face, glyphs[i].index, FT_LOAD_DEFAULT);
+ /* XXX: What to do in this error case? */
+ if (error)
+ continue;
+ /* XXX: Do we want to support bitmap fonts here? */
+ if (glyph->format == ft_glyph_format_bitmap)
+ continue;
+
+ /* Font glyphs have an inverted Y axis compared to cairo. */
+ FT_Outline_Transform (&glyph->outline, &invert_y);
+ FT_Outline_Translate (&glyph->outline,
+ DOUBLE_TO_26_6(glyphs[i].x),
+ DOUBLE_TO_26_6(glyphs[i].y));
+ FT_Outline_Decompose (&glyph->outline, &outline_funcs, path);
+ }
+ _cairo_path_close_path (path);
+#endif
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_font_text_path (void *abstract_font,
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_path_t *path)
+{
+#if 0
+ cairo_win32_font_t *font = abstract_font;
+ cairo_glyph_t *glyphs;
+ size_t nglyphs;
+
+ if (_utf8_to_glyphs (font, utf8, x, y, &glyphs, &nglyphs))
+ {
+ cairo_status_t res;
+ res = _cairo_win32_font_glyph_path (font, glyphs, nglyphs, path);
+ free (glyphs);
+ return res;
+ }
+ else
+#endif
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+static cairo_surface_t *
+_cairo_win32_font_create_glyph (void *abstract_font,
+ const cairo_glyph_t *glyph,
+ cairo_glyph_size_t *return_size)
+{
+#if 0
+ cairo_win32_font_t *font = abstract_font;
+ cairo_image_surface_t *image;
+ FT_GlyphSlot glyphslot;
+ unsigned int width, height, stride;
+ FT_Outline *outline;s
+ FT_BBox cbox;
+ FT_Bitmap bitmap;
+
+ glyphslot = font->face->glyph;
+ _install_font_matrix (&font->base.matrix, font->face);
+
+ FT_Load_Glyph (font->face, glyph->index, FT_LOAD_DEFAULT);
+
+ outline = &glyphslot->outline;
+
+ FT_Outline_Get_CBox (outline, &cbox);
+
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = (cbox.xMax + 63) & -64;
+ cbox.yMax = (cbox.yMax + 63) & -64;
+
+ width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6);
+ height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6);
+ stride = (width + 3) & -4;
+
+ bitmap.pixel_mode = ft_pixel_mode_grays;
+ bitmap.num_grays = 256;
+ bitmap.width = width;
+ bitmap.rows = height;
+ bitmap.pitch = stride;
+
+ if (width * height == 0)
+ return NULL;
+
+ bitmap.buffer = malloc (stride * height);
+ if (bitmap.buffer == NULL)
+ return NULL;
+
+ memset (bitmap.buffer, 0x0, stride * height);
+
+ FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
+ FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap);
+
+ image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data ((char *) bitmap.buffer,
+ CAIRO_FORMAT_A8,
+ width, height, stride);
+ if (image == NULL) {
+ free (bitmap.buffer);
+ return NULL;
+ }
+
+ _cairo_image_surface_assume_ownership_of_data (image);
+
+ return_size->width = (unsigned short) width;
+ return_size->height = (unsigned short) height;
+ return_size->x = (short) (cbox.xMin >> 6);
+ return_size->y = (short) (cbox.yMax >> 6);
+
+ return &image->base;
+#endif
+ return NULL;
+}
+
+const struct cairo_font_backend cairo_win32_font_backend = {
+ _cairo_win32_font_create,
+ _cairo_win32_font_copy,
+ _cairo_win32_font_destroy,
+ _cairo_win32_font_font_extents,
+ _cairo_win32_font_text_extents,
+ _cairo_win32_font_glyph_extents,
+ _cairo_win32_font_text_bbox,
+ _cairo_win32_font_glyph_bbox,
+ _cairo_win32_font_show_text,
+ _cairo_win32_font_show_glyphs,
+ _cairo_win32_font_text_path,
+ _cairo_win32_font_glyph_path,
+ _cairo_win32_font_create_glyph
+};
diff --git a/src/cairo_gdip_surface.cpp b/src/cairo_gdip_surface.cpp
new file mode 100644
index 000000000..ec1982b55
--- /dev/null
+++ b/src/cairo_gdip_surface.cpp
@@ -0,0 +1,727 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Stuart Parmenter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Stuart Parmenter.
+ *
+ * Contributor(s):
+ * Stuart Parmenter <pavlov@pavlov.net>
+ */
+
+extern "C" {
+#include "cairoint.h"
+}
+
+/* export symbols, for cairo.dll only */
+
+#pragma comment(linker, "/EXPORT:_cairo_create")
+#pragma comment(linker, "/EXPORT:_cairo_reference")
+#pragma comment(linker, "/EXPORT:_cairo_destroy")
+#pragma comment(linker, "/EXPORT:_cairo_save")
+#pragma comment(linker, "/EXPORT:_cairo_restore")
+#pragma comment(linker, "/EXPORT:_cairo_copy")
+#pragma comment(linker, "/EXPORT:_cairo_set_target_surface")
+#pragma comment(linker, "/EXPORT:_cairo_set_target_image")
+
+#ifdef CAIRO_HAS_PS_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_set_target_ps")
+#endif
+
+#ifdef CAIRO_HAS_PS_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_set_target_pdf")
+#endif
+
+#ifdef CAIRO_HAS_PNG_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_set_target_png")
+#endif
+
+#ifdef CAIRO_HAS_GL_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_set_target_gl")
+#endif
+
+#ifdef CAIRO_HAS_WIN32_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_set_target_win32")
+#endif
+
+#pragma comment(linker, "/EXPORT:_cairo_set_operator")
+#pragma comment(linker, "/EXPORT:_cairo_set_rgb_color")
+#pragma comment(linker, "/EXPORT:_cairo_set_pattern")
+#pragma comment(linker, "/EXPORT:_cairo_set_alpha")
+#pragma comment(linker, "/EXPORT:_cairo_set_tolerance")
+#pragma comment(linker, "/EXPORT:_cairo_set_fill_rule")
+#pragma comment(linker, "/EXPORT:_cairo_set_line_width")
+#pragma comment(linker, "/EXPORT:_cairo_set_line_cap")
+#pragma comment(linker, "/EXPORT:_cairo_set_line_join")
+#pragma comment(linker, "/EXPORT:_cairo_set_dash")
+#pragma comment(linker, "/EXPORT:_cairo_set_miter_limit")
+#pragma comment(linker, "/EXPORT:_cairo_set_line_cap")
+
+#pragma comment(linker, "/EXPORT:_cairo_translate")
+#pragma comment(linker, "/EXPORT:_cairo_scale")
+#pragma comment(linker, "/EXPORT:_cairo_rotate")
+
+#pragma comment(linker, "/EXPORT:_cairo_concat_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_set_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_default_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_identity_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_transform_point")
+#pragma comment(linker, "/EXPORT:_cairo_transform_distance")
+#pragma comment(linker, "/EXPORT:_cairo_inverse_transform_point")
+#pragma comment(linker, "/EXPORT:_cairo_inverse_transform_distance")
+
+#pragma comment(linker, "/EXPORT:_cairo_new_path")
+#pragma comment(linker, "/EXPORT:_cairo_move_to")
+#pragma comment(linker, "/EXPORT:_cairo_line_to")
+#pragma comment(linker, "/EXPORT:_cairo_curve_to")
+#pragma comment(linker, "/EXPORT:_cairo_arc")
+#pragma comment(linker, "/EXPORT:_cairo_arc_negative")
+#pragma comment(linker, "/EXPORT:_cairo_rel_move_to")
+#pragma comment(linker, "/EXPORT:_cairo_rel_line_to")
+#pragma comment(linker, "/EXPORT:_cairo_rel_curve_to")
+#pragma comment(linker, "/EXPORT:_cairo_rectangle")
+#pragma comment(linker, "/EXPORT:_cairo_close_path")
+
+#pragma comment(linker, "/EXPORT:_cairo_stroke")
+#pragma comment(linker, "/EXPORT:_cairo_fill")
+#pragma comment(linker, "/EXPORT:_cairo_copy_page")
+#pragma comment(linker, "/EXPORT:_cairo_show_page")
+#pragma comment(linker, "/EXPORT:_cairo_in_stroke")
+#pragma comment(linker, "/EXPORT:_cairo_in_fill")
+#pragma comment(linker, "/EXPORT:_cairo_stroke_extents")
+#pragma comment(linker, "/EXPORT:_cairo_fill_extents")
+
+#pragma comment(linker, "/EXPORT:_cairo_init_clip")
+#pragma comment(linker, "/EXPORT:_cairo_clip")
+#pragma comment(linker, "/EXPORT:_cairo_select_font")
+#pragma comment(linker, "/EXPORT:_cairo_scale_font")
+#pragma comment(linker, "/EXPORT:_cairo_transform_font")
+#pragma comment(linker, "/EXPORT:_cairo_show_text")
+#pragma comment(linker, "/EXPORT:_cairo_show_glyphs")
+#pragma comment(linker, "/EXPORT:_cairo_current_font")
+#pragma comment(linker, "/EXPORT:_cairo_current_font_extents")
+#pragma comment(linker, "/EXPORT:_cairo_set_font")
+#pragma comment(linker, "/EXPORT:_cairo_text_extents")
+#pragma comment(linker, "/EXPORT:_cairo_glyph_extents")
+#pragma comment(linker, "/EXPORT:_cairo_text_path")
+#pragma comment(linker, "/EXPORT:_cairo_glyph_path")
+#pragma comment(linker, "/EXPORT:_cairo_font_reference")
+#pragma comment(linker, "/EXPORT:_cairo_font_destroy")
+#pragma comment(linker, "/EXPORT:_cairo_font_set_transform")
+#pragma comment(linker, "/EXPORT:_cairo_font_current_transform")
+
+/*#pragma comment(linker, "/EXPORT:_cairo_ft_font_create")
+#pragma comment(linker, "/EXPORT:_cairo_ft_font_create_for_ft_face")
+*/
+#if 0
+/* hmm, this function doesn't exist, but __cairo_ft_font_destroy does */
+#pragma comment(linker, "/EXPORT:_cairo_ft_font_destroy")
+#endif
+/*
+#pragma comment(linker, "/EXPORT:_cairo_ft_font_face")
+#pragma comment(linker, "/EXPORT:_cairo_ft_font_pattern")
+*/
+#pragma comment(linker, "/EXPORT:_cairo_show_surface")
+#pragma comment(linker, "/EXPORT:_cairo_current_operator")
+#pragma comment(linker, "/EXPORT:_cairo_current_rgb_color")
+#pragma comment(linker, "/EXPORT:_cairo_current_pattern")
+#pragma comment(linker, "/EXPORT:_cairo_current_alpha")
+#pragma comment(linker, "/EXPORT:_cairo_current_tolerance")
+#pragma comment(linker, "/EXPORT:_cairo_current_point")
+#pragma comment(linker, "/EXPORT:_cairo_current_fill_rule")
+#pragma comment(linker, "/EXPORT:_cairo_current_line_width")
+#pragma comment(linker, "/EXPORT:_cairo_current_line_cap")
+#pragma comment(linker, "/EXPORT:_cairo_current_line_join")
+#pragma comment(linker, "/EXPORT:_cairo_current_rgb_color")
+#pragma comment(linker, "/EXPORT:_cairo_current_miter_limit")
+#pragma comment(linker, "/EXPORT:_cairo_current_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_current_target_surface")
+#pragma comment(linker, "/EXPORT:_cairo_current_path")
+#pragma comment(linker, "/EXPORT:_cairo_current_path_flat")
+
+#pragma comment(linker, "/EXPORT:_cairo_status")
+#pragma comment(linker, "/EXPORT:_cairo_status_string")
+
+#pragma comment(linker, "/EXPORT:_cairo_surface_create_for_image")
+#pragma comment(linker, "/EXPORT:_cairo_surface_create_similar")
+#pragma comment(linker, "/EXPORT:_cairo_surface_reference")
+#pragma comment(linker, "/EXPORT:_cairo_surface_destroy")
+#pragma comment(linker, "/EXPORT:_cairo_surface_set_repeat")
+#pragma comment(linker, "/EXPORT:_cairo_surface_set_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_surface_get_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_surface_set_filter")
+#pragma comment(linker, "/EXPORT:_cairo_surface_get_filter")
+
+#pragma comment(linker, "/EXPORT:_cairo_image_surface_create")
+#pragma comment(linker, "/EXPORT:_cairo_image_surface_create_for_data")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_create_for_surface")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_create_linear")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_create_radial")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_reference")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_destroy")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_add_color_stop")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_set_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_get_matrix")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_set_extend")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_get_extend")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_set_filter")
+#pragma comment(linker, "/EXPORT:_cairo_pattern_get_filter")
+
+#ifdef CAIRO_HAS_PS_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_ps_surface_create")
+#endif
+
+#ifdef CAIRO_HAS_PNG_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_png_surface_create")
+#endif
+
+#ifdef CAIRO_HAS_GL_SURFACE
+#pragma comment(linker, "/EXPORT:_cairo_gl_surface_create")
+#endif
+
+#pragma comment(linker, "/EXPORT:_cairo_matrix_create")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_destroy")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_copy")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_set_identity")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_set_affine")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_get_affine")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_translate")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_scale")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_rotate")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_invert")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_multiply")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_transform_distance")
+#pragma comment(linker, "/EXPORT:_cairo_matrix_transform_point")
+
+#include <windows.h>
+
+#include <gdiplus.h>
+using namespace Gdiplus;
+
+extern const cairo_surface_backend_t cairo_win32_surface_backend;
+
+cairo_surface_t *_cairo_win32_surface_create (HDC dc);
+
+void
+cairo_set_target_win32(cairo_t *cr, HDC dc)
+{
+ cairo_surface_t *surface;
+
+ surface = _cairo_win32_surface_create(dc);
+ if (surface == NULL) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_set_target_surface (cr, surface);
+
+ /* cairo_set_target_surface takes a reference, so we must destroy ours */
+ cairo_surface_destroy (surface);
+}
+
+typedef struct cairo_win32_surface {
+ cairo_surface_t base;
+ Graphics *gr;
+
+ Brush *brush;
+} cairo_win32_surface_t;
+
+
+static void
+_cairo_win32_surface_erase(cairo_win32_surface_t *surface);
+
+cairo_surface_t *
+_cairo_win32_surface_create(HDC dc)
+{
+ cairo_win32_surface_t *surface;
+
+ surface = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
+ if (surface == NULL)
+ return NULL;
+
+ surface->gr = new Graphics(dc);
+ surface->brush = NULL;
+// surface->gr->TranslateTransform(-2000*2.5, -3000*2.2);
+// surface->gr->ScaleTransform(20, 20);
+
+ surface->gr->SetSmoothingMode(SmoothingModeAntiAlias);
+
+ /* do pixmap creation, etc */
+
+ _cairo_surface_init(&surface->base, &cairo_win32_surface_backend);
+
+ _cairo_win32_surface_erase(surface);
+
+ return &surface->base;
+}
+
+static cairo_surface_t *
+_cairo_win32_surface_create_similar(void *abstract_src,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ return NULL;
+}
+
+static void
+_cairo_win32_surface_destroy (void *abstract_surface)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ delete surface->gr;
+ delete surface->brush;
+
+ free(surface);
+}
+
+static void
+_cairo_win32_surface_erase(cairo_win32_surface_t *surface)
+{
+ surface->gr->Clear(Color(255, 0, 0, 0));
+}
+
+/* XXX: We should re-work this interface to return both X/Y ppi values. */
+static double
+_cairo_win32_surface_pixels_per_inch(void *abstract_surface)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ return surface->gr->GetDpiY();
+}
+
+static Image *
+make_image(cairo_image_surface_t *image)
+{
+ Rect r(0, 0, image->width, image->height);
+ Bitmap *b = new Bitmap(image->width, image->height, PixelFormat32bppPARGB);
+ BitmapData data;
+
+ b->LockBits(&r, ImageLockModeWrite, PixelFormat32bppPARGB, &data);
+
+ memcpy(data.Scan0, image->data, image->stride * image->height);
+
+ b->UnlockBits(&data);
+
+ return b;
+}
+
+static cairo_image_surface_t *
+_cairo_win32_surface_get_image(void *abstract_surface)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ /* need to figure out how to get the data from a Graphics and turn it in to an Image */
+ return NULL;
+}
+
+
+static cairo_status_t
+_cairo_win32_surface_set_image(void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ Image *img = make_image(image);
+ surface->gr->DrawImage(img, 0, 0);
+ delete img;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_surface_set_matrix(void *abstract_surface,
+ cairo_matrix_t *matrix)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ Matrix m((float)matrix->m[0][0], (float)matrix->m[1][0], (float)matrix->m[2][0],
+ (float)matrix->m[0][1], (float)matrix->m[1][1], (float)matrix->m[2][1]);
+
+
+ surface->gr->SetTransform(&m);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_surface_set_filter (void *abstract_surface,
+ cairo_filter_t filter)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+ SmoothingMode mode;
+
+ switch (filter) {
+ case CAIRO_FILTER_FAST:
+ mode = SmoothingModeNone;
+ break;
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_NEAREST:
+ case CAIRO_FILTER_BILINEAR:
+ case CAIRO_FILTER_GAUSSIAN:
+ default:
+ mode = SmoothingModeAntiAlias;
+ break;
+ }
+ surface->gr->SetSmoothingMode(mode);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_win32_surface_set_repeat (void *abstract_surface,
+ int repeat)
+{
+ /* what is this function supposed to do? */
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_composite(cairo_operator_t op,
+ cairo_surface_t *generic_src,
+ cairo_surface_t *generic_mask,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_win32_surface_fill_rectangles(void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ SolidBrush brush(Color(color->alpha_short, color->red_short, color->green_short, color->blue_short));
+
+ RectF *r = new RectF[num_rects]; /* should really allocate a small number here on the stack and use those if possible */
+ for (int i = 0; i < num_rects; ++i) {
+ r[i].X = rects[i].x;
+ r[i].Y = rects[i].y;
+ r[i].Width = rects[i].width;
+ r[i].Height = rects[i].height;
+ }
+
+ surface->gr->FillRectangles(&brush, r, num_rects);
+
+ delete[] r;
+
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+}
+
+
+
+static int
+_cairo_win32_extract_rectangle (cairo_trapezoid_t *trap,
+ RectF *rect)
+{
+ if (trap->left.p1.x == trap->left.p2.x &&
+ trap->right.p1.x == trap->right.p2.x &&
+ trap->left.p1.y == trap->right.p1.y &&
+ trap->left.p2.y == trap->right.p2.y) {
+
+ double x = _cairo_fixed_to_double (trap->left.p1.x);
+ double y = _cairo_fixed_to_double (trap->left.p1.y);
+ rect->X = (float)x;
+ rect->Y = (float)y;
+ rect->Width = (float)(_cairo_fixed_to_double(trap->right.p1.x) - x);
+ rect->Height = (float)(_cairo_fixed_to_double(trap->left.p2.y) - y);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_composite_trapezoids (cairo_operator_t op,
+ cairo_surface_t *generic_src,
+ void *abstract_dst,
+ int x_src,
+ int y_src,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_dst;
+
+ static int zzz = 0;
+ zzz += num_traps;
+
+ Image *img = NULL;
+ Brush *brush = NULL; /* i'd really like to not allocate this on the heap.. */
+
+#define FIXED_TO_FLOAT(x) (float)_cairo_fixed_to_double((x))
+
+ /* ugh.. figure out if we're a "native" pattern or an image_surface pattern.. */
+ if (generic_src->backend == &cairo_win32_surface_backend) {
+ brush = ((cairo_win32_surface_t*)generic_src)->brush;
+ /* XXX move this outside so that TextureBrushes can take advantage of it */
+ /* Check to see if we can represent these traps as a rectangle. */
+ RectF rect;
+ if (num_traps == 1 && _cairo_win32_extract_rectangle(traps, &rect)) {
+ surface->gr->FillRectangle(brush, rect);
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+ }
+ } else {
+ /* I would really love to move this code in to create_pattern if possible */
+ img = make_image((cairo_image_surface_t*)generic_src);
+ brush = new TextureBrush(img);
+
+ // XXX this will probably break. Don't know why we have +1 and +2 offsets..
+ float xoff = (FIXED_TO_FLOAT(traps[0].left.p1.x) + 0.5f);
+ float yoff = (FIXED_TO_FLOAT(traps[0].left.p1.y) + 1.5f);
+ static_cast<TextureBrush*>(brush)->TranslateTransform((int)(-x_src + xoff),
+ (int)(-y_src + yoff));
+ }
+
+ CompositingMode mode;
+ switch (op) {
+ case CAIRO_OPERATOR_OVER:
+ mode = CompositingModeSourceOver;
+ break;
+ case CAIRO_OPERATOR_CLEAR:
+ mode = CompositingModeSourceCopy;
+ break;
+ case CAIRO_OPERATOR_SRC:
+ case CAIRO_OPERATOR_DST:
+ case CAIRO_OPERATOR_OVER_REVERSE:
+ case CAIRO_OPERATOR_IN:
+ case CAIRO_OPERATOR_IN_REVERSE:
+ case CAIRO_OPERATOR_OUT:
+ case CAIRO_OPERATOR_OUT_REVERSE:
+ case CAIRO_OPERATOR_ATOP:
+ case CAIRO_OPERATOR_ATOP_REVERSE:
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_ADD:
+ case CAIRO_OPERATOR_SATURATE:
+ mode = CompositingModeSourceOver;
+ break;
+ }
+ surface->gr->SetCompositingMode(mode);
+
+ PointF points[4];
+ for (int i = 0; i < num_traps; ++i) {
+ float top = FIXED_TO_FLOAT(traps[i].top);
+ float bottom = FIXED_TO_FLOAT(traps[i].bottom);
+
+ /* left line */
+ points[0].X = FIXED_TO_FLOAT(traps[i].left.p1.x);
+ points[0].Y = FIXED_TO_FLOAT(traps[i].left.p1.y);
+ points[1].X = FIXED_TO_FLOAT(traps[i].left.p2.x);
+ points[1].Y = FIXED_TO_FLOAT(traps[i].left.p2.y);
+
+ /* right line */
+ points[2].X = FIXED_TO_FLOAT(traps[i].right.p2.x);
+ points[2].Y = FIXED_TO_FLOAT(traps[i].right.p2.y);
+ points[3].X = FIXED_TO_FLOAT(traps[i].right.p1.x);
+ points[3].Y = FIXED_TO_FLOAT(traps[i].right.p1.y);
+
+ surface->gr->FillPolygon(brush, points, 4);
+ //Pen p(Color(255,0,0,0), 1.0f/10.0f);
+ //surface->gr->DrawPolygon(&p, points, 4);
+ }
+
+#undef FIXED_TO_FLOAT
+
+ delete img;
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_copy_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_win32_surface_show_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_win32_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface;
+
+ pixman_box16_t *box;
+ int n = pixman_region_num_rects(region);
+
+ if (n == 0)
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+
+ box = pixman_region_rects(region);
+
+ surface->gr->ResetClip();
+ for (int i = 0; i < n; ++i) {
+ Rect r(box[i].x1, box[i].y1, box[i].x2 - box[i].x1, box[i].y2 - box[i].y1);
+ surface->gr->SetClip(r, CombineModeUnion); /* do I need to do replace once and then union? */
+ }
+
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_create_pattern (void *abstract_surface,
+ cairo_pattern_t *pattern,
+ cairo_box_t *box)
+{
+ /* SOLID is easy -> SolidBrush
+ LINEAR we can only do a gradient from 1 color to another -> LinearGradientBrush
+ We should do this if thats all we need, otherwise use software.
+ RADIAL we can't really do it. Let it fall back to software I guess. */
+
+
+ /* in the case of PATTERN_SOLID, we really just want to create a brush and hand that back... */
+ if (pattern->type == CAIRO_PATTERN_SOLID) {
+
+ /* ugh, this surface creation code should _really_ live somewhere else */
+ cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
+ if (src == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_surface_init(&src->base, &cairo_win32_surface_backend);
+ pattern->source = &src->base;
+
+ src->gr = NULL;
+ src->brush = new SolidBrush(Color(pattern->color.alpha_short,
+ pattern->color.red_short,
+ pattern->color.green_short,
+ pattern->color.blue_short));
+
+
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+ }
+
+ else if (pattern->type == CAIRO_PATTERN_LINEAR && pattern->n_stops == 2) {
+
+ /* ugh, this surface creation code should _really_ live somewhere else */
+ cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
+ if (src == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_surface_init(&src->base, &cairo_win32_surface_backend);
+ pattern->source = &src->base;
+
+ src->gr = NULL;
+
+ RectF r((float)pattern->u.linear.point0.x,
+ (float)pattern->u.linear.point0.y,
+ ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16),
+ ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16));
+
+ src->brush = new LinearGradientBrush(r,
+ Color(pattern->stops[0].color_char[3],
+ pattern->stops[0].color_char[0],
+ pattern->stops[0].color_char[1],
+ pattern->stops[0].color_char[2]),
+ Color(pattern->stops[1].color_char[3],
+ pattern->stops[1].color_char[0],
+ pattern->stops[1].color_char[1],
+ pattern->stops[1].color_char[2]),
+ 90.0, FALSE);
+
+ static_cast<LinearGradientBrush*>(src->brush)->TranslateTransform((float)pattern->source_offset.x,
+ (float)pattern->source_offset.y);
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+ }
+
+ else if (pattern->type == CAIRO_PATTERN_RADIAL) {
+#if 0 /* XXX not sure this will work.. do we have to draw with FillPath() in order for this brush to work properly? */
+ /* use PathGradientBrush here */
+
+ /* ugh, this surface creation code should _really_ live somewhere else */
+ cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t));
+ if (src == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_surface_init(&src->base, &cairo_win32_surface_backend);
+ pattern->source = &src->base;
+
+ src->gr = NULL;
+
+ PointF center(pattern->u.radial.center1.x, pattern->u.radial.center1.y);
+
+ GraphicsPath path;
+ path.AddEllipse(0, 0, 140, 70);
+
+ // Use the path to construct a brush.
+ PathGradientBrush *brush = new PathGradientBrush(&path);
+ src->brush = brush;
+
+ // Set the color at the center of the path to blue.
+ brush->SetCenterColor(Color(50, 100, 0, 255));
+
+ // Set the color along the entire boundary of the path to aqua.
+ Color colors[] = {Color(255, 0, 255, 255)};
+ int count = 1;
+ brush->SetSurroundColors(colors, &count);
+
+ brush->SetCenterPoint(center);
+
+ return (cairo_int_status_t)CAIRO_STATUS_SUCCESS;
+#endif
+
+ }
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static const cairo_surface_backend_t cairo_win32_surface_backend = {
+ _cairo_win32_surface_create_similar,
+ _cairo_win32_surface_destroy,
+ _cairo_win32_surface_pixels_per_inch,
+ _cairo_win32_surface_get_image,
+ _cairo_win32_surface_set_image,
+ _cairo_win32_surface_set_matrix,
+ _cairo_win32_surface_set_filter,
+ _cairo_win32_surface_set_repeat,
+ _cairo_win32_surface_composite,
+ _cairo_win32_surface_fill_rectangles,
+ _cairo_win32_surface_composite_trapezoids,
+ _cairo_win32_surface_copy_page,
+ _cairo_win32_surface_show_page,
+ _cairo_win32_surface_set_clip_region,
+ _cairo_win32_surface_create_pattern,
+};
diff --git a/src/cairo_glitz_surface.c b/src/cairo_glitz_surface.c
index 21e889204..69fc82f2e 100644
--- a/src/cairo_glitz_surface.c
+++ b/src/cairo_glitz_surface.c
@@ -25,6 +25,7 @@
*/
#include "cairoint.h"
+#include "cairo-glitz.h"
#define GLITZ_FIXED_TO_FLOAT(f) \
(((glitz_float_t) (f)) / 65536)
@@ -52,8 +53,6 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
return;
- glitz_surface_reference (surface);
-
crsurface = cairo_glitz_surface_create (surface);
if (crsurface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
@@ -65,10 +64,9 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
cairo_surface_destroy (crsurface);
}
-typedef struct cairo_glitz_surface {
+typedef struct _cairo_glitz_surface {
cairo_surface_t base;
- unsigned long features;
glitz_surface_t *surface;
glitz_format_t *format;
@@ -119,21 +117,29 @@ _cairo_glitz_surface_get_image (void *abstract_surface)
width = glitz_surface_get_width (surface->surface);
height = glitz_surface_get_height (surface->surface);
- if (surface->format->red_size > 0) {
+ if (surface->format->type == GLITZ_FORMAT_TYPE_COLOR) {
+ if (surface->format->color.red_size > 0) {
+ format.bpp = 32;
+
+ if (surface->format->color.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;
+ }
+ } else {
format.bpp = 32;
-
- if (surface->format->alpha_size > 0)
- format.alpha_mask = 0xff000000;
- else
- format.alpha_mask = 0x0;
-
+ format.alpha_mask = 0xff000000;
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;
}
pf.masks.bpp = format.bpp;
@@ -306,8 +312,6 @@ _glitz_operator (cairo_operator_t op)
return GLITZ_OPERATOR_XOR;
case CAIRO_OPERATOR_ADD:
return GLITZ_OPERATOR_ADD;
- case CAIRO_OPERATOR_SATURATE:
- return GLITZ_OPERATOR_SATURATE;
case CAIRO_OPERATOR_OVER:
default:
return GLITZ_OPERATOR_OVER;
@@ -319,14 +323,17 @@ _glitz_surface_create_solid (glitz_surface_t *other,
glitz_format_name_t format_name,
glitz_color_t *color)
{
- glitz_surface_t *surface;
+ glitz_drawable_t *drawable;
glitz_format_t *format;
+ glitz_surface_t *surface;
+
+ drawable = glitz_surface_get_drawable (other);
- format = glitz_surface_find_similar_standard_format (other, format_name);
+ format = glitz_find_standard_format (drawable, format_name);
if (format == NULL)
return NULL;
- surface = glitz_surface_create_similar (other, format, 1, 1);
+ surface = glitz_surface_create (drawable, format, 1, 1);
if (surface == NULL)
return NULL;
@@ -337,70 +344,126 @@ _glitz_surface_create_solid (glitz_surface_t *other,
return surface;
}
+static glitz_status_t
+_glitz_ensure_target (glitz_surface_t *surface)
+{
+ glitz_drawable_t *drawable;
+
+ drawable = glitz_surface_get_attached_drawable (surface);
+ if (!drawable) {
+ glitz_drawable_format_t *dformat;
+ glitz_drawable_format_t templ;
+ glitz_format_t *format;
+ glitz_drawable_t *pbuffer;
+ glitz_pbuffer_attributes_t attributes;
+ unsigned long mask;
+ int i;
+
+ format = glitz_surface_get_format (surface);
+ if (format->type != GLITZ_FORMAT_TYPE_COLOR)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ drawable = glitz_surface_get_drawable (surface);
+ dformat = glitz_drawable_get_format (drawable);
+
+ templ.types.pbuffer = 1;
+ mask = GLITZ_FORMAT_PBUFFER_MASK;
+
+ templ.samples = dformat->samples;
+ mask |= GLITZ_FORMAT_SAMPLES_MASK;
+
+ i = 0;
+ do {
+ dformat = glitz_find_similar_drawable_format (drawable,
+ mask, &templ, i++);
+
+ if (dformat) {
+ int sufficient = 1;
+
+ if (format->color.red_size) {
+ if (dformat->color.red_size < format->color.red_size)
+ sufficient = 0;
+ }
+ if (format->color.alpha_size) {
+ if (dformat->color.alpha_size < format->color.alpha_size)
+ sufficient = 0;
+ }
+
+ if (sufficient)
+ break;
+ }
+ } while (dformat);
+
+ if (!dformat)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ attributes.width = glitz_surface_get_width (surface);
+ attributes.height = glitz_surface_get_height (surface);
+ mask = GLITZ_PBUFFER_WIDTH_MASK | GLITZ_PBUFFER_HEIGHT_MASK;
+
+ pbuffer = glitz_create_pbuffer_drawable (drawable, dformat,
+ &attributes, mask);
+ if (!pbuffer)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (glitz_drawable_get_width (pbuffer) < attributes.width ||
+ glitz_drawable_get_height (pbuffer) < attributes.height) {
+ glitz_drawable_destroy (pbuffer);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ glitz_surface_attach (surface, pbuffer,
+ GLITZ_DRAWABLE_BUFFER_FRONT_COLOR,
+ 0, 0);
+
+ glitz_drawable_destroy (pbuffer);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static glitz_format_name_t
+_glitz_format (cairo_format_t format)
+{
+ switch (format) {
+ default:
+ case CAIRO_FORMAT_ARGB32:
+ return GLITZ_STANDARD_ARGB32;
+ case CAIRO_FORMAT_RGB24:
+ return GLITZ_STANDARD_RGB24;
+ case CAIRO_FORMAT_A8:
+ return GLITZ_STANDARD_A8;
+ case CAIRO_FORMAT_A1:
+ return GLITZ_STANDARD_A1;
+ }
+}
+
static cairo_surface_t *
_cairo_glitz_surface_create_similar (void *abstract_src,
cairo_format_t format,
- int drawable,
+ int draw,
int width,
int height)
{
cairo_glitz_surface_t *src = abstract_src;
- glitz_surface_t *surface;
cairo_surface_t *crsurface;
- glitz_format_t *glitz_format;
- glitz_format_t templ;
- unsigned long mask;
+ glitz_drawable_t *drawable;
+ glitz_surface_t *surface;
+ glitz_format_t *gformat;
+
+ drawable = glitz_surface_get_drawable (src->surface);
- templ.read.offscreen = 1;
- mask = GLITZ_FORMAT_READ_OFFSCREEN_MASK;
+ gformat = glitz_find_standard_format (drawable, _glitz_format (format));
+ if (gformat == NULL)
+ return NULL;
- if (drawable) {
- templ.draw.offscreen = 1;
- if (src->features & GLITZ_FEATURE_OFFSCREEN_MULTISAMPLE_MASK) {
- templ.multisample.samples = src->format->multisample.samples;
- mask |= GLITZ_FORMAT_MULTISAMPLE_SAMPLES_MASK;
- }
- } else
- templ.draw.offscreen = 0;
-
- mask |= GLITZ_FORMAT_DRAW_OFFSCREEN_MASK;
-
- switch (format) {
- case CAIRO_FORMAT_A1:
- case CAIRO_FORMAT_A8:
- templ.alpha_size = 8;
- mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
- break;
- case CAIRO_FORMAT_RGB24:
- templ.red_size = 8;
- mask |= GLITZ_FORMAT_RED_SIZE_MASK;
- break;
- case CAIRO_FORMAT_ARGB32:
- default:
- templ.alpha_size = templ.red_size = 8;
- mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
- mask |= GLITZ_FORMAT_RED_SIZE_MASK;
- break;
- }
-
- glitz_format =
- glitz_surface_find_similar_format (src->surface, mask, &templ, 0);
- if (glitz_format == NULL) {
- mask &= ~GLITZ_FORMAT_DRAW_OFFSCREEN_MASK;
- glitz_format =
- glitz_surface_find_similar_format (src->surface, mask, &templ, 0);
- if (glitz_format == NULL)
- return NULL;
- }
-
- surface = glitz_surface_create_similar (src->surface, glitz_format,
- width, height);
+ surface = glitz_surface_create (drawable, gformat, width, height);
if (surface == NULL)
return NULL;
crsurface = cairo_glitz_surface_create (surface);
- if (crsurface == NULL)
- glitz_surface_destroy (surface);
+
+ glitz_surface_destroy (surface);
return crsurface;
}
@@ -449,6 +512,9 @@ _glitz_composite (glitz_operator_t op,
glitz_buffer_t *geometry,
glitz_geometry_format_t *format)
{
+ if (_glitz_ensure_target (dst))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (glitz_surface_get_status (dst))
return CAIRO_STATUS_NO_TARGET_SURFACE;
@@ -494,6 +560,9 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
cairo_glitz_surface_t *mask_clone = NULL;
cairo_int_status_t status;
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (generic_src->backend != dst->base.backend) {
src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src,
CAIRO_FORMAT_ARGB32);
@@ -540,6 +609,9 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
{
cairo_glitz_surface_t *dst = abstract_dst;
glitz_color_t glitz_color;
+
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
glitz_color.red = color->red_short;
glitz_color.green = color->green_short;
@@ -613,9 +685,16 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
free (data);
return status;
- } else
+ } else {
+ if (glitz_surface_get_width (dst->surface) != 1 ||
+ glitz_surface_get_height (dst->surface) != 1) {
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
glitz_set_rectangles (dst->surface, &glitz_color,
(glitz_rectangle_t *) rects, n_rects);
+ }
return CAIRO_STATUS_SUCCESS;
}
@@ -639,6 +718,9 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
int x_dst, y_dst, x_rel, y_rel, width, height;
void *data;
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (generic_src->backend != dst->base.backend)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -764,10 +846,13 @@ _cairo_glitz_surface_create_pattern (void *abstract_dst,
break;
/* fall-through */
case CAIRO_PATTERN_LINEAR: {
+ glitz_drawable_t *drawable;
glitz_fixed16_16_t *params;
int i, n_params;
- if (!(dst->features & GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
+ drawable = glitz_surface_get_drawable (dst->surface);
+ if (!(glitz_drawable_get_features (drawable) &
+ GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
break;
if (pattern->filter != CAIRO_FILTER_BILINEAR)
@@ -885,7 +970,7 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static const struct cairo_surface_backend cairo_glitz_surface_backend = {
+static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_create_similar,
_cairo_glitz_surface_destroy,
_cairo_glitz_surface_pixels_per_inch,
@@ -918,8 +1003,8 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
_cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend);
+ glitz_surface_reference (surface);
crsurface->surface = surface;
- crsurface->features = glitz_surface_get_features (surface);
crsurface->format = glitz_surface_get_format (surface);
_cairo_pattern_init (&crsurface->pattern);
diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c
index 9f9de69e1..e855a7a66 100644
--- a/src/cairo_gstate.c
+++ b/src/cairo_gstate.c
@@ -86,7 +86,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->clip.region = NULL;
gstate->clip.surface = NULL;
- gstate->pattern = _cairo_pattern_create_solid (1.0, 1.0, 1.0);
+ gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0);
gstate->alpha = 1.0;
gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
@@ -1096,8 +1096,10 @@ _cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_re
cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
}
- *x_ret = x;
- *y_ret = y;
+ if (x_ret)
+ *x_ret = x;
+ if (y_ret)
+ *y_ret = y;
return CAIRO_STATUS_SUCCESS;
}
@@ -1363,6 +1365,54 @@ BAIL:
return status;
}
+static cairo_status_t
+_calculate_region_for_intermediate_clip_surface (pixman_region16_t *out,
+ cairo_box_t *extents,
+ cairo_clip_rec_t *clip_rect)
+{
+ cairo_status_t status;
+ pixman_region16_t *extents_region, *clip_region;
+ pixman_box16_t clip_box, pixman_extents;
+
+ pixman_extents.x1 = _cairo_fixed_integer_floor (extents->p1.x);
+ pixman_extents.y1 = _cairo_fixed_integer_floor (extents->p1.y);
+ pixman_extents.x2 = _cairo_fixed_integer_ceil (extents->p2.x);
+ pixman_extents.y2 = _cairo_fixed_integer_ceil (extents->p2.y);
+ extents_region = pixman_region_create_simple (&pixman_extents);
+ if (extents_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ clip_box.x1 = clip_rect->x;
+ clip_box.y1 = clip_rect->y;
+ clip_box.x2 = clip_rect->x + clip_rect->width;
+ clip_box.y2 = clip_rect->y + clip_rect->height;
+ clip_region = pixman_region_create_simple (&clip_box);
+ if (clip_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL1;
+ }
+
+ if (pixman_region_intersect (out,
+ extents_region,
+ clip_region)
+ == PIXMAN_REGION_STATUS_FAILURE)
+ status = CAIRO_STATUS_NO_MEMORY;
+ else
+ status = CAIRO_STATUS_SUCCESS;
+
+ pixman_region_destroy (extents_region);
+ BAIL1:
+ pixman_region_destroy (clip_region);
+
+ BAIL0:
+ return status;
+}
+
+
/* Warning: This call modifies the coordinates of traps */
static cairo_status_t
_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
@@ -1385,25 +1435,38 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
int i;
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, 0.);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
- &empty_color);
- if (intermediate == NULL) {
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
status = CAIRO_STATUS_NO_MEMORY;
goto BAIL0;
}
+
+ _cairo_traps_extents (traps, &extents);
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &extents,
+ &gstate->clip);
+ if (status)
+ goto BAIL1;
+
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
/* Ugh. The cairo_composite/(Render) interface doesn't allow
an offset for the trapezoids. Need to manually shift all
- the coordinates to align with the offset origin of the clip
- surface. */
- xoff = _cairo_fixed_from_double (gstate->clip.x);
- yoff = _cairo_fixed_from_double (gstate->clip.y);
+ the coordinates to align with the offset origin of the
+ intermediate surface. */
+ xoff = _cairo_fixed_from_int (draw_extents->x1);
+ yoff = _cairo_fixed_from_int (draw_extents->y1);
for (i=0, t=traps->traps; i < traps->num_traps; i++, t++) {
t->top -= yoff;
t->bottom -= yoff;
@@ -1428,11 +1491,22 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
_cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0);
_cairo_pattern_set_alpha (&pattern, 1.0);
- _cairo_traps_extents (traps, &extents);
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
goto BAIL1;
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, 0.);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
+ &empty_color);
+ if (intermediate == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL2;
+ }
+
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
pattern.source, intermediate,
x_src,
@@ -1440,30 +1514,32 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
traps->traps,
traps->num_traps);
if (status)
- goto BAIL2;
+ goto BAIL3;
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
gstate->clip.surface,
NULL,
intermediate,
- 0, 0, 0, 0, 0, 0,
- gstate->clip.width, gstate->clip.height);
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
+ 0, 0,
+ 0, 0,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
if (status)
- goto BAIL2;
+ goto BAIL3;
_cairo_pattern_fini (&pattern);
_cairo_pattern_init_copy (&pattern, src);
- extents.p1.x = _cairo_fixed_from_int (gstate->clip.x);
- extents.p1.y = _cairo_fixed_from_int (gstate->clip.y);
- extents.p2.x =
- _cairo_fixed_from_int (gstate->clip.x + gstate->clip.width);
- extents.p2.y =
- _cairo_fixed_from_int (gstate->clip.y + gstate->clip.height);
+ extents.p1.x = _cairo_fixed_from_int (draw_extents->x1);
+ extents.p1.y = _cairo_fixed_from_int (draw_extents->y1);
+ extents.p2.x = _cairo_fixed_from_int (draw_extents->x2);
+ extents.p2.y = _cairo_fixed_from_int (draw_extents->y2);
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
- goto BAIL2;
+ goto BAIL3;
if (dst == gstate->clip.surface)
xoff = yoff = 0;
@@ -1474,13 +1550,16 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
0, 0,
xoff >> 16,
yoff >> 16,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+
- BAIL2:
+ BAIL3:
cairo_surface_destroy (intermediate);
- BAIL1:
+ BAIL2:
_cairo_pattern_fini (&pattern);
+ BAIL1:
+ pixman_region_destroy (draw_region);
BAIL0:
if (status)
@@ -1705,6 +1784,25 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
return 0;
}
+/* Reset surface clip region to the one in the gstate */
+cairo_status_t
+_cairo_gstate_restore_external_state (cairo_gstate_t *gstate)
+{
+ cairo_status_t status;
+
+ status = CAIRO_STATUS_SUCCESS;
+
+ if (gstate->surface)
+ status = _cairo_surface_set_clip_region (gstate->surface,
+ gstate->clip.region);
+
+ /* If not supported we're already using surface clipping */
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ status = CAIRO_STATUS_SUCCESS;
+
+ return status;
+}
+
cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate)
{
@@ -1762,6 +1860,10 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_traps_fini (&traps);
return status;
}
+
+ /* Fall through as status == CAIRO_INT_STATUS_UNSUPPORTED
+ means that backend doesn't support clipping regions and
+ mask surface clipping should be used instead. */
}
/* Otherwise represent the clip as a mask surface. */
@@ -1799,7 +1901,7 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_traps_fini (&traps);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@@ -1809,7 +1911,7 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
int height)
{
- /* We are dealing with 5 coordinate spaces in this function. this makes
+ /* We are dealing with 6 coordinate spaces in this function. this makes
* it ugly.
*
* - "Image" space is the space of the surface we're reading pixels from.
@@ -1833,12 +1935,16 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
* a bounding box around the "clip path", situated somewhere in device
* space. The clip path is already painted on the clip surface.
*
+ * - "Intermediate" space is the subset of the Clip space that the
+ * drawing will affect, and we allocate an intermediate surface
+ * of this size so that we can paint in it.
+ *
* - "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
+ * (in fact, there is a 7th 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
@@ -1897,15 +2003,16 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
_cairo_pattern_init (&pattern);
+ pattern_extents.p1.x = _cairo_fixed_from_double (device_x);
+ pattern_extents.p1.y = _cairo_fixed_from_double (device_y);
+ pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
+ pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
+
if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) ||
(gstate->alpha != 1.0)) {
/* I'm allowing any type of pattern for the mask right now.
Maybe this is bad. Will allow for some cool effects though. */
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- 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;
@@ -1915,13 +2022,36 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
{
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &pattern_extents,
+ &gstate->clip);
+ if (status)
+ goto BAIL1;
+
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
+
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, .0);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
&empty_color);
/* it is not completely clear what the "right" way to combine the
@@ -1935,27 +2065,33 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
gstate->clip.surface,
pattern.source,
intermediate,
- 0, 0,
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
0, 0,
0, 0,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (gstate->operator,
surface,
intermediate,
gstate->surface,
- gstate->clip.x, gstate->clip.y,
+ draw_extents->x1, draw_extents->y1,
0, 0,
- gstate->clip.x, gstate->clip.y,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x1, draw_extents->y1,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
- BAIL:
+ BAIL2:
cairo_surface_destroy (intermediate);
+ BAIL1:
+ pixman_region_destroy (draw_region);
+ BAIL0:
+ ;
}
else
{
@@ -1992,21 +2128,14 @@ _cairo_gstate_select_font (cairo_gstate_t *gstate,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
- cairo_unscaled_font_t *tmp;
-
- tmp = _cairo_unscaled_font_create (family, slant, weight);
+ if (gstate->font)
+ _cairo_unscaled_font_destroy (gstate->font);
- if (tmp == NULL)
+ gstate->font = _cairo_unscaled_font_create (family, slant, weight);
+ if (gstate->font == NULL)
return CAIRO_STATUS_NO_MEMORY;
- if (gstate->font != tmp)
- {
- if (gstate->font != NULL)
- _cairo_unscaled_font_destroy (gstate->font);
-
- cairo_matrix_set_identity (&gstate->font_matrix);
- gstate->font = tmp;
- }
+ cairo_matrix_set_identity (&gstate->font_matrix);
return CAIRO_STATUS_SUCCESS;
}
@@ -2171,30 +2300,27 @@ _cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
{
cairo_int_status_t status;
cairo_font_scale_t sc;
- double dummy = 0.0;
+ double font_scale_x, font_scale_y;
_build_font_scale (gstate, &sc);
status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents);
- /* The font responded in device space; convert to user space. */
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->ascent);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->descent);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &dummy,
- &extents->height);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->max_x_advance,
- &extents->max_y_advance);
-
+ _cairo_matrix_compute_scale_factors (&gstate->font_matrix,
+ &font_scale_x, &font_scale_y,
+ /* XXX */ 1);
+
+ /*
+ * The font responded in unscaled units, scale by the font
+ * matrix scale factors to get to user space
+ */
+
+ extents->ascent *= font_scale_y;
+ extents->descent *= font_scale_y;
+ extents->height *= font_scale_y;
+ extents->max_x_advance *= font_scale_x;
+ extents->max_y_advance *= font_scale_y;
+
return status;
}
@@ -2208,18 +2334,20 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
cairo_font_scale_t sc;
cairo_point_t point;
- double dev_x, dev_y;
+ double origin_x, origin_y;
int i;
_build_font_scale (gstate, &sc);
status = _cairo_path_current_point (&gstate->path, &point);
if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- dev_x = 0.0;
- dev_y = 0.0;
+ origin_x = 0.0;
+ origin_y = 0.0;
} else {
- dev_x = _cairo_fixed_to_double (point.x);
- dev_y = _cairo_fixed_to_double (point.y);
+ origin_x = _cairo_fixed_to_double (point.x);
+ origin_y = _cairo_fixed_to_double (point.y);
+ cairo_matrix_transform_point (&gstate->ctm_inverse,
+ &origin_x, &origin_y);
}
status = _cairo_unscaled_font_text_to_glyphs (gstate->font,
@@ -2228,15 +2356,16 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
return status;
- /* The font responded in device space, starting from (0,0); add any
- current point offset in device space, and convert to user space. */
+ /* The font responded in glyph space, starting from (0,0). Convert to
+ user space by applying the font transform, then add any current point
+ offset. */
for (i = 0; i < *nglyphs; ++i) {
- (*glyphs)[i].x += dev_x;
- (*glyphs)[i].y += dev_y;
- cairo_matrix_transform_point (&gstate->ctm_inverse,
- &((*glyphs)[i].x),
- &((*glyphs)[i].y));
+ cairo_matrix_transform_point (&gstate->font_matrix,
+ &((*glyphs)[i].x),
+ &((*glyphs)[i].y));
+ (*glyphs)[i].x += origin_x;
+ (*glyphs)[i].y += origin_y;
}
return CAIRO_STATUS_SUCCESS;
@@ -2265,44 +2394,88 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
int num_glyphs,
cairo_text_extents_t *extents)
{
- cairo_status_t status;
- cairo_glyph_t *transformed_glyphs;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_glyph_t origin_glyph;
+ cairo_text_extents_t origin_extents;
cairo_font_scale_t sc;
int i;
+ double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
+ double x_pos = 0.0, y_pos = 0.0;
+ int set = 0;
- _build_font_scale (gstate, &sc);
-
- transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
- if (transformed_glyphs == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < num_glyphs; ++i)
+ if (!num_glyphs)
{
- transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &transformed_glyphs[i].x,
- &transformed_glyphs[i].y);
+ extents->x_bearing = 0.0;
+ extents->y_bearing = 0.0;
+ extents->width = 0.0;
+ extents->height = 0.0;
+ extents->x_advance = 0.0;
+ extents->y_advance = 0.0;
+ return CAIRO_STATUS_SUCCESS;
}
- status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc,
- transformed_glyphs, num_glyphs,
- extents);
-
- /* The font responded in device space; convert to user space. */
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->x_bearing,
- &extents->y_bearing);
+ _build_font_scale (gstate, &sc);
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->width,
- &extents->height);
+ for (i = 0; i < num_glyphs; i++)
+ {
+ double x, y;
+ double wm, hm;
+
+ origin_glyph = glyphs[i];
+ origin_glyph.x = 0.0;
+ origin_glyph.y = 0.0;
+ status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc,
+ &origin_glyph, 1,
+ &origin_extents);
+
+ /*
+ * Transform font space metrics into user space metrics
+ * by running the corners through the font matrix and
+ * expanding the bounding box as necessary
+ */
+ x = origin_extents.x_bearing;
+ y = origin_extents.y_bearing;
+ cairo_matrix_transform_point (&gstate->font_matrix,
+ &x, &y);
+
+ for (hm = 0.0; hm <= 1.0; hm += 1.0)
+ for (wm = 0.0; wm <= 1.0; wm += 1.0)
+ {
+ x = origin_extents.x_bearing + origin_extents.width * wm;
+ y = origin_extents.y_bearing + origin_extents.height * hm;
+ cairo_matrix_transform_point (&gstate->font_matrix,
+ &x, &y);
+ x += glyphs[i].x;
+ y += glyphs[i].y;
+ if (!set)
+ {
+ min_x = max_x = x;
+ min_y = max_y = y;
+ set = 1;
+ }
+ else
+ {
+ if (x < min_x) min_x = x;
+ if (x > max_x) max_x = x;
+ if (y < min_y) min_y = y;
+ if (y > max_y) max_y = y;
+ }
+ }
- cairo_matrix_transform_distance (&gstate->ctm_inverse,
- &extents->x_advance,
- &extents->y_advance);
+ x = origin_extents.x_advance;
+ y = origin_extents.y_advance;
+ cairo_matrix_transform_point (&gstate->font_matrix,
+ &x, &y);
+ x_pos = glyphs[i].x + x;
+ y_pos = glyphs[i].y + y;
+ }
- free (transformed_glyphs);
+ extents->x_bearing = min_x - glyphs[0].x;
+ extents->y_bearing = min_y - glyphs[0].y;
+ extents->width = max_x - min_x;
+ extents->height = max_y - min_y;
+ extents->x_advance = x_pos - glyphs[0].x;
+ extents->y_advance = y_pos - glyphs[0].y;
return status;
}
@@ -2338,55 +2511,84 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
&bbox);
if (status)
- return status;
+ goto CLEANUP_GLYPHS;
status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox);
if (status)
- return status;
+ goto CLEANUP_GLYPHS;
if (gstate->clip.surface)
{
cairo_surface_t *intermediate;
cairo_color_t empty_color;
+ pixman_box16_t *draw_extents;
+ pixman_region16_t *draw_region;
+
+ draw_region = pixman_region_create ();
+ if (draw_region == NULL)
+ {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL0;
+ }
+
+ status = _calculate_region_for_intermediate_clip_surface (draw_region,
+ &bbox,
+ &gstate->clip);
+ if (status) {
+ goto BAIL1;
+ }
+ /* Shortcut if empty */
+ if (!pixman_region_not_empty (draw_region)) {
+ status = CAIRO_STATUS_SUCCESS;
+ goto BAIL1;
+ }
+
+ draw_extents = pixman_region_extents (draw_region);
+
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, .0);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1,
&empty_color);
+ if (intermediate == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL1;
+ }
- /* move the glyphs again, from dev space to clip space */
+ /* move the glyphs again, from dev space to intermediate space */
for (i = 0; i < num_glyphs; ++i)
{
- transformed_glyphs[i].x -= gstate->clip.x;
- transformed_glyphs[i].y -= gstate->clip.y;
+ transformed_glyphs[i].x -= draw_extents->x1;
+ transformed_glyphs[i].y -= draw_extents->y1;
}
status = _cairo_unscaled_font_show_glyphs (gstate->font,
&sc,
CAIRO_OPERATOR_ADD,
pattern.source, intermediate,
- gstate->clip.x - pattern.source_offset.x,
- gstate->clip.y - pattern.source_offset.y,
+ draw_extents->x1 - pattern.source_offset.x,
+ draw_extents->y1 - pattern.source_offset.y,
transformed_glyphs, num_glyphs);
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
gstate->clip.surface,
NULL,
intermediate,
- 0, 0,
+ draw_extents->x1 - gstate->clip.x,
+ draw_extents->y1 - gstate->clip.y,
0, 0,
0, 0,
- gstate->clip.width,
- gstate->clip.height);
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
if (status)
- goto BAIL;
+ goto BAIL2;
status = _cairo_surface_composite (gstate->operator,
pattern.source,
@@ -2394,14 +2596,17 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
gstate->surface,
0, 0,
0, 0,
- gstate->clip.x,
- gstate->clip.y,
- gstate->clip.width,
- gstate->clip.height);
-
- BAIL:
- cairo_surface_destroy (intermediate);
+ draw_extents->x1,
+ draw_extents->y1,
+ draw_extents->x2 - draw_extents->x1,
+ draw_extents->y2 - draw_extents->y1);
+ BAIL2:
+ cairo_surface_destroy (intermediate);
+ BAIL1:
+ pixman_region_destroy (draw_region);
+ BAIL0:
+ ;
}
else
{
@@ -2416,6 +2621,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
_cairo_pattern_fini (&pattern);
+ CLEANUP_GLYPHS:
free (transformed_glyphs);
return status;
diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c
index cbdc018a1..14e30f695 100644
--- a/src/cairo_image_surface.c
+++ b/src/cairo_image_surface.c
@@ -169,7 +169,7 @@ cairo_image_surface_create_for_data (char *data,
pixman_format = _create_pixman_format (format);
if (pixman_format == NULL)
return NULL;
-
+
pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
width, height,
_cairo_format_bpp (format),
@@ -199,7 +199,7 @@ static void
_cairo_image_abstract_surface_destroy (void *abstract_surface)
{
cairo_image_surface_t *surface = abstract_surface;
-
+
if (surface->pixman_image)
pixman_image_destroy (surface->pixman_image);
@@ -490,7 +490,7 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
+static cairo_int_status_t
_cairo_image_abstract_surface_create_pattern (void *abstract_surface,
cairo_pattern_t *pattern,
cairo_box_t *box)
diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c
index 7fc2694f3..b964b688c 100644
--- a/src/cairo_matrix.c
+++ b/src/cairo_matrix.c
@@ -34,6 +34,7 @@
* Carl D. Worth <cworth@isi.edu>
*/
+#define _GNU_SOURCE
#include <stdlib.h>
#include <math.h>
@@ -124,9 +125,20 @@ cairo_matrix_get_affine (cairo_matrix_t *matrix,
double *c, double *d,
double *tx, double *ty)
{
- *a = matrix->m[0][0]; *b = matrix->m[0][1];
- *c = matrix->m[1][0]; *d = matrix->m[1][1];
- *tx = matrix->m[2][0]; *ty = matrix->m[2][1];
+ if (a)
+ *a = matrix->m[0][0];
+ if (b)
+ *b = matrix->m[0][1];
+
+ if (c)
+ *c = matrix->m[1][0];
+ if (d)
+ *d = matrix->m[1][1];
+
+ if (tx)
+ *tx = matrix->m[2][0];
+ if (ty)
+ *ty = matrix->m[2][1];
return CAIRO_STATUS_SUCCESS;
}
@@ -176,9 +188,17 @@ cairo_status_t
_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
double radians)
{
+ double s;
+ double c;
+#if HAVE_SINCOS
+ sincos (radians, &s, &c);
+#else
+ s = sin (radians);
+ c = cos (radians);
+#endif
return cairo_matrix_set_affine (matrix,
- cos (radians), sin (radians),
- -sin (radians), cos (radians),
+ c, s,
+ -s, c,
0, 0);
}
@@ -398,19 +418,42 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
/* Compute the amount that each basis vector is scaled by. */
cairo_status_t
-_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy)
+_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major)
{
- double x, y;
+ double det;
- x = 1.0;
- y = 0.0;
- cairo_matrix_transform_distance (matrix, &x, &y);
- *sx = sqrt(x*x + y*y);
+ _cairo_matrix_compute_determinant (matrix, &det);
- x = 0.0;
- y = 1.0;
- cairo_matrix_transform_distance (matrix, &x, &y);
- *sy = sqrt(x*x + y*y);
+ if (det == 0)
+ *sx = *sy = 0;
+ else
+ {
+ double x = x_major != 0;
+ double y = x == 0;
+ double major, minor;
+
+ cairo_matrix_transform_distance (matrix, &x, &y);
+ major = sqrt(x*x + y*y);
+ /*
+ * ignore mirroring
+ */
+ if (det < 0)
+ det = -det;
+ if (major)
+ minor = det / major;
+ else
+ minor = 0.0;
+ if (x_major)
+ {
+ *sx = major;
+ *sy = minor;
+ }
+ else
+ {
+ *sx = minor;
+ *sy = major;
+ }
+ }
return CAIRO_STATUS_SUCCESS;
}
diff --git a/src/cairo_pdf_surface.c b/src/cairo_pdf_surface.c
new file mode 100644
index 000000000..23230aa74
--- /dev/null
+++ b/src/cairo_pdf_surface.c
@@ -0,0 +1,2208 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-pdf.h"
+/* XXX: This seems broken to me. What about users without freetype
+ * that want to use a cairo PDF surface? */
+#include "cairo-ft.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_TRUETYPE_TABLES_H
+
+#include <time.h>
+#include <zlib.h>
+
+/* Issues:
+ *
+ * - Why doesn't pages inherit /alpha%d GS dictionaries from the Pages
+ * object?
+ *
+ * - Why isn't the pattern passed to composite traps instead of
+ * pattern->source? If composite traps needs an image or a surface it
+ * can call create_pattern().
+ *
+ * - We embed an image in the stream each time it's composited. We
+ * could add generation counters to surfaces and remember the stream
+ * ID for a particular generation for a particular surface.
+ *
+ * - Multi stop gradients. What are the exponential interpolation
+ * functions, could they be used for gradients?
+ *
+ * - Clipping: must be able to reset clipping
+ *
+ * - Images of other formats than 8 bit RGBA.
+ *
+ * - Backend specific meta data.
+ *
+ * - Surface patterns.
+ *
+ * - Alpha channels in gradients.
+ *
+ * - Should/does cairo support drawing into a scratch surface and then
+ * using that as a fill pattern? For this backend, that would involve
+ * using a tiling pattern (4.6.2). How do you create such a scratch
+ * surface? cairo_surface_create_similar() ?
+ *
+ * - What if you create a similiar surface and does show_page and then
+ * does show_surface on another surface?
+ *
+ * - Output TM so page scales to the right size - PDF default user
+ * space has 1 unit = 1 / 72 inch.
+ *
+ * - Add test case for RGBA images.
+ *
+ * - Add test case for RGBA gradients.
+ *
+ * - Pattern extend isn't honoured by image backend.
+ *
+ * - Coordinate space for create_similar() args?
+ *
+ * - Investigate /Matrix entry in content stream dicts for pages
+ * instead of outputting the cm operator in every page.
+ */
+
+typedef struct ft_subset_glyph ft_subset_glyph_t;
+struct ft_subset_glyph {
+ int parent_index;
+ unsigned long location;
+};
+
+typedef struct cairo_pdf_font_backend cairo_pdf_font_backend_t;
+struct cairo_pdf_font_backend {
+ int (*use_glyph) (void *abstract_font,
+ int glyph);
+ cairo_status_t (*generate) (void *abstract_font,
+ const char **data,
+ unsigned long *length);
+ void (*destroy) (void *abstract_font);
+};
+
+typedef struct cairo_pdf_font cairo_pdf_font_t;
+struct cairo_pdf_font {
+ cairo_pdf_font_backend_t *backend;
+ cairo_unscaled_font_t *unscaled_font;
+ unsigned int font_id;
+ char *base_font;
+ int num_glyphs;
+ int *widths;
+ long x_min, y_min, x_max, y_max;
+ long ascent, descent;
+};
+
+typedef struct cairo_pdf_ft_font cairo_pdf_ft_font_t;
+struct cairo_pdf_ft_font {
+ cairo_pdf_font_t base;
+ ft_subset_glyph_t *glyphs;
+ FT_Face face;
+ unsigned long *checksum_location;
+ cairo_array_t output;
+ int *parent_to_subset;
+ cairo_status_t status;
+};
+
+typedef struct cairo_pdf_object cairo_pdf_object_t;
+typedef struct cairo_pdf_resource cairo_pdf_resource_t;
+typedef struct cairo_pdf_stream cairo_pdf_stream_t;
+typedef struct cairo_pdf_document cairo_pdf_document_t;
+typedef struct cairo_pdf_surface cairo_pdf_surface_t;
+
+struct cairo_pdf_object {
+ long offset;
+};
+
+struct cairo_pdf_resource {
+ unsigned int id;
+};
+
+struct cairo_pdf_stream {
+ unsigned int id;
+ unsigned int length_id;
+ long start_offset;
+};
+
+struct cairo_pdf_document {
+ FILE *file;
+ unsigned long refcount;
+
+ double width_inches;
+ double height_inches;
+ double x_ppi;
+ double y_ppi;
+
+ unsigned int next_available_id;
+ unsigned int pages_id;
+
+ cairo_pdf_stream_t *current_stream;
+
+ cairo_array_t objects;
+ cairo_array_t pages;
+
+ cairo_array_t fonts;
+};
+
+struct cairo_pdf_surface {
+ cairo_surface_t base;
+
+ double width_inches;
+ double height_inches;
+
+ /* HACK: Non-null if this surface was created for a pattern. */
+ cairo_pattern_t *pattern;
+
+ cairo_pdf_document_t *document;
+ cairo_pdf_stream_t *current_stream;
+
+ cairo_array_t patterns;
+ cairo_array_t xobjects;
+ cairo_array_t streams;
+ cairo_array_t alphas;
+ cairo_array_t fonts;
+};
+
+
+static cairo_pdf_document_t *
+_cairo_pdf_document_create (FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch);
+
+static void
+_cairo_pdf_document_destroy (cairo_pdf_document_t *document);
+
+static void
+_cairo_pdf_document_reference (cairo_pdf_document_t *document);
+
+static unsigned int
+_cairo_pdf_document_new_object (cairo_pdf_document_t *document);
+
+static cairo_status_t
+_cairo_pdf_document_add_page (cairo_pdf_document_t *document,
+ cairo_pdf_surface_t *surface);
+
+static void
+_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
+
+static cairo_pdf_stream_t *
+_cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
+ const char *extra_entries);
+static cairo_surface_t *
+_cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
+ double width_inches,
+ double height_inches);
+static void
+_cairo_pdf_surface_add_stream (cairo_pdf_surface_t *surface,
+ cairo_pdf_stream_t *stream);
+static void
+_cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface);
+
+static const cairo_surface_backend_t cairo_pdf_surface_backend;
+
+/* Truetype font subsetting code */
+
+#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) )
+
+#define SFNT_VERSION 0x00010000
+#define OFFSET_TABLE_SIZE 12
+#define TABLE_DIRECTORY_ENTRY_SIZE 16
+
+#ifdef WORDS_BIGENDIAN
+
+#define cpu_to_be16(v) (v)
+#define be16_to_cpu(v) (v)
+#define cpu_to_be32(v) (v)
+#define be32_to_cpu(v) (v)
+
+#else
+
+static inline unsigned short
+cpu_to_be16(unsigned short v)
+{
+ return (v << 8) | (v >> 8);
+}
+
+static inline unsigned short
+be16_to_cpu(unsigned short v)
+{
+ return cpu_to_be16 (v);
+}
+
+static inline unsigned long
+cpu_to_be32(unsigned long v)
+{
+ return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16);
+}
+
+static inline unsigned long
+be32_to_cpu(unsigned long v)
+{
+ return cpu_to_be32 (v);
+}
+
+#endif
+
+static cairo_pdf_font_backend_t cairo_pdf_ft_font_backend;
+
+static int
+cairo_pdf_font_use_glyph (cairo_pdf_font_t *font, int glyph)
+{
+ return font->backend->use_glyph (font, glyph);
+}
+
+static cairo_status_t
+cairo_pdf_font_generate (cairo_pdf_font_t *font,
+ const char **data, unsigned long *length)
+{
+ return font->backend->generate (font, data, length);
+}
+
+static void
+cairo_pdf_font_destroy (cairo_pdf_font_t *font)
+{
+ font->backend->destroy (font);
+}
+
+static cairo_pdf_font_t *
+cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
+ cairo_unscaled_font_t *unscaled_font,
+ cairo_font_scale_t *scale)
+{
+ cairo_font_t scaled_font;
+ FT_Face face;
+ cairo_pdf_ft_font_t *font;
+ unsigned long size;
+ int i, j;
+
+ /* FIXME: Why do I have to pass a scaled font to get the FT_Face? */
+ _cairo_font_init (&scaled_font, scale, unscaled_font);
+ face = cairo_ft_font_face (&scaled_font);
+
+ /* We currently only support freetype truetype fonts. */
+ size = 0;
+ if (!FT_IS_SFNT (face) ||
+ FT_Load_Sfnt_Table (face, TTAG_glyf, 0, NULL, &size) != 0)
+ return NULL;
+
+ font = malloc (sizeof (cairo_pdf_ft_font_t));
+ if (font == NULL)
+ return NULL;
+
+ font->base.unscaled_font = unscaled_font;
+ _cairo_unscaled_font_reference (unscaled_font);
+ font->base.backend = &cairo_pdf_ft_font_backend;
+ font->base.font_id = _cairo_pdf_document_new_object (document);
+
+ _cairo_array_init (&font->output, sizeof (char));
+ if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
+ goto fail1;
+
+ font->face = face;
+ font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
+ if (font->glyphs == NULL)
+ goto fail2;
+
+ font->parent_to_subset = calloc (face->num_glyphs, sizeof (int));
+ if (font->parent_to_subset == NULL)
+ goto fail3;
+
+ font->base.num_glyphs = 1;
+ font->base.x_min = face->bbox.xMin;
+ font->base.y_min = face->bbox.yMin;
+ font->base.x_max = face->bbox.xMax;
+ font->base.y_max = face->bbox.yMax;
+ font->base.ascent = face->ascender;
+ font->base.descent = face->descender;
+ font->base.base_font = strdup (face->family_name);
+ if (font->base.base_font == NULL)
+ goto fail4;
+
+ for (i = 0, j = 0; font->base.base_font[j]; j++) {
+ if (font->base.base_font[j] == ' ')
+ continue;
+ font->base.base_font[i++] = font->base.base_font[j];
+ }
+ font->base.base_font[i] = '\0';
+
+ font->base.widths = calloc (face->num_glyphs, sizeof (int));
+ if (font->base.widths == NULL)
+ goto fail5;
+
+ font->status = CAIRO_STATUS_SUCCESS;
+
+ return &font->base;
+
+ fail5:
+ free (font->base.base_font);
+ fail4:
+ free (font->parent_to_subset);
+ fail3:
+ free (font->glyphs);
+ fail2:
+ _cairo_array_fini (&font->output);
+ fail1:
+ free (font);
+ return NULL;
+}
+
+static void
+cairo_pdf_ft_font_destroy (void *abstract_font)
+{
+ cairo_pdf_ft_font_t *font = abstract_font;
+
+ _cairo_unscaled_font_destroy (font->base.unscaled_font);
+ free (font->base.base_font);
+ free (font->parent_to_subset);
+ free (font->glyphs);
+ _cairo_array_fini (&font->output);
+ free (font);
+}
+
+static void *
+cairo_pdf_ft_font_write (cairo_pdf_ft_font_t *font,
+ const void *data, size_t length)
+{
+ void *p;
+
+ p = _cairo_array_append (&font->output, data, length);
+ if (p == NULL)
+ font->status = CAIRO_STATUS_NO_MEMORY;
+
+ return p;
+}
+
+static void
+cairo_pdf_ft_font_write_be16 (cairo_pdf_ft_font_t *font,
+ unsigned short value)
+{
+ unsigned short be16_value;
+
+ be16_value = cpu_to_be16 (value);
+ cairo_pdf_ft_font_write (font, &be16_value, sizeof be16_value);
+}
+
+static void
+cairo_pdf_ft_font_write_be32 (cairo_pdf_ft_font_t *font, unsigned long value)
+{
+ unsigned long be32_value;
+
+ be32_value = cpu_to_be32 (value);
+ cairo_pdf_ft_font_write (font, &be32_value, sizeof be32_value);
+}
+
+static unsigned long
+cairo_pdf_ft_font_align_output (cairo_pdf_ft_font_t *font)
+{
+ int length, aligned;
+ static const char pad[4];
+
+ length = _cairo_array_num_elements (&font->output);
+ aligned = (length + 3) & ~3;
+ cairo_pdf_ft_font_write (font, pad, aligned - length);
+
+ return aligned;
+}
+
+static int
+cairo_pdf_ft_font_write_cmap_table (cairo_pdf_ft_font_t *font, unsigned long tag)
+{
+ int i;
+
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 1);
+
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be32 (font, 12);
+
+ /* Output a format 6 encoding table. */
+
+ cairo_pdf_ft_font_write_be16 (font, 6);
+ cairo_pdf_ft_font_write_be16 (font, 10 + 2 * (font->base.num_glyphs - 1));
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 1); /* First glyph */
+ cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs - 1);
+ for (i = 1; i < font->base.num_glyphs; i++)
+ cairo_pdf_ft_font_write_be16 (font, i);
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_generic_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ char *buffer;
+ unsigned long size;
+
+ size = 0;
+ FT_Load_Sfnt_Table (font->face, tag, 0, NULL, &size);
+ buffer = cairo_pdf_ft_font_write (font, NULL, size);
+ FT_Load_Sfnt_Table (font->face, tag, 0, buffer, &size);
+
+ return 0;
+}
+
+static int
+cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ unsigned long start_offset, index, size;
+ TT_Header *header;
+ unsigned long begin, end;
+ char *buffer;
+ int i;
+ union {
+ unsigned char *bytes;
+ unsigned short *short_offsets;
+ unsigned long *long_offsets;
+ } u;
+
+ header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
+ if (header->Index_To_Loc_Format == 0)
+ size = sizeof (short) * (font->face->num_glyphs + 1);
+ else
+ size = sizeof (long) * (font->face->num_glyphs + 1);
+
+ u.bytes = malloc (size);
+ if (u.bytes == NULL) {
+ font->status = CAIRO_STATUS_NO_MEMORY;
+ return font->status;
+ }
+ FT_Load_Sfnt_Table (font->face, TTAG_loca, 0, u.bytes, &size);
+
+ start_offset = _cairo_array_num_elements (&font->output);
+ for (i = 0; i < font->base.num_glyphs; i++) {
+ index = font->glyphs[i].parent_index;
+ if (header->Index_To_Loc_Format == 0) {
+ begin = be16_to_cpu (u.short_offsets[index]) * 2;
+ end = be16_to_cpu (u.short_offsets[index + 1]) * 2;
+ }
+ else {
+ begin = be32_to_cpu (u.long_offsets[index]);
+ end = be32_to_cpu (u.long_offsets[index + 1]);
+ }
+
+ size = end - begin;
+
+ font->glyphs[i].location =
+ cairo_pdf_ft_font_align_output (font) - start_offset;
+ buffer = cairo_pdf_ft_font_write (font, NULL, size);
+ if (buffer == NULL)
+ break;
+ FT_Load_Sfnt_Table (font->face, TTAG_glyf, begin, buffer, &size);
+ /* FIXME: remap composite glyphs */
+ }
+
+ font->glyphs[i].location =
+ cairo_pdf_ft_font_align_output (font) - start_offset;
+
+ free (u.bytes);
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_head_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ TT_Header *head;
+
+ head = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
+
+ cairo_pdf_ft_font_write_be32 (font, head->Table_Version);
+ cairo_pdf_ft_font_write_be32 (font, head->Font_Revision);
+
+ font->checksum_location =
+ (unsigned long *) _cairo_array_index (&font->output, 0) +
+ _cairo_array_num_elements (&font->output) / sizeof (long);
+ cairo_pdf_ft_font_write_be32 (font, 0);
+ cairo_pdf_ft_font_write_be32 (font, head->Magic_Number);
+
+ cairo_pdf_ft_font_write_be16 (font, head->Flags);
+ cairo_pdf_ft_font_write_be16 (font, head->Units_Per_EM);
+
+ cairo_pdf_ft_font_write_be32 (font, head->Created[0]);
+ cairo_pdf_ft_font_write_be32 (font, head->Created[1]);
+ cairo_pdf_ft_font_write_be32 (font, head->Modified[0]);
+ cairo_pdf_ft_font_write_be32 (font, head->Modified[1]);
+
+ cairo_pdf_ft_font_write_be16 (font, head->xMin);
+ cairo_pdf_ft_font_write_be16 (font, head->yMin);
+ cairo_pdf_ft_font_write_be16 (font, head->xMax);
+ cairo_pdf_ft_font_write_be16 (font, head->yMax);
+
+ cairo_pdf_ft_font_write_be16 (font, head->Mac_Style);
+ cairo_pdf_ft_font_write_be16 (font, head->Lowest_Rec_PPEM);
+
+ cairo_pdf_ft_font_write_be16 (font, head->Font_Direction);
+ cairo_pdf_ft_font_write_be16 (font, head->Index_To_Loc_Format);
+ cairo_pdf_ft_font_write_be16 (font, head->Glyph_Data_Format);
+
+ return font->status;
+}
+
+static int cairo_pdf_ft_font_write_hhea_table (cairo_pdf_ft_font_t *font, unsigned long tag)
+{
+ TT_HoriHeader *hhea;
+
+ hhea = FT_Get_Sfnt_Table (font->face, ft_sfnt_hhea);
+
+ cairo_pdf_ft_font_write_be32 (font, hhea->Version);
+ cairo_pdf_ft_font_write_be16 (font, hhea->Ascender);
+ cairo_pdf_ft_font_write_be16 (font, hhea->Descender);
+ cairo_pdf_ft_font_write_be16 (font, hhea->Line_Gap);
+
+ cairo_pdf_ft_font_write_be16 (font, hhea->advance_Width_Max);
+
+ cairo_pdf_ft_font_write_be16 (font, hhea->min_Left_Side_Bearing);
+ cairo_pdf_ft_font_write_be16 (font, hhea->min_Right_Side_Bearing);
+ cairo_pdf_ft_font_write_be16 (font, hhea->xMax_Extent);
+ cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Rise);
+ cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Run);
+ cairo_pdf_ft_font_write_be16 (font, hhea->caret_Offset);
+
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+
+ cairo_pdf_ft_font_write_be16 (font, hhea->metric_Data_Format);
+ cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs);
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_hmtx_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ unsigned long entry_size;
+ short *p;
+ int i;
+
+ for (i = 0; i < font->base.num_glyphs; i++) {
+ entry_size = 2 * sizeof (short);
+ p = cairo_pdf_ft_font_write (font, NULL, entry_size);
+ FT_Load_Sfnt_Table (font->face, TTAG_hmtx,
+ font->glyphs[i].parent_index * entry_size,
+ (FT_Byte *) p, &entry_size);
+ font->base.widths[i] = be16_to_cpu (p[0]);
+ }
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_loca_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ int i;
+ TT_Header *header;
+
+ header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
+
+ if (header->Index_To_Loc_Format == 0) {
+ for (i = 0; i < font->base.num_glyphs + 1; i++)
+ cairo_pdf_ft_font_write_be16 (font, font->glyphs[i].location / 2);
+ }
+ else {
+ for (i = 0; i < font->base.num_glyphs + 1; i++)
+ cairo_pdf_ft_font_write_be32 (font, font->glyphs[i].location);
+ }
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_maxp_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ TT_MaxProfile *maxp;
+
+ maxp = FT_Get_Sfnt_Table (font->face, ft_sfnt_maxp);
+
+ cairo_pdf_ft_font_write_be32 (font, maxp->version);
+ cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxPoints);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxContours);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositePoints);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositeContours);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxZones);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxTwilightPoints);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxStorage);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxFunctionDefs);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxInstructionDefs);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxStackElements);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxSizeOfInstructions);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentElements);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentDepth);
+
+ return font->status;
+}
+
+typedef struct table table_t;
+struct table {
+ unsigned long tag;
+ int (*write) (cairo_pdf_ft_font_t *font, unsigned long tag);
+};
+
+static const table_t truetype_tables[] = {
+ { TTAG_cmap, cairo_pdf_ft_font_write_cmap_table },
+ { TTAG_cvt, cairo_pdf_ft_font_write_generic_table },
+ { TTAG_fpgm, cairo_pdf_ft_font_write_generic_table },
+ { TTAG_glyf, cairo_pdf_ft_font_write_glyf_table },
+ { TTAG_head, cairo_pdf_ft_font_write_head_table },
+ { TTAG_hhea, cairo_pdf_ft_font_write_hhea_table },
+ { TTAG_hmtx, cairo_pdf_ft_font_write_hmtx_table },
+ { TTAG_loca, cairo_pdf_ft_font_write_loca_table },
+ { TTAG_maxp, cairo_pdf_ft_font_write_maxp_table },
+ { TTAG_name, cairo_pdf_ft_font_write_generic_table },
+ { TTAG_prep, cairo_pdf_ft_font_write_generic_table },
+};
+
+static cairo_status_t
+cairo_pdf_ft_font_write_offset_table (cairo_pdf_ft_font_t *font)
+{
+ unsigned short search_range, entry_selector, range_shift;
+ int num_tables;
+
+ num_tables = ARRAY_LENGTH (truetype_tables);
+ search_range = 1;
+ entry_selector = 0;
+ while (search_range * 2 <= num_tables) {
+ search_range *= 2;
+ entry_selector++;
+ }
+ search_range *= 16;
+ range_shift = num_tables * 16 - search_range;
+
+ cairo_pdf_ft_font_write_be32 (font, SFNT_VERSION);
+ cairo_pdf_ft_font_write_be16 (font, num_tables);
+ cairo_pdf_ft_font_write_be16 (font, search_range);
+ cairo_pdf_ft_font_write_be16 (font, entry_selector);
+ cairo_pdf_ft_font_write_be16 (font, range_shift);
+
+ cairo_pdf_ft_font_write (font, NULL, ARRAY_LENGTH (truetype_tables) * 16);
+
+ return font->status;
+}
+
+static unsigned long
+cairo_pdf_ft_font_calculate_checksum (cairo_pdf_ft_font_t *font,
+ unsigned long start, unsigned long end)
+{
+ unsigned long *padded_end;
+ unsigned long *p;
+ unsigned long checksum;
+ char *data;
+
+ checksum = 0;
+ data = _cairo_array_index (&font->output, 0);
+ p = (unsigned long *) (data + start);
+ padded_end = (unsigned long *) (data + ((end + 3) & ~3));
+ while (p < padded_end)
+ checksum += *p++;
+
+ return checksum;
+}
+
+static void
+cairo_pdf_ft_font_update_entry (cairo_pdf_ft_font_t *font, int index, unsigned long tag,
+ unsigned long start, unsigned long end)
+{
+ unsigned long *entry;
+
+ entry = _cairo_array_index (&font->output, 12 + 16 * index);
+ entry[0] = cpu_to_be32 (tag);
+ entry[1] = cpu_to_be32 (cairo_pdf_ft_font_calculate_checksum (font, start, end));
+ entry[2] = cpu_to_be32 (start);
+ entry[3] = cpu_to_be32 (end - start);
+}
+
+static cairo_status_t
+cairo_pdf_ft_font_generate (void *abstract_font,
+ const char **data, unsigned long *length)
+{
+ cairo_pdf_ft_font_t *font = abstract_font;
+ unsigned long start, end, next, checksum;
+ int i;
+
+ if (cairo_pdf_ft_font_write_offset_table (font))
+ return font->status;
+
+ start = cairo_pdf_ft_font_align_output (font);
+ end = start;
+
+ for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) {
+ if (truetype_tables[i].write (font, truetype_tables[i].tag))
+ goto fail;
+
+ end = _cairo_array_num_elements (&font->output);
+ next = cairo_pdf_ft_font_align_output (font);
+ cairo_pdf_ft_font_update_entry (font, i, truetype_tables[i].tag,
+ start, end);
+ start = next;
+ }
+
+ checksum =
+ 0xb1b0afba - cairo_pdf_ft_font_calculate_checksum (font, 0, end);
+ *font->checksum_location = cpu_to_be32 (checksum);
+
+ *data = _cairo_array_index (&font->output, 0);
+ *length = _cairo_array_num_elements (&font->output);
+
+ fail:
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph)
+{
+ cairo_pdf_ft_font_t *font = abstract_font;
+
+ if (font->parent_to_subset[glyph] == 0) {
+ font->parent_to_subset[glyph] = font->base.num_glyphs;
+ font->glyphs[font->base.num_glyphs].parent_index = glyph;
+ font->base.num_glyphs++;
+ }
+
+ return font->parent_to_subset[glyph];
+}
+
+static cairo_pdf_font_backend_t cairo_pdf_ft_font_backend = {
+ cairo_pdf_ft_font_use_glyph,
+ cairo_pdf_ft_font_generate,
+ cairo_pdf_ft_font_destroy
+};
+
+/* PDF Generation */
+
+static unsigned int
+_cairo_pdf_document_new_object (cairo_pdf_document_t *document)
+{
+ cairo_pdf_object_t object;
+
+ object.offset = ftell (document->file);
+ if (_cairo_array_append (&document->objects, &object, 1) == NULL)
+ return 0;
+
+ return document->next_available_id++;
+}
+
+static void
+_cairo_pdf_document_update_object (cairo_pdf_document_t *document,
+ unsigned int id)
+{
+ cairo_pdf_object_t *object;
+
+ object = _cairo_array_index (&document->objects, id - 1);
+ object->offset = ftell (document->file);
+}
+
+static void
+_cairo_pdf_surface_add_stream (cairo_pdf_surface_t *surface,
+ cairo_pdf_stream_t *stream)
+{
+ _cairo_array_append (&surface->streams, &stream, 1);
+ surface->current_stream = stream;
+}
+
+static void
+_cairo_pdf_surface_add_pattern (cairo_pdf_surface_t *surface, unsigned int id)
+{
+ cairo_pdf_resource_t resource;
+
+ resource.id = id;
+ _cairo_array_append (&surface->patterns, &resource, 1);
+}
+
+static void
+_cairo_pdf_surface_add_xobject (cairo_pdf_surface_t *surface, unsigned int id)
+{
+ cairo_pdf_resource_t resource;
+ int i, num_resources;
+
+ num_resources = _cairo_array_num_elements (&surface->xobjects);
+ for (i = 0; i < num_resources; i++) {
+ _cairo_array_copy_element (&surface->xobjects, i, &resource);
+ if (resource.id == id)
+ return;
+ }
+
+ resource.id = id;
+ _cairo_array_append (&surface->xobjects, &resource, 1);
+}
+
+static unsigned int
+_cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface, double alpha)
+{
+ int num_alphas, i;
+ double other;
+
+ num_alphas = _cairo_array_num_elements (&surface->alphas);
+ for (i = 0; i < num_alphas; i++) {
+ _cairo_array_copy_element (&surface->alphas, i, &other);
+ if (alpha == other)
+ return i;
+ }
+
+ _cairo_array_append (&surface->alphas, &alpha, 1);
+ return _cairo_array_num_elements (&surface->alphas) - 1;
+}
+
+static void
+_cairo_pdf_surface_add_font (cairo_pdf_surface_t *surface, unsigned int id)
+{
+ cairo_pdf_resource_t resource;
+ int i, num_fonts;
+
+ num_fonts = _cairo_array_num_elements (&surface->fonts);
+ for (i = 0; i < num_fonts; i++) {
+ _cairo_array_copy_element (&surface->fonts, i, &resource);
+ if (resource.id == id)
+ return;
+ }
+
+ resource.id = id;
+ _cairo_array_append (&surface->fonts, &resource, 1);
+}
+
+cairo_surface_t *
+cairo_pdf_surface_create (FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch)
+{
+ cairo_pdf_document_t *document;
+ cairo_surface_t *surface;
+
+ document = _cairo_pdf_document_create (file,
+ width_inches,
+ height_inches,
+ x_pixels_per_inch,
+ y_pixels_per_inch);
+ if (document == NULL)
+ return NULL;
+
+ surface = _cairo_pdf_surface_create_for_document (document,
+ width_inches,
+ height_inches);
+
+ _cairo_pdf_document_destroy (document);
+
+ return surface;
+}
+
+static cairo_surface_t *
+_cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
+ double width_inches,
+ double height_inches)
+{
+ cairo_pdf_surface_t *surface;
+
+ surface = malloc (sizeof (cairo_pdf_surface_t));
+ if (surface == NULL)
+ return NULL;
+
+ _cairo_surface_init (&surface->base, &cairo_pdf_surface_backend);
+
+ surface->width_inches = width_inches;
+ surface->height_inches = height_inches;
+
+ surface->pattern = NULL;
+ _cairo_pdf_document_reference (document);
+ surface->document = document;
+ _cairo_array_init (&surface->streams, sizeof (cairo_pdf_stream_t *));
+ _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_resource_t));
+ _cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t));
+ _cairo_array_init (&surface->alphas, sizeof (double));
+ _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t));
+
+ return &surface->base;
+}
+
+static void
+_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
+{
+ int num_streams, i;
+ cairo_pdf_stream_t *stream;
+
+ num_streams = _cairo_array_num_elements (&surface->streams);
+ for (i = 0; i < num_streams; i++) {
+ _cairo_array_copy_element (&surface->streams, i, &stream);
+ free (stream);
+ }
+
+ _cairo_array_truncate (&surface->streams, 0);
+ _cairo_array_truncate (&surface->patterns, 0);
+ _cairo_array_truncate (&surface->xobjects, 0);
+ _cairo_array_truncate (&surface->alphas, 0);
+ _cairo_array_truncate (&surface->fonts, 0);
+}
+
+static cairo_surface_t *
+_cairo_pdf_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ cairo_pdf_surface_t *template = abstract_src;
+
+ return _cairo_pdf_surface_create_for_document (template->document,
+ width, height);
+}
+
+static cairo_pdf_stream_t *
+_cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
+ const char *extra_entries)
+{
+ FILE *file = document->file;
+ cairo_pdf_stream_t *stream;
+
+ stream = malloc (sizeof (cairo_pdf_stream_t));
+ if (stream == NULL) {
+ return NULL;
+ }
+
+ stream->id = _cairo_pdf_document_new_object (document);
+ stream->length_id = _cairo_pdf_document_new_object (document);
+
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Length %d 0 R\r\n"
+ "%s"
+ ">>\r\n"
+ "stream\r\n",
+ stream->id,
+ stream->length_id,
+ extra_entries);
+
+ stream->start_offset = ftell (file);
+
+ document->current_stream = stream;
+
+ return stream;
+}
+
+static void
+_cairo_pdf_document_close_stream (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ long length;
+ cairo_pdf_stream_t *stream;
+
+ stream = document->current_stream;
+ if (stream == NULL)
+ return;
+
+ length = ftell(file) - stream->start_offset;
+ fprintf (file,
+ "\r\n"
+ "endstream\r\n"
+ "endobj\r\n");
+
+ _cairo_pdf_document_update_object (document, stream->length_id);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ " %ld\r\n"
+ "endobj\r\n",
+ stream->length_id,
+ length);
+
+ document->current_stream = NULL;
+}
+
+static void
+_cairo_pdf_surface_destroy (void *abstract_surface)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_document_t *document = surface->document;
+
+ if (surface->current_stream == document->current_stream)
+ _cairo_pdf_document_close_stream (document);
+
+ _cairo_pdf_document_destroy (document);
+
+ free (surface);
+}
+
+/* XXX: We should re-work this interface to return both X/Y ppi values. */
+static double
+_cairo_pdf_surface_pixels_per_inch (void *abstract_surface)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ return surface->document->y_ppi;
+}
+
+static void
+_cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface)
+{
+ cairo_pdf_document_t *document = surface->document;
+ cairo_pdf_stream_t *stream;
+ FILE *file = document->file;
+ char extra[200];
+
+ if (document->current_stream == NULL ||
+ document->current_stream != surface->current_stream) {
+ _cairo_pdf_document_close_stream (document);
+ snprintf (extra, sizeof extra,
+ " /Type /XObject\r\n"
+ " /Subtype /Form\r\n"
+ " /BBox [ 0 0 %f %f ]\r\n",
+ surface->width_inches * document->x_ppi,
+ surface->height_inches * document->y_ppi);
+ stream = _cairo_pdf_document_open_stream (document, extra);
+ _cairo_pdf_surface_add_stream (surface, stream);
+
+ /* If this is the first stream we open for this surface,
+ * output the cairo to PDF transformation matrix. */
+ if (_cairo_array_num_elements (&surface->streams) == 1)
+ fprintf (file, "1 0 0 -1 0 %f cm\r\n",
+ document->height_inches * document->y_ppi);
+ }
+}
+
+static cairo_image_surface_t *
+_cairo_pdf_surface_get_image (void *abstract_surface)
+{
+ return NULL;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_image (void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_matrix (void *abstract_surface,
+ cairo_matrix_t *matrix)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_filter (void *abstract_surface,
+ cairo_filter_t filter)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_set_repeat (void *abstract_surface,
+ int repeat)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void *
+compress_dup (const void *data, unsigned long data_size,
+ unsigned long *compressed_size)
+{
+ void *compressed;
+
+ /* Bound calculation taken from zlib. */
+ *compressed_size = data_size + (data_size >> 12) + (data_size >> 14) + 11;
+ compressed = malloc (*compressed_size);
+ if (compressed == NULL)
+ return NULL;
+
+ compress (compressed, compressed_size, data, data_size);
+
+ return compressed;
+}
+
+static unsigned int
+emit_image_data (cairo_pdf_document_t *document,
+ cairo_image_surface_t *image)
+{
+ FILE *file = document->file;
+ cairo_pdf_stream_t *stream;
+ char entries[200];
+ char *rgb, *compressed;
+ int i, x, y;
+ unsigned long rgb_size, compressed_size;
+ pixman_bits_t *pixel;
+
+ rgb_size = image->height * image->width * 3;
+ rgb = malloc (rgb_size);
+ if (rgb == NULL)
+ return 0;
+
+ i = 0;
+ for (y = 0; y < image->height; y++) {
+ pixel = (pixman_bits_t *) (image->data + y * image->stride);
+
+ for (x = 0; x < image->width; x++, pixel++) {
+ rgb[i++] = (*pixel & 0x00ff0000) >> 16;
+ rgb[i++] = (*pixel & 0x0000ff00) >> 8;
+ rgb[i++] = (*pixel & 0x000000ff) >> 0;
+ }
+ }
+
+ compressed = compress_dup (rgb, rgb_size, &compressed_size);
+ if (compressed == NULL) {
+ free (rgb);
+ return 0;
+ }
+
+ _cairo_pdf_document_close_stream (document);
+
+ snprintf (entries, sizeof entries,
+ " /Type /XObject\r\n"
+ " /Subtype /Image\r\n"
+ " /Width %d\r\n"
+ " /Height %d\r\n"
+ " /ColorSpace /DeviceRGB\r\n"
+ " /BitsPerComponent 8\r\n"
+ " /Filter /FlateDecode\r\n",
+ image->width, image->height);
+
+ stream = _cairo_pdf_document_open_stream (document, entries);
+ fwrite (compressed, 1, compressed_size, file);
+ _cairo_pdf_document_close_stream (document);
+
+ free (rgb);
+ free (compressed);
+
+ return stream->id;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
+ cairo_image_surface_t *image)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ unsigned id;
+ cairo_matrix_t i2u;
+
+ id = emit_image_data (dst->document, image);
+ if (id == 0)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_pdf_surface_add_xobject (dst, id);
+
+ _cairo_pdf_surface_ensure_stream (dst);
+
+ cairo_matrix_copy (&i2u, &image->base.matrix);
+ cairo_matrix_invert (&i2u);
+ cairo_matrix_translate (&i2u, 0, image->height);
+ cairo_matrix_scale (&i2u, image->width, -image->height);
+
+ fprintf (file,
+ "q %f %f %f %f %f %f cm /res%d Do Q\r\n",
+ i2u.m[0][0], i2u.m[0][1],
+ i2u.m[1][0], i2u.m[1][1],
+ i2u.m[2][0], i2u.m[2][1],
+ id);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* The contents of the surface is already transformed into PDF units,
+ * but when we composite the surface we may want to use a different
+ * space. The problem I see now is that the show_surface snippet
+ * creates a surface 1x1, which in the snippet environment is the
+ * entire surface. When compositing the surface, cairo gives us the
+ * 1x1 to 256x256 matrix. This would be fine if cairo didn't actually
+ * also transform the drawing to the surface. Should the CTM be part
+ * of the current target surface?
+ */
+
+static cairo_int_status_t
+_cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
+ cairo_pdf_surface_t *src,
+ int width, int height)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ cairo_matrix_t i2u;
+ cairo_pdf_stream_t *stream;
+ int num_streams, i;
+
+ if (src->pattern != NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_pdf_surface_ensure_stream (dst);
+
+ cairo_matrix_copy (&i2u, &src->base.matrix);
+ cairo_matrix_invert (&i2u);
+ cairo_matrix_scale (&i2u,
+ 1.0 / (src->width_inches * document->x_ppi),
+ 1.0 / (src->height_inches * document->y_ppi));
+
+ fprintf (file,
+ "q %f %f %f %f %f %f cm",
+ i2u.m[0][0], i2u.m[0][1],
+ i2u.m[1][0], i2u.m[1][1],
+ i2u.m[2][0], i2u.m[2][1]);
+
+ num_streams = _cairo_array_num_elements (&src->streams);
+ for (i = 0; i < num_streams; i++) {
+ _cairo_array_copy_element (&src->streams, i, &stream);
+ fprintf (file,
+ " /res%d Do",
+ stream->id);
+
+ _cairo_pdf_surface_add_xobject (dst, stream->id);
+
+ }
+
+ fprintf (file, " Q\r\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_composite (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ cairo_surface_t *generic_mask,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ cairo_pdf_surface_t *dst = abstract_dst;
+ cairo_pdf_surface_t *src;
+ cairo_image_surface_t *image;
+
+ if (generic_src->backend == &cairo_pdf_surface_backend) {
+ src = (cairo_pdf_surface_t *) generic_src;
+ return _cairo_pdf_surface_composite_pdf (dst, src, width, height);
+ }
+ else {
+ image = _cairo_surface_get_image (generic_src);
+ return _cairo_pdf_surface_composite_image (dst, image);
+ }
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_fill_rectangles (void *abstract_surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ int i;
+
+ if (surface->pattern != NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_pdf_surface_ensure_stream (surface);
+
+ fprintf (file,
+ "%f %f %f rg\r\n",
+ color->red, color->green, color->blue);
+
+ for (i = 0; i < num_rects; i++) {
+ fprintf (file,
+ "%d %d %d %d re f\r\n",
+ rects[i].x, rects[i].y,
+ rects[i].width, rects[i].height);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+emit_tiling_pattern (cairo_operator_t operator,
+ cairo_pdf_surface_t *dst,
+ cairo_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = dst->document;
+ FILE *file = document->file;
+ cairo_pdf_stream_t *stream;
+ cairo_image_surface_t *image;
+ char entries[250];
+ unsigned int id, alpha;
+ cairo_matrix_t pm;
+
+ if (pattern->u.surface.surface->backend == &cairo_pdf_surface_backend) {
+ return;
+ }
+
+ image = _cairo_surface_get_image (pattern->u.surface.surface);
+
+ _cairo_pdf_document_close_stream (document);
+
+ id = emit_image_data (dst->document, image);
+
+ /* BBox must be smaller than XStep by YStep or acroread wont
+ * display the pattern. */
+
+ cairo_matrix_set_identity (&pm);
+ cairo_matrix_scale (&pm, image->width, image->height);
+ cairo_matrix_copy (&pm, &pattern->matrix);
+ cairo_matrix_invert (&pm);
+
+ snprintf (entries, sizeof entries,
+ " /BBox [ 0 0 256 256 ]\r\n"
+ " /XStep 256\r\n"
+ " /YStep 256\r\n"
+ " /PatternType 1\r\n"
+ " /TilingType 1\r\n"
+ " /PaintType 1\r\n"
+ " /Resources << /XObject << /res%d %d 0 R >> >>\r\n"
+ " /Matrix [ %f %f %f %f %f %f ]\r\n",
+ id, id,
+ pm.m[0][0], pm.m[0][1],
+ pm.m[1][0], pm.m[1][1],
+ pm.m[2][0], pm.m[2][1]);
+
+ stream = _cairo_pdf_document_open_stream (document, entries);
+
+ _cairo_pdf_surface_add_pattern (dst, stream->id);
+
+ _cairo_pdf_surface_ensure_stream (dst);
+ alpha = _cairo_pdf_surface_add_alpha (dst, 1.0);
+ fprintf (file,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ stream->id, alpha);
+}
+
+static unsigned int
+emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ unsigned int function_id;
+
+ function_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /FunctionType 0\r\n"
+ " /Domain [ 0.0 1.0 ]\r\n"
+ " /Size [ 2 ]\r\n"
+ " /BitsPerSample 8\r\n"
+ " /Range [ 0.0 1.0 0.0 1.0 0.0 1.0 ]\r\n"
+ " /Length 6\r\n"
+ ">>\r\n"
+ "stream\r\n",
+ function_id);
+
+ fputc (pattern->stops[0].color_char[0], file);
+ fputc (pattern->stops[0].color_char[1], file);
+ fputc (pattern->stops[0].color_char[2], file);
+ fputc (pattern->stops[1].color_char[0], file);
+ fputc (pattern->stops[1].color_char[1], file);
+ fputc (pattern->stops[1].color_char[2], file);
+
+ fprintf (file,
+ "\r\n"
+ "endstream\r\n"
+ "endobj\r\n");
+
+ return function_id;
+}
+
+static void
+emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ unsigned int function_id, pattern_id, alpha;
+ double x0, y0, x1, y1;
+ cairo_matrix_t p2u;
+
+ _cairo_pdf_document_close_stream (document);
+
+ function_id = emit_pattern_stops (surface, pattern);
+
+ cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_invert (&p2u);
+
+ x0 = pattern->u.linear.point0.x;
+ y0 = pattern->u.linear.point0.y;
+ cairo_matrix_transform_point (&p2u, &x0, &y0);
+ x1 = pattern->u.linear.point1.x;
+ y1 = pattern->u.linear.point1.y;
+ cairo_matrix_transform_point (&p2u, &x1, &y1);
+
+ pattern_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Pattern\r\n"
+ " /PatternType 2\r\n"
+ " /Matrix [ 1 0 0 -1 0 %f ]\r\n"
+ " /Shading\r\n"
+ " << /ShadingType 2\r\n"
+ " /ColorSpace /DeviceRGB\r\n"
+ " /Coords [ %f %f %f %f ]\r\n"
+ " /Function %d 0 R\r\n"
+ " /Extend [ %s %s ]\r\n"
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ pattern_id,
+ document->height_inches * document->y_ppi,
+ x0, y0, x1, y1,
+ function_id,
+ (1 || pattern->extend) ? "true" : "false",
+ (1 || pattern->extend) ? "true" : "false");
+
+ _cairo_pdf_surface_add_pattern (surface, pattern_id);
+
+ _cairo_pdf_surface_ensure_stream (surface);
+ alpha = _cairo_pdf_surface_add_alpha (surface, 1.0);
+
+ /* Use pattern */
+ fprintf (file,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ pattern_id, alpha);
+}
+
+static void
+emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
+{
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ unsigned int function_id, pattern_id, alpha;
+ double x0, y0, x1, y1, r0, r1;
+ cairo_matrix_t p2u;
+
+ _cairo_pdf_document_close_stream (document);
+
+ function_id = emit_pattern_stops (surface, pattern);
+
+ cairo_matrix_copy (&p2u, &pattern->matrix);
+ cairo_matrix_invert (&p2u);
+
+ x0 = pattern->u.radial.center0.x;
+ y0 = pattern->u.radial.center0.y;
+ r0 = pattern->u.radial.radius0;
+ cairo_matrix_transform_point (&p2u, &x0, &y0);
+ x1 = pattern->u.radial.center1.x;
+ y1 = pattern->u.radial.center1.y;
+ r1 = pattern->u.radial.radius1;
+ cairo_matrix_transform_point (&p2u, &x1, &y1);
+
+ /* FIXME: This is surely crack, but how should you scale a radius
+ * in a non-orthogonal coordinate system? */
+ cairo_matrix_transform_distance (&p2u, &r0, &r1);
+
+ pattern_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Pattern\r\n"
+ " /PatternType 2\r\n"
+ " /Matrix [ 1 0 0 -1 0 %f ]\r\n"
+ " /Shading\r\n"
+ " << /ShadingType 3\r\n"
+ " /ColorSpace /DeviceRGB\r\n"
+ " /Coords [ %f %f %f %f %f %f ]\r\n"
+ " /Function %d 0 R\r\n"
+ " /Extend [ %s %s ]\r\n"
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ pattern_id,
+ document->height_inches * document->y_ppi,
+ x0, y0, r0, x1, y1, r1,
+ function_id,
+ (1 || pattern->extend) ? "true" : "false",
+ (1 || pattern->extend) ? "true" : "false");
+
+ _cairo_pdf_surface_add_pattern (surface, pattern_id);
+
+ _cairo_pdf_surface_ensure_stream (surface);
+ alpha = _cairo_pdf_surface_add_alpha (surface, 1.0);
+
+ /* Use pattern */
+ fprintf (file,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ pattern_id, alpha);
+}
+
+static double
+intersect (cairo_line_t *line, cairo_fixed_t y)
+{
+ return _cairo_fixed_to_double (line->p1.x) +
+ _cairo_fixed_to_double (line->p2.x - line->p1.x) *
+ _cairo_fixed_to_double (y - line->p1.y) /
+ _cairo_fixed_to_double (line->p2.y - line->p1.y);
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ void *abstract_dst,
+ int x_src,
+ int y_src,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ cairo_pdf_surface_t *surface = abstract_dst;
+ cairo_pdf_surface_t *source = (cairo_pdf_surface_t *) generic_src;
+ cairo_pdf_document_t *document = surface->document;
+ cairo_pattern_t *pattern;
+ FILE *file = document->file;
+ int i;
+ unsigned int alpha;
+
+ /* FIXME: we really just want the original pattern here, not a
+ * source surface. */
+ pattern = source->pattern;
+
+ if (source->base.backend != &cairo_pdf_surface_backend) {
+ printf ("_cairo_pdf_surface_composite_trapezoids: not a pdf source\r");
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (pattern == NULL) {
+ printf ("_cairo_pdf_surface_composite_trapezoids: "
+ "non-pattern pdf source\r");
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SOLID:
+ alpha = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha);
+ _cairo_pdf_surface_ensure_stream (surface);
+ fprintf (file,
+ "%f %f %f rg /a%d gs\r\n",
+ pattern->color.red,
+ pattern->color.green,
+ pattern->color.blue,
+ alpha);
+ break;
+
+ case CAIRO_PATTERN_SURFACE:
+ emit_tiling_pattern (operator, surface, pattern);
+ break;
+
+ case CAIRO_PATTERN_LINEAR:
+ emit_linear_pattern (surface, pattern);
+ break;
+
+ case CAIRO_PATTERN_RADIAL:
+ emit_radial_pattern (surface, pattern );
+ break;
+ }
+
+ /* After the above switch the current stream should belong to this
+ * surface, so no need to _cairo_pdf_surface_ensure_stream() */
+ assert (document->current_stream != NULL &&
+ document->current_stream == surface->current_stream);
+
+ for (i = 0; i < num_traps; i++) {
+ double left_x1, left_x2, right_x1, right_x2;
+
+ left_x1 = intersect (&traps[i].left, traps[i].top);
+ left_x2 = intersect (&traps[i].left, traps[i].bottom);
+ right_x1 = intersect (&traps[i].right, traps[i].top);
+ right_x2 = intersect (&traps[i].right, traps[i].bottom);
+
+ fprintf (file,
+ "%f %f m %f %f l %f %f l %f %f l h\r\n",
+ left_x1, _cairo_fixed_to_double (traps[i].top),
+ left_x2, _cairo_fixed_to_double (traps[i].bottom),
+ right_x2, _cairo_fixed_to_double (traps[i].bottom),
+ right_x1, _cairo_fixed_to_double (traps[i].top));
+ }
+
+ fprintf (file,
+ "f\r\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_copy_page (void *abstract_surface)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_document_t *document = surface->document;
+
+ return _cairo_pdf_document_add_page (document, surface);
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_show_page (void *abstract_surface)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_document_t *document = surface->document;
+ cairo_int_status_t status;
+
+ status = _cairo_pdf_document_add_page (document, surface);
+ if (status == CAIRO_STATUS_SUCCESS)
+ _cairo_pdf_surface_clear (surface);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_create_pattern (void *abstract_surface,
+ cairo_pattern_t *pattern,
+ cairo_box_t *extents)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_surface_t *source;
+
+ source = (cairo_pdf_surface_t *)
+ _cairo_pdf_surface_create_for_document (surface->document, 0, 0);
+ source->pattern = pattern;
+ pattern->source = &source->base;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_pdf_font_t *
+_cairo_pdf_document_get_font (cairo_pdf_document_t *document,
+ cairo_unscaled_font_t *unscaled_font,
+ cairo_font_scale_t *scale)
+{
+ cairo_pdf_font_t *font;
+ unsigned int num_fonts, i;
+
+ num_fonts = _cairo_array_num_elements (&document->fonts);
+ for (i = 0; i < num_fonts; i++) {
+ _cairo_array_copy_element (&document->fonts, i, &font);
+ if (font->unscaled_font == unscaled_font)
+ return font;
+ }
+
+ /* FIXME: Figure out here which font backend is in use and call
+ * the appropriate constructor. */
+ font = cairo_pdf_ft_font_create (document, unscaled_font, scale);
+ if (font == NULL)
+ return NULL;
+
+ if (_cairo_array_append (&document->fonts, &font, 1) == NULL) {
+ cairo_pdf_font_destroy (font);
+ return NULL;
+ }
+
+ return font;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font,
+ cairo_font_scale_t *scale,
+ cairo_operator_t operator,
+ cairo_surface_t *source,
+ void *abstract_surface,
+ int source_x,
+ int source_y,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_document_t *document = surface->document;
+ FILE *file = document->file;
+ cairo_pdf_font_t *pdf_font;
+ int i, index;
+
+ pdf_font = _cairo_pdf_document_get_font (document, font, scale);
+ if (pdf_font == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_pdf_surface_ensure_stream (surface);
+
+ fprintf (file, "0 0 0 rg BT /res%u 1 Tf", pdf_font->font_id);
+ for (i = 0; i < num_glyphs; i++) {
+
+ index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index);
+
+ fprintf (file,
+ " %f %f %f %f %f %f Tm (%c) Tj",
+ scale->matrix[0][0],
+ scale->matrix[0][1],
+ scale->matrix[1][0],
+ -scale->matrix[1][1],
+ glyphs[i].x,
+ glyphs[i].y,
+ index);
+ }
+ fprintf (file, " ET\r\n");
+
+ _cairo_pdf_surface_add_font (surface, pdf_font->font_id);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_pdf_surface_backend = {
+ _cairo_pdf_surface_create_similar,
+ _cairo_pdf_surface_destroy,
+ _cairo_pdf_surface_pixels_per_inch,
+ _cairo_pdf_surface_get_image,
+ _cairo_pdf_surface_set_image,
+ _cairo_pdf_surface_set_matrix,
+ _cairo_pdf_surface_set_filter,
+ _cairo_pdf_surface_set_repeat,
+ _cairo_pdf_surface_composite,
+ _cairo_pdf_surface_fill_rectangles,
+ _cairo_pdf_surface_composite_trapezoids,
+ _cairo_pdf_surface_copy_page,
+ _cairo_pdf_surface_show_page,
+ _cairo_pdf_surface_set_clip_region,
+ _cairo_pdf_surface_create_pattern,
+ _cairo_pdf_surface_show_glyphs
+};
+
+static cairo_pdf_document_t *
+_cairo_pdf_document_create (FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch)
+{
+ cairo_pdf_document_t *document;
+
+ document = malloc (sizeof (cairo_pdf_document_t));
+ if (document == NULL)
+ return NULL;
+
+ document->file = file;
+ document->refcount = 1;
+ document->width_inches = width_inches;
+ document->height_inches = height_inches;
+ document->x_ppi = x_pixels_per_inch;
+ document->y_ppi = y_pixels_per_inch;
+
+ _cairo_array_init (&document->objects, sizeof (cairo_pdf_object_t));
+ _cairo_array_init (&document->pages, sizeof (unsigned int));
+ document->next_available_id = 1;
+
+ document->current_stream = NULL;
+
+ document->pages_id = _cairo_pdf_document_new_object (document);
+
+ _cairo_array_init (&document->fonts, sizeof (cairo_pdf_font_t *));
+
+ /* Document header */
+ fprintf (file, "%%PDF-1.4\r\n");
+
+ return document;
+}
+
+static unsigned int
+_cairo_pdf_document_write_info (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ unsigned int id;
+
+ id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Creator (cairographics.org)\r\n"
+ " /Producer (cairographics.org)\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ id);
+
+ return id;
+}
+
+static void
+_cairo_pdf_document_write_pages (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ unsigned int page_id;
+ int num_pages, i;
+
+ _cairo_pdf_document_update_object (document, document->pages_id);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Pages\r\n"
+ " /Kids [ ",
+ document->pages_id);
+
+ num_pages = _cairo_array_num_elements (&document->pages);
+ for (i = 0; i < num_pages; i++) {
+ _cairo_array_copy_element (&document->pages, i, &page_id);
+ fprintf (file, "%d 0 R ", page_id);
+ }
+
+ fprintf (file, "]\r\n");
+ fprintf (file, " /Count %d\r\n", num_pages);
+
+ /* TODO: Figure out wich other defaults to be inherited by /Page
+ * objects. */
+ fprintf (file,
+ " /MediaBox [ 0 0 %f %f ]\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ document->width_inches * document->x_ppi,
+ document->height_inches * document->y_ppi);
+}
+
+static cairo_status_t
+_cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ cairo_pdf_font_t *font;
+ int num_fonts, i, j;
+ const char *data;
+ char *compressed;
+ unsigned long data_size, compressed_size;
+ unsigned int stream_id, descriptor_id;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ num_fonts = _cairo_array_num_elements (&document->fonts);
+ for (i = 0; i < num_fonts; i++) {
+ _cairo_array_copy_element (&document->fonts, i, &font);
+
+ status = cairo_pdf_font_generate (font, &data, &data_size);
+ if (status)
+ goto fail;
+
+ compressed = compress_dup (data, data_size, &compressed_size);
+ if (compressed == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ stream_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Filter /FlateDecode\r\n"
+ " /Length %lu\r\n"
+ " /Length1 %lu\r\n"
+ ">>\r\n"
+ "stream\r\n",
+ stream_id,
+ compressed_size,
+ data_size);
+ fwrite (compressed, 1, compressed_size, file);
+ fprintf (file,
+ "\r\n"
+ "endstream\r\n"
+ "endobj\r\n");
+ free (compressed);
+
+ descriptor_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /FontDescriptor\r\n"
+ " /FontName /%s\r\n"
+ " /Flags 32\r\n"
+ " /FontBBox [ %ld %ld %ld %ld ]\r\n"
+ " /ItalicAngle 0\r\n"
+ " /Ascent %ld\r\n"
+ " /Descent %ld\r\n"
+ " /CapHeight 500\r\n"
+ " /StemV 80\r\n"
+ " /StemH 80\r\n"
+ " /FontFile2 %u 0 R\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ descriptor_id,
+ font->base_font,
+ font->x_min,
+ font->y_min,
+ font->x_max,
+ font->y_max,
+ font->ascent,
+ font->descent,
+ stream_id);
+
+ _cairo_pdf_document_update_object (document, font->font_id);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Font\r\n"
+ " /Subtype /TrueType\r\n"
+ " /BaseFont /%s\r\n"
+ " /FirstChar 0\r\n"
+ " /LastChar %d\r\n"
+ " /FontDescriptor %d 0 R\r\n"
+ " /Widths ",
+ font->font_id,
+ font->base_font,
+ font->num_glyphs,
+ descriptor_id);
+
+ fprintf (file,
+ "[");
+
+ for (j = 0; j < font->num_glyphs; j++)
+ fprintf (file,
+ " %d",
+ font->widths[j]);
+
+ fprintf (file,
+ " ]\r\n"
+ ">>\r\n"
+ "endobj\r\n");
+
+ fail:
+ cairo_pdf_ft_font_destroy (font);
+ }
+
+ return status;
+}
+
+static unsigned int
+_cairo_pdf_document_write_catalog (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ unsigned int id;
+
+ id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Catalog\r\n"
+ " /Pages %d 0 R\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ id, document->pages_id);
+
+ return id;
+}
+
+static long
+_cairo_pdf_document_write_xref (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ cairo_pdf_object_t *object;
+ int num_objects, i;
+ long offset;
+
+ num_objects = _cairo_array_num_elements (&document->objects);
+
+ offset = ftell(file);
+ fprintf (document->file,
+ "xref\r\n"
+ "%d %d\r\n",
+ 0, num_objects + 1);
+
+ fprintf (file, "0000000000 65535 f\r\n");
+ for (i = 0; i < num_objects; i++) {
+ object = _cairo_array_index (&document->objects, i);
+ fprintf (file, "%010ld 00000 n\r\n", object->offset);
+ }
+
+ return offset;
+}
+
+static void
+_cairo_pdf_document_reference (cairo_pdf_document_t *document)
+{
+ document->refcount++;
+}
+
+static void
+_cairo_pdf_document_destroy (cairo_pdf_document_t *document)
+{
+ FILE *file = document->file;
+ long offset;
+ unsigned int info_id, catalog_id;
+
+ document->refcount--;
+ if (document->refcount > 0)
+ return;
+
+ _cairo_pdf_document_close_stream (document);
+ _cairo_pdf_document_write_pages (document);
+ _cairo_pdf_document_write_fonts (document);
+ info_id = _cairo_pdf_document_write_info (document);
+ catalog_id = _cairo_pdf_document_write_catalog (document);
+ offset = _cairo_pdf_document_write_xref (document);
+
+ fprintf (file,
+ "trailer\r\n"
+ "<< /Size %d\r\n"
+ " /Root %d 0 R\r\n"
+ " /Info %d 0 R\r\n"
+ ">>\r\n",
+ document->next_available_id,
+ catalog_id,
+ info_id);
+
+ fprintf (file,
+ "startxref\r\n"
+ "%ld\r\n"
+ "%%%%EOF\r\n",
+ offset);
+
+ free (document);
+}
+
+static cairo_status_t
+_cairo_pdf_document_add_page (cairo_pdf_document_t *document,
+ cairo_pdf_surface_t *surface)
+{
+ cairo_pdf_stream_t *stream;
+ cairo_pdf_resource_t *res;
+ FILE *file = document->file;
+ unsigned int page_id;
+ double alpha;
+ int num_streams, num_alphas, num_resources, i;
+
+ _cairo_pdf_document_close_stream (document);
+
+ page_id = _cairo_pdf_document_new_object (document);
+ fprintf (file,
+ "%d 0 obj\r\n"
+ "<< /Type /Page\r\n"
+ " /Parent %d 0 R\r\n"
+ " /Contents [",
+ page_id,
+ document->pages_id);
+
+ num_streams = _cairo_array_num_elements (&surface->streams);
+ for (i = 0; i < num_streams; i++) {
+ _cairo_array_copy_element (&surface->streams, i, &stream);
+ fprintf (file,
+ " %d 0 R",
+ stream->id);
+ }
+
+ fprintf (file,
+ " ]\r\n"
+ " /Resources <<\r\n");
+
+ num_resources = _cairo_array_num_elements (&surface->fonts);
+ if (num_resources > 0) {
+ fprintf (file,
+ " /Font <<");
+
+ for (i = 0; i < num_resources; i++) {
+ res = _cairo_array_index (&surface->fonts, i);
+ fprintf (file,
+ " /res%d %d 0 R",
+ res->id, res->id);
+ }
+
+ fprintf (file,
+ " >>\r\n");
+ }
+
+ num_alphas = _cairo_array_num_elements (&surface->alphas);
+ if (num_alphas > 0) {
+ fprintf (file,
+ " /ExtGState <<\r\n");
+
+ for (i = 0; i < num_alphas; i++) {
+ _cairo_array_copy_element (&surface->alphas, i, &alpha);
+ fprintf (file,
+ " /a%d << /ca %f >>\r\n",
+ i, alpha);
+ }
+
+ fprintf (file,
+ " >>\r\n");
+ }
+
+ num_resources = _cairo_array_num_elements (&surface->patterns);
+ if (num_resources > 0) {
+ fprintf (file,
+ " /Pattern <<");
+ for (i = 0; i < num_resources; i++) {
+ res = _cairo_array_index (&surface->patterns, i);
+ fprintf (file,
+ " /res%d %d 0 R",
+ res->id, res->id);
+ }
+
+ fprintf (file,
+ " >>\r\n");
+ }
+
+ num_resources = _cairo_array_num_elements (&surface->xobjects);
+ if (num_resources > 0) {
+ fprintf (file,
+ " /XObject <<");
+
+ for (i = 0; i < num_resources; i++) {
+ res = _cairo_array_index (&surface->xobjects, i);
+ fprintf (file,
+ " /res%d %d 0 R",
+ res->id, res->id);
+ }
+
+ fprintf (file,
+ " >>\r\n");
+ }
+
+ fprintf (file,
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n");
+
+ _cairo_array_append (&document->pages, &page_id, 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+cairo_set_target_pdf (cairo_t *cr,
+ FILE *file,
+ double width_inches,
+ double height_inches,
+ double x_pixels_per_inch,
+ double y_pixels_per_inch)
+{
+ cairo_surface_t *surface;
+
+ surface = cairo_pdf_surface_create (file,
+ width_inches,
+ height_inches,
+ x_pixels_per_inch,
+ y_pixels_per_inch);
+
+ if (surface == NULL) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_set_target_surface (cr, surface);
+
+ /* cairo_set_target_surface takes a reference, so we must destroy ours */
+ cairo_surface_destroy (surface);
+}
diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c
index 4c689d599..2279b07a9 100644
--- a/src/cairo_png_surface.c
+++ b/src/cairo_png_surface.c
@@ -38,6 +38,7 @@
#include <png.h>
#include "cairoint.h"
+#include "cairo-png.h"
static const cairo_surface_backend_t cairo_png_surface_backend;
diff --git a/src/cairo_polygon.c b/src/cairo_polygon.c
index 8fa32f9f6..e85858033 100644
--- a/src/cairo_polygon.c
+++ b/src/cairo_polygon.c
@@ -37,8 +37,6 @@
#include <stdlib.h>
#include "cairoint.h"
-#define CAIRO_POLYGON_GROWTH_INC 10
-
/* private functions */
static cairo_status_t
@@ -104,7 +102,8 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_poin
}
if (polygon->num_edges >= polygon->edges_size) {
- status = _cairo_polygon_grow_by (polygon, CAIRO_POLYGON_GROWTH_INC);
+ int additional = polygon->edges_size ? polygon->edges_size : 16;
+ status = _cairo_polygon_grow_by (polygon, additional);
if (status) {
return status;
}
diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c
index bfdfada38..4da8162c7 100644
--- a/src/cairo_ps_surface.c
+++ b/src/cairo_ps_surface.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-ps.h"
#include <time.h>
#include <zlib.h>
@@ -130,8 +131,6 @@ cairo_ps_surface_create (FILE *file,
"%%%%CreationDate: %s",
ctime (&now));
fprintf (file,
- "%%%%Copyright: 2003 Carl Worth and Keith Packard\n");
- fprintf (file,
"%%%%BoundingBox: %d %d %d %d\n",
0, 0, (int) (surface->width_inches * 72.0), (int) (surface->height_inches * 72.0));
/* The "/FlateDecode filter" currently used is a feature of LanguageLevel 3 */
diff --git a/src/cairo_quartz_surface.c b/src/cairo_quartz_surface.c
new file mode 100644
index 000000000..b7103b051
--- /dev/null
+++ b/src/cairo_quartz_surface.c
@@ -0,0 +1,392 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Calum Robinson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Calum Robinson
+ *
+ * Contributor(s):
+ * Calum Robinson <calumr@mac.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-quartz.h"
+
+#pragma mark Types
+
+typedef struct cairo_quartz_surface {
+ cairo_surface_t base;
+
+ CGContextRef context;
+
+ int width;
+ int height;
+
+ cairo_image_surface_t *image;
+
+ CGImageRef cgImage;
+} cairo_quartz_surface_t;
+
+
+
+
+
+#pragma mark Private functions
+
+
+
+
+void ImageDataReleaseFunc(void *info, const void *data, size_t size)
+{
+ if (data != NULL)
+ {
+ free((void *)data);
+ }
+}
+
+
+
+
+#pragma mark Public functions
+
+
+
+
+
+void
+cairo_set_target_quartz_context( cairo_t *cr,
+ CGContextRef context,
+ int width,
+ int height)
+{
+ cairo_surface_t *surface;
+
+
+ if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
+ return;
+
+ surface = cairo_quartz_surface_create(context, width, height);
+ if (surface == NULL)
+ {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_set_target_surface(cr, surface);
+
+ /* cairo_set_target_surface takes a reference, so we must destroy ours */
+ cairo_surface_destroy(surface);
+}
+
+
+static cairo_surface_t *
+_cairo_quartz_surface_create_similar( void *abstract_src,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
+{
+ return NULL;
+}
+
+
+static void
+_cairo_quartz_surface_destroy(void *abstract_surface)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+
+
+ if (surface->cgImage)
+ {
+ CGImageRelease(surface->cgImage);
+ }
+
+
+ free(surface);
+}
+
+
+static double
+_cairo_quartz_surface_pixels_per_inch(void *abstract_surface)
+{
+
+
+ // TODO - get this from CGDirectDisplay somehow?
+ return 96.0;
+}
+
+
+static cairo_image_surface_t *
+_cairo_quartz_surface_get_image(void *abstract_surface)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+ CGColorSpaceRef colorSpace;
+ void *imageData;
+ UInt32 imageDataSize, rowBytes;
+ CGDataProviderRef dataProvider;
+
+
+ // We keep a cached (cairo_image_surface_t *) in the cairo_quartz_surface_t
+ // struct. If the window is ever drawn to without going through Cairo, then
+ // we would need to refetch the pixel data from the window into the cached
+ // image surface.
+ if (surface->image)
+ {
+ cairo_surface_reference(&surface->image->base);
+
+ return surface->image;
+ }
+
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+
+
+ rowBytes = surface->width * 4;
+ imageDataSize = rowBytes * surface->height;
+ imageData = malloc(imageDataSize);
+
+ dataProvider = CGDataProviderCreateWithData(NULL, imageData, imageDataSize, ImageDataReleaseFunc);
+
+ surface->cgImage = CGImageCreate( surface->width,
+ surface->height,
+ 8,
+ 32,
+ rowBytes,
+ colorSpace,
+ kCGImageAlphaPremultipliedFirst,
+ dataProvider,
+ NULL,
+ false,
+ kCGRenderingIntentDefault);
+
+
+ CGColorSpaceRelease(colorSpace);
+ CGDataProviderRelease(dataProvider);
+
+
+ surface->image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data( imageData,
+ CAIRO_FORMAT_ARGB32,
+ surface->width,
+ surface->height,
+ rowBytes);
+
+
+ // Set the image surface Cairo state to match our own.
+ _cairo_image_surface_set_repeat(surface->image, surface->base.repeat);
+ _cairo_image_surface_set_matrix(surface->image, &(surface->base.matrix));
+
+
+ return surface->image;
+}
+
+
+static cairo_status_t
+_cairo_quartz_surface_set_image( void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+
+ if (surface->image == image)
+ {
+ CGRect rect;
+
+
+ rect = CGRectMake(0, 0, surface->width, surface->height);
+
+ CGContextDrawImage(surface->context, rect, surface->cgImage);
+
+
+ status = CAIRO_STATUS_SUCCESS;
+ }
+ else
+ {
+ // TODO - set_image from something other than what we returned from get_image
+ status = CAIRO_STATUS_NO_TARGET_SURFACE;
+ }
+
+
+ return status;
+}
+
+
+static cairo_status_t
+_cairo_quartz_surface_set_matrix(void *abstract_surface, cairo_matrix_t *matrix)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_set_matrix(surface->image, matrix);
+}
+
+
+static cairo_status_t
+_cairo_quartz_surface_set_filter(void *abstract_surface, cairo_filter_t filter)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_set_filter(surface->image, filter);
+}
+
+
+static cairo_status_t
+_cairo_quartz_surface_set_repeat(void *abstract_surface, int repeat)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_set_repeat(surface->image, repeat);
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_composite( cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ cairo_surface_t *generic_mask,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_fill_rectangles( void *abstract_surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_composite_trapezoids( cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ void *abstract_dst,
+ int xSrc,
+ int ySrc,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_copy_page(void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_show_page(void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_set_clip_region( void *abstract_surface,
+ pixman_region16_t *region)
+{
+ cairo_quartz_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_set_clip_region(surface->image, region);
+}
+
+
+static cairo_int_status_t
+_cairo_quartz_surface_create_pattern( void *abstract_surface,
+ cairo_pattern_t *pattern,
+ cairo_box_t *extents)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
+static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
+ _cairo_quartz_surface_create_similar,
+ _cairo_quartz_surface_destroy,
+ _cairo_quartz_surface_pixels_per_inch,
+ _cairo_quartz_surface_get_image,
+ _cairo_quartz_surface_set_image,
+ _cairo_quartz_surface_set_matrix,
+ _cairo_quartz_surface_set_filter,
+ _cairo_quartz_surface_set_repeat,
+ _cairo_quartz_surface_composite,
+ _cairo_quartz_surface_fill_rectangles,
+ _cairo_quartz_surface_composite_trapezoids,
+ _cairo_quartz_surface_copy_page,
+ _cairo_quartz_surface_show_page,
+ _cairo_quartz_surface_set_clip_region,
+ _cairo_quartz_surface_create_pattern
+};
+
+
+cairo_surface_t *
+cairo_quartz_surface_create( CGContextRef context,
+ int width,
+ int height)
+{
+ cairo_quartz_surface_t *surface;
+
+
+ surface = malloc(sizeof(cairo_quartz_surface_t));
+ if (surface == NULL)
+ return NULL;
+
+ _cairo_surface_init(&surface->base, &cairo_quartz_surface_backend);
+
+
+ surface->context = context;
+
+ surface->width = width;
+ surface->height = height;
+
+ surface->image = NULL;
+
+ surface->cgImage = NULL;
+
+
+ // Set up the image surface which Cairo draws into and we blit to & from.
+ surface->image = _cairo_quartz_surface_get_image(surface);
+
+
+ return (cairo_surface_t *)surface;
+}
+
+
+DEPRECATE (cairo_surface_create_for_drawable, cairo_quartz_surface_create);
diff --git a/src/cairo_spline.c b/src/cairo_spline.c
index bed351ef4..ff290d9dd 100644
--- a/src/cairo_spline.c
+++ b/src/cairo_spline.c
@@ -54,8 +54,6 @@ _cairo_spline_error_squared (cairo_spline_t *spline);
static cairo_status_t
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result);
-#define CAIRO_SPLINE_GROWTH_INC 100
-
cairo_int_status_t
_cairo_spline_init (cairo_spline_t *spline,
cairo_point_t *a, cairo_point_t *b,
@@ -136,7 +134,8 @@ _cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point)
}
if (spline->num_points >= spline->points_size) {
- status = _cairo_spline_grow_by (spline, CAIRO_SPLINE_GROWTH_INC);
+ int additional = spline->points_size ? spline->points_size : 32;
+ status = _cairo_spline_grow_by (spline, additional);
if (status)
return status;
}
diff --git a/src/cairo_wideint.c b/src/cairo_wideint.c
index 45682c1cb..b636dface 100644
--- a/src/cairo_wideint.c
+++ b/src/cairo_wideint.c
@@ -1,25 +1,37 @@
/*
- * $Id: cairo_wideint.c,v 1.1 2004-05-28 19:37:15 keithp Exp $
+ * $Id: cairo_wideint.c,v 1.4 2005-01-19 15:07:00 cworth 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.
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
*
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Keith Packard
+ *
+ * Contributor(s):
+ * Keith R. Packard <keithp@keithp.com>
*/
#include "cairoint.h"
@@ -44,7 +56,7 @@ static const unsigned char top_bit[256] =
#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
-const cairo_uquorem64_t
+cairo_uquorem64_t
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
{
cairo_uquorem64_t qr;
@@ -56,7 +68,7 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
#else
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint32_to_uint64 (uint32_t i)
{
cairo_uint64_t q;
@@ -66,7 +78,7 @@ _cairo_uint32_to_uint64 (uint32_t i)
return q;
}
-const cairo_int64_t
+cairo_int64_t
_cairo_int32_to_int64 (int32_t i)
{
cairo_uint64_t q;
@@ -86,7 +98,7 @@ _cairo_uint32s_to_uint64 (uint32_t h, uint32_t l)
return q;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
@@ -98,7 +110,7 @@ _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
@@ -114,7 +126,7 @@ _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
#define uint32_hi(i) ((i) >> 16)
#define uint32_carry16 ((1) << 16)
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
{
cairo_uint64_t s;
@@ -142,7 +154,18 @@ _cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
return s;
}
-const cairo_uint64_t
+cairo_int64_t
+_cairo_int32x32_64_mul (int32_t a, int32_t b)
+{
+ s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t b));
+ if (a < 0)
+ s.hi -= b;
+ if (b < 0)
+ s.hi -= a;
+ return s;
+}
+
+cairo_uint64_t
_cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint64_t s;
@@ -152,7 +175,7 @@ _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_lsl (cairo_uint64_t a, int shift)
{
if (shift >= 32)
@@ -169,7 +192,7 @@ _cairo_uint64_lsl (cairo_uint64_t a, int shift)
return a;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_rsl (cairo_uint64_t a, int shift)
{
if (shift >= 32)
@@ -188,7 +211,7 @@ _cairo_uint64_rsl (cairo_uint64_t a, int shift)
#define _cairo_uint32_rsa(a,n) ((uint32_t) (((int32_t) (a)) >> (n)))
-const cairo_int64_t
+cairo_int64_t
_cairo_uint64_rsa (cairo_int64_t a, int shift)
{
if (shift >= 32)
@@ -205,20 +228,20 @@ _cairo_uint64_rsa (cairo_int64_t a, int shift)
return a;
}
-const int
+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
+int
_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b)
{
return a.hi == b.hi && a.lo == b.lo;
}
-const int
+int
_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
{
if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
@@ -228,7 +251,7 @@ _cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
return _cairo_uint64_lt (a, b);
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_not (cairo_uint64_t a)
{
a.lo = ~a.lo;
@@ -236,7 +259,7 @@ _cairo_uint64_not (cairo_uint64_t a)
return a;
}
-const cairo_uint64_t
+cairo_uint64_t
_cairo_uint64_negate (cairo_uint64_t a)
{
a.lo = ~a.lo;
@@ -325,7 +348,7 @@ _cairo_uint64x32_normalized_divrem (cairo_uint64_t num, uint32_t den)
return qr;
}
-const cairo_uquorem64_t
+cairo_uquorem64_t
_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
{
cairo_uquorem32_t qr32;
@@ -444,7 +467,7 @@ _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
#endif /* !HAVE_UINT64_T */
-const cairo_quorem64_t
+cairo_quorem64_t
_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
{
int num_neg = _cairo_int64_negative (num);
@@ -470,7 +493,7 @@ _cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
#if HAVE_UINT128_T
-const cairo_uquorem128_t
+cairo_uquorem128_t
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
{
cairo_uquorem128_t qr;
@@ -482,7 +505,7 @@ _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
#else
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint32_to_uint128 (uint32_t i)
{
cairo_uint128_t q;
@@ -492,7 +515,7 @@ _cairo_uint32_to_uint128 (uint32_t i)
return q;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int32_to_int128 (int32_t i)
{
cairo_int128_t q;
@@ -502,7 +525,7 @@ _cairo_int32_to_int128 (int32_t i)
return q;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint64_to_uint128 (cairo_uint64_t i)
{
cairo_uint128_t q;
@@ -512,7 +535,7 @@ _cairo_uint64_to_uint128 (cairo_uint64_t i)
return q;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int64_to_int128 (cairo_int64_t i)
{
cairo_int128_t q;
@@ -522,7 +545,7 @@ _cairo_int64_to_int128 (cairo_int64_t i)
return q;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
@@ -534,7 +557,7 @@ _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
return s;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
@@ -594,7 +617,7 @@ static const cairo_uint64_t uint64_carry32 = { 0, 1 };
#endif
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
{
cairo_uint128_t s;
@@ -622,7 +645,22 @@ _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
return s;
}
-const cairo_uint128_t
+cairo_int128_t
+_cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b)
+{
+ cairo_int128_t s;
+ s = _cairo_uint64x64_128_mul (_cairo_int64_to_uint64(a),
+ _cairo_int64_to_uint64(b));
+ if (_cairo_int64_negative (a))
+ s.hi = _cairo_uint64_sub (s.hi,
+ _cairo_int64_to_uint64 (b));
+ if (_cairo_int64_negative (b))
+ s.hi = _cairo_uint64_sub (s.hi,
+ _cairo_int64_to_uint64 (a));
+ return s;
+}
+
+cairo_uint128_t
_cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b)
{
cairo_uint128_t s;
@@ -635,7 +673,7 @@ _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b)
return s;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_lsl (cairo_uint128_t a, int shift)
{
if (shift >= 64)
@@ -653,7 +691,7 @@ _cairo_uint128_lsl (cairo_uint128_t a, int shift)
return a;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_rsl (cairo_uint128_t a, int shift)
{
if (shift >= 64)
@@ -671,7 +709,7 @@ _cairo_uint128_rsl (cairo_uint128_t a, int shift)
return a;
}
-const cairo_uint128_t
+cairo_uint128_t
_cairo_uint128_rsa (cairo_int128_t a, int shift)
{
if (shift >= 64)
@@ -689,7 +727,7 @@ _cairo_uint128_rsa (cairo_int128_t a, int shift)
return a;
}
-const int
+int
_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
{
return (_cairo_uint64_lt (a.hi, b.hi) ||
@@ -697,7 +735,7 @@ _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
_cairo_uint64_lt (a.lo, b.lo)));
}
-const int
+int
_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
{
if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
@@ -707,7 +745,7 @@ _cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
return _cairo_uint128_lt (a, b);
}
-const int
+int
_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
{
return (_cairo_uint64_eq (a.hi, b.hi) &&
@@ -722,7 +760,7 @@ _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
/*
* den >= num.hi
*/
-static const cairo_uquorem64_t
+static cairo_uquorem64_t
_cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
{
cairo_uquorem64_t qr64;
@@ -786,7 +824,7 @@ _cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
#if HAVE_UINT64_T
-static const int
+static int
_cairo_leading_zeros64 (cairo_uint64_t q)
{
int top = 0;
@@ -823,7 +861,7 @@ _cairo_leading_zeros64 (cairo_uint64_t d)
#endif
-const cairo_uquorem128_t
+cairo_uquorem128_t
_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
{
cairo_uquorem64_t qr64;
@@ -943,7 +981,7 @@ _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
return qr;
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int128_negate (cairo_int128_t a)
{
a.lo = _cairo_uint64_not (a.lo);
@@ -951,7 +989,7 @@ _cairo_int128_negate (cairo_int128_t a)
return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1));
}
-const cairo_int128_t
+cairo_int128_t
_cairo_int128_not (cairo_int128_t a)
{
a.lo = _cairo_uint64_not (a.lo);
@@ -961,7 +999,7 @@ _cairo_int128_not (cairo_int128_t a)
#endif /* !HAVE_UINT128_T */
-const cairo_quorem128_t
+cairo_quorem128_t
_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den)
{
int num_neg = _cairo_int128_negative (num);
diff --git a/src/cairo_wideint.h b/src/cairo_wideint.h
deleted file mode 100644
index c634ce081..000000000
--- a/src/cairo_wideint.h
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * $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 21760d764..758cf26de 100644
--- a/src/cairo_xcb_surface.c
+++ b/src/cairo_xcb_surface.c
@@ -730,7 +730,7 @@ _cairo_xcb_surface_create_pattern (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-static const struct cairo_surface_backend cairo_xcb_surface_backend = {
+static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_destroy,
_cairo_xcb_surface_pixels_per_inch,
diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c
index dda7995bd..d9d74f583 100644
--- a/src/cairo_xlib_surface.c
+++ b/src/cairo_xlib_surface.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-xlib.h"
void
cairo_set_target_drawable (cairo_t *cr,
@@ -61,7 +62,7 @@ cairo_set_target_drawable (cairo_t *cr,
cairo_surface_destroy (surface);
}
-typedef struct cairo_xlib_surface {
+typedef struct _cairo_xlib_surface {
cairo_surface_t base;
Display *dpy;
@@ -118,6 +119,16 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
}
static cairo_surface_t *
+_cairo_xlib_surface_create_with_size (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ cairo_format_t format,
+ Colormap colormap,
+ int width,
+ int height);
+
+
+static cairo_surface_t *
_cairo_xlib_surface_create_similar (void *abstract_src,
cairo_format_t format,
int drawable,
@@ -149,7 +160,9 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
_CAIRO_FORMAT_DEPTH (format));
surface = (cairo_xlib_surface_t *)
- cairo_xlib_surface_create (dpy, pix, NULL, format, DefaultColormap (dpy, scr));
+ _cairo_xlib_surface_create_with_size (dpy, pix, NULL, format,
+ DefaultColormap (dpy, scr),
+ width, height);
surface->owns_pixmap = 1;
surface->width = width;
@@ -199,6 +212,7 @@ _cairo_xlib_surface_get_image (void *abstract_surface)
&surface->width, &surface->height,
&bwidth_ignore, &depth_ignore);
+ /* XXX: This should try to use the XShm extension if availible */
ximage = XGetImage (surface->dpy,
surface->drawable,
0, 0,
@@ -684,13 +698,13 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ void *abstract_surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs);
-static const struct cairo_surface_backend cairo_xlib_surface_backend = {
+static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_create_similar,
_cairo_xlib_surface_destroy,
_cairo_xlib_surface_pixels_per_inch,
@@ -709,17 +723,17 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = {
_cairo_xlib_surface_show_glyphs
};
-cairo_surface_t *
-cairo_xlib_surface_create (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap)
+static cairo_surface_t *
+_cairo_xlib_surface_create_with_size (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ cairo_format_t format,
+ Colormap colormap,
+ int width,
+ int height)
{
cairo_xlib_surface_t *surface;
int render_standard;
- Window w;
- unsigned int ignore;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@@ -736,7 +750,9 @@ cairo_xlib_surface_create (Display *dpy,
surface->drawable = drawable;
surface->owns_pixmap = 0;
surface->visual = visual;
-
+ surface->width = width;
+ surface->height = height;
+
if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
surface->render_major = -1;
surface->render_minor = -1;
@@ -758,12 +774,6 @@ 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,
@@ -776,8 +786,31 @@ cairo_xlib_surface_create (Display *dpy,
return (cairo_surface_t *) surface;
}
-DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
+cairo_surface_t *
+cairo_xlib_surface_create (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ cairo_format_t format,
+ Colormap colormap)
+{
+ Window window_ignore;
+ unsigned int int_ignore;
+ unsigned int width, height;
+
+ /* XXX: This call is a round-trip. We probably want to instead (or
+ * also?) export a version that accepts width/height. Then, we'll
+ * likely also need a resize function too.
+ */
+ XGetGeometry(dpy, drawable,
+ &window_ignore, &int_ignore, &int_ignore,
+ &width, &height,
+ &int_ignore, &int_ignore);
+
+ return _cairo_xlib_surface_create_with_size (dpy, drawable, visual, format,
+ colormap, width, height);
+}
+DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
/* RENDER glyphset cache code */
@@ -839,8 +872,45 @@ _xlib_glyphset_cache_create_entry (void *cache,
v->info.width = im->image ? im->image->stride : im->size.width;
v->info.height = im->size.height;
- v->info.x = - im->extents.x_bearing;
- v->info.y = im->extents.y_bearing;
+
+ /*
+ * Most of the font rendering system thinks of glyph tiles as having
+ * an origin at (0,0) and an x and y bounding box "offset" which
+ * extends possibly off into negative coordinates, like so:
+ *
+ *
+ * (x,y) <-- probably negative numbers
+ * +----------------+
+ * | . |
+ * | . |
+ * |......(0,0) |
+ * | |
+ * | |
+ * +----------------+
+ * (width+x,height+y)
+ *
+ * This is a postscript-y model, where each glyph has its own
+ * coordinate space, so it's what we expose in terms of metrics. It's
+ * apparantly what everyone's expecting. Everyone except the Render
+ * extension. Render wants to see a glyph tile starting at (0,0), with
+ * an origin offset inside, like this:
+ *
+ * (0,0)
+ * +---------------+
+ * | . |
+ * | . |
+ * |......(x,y) |
+ * | |
+ * | |
+ * +---------------+
+ * (width,height)
+ *
+ * Luckily, this is just the negation of the numbers we already have
+ * sitting around for x and y.
+ */
+
+ v->info.x = -im->size.x;
+ v->info.y = -im->size.y;
v->info.xOff = 0;
v->info.yOff = 0;
@@ -875,7 +945,7 @@ _xlib_glyphset_cache_destroy_entry (void *cache, void *entry)
free (v);
}
-const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
+static const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
_cairo_glyph_cache_hash,
_cairo_glyph_cache_keys_equal,
_xlib_glyphset_cache_create_entry,
@@ -964,6 +1034,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
unsigned int stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -987,10 +1058,12 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ thisX = (int) floor (glyphs[i].x + 0.5);
+ thisY = (int) floor (glyphs[i].y + 0.5);
+ elts[i].xOff = thisX - lastX;
+ elts[i].yOff = thisY - lastY;
+ lastX = thisX;
+ lastY = thisY;
}
XRenderCompositeText32 (self->dpy,
@@ -1039,6 +1112,7 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
unsigned short stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -1062,10 +1136,12 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ thisX = (int) floor (glyphs[i].x + 0.5);
+ thisY = (int) floor (glyphs[i].y + 0.5);
+ elts[i].xOff = thisX - lastX;
+ elts[i].yOff = thisY - lastY;
+ lastX = thisX;
+ lastY = thisY;
}
XRenderCompositeText16 (self->dpy,
@@ -1113,6 +1189,7 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
char stack_chars [N_STACK_BUF];
int i;
+ int thisX, thisY;
int lastX = 0, lastY = 0;
/* Acquire arrays of suitable sizes. */
@@ -1136,10 +1213,12 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font,
elts[i].chars = &(chars[i]);
elts[i].nchars = 1;
elts[i].glyphset = g->glyphset;
- elts[i].xOff = glyphs[i].x - lastX;
- elts[i].yOff = glyphs[i].y - lastY;
- lastX = glyphs[i].x;
- lastY = glyphs[i].y;
+ thisX = (int) floor (glyphs[i].x + 0.5);
+ thisY = (int) floor (glyphs[i].y + 0.5);
+ elts[i].xOff = thisX - lastX;
+ elts[i].yOff = thisY - lastY;
+ lastX = thisX;
+ lastY = thisY;
}
XRenderCompositeText8 (self->dpy,
@@ -1172,14 +1251,14 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ void *abstract_surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
unsigned int elt_size;
- cairo_xlib_surface_t *self = (cairo_xlib_surface_t *) surface;
+ cairo_xlib_surface_t *self = abstract_surface;
cairo_image_surface_t *tmp = NULL;
cairo_xlib_surface_t *src = NULL;
glyphset_cache_t *g;
@@ -1200,7 +1279,7 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
}
/* prep the source surface. */
- if (source->backend == surface->backend) {
+ if (source->backend == self->base.backend) {
src = (cairo_xlib_surface_t *) source;
} else {
@@ -1209,7 +1288,7 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font,
goto FREE_ENTRIES;
src = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (surface, self->format, 1,
+ _cairo_surface_create_similar_scratch (&self->base, self->format, 1,
tmp->width, tmp->height);
if (src == NULL)
diff --git a/src/cairoint.h b/src/cairoint.h
index be0e54e78..6f9d50617 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -49,6 +49,7 @@
#include "config.h"
#endif
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
@@ -63,7 +64,7 @@
# define slim_hidden_proto1(name, internal) \
extern __typeof (name) name \
__asm__ (slim_hidden_asmname (internal)) \
- __internal_linkage;
+ cairo_private;
# define slim_hidden_def1(name, internal) \
extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \
__attribute__((__alias__(slim_hidden_asmname(internal))))
@@ -79,12 +80,11 @@
/* slim_internal.h */
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__)
-#define __internal_linkage __attribute__((__visibility__("hidden")))
+#define cairo_private __attribute__((__visibility__("hidden")))
#else
-#define __internal_linkage
+#define cairo_private
#endif
-
/* These macros allow us to deprecate a function by providing an alias
for the old function name to the new function name. With this
macro, binary compatibility is preserved. The macro only works on
@@ -108,7 +108,7 @@
#define __attribute__(x)
#endif
-#include "cairo_wideint.h"
+#include "cairo-wideint.h"
typedef int32_t cairo_fixed_16_16_t;
typedef cairo_int64_t cairo_fixed_32_32_t;
@@ -122,38 +122,38 @@ typedef cairo_fixed_16_16_t cairo_fixed_t;
#define CAIRO_MAXSHORT SHRT_MAX
#define CAIRO_MINSHORT SHRT_MIN
-typedef struct cairo_point {
+typedef struct _cairo_point {
cairo_fixed_t x;
cairo_fixed_t y;
} cairo_point_t;
-typedef struct cairo_slope
+typedef struct _cairo_slope
{
cairo_fixed_t dx;
cairo_fixed_t dy;
} cairo_slope_t, cairo_distance_t;
-typedef struct cairo_point_double {
+typedef struct _cairo_point_double {
double x;
double y;
} cairo_point_double_t;
-typedef struct cairo_distance_double {
+typedef struct _cairo_distance_double {
double dx;
double dy;
} cairo_distance_double_t;
-typedef struct cairo_line {
+typedef struct _cairo_line {
cairo_point_t p1;
cairo_point_t p2;
} cairo_line_t, cairo_box_t;
-typedef struct cairo_trapezoid {
+typedef struct _cairo_trapezoid {
cairo_fixed_t top, bottom;
cairo_line_t left, right;
} cairo_trapezoid_t;
-typedef struct cairo_rectangle_int {
+typedef struct _cairo_rectangle_int {
short x, y;
unsigned short width, height;
} cairo_rectangle_t, cairo_glyph_size_t;
@@ -180,21 +180,21 @@ typedef enum cairo_direction {
#define CAIRO_PATH_BUF_SZ 64
-typedef struct cairo_path_op_buf {
+typedef struct _cairo_path_op_buf {
int num_ops;
cairo_path_op_t op[CAIRO_PATH_BUF_SZ];
- struct cairo_path_op_buf *next, *prev;
+ struct _cairo_path_op_buf *next, *prev;
} cairo_path_op_buf_t;
-typedef struct cairo_path_arg_buf {
+typedef struct _cairo_path_arg_buf {
int num_points;
cairo_point_t points[CAIRO_PATH_BUF_SZ];
- struct cairo_path_arg_buf *next, *prev;
+ struct _cairo_path_arg_buf *next, *prev;
} cairo_path_arg_buf_t;
-typedef struct cairo_path {
+typedef struct _cairo_path {
cairo_path_op_buf_t *op_head;
cairo_path_op_buf_t *op_tail;
@@ -206,14 +206,14 @@ typedef struct cairo_path {
int has_current_point;
} cairo_path_t;
-typedef struct cairo_edge {
+typedef struct _cairo_edge {
cairo_line_t edge;
int clockWise;
cairo_fixed_16_16_t current_x;
} cairo_edge_t;
-typedef struct cairo_polygon {
+typedef struct _cairo_polygon {
int num_edges;
int edges_size;
cairo_edge_t *edges;
@@ -225,7 +225,7 @@ typedef struct cairo_polygon {
int closed;
} cairo_polygon_t;
-typedef struct cairo_spline {
+typedef struct _cairo_spline {
cairo_point_t a, b, c, d;
cairo_slope_t initial_slope;
@@ -243,7 +243,7 @@ typedef struct _cairo_pen_vertex {
cairo_slope_t slope_cw;
} cairo_pen_vertex_t;
-typedef struct cairo_pen {
+typedef struct _cairo_pen {
double radius;
double tolerance;
@@ -251,12 +251,47 @@ typedef struct cairo_pen {
int num_vertices;
} cairo_pen_t;
-typedef struct cairo_color cairo_color_t;
-typedef struct cairo_image_surface cairo_image_surface_t;
+typedef struct _cairo_color cairo_color_t;
+typedef struct _cairo_image_surface cairo_image_surface_t;
+
+/* cairo_array.c structures and functions */
+
+typedef struct _cairo_array cairo_array_t;
+struct _cairo_array {
+ int size;
+ int num_elements;
+ int element_size;
+ char *elements;
+};
+
+cairo_private void
+_cairo_array_init (cairo_array_t *array, int element_size);
+
+cairo_private void
+_cairo_array_fini (cairo_array_t *array);
+
+cairo_private cairo_status_t
+_cairo_array_grow_by (cairo_array_t *array, int additional);
+
+cairo_private void
+_cairo_array_truncate (cairo_array_t *array, int length);
+
+cairo_private void *
+_cairo_array_append (cairo_array_t *array,
+ const void *elements, int num_elements);
+
+cairo_private void *
+_cairo_array_index (cairo_array_t *array, int index);
+
+cairo_private void
+_cairo_array_copy_element (cairo_array_t *array, int index, void *dst);
+
+cairo_private int
+_cairo_array_num_elements (cairo_array_t *array);
/* cairo_cache.c structures and functions */
-typedef struct cairo_cache_backend {
+typedef struct _cairo_cache_backend {
unsigned long (*hash) (void *cache,
void *key);
@@ -276,7 +311,6 @@ typedef struct cairo_cache_backend {
} cairo_cache_backend_t;
-
/*
* The cairo_cache system makes the following assumptions about
* entries in its cache:
@@ -312,7 +346,7 @@ typedef struct {
typedef struct {
unsigned long refcount;
const cairo_cache_backend_t *backend;
- cairo_cache_arrangement_t *arrangement;
+ const cairo_cache_arrangement_t *arrangement;
cairo_cache_entry_base_t **entries;
unsigned long max_memory;
@@ -326,23 +360,23 @@ typedef struct {
#endif
} cairo_cache_t;
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
const cairo_cache_backend_t *backend,
unsigned long max_memory);
-extern void __internal_linkage
+cairo_private void
_cairo_cache_reference (cairo_cache_t *cache);
-extern void __internal_linkage
+cairo_private void
_cairo_cache_destroy (cairo_cache_t *cache);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_cache_lookup (cairo_cache_t *cache,
void *key,
void **entry_return);
-extern unsigned long __internal_linkage
+cairo_private unsigned long
_cairo_hash_string (const char *c);
#define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
@@ -354,25 +388,24 @@ typedef struct {
double matrix[2][2];
} cairo_font_scale_t;
-struct cairo_font_backend;
+struct _cairo_font_backend;
typedef struct {
int refcount;
- const struct cairo_font_backend *backend;
+ const struct _cairo_font_backend *backend;
} cairo_unscaled_font_t;
/*
- * A cairo_font contains a pointer to a cairo_sizeless_font_t and a scale
+ * A cairo_font contains a pointer to a cairo_unscaled_font_t and a scale
* matrix. These are the things the user holds references to.
*/
-struct cairo_font {
+struct _cairo_font {
int refcount;
cairo_font_scale_t scale;
cairo_unscaled_font_t *unscaled;
};
-
/* cairo_font.c is responsible for two global caches:
*
* - font entries: [[[base], name, weight, slant], cairo_unscaled_font_t ]
@@ -397,29 +430,28 @@ typedef struct {
cairo_text_extents_t extents;
} cairo_image_glyph_cache_entry_t;
-extern void __internal_linkage
+cairo_private void
_cairo_lock_global_image_glyph_cache (void);
-extern void __internal_linkage
+cairo_private void
_cairo_unlock_global_image_glyph_cache (void);
-extern cairo_cache_t * __internal_linkage
+cairo_private cairo_cache_t *
_cairo_get_global_image_glyph_cache (void);
/* Some glyph cache functions you can reuse. */
-extern unsigned long __internal_linkage
+cairo_private unsigned long
_cairo_glyph_cache_hash (void *cache, void *key);
-extern int __internal_linkage
+cairo_private int
_cairo_glyph_cache_keys_equal (void *cache,
void *k1,
void *k2);
-
/* the font backend interface */
-typedef struct cairo_font_backend {
+typedef struct _cairo_font_backend {
cairo_unscaled_font_t *(*create) (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
@@ -469,10 +501,19 @@ typedef struct cairo_font_backend {
} cairo_font_backend_t;
/* concrete font backends */
-extern const struct cairo_font_backend cairo_ft_font_backend;
+#ifdef CAIRO_HAS_FT_FONT
+
+extern const cairo_private struct _cairo_font_backend cairo_ft_font_backend;
+
+#endif
+
+#ifdef CAIRO_HAS_ATSUI_FONT
+extern const cairo_private struct _cairo_font_backend cairo_atsui_font_backend;
-typedef struct cairo_surface_backend {
+#endif
+
+typedef struct _cairo_surface_backend {
cairo_surface_t *
(*create_similar) (void *surface,
cairo_format_t format,
@@ -566,19 +607,18 @@ typedef struct cairo_surface_backend {
cairo_font_scale_t *scale,
cairo_operator_t operator,
cairo_surface_t *source,
- cairo_surface_t *surface,
+ void *surface,
int source_x,
int source_y,
const cairo_glyph_t *glyphs,
int num_glyphs);
-
} cairo_surface_backend_t;
-struct cairo_matrix {
+struct _cairo_matrix {
double m[3][2];
};
-typedef struct cairo_format_masks {
+typedef struct _cairo_format_masks {
int bpp;
unsigned long alpha_mask;
unsigned long red_mask;
@@ -586,7 +626,7 @@ typedef struct cairo_format_masks {
unsigned long blue_mask;
} cairo_format_masks_t;
-struct cairo_surface {
+struct _cairo_surface {
const cairo_surface_backend_t *backend;
unsigned int ref_count;
@@ -596,7 +636,7 @@ struct cairo_surface {
int repeat;
};
-struct cairo_image_surface {
+struct _cairo_image_surface {
cairo_surface_t base;
/* libic-specific fields */
@@ -617,7 +657,7 @@ struct cairo_image_surface {
madness). I'm still working on a cleaner API, but in the meantime,
at least this does prevent precision loss in color when changing
alpha. */
-struct cairo_color {
+struct _cairo_color {
double red;
double green;
double blue;
@@ -639,7 +679,7 @@ typedef enum {
CAIRO_PATTERN_RADIAL
} cairo_pattern_type_t;
-typedef struct cairo_color_stop {
+typedef struct _cairo_color_stop {
cairo_fixed_t offset;
cairo_fixed_48_16_t scale;
int id;
@@ -651,7 +691,7 @@ typedef void (*cairo_shader_function_t) (unsigned char *color0,
cairo_fixed_t factor,
int *pixel);
-typedef struct cairo_shader_op {
+typedef struct _cairo_shader_op {
cairo_color_stop_t *stops;
int n_stops;
cairo_fixed_t min_offset;
@@ -660,7 +700,7 @@ typedef struct cairo_shader_op {
cairo_shader_function_t shader_function;
} cairo_shader_op_t;
-struct cairo_pattern {
+struct _cairo_pattern {
unsigned int ref_count;
cairo_extend_t extend;
@@ -696,20 +736,30 @@ struct cairo_pattern {
} u;
};
-typedef struct cairo_traps {
+typedef struct _cairo_traps {
cairo_trapezoid_t *traps;
int num_traps;
int traps_size;
cairo_box_t extents;
} cairo_traps_t;
-#define CAIRO_FONT_FAMILY_DEFAULT "serif"
#define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL
#define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL
+#ifdef CAIRO_HAS_FT_FONT
+
+#define CAIRO_FONT_FAMILY_DEFAULT "serif"
+
/* XXX: Platform-specific. Other platforms may want a different default */
#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend
+#elif defined(CAIRO_HAS_ATSUI_FONT)
+
+#define CAIRO_FONT_FAMILY_DEFAULT "Monaco"
+
+#define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_font_backend
+
+#endif
#define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER
#define CAIRO_GSTATE_TOLERANCE_DEFAULT 0.1
@@ -721,7 +771,7 @@ typedef struct cairo_traps {
#define CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT 96.0
/* Need a name distinct from the cairo_clip function */
-typedef struct cairo_clip_rec {
+typedef struct _cairo_clip_rec {
int x;
int y;
int width;
@@ -730,7 +780,7 @@ typedef struct cairo_clip_rec {
cairo_surface_t *surface;
} cairo_clip_rec_t;
-typedef struct cairo_gstate {
+typedef struct _cairo_gstate {
cairo_operator_t operator;
double tolerance;
@@ -767,16 +817,16 @@ typedef struct cairo_gstate {
cairo_pen_t pen_regular;
- struct cairo_gstate *next;
+ struct _cairo_gstate *next;
} cairo_gstate_t;
-struct cairo {
+struct _cairo {
unsigned int ref_count;
cairo_gstate_t *gstate;
cairo_status_t status;
};
-typedef struct cairo_stroke_face {
+typedef struct _cairo_stroke_face {
cairo_point_t ccw;
cairo_point_t point;
cairo_point_t cw;
@@ -785,217 +835,224 @@ typedef struct cairo_stroke_face {
} cairo_stroke_face_t;
/* cairo.c */
-extern void __internal_linkage
+cairo_private void
_cairo_restrict_value (double *value, double min, double max);
/* cairo_fixed.c */
-extern cairo_fixed_t __internal_linkage
+cairo_private cairo_fixed_t
_cairo_fixed_from_int (int i);
-extern cairo_fixed_t
+cairo_private cairo_fixed_t
_cairo_fixed_from_double (double d);
-cairo_fixed_t
+cairo_private cairo_fixed_t
_cairo_fixed_from_26_6 (uint32_t i);
-extern double
+cairo_private double
_cairo_fixed_to_double (cairo_fixed_t f);
-extern int __internal_linkage
+cairo_private int
_cairo_fixed_is_integer (cairo_fixed_t f);
-extern int __internal_linkage
+cairo_private int
_cairo_fixed_integer_part (cairo_fixed_t f);
+cairo_private int
+_cairo_fixed_integer_floor (cairo_fixed_t f);
+
+cairo_private int
+_cairo_fixed_integer_ceil (cairo_fixed_t f);
+
+
/* cairo_gstate.c */
-extern cairo_gstate_t * __internal_linkage
+cairo_private cairo_gstate_t *
_cairo_gstate_create (void);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_init (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_fini (cairo_gstate_t *gstate);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_destroy (cairo_gstate_t *gstate);
-extern cairo_gstate_t * __internal_linkage
+cairo_private cairo_gstate_t *
_cairo_gstate_clone (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_copy (cairo_gstate_t *dest, cairo_gstate_t *src);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_begin_group (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_end_group (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface);
-extern cairo_surface_t * __internal_linkage
+cairo_private cairo_surface_t *
_cairo_gstate_current_target_surface (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern);
-extern cairo_pattern_t *__internal_linkage
+cairo_private cairo_pattern_t *
_cairo_gstate_current_pattern (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator);
-extern cairo_operator_t __internal_linkage
+cairo_private cairo_operator_t
_cairo_gstate_current_operator (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_current_rgb_color (cairo_gstate_t *gstate,
double *red,
double *green,
double *blue);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance);
-extern double __internal_linkage
+cairo_private double
_cairo_gstate_current_tolerance (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha);
-extern double __internal_linkage
+cairo_private double
_cairo_gstate_current_alpha (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule);
-extern cairo_fill_rule_t __internal_linkage
+cairo_private cairo_fill_rule_t
_cairo_gstate_current_fill_rule (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width);
-extern double __internal_linkage
+cairo_private double
_cairo_gstate_current_line_width (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap);
-extern cairo_line_cap_t __internal_linkage
+cairo_private cairo_line_cap_t
_cairo_gstate_current_line_cap (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join);
-extern cairo_line_join_t __internal_linkage
+cairo_private cairo_line_join_t
_cairo_gstate_current_line_join (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit);
-extern double __internal_linkage
+cairo_private double
_cairo_gstate_current_miter_limit (cairo_gstate_t *gstate);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_current_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_default_matrix (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_transform_point (cairo_gstate_t *gstate, double *x, double *y);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_new_path (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_curve_to (cairo_gstate_t *gstate,
double x1, double y1,
double x2, double y2,
double x3, double y3);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_arc (cairo_gstate_t *gstate,
double xc, double yc,
double radius,
double angle1, double angle2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
double xc, double yc,
double radius,
double angle1, double angle2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_rel_curve_to (cairo_gstate_t *gstate,
double dx1, double dy1,
double dx2, double dy2,
double dx3, double dy3);
/* XXX: NYI
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_stroke_path (cairo_gstate_t *gstate);
*/
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_close_path (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x, double *y);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_interpret_path (cairo_gstate_t *gstate,
cairo_move_to_func_t *move_to,
cairo_line_to_func_t *line_to,
@@ -1003,174 +1060,177 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate,
cairo_close_path_func_t *close_path,
void *closure);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_copy_page (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_show_page (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
double *x1, double *y1,
double *x2, double *y2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
double *x1, double *y1,
double *x2, double *y2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double x,
double y,
int *inside_ret);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
double x,
double y,
int *inside_ret);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_init_clip (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
+_cairo_gstate_restore_external_state (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
_cairo_gstate_show_surface (cairo_gstate_t *gstate,
cairo_surface_t *surface,
int width,
int height);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_select_font (cairo_gstate_t *gstate,
const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_scale_font (cairo_gstate_t *gstate,
double scale);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_transform_font (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_current_font (cairo_gstate_t *gstate,
cairo_font_t **font);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
-extern void __internal_linkage
+cairo_private void
_cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
cairo_font_extents_t *extents);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_set_font (cairo_gstate_t *gstate,
cairo_font_t *font);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_text_to_glyphs (cairo_gstate_t *font,
const unsigned char *utf8,
cairo_glyph_t **glyphs,
int *num_glyphs);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_glyph_t *glyphs,
int num_glyphs);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
cairo_glyph_t *glyphs,
int num_glyphs);
/* cairo_color.c */
-extern void __internal_linkage
+cairo_private void
_cairo_color_init (cairo_color_t *color);
-extern void __internal_linkage
+cairo_private void
_cairo_color_fini (cairo_color_t *color);
-extern void __internal_linkage
+cairo_private void
_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue);
-extern void __internal_linkage
+cairo_private void
_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue);
-extern void __internal_linkage
+cairo_private void
_cairo_color_set_alpha (cairo_color_t *color, double alpha);
/* cairo_font.c */
-extern cairo_unscaled_font_t * __internal_linkage
+cairo_private cairo_unscaled_font_t *
_cairo_unscaled_font_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
-extern void __internal_linkage
+cairo_private void
_cairo_font_init (cairo_font_t *scaled,
cairo_font_scale_t *scale,
cairo_unscaled_font_t *unscaled);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const struct cairo_font_backend *backend);
+ const struct _cairo_font_backend *backend);
-extern void __internal_linkage
+cairo_private void
_cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
-extern void __internal_linkage
+cairo_private void
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_font_extents_t *extents);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
const unsigned char *utf8,
cairo_glyph_t **glyphs,
int *num_glyphs);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font,
cairo_font_scale_t *scale,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font,
cairo_font_scale_t *size,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_box_t *bbox);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font,
cairo_font_scale_t *size,
cairo_operator_t operator,
@@ -1181,7 +1241,7 @@ _cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font,
cairo_glyph_t *glyphs,
int num_glyphs);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font,
cairo_font_scale_t *size,
cairo_glyph_t *glyphs,
@@ -1189,47 +1249,47 @@ _cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font,
cairo_path_t *path);
/* cairo_hull.c */
-extern cairo_status_t
+cairo_private cairo_status_t
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices);
/* cairo_path.c */
-extern void __internal_linkage
+cairo_private void
_cairo_path_init (cairo_path_t *path);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other);
-extern void __internal_linkage
+cairo_private void
_cairo_path_fini (cairo_path_t *path);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_rel_move_to (cairo_path_t *path, cairo_slope_t *slope);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_rel_line_to (cairo_path_t *path, cairo_slope_t *slope);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_curve_to (cairo_path_t *path,
cairo_point_t *p0,
cairo_point_t *p1,
cairo_point_t *p2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_rel_curve_to (cairo_path_t *path,
cairo_slope_t *s0,
cairo_slope_t *s1,
cairo_slope_t *s2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_close_path (cairo_path_t *path);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point);
typedef cairo_status_t (cairo_path_move_to_func_t) (void *closure,
@@ -1245,7 +1305,7 @@ typedef cairo_status_t (cairo_path_curve_to_func_t) (void *closure,
typedef cairo_status_t (cairo_path_close_path_func_t) (void *closure);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_interpret (cairo_path_t *path,
cairo_direction_t dir,
cairo_path_move_to_func_t *move_to,
@@ -1254,37 +1314,37 @@ _cairo_path_interpret (cairo_path_t *path,
cairo_path_close_path_func_t *close_path,
void *closure);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2);
/* cairo_path_fill.c */
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
/* cairo_path_stroke.c */
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
/* cairo_surface.c */
-extern cairo_surface_t * __internal_linkage
+cairo_private cairo_surface_t *
_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_private cairo_surface_t *
_cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_format_t format,
int width,
int height,
cairo_color_t *color);
-extern void __internal_linkage
+cairo_private void
_cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
cairo_operator_t operator,
cairo_color_t *color,
@@ -1293,7 +1353,7 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface,
int width,
int height);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_composite (cairo_operator_t operator,
cairo_surface_t *src,
cairo_surface_t *mask,
@@ -1307,14 +1367,14 @@ _cairo_surface_composite (cairo_operator_t operator,
unsigned int width,
unsigned int height);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_operator_t operator,
const cairo_color_t *color,
cairo_rectangle_t *rects,
int num_rects);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t operator,
cairo_surface_t *src,
cairo_surface_t *dst,
@@ -1323,248 +1383,248 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator,
cairo_trapezoid_t *traps,
int ntraps);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_copy_page (cairo_surface_t *surface);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_show_page (cairo_surface_t *surface);
-extern double __internal_linkage
+cairo_private double
_cairo_surface_pixels_per_inch (cairo_surface_t *surface);
-extern cairo_image_surface_t * __internal_linkage
+cairo_private cairo_image_surface_t *
_cairo_surface_get_image (cairo_surface_t *surface);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_set_image (cairo_surface_t *surface,
cairo_image_surface_t *image);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_surface_create_pattern (cairo_surface_t *surface,
cairo_pattern_t *pattern,
cairo_box_t *extents);
/* cairo_image_surface.c */
-extern cairo_image_surface_t * __internal_linkage
+cairo_private cairo_image_surface_t *
_cairo_image_surface_create_with_masks (char *data,
cairo_format_masks_t *format,
int width,
int height,
int stride);
-extern void __internal_linkage
+cairo_private void
_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_image_surface_set_filter (cairo_image_surface_t *surface,
cairo_filter_t filter);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_image_surface_set_repeat (cairo_image_surface_t *surface,
int repeat);
-extern cairo_int_status_t __internal_linkage
+cairo_private cairo_int_status_t
_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
pixman_region16_t *region);
/* cairo_pen.c */
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_init_empty (cairo_pen_t *pen);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other);
-extern void __internal_linkage
+cairo_private void
_cairo_pen_fini (cairo_pen_t *pen);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_add_points_for_slopes (cairo_pen_t *pen,
cairo_point_t *a,
cairo_point_t *b,
cairo_point_t *c,
cairo_point_t *d);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
cairo_slope_t *slope,
int *active);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
cairo_slope_t *slope,
int *active);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pen_stroke_spline (cairo_pen_t *pen,
cairo_spline_t *spline,
double tolerance,
cairo_traps_t *traps);
/* cairo_polygon.c */
-extern void __internal_linkage
+cairo_private void
_cairo_polygon_init (cairo_polygon_t *polygon);
-extern void __internal_linkage
+cairo_private void
_cairo_polygon_fini (cairo_polygon_t *polygon);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_polygon_close (cairo_polygon_t *polygon);
/* cairo_spline.c */
-extern cairo_int_status_t __internal_linkage
+cairo_private cairo_int_status_t
_cairo_spline_init (cairo_spline_t *spline,
cairo_point_t *a,
cairo_point_t *b,
cairo_point_t *c,
cairo_point_t *d);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance);
-extern void __internal_linkage
+cairo_private void
_cairo_spline_fini (cairo_spline_t *spline);
/* cairo_matrix.c */
-extern void __internal_linkage
+cairo_private void
_cairo_matrix_init (cairo_matrix_t *matrix);
-extern void __internal_linkage
+cairo_private void
_cairo_matrix_fini (cairo_matrix_t *matrix);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_set_translate (cairo_matrix_t *matrix,
double tx, double ty);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_set_scale (cairo_matrix_t *matrix,
double sx, double sy);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
double angle);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
double *x, double *y,
double *width, double *height);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2);
-extern cairo_status_t __internal_linkage
-_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy);
+cairo_private cairo_status_t
+_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major);
-extern int __internal_linkage
+cairo_private int
_cairo_matrix_is_integer_translation(cairo_matrix_t *matrix, int *itx, int *ity);
/* cairo_traps.c */
-extern void __internal_linkage
+cairo_private void
_cairo_traps_init (cairo_traps_t *traps);
-extern void __internal_linkage
+cairo_private void
_cairo_traps_fini (cairo_traps_t *traps);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3]);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_traps_tessellate_rectangle (cairo_traps_t *traps, cairo_point_t q[4]);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_traps_tessellate_polygon (cairo_traps_t *traps,
cairo_polygon_t *poly,
cairo_fill_rule_t fill_rule);
-extern int __internal_linkage
+cairo_private int
_cairo_traps_contain (cairo_traps_t *traps, double x, double y);
-extern void __internal_linkage
+cairo_private void
_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents);
/* cairo_slope.c */
-extern void __internal_linkage
+cairo_private void
_cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b);
-extern int __internal_linkage
+cairo_private int
_cairo_slope_compare (cairo_slope_t *a, cairo_slope_t *b);
-extern int __internal_linkage
+cairo_private int
_cairo_slope_clockwise (cairo_slope_t *a, cairo_slope_t *b);
-extern int __internal_linkage
+cairo_private int
_cairo_slope_counter_clockwise (cairo_slope_t *a, cairo_slope_t *b);
/* cairo_pattern.c */
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_init (cairo_pattern_t *pattern);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_fini (cairo_pattern_t *pattern);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_init_solid (cairo_pattern_t *pattern,
double red, double green, double blue);
-extern cairo_pattern_t *__internal_linkage
+cairo_private cairo_pattern_t *
_cairo_pattern_create_solid (double red, double green, double blue);
-extern cairo_status_t __internal_linkage
+cairo_private cairo_status_t
_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
double *red, double *green, double *blue);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_set_source_offset (cairo_pattern_t *pattern,
double x, double y);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_transform (cairo_pattern_t *pattern,
cairo_matrix_t *ctm_inverse);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_prepare_surface (cairo_pattern_t *pattern);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_shader_init (cairo_pattern_t *pattern,
cairo_shader_op_t *op);
-extern void __internal_linkage
+cairo_private void
_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
cairo_fixed_t factor,
int *pixel);
-extern cairo_image_surface_t *__internal_linkage
+cairo_private cairo_image_surface_t *
_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box);
/* Avoid unnecessary PLT entries. */
diff --git a/test/.cvsignore b/test/.cvsignore
index 3b5304218..27e57c1d4 100644
--- a/test/.cvsignore
+++ b/test/.cvsignore
@@ -3,8 +3,11 @@
Makefile
Makefile.in
fill_rule
+leaky_polygon
line_width
move_to_show_surface
+text_cache_crash
+text_rotate
*-out.png
*-diff.png
diff --git a/test/Makefile.am b/test/Makefile.am
index 2f80f9f89..e7fd3fd6b 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,17 +1,24 @@
# All new test cases go here
TESTS = \
fill_rule \
+leaky_polygon \
line_width \
-move_to_show_surface
+move_to_show_surface \
+text_cache_crash \
+text_rotate
# And all new test go here too. I really don't like having to repeat
# this list. Anyone know a good way to avoid it? Can I use a wildcard
# here?
EXTRA_DIST = \
fill_rule-ref.png \
+leaky_polygon-ref.png \
line_width-ref.png \
move_to_show_surface-ref.png
+# Once we can draw the text_rotate.c test case correctly, we should
+# create and add text_rotate-ref.png to the list of reference PNGs.
+
# This list is only for known bugs (not regressions). We do need to
# fix these before the next release, but they are expected to fail for
# now, so they don't need to hold up any new code commit.
@@ -20,8 +27,9 @@ move_to_show_surface-ref.png
# here. New failures due to local, uncommitted code changes are
# regression bugs that should not be listed here. Instead they should
# be fixed before the code is committed.
-XFAIL_TESTS = \
-move_to_show_surface
+XFAIL_TESTS = \
+move_to_show_surface \
+text_rotate
check_PROGRAMS = $(TESTS)
@@ -47,7 +55,10 @@ xmalloc.h
# time to break down and auto-generate the Makefile.am or something
# from autogen.sh. My, but this is painful...
fill_rule_SOURCES = fill_rule.c $(cairo_test_lib)
+leaky_polygon_SOURCES = leaky_polygon.c $(cairo_test_lib)
line_width_SOURCES = line_width.c $(cairo_test_lib)
move_to_show_surface_SOURCES = move_to_show_surface.c $(cairo_test_lib)
+text_cache_crash_SOURCES = text_cache_crash.c $(cairo_test_lib)
+text_rotate_SOURCES = text_rotate.c $(cairo_test_lib)
CLEANFILES = *-out.png *-diff.png
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 75327c892..2364570a2 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -23,8 +23,12 @@
* Author: Carl D. Worth <cworth@cworth.org>
*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
+#include <string.h>
#include "cairo_test.h"
@@ -127,10 +131,17 @@ cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
cairo_destroy (cr);
+ /* Skip image check for tests with no image (width,height == 0,0) */
+ if (test->width == 0 || test->height == 0) {
+ free (png_buf);
+ free (diff_buf);
+ return CAIRO_TEST_SUCCESS;
+ }
+
/* Then we've got a bunch of string manipulation and file I/O for the check */
srcdir = getenv ("srcdir");
if (!srcdir)
- srcdir = "";
+ srcdir = ".";
xasprintf (&png_name, "%s%s", test->name, CAIRO_TEST_PNG_SUFFIX);
xasprintf (&ref_name, "%s/%s%s", srcdir, test->name, CAIRO_TEST_REF_SUFFIX);
xasprintf (&diff_name, "%s%s", test->name, CAIRO_TEST_DIFF_SUFFIX);
diff --git a/test/cairo-test.h b/test/cairo-test.h
index 7062f029d..58936d568 100644
--- a/test/cairo-test.h
+++ b/test/cairo-test.h
@@ -26,6 +26,7 @@
#ifndef _CAIRO_TEST_H_
#define _CAIRO_TEST_H_
+#include <math.h>
#include <cairo.h>
typedef enum cairo_test_status {
diff --git a/test/cairo_test.c b/test/cairo_test.c
index 75327c892..2364570a2 100644
--- a/test/cairo_test.c
+++ b/test/cairo_test.c
@@ -23,8 +23,12 @@
* Author: Carl D. Worth <cworth@cworth.org>
*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
+#include <string.h>
#include "cairo_test.h"
@@ -127,10 +131,17 @@ cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
cairo_destroy (cr);
+ /* Skip image check for tests with no image (width,height == 0,0) */
+ if (test->width == 0 || test->height == 0) {
+ free (png_buf);
+ free (diff_buf);
+ return CAIRO_TEST_SUCCESS;
+ }
+
/* Then we've got a bunch of string manipulation and file I/O for the check */
srcdir = getenv ("srcdir");
if (!srcdir)
- srcdir = "";
+ srcdir = ".";
xasprintf (&png_name, "%s%s", test->name, CAIRO_TEST_PNG_SUFFIX);
xasprintf (&ref_name, "%s/%s%s", srcdir, test->name, CAIRO_TEST_REF_SUFFIX);
xasprintf (&diff_name, "%s%s", test->name, CAIRO_TEST_DIFF_SUFFIX);
diff --git a/test/cairo_test.h b/test/cairo_test.h
index 7062f029d..58936d568 100644
--- a/test/cairo_test.h
+++ b/test/cairo_test.h
@@ -26,6 +26,7 @@
#ifndef _CAIRO_TEST_H_
#define _CAIRO_TEST_H_
+#include <math.h>
#include <cairo.h>
typedef enum cairo_test_status {
diff --git a/test/fill-rule-ref.png b/test/fill-rule-ref.png
index 25442c049..e2e10d4a8 100644
--- a/test/fill-rule-ref.png
+++ b/test/fill-rule-ref.png
Binary files differ
diff --git a/test/fill-rule.c b/test/fill-rule.c
index 40ab9a123..037a044ab 100644
--- a/test/fill-rule.c
+++ b/test/fill-rule.c
@@ -42,22 +42,39 @@
* planning on doing the new tessellator which should fix this
* problem.
*
+ * 2005-01-11 Carl Worth <cworth@cworth.org>
+ *
+ * Keith committed some fixes that fix the original size-20
+ * star_path:
+ *
+ * * src/cairo_wideint.c: (_cairo_int32x32_64_mul),
+ * (_cairo_int64x64_128_mul):
+ * * src/cairo_wideint.h:
+ * int32x32_64_mul and int64x64_128_mul are different from their
+ * unsigned compatriots
+ *
+ * 2005-01-12 Carl Worth <cworth@cworth.org>
+ *
+ * Going back to the SVG test suite, however, the original star
+ * shape is still broken. Adding both shapes now as little_star_path
+ * and big_star_path.
+ *
*/
#include "cairo_test.h"
-#define STAR_SIZE 20
+#define LITTLE_STAR_SIZE 20
+#define BIG_STAR_SIZE 80
cairo_test_t test = {
"fill_rule",
- "Tests cairo_set_full_rule with a star shape",
- STAR_SIZE * 2 + 3, STAR_SIZE +2
+ "Tests cairo_set_full_rule with some star shapes",
+ BIG_STAR_SIZE * 2 + 3, BIG_STAR_SIZE + LITTLE_STAR_SIZE + 3
};
-
-/* Not a perfect star, but one that does show the tessellation bug. */
+/* The SVG start trimmed down, but still showing the bug (originally) */
static void
-star_path (cairo_t *cr)
+little_star_path (cairo_t *cr)
{
cairo_move_to (cr, 10, 0);
cairo_rel_line_to (cr, 6, 20);
@@ -66,6 +83,19 @@ star_path (cairo_t *cr)
cairo_rel_line_to (cr, -16, 12);
}
+/* The star shape from the SVG test suite. This was is still buggy even after
+ we got little_star_path working. */
+static void
+big_star_path (cairo_t *cr)
+{
+ cairo_move_to (cr, 40, 0);
+ cairo_rel_line_to (cr, 25, 80);
+ cairo_rel_line_to (cr, -65, -50);
+ cairo_rel_line_to (cr, 80, 0);
+ cairo_rel_line_to (cr, -65, 50);
+ cairo_close_path (cr);
+}
+
/* Fill the same path twice, once with each fill rule */
static void
draw (cairo_t *cr, int width, int height)
@@ -73,12 +103,22 @@ draw (cairo_t *cr, int width, int height)
cairo_set_rgb_color (cr, 1, 0, 0);
cairo_translate (cr, 1, 1);
- star_path (cr);
+ little_star_path (cr);
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
+ cairo_fill (cr);
+
+ cairo_translate (cr, LITTLE_STAR_SIZE + 1, 0);
+ little_star_path (cr);
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_fill (cr);
+
+ cairo_translate (cr, -(LITTLE_STAR_SIZE + 1), LITTLE_STAR_SIZE + 1);
+ big_star_path (cr);
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
cairo_fill (cr);
- cairo_translate (cr, STAR_SIZE + 1, 0);
- star_path (cr);
+ cairo_translate (cr, BIG_STAR_SIZE + 1, 0);
+ big_star_path (cr);
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
cairo_fill (cr);
}
diff --git a/test/fill_rule-ref.png b/test/fill_rule-ref.png
index 25442c049..e2e10d4a8 100644
--- a/test/fill_rule-ref.png
+++ b/test/fill_rule-ref.png
Binary files differ
diff --git a/test/fill_rule.c b/test/fill_rule.c
index 40ab9a123..037a044ab 100644
--- a/test/fill_rule.c
+++ b/test/fill_rule.c
@@ -42,22 +42,39 @@
* planning on doing the new tessellator which should fix this
* problem.
*
+ * 2005-01-11 Carl Worth <cworth@cworth.org>
+ *
+ * Keith committed some fixes that fix the original size-20
+ * star_path:
+ *
+ * * src/cairo_wideint.c: (_cairo_int32x32_64_mul),
+ * (_cairo_int64x64_128_mul):
+ * * src/cairo_wideint.h:
+ * int32x32_64_mul and int64x64_128_mul are different from their
+ * unsigned compatriots
+ *
+ * 2005-01-12 Carl Worth <cworth@cworth.org>
+ *
+ * Going back to the SVG test suite, however, the original star
+ * shape is still broken. Adding both shapes now as little_star_path
+ * and big_star_path.
+ *
*/
#include "cairo_test.h"
-#define STAR_SIZE 20
+#define LITTLE_STAR_SIZE 20
+#define BIG_STAR_SIZE 80
cairo_test_t test = {
"fill_rule",
- "Tests cairo_set_full_rule with a star shape",
- STAR_SIZE * 2 + 3, STAR_SIZE +2
+ "Tests cairo_set_full_rule with some star shapes",
+ BIG_STAR_SIZE * 2 + 3, BIG_STAR_SIZE + LITTLE_STAR_SIZE + 3
};
-
-/* Not a perfect star, but one that does show the tessellation bug. */
+/* The SVG start trimmed down, but still showing the bug (originally) */
static void
-star_path (cairo_t *cr)
+little_star_path (cairo_t *cr)
{
cairo_move_to (cr, 10, 0);
cairo_rel_line_to (cr, 6, 20);
@@ -66,6 +83,19 @@ star_path (cairo_t *cr)
cairo_rel_line_to (cr, -16, 12);
}
+/* The star shape from the SVG test suite. This was is still buggy even after
+ we got little_star_path working. */
+static void
+big_star_path (cairo_t *cr)
+{
+ cairo_move_to (cr, 40, 0);
+ cairo_rel_line_to (cr, 25, 80);
+ cairo_rel_line_to (cr, -65, -50);
+ cairo_rel_line_to (cr, 80, 0);
+ cairo_rel_line_to (cr, -65, 50);
+ cairo_close_path (cr);
+}
+
/* Fill the same path twice, once with each fill rule */
static void
draw (cairo_t *cr, int width, int height)
@@ -73,12 +103,22 @@ draw (cairo_t *cr, int width, int height)
cairo_set_rgb_color (cr, 1, 0, 0);
cairo_translate (cr, 1, 1);
- star_path (cr);
+ little_star_path (cr);
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
+ cairo_fill (cr);
+
+ cairo_translate (cr, LITTLE_STAR_SIZE + 1, 0);
+ little_star_path (cr);
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_fill (cr);
+
+ cairo_translate (cr, -(LITTLE_STAR_SIZE + 1), LITTLE_STAR_SIZE + 1);
+ big_star_path (cr);
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
cairo_fill (cr);
- cairo_translate (cr, STAR_SIZE + 1, 0);
- star_path (cr);
+ cairo_translate (cr, BIG_STAR_SIZE + 1, 0);
+ big_star_path (cr);
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
cairo_fill (cr);
}
diff --git a/test/leaky-polygon-ref.png b/test/leaky-polygon-ref.png
new file mode 100644
index 000000000..0daabe15a
--- /dev/null
+++ b/test/leaky-polygon-ref.png
Binary files differ
diff --git a/test/leaky-polygon.c b/test/leaky-polygon.c
new file mode 100644
index 000000000..39daf4ca3
--- /dev/null
+++ b/test/leaky-polygon.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+/* Bug history
+ *
+ * 2005-01-07 Carl Worth <cworth@cworth.org>
+ *
+ * Bug reported:
+ *
+ * From: Chris <fltk@functionalfuture.com>
+ * Subject: [cairo] Render to image buffer artifacts
+ * To: cairo@cairographics.org
+ * Date: Fri, 07 Jan 2005 02:22:28 -0500
+ *
+ * I've attached the code and image that shows this off. Scaling at
+ * different levels seems to change the corruption.
+ *
+ * For some reason there are artifacts in the alpha channel. I don't know
+ * if that's the only place, but the alpha channel looks bad.
+ *
+ * If you run the code and parse the attached image, directing stdout to a
+ * file, you can see in the lower left corner there are alpha values where
+ * it should be transparent.
+ * [...]
+ *
+ * 2005-01-11 Carl Worth <cworth@cworth.org>
+ *
+ * I trimmed the original test case down to the code that appears here.
+ *
+ */
+
+#include "cairo_test.h"
+
+#define WIDTH 21
+#define HEIGHT 21
+
+cairo_test_t test = {
+ "leaky_polygon",
+ "Exercises a corner case in the trapezoid rasterization in which pixels outside the trapezoids received a non-zero alpha",
+ WIDTH, HEIGHT
+};
+
+static void
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_scale (cr, 1.0/(1<<16), 1.0/(1<<16));
+
+ cairo_move_to (cr, 131072,39321);
+ cairo_line_to (cr, 1103072,1288088);
+ cairo_line_to (cr, 1179648,1294990);
+ cairo_close_path (cr);
+
+ cairo_fill (cr);
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/leaky_polygon-ref.png b/test/leaky_polygon-ref.png
new file mode 100644
index 000000000..0daabe15a
--- /dev/null
+++ b/test/leaky_polygon-ref.png
Binary files differ
diff --git a/test/leaky_polygon.c b/test/leaky_polygon.c
new file mode 100644
index 000000000..39daf4ca3
--- /dev/null
+++ b/test/leaky_polygon.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+/* Bug history
+ *
+ * 2005-01-07 Carl Worth <cworth@cworth.org>
+ *
+ * Bug reported:
+ *
+ * From: Chris <fltk@functionalfuture.com>
+ * Subject: [cairo] Render to image buffer artifacts
+ * To: cairo@cairographics.org
+ * Date: Fri, 07 Jan 2005 02:22:28 -0500
+ *
+ * I've attached the code and image that shows this off. Scaling at
+ * different levels seems to change the corruption.
+ *
+ * For some reason there are artifacts in the alpha channel. I don't know
+ * if that's the only place, but the alpha channel looks bad.
+ *
+ * If you run the code and parse the attached image, directing stdout to a
+ * file, you can see in the lower left corner there are alpha values where
+ * it should be transparent.
+ * [...]
+ *
+ * 2005-01-11 Carl Worth <cworth@cworth.org>
+ *
+ * I trimmed the original test case down to the code that appears here.
+ *
+ */
+
+#include "cairo_test.h"
+
+#define WIDTH 21
+#define HEIGHT 21
+
+cairo_test_t test = {
+ "leaky_polygon",
+ "Exercises a corner case in the trapezoid rasterization in which pixels outside the trapezoids received a non-zero alpha",
+ WIDTH, HEIGHT
+};
+
+static void
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_scale (cr, 1.0/(1<<16), 1.0/(1<<16));
+
+ cairo_move_to (cr, 131072,39321);
+ cairo_line_to (cr, 1103072,1288088);
+ cairo_line_to (cr, 1179648,1294990);
+ cairo_close_path (cr);
+
+ cairo_fill (cr);
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/line-width-ref.png b/test/line-width-ref.png
index 1490b1b42..ddcd929d8 100644
--- a/test/line-width-ref.png
+++ b/test/line-width-ref.png
Binary files differ
diff --git a/test/line_width-ref.png b/test/line_width-ref.png
index 1490b1b42..ddcd929d8 100644
--- a/test/line_width-ref.png
+++ b/test/line_width-ref.png
Binary files differ
diff --git a/test/text-cache-crash.c b/test/text-cache-crash.c
new file mode 100644
index 000000000..6ac3245a6
--- /dev/null
+++ b/test/text-cache-crash.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+/* Bug history
+ *
+ * 2004-11-04 Ned Konz <ned@squeakland.org>
+ *
+ * Reported bug on mailing list:
+ *
+ * From: Ned Konz <ned@squeakland.org>
+ * To: cairo@cairographics.org
+ * Date: Thu, 4 Nov 2004 09:49:38 -0800
+ * Subject: [cairo] getting assertions [cairo_cache.c:143: _entry_destroy:
+ * Assertion `cache->used_memory > entry->memory' failed]
+ *
+ * The attached program dies on me with the assert
+ *
+ * $ ./testCairo
+ * testCairo: cairo_cache.c:143: _entry_destroy: Assertion `cache->used_memory > entry->memory' failed.
+ *
+ * 2004-11-04 Carl Worth <cworth@cworth.org>
+ *
+ * I trimmed down Ned's example to the folllowing test while still
+ * maintaining the assertion.
+ *
+ * Oh, actually, it looks like I may have triggered something
+ * slightly different:
+ *
+ * text_cache_crash: cairo_cache.c:422: _cairo_cache_lookup: Assertion `cache->max_memory >= (cache->used_memory + new_entry->memory)' failed.
+ *
+ * I'll have to go back and try the original test after I fix this.
+ *
+ * 2004-11-13 Carl Worth <cworth@cworth.org>
+ *
+ * Found the bug. cairo_gstate_select_font was noticing when the
+ * same font was selected twice in a row and was erroneously failing
+ * to free the old reference. Committed a fix and verified it also
+ * fixed the orginal test case.
+ */
+
+#include "cairo_test.h"
+
+cairo_test_t test = {
+ "text_cache_crash",
+ "Test case for bug causing an assertion failure in _cairo_cache_lookup",
+ 0, 0,
+};
+#include <cairo.h>
+
+static void
+draw (cairo_t *cr, int width, int height)
+{
+ /* Once there was a bug that choked when selecting the same font twice. */
+ cairo_select_font(cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_scale_font(cr, 40.0);
+
+ cairo_select_font(cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_scale_font(cr, 40.0);
+ cairo_move_to(cr, 10, 50);
+ cairo_show_text(cr, "hello");
+
+ /* Then there was a bug that choked when selecting a font too big
+ * for the cache. */
+
+/* XXX: Sometimes this leads to an assertion:
+
+_cairo_cache_lookup: Assertion `cache->max_memory >= (cache->used_memory + new_entry->memory)' failed.
+Aborted
+
+ But other times my machine hangs completely only to return to life
+ several minutes later with some programs missing. This seems like
+ the out-of-memory killer to me.
+
+ It seems like I usually get the assertion when I run
+ ./text_cache_crash directly and I usually get the machine hang when
+ I run "make check" but I don't know if there's a perfect
+ correlation there.
+
+ So there's a bad bug here somewhere that really needs to be fixed.
+ But in the meantime, I need "make check" not to destory work, so
+ I'm commenting this test out for now.
+
+ cairo_scale_font (cr, 500);
+ cairo_show_text (cr, "hello");
+*/
+}
+
+int
+main (void)
+{
+ int ret;
+
+ ret = cairo_test (&test, draw);
+
+ /* It's convenient to be able to free all memory (including
+ * statically allocated memory). This makes it quite easy to use
+ * tools such as valgrind to verify that there are no memory leaks
+ * whatsoever.
+ *
+ * But I'm not sure what would be a sensible cairo API function
+ * for this. The cairo_destroy_caches call below is just something
+ * I made as a local modification to cairo.
+ */
+ /*
+ cairo_destroy_caches ();
+ FcFini ();
+ */
+
+ return ret;
+}
+
diff --git a/test/text-rotate.c b/test/text-rotate.c
new file mode 100644
index 000000000..c08c402cf
--- /dev/null
+++ b/test/text-rotate.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+/* Bug history
+ *
+ * 2004-11-03 Steve Chaplin <stevech1097@yahoo.com.au>
+ *
+ * Reported bug on mailing list:
+ *
+ * From: Steve Chaplin <stevech1097@yahoo.com.au>
+ * To: cairo@cairographics.org
+ * Date: Thu, 04 Nov 2004 00:00:17 +0800
+ * Subject: [cairo] Rotated text bug on drawable target
+ *
+ * The attached file draws text rotated 90 degrees first to a PNG file and
+ * then to a drawable. The PNG file looks fine, the text on the drawable is
+ * unreadable.
+ *
+ * Steve
+ *
+ * 2004-11-03 Carl Worth <cworth@cworth.org>
+ *
+ * Looks like the major problems with this bg appeared in the great
+ * font rework between 0.1.23 and 0.2.0. And it looks like we need
+ * to fix the regression test suite to test the xlib target (since
+ * the bug does not show up in the png backend).
+ *
+ * Hmm... Actually, things don't look perfect even in the PNG
+ * output. Look at how that 'o' moves around. It's particularly off
+ * in the case where it's rotated by PI.
+ *
+ * And I'm still not sure about what to do for test cases with
+ * text--a new version of freetype will change everything. We may
+ * need to add a simple backend for stroked fonts and add a simple
+ * builtin font to cairo for pixel-perfect tests with text.
+ */
+
+#include "cairo_test.h"
+
+#define WIDTH 150
+#define HEIGHT 150
+#define NUM_TEXT 20
+#define TEXT_SIZE 12
+
+cairo_test_t test = {
+ "text_rotate",
+ "Tests show_text under various rotations",
+ WIDTH, HEIGHT
+};
+
+/* Draw the word cairo at NUM_TEXT different angles */
+static void
+draw (cairo_t *cr, int width, int height)
+{
+ int i, x_off, y_off;
+ cairo_text_extents_t extents;
+ static char text[] = "cairo";
+
+ cairo_select_font (cr, "Bitstream Vera Sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_scale_font (cr, TEXT_SIZE);
+
+ cairo_set_rgb_color (cr, 0,0,0);
+
+ cairo_translate (cr, WIDTH/2.0, HEIGHT/2.0);
+
+ cairo_text_extents (cr, text, &extents);
+
+ if (NUM_TEXT == 1) {
+ x_off = y_off = 0;
+ } else {
+ y_off = - round (extents.height / 2.0);
+ x_off = round ((extents.height+1) / (2 * tan (M_PI/NUM_TEXT)));
+ }
+
+ for (i=0; i < NUM_TEXT; i++) {
+ cairo_save (cr);
+ cairo_rotate (cr, 2*M_PI*i/NUM_TEXT);
+ cairo_set_line_width (cr, 1.0);
+ cairo_rectangle (cr, x_off - 0.5, y_off - 0.5, extents.width + 1, extents.height + 1);
+ cairo_set_rgb_color (cr, 1, 0, 0);
+ cairo_stroke (cr);
+ cairo_move_to (cr, x_off - extents.x_bearing, y_off - extents.y_bearing);
+ cairo_set_rgb_color (cr, 0, 0, 0);
+ cairo_show_text (cr, "cairo");
+ cairo_restore (cr);
+ }
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/text_cache_crash.c b/test/text_cache_crash.c
new file mode 100644
index 000000000..6ac3245a6
--- /dev/null
+++ b/test/text_cache_crash.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+/* Bug history
+ *
+ * 2004-11-04 Ned Konz <ned@squeakland.org>
+ *
+ * Reported bug on mailing list:
+ *
+ * From: Ned Konz <ned@squeakland.org>
+ * To: cairo@cairographics.org
+ * Date: Thu, 4 Nov 2004 09:49:38 -0800
+ * Subject: [cairo] getting assertions [cairo_cache.c:143: _entry_destroy:
+ * Assertion `cache->used_memory > entry->memory' failed]
+ *
+ * The attached program dies on me with the assert
+ *
+ * $ ./testCairo
+ * testCairo: cairo_cache.c:143: _entry_destroy: Assertion `cache->used_memory > entry->memory' failed.
+ *
+ * 2004-11-04 Carl Worth <cworth@cworth.org>
+ *
+ * I trimmed down Ned's example to the folllowing test while still
+ * maintaining the assertion.
+ *
+ * Oh, actually, it looks like I may have triggered something
+ * slightly different:
+ *
+ * text_cache_crash: cairo_cache.c:422: _cairo_cache_lookup: Assertion `cache->max_memory >= (cache->used_memory + new_entry->memory)' failed.
+ *
+ * I'll have to go back and try the original test after I fix this.
+ *
+ * 2004-11-13 Carl Worth <cworth@cworth.org>
+ *
+ * Found the bug. cairo_gstate_select_font was noticing when the
+ * same font was selected twice in a row and was erroneously failing
+ * to free the old reference. Committed a fix and verified it also
+ * fixed the orginal test case.
+ */
+
+#include "cairo_test.h"
+
+cairo_test_t test = {
+ "text_cache_crash",
+ "Test case for bug causing an assertion failure in _cairo_cache_lookup",
+ 0, 0,
+};
+#include <cairo.h>
+
+static void
+draw (cairo_t *cr, int width, int height)
+{
+ /* Once there was a bug that choked when selecting the same font twice. */
+ cairo_select_font(cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_scale_font(cr, 40.0);
+
+ cairo_select_font(cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_scale_font(cr, 40.0);
+ cairo_move_to(cr, 10, 50);
+ cairo_show_text(cr, "hello");
+
+ /* Then there was a bug that choked when selecting a font too big
+ * for the cache. */
+
+/* XXX: Sometimes this leads to an assertion:
+
+_cairo_cache_lookup: Assertion `cache->max_memory >= (cache->used_memory + new_entry->memory)' failed.
+Aborted
+
+ But other times my machine hangs completely only to return to life
+ several minutes later with some programs missing. This seems like
+ the out-of-memory killer to me.
+
+ It seems like I usually get the assertion when I run
+ ./text_cache_crash directly and I usually get the machine hang when
+ I run "make check" but I don't know if there's a perfect
+ correlation there.
+
+ So there's a bad bug here somewhere that really needs to be fixed.
+ But in the meantime, I need "make check" not to destory work, so
+ I'm commenting this test out for now.
+
+ cairo_scale_font (cr, 500);
+ cairo_show_text (cr, "hello");
+*/
+}
+
+int
+main (void)
+{
+ int ret;
+
+ ret = cairo_test (&test, draw);
+
+ /* It's convenient to be able to free all memory (including
+ * statically allocated memory). This makes it quite easy to use
+ * tools such as valgrind to verify that there are no memory leaks
+ * whatsoever.
+ *
+ * But I'm not sure what would be a sensible cairo API function
+ * for this. The cairo_destroy_caches call below is just something
+ * I made as a local modification to cairo.
+ */
+ /*
+ cairo_destroy_caches ();
+ FcFini ();
+ */
+
+ return ret;
+}
+
diff --git a/test/text_rotate.c b/test/text_rotate.c
new file mode 100644
index 000000000..c08c402cf
--- /dev/null
+++ b/test/text_rotate.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2004 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+/* Bug history
+ *
+ * 2004-11-03 Steve Chaplin <stevech1097@yahoo.com.au>
+ *
+ * Reported bug on mailing list:
+ *
+ * From: Steve Chaplin <stevech1097@yahoo.com.au>
+ * To: cairo@cairographics.org
+ * Date: Thu, 04 Nov 2004 00:00:17 +0800
+ * Subject: [cairo] Rotated text bug on drawable target
+ *
+ * The attached file draws text rotated 90 degrees first to a PNG file and
+ * then to a drawable. The PNG file looks fine, the text on the drawable is
+ * unreadable.
+ *
+ * Steve
+ *
+ * 2004-11-03 Carl Worth <cworth@cworth.org>
+ *
+ * Looks like the major problems with this bg appeared in the great
+ * font rework between 0.1.23 and 0.2.0. And it looks like we need
+ * to fix the regression test suite to test the xlib target (since
+ * the bug does not show up in the png backend).
+ *
+ * Hmm... Actually, things don't look perfect even in the PNG
+ * output. Look at how that 'o' moves around. It's particularly off
+ * in the case where it's rotated by PI.
+ *
+ * And I'm still not sure about what to do for test cases with
+ * text--a new version of freetype will change everything. We may
+ * need to add a simple backend for stroked fonts and add a simple
+ * builtin font to cairo for pixel-perfect tests with text.
+ */
+
+#include "cairo_test.h"
+
+#define WIDTH 150
+#define HEIGHT 150
+#define NUM_TEXT 20
+#define TEXT_SIZE 12
+
+cairo_test_t test = {
+ "text_rotate",
+ "Tests show_text under various rotations",
+ WIDTH, HEIGHT
+};
+
+/* Draw the word cairo at NUM_TEXT different angles */
+static void
+draw (cairo_t *cr, int width, int height)
+{
+ int i, x_off, y_off;
+ cairo_text_extents_t extents;
+ static char text[] = "cairo";
+
+ cairo_select_font (cr, "Bitstream Vera Sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_scale_font (cr, TEXT_SIZE);
+
+ cairo_set_rgb_color (cr, 0,0,0);
+
+ cairo_translate (cr, WIDTH/2.0, HEIGHT/2.0);
+
+ cairo_text_extents (cr, text, &extents);
+
+ if (NUM_TEXT == 1) {
+ x_off = y_off = 0;
+ } else {
+ y_off = - round (extents.height / 2.0);
+ x_off = round ((extents.height+1) / (2 * tan (M_PI/NUM_TEXT)));
+ }
+
+ for (i=0; i < NUM_TEXT; i++) {
+ cairo_save (cr);
+ cairo_rotate (cr, 2*M_PI*i/NUM_TEXT);
+ cairo_set_line_width (cr, 1.0);
+ cairo_rectangle (cr, x_off - 0.5, y_off - 0.5, extents.width + 1, extents.height + 1);
+ cairo_set_rgb_color (cr, 1, 0, 0);
+ cairo_stroke (cr);
+ cairo_move_to (cr, x_off - extents.x_bearing, y_off - extents.y_bearing);
+ cairo_set_rgb_color (cr, 0, 0, 0);
+ cairo_show_text (cr, "cairo");
+ cairo_restore (cr);
+ }
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}