summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Worth <cworth@cworth.org>2006-02-13 16:47:13 -0800
committerCarl Worth <cworth@cworth.org>2006-02-13 16:47:13 -0800
commit5de154bcdb659618d723bcec14e0315630c62c7e (patch)
tree462e5c5d5a444c9388da1d33de1399e2fa98c9ed
parent6c38e238e5daab5df4c11027d28e48e62bbd4bc8 (diff)
parentf030aec810d74a60a44c35bf7815b9e94743cd65 (diff)
Remove pixman from SNAPSHOT_0_5_0SNAPSHOT_0_5_0
-rw-r--r--ChangeLog2241
-rw-r--r--NEWS304
-rw-r--r--PORTING_GUIDE257
-rw-r--r--RELEASING14
-rw-r--r--ROADMAP80
-rw-r--r--TODO105
-rwxr-xr-xautogen.sh2
-rw-r--r--configure.in154
-rw-r--r--doc/public/Makefile.am17
-rw-r--r--doc/public/cairo-docs.xml12
-rw-r--r--doc/public/cairo-sections.txt196
-rw-r--r--doc/public/language-bindings.xml726
-rw-r--r--doc/public/tmpl/cairo-atsui.sgml3
-rw-r--r--doc/public/tmpl/cairo-font.sgml148
-rw-r--r--doc/public/tmpl/cairo-ft.sgml26
-rw-r--r--doc/public/tmpl/cairo-glitz.sgml8
-rw-r--r--doc/public/tmpl/cairo-matrix.sgml69
-rw-r--r--doc/public/tmpl/cairo-pattern.sgml18
-rw-r--r--doc/public/tmpl/cairo-pdf.sgml20
-rw-r--r--doc/public/tmpl/cairo-png.sgml41
-rw-r--r--doc/public/tmpl/cairo-ps.sgml12
-rw-r--r--doc/public/tmpl/cairo-quartz.sgml10
-rw-r--r--doc/public/tmpl/cairo-surface.sgml72
-rw-r--r--doc/public/tmpl/cairo-xcb.sgml7
-rw-r--r--doc/public/tmpl/cairo-xlib.sgml25
-rw-r--r--doc/public/tmpl/cairo.sgml363
-rw-r--r--src/Makefile.am85
-rw-r--r--src/cairo-arc-private.h57
-rw-r--r--src/cairo-arc.c296
-rw-r--r--src/cairo-array.c139
-rw-r--r--src/cairo-atsui-font.c1215
-rw-r--r--src/cairo-atsui.h8
-rw-r--r--src/cairo-cache.c11
-rw-r--r--src/cairo-color.c120
-rw-r--r--src/cairo-features.h.in24
-rw-r--r--src/cairo-font.c954
-rw-r--r--src/cairo-ft-font.c962
-rw-r--r--src/cairo-ft-private.h4
-rw-r--r--src/cairo-ft.h24
-rw-r--r--src/cairo-glitz-surface.c1106
-rw-r--r--src/cairo-glitz.h9
-rw-r--r--src/cairo-gstate-private.h80
-rw-r--r--src/cairo-gstate.c2118
-rw-r--r--src/cairo-hash.c11
-rw-r--r--src/cairo-image-surface.c142
-rw-r--r--src/cairo-matrix.c461
-rw-r--r--src/cairo-output-stream.c285
-rw-r--r--src/cairo-path-bounds.c16
-rw-r--r--src/cairo-path-data-private.h55
-rw-r--r--src/cairo-path-data.c422
-rw-r--r--src/cairo-path-fill.c20
-rw-r--r--src/cairo-path-fixed-private.h74
-rw-r--r--src/cairo-path-stroke.c34
-rw-r--r--src/cairo-path.c389
-rw-r--r--src/cairo-pattern.c449
-rw-r--r--src/cairo-pdf-surface.c1139
-rw-r--r--src/cairo-pdf.h33
-rw-r--r--src/cairo-pen.c6
-rw-r--r--src/cairo-png.c465
-rw-r--r--src/cairo-private.h51
-rw-r--r--src/cairo-ps-surface.c323
-rw-r--r--src/cairo-ps.h32
-rw-r--r--src/cairo-quartz-surface.c403
-rw-r--r--src/cairo-quartz.h11
-rw-r--r--src/cairo-surface.c589
-rw-r--r--src/cairo-traps.c99
-rw-r--r--src/cairo-unicode.c28
-rw-r--r--src/cairo-wideint.h12
-rw-r--r--src/cairo-win32-font.c602
-rw-r--r--src/cairo-win32-surface.c239
-rw-r--r--src/cairo-win32.h26
-rw-r--r--src/cairo-xcb-surface.c613
-rw-r--r--src/cairo-xcb-xrender.h (renamed from src/cairo_fixed.c)67
-rw-r--r--src/cairo-xcb.h27
-rw-r--r--src/cairo-xlib-surface.c770
-rw-r--r--src/cairo-xlib-test.h (renamed from src/cairo-png.h)27
-rw-r--r--src/cairo-xlib-xrender.h (renamed from src/cairo_color.c)69
-rw-r--r--src/cairo-xlib.h43
-rw-r--r--src/cairo.c1426
-rw-r--r--src/cairo.h862
-rw-r--r--src/cairo_array.c134
-rw-r--r--src/cairo_atsui_font.c807
-rw-r--r--src/cairo_cache.c518
-rw-r--r--src/cairo_font.c476
-rw-r--r--src/cairo_ft_font.c1538
-rw-r--r--src/cairo_glitz_surface.c1317
-rw-r--r--src/cairo_gstate.c2566
-rw-r--r--src/cairo_hull.c202
-rw-r--r--src/cairo_image_surface.c675
-rw-r--r--src/cairo_matrix.c645
-rw-r--r--src/cairo_path.c495
-rw-r--r--src/cairo_path_bounds.c182
-rw-r--r--src/cairo_path_fill.c206
-rw-r--r--src/cairo_path_stroke.c848
-rw-r--r--src/cairo_pattern.c1325
-rw-r--r--src/cairo_pdf_surface.c2222
-rw-r--r--src/cairo_pen.c587
-rw-r--r--src/cairo_png_surface.c425
-rw-r--r--src/cairo_polygon.c172
-rw-r--r--src/cairo_ps_surface.c443
-rw-r--r--src/cairo_quartz_surface.c392
-rw-r--r--src/cairo_slope.c103
-rw-r--r--src/cairo_spline.c288
-rw-r--r--src/cairo_surface.c708
-rw-r--r--src/cairo_traps.c740
-rw-r--r--src/cairo_unicode.c340
-rw-r--r--src/cairo_wideint.c1024
-rw-r--r--src/cairo_win32_font.c1252
-rw-r--r--src/cairo_win32_surface.c931
-rw-r--r--src/cairo_xcb_surface.c978
-rw-r--r--src/cairo_xlib_surface.c1530
-rw-r--r--src/cairoint.h1054
-rw-r--r--test/.cvsignore54
-rw-r--r--test/Makefile.am205
-rw-r--r--test/buffer-diff.c105
-rw-r--r--test/buffer-diff.h22
-rw-r--r--test/buffer_diff.c73
-rw-r--r--test/buffer_diff.h38
-rw-r--r--test/cairo-test.c533
-rw-r--r--test/cairo-test.h12
-rw-r--r--test/cairo_test.c247
-rw-r--r--test/clip-nesting-ref.pngbin0 -> 1050 bytes
-rw-r--r--test/clip-nesting.c98
-rw-r--r--test/clip-twice.c11
-rw-r--r--test/clip_twice-ref.pngbin751 -> 0 bytes
-rw-r--r--test/coverage-ref.pngbin44324 -> 0 bytes
-rw-r--r--test/create-for-png-ref.png (renamed from test/move_to_show_surface-ref.png)bin100 -> 100 bytes
-rw-r--r--test/create-for-png.c69
-rw-r--r--test/create-from-png-ref.pngbin0 -> 100 bytes
-rw-r--r--test/create-from-png.c69
-rw-r--r--test/fill-and-stroke-ref.pngbin0 -> 279 bytes
-rw-r--r--test/fill-and-stroke.c63
-rw-r--r--test/fill-rule.c10
-rw-r--r--test/fill_rule-ref.pngbin1979 -> 0 bytes
-rw-r--r--test/fill_rule.c130
-rw-r--r--test/filter-nearest-offset-ref.pngbin0 -> 254 bytes
-rw-r--r--test/filter-nearest-offset.c107
-rw-r--r--test/get-and-set.c142
-rw-r--r--test/gradient-alpha-ref.pngbin0 -> 153 bytes
-rw-r--r--test/gradient-alpha.c (renamed from test/cairo_test.h)68
-rw-r--r--test/imagediff.c8
-rw-r--r--test/leaky-polygon.c8
-rw-r--r--test/leaky_polygon-ref.pngbin255 -> 0 bytes
-rw-r--r--test/line-width.c10
-rw-r--r--test/line_width-ref.pngbin171 -> 0 bytes
-rw-r--r--test/linear-gradient.c42
-rw-r--r--test/linear_gradient-ref.pngbin12724 -> 0 bytes
-rw-r--r--test/linear_gradient.c141
-rw-r--r--test/mask-ref.pngbin0 -> 87846 bytes
-rw-r--r--test/mask.c246
-rw-r--r--test/move-to-show-surface.c30
-rw-r--r--test/paint-ref.pngbin0 -> 116 bytes
-rw-r--r--test/paint-with-alpha-ref.pngbin0 -> 164 bytes
-rw-r--r--test/paint-with-alpha.c (renamed from test/move_to_show_surface.c)53
-rw-r--r--test/paint.c (renamed from test/line_width.c)36
-rw-r--r--test/path-data-ref.pngbin0 -> 387 bytes
-rw-r--r--test/path-data.c184
-rw-r--r--test/pdf-surface.c115
-rw-r--r--test/pixman-rotate.c56
-rw-r--r--test/pixman_rotate-ref.pngbin260 -> 0 bytes
-rw-r--r--test/pixman_rotate.c78
-rw-r--r--test/ps-surface.c115
-rw-r--r--test/read-png.c35
-rw-r--r--test/read_png.c166
-rw-r--r--test/read_png.h45
-rw-r--r--test/rel-path-ref.pngbin0 -> 212 bytes
-rw-r--r--test/rel-path.c56
-rw-r--r--test/scale-source-surface-paint-ref.pngbin0 -> 147 bytes
-rw-r--r--test/scale-source-surface-paint.c64
-rw-r--r--test/select-font-no-show-text.c64
-rw-r--r--test/self-copy-ref.pngbin0 -> 291 bytes
-rw-r--r--test/self-copy.c90
-rw-r--r--test/set-source-ref.pngbin0 -> 120 bytes
-rw-r--r--test/set-source.c87
-rw-r--r--test/source-clip-ref.pngbin0 -> 180 bytes
-rw-r--r--test/source-clip.c84
-rw-r--r--test/source-surface-scale-paint-ref.pngbin0 -> 147 bytes
-rw-r--r--test/source-surface-scale-paint.c64
-rw-r--r--test/surface-finish-twice.c74
-rw-r--r--test/surface-pattern-ref.pngbin0 -> 194 bytes
-rw-r--r--test/surface-pattern.c (renamed from test/clip_twice.c)64
-rwxr-xr-xtest/testsvg4
-rw-r--r--test/text-cache-crash.c26
-rw-r--r--test/text-rotate.c25
-rw-r--r--test/text_cache_crash.c133
-rw-r--r--test/text_rotate.c117
-rw-r--r--test/transforms-ref.pngbin0 -> 302 bytes
-rw-r--r--test/transforms.c111
-rw-r--r--test/translate-show-surface-ref.pngbin0 -> 100 bytes
-rw-r--r--test/translate-show-surface.c (renamed from test/leaky_polygon.c)69
-rw-r--r--test/trap-clip-ref.pngbin0 -> 71701 bytes
-rw-r--r--test/trap-clip.c (renamed from test/coverage.c)158
-rw-r--r--test/user-data.c82
-rw-r--r--test/write-png.c4
-rw-r--r--test/write-png.h2
-rw-r--r--test/write_png.c99
-rw-r--r--test/write_png.h35
-rw-r--r--test/xlib-surface.c269
-rw-r--r--test/xmalloc.c5
-rw-r--r--test/xmalloc.h2
-rwxr-xr-xutil/cairo-api-update60
201 files changed, 19669 insertions, 33188 deletions
diff --git a/ChangeLog b/ChangeLog
index abf671a09..55cb2b9e9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,2244 @@
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * PORTING_GUIDE: Added porting guide to help with transition to
+ cairo 0.5 API.
+
+ * NEWS: Added notes for snapshot 0.5.0
+
+ * configure.in: Increment CAIRO_VERSION to 0.5.0
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-xcb-surface.c: (_get_image_surface),
+ (_cairo_xcb_surface_create_internal): Bring up to date with
+ Keith's latest improvements to cairo-xlib-surface.c: Add some
+ comments about how and why masks are computed. Generalize
+ overflow detection in mask computation. Expand on pixman format
+ conversion comment. Fix the broken visual->format case.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ Two fixes from Kristian Høgsberg:
+
+ * src/cairo-output-stream.c: (_cairo_output_stream_create),
+ (_cairo_output_stream_destroy),
+ (_cairo_output_stream_create_for_file): Fix to close the file if
+ we opened it.
+
+ * src/cairo-pdf-surface.c: (_cairo_pdf_document_finish): Grab the
+ status from out of the stream _before_ we destroy the stream.
+
+2005-05-17 Keith Packard <keithp@keithp.com>
+
+ * src/cairo-xlib-surface.c: (_get_image_surface):
+ Add some comments about how and why masks are computed.
+ Generalize overflow detection in mask computation.
+ Expand on pixman format conversion comment.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-xcb-surface.c:
+ * src/cairo-xlib-surface.c: Fix documentation to not mention
+ set_size for the _for_bitmap functions.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * util/cairo-api-update: Remove #ifdef munging since we once again
+ support either #if or #ifdef.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * RELEASING: Update instructions to match output of 'make
+ distcheck'
+
+ * src/Makefile.am:
+ * test/Makefile.am: Add private headers and flesh out CLEANFILES
+ so that 'make distcheck' actually passes.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.h: Add a few more REPLACED_BY and DEPRECATED_BY
+ definitions.
+
+ * util/cairo-api-update: Add some helpful warnings.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * src/Makefile.am (libcairo_xlib_headers): Add
+ cairo-xlib-xrender.h which was missed from an earlier commit.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * src/Makefile.am:
+ * src/cairo-xcb.h:
+ * src/cairo-xcb-xrender.h:
+ * src/cairo-xcb-surface.c:
+ (cairo_xcb_surface_create),
+ (cairo_xcb_surface_create_for_bitmap),
+ (cairo_xcb_surface_create_with_xrender_format): Update cairo-xcb.h
+ to provide the same style of interface as cairo-xlib.h.
+
+ * test/cairo-test.c: Update to match new cairo_xcb_surface_t
+ create functions.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-xlib-surface.c (_get_image_surface): Avoid shifting
+ 32-bit quanity by 32 bits, which is undefined behavior.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ Rework of cairo_xlib_surface create functions by Keith Packard:
+
+ * src/cairo-xlib-xrender.h:
+ Add cairo_xlib_surface_create_with_render_format.
+
+ * src/cairo-xlib.h:
+ * src/cairo-xlib-surface.c:
+ (cairo_xlib_surface_create),
+ (cairo_xlib_surface_create_for_bitmap): Reduce Xlib constructors
+ down to two simple forms. Add width, height to constructors and
+ eliminate any synchronous size queries from the implementation.
+
+ * test/cairo-test.c: (create_xlib_surface):
+ * test/xlib-surface.c: (do_test): Update to match new
+ cairo_xlib_surface_t create functions.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * src/cairoint.h:
+ * src/cairo-output-stream.c: Remove destroy_closure from
+ cairo_output_stream_t interface.
+
+ * src/cairo-pdf.h:
+ * src/cairo-pdf-surface.c: Remove destroy_closure argument from
+ cairo_pdf_surface_create_for_stream. Rename width,height to
+ width_in_points, height_in_points for better clarity.
+
+ * src/cairo-ps.h:
+ * src/cairo-ps-surface.c: Brush a bunch of dust off of the PS
+ backend and bring it up to date with the latest API conventions
+ from the PDF backend. These include: accepting a filename rather
+ than a FILE in the primary constructor, providing a stream-based
+ interface for more flexibility, and accepting a surface size in
+ device-space units (points) rather than inches.
+
+ * test/pdf-surface.c: (main): Make it a little more clear that the
+ width and height being passed around are in units of points.
+
+ * test/ps-surface.c: (main): Update to the latest cairo-ps.h
+ changes as described above. Notice how much more sane things
+ become now that the surface size is described in device-space
+ units.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/ps-surface.c: (draw), (main): Add simple test for ps
+ surface backend (modeled after pdf-surface.c).
+
+ * test/pdf-surface.c: (main): Add print message telling user to
+ examine resulting file.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * test/pdf-surface.c: (draw), (main): Update PDF test case to make
+ sure we're actually getting the right paper size, image scaling
+ etc. And it should now be easier to see if cairo is happy by manually
+ viewing the resulting PDF file.
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-xlib-test.h: Fix to include cairo-xlib.h, (which also
+ fixes test/xlib-surface.c).
+
+2005-05-17 Carl Worth <cworth@cworth.org>
+
+ * test/pdf-surface.c: (main): Update to the latest PDF surface API
+ changes: use filename not FILE* and use surface dimension in
+ points, not inches.
+
+2005-05-16 Keith Packard <keithp@keithp.com>
+
+ * src/cairo-pattern.c: (_cairo_pattern_shader_init):
+ Initialize op->stops[0].scale = 0.
+
+ This scale value is used only when computing gradient values
+ before the defined range, in which case stop 0 is used for both
+ ends of the interpolation, making the value of 'scale' not
+ actually matter, except that valgrind notices we're using
+ an undefined value.
+
+2005-05-16 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/Makefile.am: Remove quarter-over test name accidentally
+ added to Makefile.
+
+2005-05-16 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo-pdf-surface.c (cairo_pdf_surface_create):
+ * src/cairo-output-stream.c
+ (_cairo_output_stream_create_for_file): Take a filename instead of
+ a FILE pointer.
+
+2005-05-14 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-xcb.h:
+ * src/cairo-xcb-surface.c: (_cairo_xcb_surface_create_similar),
+ (_cairo_xcb_surface_finish), (_cairo_xcb_surface_get_size),
+ (_bits_per_pixel), (_bytes_per_line), (_get_image_surface),
+ (_draw_image_surface), (_cairo_xcb_surface_get_extents),
+ (_cairo_surface_is_xcb), (_cairo_xcb_surface_create_internal),
+ (cairo_xcb_surface_create_for_pixmap),
+ (cairo_xcb_surface_create_for_pixmap_with_visual),
+ (cairo_xcb_surface_create_for_window_with_visual),
+ (cairo_xcb_surface_set_size):
+ Brush the dust off the XCB backend and get it compiling and
+ working again. This patch makes the XCB surface API match that of
+ the Xlib surface API as of yesterday. But, it's already stale as
+ the Xlib API changed again. So we'll need one more revision of the
+ XCB backend before the next snapshot.
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/cairo-test.c: (create_xcb_surface), (cleanup_xcb):
+ * test/cairo-test.h: Add support for testing of the xcb backend as
+ well.
+
+2005-05-14 Carl Worth <cworth@cworth.org>
+
+ * test/cairo-test.c: (cairo_test_real):
+ * test/pdf-surface.c: (main):
+ * test/xlib-surface.c: (do_test), (main): Cleanup output a bit,
+ move verbose messages to test-specific log file.
+
+2005-05-14 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-xlib-surface.c: (cairo_xlib_surface_create_with_visual):
+ Fix the last commit so it actually compiles now.
+
+2005-05-14 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-xlib-surface.c: (cairo_test_xlib_disable_render),
+ (cairo_xlib_surface_create_with_visual)
+
+ * test/.cvsignore: Fix a few documentation typos in the recent
+ xlib surface rework.
+
+2005-05-14 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-atsui.h:
+ * src/cairo-ft.h:
+ * src/cairo-glitz.h:
+ * src/cairo-pdf.h:
+ * src/cairo-ps.h:
+ * src/cairo-quartz.h:
+ * src/cairo-win32.h:
+ * src/cairo-xcb.h:
+ * src/cairo-xlib.h: Add an #error if cairo-foo.h is included when
+ cairo was compiled without support for the foo backend.
+
+2005-05-14 Carl Worth <cworth@cworth.org>
+
+ * test/pdf-surface.c (main): Update for change in
+ cairo_pdf_surface_create which no longer accepts DPI values.
+
+2005-05-13 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-xlib-surface.c src/cairo-xlib.h
+ doc/public/cairo-sections.txt: Drop the _for_pixmap() and
+ _for_window() out of the create functions and use some lazy
+ cleverness to sniff the information out as needed.
+
+ * src/cairo-xlib-surface.c src/cairo-xlib-test.h Makefile.am:
+ add cairo_test_xlib_disable_render() to turn off RENDER
+ for tests.
+
+ * test/xlib-surface.c: Test various different types of
+ Xlib surface creation.
+
+ * src/cairo-xlib.h: Remove left-over include of Xrender.h.
+
+2005-05-13 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo-pdf-surface.c (_cairo_pdf_document_open_stream): Make
+ this a varg function and use the new
+ _cairo_output_stream_vprintf() function to format extra dict
+ contents.
+
+ * src/cairo-output-stream.c (_cairo_output_stream_vprintf):
+ Reimplement the printf logic so we can special case formatting of
+ doubles to be locale independent and trim trailing zeros.
+
+ * src/cairo-pdf-surface.c: Rename
+ cairo_pdf_surface_create_for_callback() to
+ cairo_pdf_surface_create_for_stream(), and change PDF constructors
+ to take width and height as points and move PPI setting to
+ cairo_pdf_surface_set_ppi()
+
+2005-05-13 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-xlib-surface.c (_cairo_xlib_surface_create_internal): Fix
+ misplaced goto.
+
+2005-05-12 Carl Worth <cworth@cworth.org>
+
+ * src/cairoint.h:
+ * src/cairo-image-surface.c: (_cairo_image_surface_create_with_masks):
+ Fix image->data to be unsigned
+
+ * src/cairo-glitz-surface.c: (_cairo_glitz_surface_get_image):
+ * src/cairo-image-surface.c:
+ (_cairo_image_surface_create_for_pixman_image),
+ * src/cairo-xlib-surface.c: (_get_image_surface),
+ (_draw_image_surface), (_xlib_glyphset_cache_create_entry):
+ Track change in signedness of data member/parameter.
+
+2005-05-12 Carl Worth <cworth@cworth.org>
+
+ Update xcb backend to compile after recent API changes:
+
+ * src/cairo-xcb-surface.c: (_cairo_xcb_surface_finish):
+ Fix missing return value.
+ (_cairo_xcb_surface_acquire_source_image): Remove calls to
+ non-existent cairo_surface functions.
+ (_cairo_xcb_surface_set_matrix): Update for new matrix member names.
+ (_cairo_xcb_surface_get_extents): Fix typo.
+
+2005-05-12 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/paint-with-alpha-ref.png:
+ * test/paint-with-alpha.c: (draw), (main): Add new test for bug in
+ cairo_paint_with_alpha not transforming the source.
+
+ * src/cairo-gstate.c: (_cairo_gstate_mask): Use a transformed copy
+ of the source just like we do in all the other calls to
+ cairo_surface_composite. Fixes the bug tested by
+ test/paint-with-alpha.
+
+2005-05-12 Keith Packard <keithp@keithp.com>
+
+ reviewed by: otaylor
+
+ * src/cairo-gstate.c: (_get_mask_extents):
+ _get_mask_extents creates a pixman region but
+ neglects to destroy it.
+
+2005-05-11 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-win32-surface.c (categorize_solid_dest_operator):
+ Handle more cases by assuming no-super-luminescent colors.
+
+2005-05-11 T Rowley <tim.rowley@gmail.com>
+
+ * src/cairo-atsui-font.c:
+ * src/cairo-atsui.h:
+ * src/cairo-quartz-surface.c: Revive quartz backend.
+
+2005-05-11 David Reveman <davidr@novell.com>
+
+ * src/cairo-glitz-surface.c (_cairo_glitz_surface_fill_rectangles):
+ Set fill type repeat on source surface.
+ (_cairo_glitz_surface_show_glyphs): Add missing cairo operator to
+ glitz operator conversion.
+ (_cairo_glitz_surface_show_glyphs): Only render glyphs with non zero
+ size.
+
+2005-05-11 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-surface.c (_fallback_fill_rectangles):
+ Fix bounding box computation.
+
+ * src/cairo-win32-surface.c: Patch from Tor Lillqvist
+ to make things compile and work again.
+
+ * test/cairo-test.c (create_win32_surface): Don't
+ #error because there is no win32 test, it isn't useful.
+ Just skip it.
+
+ * src/cairo-win32-font.c: Fix up matrix constness.
+
+ * test/Makefile.am (TESTS): Skip the pdf-surface test
+ if we don't have the PDF backend.
+
+ * src/cairo-win32-surface.c (categorize_solid_dest_operator):
+ Optimize fill_rectangles for all cases where the destination
+ ends up a solid color.
+
+2005-05-11 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-xlib-surface.c src/cairo-xlib.h: Remove leftover
+ cairo_xlib_surface_create().
+
+2005-05-10 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo.c src/cairo-path-data.c src/cairo-path-data-private.h:
+ Pass the gstate to _cairo_path_data_create[_flat] and use
+ _cairo_gstate_backend_to_user() so as to properly handle
+ the surface device offset.
+
+2005-05-10 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-arc.c (_cairo_arc_path_negative): Don't use return
+ when calling a void function (thanks to Damien Carbery
+ <damien.carbery@sun.com>). Closes bug #3134.
+
+2005-05-10 Carl Worth <cworth@cworth.org>
+
+ * test/cairo-test.c:
+ * test/cairo-test.h: Removing mucking around with stderr and add a
+ cairo_test_log function instead.
+
+ * test/buffer-diff.c:
+ * test/create-for-png.c:
+ * test/pdf-surface.c:
+ * test/read-png.c:
+ * test/trap-clip.c:
+ * test/xmalloc.c: Switch all error messages from
+ fprintf(stderr,...) to cairo_test_log(...).
+
+2005-05-10 Carl Worth <cworth@cworth.org>
+
+ * configure.in: Fix URLs for glitz and xlibs, (thanks to Jason
+ Dorje Short <jdorje@users.sf.net>).
+
+2005-05-10 Carl Worth <cworth@cworth.org>
+
+ * configure.in: Update to current canonical URL for XCB.
+
+2005-05-10 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-wideint.h: Don't guess and make our own definitions
+ for uint8_t, etc. Just error out if we can't find a suitable
+ header file.
+
+ * src/cairo-png.c: (unpremultiply_data), (premultiply_data):
+ * test/read-png.c: (premultiply_data): Fix to use fixed-size type
+ so that this code works when sizeof(unsigned long) != 32. Thanks
+ to Manish Singh.
+
+2005-05-10 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-gstate.c: (_cairo_gstate_get_font_matrix):
+ * src/cairo.c: (cairo_get_font_matrix):
+ * src/cairo.h:
+ * src/cairoint.h: Fix cairo_get_font_matrix to actually use its
+ out-parameter. And change the return type to void.
+
+2005-05-09 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-ft-font.c (_cairo_ft_unscaled_font_create_glyph):
+ Get the glyphslot point *after* we get the FT_Face. (Robert O'Callahan)
+
+2005-05-09 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.h (cairo_current_target_surface): Fix deprecation
+ macro to point to the right function, (thanks to John Ellson).
+
+2005-05-09 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-font.c: (_cairo_simple_font_face_create_font),
+ (cairo_scaled_font_create), (_cairo_scaled_font_init):
+ * src/cairo-ft-font.c: (_ft_scaled_font_create),
+ (_cairo_ft_scaled_font_create), (_ft_font_face_create_font):
+ * src/cairo-gstate.c: (_cairo_gstate_transform),
+ (_cairo_gstate_set_matrix), (_cairo_gstate_set_font_matrix):
+ * src/cairo-image-surface.c: (_cairo_image_surface_set_matrix):
+ * src/cairo-matrix.c: (_cairo_matrix_get_affine),
+ (cairo_matrix_transform_distance), (cairo_matrix_transform_point),
+ (_cairo_matrix_transform_bounding_box),
+ (_cairo_matrix_compute_determinant),
+ (_cairo_matrix_compute_eigen_values),
+ (_cairo_matrix_compute_scale_factors),
+ (_cairo_matrix_is_integer_translation):
+ * src/cairo-pattern.c: (cairo_pattern_set_matrix),
+ (_cairo_pattern_transform):
+ * src/cairo.c: (cairo_transform), (cairo_set_matrix),
+ (cairo_set_font_matrix):
+ * src/cairo.h:
+ * src/cairoint.h: Push cairo_matrix_t const-correctness down
+ through the entire implmentation, (expanding on preliminary work
+ by Robert O'Callahan <rocallahan@novell.com>)
+
+2005-05-09 Carl Worth <cworth@cworth.org>
+
+ * configure.in:
+ * src/cairo-features.h.in: Change cairo-features again so that
+ either #if or #ifdef will work to test any feature.
+
+2005-05-07 Owen Taylor <otaylor@redhat.com>
+
+ * doc/public/language-bindings.xml doc/public/cairo-doc.xml
+ doc/public/Makefile.am: Document suggested conventions and
+ techniques for many aspects of creating a language binding
+ for Cairo.
+
+2005-05-07 Owen Taylor <otaylor@redhat.com>
+
+ * doc/public/cairo-sections.txt: Update.
+
+2005-05-07 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.h (cairo_set_alpha): Point to both
+ cairo_set_source_rgba and cairo_paint_with_alpha in deprecation of
+ cairo_set_alpha.
+
+2005-05-07 Carl Worth <cworth@cworth.org>
+
+ * util/cairo-api-update: Make idempotent substitutions that extend
+ old names:
+
+ cairo_select_font -> cairo_select_font_face
+ cairo_pattern_add_color_stop -> cairo_pattern_add_color_stop_rgba
+
+ by only substituting if the old name is not immediately followed
+ by an underscore.
+
+ Tweak the substitution slightly to allow the script to be run on
+ the cairo source itself, (eg. avoid changing the REPLACED_BY and
+ DEPRECATED_BY macros that must mention the old names).
+
+2005-05-07 Carl Worth <cworth@cworth.org>
+
+ * configure.in:
+
+ * src/cairo-features.h.in: Change definitions of everything in
+ cairo-features.h to prefer #if over #ifdef.
+
+ * src/cairo-atsui.h:
+ * src/cairo-cache.c:
+ * src/cairo-ft-private.h:
+ * src/cairo-ft.h:
+ * src/cairo-glitz.h:
+ * src/cairo-pdf.h:
+ * src/cairo-ps.h:
+ * src/cairo-quartz.h:
+ * src/cairo-win32.h:
+ * src/cairo-xcb.h:
+ * src/cairo-xlib.h:
+ * src/cairo.c:
+ * src/cairo.h:
+ * src/cairoint.h:
+ * test/cairo-test.c: Track #ifdef -> #if changes.
+
+ * util/cairo-api-update: Add support to automatically change all
+ #ifdef CAIRO_HAS to #if CAIRO_HAS.
+
+2005-05-07 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-gstate.c:
+ * src/cairo-pattern.c:
+ * src/cairo.c:
+ * src/cairo.h:
+ * src/cairoint.h: Remove deprecated cairo_get_rgb_color that was
+ accidentally missed in the recent purge of deprecated functions.
+
+2005-05-07 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-xcb-surface.c (_render_operator):
+ * src/cairo-win32-surface.c (_cairo_win32_surface_composite)
+ (_cairo_win32_surface_fill_rectangles): Update to track new
+ CAIRO_OPERATOR names.
+
+ * test/select-font-no-show-text.c:
+ * src/cairo-surface.c (cairo_surface_set_user_data): Fix
+ documentation to refer to functions by their current names.
+
+ * src/cairo-gstate.c (_cairo_gstate_begin_group): Update to track
+ latest API (in currently unused function).
+
+2005-05-06 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-glitz-surface.c (_cairo_glitz_surface_show_glyphs):
+ Fix return type from cairo_status_t to cairo_int_status_t.
+
+2005-05-06 Carl Worth <cworth@cworth.org>
+
+ * ROADMAP: Note that cairo_mask, and "just eliminate a bunch of
+ functions are now done".
+
+ * TODO: Note that all backwards-compatible and
+ backwards-incompatible cahnges for the API Shakeup are now
+ done. Sort "new functionality" of API Shakeup into its own
+ category.
+
+2005-05-06 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.c:
+ * src/cairo.h: Eliminate the following deprecated functions from
+ cairo's interface:
+
+ cairo_copy
+ cairo_get_path
+ cairo_get_path_flat
+ cairo_matrix_create
+ cairo_matrix_destroy
+ cairo_matrix_copy
+ cairo_matrix_get_affine
+ cairo_surface_set_repeat
+ cairo_surface_set_matrix
+ cairo_surface_get_matrix
+ cairo_surface_set_filter
+ cairo_surface_get_filter
+
+ Also, eliminate all support for compiling against, or running with
+ old, deprecated names for functions.
+
+ * src/cairo-ft-font.c: (_compute_transform):
+ * src/cairo-gstate.c:
+ * src/cairo-image-surface.c: (cairo_image_surface_create_for_data):
+ * src/cairo-matrix.c: (_cairo_matrix_get_affine),
+ (_cairo_matrix_compute_adjoint),
+ (_cairo_matrix_is_integer_translation):
+ * src/cairo-pattern.c: (cairo_pattern_add_color_stop_rgba),
+ (cairo_pattern_set_matrix), (cairo_pattern_get_matrix),
+ (_cairo_image_data_set_linear), (_cairo_linear_pattern_classify),
+ (_cairo_image_data_set_radial):
+ * src/cairo-pdf-surface.c: (_cairo_pdf_surface_composite_image),
+ (_cairo_pdf_surface_composite_pdf), (emit_surface_pattern),
+ (emit_linear_pattern), (emit_radial_pattern):
+ * src/cairo-surface.c:
+ * src/cairo-xlib-surface.c:
+ (_cairo_xlib_surface_acquire_source_image),
+ (cairo_xlib_surface_create):
+ * src/cairo.c: (cairo_set_source_rgba), (cairo_set_source),
+ (cairo_get_source), (cairo_transform), (cairo_identity_matrix),
+ (cairo_user_to_device), (cairo_user_to_device_distance),
+ (cairo_device_to_user), (cairo_device_to_user_distance),
+ (cairo_reset_clip), (cairo_select_font_face), (cairo_font_extents),
+ (cairo_set_font_size), (cairo_get_operator), (cairo_get_rgb_color),
+ (cairo_get_tolerance), (cairo_get_fill_rule),
+ (cairo_get_line_width), (cairo_get_line_cap),
+ (cairo_get_line_join), (cairo_get_miter_limit), (cairo_get_matrix),
+ (cairo_get_target), (cairo_status), (cairo_status_string):
+ * src/cairoint.h:
+ * test/cairo-test.c: (cairo_test_create_png_pattern):
+ * test/gradient-alpha.c: (draw):
+ * test/mask.c: (set_gradient_pattern), (set_image_pattern):
+ * test/move-to-show-surface.c: (draw):
+ * test/select-font-no-show-text.c: (draw):
+ * test/set-source.c: (draw):
+ * test/text-cache-crash.c: (draw):
+ * test/text-rotate.c: (draw):
+ * test/transforms.c: (draw_L_shape):
+ * test/translate-show-surface.c: (draw):
+ * test/trap-clip.c: (set_gradient_pattern), (set_image_pattern):
+ * util/cairo-api-update:
+
+ Deal with all of the removals.
+
+2005-05-06 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-glitz-surface.c: (_glitz_operator),
+ (_cairo_glitz_surface_fill_rectangles):
+ * src/cairo-gstate.c: (_cairo_gstate_mask):
+ * src/cairo-image-surface.c: (_pixman_operator),
+ (_cairo_image_surface_composite_trapezoids):
+ * src/cairo-ps-surface.c: (_cairo_ps_surface_erase),
+ (_cairo_ps_surface_copy_page):
+ * src/cairo-surface.c: (_cairo_surface_create_similar_solid):
+ * src/cairo-xlib-surface.c: (_render_operator):
+ * src/cairo.h:
+ * test/cairo-test.c: (cairo_test_for_target):
+ * test/mask.c: (mask_polygon), (draw):
+
+ Rename and re-order the cairo_operator_t enum to names that
+ abbreviate less and are easier to understand,
+ (eg. CAIRO_OPERATOR_DEST_OVER instead of
+ CAIRO_OPEERATOR_OVER_REVERSE).
+
+2005-05-06 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.c: (cairo_create), (cairo_save), (cairo_get_target):
+ * src/cairo.h:
+ * src/cairoint.h:
+ * src/cairo-gstate.c: (_cairo_gstate_create), (_cairo_gstate_init),
+ (_cairo_gstate_get_target):
+ * src/cairo-glitz.h:
+ * src/cairo-pdf.h:
+ * src/cairo-ps.h:
+ * src/cairo-quartz-surface.c:
+ * src/cairo-quartz.h:
+ * src/cairo-surface.c: (_cairo_surface_begin):
+ * src/cairo-win32.h:
+ * src/cairo-xcb.h:
+ * src/cairo-xlib.h: Remove cairo_set_target_surface and all other
+ backend-specific cairo_set_target functions. Require a
+ cairo_surface_t* to call cairo_create.
+
+ * test/cairo-test.c: (create_image_surface), (cleanup_image),
+ (create_glitz_surface), (cleanup_glitz), (create_quartz_surface),
+ (cleanup_quartz), (create_win32_surface), (cleanup_win32),
+ (create_xcb_surface), (cleanup_xcb), (create_xlib_surface),
+ (cleanup_xlib), (cairo_test_for_target), (cairo_test_real):
+
+ Port to use new cairo_create interface.
+
+ * test/clip-nesting.c: (draw):
+ * test/mask.c: (mask_polygon), (draw):
+ * test/path-data.c: (main):
+ * test/pdf-surface.c: (main):
+ * test/pixman-rotate.c: (draw):
+ * test/scale-source-surface-paint.c: (draw):
+ * test/self-copy.c: (draw):
+ * test/source-clip.c: (draw):
+ * test/source-surface-scale-paint.c: (draw):
+ * test/surface-pattern.c: (draw):
+
+ Rewrite all tests that were using cairo_set_target_surface to
+ instead create a temporary cairo_t, (eventually to be replaced
+ with cairo_begin_group).
+
+2005-05-05 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo.[ch] doc/public/cairo-sections.txt: Add
+ cairo_paint_with_alpha().
+
+ * src/cairo-pattern.c (_cairo_pattern_acquire_surfaces): Fix
+ segfault when mask == NULL.
+
+ * test/mask.c test/mask-ref.png: Add testing of cairo_paint_with_alpha().
+
+ * test/coverage.c test/coverage-ref.png: Remove ... it's not testing
+ anything that mask doesn't test better.
+
+2005-05-04 David Reveman <davidr@novell.com>
+
+ * src/cairo-glitz-surface.c: Add glyph caching to glitz backend.
+
+2005-05-03 Kristian Høgsberg <krh@redhat.com>
+
+ Fills as paths patch originally by Owen Taylor.
+
+ * src/cairo-path.c: (_cairo_path_fixed_rel_move_to),
+ (_cairo_path_fixed_line_to), (_cairo_path_fixed_rel_line_to),
+ (_cairo_path_fixed_curve_to), (_cairo_path_fixed_rel_curve_to):
+ Make sure we have a current point for the relative path operators.
+
+ * src/cairoint.h:
+ * src/cairo-gstate.c: (_cairo_gstate_fill):
+ * src/cairo-surface.c: (_cairo_surface_fill_path): Add fill_path
+ backend method.
+
+ * src/cairo-pdf-surface.c: (_cairo_pdf_document_close_stream),
+ (emit_image_data), (emit_surface_pattern),
+ (_cairo_pdf_path_move_to), (_cairo_pdf_path_line_to),
+ (_cairo_pdf_path_curve_to), (_cairo_pdf_path_close_path),
+ (_cairo_pdf_surface_fill_path): Implement fill_path in the PDF
+ backend.
+
+2005-05-03 Carl Worth <cworth@cworth.org>
+
+ Originally 2005-04-20 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.h:
+ * src/cairo.c: Remove cairo_show_surface. Add new
+ cairo_set_source_surface.
+
+ * src/cairo-gstate.c: Remove _cairo_gstate_show_surface.
+
+ * test/create-for-png.c: (draw):
+ * test/pixman-rotate.c: (draw):
+ * test/move-to-show-surface.c: (draw):
+ * test/translate-show-surface.c: (draw): Replace calls to
+ cairo_show_surface with cairo_set_source_surface; cairo_paint.
+
+ * test/cairo-test.c: (cairo_test_real): Fix messages to prefer -
+ over _.
+
+ * src/cairo-png.c: (cairo_surface_write_to_png): Fix
+ documentation.
+
+ * test/filter-nearest-offset-ref.png:
+ * test/filter-nearest-offset.c:
+ * test/scale-source-surface-paint-ref.png:
+ * test/scale-source-surface-paint.c:
+ * test/source-surface-scale-paint-ref.png:
+ * test/source-surface-scale-paint.c: Three new tests to exercise
+ set_source_surface more completely, (two of these are expected
+ failures dues to outstanding bugs).
+
+2005-05-03 Carl Worth <cworth@cworth.org>
+
+ * TODO: Add suggestion for copy-on-write regions to fix clip
+ region problems.
+
+ * src/Makefile.am (install-data-local): Fix check for old headers
+ to respect DESTDIR, (to work better when cross-compiling, etc.).
+ Thanks to Luke-Jr <luke-jr@utopios.org>.
+
+2005-05-02 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-ft-font.c (_cairo_ft_scaled_font_font_extents): Changes the
+ sign of extents->descent to match win32 backend and the conventional
+ convention.
+
+ * src/cairo.h: Document cairo_font_extents_t.
+
+2005-04-28 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-surface.c src/cairoint.h: Add _cairo_surface_begin/end
+ to save and restore the clip state of a surface. Copy and store
+ clip regions set on a surface so that we can save and restore them.
+
+ * src/cairo.[ch]: Add a CAIRO_STATUS_BAD_NESTING error
+ for interleaved use of two cairo_t's on the same surface. Also,
+ add a skeleton doc comment for cairo_status_t.
+
+ * src/cairo.c src/cairo-gstate.c src/cairoint.h: Use
+ _cairo_surface_begin/end to replace
+ _cairo_gstate_restore_external_state.
+
+ * src/cairo-gstate.c: Use _cairo_surface_begin/end to save the
+ state of a surface when we start drawing at it and restore it
+ at the end. Check that the save level of the surface is what
+ we expect on drawing operations and fail with CAIRO_STATUS_BAD_NESTING
+ otherwise.
+
+ * src/cairo-pattern.c src/cairoint.h (_cairo_pattern_acquire_surface_for_surface)
+ (_cairo_pattern_release_surface): Surround use of pattern->surface
+ with _cairo_surface->begin/end so we don't clip surfaces used as
+ sources.
+
+ * test/clip-nesting.c test/Makefile.am: Test of destinatin
+ clipping with the nested creation of cairo_t's for the same
+ context.
+
+ * test/source-clip.c test/Makefile.am: Test that clipping on
+ a source as a destination doesn't affect use of it as a source.
+
+ * test/self-copy.c: XFAIL test for copying from a surface as
+ a source to itself as a destination with a clip.
+
+2005-05-02 Keith Packard <keithp@keithp.com>
+
+ reviewed by: cworth
+
+ * src/cairo-path.c: (_cairo_path_fixed_rel_curve_to):
+ Use correct arguments to compute absolute positions.
+
+ * test/Makefile.am:
+ * test/rel-path-ref.png:
+ * test/rel-path.c: (draw), (main):
+ Test cairo_rel_move_to, cairo_rel_line_to and cairo_rel_curve_to
+
+2005-05-02 Owen Taylor <otaylor@redhat.com>
+
+ * test/Makefile.am (EXTRA_DIST): mask-ref.png, not
+ mask.png. (Pointed out by Carl)
+
+2005-05-02 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo.[ch] src/cairo-gstate.c: Add cairo_mask()
+ and cairo_mask_surface().
+
+ * test/maks.c tests/Makefile.am tests/mask-ref.png: Add a
+ comprehensive tests for cairo_mask().
+
+ * docs/public/cairo-sections.txt: Updated
+
+2005-05-02 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo-gstate.c (_cairo_gstate_glyph_path): Also call
+ _cairo_gstate_ensure_font() for this function.
+
+2005-04-28 Owen Taylor <otaylor@redhat.com>
+
+ * TODO, ROADMAP: Add a item about reworking cairo_format_t.
+
+2005-04-28 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/cairo-test.c: (cairo_test_for_target): Replace annoying _
+ in output image filenames with - for better consistency.
+
+2005-04-27 Carl Worth <cworth@cworth.org>
+
+ * test/cairo-test.c: (set_xlib_target), (cleanup_xlib_target):
+ Use 1 instead of 0 for width and height to avoid BadValue errors
+ from XCreatePixmap.
+
+2005-04-27 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/buffer-diff.c: (xunlink), (buffer_diff), (image_diff):
+ * test/buffer-diff.h:
+ * test/cairo-test.c: (set_image_target), (cleanup_image_target),
+ (set_glitz_target), (cleanup_glitz_target), (set_quartz_target),
+ (cleanup_quartz_target), (set_win32_target),
+ (cleanup_win32_target), (set_xcb_target), (cleanup_xcb_target),
+ (set_xlib_target), (cleanup_xlib_target), (cairo_test_for_target),
+ (cairo_test_real), (cairo_test_expect_failure), (cairo_test):
+ * test/cairo-test.h:
+ * test/read-png.c: (read_png_argb32):
+ * test/xmalloc.h: Add support for testing multiple backends,
+ courtesy of cairo_surface_write_to_png. Currently, only image and
+ xlib backends are fullk hooked-up, but other backends should be
+ quite easy to add for anyone skilled in the appropriate art.
+
+2005-04-27 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-traps.c src/cairoint.h (_cairo_traps_init_box):
+ New function to create a single trapezoid box.
+
+ * src/cairo.c src/cairo-gstate.c src/cairoint.h: Move
+ the implementation of cairo_paint() into cairo-gstate.c
+ for a better fix for the problem with backend/user coordinate
+ confusion. Also no longer clear the current path on
+ cairo_paint().
+
+2005-04-26 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.c (cairo_paint): Build rectangle with an identity
+ matrix in place so that the entire target surface will be filled
+ even when there is a transformation in place.
+
+2005-04-26 Owen Taylor <otaylor@redhat.com>
+
+ * doc/public/cairo-sections.txt: Updated.
+
+ * src/cairo-png.c src/cairo.h: Fix up some doc build issues.
+
+2005-04-26 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/paint-ref.png:
+ * test/paint.c: (draw), (main): Add test to demonstrate bug in
+ cairo_paint when under a non-identity transformation.
+
+2005-04-26 Carl Worth <cworth@cworth.org>
+
+ * ROADMAP:
+ * TODO: Note that cairo_paint and cairo_clip/fill/stroke_preserve
+ are all done now.
+
+2005-04-26 Carl Worth <cworth@cworth.org>
+
+ Originally: 2005-04-19 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.h: Add cairo_stroke_preserve, cairo_fill_preserve,
+ and cairo_clip_preserve.
+
+ * src/cairoint.h:
+ * src/cairo-gstate-private.h:
+ * src/cairo-gstate.c: Rip the path out of cairo_gstate_t.
+
+ * src/cairo-private.h: Add path to cairo_t.
+
+ * src/cairo.c: Bring in most of the path code that used to live in
+ cairo-gstate.c
+
+ * src/Makefile.am:
+ * src/cairo-arc-private.h:
+ * src/cairo-arc.c: Move arc generation code into its own file.
+
+ * src/cairo-path-data-private.h:
+ * src/cairo-path-data.c: Accept path+ctm_inverse+tolerance instead
+ of gstate. Absorb flattening and device space->user space
+ conversion that used to be in _cairo_gstate_intepret_path.
+
+ * src/cairo-path.c: Prefer cairo_fixed_t parameters over
+ ciaro_point_t for cross-file interfaces.
+
+ * src/cairo-ft-font.c: Track changes in _cairo_path_fixed
+ interfaces.
+
+ * test/fill-and-stroke.c: (draw): Port to use cairo_fill_preserve
+ rather than cairo_save/cairo_restore which no longer work for
+ saving the path.
+
+ * test/get-and-set.c: (settings_set), (settings_get),
+ (settings_equal): Remove get and set of current point since it is
+ no longer affected by cairo_save and cairo_restore. Add get and
+ set testing for cairo_matrix_t.
+
+2005-04-26 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/cairo-test.h:
+ * test/pdf-surface.c: (main): Add very simple test to generate PDF
+ output, (no automated verification yet).
+
+ * test/cairo-test.c: (cairo_test):
+ * test/create-for-png.c: (draw):
+ * test/pixman-rotate.c: Track PNG interface changes, (no more
+ include of cairo-png.h, cairo_surface_write_png renamed to
+ cairo_surface_write_to_png).
+
+2005-04-26 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo-png.h: Prototypes moved to cairo.h, this file removed.
+
+ * src/cairo-png.c (cairo_surface_write_to_png_stream): Renamed
+ from cairo_surface_write_png_to_stream() for consistency.
+ (cairo_surface_write_to_png): Renamed from
+ cairo_surface_write_png() for consistency.
+
+2005-04-25 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo-png.c (cairo_surface_write_png): Factor out bulk of
+ the code into a new callback based function, write_png(). Call it
+ with a stdio write callback.
+ (cairo_surface_write_png_to_stream): New function to write a
+ surface to a PNG stream.
+ (cairo_image_surface_create_from_png): Likewise, move most of the
+ code to read_png(), clean up error handling and reduce this
+ function to calling read_png() with a stdio based read function.
+ (cairo_image_surface_create_from_png_stream): New function to
+ create an image surface from a PNG stream.
+
+ * src/cairo-image-surface.c (cairo_image_surface_get_width)
+ (cairo_image_surface_get_height): New functions to get widht and
+ height of an image surface.
+
+ * src/cairo.h: Add new prototype and error codes.
+
+ * test/create-for-png.c (draw): Adjust to new PNG API.
+
+2005-04-25 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-win32-surface.c (cairo_win32_surface_create): Initialize
+ the saved_dc_bitmap field here as well ... not strictly needed,
+ but cleaner. (Reported by Peter Arsoff)
+
+2005-04-23 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo-gstate.c (_composite_trap_region): Finalize the
+ correct pattern.
+
+2005-04-22 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo-png.c (cairo_image_surface_create_for_png): Only check
+ PNG signature if we read all the bytes. Don't fclose() the FILE
+ argument (Steve Chaplin <stevech1097@yahoo.com.au>).
+
+ Rename to cairo_image_surface_create_for_png() to
+ cairo_image_surface_create_from_png() and change FILE arguments
+ for this function and cairo_surface_write_png() to be a filename
+ argument instead.
+
+2005-04-21 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo-surface.c (_cairo_surface_set_clip_region): Handle
+ backends that don't have a set_clip_region implementation (PDF).
+
+2005-04-19 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.c: (cairo_paint):
+ * src/cairo.h: Add new cairo_paint function.
+
+ * src/cairoint.h: Add new get_extents function to the surface
+ backend interface.
+
+ * src/cairo-gstate.c: (_cairo_gstate_get_clip_extents): Add
+ function to query current clip_extents.
+
+ * src/cairo-glitz-surface.c: (_cairo_glitz_surface_get_extents):
+ * src/cairo-image-surface.c: (_cairo_image_surface_get_extents),
+ (_cairo_image_abstract_surface_get_extents):
+ * src/cairo-pdf-surface.c: (_cairo_pdf_surface_get_extents):
+ * src/cairo-ps-surface.c: (_cairo_ps_surface_get_extents):
+ * src/cairo-quartz-surface.c: (_cairo_quartz_surface_get_extents):
+ * src/cairo-win32-surface.c: (_cairo_win32_get_extents):
+ * src/cairo-xcb-surface.c: (_cairo_xcb_surface_get_extents):
+ * src/cairo-xlib-surface.c: (_cairo_xlib_surface_get_extents):
+ Implement the new get_extents function for each backend.
+
+ * src/cairo-surface.c: (_cairo_surface_init),
+ (_cairo_surface_set_clip_region),
+ (_cairo_surface_get_clip_extents): Save the clip extents from
+ set_clip_region and implement _cairo_surface_get_clip_extents.
+
+ * src/cairo-xlib-surface.c: (_cairo_xlib_surface_get_size),
+ (_get_image_surface): Abstract away the evil XGetGeometry
+ roundtrip in _cairo_xlib_surface_get_size.
+
+ * test/gradient-alpha.c: (draw):
+ * test/linear-gradient.c: (draw): Rewrite a couple of tests to
+ call cairo_paint.
+
+2005-04-19 Carl Worth <cworth@cworth.org>
+
+ * TODO: Update API Shakeup chart to indicate that cairo_paint and
+ cairo_fill_preserve patches have been sent.
+
+2005-04-19 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/surface-pattern-ref.png:
+ * test/surface-pattern.c: (draw), (main): Add a test of a
+ repeating surface pattern.
+
+2005-04-18 Carl Worth <cworth@cworth.org>
+
+ * ROADMAP: Mark a couple of items that are now complete.
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/fill-and-stroke-ref.png:
+ * test/fill-and-stroke.c: (draw), (main): Add test case that fills
+ and strokes the same shapes, (in preparation for testing
+ cairo_fill_preserve patch).
+
+2005-04-14 Carl Worth <cworth@cworth.org>
+
+ * TODO: Update API Shakeup chart to indicate that cairo_set_source
+ is done.
+
+2005-04-14 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.h:
+ * src/cairo.c: Rename, add, and delete:
+
+ cairo_set_pattern -> cairo_set_source
+ cairo_get_pattern -> cairo_get_source
+ cairo_set_rgb_color -> cairo_set_source_rgb
+ -> cairo_set_source_rgba
+ cairo_set_alpha ->
+ cairo_get_alpha ->
+
+ Note that we'll likely want to add cairo_set_source_surface.
+
+ * src/cairo-color.c: Add _cairo_stock_color helper function.
+ Improve some interfaces:
+
+ _cairo_color_init _cairo_color_init_rgb
+ _cairo_color_set_rgb -> _cairo_color_init_rgba
+ _cairo_color_set_alpha _cairo_color_multiply_alpha
+
+ _cairo_color_get_rgb -> _cairo_color_get_rbga
+ _cairo_color_get_rgba_premultiplied
+
+ * src/cairoint.h: Add cairo_stock_t and some helper macros:
+
+ CAIRO_COLOR_WHITE
+ CAIRO_COLOR_BLACK
+ CAIRO_COLOR_TRANSPARENT
+
+ Fix cairo_pattern_t by eliminating pattern->alpha.
+ Fix cairo_solid_pattern_t to use cairo_color_t rather than three
+ doubles.
+
+ * src/cairo-glitz-surface.c:
+ (_cairo_glitz_pattern_acquire_surface),
+ (_cairo_glitz_pattern_acquire_surfaces),
+ (_cairo_glitz_surface_composite_trapezoids): Track removal of
+ pattern->alpha, simplifying the code considerably
+
+ * src/cairo-gstate-private.h:
+
+ * src/cairo-gstate.c: Track _cairo_color interface changes. Remove
+ gstate->alpha. Propagate down set_source renamings.
+
+ * src/cairo.h:
+ * src/cairo-pattern.c: Rename:
+
+ cairo_pattern_add_color_stop -> cairo_pattern_add_color_stop_rgba
+
+ and add:
+
+ cairo_pattern_add_color_stop_rgb
+
+ Remove pattern->alpha, simplifying the code considerably.
+
+ * src/cairo-pdf-surface.c:
+ * src/cairo-ps-surface.c: Track pattern and color interface
+ changes.
+
+ * src/cairo-surface.c: Add const where appropriate on
+ cairo_color_t*.
+
+ * src/cairo-xlib-surface.c: (_cairo_surface_is_xlib): Add private
+ type inspection predicate.
+ (cairo_xlib_surface_set_size): Add check for surface type
+ mismatch, (no useful error reporting yet, though).
+
+ * test/Makefile.am: Note coverage as en expected failure.
+
+ * test/cairo-test.c: (cairo_test_expect_failure): Improve line
+ wrap on expected failure messages.
+
+ * test/clip-twice.c:
+ * test/coverage.c:
+ * test/fill-rule.c:
+ * test/line-width.c:
+ * test/linear-gradient.c:
+ * test/pixman-rotate.c:
+ * test/set-source.c:
+ * test/text-rotate.c:
+ * test/trap-clip.c: Port all tests to new cairo_set_source
+ interfaces.
+
+2005-04-14 Carl Worth <cworth@cworth.org>
+
+ * test/gradient-alpha-ref.png:
+ * test/gradient-alpha.c: (draw): Make gradient change color in
+ addition to just changing alpha in order to highlight distinction
+ between interpolating in premultiplied vs. non-premultiplied
+ space.
+
+2005-04-14 Carl Worth <cworth@cworth.org>
+
+ * test/Makefile.am: Improve instructions for when to add a test to
+ the XFAIL list.
+
+ * test/cairo-test.c: (cairo_test_expect_failure):
+ * test/cairo-test.h:
+ * test/pixman-rotate.c: (main):
+ * test/text-rotate.c: (main): Print explanations for expected
+ failures.
+
+2005-04-14 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/gradient-alpha-ref.png:
+ * test/gradient-alpha.c: (draw), (main): Add gradient-alpha test
+ in preparation for upcoming cairo_set_source patch.
+
+2005-04-14 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/set-source-ref.png:
+ * test/set-source.c: (draw), (main): Add set-source test in
+ preparation for upcoming cairo_set_source patch.
+
+2005-04-14 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-font.c (_cairo_simple_font_face_destroy): Remove
+ a stray free() (#3029, Carl Worth)
+
+ * test/select-font-no-show-text.c: Note that the bug is fixed.
+
+2005-04-13 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-image-surface.c:
+ (_cairo_image_abstract_surface_finish): Set freed pointer to NULL.
+
+ * src/cairo-surface.c: (cairo_surface_finish): Fix to actually set
+ surface->finished when done. Closes bug #2950 as documented in
+ test/surface-finish-twice.c.
+
+ * test/surface-finish-twice.c: Note that this bug is fixed.
+
+2005-04-13 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/surface-finish-twice.c: (draw), (main): Add new test to
+ exercise crash when calling cairo_surface_finish twice on the same
+ surface.
+
+2005-04-13 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/select-font-no-show-text.c: (draw), (main): Add new
+ set-surface-no-show-text test.
+
+ * test/cairo-test.c: (cairo_test): Be sure to call cairo_destroy
+ even if the image size is 0,0 so that we can test bugs triggered
+ during cleanup.
+
+2005-04-13 Carl Worth <cworth@cworth.org>
+
+ * test/coverage-ref.png:
+ * test/coverage.c: (draw_funcs), (draw): Temporarily remove all
+ text from this test case until we come up with an approach for
+ drawing the same text with different freetype configurations.
+
+2005-04-13 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-traps.c (_cairo_traps_extract_region): Work around
+ a pair of bugs elsewhere (denegerate trapezoids from tesellator,
+ pixman_region_union_rect() failing on width/height zero rectangles)
+
+2005-04-13 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairoint.h src/cairo-traps.c: Add _cairo_traps_extract_region
+ for converting trapezoids into a pixman region.
+
+ * src/cairo-gstate.c (cairo_clip): Represent all rectangular
+ pixel-aligned regions as regions, not just single rectangles.
+
+ * src/cairo-gstate.c (_cairo_gstate_clip_and_composite_trapezoid):
+ Split into manageable pieces, optimize rectangular pixel-
+ aligned regions by using _cairo_surface_fill_rectangles()
+ or _cairo_surface_set_clip_region() as appropriate.
+
+ * tests/trap-clip.c tests/trap-clip-ref.png tests/Makefile.am:
+ Add a test for trapezoids clipping.
+
+ * doc/public/cairo-docs.xml: Add an index.
+
+2005-04-12 Carl Worth <cworth@cworth.org>
+
+ * test/translate-show-surface.c: Note that bug is now fixed.
+
+2005-04-12 Carl Worth <cworth@cworth.org>
+
+ * autogen.sh: Replace errant use of aclocal with $ACLOCAL, as
+ reported by Martin Hedenfalk. Closes bug #3000.
+
+2005-04-12 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-pattern.c:
+ * src/cairo-surface.c: (_cairo_surface_init): Default to
+ CAIRO_FILTER_GOOD rather than CAIRO_FILTER_BEST.
+
+ * src/cairo-pattern.c:
+ (_cairo_pattern_acquire_surface_for_surface): Optimize to use
+ CAIRO_FILTER_NEAREST when the pattern matrix is an integer
+ translation.
+
+2005-04-12 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-pattern.c:
+ (_cairo_pattern_acquire_surface_for_surface):
+ * src/cairo-surface.c: (_cairo_surface_init): Use
+ CAIRO_FILTER_BEST by default rather than CAIRO_FILTER_NEAREST.
+
+2005-04-12 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-gstate.c (_cairo_gstate_show_surface): Offset the src
+ pattern by (0,0)->CTM. This fixes test/translate-show-surface.
+
+ * src/cairo-glitz-surface.c
+ (_cairo_glitz_surface_composite_trapezoids): Use unsigned cahr* to
+ match new prototype for cairo_image_surface_create_for_data.
+
+2005-04-11 Carl Worth <cworth@cworth.org>
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/translate-show-surface-ref.png:
+ * test/translate-show-surface.c: (draw), (main): Add new test
+ demonstrating bug in the sequence: cairo_translate;
+ cairo_show_surface.
+
+2005-04-11 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.c (cairo_select_font_face): Add deprecation alias from
+ cairo_scale_font to cairo_set_font_size.
+
+2005-04-11 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.c (cairo_select_font_face): Add deprecation alias from
+ cairo_select_font to cairo_select_font_face.
+
+2005-04-11 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo.h doc/public/cairo-sections.txt
+ src/cairo-matrix.c: Update.
+
+ * doc/public/cairo-docs.xml: Include cairo-font.xml
+
+2005-04-08 Carl Worth <cworth@cworth.org>
+
+ * src/cairoint.h:
+ * src/cairo.h: Move include of pixman.h from cairo.h to cairoint.h
+ since libpixman isn't part of cairo's public interface.
+
+ * test/move-to-show-surface.c (draw): Use unsigned long rather
+ than uint32_t since we no longer have pixman.h setting that type
+ up for us.
+
+ * src/cairo-font.c (cairo_font_face_destroy): Remove unused
+ variable user_data_copy.
+
+2005-04-08 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo.h src/cairo-font.c src/cairoint.h
+ doc/public/cairo-sections.txt:
+ Add cairo_font_face_set/get_user_data().
+
+ * src/cairo-array.c src/cairoint.h src/cairo-surface.c:
+ Refactor user data code from cairo-surface.c into
+ cairo_user_data_array_t.
+
+ * src/cairo-font.c (cairo_font_face_destroy,
+ (cairo_scaled_font_destroy, _cairo_unscaled_font_destroy):
+ Switch these types to be like cairo_surface_t where the
+ generic code frees the wrapper object.
+
+ * src/cairo-atsui-font.c src/cairo-ft-font.c
+ src/cairo-win32-font.c: Fix up for the above changes.
+
+ * src/cairo-ft-font.c (_cairo_ft_unscaled_font_destroy,
+ _ft_font_face_destroy): Implement a complicated mutual-referencing
+ scheme to make sure that a face from cairo_ft_font_face_create_for_ft_face()
+ is freed only when the FT_Face is no longer needed.
+
+ * src/cairo-ft-font.c (cairo_ft_font_face_create_for_ft_face):
+ Update the docs to describe how to figure out when the FT_Face
+ can be freed.
+
+ * src/cairo-ft-font.c: Fix refcount leaks when creating fonts.
+
+ * src/cairo-pdf-surface.c (cairo_pdf_ft_font_create): Remove
+ excess call to _cairo_unscaled_font_reference().
+
+ * src/cairo-gstate.c (_cairo_gstate_set_font_face): Remove
+ stray initialization of font matrix to the identity.
+
+ * src/cairo-array.c (_cairo_user_data_array_set_data) test/user-data.c:
+ Fix a bug when setting/unsetting a key with a free key slot before it,
+ add that to the test case.
+
+ * src/cairo-array.c (_cairo_user_data_array_set_data):
+ Don't append an element when user_data is NULL.
+
+2005-04-08 Dave Beckett <Dave.Beckett@bristol.ac.uk>
+
+ * src/cairo-glitz-surface.c (_cairo_glitz_surface_set_matrix):
+ Update to track changes to cairo_matrix_t interface.
+
+2005-04-08 Carl Worth <cworth@cworth.org>
+
+ * ROADMAP: Add ROADMAP file with an initial stab at 1.0 items.
+
+2005-04-08 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-gstate.c:
+ (_cairo_gstate_transform), (_cairo_gstate_set_matrix),
+ (_cairo_gstate_interpret_path): Eliminate internal use of
+ deprecated cairo_matrix_copy.
+
+ * src/cairo-gstate.c: (_cairo_gstate_get_matrix),
+ * src/cairo-matrix.c: (cairo_matrix_copy):
+ * src/cairo.c: (cairo_get_matrix):
+ * src/cairo.h:
+ * src/cairoint.h: Change cairo_get_matrix to accept a pointer to
+ the return value cairo_matrix_t rather than returning the value
+ directly.
+
+2005-04-08 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-matrix.c (cairo_matrix_init_identity): Don't try to
+ return a value (even a void value) from a void function. Closes
+ bug #2931.
+
+2005-04-07 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-wideint.h: Remove broken code for defining
+ uint64_t.
+
+2005-04-07 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-surface.c: (_cairo_surface_release_source_image),
+ (_cairo_surface_release_dest_image),
+ (_cairo_surface_clone_similar), (_cairo_surface_composite),
+ (_cairo_surface_fill_rectangles),
+ (_cairo_surface_composite_trapezoids), (_cairo_surface_copy_page),
+ (_cairo_surface_show_page), (_cairo_surface_show_glyphs):
+
+ Change to allow NULL backend function pointers to indicate
+ unsupported functions.
+
+ * src/cairo-glitz-surface.c:
+ * src/cairo-image-surface.c:
+ * src/cairo-pdf-surface.c:
+ * src/cairo-ps-surface.c:
+ * src/cairo-quartz-surface.c:
+ * src/cairo-win32-surface.c:
+ * src/cairo-xcb-surface.c:
+ * src/cairo-xlib-surface.c: Eliminate stub functions and replace
+ with NULL in surface backend table.
+
+2005-04-07 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo.[ch] src/cairoint.h src/cairo-gstate.c
+ docs/public/cairo-sections.txt:
+ cairo_select_font() => cairo_select_font_face()
+ cairo_scale_font() => cairo_set_font_size()
+ cairo_transform_font() => cairo_set_font_matrix()
+ Add cairo_get_font_matrix(). Make cairo_set_font_face()
+ not reset the font matrix. Default the font matrix
+ to SCALE(10). Document cairo_select_font_face().
+
+ * test/coverage.c (draw) test/text-cache-crash.c (draw)
+ test/text-rotate.c (draw): Use cairo_set_font_size().
+
+ * src/cairo-font.c src/cairo.h: Fix up some parameter
+ names for docs.
+
+2005-04-07 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-win32-font.c: Fix various compilation errors.
+
+2005-04-07 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-gstate.c:
+ * src/cairo-png.c:
+ * src/cairo-win32-font.c:
+ * src/cairo-win32-surface.c:
+ * src/cairo-win32.h:
+ * src/cairoint.h: Minor changes to header file inclusion
+ recommended by Oleg Smolsky for better portability to MSVC.
+
+2005-04-07 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-png.c (PNG_SIG_SIZE): Use a preprocessor macro to get
+ a literal value in the array size declaration, (for better
+ portability to lame compilers that can't deal with a const int
+ variable for the array size). Reported by Oleg Smolsky.
+ (PNG_SIG_SIZE): Fix typo.
+
+2005-04-07 Carl Worth <cworth@cworth.org>
+
+ * configure.in:
+ * src/cairo-wideint.h:
+ * src/cairoint.h: Use configure-time checks for stdint.h
+ vs. inttypes.h vs. sys/int_types.h rather than ad-hoc
+ system-specific macros. Also define these types manually none of
+ these header are available. (Thanks to Jason Dorje Short
+ <jdorje@users.sf.net>).
+
+2005-04-07 Carl Worth <cworth@cworth.org>
+
+ * test/imagediff.c (main): Fix to return non-zero status on error.
+
+2005-04-06 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo.h src/cairo-gstate.c src/cairo-font.c: Add
+ a cairo_font_face_t type to hold a description of a font
+ face. Replace cairo_set_font() with cairo_set_font_face().
+
+ * src/cairoint.h src/cairo-font.c src/cairo-gstate.c: Add
+ "cairo_simple_font_face" for family/weight/slant and use
+ it to implement font naming for the toy API.
+
+ * src/cairo-ft.h src/cairo-ft-font.c cairo-win32.h
+ cairo-win32-font.c: Switch the FreeType and Win32 backends
+ over to using cairo_font_face_t.
+
+ * src/cairo.h src/cairo-font.c src/cairo-ft-font.c
+ src/cairo-win32-font.c: Pass in font matrix and CTM separately
+ rather than as a composite scale when creating fonts; allows
+ removing font_matrix argument to metrics functions.
+
+ * src/cairoint.h src/cairo-font.c src/cairo-ft-font.c
+ src/cairo-win32-font.c: Remove cairo_font_scale_t type,
+ just use cairo_matrix_t and ignore translations.
+
+ * src/cairo-ft.h src/cairo-ft-font.c: Remove
+ cairo_ft_font_get_pattern() -- it can't work for all FreeType
+ backend fonts and doesn't seem particularly useful.
+
+ * src/cairo.[ch]: Rename cairo_font_get_extents() to
+ cairo_font_extents()
+
+ * doc/public/cairo-sections.txt: Update, split font functions
+ into a separate section.
+
+ * src/cairo-ft-font.c (_ft_unscaled_font_get_for_pattern): Fix
+ locking order problem.
+
+ * src/cairo-font.c: Add caches for simple font faces and from
+ cairo_font_face_t to cairo_scaled_font_t.
+
+ * src/cairo.h src/cairoint.h src/cairo-font.c src/cairo-win32-font.c
+ src/cairo-ft-font.c src/cairo-gstate.c src/cairo-gstate-private.h:
+ Rename cairo_font_t to cairo_scaled_font_t.
+
+2005-04-06 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.h: Rework the cairo_matrix_t interface in several ways.
+ Expose a struct for cairo_matrix_t.
+
+ Add new function to return current matrix:
+ cairo_get_matrix
+
+ Deprecate the following functions (in documentation):
+ cairo_matrix_create
+ cairo_matrix_destroy
+ cairo_matrix_get_affine
+
+ Rename:
+ cairo_matrix_set_affine -> cairo_matrix_init
+ cairo_matrix_set_identity -> cairo_matrix_init_identity
+
+ Add other new matrix initialization functions:
+ cairo_matrix_init_translate
+ cairo_matrix_init_scale
+ cairo_matrix_init_rotate
+
+ Change return type of almost all cairo_matrix functions from
+ cairo_status_t to void.
+
+ * src/cairo-atsui-font.c:
+ * src/cairo-ft-font.c:
+ * src/cairo-gstate.c:
+ * src/cairo-image-surface.c:
+ * src/cairo-matrix.c:
+ * src/cairo-pattern.c:
+ * src/cairo-pdf-surface.c:
+ * src/cairo-pen.c:
+ * src/cairo-surface.c:
+ * src/cairo-win32-font.c:
+ * src/cairo-xlib-surface.c:
+ * src/cairo.c:
+ * src/cairoint.h: Track changes to cairo_matrix_t interface.
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/transforms-ref.png:
+ * test/transforms.c: Add a test case showing the same path drawn
+ under various transforms, (including skews set directly by
+ initializing a cairo_matrix_t).
+
+2005-04-06 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.h: Make handling of unsigned char* vs. char*
+ consistent. Change all parameters that are actual string data from
+ unsigned char* to char* (cairo_text_extents, cairo_show_text,
+ cairo_text_path). Change all data buffers from char* to unsigned
+ char* (cairo_write_func_t).
+
+ * src/cairo-gstate.c: (_cairo_gstate_text_to_glyphs):
+ * src/cairo-ft-font.c: (_cairo_ft_font_text_to_glyphs):
+ * src/cairo-font.c: (_cairo_font_text_to_glyphs):
+ * src/cairo-atsui-font.c: (_cairo_atsui_font_text_to_glyphs):
+ * src/cairoint.h:
+ * src/cairo.c: (cairo_text_extents), (cairo_show_text),
+ (cairo_text_path): Track changes from unsigned char* to
+ char*. Convert to unsigned only at the internal interface to
+ unicode processing.
+
+ * test/move-to-show-surface.c: (draw):
+ * src/cairo-output-stream.c: (_cairo_output_stream_printf),
+ (stdio_write): Track change from char* to unsigned char*.
+
+2005-04-06 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-cache.c (_cairo_cache_init): Fix reversed arguments in
+ call to calloc.
+
+2005-04-04 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.h (cairo_set_target_image,
+ cairo_image_surface_create_for_data):
+ * src/cairo.c: (cairo_set_target_image): Change type of data
+ parameter from char* to unsigned char*.
+
+ * src/cairo-ft-font.c: (_cairo_ft_font_create_glyph):
+ * src/cairo-image-surface.c: (cairo_image_surface_create_for_data):
+ * src/cairo-pattern.c:
+ (_cairo_pattern_acquire_surface_for_gradient):
+ * test/buffer-diff.c: (buffer_diff):
+ * test/buffer-diff.h:
+ * test/write-png.c: (write_png_argb32):
+ * test/write-png.h: Propagate the unsigned char* change down the
+ stack.
+
+ * src/cairo-xlib-surface.c: (_get_image_surface): Add cast since
+ XImage uses char* rather than unsigned char*.
+
+ * src/cairo-png.c: (cairo_image_surface_create_for_png): Fix
+ memory leak of image data.
+
+ * test/cairo-test.c: (cairo_test), (cairo_test_create_png_pattern):
+ * test/cairo-test.h: Switch to use cairo_surface_write_png rather
+ than a custom write_png_argb32.
+
+ * test/.cvsignore:
+ * test/Makefile.am:
+ * test/create-for-png-ref.png:
+ * test/create-for-png.c: (draw), (main): Add test to exercise the
+ cairo_image_surface_create_for_png function.
+
+2005-04-04 Carl Worth <cworth@cworth.org>
+
+ * TODO: Remove items for PNG backend removal and trapezoid
+ reasterization re-implementation since they have been completed.
+
+2005-04-04 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.c:
+ * src/cairo.h: Drop cairo_default_matrix since it is now always
+ identical to cairo_identity_matrix.
+
+ * src/cairo-gstate-private.h:
+ * src/cairo-gstate.c: (_cairo_gstate_init),
+ (_cairo_gstate_set_target_surface): Remove gstate->pixels_per
+ inch. Change default matrix to always be the identity matrix.
+
+ * src/cairo-glitz-surface.c:
+ * src/cairo-image-surface.c:
+ * src/cairo-pdf-surface.c:
+ * src/cairo-ps-surface.c:
+ * src/cairo-quartz-surface.c:
+ * src/cairo-surface.c:
+ * src/cairo-win32-surface.c:
+ * src/cairo-xcb-surface.c:
+ * src/cairo-xlib-surface.c:
+ * src/cairoint.h: Drop pixels_per_inch function from surface
+ backend interface as it is no longer needed.
+
+2005-04-02 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-gstate.c: (_cairo_gstate_show_surface): Use the
+ current point to offset just the destination, not the source and
+ destination. With this fix, cairo_show_surface should work with
+ the current point at places other than the origin.
+
+ * test/Makefile.am: Move move-to-show-surface off the expected
+ failure list.
+
+ * test/move-to-show-surface.c: Add comment indicating that bug is
+ resolved.
+
+ * test/testsvg: Don't use diff to compare images, just imagediff.
+
+2005-04-02 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.h:
+ * src/cairo.c: (cairo_set_target_image), (cairo_text_extents),
+ (cairo_show_text), (cairo_text_path):
+ * src/cairo-image-surface.c: (cairo_image_surface_create_for_data):
+ * src/cairo-gstate.c: (_cairo_gstate_text_to_glyphs):
+ * src/cairo-font.c: (_cairo_font_create): Style and indentation
+ fixes.
+
+ * src/cairo-ft-font.c: (_cairo_ft_font_create): Add (unsigned
+ char*) cast to quiet new gcc-4 warnings.
+
+ * src/cairo-ft-font.c: (_cairo_ft_font_glyph_extents): Initialize
+ variables to quiet new gcc-4 warnings.
+
+ * src/cairo-pdf-surface.c: (cairo_pdf_ft_font_write_generic_table),
+ (cairo_pdf_ft_font_write_glyf_table):
+ * src/cairo-png.c: (cairo_surface_write_png),
+ (cairo_image_surface_create_for_png):
+ * src/cairo-xlib-surface.c: (_get_image_surface):
+ * src/cairo-ps-surface.c: (_cairo_ps_surface_copy_page):
+ Use unsigned char* as expected by freetype, libpng, Xlib, and zlib.
+
+ * src/cairoint.h:
+ * src/cairo-unicode.c: (_utf8_get_char), (_utf8_get_char_extended),
+ (_cairo_utf8_to_ucs4), (_cairo_utf8_to_utf16): Propagate unsigned
+ char* down from cairo_text_extents.
+
+2005-04-01 Carl Worth <cworth@cworth.org>
+
+ * TODO: Update API shakeup chart.
+
+ * src/cairo.h:
+ * src/cairo.c: (cairo_set_target_image_no_data): Add a standin for
+ the function that should be cairo_set_target_image which should
+ then have some other name. We can straighten that mess out when we
+ eliminate the set_target functions. Add deprecation alias for
+ cairo_current_pattern.
+
+ * src/cairoint.h:
+ * src/cairo-image-surface.c:
+ * src/cairo-surface.c: Deprecate cairo_surface_create_for_image in
+ favor of cairo_image_surface_create_for_data.
+
+2005-03-31 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo.c (cairo_set_target_png): Remove this function now
+ that the PNG backend is gone.
+
+2005-03-30 Carl Worth <cworth@cworth.org>
+
+ * configure.in: Fix typo I had introduced into Jason's patch that
+ made configure fail.
+
+2005-03-30 Carl Worth <cworth@cworth.org>
+
+ A few fixes courtesy of Jason Dorje Short <jdorje@users.sf.net>:
+
+ * configure.in: Disable PS backend if zlib is not found.
+
+ * src/cairo-win32-font.c: (_cairo_win32_font_glyph_path): Fix
+ mistyped parameter.
+
+ * src/cairo-win32-surface.c: (_cairo_win32_surface_finish): Fix
+ missing return value.
+
+2005-03-30 T Rowley <tim.rowley@gmail.com>
+
+ * src/cairo-gstate.c (_cairo_gstate_stroke_extents): call
+ _cairo_pen_init so that the result takes into account the caps.
+
+2005-03-29 T Rowley <tim.rowley@gmail.com>
+
+ * src/cairo-xlib.h: include Xlib.h to fix solaris build bustage.
+
+2005-03-29 T Rowley <tim.rowley@gmail.com>
+
+ * src/cairo-wideint.h: add preprocessor tests for stdint.h/inttypes.h
+
+ * src/cairoint.h: add preprocessor tests for stdint.h/inttypes.h
+
+2005-03-29 T Rowley <tim.rowley@gmail.com>
+
+ * configure.in: re-enable quartz backend
+
+ * src/cairo-quartz-surface.c: update to compilable/workable version
+
+ * src/cairo-atsui-font.c: update to compilable/workable version
+
+2005-03-29 Carl Worth <cworth@cworth.org>
+
+ * test/Makefile.am:
+ * test/*_*.c: More _/- renames in the test directory.
+
+2005-03-28 Carl Worth <cworth@cworth.org>
+
+ * src/Makefile.am:
+ * src/cairo_*.c: Renamed a bunch of files to use - rather than _
+ as a separator. Copy happened in the master repository to preserve
+ history, so this is just a big remove.
+
+2005-03-28 Carl Worth <cworth@cworth.org>
+
+ * TODO: Sorted API shakeup chart.
+
+2005-03-28 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo-png.c (cairo_image_surface_write_png)
+ (cairo_image_surface_create_from_png): New PNG utility functions.
+
+ * src/cairo_pdf_surface.c, src/cairo-pdf.h: Reverse the naming of
+ the pdf constructors so the callback based ones have the long
+ names.
+
+2005-03-25 Jamey Sharp <jamey@minilop.net>
+
+ * src/cairo-xcb.h:
+ * src/cairo_xcb_surface.c:
+ Fix "implicit declaration" warning in cairo.c by moving
+ cairo_xcb_surface_create prototype into cairo-xcb.h.
+
+2005-03-23 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-path-fixed-private.h:
+ * src/cairo_path.c: Clean up names of cairo_path internals.
+
+2005-03-23 Carl Worth <cworth@cworth.org>
+
+ * src/cairo_path_fill.c:
+ * src/cairo_path_stroke.c: Remove unneeded includes of
+ cairo-path-fixed-private.h.
+
+ * src/cairo_ft_font.c (_cairo_ft_font_glyph_path): Fix
+ indentation.
+
+2005-03-23 Carl Worth <cworth@cworth.org>
+
+ * TODO: More updates to the API Shakeup chart.
+
+2005-03-23 Carl Worth <cworth@cworth.org>
+
+ * src/cairo_path.c: (_cairo_path_fixed_init),
+ (_cairo_path_fixed_init_copy), (_cairo_path_fixed_fini),
+ (_cairo_path_fixed_move_to), (_cairo_path_fixed_rel_move_to),
+ (_cairo_path_fixed_line_to), (_cairo_path_fixed_rel_line_to),
+ (_cairo_path_fixed_curve_to), (_cairo_path_fixed_rel_curve_to),
+ (_cairo_path_fixed_close_path),
+ (_cairo_path_fixed_get_current_point), (_cairo_path_add),
+ (_cairo_path_add_op_buf), (_cairo_path_new_op_buf),
+ (_cairo_path_add_arg_buf), (_cairo_path_new_arg_buf),
+ (_cairo_path_fixed_interpret):
+ * src/cairo_path_bounds.c: (_cairo_path_fixed_bounds):
+ * src/cairo_path_fill.c: (_cairo_path_fixed_fill_to_traps):
+ * src/cairo_path_stroke.c: (_cairo_path_fixed_stroke_to_traps):
+ * src/cairoint.h: Rename cairo_path_real_t to cairo_path_fixed_t
+ and fix all _cairo_path functions to be named as _cairo_path_fixed
+ functions.
+
+ * src/cairo-gstate-private.h:
+ * src/cairo-path-fixed-private.h:
+ * src/cairo_font.c: (_cairo_font_glyph_path):
+ * src/cairo_ft_font.c: (_move_to), (_line_to), (_conic_to),
+ (_cubic_to), (_cairo_ft_font_glyph_path):
+ * src/cairo_gstate.c: (_cairo_gstate_init),
+ (_cairo_gstate_init_copy), (_cairo_gstate_fini),
+ (_cairo_gstate_new_path), (_cairo_gstate_move_to),
+ (_cairo_gstate_line_to), (_cairo_gstate_curve_to),
+ (_cairo_gstate_rel_move_to), (_cairo_gstate_rel_line_to),
+ (_cairo_gstate_rel_curve_to), (_cairo_gstate_close_path),
+ (_cairo_gstate_get_current_point), (_cairo_gstate_interpret_path),
+ (_cairo_gstate_stroke), (_cairo_gstate_in_stroke),
+ (_cairo_gstate_fill), (_cairo_gstate_in_fill),
+ (_cairo_gstate_stroke_extents), (_cairo_gstate_fill_extents),
+ (_cairo_gstate_clip), (_cairo_gstate_text_to_glyphs): Track name
+ change of cairo_path_real_t and _cairo_path_fixed functions.
+
+2005-03-23 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-path-data-private.h: Remove CAIRO_BEGIN_DECLS and
+ CAIRO_END_DECLS as they are not needed for private headers.
+
+ * src/cairoint.h: Add ASSERT_NOT_REACHED macro.
+
+ * src/cairo.c: (cairo_get_path), (cairo_get_path_flat): Rewrite in
+ terms of cairo_copt_path and cairo_copy_path_flat in preparation
+ for removing cairo_gstate_interpret_path.
+
+2005-03-23 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-gstate-private.h:
+ * src/cairo-path-fixed-private.h:
+ * src/cairo-private.h:
+ * src/cairoint.h: Begin the process of breaking up cairoint.h,
+ moving structure definitions of cairo_t, cairo_gstate_t, and
+ cairo_path_real_t into their own header files.
+
+ * src/cairo.c:
+ * src/cairo_gstate.c:
+ * src/cairo_path.c:
+ * src/cairo_path_fill.c:
+ * src/cairo_path_stroke.c:
+ * src/cairo_pen.c: Track changes to header files, reaching into
+ the new private headers where necessary.
+
+2005-03-23 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.c: (cairo_set_target_glitz), (cairo_set_target_pdf),
+ (cairo_set_target_pdf_as_file), (cairo_set_target_png),
+ (cairo_set_target_ps), (cairo_set_target_win32),
+ (cairo_set_target_xcb), (cairo_set_target_drawable): Move
+ surface-specific cairo_t functions to cairo.c.
+
+ * src/cairo_glitz_surface.c:
+ * src/cairo_pdf_surface.c:
+ * src/cairo_png_surface.c:
+ * src/cairo_ps_surface.c:
+ * src/cairo_win32_surface.c:
+ * src/cairo_xcb_surface.c:
+ * src/cairo_xlib_surface.c: Remove functions that have now moved
+ to cairo.c.
+
+ * test/.cvsignore: A few new files to ignore now with new
+ compilation mode using a libtool helper library.
+
+2005-03-23 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.h: Add backwards-compatibility for recently renamed
+ functions.
+
+2005-03-21 Carl Worth <cworth@cworth.org>
+
+ * src/cairo.c:
+ * src/cairo_gstate.c: (_cairo_gstate_transform),
+ (_cairo_gstate_user_to_device),
+ (_cairo_gstate_user_to_device_distance),
+ (_cairo_gstate_device_to_user),
+ (_cairo_gstate_device_to_user_distance),
+ (_cairo_gstate_reset_clip):
+ * src/cairo_matrix.c:
+ * src/cairoint.h:
+ * src/cairo.h: Rename functions to eliminate abbreviations:
+ cairo_concat_matrix -> cairo_transform
+ cairo_transform_point -> cairo_user_to_device
+ cairo_transform_distance -> cairo_user_to_device_distance
+ cairo_inverse_transform_point -> cairo_device_to_user
+ cairo_inverse_transform_distance-> cairo_device_to_user_distance
+ cairo_init_clip -> cairo_reset_clip
+
+2005-03-18 Carl Worth <cworth@cworth.org>
+
+ * TODO: Update API shakeup chart.
+
+2005-03-18 Carl Worth <cworth@cworth.org>
+
+ * src/cairo-path-data-private.h: * src/cairo.c: (cairo_copy_path),
+ (cairo_copy_path_flat),
+ (cairo_append_path): Rename cairo_copy_path_data,
+ cairop_copy_path_data_flat, and cairo_append_path_data to
+ cairo_copy_path, cairo_copy_path_flat, and cairo_append_path.
+
+ * src/cairo.h: Add new cairo_path_t, containing a
+ cairo_path_data_t array and an explicit length. Remove
+ CAIRO_PATH_END_PATH terminator from cairo_path_data_t.
+
+ * src/cairo_atsui_font.c: (_cairo_atsui_font_glyph_path):
+ * src/cairo_font.c: (_cairo_font_glyph_path):
+ * src/cairo_ft_font.c: (_move_to), (_line_to), (_conic_to),
+ (_cubic_to), (_cairo_ft_font_glyph_path):
+ * src/cairo_gstate.c: (_cairo_gstate_interpret_path):
+ * src/cairo_path.c: (_cairo_path_init), (_cairo_path_init_copy),
+ (_cairo_path_fini), (_cairo_path_move_to),
+ (_cairo_path_rel_move_to), (_cairo_path_line_to),
+ (_cairo_path_rel_line_to), (_cairo_path_curve_to),
+ (_cairo_path_rel_curve_to), (_cairo_path_close_path),
+ (_cairo_path_get_current_point), (_cairo_path_add),
+ (_cairo_path_add_op_buf), (_cairo_path_new_op_buf),
+ (_cairo_path_add_arg_buf), (_cairo_path_new_arg_buf),
+ (_cairo_path_interpret):
+ * src/cairo_path_bounds.c: (_cairo_path_bounds):
+ * src/cairo_path_data.c: (_cairo_path_data_count),
+ (_cairo_path_data_populate), (_cairo_path_data_create_real),
+ (cairo_path_destroy), (_cairo_path_data_append_to_context):
+ * src/cairo_path_fill.c: (_cairo_path_fill_to_traps):
+ * src/cairo_path_stroke.c: (_cairo_path_stroke_to_traps):
+ * src/cairoint.h:
+ * test/path_data.c: (munge_and_set_path), (draw), (main): Rename
+ the internal path object from cairo_path_t to cairo_path_real_t.
+
+2005-03-18 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo_pdf_surface.c (cairo_set_target_pdf_as_file)
+ (cairo_set_target_pdf): Remove return statements from these
+ functions (bug #2137).
+
+2005-03-18 Carl Worth <cworth@cworth.org>
+
+ * src/Makefile.am (libcairo_la_SOURCES): Remove unused
+ libcairo_freetype_sources (thanks to Damien Carbery). Closes bug
+ #2673.
+
+2005-03-17 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo_matrix.c (cairo_matrix_rotate): doc fix -
+ 90 degrees is MI_PI/2 radians.
+
+ * src/cairo.c src/cairo_matrix.c src/cairo_ft_font.c
+ src/cairo_ps_surface.c src/cairo_quartz_surface.c
+ src/cairo_win32_font.c src/cairo_win32_surface.c
+ src/cairo_xlib_surface.c: Cairo is only capitalized
+ at the beginning of sentences.
+
+2005-03-17 Kristian Høgsberg <krh@redhat.com>
+
+ From Tor Lillqvist <tml@novell.com>:
+
+ * test/cairo_test.c (cairo_test): Open output PNG files in binary
+ mode.
+
+2005-03-17 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo.h src/cairo_surface.c src/cairo-xlib.h
+ src/cairo_xlib_surface.c: Move cairo_xlib_surface_set_device_offset()
+ to a generic cairo_surface_set_device_offset().
+
+ * src/cairo_gstate.c: Take the surface's device offset into
+ account.
+
+ * doc/public/cairo-sections.txt: Update.
+
+2005-03-17 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo_matrix.c: Fix the docs to to correctly describe
+ the order of transformation for muliply/scale/rotate/translate.
+ (cairo_matrix_translate): Fix translate/rotate typo in the
+ parameter descriptions.
+
+2005-03-17 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo_output_stream.c: Forgot to add this file.
+
+2005-03-16 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo_surface.c (_destroy_user_data)
+ (cairo_surface_set_user_data): Dont call user data destroy
+ function if it's NULL.
+
+ * test/user_data.c: (main): Add test case for user data with NULL
+ destroy function.
+
+2005-03-16 Kristian Høgsberg <krh@redhat.com>
+
+ * src/Makefile.am: Add cairo_output_stream.c
+
+ * src/cairo.h: Add new errors, CAIRO_STATUS_WRITE_ERROR and
+ CAIRO_STATUS_SURFACE_FINISHED, add cairo_surface_finish()
+ prototype, add cairo_write_func_t.
+
+ * src/cairo.c: Add strings for new errors, documentation fix.
+
+ * src/cairo_win32_surface.c:
+ * src/cairo_xcb_surface.c:
+ * src/cairo_xlib_surface.c:
+ * src/cairo_glitz_surface.c:
+ * src/cairo_image_surface.c:
+ * src/cairo_png_surface.c:
+ * src/cairo_ps_surface.c: Rename surface destroy functions to
+ finish and change them to not free the surface.
+
+ * src/cairo-pdf.h:
+ * src/cairo_pdf_surface.c: Change PDF surface constructors to take
+ a write function in the general case and add stdio convenience
+ constructors. Change destroy function to finish for
+ cairo_pdf_surface. Change implementation to use
+ cairo_output_stream_t functions for output.
+
+ * src/cairo_font.c: (_cairo_font_show_glyphs): Use
+ _cairo_surface_show_glyphs instead of calling function pointer
+ directly.
+
+ * src/cairoint.h: Add prototypes for cairo output stream
+ functions, rename destroy to finish in cairo_surface_backend_t and
+ add finished flag to cairo_surface_t.
+
+ * src/cairo_surface.c: Add cairo_surface_finish() and call it from
+ cairo_surface_destroy(). Check the finished flag in
+ cairo_surface_t in functions that change the surface.
+
+2005-03-15 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo-xlib.h src/cairo_xlib_surface.c: Rework set
+ of contructors for XLib surfaces. Add
+ cairo_xlib_surface_set_size().
+
+ * src/cairo-xlib.h src/cairo_xlib_surface.c: Add
+ cairo_xlib_surface_set_device_offset().
+
+ * src/cairo_xlib_surface.c (cairo_xlib_surface_set_clip_region):
+ Rewrite for clarity and efficiency.
+
+ * src/cairo_xlib_surface.c (_get_image_surface): Use a
+ temporary pixmap to avoid possible BadMatch when fetch
+ from windows.
+
+ * src/cairo.[ch] src/cairo-xlib.h: Fix some parameter names
+ for the docs.
+
+ * doc/public/cairo-sections.txt: Update
+
+2005-03-14 Carl Worth <cworth@cworth.org>
+
+ * test/path_data-ref.png: Add reference image.
+
+2005-03-14 Carl Worth <cworth@cworth.org>
+
+ * test/Makefile.am: Fixes to force tests to run against locally
+ compiled version (thanks to Manish Singh).
+
+2005-03-11 Carl Worth <cworth@cworth.org>
+
+ * doc/public/cairo-sections.txt:
+ * doc/public/tmpl/cairo-surface.sgml:
+ * doc/public/tmpl/cairo.sgml: Added some documentation, so we get
+ some churn here.
+
+ * src/cairo.c:
+ * src/cairo.h: New functions: cairo_copy_path_data,
+ cairo_copy_path_data_flat, and cairo_append_path_data.
+
+ * src/Makefile.am:
+ * src/cairo-path-data-private.h:
+ * src/cairo_path_data.c: Add new implementation for
+ cairo_copy_path_data and cairo_append_path_data.
+
+ * test/Makefile.am:
+ * test/path_data.c: New test for new path_data functions.
+
+2005-03-10 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo_surface.c (_destroy_user_data): Add this function and
+ call it on surface destruction.
+
+2005-03-10 Kristian Høgsberg <krh@redhat.com>
+
+ * test/user_data.c (main): Fix assert()'s using = instead of ==.
+
+ * test/cairo_test.c (cairo_test): Move xunlink call below the
+ xasprintf that builds the filename to unlink.
+
+2005-03-10 Carl Worth <cworth@cworth.org>
+
+ * TODO: API Shakeup status update.
+
+2005-03-10 Carl Worth <cworth@cworth.org>
+
+ Originally: 2005-02-24 Carl Worth <cworth@cworth.org>
+
+ * src/cairo_surface.c (cairo_surface_set_user_data)
+ (cairo_surface_get_user_data):
+ * src/cairo.h: Add const qualifier to cairo_user_data_key_t
+ arguments.
+
+ Originally: 2005-02-15 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo_surface.c (cairo_surface_get_data, cairo_surface_set_data):
+ Add these two functions to set and get user data on an surface.
+
+ * src/cairo.h: Function prototypes for new functions.
+
+ * test/user_data.c: Test case for user data functions.
+
+2005-03-09 Carl Worth <cworth@cworth.org>
+
+ * test/cairo_test.c (cairo_test): Move filename initialization up
+ to before first use.
+
+ * test/get_and_set.c:
+ * test/Makefile.am: Add test for the most trivial cairo_get and
+ cairo_set functions.
+
+2005-03-09 Carl Worth <cworth@cworth.org>
+
+ * test/cairo_test.c: (cairo_test):
+ * test/cairo_test.h:
+ * test/clip_twice.c: (draw):
+ * test/coverage.c: (draw):
+ * test/fill_rule.c: (draw):
+ * test/leaky_polygon.c: (draw):
+ * test/line_width.c: (draw):
+ * test/linear_gradient.c: (draw):
+ * test/move_to_show_surface.c: (draw):
+ * test/pixman_rotate.c: (draw):
+ * test/text_cache_crash.c: (draw):
+ * test/text_rotate.c: (draw): Change the draw function under test
+ to return a cairo_test_status_t so that it can indicate test
+ failure even if there is no result image.
+
+2005-03-09 Carl Worth <cworth@cworth.org>
+
+ * TODO: Update API Shakeup planning chart.
+ fix typos.
+
+2005-03-09 Carl Worth <cworth@cworth.org>
+
+ * doc/public/cairo-sections.txt:
+ * src/cairo.c: (cairo_get_pattern), (cairo_get_font),
+ (cairo_get_font_extents), (cairo_get_operator),
+ (cairo_get_rgb_color), (cairo_get_alpha), (cairo_get_tolerance),
+ (cairo_get_current_point), (cairo_get_fill_rule),
+ (cairo_get_line_width), (cairo_get_line_cap),
+ (cairo_get_line_join), (cairo_get_miter_limit), (cairo_get_matrix),
+ (cairo_get_target_surface), (cairo_get_path),
+ (cairo_get_path_flat):
+ * src/cairo.h:
+ * src/cairo_ft_font.c: (_conic_to):
+ * src/cairo_gstate.c: (_cairo_gstate_get_target_surface),
+ (_cairo_gstate_get_pattern), (_cairo_gstate_get_operator),
+ (_cairo_gstate_get_rgb_color), (_cairo_gstate_get_tolerance),
+ (_cairo_gstate_get_alpha), (_cairo_gstate_get_fill_rule),
+ (_cairo_gstate_get_line_width), (_cairo_gstate_get_line_cap),
+ (_cairo_gstate_get_line_join), (_cairo_gstate_get_miter_limit),
+ (_cairo_gstate_get_matrix), (_cairo_gstate_get_current_point),
+ (_cairo_gstate_show_surface), (_cairo_gstate_get_font),
+ (_cairo_gstate_get_font_transform), (_cairo_gstate_get_font_scale),
+ (_cairo_gstate_ensure_font), (_cairo_gstate_get_font_extents),
+ (_cairo_gstate_text_to_glyphs):
+ * src/cairo_path.c: (_cairo_path_get_current_point):
+ * src/cairoint.h:
+ * test/pixman_rotate.c: (draw):Rename all the cairo_current
+ functions to cairo_get functions instead. Add documentation for
+ all of these functions (and a few others as well).
+
+ Add support so that old binarys should still run and old source
+ should still compile, (though we'll rip that out again on the API
+ Shakeup flag day).
+
+2005-03-08 Carl Worth <cworth@cworth.org>
+
+ * configure.in: Add -head to CAIRO_VERSION after tagging with
+ SNAPSHOT_0_4_0.
+
2005-03-08 Carl Worth <cworth@cworth.org>
* gtk-doc.make (dist-check-gtkdoc): Commit workaround to prevent
diff --git a/NEWS b/NEWS
index 62a1b1829..447583c45 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,307 @@
+Snapshot 0.5.0 (2005-05-17 Carl Worth <cworth@cworth.org>)
+==========================================================
+This is a pretty big, and fairly significant snapshot. It represents
+between 2 and 3 months of solid work from a lot of people on improving
+the API as much as possible. I'd like to express my appreciation and
+congratulations to everyone who has worked on the big API Shakeup,
+(whether in email battles over names, or fixing my silly bugs).
+
+This snapshot will require some effort on the part of users, since
+there are a _lot_ of API changes (ie. no cairo program ever written is
+safe --- they're all broken now in at least one way). But, in spite of
+that, we do encourage everyone to move their code to this snapshot as
+soon as possible. And we're doing everything we can think of to make
+the transition as smooth as possible.
+
+The idea behind 0.5 is that we've tried to make every good API change
+we could want now, and get them all done with. That is, between now
+and the 1.0 release of cairo, we expect very few new API changes,
+(though some will certainly sneak in). We will have some significant
+additions, but the pain of moving code from cairo 0.4 to cairo 0.5
+should be a one time experience, and things should be much smoother as
+we continue to move toward cairo 1.0.
+
+And with so many changes coming out for the first time in this 0.5
+release, we really do need a lot of people trying this out to make
+sure the ideas are solid before we freeze the API in preparation for
+the 1.0 release.
+
+OK, enough introduction. Here is a (not-quite-complete) description of
+the API removals, changes and additions in this snapshot, (compared to
+0.4.0)
+
+API removals
+============
+The following public functions have been removed:
+
+- cairo_set_target_*
+
+ This is a big change. See the description of cairo_create in
+ the API changes section for how to deal with this.
+
+- cairo_set_alpha
+
+ Alpha blending hasn't gone away; there's just a much more
+ unified rendering model now. Almost all uses of
+ cairo_set_alpha will be trivially replaced with
+ cairo_set_source_rgba and a few others will be replaced just
+ as easily with cairo_paint_with_alpha.
+
+- cairo_show_surface
+
+ Another useful function that we realized was muddling up the
+ rendering model. The replacement is quite easy:
+ cairo_set_source_surface and cairo_paint.
+
+- cairo_matrix_create
+- cairo_matrix_destroy
+- cairo_matrix_copy
+- cairo_matrix_get_affine
+
+ These functions supported an opaque cairo_matrix_t. We now
+ have an exposed cairo_matrix_t structure, so these can be
+ dropped.
+
+- cairo_surface_set_repeat
+- cairo_surface_set_matrix
+- cairo_surface_set_filter
+
+ These properties don't belong on surfaces. If you were using
+ them, you'll just want to instead use
+ cairo_pattern_create_for_surface and then set these properties
+ on the pattern.
+
+- cairo_copy
+
+ This was a confusing function and hopefully nobody will miss
+ it. But if you really don't find cairo_save/restore adequate,
+ let us know and we have another idea for a potential
+ replacement.
+
+And while we're on the subject of removals, we carefully tightened up
+the cairo header files so they no longer gratuitously include header
+files that are not strictly necessary, (stdio.h, stdint.h, pixman.h,
+Xrender.h, etc. and their dependencies). This may lead to some
+surprising errors, so keep your eyes open for that.
+
+API changes
+===========
+Here are some of the API changes that have occurred:
+
+~ cairo_create(void) -> cairo_create(cairo_surface_t *)
+
+ This is the big change that breaks every program. The ability
+ to re-target a cairo_t was not particularly useful, but it did
+ introduce a lot of muddy semantic questions. To eliminate
+ that, cairo_create now requires its target surface to be
+ passed in at creation time. This isn't too hard to cope with
+ as the typical first operation after cairo_create was often
+ cairo_set_target_foo. So the order of those two swap and the
+ application instead has cairo_foo_surface_create, then
+ cairo_create.
+
+~ cairo_current_* -> cairo_get_*
+
+ We had a strange mixture of cairo_get and cairo_current
+ functions. They've all been standardized on cairo_get, (though
+ note one is cairo_get_current_point).
+
+~ CAIRO_OPERATOR_SRC -> CAIRO_OPERATOR_SOURCE
+~ CAIRO_OPERATOR_OVER_REVERSE -> CAIRO_OPERATOR_DEST_OVER
+
+ Many of the cairo_operator_t symbolic values were renamed to
+ reduce the amount of abbreviation. The confusing "OP_REVERSE"
+ naming was also changed to use "DEST_OP" instead which is
+ easier to read and has wider acceptance in other
+ libraries/languages.
+
+~ cairo_set_pattern -> cairo_set_source
+~ cairo_set_rgb_color -> cairo_set_source_rgb
+
+ All of the various functions that changed the source
+ color/pattern were unified to use cairo_set_source names to
+ make the relation more clear.
+
+~ cairo_transform_point -> cairo_user_to_device
+~ cairo_transform_distance -> cairo_user_to_device_distance
+~ cairo_inverse_transform_point -> cairo_device_to_user
+~ cairo_inverse_transform_distance -> cairo_device_to_user_distance
+
+ These names just seemed a lot more clear.
+
+~ cairo_init_clip -> cairo_reset_clip
+~ cairo_concat_matrix -> cairo_transform
+
+ More abbreviation elimination
+
+~ cairo_current_path -> cairo_copy_path
+~ cairo_current_path_flat -> cairo_copy_path_flat
+
+ The former mechanism for examining the current path was a
+ function that required 3 or 4 callbacks. This was more
+ complexity than warranted in most situations. The new
+ cairo_copy_path function copies the current path into an
+ exposed data structure, and the documentation provides a
+ convenient idiom for navigating the path data.
+
+API additions
+-------------
++ cairo_paint
+
+ A generalized version of the painting operators cairo_stroke
+ and cairo_fill. The cairo_paint call applies the source paint
+ everywhere within the current clip region. Very useful for
+ clearing a surface to a solid color, or painting an image,
+ (see cairo_set_source_surface).
+
++ cairo_paint_with_alpha
+
+ Like cairo_paint but applying some alpha to the source,
+ (making the source paint translucent, eg. to blend an image on
+ top of another).
+
++ cairo_mask
+
+ A more generalized version of cairo_paint_with_alpha which
+ allows a pattern to specify the amount of translucence at each
+ point rather than using a constant value everywhere.
+
++ cairo_mask_surface
+
+ A convenience function on cairo_mask for when the mask pattern
+ is already contained within a surface.
+
++ cairo_surface_set_user_data
++ cairo_surface_get_user_data
++ cairo_font_face_set_user_data
++ cairo_font_face_get_user_data
+
+ Associate arbitrary data with a surface or font face for later
+ retrieval. Get notified when a surface or font face object is
+ destroyed.
+
++ cairo_surface_finish
+
+ Allows the user to instruct cairo to finish all of its
+ operations for a given surface. This provides a safe point for
+ doing things such as flushing and closing files that the
+ surface may have had open for writing.
+
++ cairo_fill_preserve
++ cairo_stroke_preserve
++ cairo_clip_preserve
+
+ One interesting change in cairo is that the path is no longer
+ part of the graphics state managed by
+ cairo_save/restore. This allows functions to construct paths
+ without interfering with the graphics state. But it prevents
+ the traditional idiom for fill-and-stroke:
+
+ cairo_save; cairo_fill; cairo_restore; cairo_stroke
+
+ Instead we know have alternate versions cairo cairo_fill,
+ cairo_stroke, and cairo_clip that preserve the current path
+ rather than consuming it. So the idiom now becomes simply:
+
+ cairo_fill_preserve; cairo_stroke
+
++ cairo_surface_write_to_png
++ cairo_surface_write_to_png_stream
+
+ In place of a single PNG backend, now a surface created
+ through any backend (except PDF currently) can be written out
+ to a PNG image.
+
++ cairo_image_surface_create_from_png
++ cairo_image_surface_create_from_png_stream
+
+ And its just as easy to load a PNG image into a surface as well.
+
++ cairo_append_path
+
+ With the new, exposed path data structure, it's now possible
+ to append bulk path data to the current path, (rather than
+ issuing a long sequence of cairo_move_to/line_to/curve_to
+ function calls).
+
+Xlib and XCB backends
+---------------------
+
+Any cairo_format_t and Colormap arguments have been dropped from
+cairo_xlib_surface_create. There are also two new
+cairo_xlib|xcb_surface_create functions:
+
+ cairo_xlib|xcb_surface_create_for_bitmap
+ (Particular for creating A1 surfaces)
+ cairo_xlib|xcb_surface_create_with_xrender_format
+ (For any other surface types, not described by a Visual*)
+
+All of these surface create functions now accept width and height. In
+addition, there are new cairo_xlib|xcb_surface_set_size functions
+which must be called each time a window that is underlying a surface
+changes size.
+
+Print backends (PS and PDF)
+---------------------------
+The old FILE* based interfaces have been eliminated. In their place we
+have two different functions. One accepts a simple const char
+*filename. The other is a more general function which accepts a
+callback write function and a void* closure. This should allow the
+flexibility needed to hook up with various stream object in many
+languages.
+
+In addition, when specifying the surface size during construction, the
+units are now device-space units (ie. points) rather than inches. This
+provides consistency with all the other surface types and also makes
+it much easier to reason about the size of the surface when drawing to
+it with the default identity matrix.
+
+Finally, the DPI parameters, which are only needed to control the
+quality of fallbacks, have been made optional. Nothing is required
+during surface_create (300 DPI is assumed) and
+cairo_ps|pdf_surface_set_dpi can be used to set alternate values if
+needed.
+
+Font system
+-----------
+Owen very graciously listened to feedback after the big font rework he
+had done for 0.4, and came up with way to improve it even more. In 0.4
+there was a cairo_font_t that was always pre-scaled. Now, there is an
+unscaled cairo_font_face_t which is easier to construct, (eg. no
+scaling matrix required) and work with, (it can be scaled and
+transformed after being set on the graphics state). And the font size
+manipulation functions are much easier. You can set an explicit size
+and read/modify/write the font matrix with:
+
+ cairo_set_font_size
+ cairo_get_font_matrix
+ cairo_set_font_matrix
+
+(Previously you could only multiply in a scale factor or a matrix.) A
+pleasant side effect is that we can (and do) now have a default font
+size that is reasonable, as opposed to the old default height of one
+device-space unit which was useless until scaled.
+
+Of course, the old pre-scaled font had allowed some performance
+benefits when getting many metrics for a font. Those benefits are
+still made available through the new cairo_scaled_font_t. And a
+cairo_font_face_t can be "promoted" to a cairo_scaled_font_t by
+suppling a font_matrix and the desired CTM.
+
+Quartz backend
+--------------
+Tim Rowley put in the work to bring the Quartz backend back after it
+had been disabled in the 0.4.0 snapshot. He was not able to bring back
+the function that allows one to create a cairo_font_t from an ATSUI
+style:
+
+ cairo_font_t *
+ cairo_atsui_font_create (ATSUStyle style);
+
+because he didn't have a test case for it. If you care about this
+function, please provide a fairly minimal test and we'll try to bring
+it back in an upcoming snapshot.
+
Snapshot 0.4.0 (2005-03-08 Carl Worth <cworth@cworth.org>)
==========================================================
New documentation
diff --git a/PORTING_GUIDE b/PORTING_GUIDE
new file mode 100644
index 000000000..b8bdd37b6
--- /dev/null
+++ b/PORTING_GUIDE
@@ -0,0 +1,257 @@
+ ...-----=======-----...
+ Cairo 0.5 Porting Guide
+ ...-----=======-----...
+
+Here are some notes on more easily porting cairo_code from cairo 0.4
+to cairo 0.5. It is sorted roughly in order of importance, (the items
+near the top are expected to affect the most people).
+
+Automated API renamings
+=======================
+There have been a lot of simple renamings where the functionality is
+the same but the name of the symbol is different. We have provided a
+script to automate the conversion of these symbols. It can be found
+within the cairo distribution in:
+
+ util/cairo-api-update
+
+This script is used by installing it somewhere on your PATH, and the
+running it and providing the names of your source files on the command
+line. For example:
+
+ cairo-api-update *.[ch]
+
+The script will first save backup copies of each file (renamed with a
+.bak extension) and then will perform all of the simple renamings.
+
+For your benefit, the script also produces messages giving filenames
+and line numbers for several of the manual API updates that you will
+need to perform as described below.
+
+
+Manual API changes
+==================
+This section of the porting guide describes changes you will have to
+manually make to your source code. In addition to the information in
+this guide, the cairo-api-update script will notify you of some of
+these issues as described above.
+
+Cairo's deprecation warnings
+----------------------------
+Also, if your compiler provides warnings for implicit declarations of
+functions, (eg. "gcc -Wall"), then simply attempting to compile your
+program will cause cairo to generate messages intended to guide you
+through the porting process.
+
+For example, if you neglect to update an old call to
+cairo_set_target_drawable, you might see an error message as follows:
+
+ foo.c:10: warning: implicit declaration of function
+ ‘cairo_set_target_drawable_DEPRECATED_BY_cairo_xlib_surface_create’
+
+This message is indicating to you that the deprecatd function
+cairo_set_target_drawable appears in your program foo.c on line 10,
+and you should rewrite your program to call cairo_xlib_surface_create
+instead.
+
+The remainder of this porting guide is arranged as a set of common
+code patterns that appear in old (cairo-0.4) code and how it should be
+transformed to new (cairo-0.5) code.
+
+cairo_create
+------------
+Was: cr = cairo_create ();
+ cairo_set_target_foo (cr, args);
+ /* draw */
+ cairo_destroy (cr);
+
+Now: cairo_surface_t *surface;
+
+ surface = cairo_foo_surface_create (args);
+ cr = cairo_create (surface);
+ /* draw */
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+Or: cairo_surface_t *surface;
+
+ surface = cairo_foo_surface_create (args);
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+ /* draw */
+ cairo_destroy (cr);
+
+NOTE: Many of the cairo_foo_surface_create functions accept the
+ identical arguments as the the old cairo_set_target_foo
+ functions, (minus the cairo_t*), making this transformation
+ quite easy. One notable exception is cairo_set_target_drawable
+ which, when it becomes cairo_xlib_surface_create must pickup new
+ arguments for the Visual*, the width, and the height.
+
+cairo_set_alpha (1)
+-------------------
+Was: cairo_set_rgb_color (cr, red, green, blue);
+ cairo_set_alpha (cr, alpha);
+
+Now: cairo_set_source_rgba (cr, red, green, blue, alpha);
+
+cairo_show_surface
+------------------
+Was: cairo_show_surface (cr, surface, width, height);
+
+Now: cairo_set_source_surface (cr, surface, x, y);
+ cairo_paint (cr);
+
+NOTE: The type signatures of cairo_show_surface and cairo_set_source
+ are the same, but pay attention that cairo_show_surface required
+ the width and height, while cairo_set_source_surface requires
+ the X,Y location to where the surface will be placed.
+
+cairo_set_alpha (2)
+-------------------
+Was: cairo_set_alpha (cr, alpha);
+ cairo_show_surface (cr, surface, width, height);
+
+Now: cairo_set_source_surface (cr, surface, x, y);
+ cairo_paint_with_alpha (cr, alpha);
+
+filling and stroking
+--------------------
+Was: cairo_save (cr);
+ /* set fill color */
+ cairo_fiill (cr);
+ cairo_restore (cr);
+ /* set stroke color */
+ cairo_stroke (cr);
+
+Now: /* set fill color */
+ cairo_fill_preserve (cr);
+ /* set stroke color */
+ cairo_stroke (cr);
+
+NOTE: The current path is no longer saved/restored by
+ cairo_save/cairo_restore. This can lead to some subtle
+ surprises, so look out.
+
+cairo_matrix_t
+--------------
+Was: cairo_matrix_t *matrix;
+
+ matrix = cairo_matrix_create ();
+ /* Do stuff with matrix */
+ cairo_matrix_destroy (matrix);
+
+Now: cairo_matrix_t matrix;
+ cairo_matrix_init_identity (&matrix);
+ /* Do stuff with &matrix */
+
+NOTE: If you are really lazy, you can still use a cairo_matrix_t* and
+ avoid putting the &matrix all over by just replacing
+ cairo_matrix_create() with malloc() and cairo_matrix_destroy()
+ with free(). That's not as nice, and you still need to be
+ careful to see if you need to initialize it to an identity
+ matrix as cairo_matrix_create() did for you.
+
+Rendering to a temporary surface
+--------------------------------
+Was: cairo_save (cr);
+ {
+ cairo_set_target_surface (cr, temporary);
+ /* draw through cr onto temporary */
+ }
+ cairo_restore (cr);
+ /* use temporary as source on cr */
+
+Now: {
+ cr2 = cairo_create (temporary);
+ /* draw through cr2 onto temporary */
+ cairo_destory (cr2);
+ }
+ /* use temporary as source on cr */
+
+NOTE: Having to create another cairo_t is a bit annoying, but having
+ to invent a new name for it is just awful, (imagine a deeply
+ nested version of this code). Fortunately, the style above is
+ just a stop-gap measure until the new group API comes along.
+
+Iterating over a path
+---------------------
+Was: cairo_current_path (cr,
+ my_move_to,
+ my_line_to,
+ my_curve_to,
+ my_close_path,
+ closure);
+
+Now: int i;
+ cairo_path_t *path;
+ cairo_path_data_t *data;
+
+ path = cairo_copy_path (cr);
+
+ for (i=0; i < path->num_data; i += path->data[i].header.length) {
+ data = &path->data[i];
+ switch (data->header.type) {
+ case CAIRO_PATH_MOVE_TO:
+ my_move_to (closure, data[1].point.x, data[1].point.y);
+ break;
+ case CAIRO_PATH_LINE_TO:
+ my_line_to (closure, data[1].point.x, data[1].point.y);
+ break;
+ case CAIRO_PATH_CURVE_TO:
+ my_curve_to (closure, data[1].point.x, data[1].point.y,
+ data[2].point.x, data[2].point.y,
+ data[3].point.x, data[3].point.y);
+ break;
+ case CAIRO_PATH_CLOSE_PATH:
+ my_close_path (closure);
+ break;
+ }
+ }
+ cairo_path_destroy (path);
+
+NOTE: This version makes it looks like the new form is a _lot_ more
+ verbose than the old version. But realize that the old version
+ required the support of 4 additional functions. The new approach
+ allows great flexibility including the ability to inline the
+ entire operation within the switch statement when appropriate.
+
+Erasing a surface to transparent
+--------------------------------
+Was: cairo_set_rgb_color (cr, 0., 0., 0.);
+ cairo_set_alpha (cr, 0.)
+ cairo_set_operator (cr, CAIRO_OPERATOR_SRC);
+ cairo_rectangle (cr, 0., 0., surface_width, surface_height);
+ cairo_fill (cr);
+
+Now: cairo_set_source_rgba (cr, 0., 0., 0., 0.);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+
+NOTE: Using cairo_rectanlgle and fill would still work just fine. It's
+ just a lot more convenient to use cairo_paint now, (particularly
+ as it doesn't require you to even know what the bounds of the
+ target surface are).
+
+Drawing to a PNG file
+---------------------
+Was: file = fopen (filename, "w");
+ cr = cairo_create ();
+ cairo_set_target_png (cr, file, format, width, height);
+ /* draw image */
+ cairo_destroy (cr);
+ fclose (file);
+
+Now: surface = cairo_image_surface_create (format, width, height);
+ cr = cairo_create (surface);
+ /* draw image */
+ cairo_surface_write_to_png (surface, filename);
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+NOTE: The png backend is gone. So there is no cairo_png_surface_create
+ to take the place of cairo_set_target_png. And notice that we
+ used an image surface here, but it is just as easy to use
+ cairo_surface_write_to_png with an xlib or other surface, (but
+ not PDF at the moment). This is one of the big advantages of
+ this approach as opposed to a PNG surface.
diff --git a/RELEASING b/RELEASING
index 57f289dfc..c6513f451 100644
--- a/RELEASING
+++ b/RELEASING
@@ -18,9 +18,10 @@ fixes are committed. Here are the steps to follow:
Running "make distcheck" should result in no warnings or
errors and end with a message of the form:
- ================================================
- cairo-X.Y.Z.tar.gz is ready for distribution
- ================================================
+ ==================================================
+ cairo-X.Y.Z-head archives ready for distribution:
+ caioo-X.Y.Z-head.tar.gz
+ ==================================================
(But the tar file isn't actually ready yet, as we still have
some more steps to follow).
@@ -31,11 +32,14 @@ fixes are committed. Here are the steps to follow:
snapshot. Summarize major changes briefly in a style similar
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
+ by looking for cairo*.h in the ChangeLog. Additionally, the
output of the following command should be examined using the
previous snapshot tag:
- cvs diff -r SNAPSHOT_X_Y_Z src/cairo.h
+ cvs diff -r SNAPSHOT_X_Y_Z src/*.h
+
+ [Hmm, it would be nice to have a pattern for that command that
+ would exclude private header files.]
4) Increment CAIRO_VERSION in configure.in
diff --git a/ROADMAP b/ROADMAP
new file mode 100644
index 000000000..4a47c4964
--- /dev/null
+++ b/ROADMAP
@@ -0,0 +1,80 @@
+Here are some quick notes as far as a cairo roadmap goes.
+
+See also the TODO file for a different view, (less organized, but
+often in more detail, particularly for the API Shakeup work in
+progress).
+
+cairo 1.0 release requirements
+==============================
+
+Implementation work
+-------------------
+ I1. Fix clipping to be sane
+ Dificulty: moderate
+ Status: cworth has started looking at this
+
+ I2. Real PostScript/PDF fallbacks (cairo_meta_surface_t)
+ Difficulty: hard
+ Status: otaylor has drafted a plan or two on the list
+
+API Issues (more detail in TODO file)
+-------------------------------------
+
+✓A1. Add cairo_paint
+ Difficulty: moderate or moderate to minor
+ Dependencies: much easier after [I1]. needs some cleanups from [A4]
+ Status: Done
+
+✓A2. Add cairo_mask
+ Difficulty: moderate
+ Status: Done
+
+ A3. Add cairo_begin/end/get_group
+ Difficulty: easy to hard (depending on how sophisticated an
+ implementation is acceptable, and whether the
+ cairo_meta_surface_t mentioned in [I2] is done)
+ Status: cworth sent API proposal to the list
+ (still some unresolved API issues)
+
+✓A4. Make set_source consistent
+ Difficulty: easy
+ Dependencies: needs [A2,A3] to avoid losing functionality,
+ (but we may just live with that as we've now got
+ a circular dependency)
+ Status: Done.
+
+✓A5. Add cairo_clip/fill/stroke_preserve
+ Difficulty: easy
+ Status: Done.
+
+✓A6. Just eliminate a bunch of functions:
+
+ ✓ cairo_set_target_*
+ ✓ cairo_copy
+ ✓ cairo_surface_set_repeat/matrix/filter
+ ✓ cairo_show_surface
+
+ Difficulty: trivial
+ Dependencies: eliminating cairo_show_surface depends on [A1]
+ Status: Done.
+
+ A7. cairo_surface_mark_dirty
+ Difficulty: trivial to add API, moderate to actually optimize
+ based on it
+ Status: cworth has sent API proposal to list
+
+ A8. cairo_format_t:
+ Difficulty: moderate. It's just going through and examining
+ each use of cairo_format_t, but there are a lot
+ of them.
+ Status: not started, there is a rough plan in TODO
+
+Performance work
+----------------
+✓P1. Make pixel-aligned rectangle compositing fast
+ Difficulty: moderate to easy
+ Status: Done.
+
+ P2. Generate better trapezoids to go easier on the rasterizer
+ Difficulty: moderate to hard
+ Status: cworth drafted a plan to the list
diff --git a/TODO b/TODO
index f0edbc309..ea44263ed 100644
--- a/TODO
+++ b/TODO
@@ -1,29 +1,42 @@
-API Shakeup work
-----------------
-Patch? Reviewed?
-yes yes user data (was Re: [cairo] Patch improving fallbacks)
- cairo_paint
-yes yes setters and getters
- cairo_current_matrix
- Renaming the terms of the rendering equation
- Making set_source consistent
- Eliminating cairo_show_surface
- cairo_mask
- cairo_begin_group, cairo_end_group, cairo_get_group
-yes yes cairo_output_stream_t and cairo_surface_finish()
- cairo_create and eliminating cairo_set_target_surface
- cairo_fill_preserve, cairo_stroke_preserve, cairo_clip_preserve
- default matrix
- cairo_current_path -> cairo_copy_path_data
- cairo_surface_finish, cairo_surface_flush
- cairo_<device>_surface_mark_dirty
- Eliminating cairo_copy
- Eliminating cairo_surface_set_repeat/matrix/filter
- A hidden offset for the xlib backend
- cairo_stroke_path -> cairo_stroke_to_path
- Simplifying the operator set
- Abbreviation hunt: cairo_init_clip and cairo_concat_matrix
- Consistent error handling for all objects
+API Shakeup planning
+--------------------
+ Patch submitted to mailing list?
+/ Documentation included in patch?
+|/ Review of patch completed?
+||/ Test case included?
+|||/ Committed.
+||||/
+New functionality (more-or-less)
+--------------------------------
+ cairo_begin_group, cairo_end_group, cairo_get_group
+ cairo_<device>_surface_mark_dirty
+ Consistent error handling for all objects
+
+Somewhat backwards-compatible changes
+-----------------------------------
+PDRTC user data (was Re: [cairo] Patch improving fallbacks)
+PDRTC setters and getters
+PDRTC cairo_output_stream_t and cairo_surface_finish()
+PDRTC cairo_current_path -> cairo_copy_path_data
+PDR C cairo_surface_finish, cairo_surface_flush
+PDRTC Abbreviation hunt: cairo_init_clip and cairo_concat_matrix
+PDRTC Renaming the terms of the rendering equation
+PDRTC default matrix
+PDRTC cairo_paint
+PDRTC Making set_source consistent
+PDRTC cairo_stroke_path -> cairo_stroke_to_path
+PDRTC cairo_current_matrix
+PDRTC cairo_mask
+PDRTC cairo_fill_preserve, cairo_stroke_preserve, cairo_clip_preserve
+PDR C A hidden offset for the xlib backend
+
+Backwards incompatible
+----------------------
+PDRTC Simplifying the operator set
+PDRTC cairo_create and eliminating cairo_set_target_surface
+PDRTC Eliminating cairo_copy
+PDRTC Eliminating cairo_surface_set_repeat/matrix/filter
+PDRTC Eliminating cairo_show_surface
* Add support for non-antialiased rendering. API ?
@@ -37,8 +50,37 @@ yes yes cairo_output_stream_t and cairo_surface_finish()
((src Op dest) In clip) Add (dest Out clip)
-* Replace PNG backend with an image_surface function to save a PNG
- image.
+* Split cairo_format_t into two things:
+
+ - An enumeration that determines the "capabilities" of a surface -
+ A vs. ARGB. vs. RGB
+ - An enumeration that determines a specific in-memory representation
+ of data. (A1/A8/ARGB32/etc.. Could be extensible to things like
+ RGBA32_BYTES_NONPREMULTIPLIED. Some consistent naming convention would
+ be be good.)
+
+ One issue here is that some interfaces, like cairo_surface_create_similar()
+ might be useful with either one. We might want to create an A1 surface
+ compatible with the backend (are there examples other than A1? Should
+ bilevel just be another "capability"?), or we might want to just create
+ an alpha surface without caring about the depth.
+
+ If we want to support this, we could do something like:
+
+ typedef enum cairo_pixel_format_t {
+ CAIRO_PIXEL_FORMAT_A8 = CAIRO_FORMAT_ALPHA,
+ CAIRO_PIXEL_FORMAT_RGB24 = CAIRO_FORMAT_RGB,
+ CAIRO_PIXEL_FORMAT_A1,
+ };
+
+ To allow passing either in.
+
+ (I don't particularly like this idea for create_similar() because then you
+ aren't really saying ALPHA-dont-care, you are saying ALPHA-8. I think it
+ would be better to have a separate path for create_similar_with_pixel_format()
+ if we need that. But it might be useful for cairo_image_surface_create() ...
+ people are going to screw up and pass CAIRO_FORMAT_RGB into that, and if it
+ "just worked" that would save people trouble....)
* Clean up the API in preparation for freezing and release.
@@ -83,9 +125,6 @@ do gradients the Right Way).
* Implement cairo_arc_to.
-* Re-implement the trapezoid rasterization algorithm according to the
- new "specification".
-
* Stroking closed, degenerate paths should still draw caps. Round
caps are easy; square should probably draw an axis-aligned square.
@@ -128,3 +167,7 @@ do gradients the Right Way).
* Verification, profiling, optimization.
centi_unfinished.svg may provide a good test case.
+
+* Implement copy-on-write regions in pixman as a more complete
+ solution than the BAD_NESTING stuff to Owen's "Clip region problems"
+ thread.
diff --git a/autogen.sh b/autogen.sh
index f834cfed1..ae8acc606 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -93,7 +93,7 @@ else
fi
if test -z "$ACLOCAL_FLAGS"; then
- acdir=`aclocal --print-ac-dir`
+ acdir=`$ACLOCAL --print-ac-dir`
if [ ! -f $acdir/pkg.m4 ]; then
echo "$ARGV0: Error: Could not find pkg-config macros."
echo " (Looked in $acdir/pkg.m4)"
diff --git a/configure.in b/configure.in
index 5ee585e73..070b0ef64 100644
--- a/configure.in
+++ b/configure.in
@@ -5,7 +5,7 @@ AC_INIT(src/cairo.h)
dnl ===========================================================================
# Package version number, (as distinct from shared library version)
-CAIRO_VERSION=0.4.0
+CAIRO_VERSION=0.5.0
# libtool shared library version
@@ -60,18 +60,15 @@ if test "x$use_xlib" = "xyes"; then
AC_PATH_XTRA
XRENDER_LIBS="$X_LIBS -lXrender -lXext -lX11 $X_EXTRA_LIBS"
use_xlib=yes], [
- use_xlib="no (requires Xrender http://freedesktop.org/software/xlibs)"])])
+ use_xlib="no (requires Xrender http://freedesktop.org/Software/xlibs)"])])
fi
-if test "x$use_xlib" != "xyes"; then
- XLIB_SURFACE_FEATURE=CAIRO_HAS_NO_XLIB_SURFACE
- AM_CONDITIONAL(CAIRO_HAS_XLIB_SURFACE, false)
-else
- XLIB_SURFACE_FEATURE=CAIRO_HAS_XLIB_SURFACE
- AM_CONDITIONAL(CAIRO_HAS_XLIB_SURFACE, true)
+AM_CONDITIONAL(CAIRO_HAS_XLIB_SURFACE, test "x$use_xlib" = "xyes")
+if test "x$use_xlib" = "xyes"; then
+ XLIB_SURFACE_FEATURE="#define CAIRO_HAS_XLIB_SURFACE 1"
fi
-
AC_SUBST(XLIB_SURFACE_FEATURE)
+
AC_SUBST(XRENDER_REQUIRES)
CAIRO_CFLAGS="$CAIRO_CFLAGS $XRENDER_CFLAGS"
@@ -79,22 +76,18 @@ CAIRO_LIBS="$CAIRO_LIBS $XRENDER_LIBS"
AC_ARG_ENABLE(quartz,
[ --disable-quartz Disable cairo's quartz backend],
- [use_quartz=$enableval], [use_quartz="no (temporarily disabled while code is out of sync)"])
+ [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
+AM_CONDITIONAL(CAIRO_HAS_QUARTZ_SURFACE, test "x$use_quartz" = "xyes")
+if test "x$use_quartz" = "xyes"; then
+ QUARTZ_SURFACE_FEATURE="#define CAIRO_HAS_QUARTZ_SURFACE 1"
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"
@@ -106,21 +99,18 @@ AC_ARG_ENABLE(xcb,
if test "x$use_xcb" = "xyes"; then
PKG_CHECK_MODULES(XCB, xcb, [use_xcb=yes], [
- use_xcb="no (requires XCB http://freedesktop.org/software/xcb)"])
+ use_xcb="no (requires XCB http://xcb.freedesktop.org)"])
fi
-if test "x$use_xcb" != "xyes"; then
- XCB_SURFACE_FEATURE=CAIRO_HAS_NO_XCB_SURFACE
- AM_CONDITIONAL(CAIRO_HAS_XCB_SURFACE, false)
-else
- XCB_SURFACE_FEATURE=CAIRO_HAS_XCB_SURFACE
- AM_CONDITIONAL(CAIRO_HAS_XCB_SURFACE, true)
+AM_CONDITIONAL(CAIRO_HAS_XCB_SURFACE, test "x$use_xcb" = "xyes")
+if test "x$use_xcb" = "xyes"; then
+ XCB_SURFACE_FEATURE="#define CAIRO_HAS_XCB_SURFACE 1"
fi
+AC_SUBST(XCB_SURFACE_FEATURE)
CAIRO_CFLAGS="$CAIRO_CFLAGS $XCB_CFLAGS"
CAIRO_LIBS="$CAIRO_LIBS $XCB_LIBS"
-AC_SUBST(XCB_SURFACE_FEATURE)
dnl ===========================================================================
@@ -147,23 +137,16 @@ if test "x$use_win32" = "xyes"; then
CAIRO_LIBS="$CAIRO_LIBS -lgdi32 -lmsimg32"
fi
-if test "x$use_win32" != "xyes"; then
- WIN32_SURFACE_FEATURE=CAIRO_HAS_NO_WIN32_SURFACE
- AM_CONDITIONAL(CAIRO_HAS_WIN32_SURFACE, false)
-else
- WIN32_SURFACE_FEATURE=CAIRO_HAS_WIN32_SURFACE
- AM_CONDITIONAL(CAIRO_HAS_WIN32_SURFACE, true)
+AM_CONDITIONAL(CAIRO_HAS_WIN32_SURFACE, test "x$use_win32" = "xyes")
+if test "x$use_win32" = "xyes"; then
+ WIN32_SURFACE_FEATURE="#define CAIRO_HAS_WIN32_SURFACE 1"
fi
+AC_SUBST(WIN32_SURFACE_FEATURE)
-if test "x$use_win32" != "xyes"; then
- WIN32_FONT_FEATURE=CAIRO_HAS_NO_WIN32_FONT
- AM_CONDITIONAL(CAIRO_HAS_WIN32_FONT, false)
-else
- WIN32_FONT_FEATURE=CAIRO_HAS_WIN32_FONT
- AM_CONDITIONAL(CAIRO_HAS_WIN32_FONT, true)
+AM_CONDITIONAL(CAIRO_HAS_WIN32_FONT, test "x$use_win32" = "xyes")
+if test "x$use_win32" = "xyes"; then
+ WIN32_FONT_FEATURE="#define CAIRO_HAS_WIN32_FONT 1"
fi
-
-AC_SUBST(WIN32_SURFACE_FEATURE)
AC_SUBST(WIN32_FONT_FEATURE)
dnl ===========================================================================
@@ -172,24 +155,27 @@ AC_ARG_ENABLE(ps,
[ --disable-ps Disable cairo's PostScript backend],
[use_ps=$enableval], [use_ps=yes])
-if test "x$use_ps" != "xyes"; then
- PS_SURFACE_FEATURE=CAIRO_HAS_NO_PS_SURFACE
- AM_CONDITIONAL(CAIRO_HAS_PS_SURFACE, false)
-else
- PS_SURFACE_FEATURE=CAIRO_HAS_PS_SURFACE
+# The postscript module requires zlib.
+AC_CHECK_LIB(z, compress,
+ [AC_CHECK_HEADER(zlib.h, [],
+ [use_ps="no (requires zlib http://www.gzip.org/zlib/)"])],
+ [use_ps="no (requires zlib http://www.gzip.org/zlib/)"])
+
+AM_CONDITIONAL(CAIRO_HAS_PS_SURFACE, test "x$use_ps" = "xyes")
+if test "x$use_ps" = "xyes"; then
+ PS_SURFACE_FEATURE="#define CAIRO_HAS_PS_SURFACE 1"
PS_LIBS=-lz
- AM_CONDITIONAL(CAIRO_HAS_PS_SURFACE, true)
fi
+AC_SUBST(PS_SURFACE_FEATURE)
CAIRO_LIBS="$CAIRO_LIBS $PS_LIBS"
-AC_SUBST(PS_SURFACE_FEATURE)
AC_SUBST(PS_LIBS)
dnl ===========================================================================
AC_ARG_ENABLE(png,
- [ --disable-png Disable cairo's PNG backend],
+ [ --disable-png Disable cairo's PNG functions],
[use_png=$enableval], [use_png=yes])
if test "x$use_png" = "xyes"; then
@@ -211,18 +197,15 @@ if test "x$use_png" = "xyes"; then
fi
fi
-if test "x$use_png" != "xyes"; then
- PNG_SURFACE_FEATURE=CAIRO_HAS_NO_PNG_SURFACE
- AM_CONDITIONAL(CAIRO_HAS_PNG_SURFACE, false)
-else
- PNG_SURFACE_FEATURE=CAIRO_HAS_PNG_SURFACE
- AM_CONDITIONAL(CAIRO_HAS_PNG_SURFACE, true)
+AM_CONDITIONAL(CAIRO_HAS_PNG_FUNCTIONS, test "x$use_png" = "xyes")
+if test "x$use_png" = "xyes"; then
+ PNG_FUNCTIONS_FEATURE="#define CAIRO_HAS_PNG_FUNCTIONS 1"
fi
+AC_SUBST(PNG_FUNCTIONS_FEATURE)
CAIRO_CFLAGS="$CAIRO_CFLAGS $PNG_CFLAGS"
CAIRO_LIBS="$CAIRO_LIBS $PNG_LIBS"
-AC_SUBST(PNG_SURFACE_FEATURE)
AC_SUBST(PNG_REQUIRES)
dnl ===========================================================================
@@ -234,39 +217,22 @@ AC_ARG_ENABLE(glitz,
if test "x$use_glitz" = "xyes"; then
PKG_CHECK_MODULES(GLITZ, glitz >= 0.4.0, [
GLITZ_REQUIRES=glitz
- use_glitz=yes], [use_glitz="no (requires glitz http://freedesktop.org/software/glitz)"])
+ use_glitz=yes], [use_glitz="no (requires glitz http://freedesktop.org/Software/glitz)"])
fi
-if test "x$use_glitz" != "xyes"; then
- GLITZ_SURFACE_FEATURE=CAIRO_HAS_NO_GLITZ_SURFACE
- AM_CONDITIONAL(CAIRO_HAS_GLITZ_SURFACE, false)
-else
- GLITZ_SURFACE_FEATURE=CAIRO_HAS_GLITZ_SURFACE
- AM_CONDITIONAL(CAIRO_HAS_GLITZ_SURFACE, true)
+AM_CONDITIONAL(CAIRO_HAS_GLITZ_SURFACE, test "x$use_glitz" = "xyes")
+if test "x$use_glitz" = "xyes"; then
+ GLITZ_SURFACE_FEATURE="#define CAIRO_HAS_GLITZ_SURFACE 1"
fi
+AC_SUBST(GLITZ_SURFACE_FEATURE)
CAIRO_CFLAGS="$CAIRO_CFLAGS $GLITZ_CFLAGS"
CAIRO_LIBS="$CAIRO_LIBS $GLITZ_LIBS"
-AC_SUBST(GLITZ_SURFACE_FEATURE)
AC_SUBST(GLITZ_REQUIRES)
dnl ===========================================================================
-AC_ARG_ENABLE(sanity-checking,
- [ --disable-sanity Disable cairo's sanity checking routines],
- [check_sanity=$enableval], [check_sanity=yes])
-
-if test "x$check_sanity" != "xyes"; then
- SANITY_CHECKING_FEATURE=CAIRO_NO_SANITY_CHECKING
-else
- SANITY_CHECKING_FEATURE=CAIRO_DO_SANITY_CHECKING
-fi
-
-AC_SUBST(SANITY_CHECKING_FEATURE)
-
-dnl ===========================================================================
-
PKG_CHECK_MODULES(PIXMAN, libpixman >= 0.1.4)
CAIRO_CFLAGS="$CAIRO_CFLAGS $PIXMAN_CFLAGS"
CAIRO_LIBS="$CAIRO_LIBS $PIXMAN_LIBS"
@@ -333,12 +299,9 @@ 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)
+AM_CONDITIONAL(CAIRO_HAS_FT_FONT, test "x$use_freetype" = "xyes")
+if test "x$use_freetype" = "xyes"; then
+ FT_FONT_FEATURE="#define CAIRO_HAS_FT_FONT 1"
fi
AC_SUBST(FT_FONT_FEATURE)
@@ -353,18 +316,15 @@ if test x"$use_freetype" != "xyes" ; then
use_pdf=no
fi
-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
+AM_CONDITIONAL(CAIRO_HAS_PDF_SURFACE, test "x$use_pdf" = "xyes")
+if test "x$use_pdf" = "xyes"; then
+ PDF_SURFACE_FEATURE="#define CAIRO_HAS_PDF_SURFACE 1"
PDF_LIBS=-lz
- AM_CONDITIONAL(CAIRO_HAS_PDF_SURFACE, true)
fi
+AC_SUBST(PDF_SURFACE_FEATURE)
CAIRO_LIBS="$CAIRO_LIBS $PDF_LIBS"
-AC_SUBST(PDF_SURFACE_FEATURE)
AC_SUBST(PDF_LIBS)
dnl ===========================================================================
@@ -381,17 +341,15 @@ if test "x$use_atsui" = "xyes"; then
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)
+AM_CONDITIONAL(CAIRO_HAS_ATSUI_FONT, test "x$use_atsui" = "xyes")
+if test "x$use_atsui" = "xyes"; then
+ ATSUI_FONT_FEATURE="#define CAIRO_HAS_ATSUI_FONT 1"
fi
AC_SUBST(ATSUI_FONT_FEATURE)
dnl ===========================================================================
dnl Checks for precise integer types
+AC_CHECK_HEADERS([stdint.h inttypes.h sys/int_types.h])
AC_CHECK_TYPES([uint64_t, uint128_t])
dnl Use lots of warning flags with GCC
@@ -435,14 +393,15 @@ echo " XCB: $use_xcb"
echo " Win32: $use_win32"
echo " PostScript: $use_ps"
echo " PDF: $use_pdf"
-echo " PNG: $use_png"
echo " glitz: $use_glitz"
echo ""
-echo "and the following font backends:"
+echo "the following font backends:"
echo " FreeType: $use_freetype"
echo " Win32: $use_win32"
echo " ATSUI: $use_atsui"
echo ""
+echo "and the following features:"
+echo " PNG functions: $use_png"
if test x"$use_freetype" != "xyes" && \
test x"$use_win32" != "xyes" && \
@@ -453,4 +412,3 @@ if test x"$use_freetype" != "xyes" && \
http://freetype.org/ http://fontconfig.org/
])
fi
-
diff --git a/doc/public/Makefile.am b/doc/public/Makefile.am
index b993bb978..f058d36aa 100644
--- a/doc/public/Makefile.am
+++ b/doc/public/Makefile.am
@@ -19,11 +19,15 @@ HFILE_GLOB=$(top_srcdir)/src/*.h
CFILE_GLOB=$(top_srcdir)/src/*.c $(top_srcdir)/src/*.h
# Headers to ignore
-IGNORE_HFILES= \
- cairo-features.h \
- cairo-ft-private.h \
- cairo-win32-private.h \
- cairoint.h \
+IGNORE_HFILES= \
+ cairo-features.h \
+ cairo-ft-private.h \
+ cairo-gstate-private.h \
+ cairo-path-fixed-private.h \
+ cairo-private.h \
+ cairo-win32-private.h \
+ cairo-xlib-test.h \
+ cairoint.h \
cairo-wideint.h
# CFLAGS and LDFLAGS for compiling scan program. Only needed
@@ -35,7 +39,8 @@ GTKDOC_LIBS =
MKDB_OPTIONS=--sgml-mode --output-format=xml
# Non-autogenerated SGML files to be included in $(DOC_MAIN_SGML_FILE)
-content_files =
+content_files = \
+ language-bindings.xml
# Images to copy into HTML directory
HTML_IMAGES =
diff --git a/doc/public/cairo-docs.xml b/doc/public/cairo-docs.xml
index 2a4cdae8a..729738aac 100644
--- a/doc/public/cairo-docs.xml
+++ b/doc/public/cairo-docs.xml
@@ -12,6 +12,7 @@
<xi:include href="xml/cairo-surface.xml"/>
<xi:include href="xml/cairo-pattern.xml"/>
<xi:include href="xml/cairo-matrix.xml"/>
+ <xi:include href="xml/cairo-font.xml"/>
<xi:include href="xml/cairo-atsui.xml"/>
<xi:include href="xml/cairo-ft.xml"/>
<xi:include href="xml/cairo-glitz.xml"/>
@@ -22,10 +23,9 @@
<xi:include href="xml/cairo-win32.xml"/>
<xi:include href="xml/cairo-xcb.xml"/>
<xi:include href="xml/cairo-xlib.xml"/>
- </part>
+ </part>
+ <index>
+ <title>Index</title>
+ </index>
+ <xi:include href="language-bindings.xml"/>
</book>
-
-
-
-
-
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 3da0fa801..b462436b8 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -7,70 +7,68 @@ cairo_atsui_font_create
<SECTION>
<FILE>cairo-ft</FILE>
<TITLE>FreeType Fonts</TITLE>
-cairo_ft_font_create
-cairo_ft_font_create_for_ft_face
-cairo_ft_font_lock_face
-cairo_ft_font_unlock_face
-cairo_ft_font_get_pattern
+cairo_ft_font_face_create_for_pattern
+cairo_ft_font_face_create_for_ft_face
+cairo_ft_scaled_font_lock_face
+cairo_ft_scaled_font_unlock_face
</SECTION>
<SECTION>
<FILE>cairo-glitz</FILE>
<TITLE>Glitz backend</TITLE>
-cairo_set_target_glitz
cairo_glitz_surface_create
</SECTION>
<SECTION>
<FILE>cairo-pdf</FILE>
<TITLE>PDF Backend</TITLE>
-cairo_set_target_pdf
cairo_pdf_surface_create
+cairo_pdf_surface_create_for_callback
</SECTION>
<SECTION>
<FILE>cairo-png</FILE>
<TITLE>PNG Backend</TITLE>
-cairo_set_target_png
-cairo_png_surface_create
+cairo_image_surface_create_from_png
+cairo_image_surface_create_from_png_stream
+cairo_surface_write_to_png
+cairo_surface_write_to_png_stream
</SECTION>
<SECTION>
<FILE>cairo-ps</FILE>
<TITLE>PS Backend</TITLE>
-cairo_set_target_ps
cairo_ps_surface_create
</SECTION>
<SECTION>
<FILE>cairo-quartz</FILE>
<TITLE>Quartz Backend</TITLE>
-cairo_set_target_quartz_context
cairo_quartz_surface_create
</SECTION>
<SECTION>
<FILE>cairo-win32</FILE>
<TITLE>Microsoft Windows Backend</TITLE>
-cairo_set_target_win32
cairo_win32_surface_create
-cairo_win32_font_create_for_logfontw
-cairo_win32_font_select_font
-cairo_win32_font_done_font
-cairo_win32_font_get_scale_factor
+cairo_win32_font_face_create_for_logfontw
+cairo_win32_scaled_font_select_font
+cairo_win32_scaled_font_done_font
+cairo_win32_scaled_font_get_metrics_factor
</SECTION>
<SECTION>
<FILE>cairo-xcb</FILE>
<TITLE>XCB Backend</TITLE>
-cairo_set_target_xcb
+cairo_xcb_surface_create
</SECTION>
<SECTION>
<FILE>cairo-xlib</FILE>
<TITLE>XLib Backend</TITLE>
-cairo_set_target_drawable
cairo_xlib_surface_create
+cairo_xlib_surface_create_with_visual
+cairo_xlib_surface_set_size
</SECTION>
<SECTION>
@@ -81,11 +79,15 @@ cairo_surface_create_for_image
cairo_surface_create_similar
cairo_surface_reference
cairo_surface_destroy
+cairo_surface_finish
cairo_surface_set_repeat
cairo_surface_set_matrix
cairo_surface_get_matrix
cairo_surface_set_filter
cairo_surface_get_filter
+cairo_surface_set_user_data
+cairo_surface_get_user_data
+cairo_surface_set_device_offset
</SECTION>
<SECTION>
@@ -97,7 +99,8 @@ cairo_pattern_create_linear
cairo_pattern_create_radial
cairo_pattern_reference
cairo_pattern_destroy
-cairo_pattern_add_color_stop
+cairo_pattern_add_color_stop_rgb
+cairo_pattern_add_color_stop_rgba
cairo_pattern_set_matrix
cairo_pattern_get_matrix
cairo_extend_t
@@ -105,18 +108,19 @@ cairo_pattern_set_extend
cairo_pattern_get_extend
cairo_pattern_set_filter
cairo_pattern_get_filter
+<SUBSECTION Private>
+cairo_pattern_add_color_stop
</SECTION>
<SECTION>
<FILE>cairo-matrix</FILE>
<TITLE>cairo_matrix_t</TITLE>
cairo_matrix_t
-cairo_matrix_create
-cairo_matrix_destroy
-cairo_matrix_copy
-cairo_matrix_set_identity
-cairo_matrix_set_affine
-cairo_matrix_get_affine
+cairo_matrix_init
+cairo_matrix_init_identity
+cairo_matrix_init_translate
+cairo_matrix_init_scale
+cairo_matrix_init_rotate
cairo_matrix_translate
cairo_matrix_scale
cairo_matrix_rotate
@@ -124,6 +128,31 @@ cairo_matrix_invert
cairo_matrix_multiply
cairo_matrix_transform_distance
cairo_matrix_transform_point
+<SUBSECTION Private>
+cairo_matrix_create
+cairo_matrix_destroy
+cairo_matrix_copy
+cairo_matrix_set_identity
+cairo_matrix_set_affine
+cairo_matrix_get_affine
+</SECTION>
+
+<SECTION>
+<FILE>cairo-font</FILE>
+<TITLE>Fonts</TITLE>
+cairo_font_face_t
+cairo_scaled_font_t
+cairo_font_face_reference
+cairo_font_face_destroy
+cairo_font_face_get_user_data
+cairo_font_face_set_user_data
+cairo_scaled_font_create
+cairo_scaled_font_reference
+cairo_scaled_font_destroy
+cairo_font_extents_t
+cairo_scaled_font_extents
+cairo_text_extents_t
+cairo_scaled_font_glyph_extents
</SECTION>
<SECTION>
@@ -136,13 +165,13 @@ cairo_destroy
cairo_save
cairo_restore
cairo_copy
-cairo_set_target_surface
cairo_format_t
-cairo_set_target_image
cairo_operator_t
cairo_set_operator
-cairo_set_rgb_color
-cairo_set_pattern
+cairo_set_source_rgb
+cairo_set_source_rgba
+cairo_set_source
+cairo_set_source_surface
cairo_set_alpha
cairo_set_tolerance
cairo_fill_rule_t
@@ -157,14 +186,14 @@ cairo_set_miter_limit
cairo_translate
cairo_scale
cairo_rotate
-cairo_concat_matrix
+cairo_transform
cairo_set_matrix
cairo_default_matrix
cairo_identity_matrix
-cairo_transform_point
-cairo_transform_distance
-cairo_inverse_transform_point
-cairo_inverse_transform_distance
+cairo_user_to_device
+cairo_user_to_device_distance
+cairo_device_to_user
+cairo_device_to_user_distance
cairo_new_path
cairo_move_to
cairo_line_to
@@ -176,8 +205,14 @@ cairo_rel_line_to
cairo_rel_curve_to
cairo_rectangle
cairo_close_path
+cairo_paint
+cairo_paint_with_alpha
+cairo_mask
+cairo_mask_surface
cairo_stroke
+cairo_stroke_preserve
cairo_fill
+cairo_fill_preserve
cairo_copy_page
cairo_show_page
cairo_in_stroke
@@ -185,35 +220,61 @@ cairo_in_fill
cairo_bool_t
cairo_stroke_extents
cairo_fill_extents
-cairo_init_clip
cairo_clip
-cairo_font_t
+cairo_clip_preserve
+cairo_reset_clip
cairo_glyph_t
-cairo_text_extents_t
-cairo_font_extents_t
cairo_font_slant_t
cairo_font_weight_t
-cairo_select_font
-cairo_scale_font
-cairo_transform_font
+cairo_select_font_face
+cairo_set_font_size
+cairo_set_font_matrix
+cairo_get_font_matrix
cairo_show_text
cairo_show_glyphs
-cairo_current_font
-cairo_current_font_extents
-cairo_set_font
+cairo_get_font_face
+cairo_font_extents
+cairo_set_font_face
cairo_text_extents
cairo_glyph_extents
cairo_text_path
cairo_glyph_path
-cairo_font_reference
-cairo_font_destroy
-cairo_font_extents
-cairo_font_glyph_extents
cairo_show_surface
+cairo_get_operator
+cairo_get_source
+cairo_get_tolerance
+cairo_get_current_point
+cairo_get_fill_rule
+cairo_get_line_width
+cairo_get_line_cap
+cairo_get_line_join
+cairo_get_miter_limit
+cairo_get_matrix
+cairo_get_target
+cairo_get_path
+cairo_get_path_flat
+cairo_copy_path
+cairo_copy_path_flat
+cairo_append_path
+cairo_path_t
+cairo_path_destroy
+cairo_status_t
+cairo_status
+cairo_status_string
+cairo_filter_t
+cairo_image_surface_create
+cairo_image_surface_create_for_data
+cairo_image_surface_get_width
+cairo_image_surface_get_height
+cairo_destroy_func_t
+cairo_user_data_key_t
+cairo_read_func_t
+cairo_write_func_t
+<SUBSECTION Private>
+CAIRO_BEGIN_DECLS
+CAIRO_END_DECLS
+cairo_concat_matrix
cairo_current_operator
-cairo_current_rgb_color
-cairo_current_pattern
-cairo_current_alpha
cairo_current_tolerance
cairo_current_point
cairo_current_fill_rule
@@ -225,27 +286,18 @@ cairo_current_matrix
cairo_current_target_surface
cairo_current_path
cairo_current_path_flat
-cairo_status_t
-cairo_status
-cairo_status_string
-cairo_filter_t
-cairo_image_surface_create
-cairo_image_surface_create_for_data
-<SUBSECTION Private>
-CAIRO_BEGIN_DECLS
-CAIRO_END_DECLS
-cairo_get_operator
-cairo_get_rgb_color
-cairo_get_alpha
-cairo_get_tolerance
-cairo_get_current_point
-cairo_get_fill_rule
-cairo_get_line_width
-cairo_get_line_cap
-cairo_get_line_join
-cairo_get_miter_limit
-cairo_get_matrix
-cairo_get_target_surface
+cairo_current_font_extents
+cairo_init_clip
+cairo_inverse_transform_point
+cairo_inverse_transform_distance
+cairo_scale_font
+cairo_select_font
+cairo_set_pattern
+cairo_set_rgb_color
+cairo_transform_font
+cairo_get_font_extents
cairo_get_status
cairo_get_status_string
+cairo_transform_point
+cairo_transform_distance
</SECTION>
diff --git a/doc/public/language-bindings.xml b/doc/public/language-bindings.xml
new file mode 100644
index 000000000..1b999d82f
--- /dev/null
+++ b/doc/public/language-bindings.xml
@@ -0,0 +1,726 @@
+<appendix id="language-bindings">
+ <title>Creating a language binding for cairo</title>
+ <para>
+ While cairo is implemented and C, and has a C API, it is expected
+ that many users of cairo will be using it from languages other
+ than C. The glue that connects the core cairo library to another
+ language is known as a <firstterm>language
+ binding</firstterm>. This appendix attempts to collect together
+ issues that come up when creating a language bindings for cairo
+ and present standardized solutions to promote consistency among
+ the different language bindings.
+ </para>
+ <sect1 id="bindings-general">
+ <title>General considerations</title>
+ <para>
+ The naming of the central <link
+ linkend="cairo-t"><type>cairo_t</type></link> type is a
+ special exception. The object is “a cairo context” not “a
+ cairo”, and names such as <type>cairo_t</type> rather than
+ <type>cairo_context_t</type> and
+ <function>cairo_set_source()</function> rather than
+ <function>cairo_context_set_source()</function> are simply
+ abbreviations to make the C API more palatable. In languages
+ which have object-oriented syntax, this abbreviation is much
+ less useful. In fact, if ‘Cairo’ is used as a namespace, then
+ in many languages, you'd end up with a ridiculous type name
+ like ‘Cairo.Cairo’. For this reason, and for inter-language
+ consistency all object-oriented languages should name this
+ type as if it were <type>cairo_context_t</type>.
+ </para>
+ <para>
+ The punctuation and casing of the type names and
+ method names of cairo should be changed to match the general
+ convention of the language. In Java, where type names are written
+ in StudlyCaps and method names in javaCaps, cairo_font_extents_t
+ will become FontExtents and
+ <literal>cairo_set_source(cr,source)</literal>,
+ <literal>cr.setSource(source)</literal>.
+ As compared to changing the punctuation, and casing, much
+ more reluctance should be used in changing the method names
+ themselves. Even if get is usually omitted from getters in
+ your language, you shouldn't bind cairo_get_source() as
+ cr.source().
+ </para>
+ </sect1>
+ <sect1 id="bindings-memory">
+ <title>Memory Management</title>
+ <para>
+ The objects in cairo can roughly be divided into two types:
+ refcounted opaque types like
+ <link
+ linkend="cairo-surface-t"><type>cairo_surface_t</type></link>
+ and plain structures like
+ <link
+ linkend="cairo-glyph-t"><type>cairo_glyph_t</type></link>.
+ <link
+ linkend="cairo-path-t"><type>cairo_path_t</type></link>
+ and
+ <link
+ linkend="cairo-path-data-t"><type>cairo_path_data_t</type></link>
+ are special cases and are treated separately in this appendix.
+ </para>
+ <para>
+ Refcounted opaque types all have a
+ <function>..._reference()</function>
+ function to increase the refcount by one and a
+ <function>..._destroy()</function> to decrease the refcount
+ by one. These should not be exposed to the user of the language
+ binding, but rather used to implement memory management within
+ the language binding. The simplest way to do memory management
+ for a language binding is to treat the language binding object
+ as a simple handle to the cairo object. The language binding
+ object references the cairo object, and unreferences it when
+ finalized. This is the recommended method, though there are
+ a couple of caveats to be noted:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Equality won't work as expected. You can have two language
+ objects for the same cairo and they won't necessarily
+ compare equal. If the language allows customizing the
+ equality operation, then this is fixable by comparing
+ the underlying pointers. It also can be fixed by creating
+ at most one language object per cairo object, and
+ uniquifying via a <firstterm>pin table</firstterm> (a hash
+ table that goes from cairo object to language object).
+ For <type>cairo_surface_t</type> you can use also
+ <link
+ linkend="cairo-surface-set-user-data"><function>cairo_surface_set_user_data()</function></link>
+ instead of a separate pin table.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Derivation from the language object doesn't work because
+ you can lose the language object while keeping the Cairo
+ object. Code like:
+ </para>
+<programlisting>
+public class MySurface (ImageSurface) {
+ public MySurface (width, height) {
+ super (Format.ARGB32, width, height);
+ }
+ public int get42 () {
+ return 42;
+ }
+}
+
+ cr = Cairo(MySurface(width, height));
+ surface = cr.getTarget();
+</programlisting>
+ <para>
+ Can result in <varname>surface</varname> containing an
+ <classname>ImageSurface</classname> not a <classname>MySurface</classname>.
+ This is not easily fixable without creating memory leaks,
+ and it's probably best to simply forbid deriving from the
+ language objects.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ When a plain structure is used as a return value from cairo,
+ this is done by passing it as a “out parameter”.
+ </para>
+<programlisting>
+cairo_font_extents_t extents;
+
+cairo_font_extents (cr, &amp;extents);</programlisting>
+ <para>
+ In a language binding, this should typically be treated
+ as a return value:
+ </para>
+<programlisting>
+FontExtents extents = cr.fontExtents ();</programlisting>
+ <para>
+ A language binding has a choice in how it implements the
+ language objects for plain structures. It can use a pure
+ language object with fields corresponding to those of the C
+ structure, and convert from and to the C structure when calling
+ cairo functions or converting cairo return values. Or it
+ can keep a pointer to the C structure internally and wrap
+ it inside a language object much like occurs for refcounted
+ objects. The choice should be invisible to the user: they should
+ be able to imagine that it is implemented as a pure language
+ object.
+ </para>
+ </sect1>
+ <sect1 id="bindings-return-values">
+ <title>Multiple return values</title>
+ <para>
+ There are a number of functions in the cairo API that have
+ multiple <firstterm>out parameters</firstterm> or
+ <firstterm>in-out parameters</firstterm>. In some languages
+ these can be translated into multiple return values. In Python,
+ what is:
+ </para>
+ <programlisting>
+cairo_user_to_device (cr, &amp;x, &amp;y);</programlisting>
+ <para>
+ can by mapped to:
+ </para>
+ <programlisting>
+(x, y) = cr.user_to_device (cr, x, y);</programlisting>
+ <para>
+ but many languages don't have provisions for multiple return
+ values, so it is necessary to introduce auxiliary types.
+ Most of the functions that require the auxiliary types
+ require a type that would, in C, look like
+ </para>
+ <programlisting>
+typedef struct _cairo_point cairo_point_t;
+struct _cairo_point {
+ double x;
+ double y;
+}</programlisting>
+ <para>
+ The same type should be used both for functions that use a pair
+ of coordinates as an absolute position, and functions that use
+ a pair of coordinates as a displacement. While an argument could
+ be made that having a separate “distance” type is more correct,
+ it is more likely just to confuse users.
+ </para>
+ <programlisting>
+void
+cairo_user_to_device (cairo_t *cr, double *x, double *y);
+
+void
+cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy);
+
+void
+cairo_device_to_user (cairo_t *cr, double *x, double *y);
+
+void
+cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy);
+
+void
+cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy);
+
+void
+cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y);
+
+void
+cairo_get_current_point (cairo_t *cr, double *x, double *y);
+ </programlisting>
+ <para>
+ There are also a couple of functions that return four values
+ representing a rectangle. These should be mapped to a
+ “rectangle” type that looks like:
+ </para>
+ <programlisting>
+typedef struct _cairo_rectangle cairo_rectangle_t;
+struct _cairo_rectangle {
+ double x;
+ double y;
+ double width;
+ double height;
+}</programlisting>
+ <para>
+ The C function returns the rectangle as a set of two points to
+ facilitate rounding to integral extents, but this isn't worth
+ adding a “box” type to go along with the more obvious
+ “rectangle” representation.
+ </para>
+ <remark>
+ Q: Would it make sense here to define a standard
+ <function>cairo_rectangle_round()</function> method
+ that language bindings should map?
+ </remark>
+ <programlisting>
+void
+cairo_stroke_extents (cairo_t *cr,
+ double *x1, double *y1,
+ double *x2, double *y2);
+
+void
+cairo_fill_extents (cairo_t *cr,
+ double *x1, double *y1,
+ double *x2, double *y2);
+ </programlisting>
+ </sect1>
+ <sect1 id="bindings-overloading">
+ <title>Overloading and optional arguments</title>
+ <para>
+ Function overloading (having a several variants of a function
+ with the same name and different arguments) is a language
+ feature available in many languages but not in C.
+ </para>
+ <para>
+ In general, language binding authors should use restraint in
+ combining functions in the cairo API via function
+ overloading. What may seem like an obvious overload now may
+ turn out to be strange with future additions to cairo.
+ It might seem logical to make
+ <link
+ linkend="cairo-set-source-rgb"><function>cairo_set_source_rgb()</function></link>
+ an overload of <function>cairo_set_source()</function>, but future plans to add
+ <function>cairo_set_source_rgb_premultiplied()</function>,
+ which will also take three doubles make this a bad idea. For
+ this reason, only the following pairs of functions should
+ be combined via overloading
+ </para>
+ <programlisting>
+void
+cairo_set_source (cairo_t *cr, cairo_pattern_t *source);
+
+void
+cairo_set_source_surface (cairo_t *cr,
+ cairo_surface_t *source,
+ double surface_x,
+ double surface_y);
+
+void
+cairo_mask (cairo_t *cr,
+ cairo_pattern_t *pattern);
+
+void
+cairo_mask_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double surface_x,
+ double surface_y);
+
+cairo_surface_t *
+cairo_image_surface_create (cairo_format_t format,
+ int width,
+ int height);
+cairo_surface_t *
+cairo_image_surface_create_for_data (unsigned char *data,
+ cairo_format_t format,
+ int width,
+ int height,
+ int stride);
+
+cairo_status_t
+cairo_surface_write_to_png (cairo_surface_t *surface,
+ const char *filename);
+
+cairo_status_t
+cairo_surface_write_to_png_stream (cairo_surface_t *surface,
+ cairo_write_func_t write_func,
+ void *closure);
+
+cairo_surface_t *
+cairo_image_surface_create_from_png (const char *filename);
+
+cairo_surface_t *
+cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
+ void *closure);
+ </programlisting>
+ <para>
+ Note that there are cases where all constructors for a type
+ aren't overloaded together. For example
+ <link
+ linkend="cairo-image-surface-create-from-png"><function>cairo_image_surface_create_from_png()</function></link>
+ should <emphasis>not</emphasis> be overloaded together with
+ <link
+ linkend="cairo-image-surface-create"><function>cairo_image_surface_create()</function></link>.
+ In such cases, the remaining constructors will typically need to
+ be bound as static methods. In Java, for example, we might have:
+ </para>
+<programlisting>
+Surface surface1 = ImageSurface(Format.RGB24, 100, 100);
+Surface surface2 = ImageSurface.createFromPNG("camera.png");</programlisting>
+ <para>
+ Some other overloads that add combinations not found in C may be
+ convenient for users for language bindings that provide
+ <type>cairo_point_t</type> and <type>cairo_rectangle_t</type>
+ types, for example:
+ </para>
+ <programlisting>
+void
+cairo_move_to (cairo_t *cr,
+ cairo_point_t *point);
+void
+cairo_rectangle (cairo_t *cr,
+ cairo_rectangle_t *rectangle);
+ </programlisting>
+ </sect1>
+ <sect1 id="bindings-streams">
+ <title>Streams and File I/O</title>
+ <para>
+ Various places in the cairo API deal with reading and writing
+ data, whether from and to files, or to other sources and
+ destinations. In these cases, what is typically provided in the
+ C API is a simple version that just takes a filename, and a
+ complex version that takes a callback function.
+ An example is the PNG handling functions:
+ </para>
+<programlisting>
+cairo_surface_t *
+cairo_image_surface_create_from_png (const char *filename);
+
+cairo_surface_t *
+cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
+ void *closure);
+
+cairo_status_t
+cairo_surface_write_to_png (cairo_surface_t *surface,
+ const char *filename);
+
+cairo_status_t
+cairo_surface_write_to_png_stream (cairo_surface_t *surface,
+ cairo_write_func_t write_func,
+ void *closure);</programlisting>
+ <para>
+ The expectation is that the filename version will be mapped
+ literally in the language binding, but the callback version
+ will be mapped to a version that takes a language stream
+ object. For example, in Java, the four functions above
+ might be mapped to:
+ </para>
+<programlisting>
+static public ImageSurface createFromPNG (String filename) throws IOException;
+static public ImageSurface createFromPNG (InputStream stream) throws IOException;
+public void writeToPNG (String filename) throws IOException;
+public void writeToPNG (OutputStream stream) throws IOException;
+</programlisting>
+ <para>
+ In many cases, it will be better to
+ implement the filename version internally
+ using the stream version, rather than building it on top of the
+ filename version in C. The reason for this is that will
+ naturally give a more standard handling of file errors for
+ the language, as seen in the above Java example, where
+ <methodname>createFromPNG()</methodname> is marked as raising
+ an exception. Propagating exceptions from inside the callback
+ function to the caller will pose a challenge to the language
+ binding implementor, since an exception must not propagate
+ through the Cairo code. A technique that will be useful in
+ some cases is to catch the exception in the callback,
+ store the exception object inside a structure pointed to by
+ <parameter>closure</parameter>, and then rethrow it once
+ the function returns.
+ </para>
+ <remark>
+ I'm not sure how to handle this for
+ <link
+ linkend="cairo-pdf-surface-create-for-callback"><function>cairo_pdf_surface_create_for_callback()</function></link>.
+ Other than keep a “exception to rethrow” thread-specific
+ variable
+ that is checked after <emphasis>every</emphasis> call to a Cairo
+ function.
+ </remark>
+ </sect1>
+ <sect1 id="bindings-errors">
+ <title>Error handling</title>
+ <para>
+ The error handling approach in C for Cairo has multiple
+ elements:
+ </para>
+ <itemizedlist>
+ <listitem><para>
+ When a method on an object fails, the object is put into
+ an error state. Subsequent operations on the object do
+ nothing. The status of the object can be queried with
+ a function like <link
+ linkend="cairo-status"><function>status()</function></link>.
+ </para></listitem>
+ <listitem><para>
+ Constructors, rather than
+ returning<constant>NULL</constant> on out-of-memory failure,
+ return a special singleton object on which all
+ operations do nothing. Retrieving the status of the
+ singleton object returns <constant>CAIRO_STATUS_NO_MEMORY</constant>
+ </para>
+ <remark>
+ Is this going to apply to
+ <type>cairo_surface_t</type> as well?
+ </remark>
+ <remark>
+ What about cairo_copy_path_data()? It's probably going to
+ have to return <constant>NULL</constant>.
+ </remark>
+ </listitem>
+ <listitem><para>
+ Errors propagate from object to object. Setting a pattern
+ in an out-of-memory state as the source of a
+ <type>cairo_t</type> puts the type into an error state.
+ </para></listitem>
+ </itemizedlist>
+ <remark>Much of the above is not yet implemented at the time of
+ this writing</remark>
+ <para>
+ A language binding could copy the C approach, and for a
+ language without exceptions, this is likely the right thing
+ to do. However, for a language with exceptions, exposing
+ a completely different style of error handling for cairo
+ would be strange. So, instead, status should be checked
+ after every call to cairo, and exceptions thrown as necessary.
+ </para>
+ <para>
+ One problem that can arise with this, in languages
+ where handling exceptions is mandatory (like Java), is that almost
+ every cairo function can result in a status being set,
+ usually because of an out-of-memory condition. This could make
+ cairo hard to use. To resolve this problem, let's classify then
+ cairo status codes:
+ </para>
+<programlisting>
+/* Memory */
+CAIRO_STATUS_NO_MEMORY,
+
+/* Programmer error */
+CAIRO_STATUS_INVALID_RESTORE
+CAIRO_STATUS_INVALID_POP_GROUP
+CAIRO_STATUS_NO_CURRENT_POINT
+CAIRO_STATUS_INVALID_MATRIX
+CAIRO_STATUS_NO_TARGET_SURFACE
+CAIRO_STATUS_INVALID_STRING
+CAIRO_STATUS_SURFACE_FINISHED
+CAIRO_STATUS_BAD_NESTING
+
+/* Language binding implementation */
+CAIRO_STATUS_NULL_POINTER
+CAIRO_STATUS_INVALID_PATH_DATA
+CAIRO_STATUS_SURFACE_TYPE_MISMATCH
+
+/* Other */
+CAIRO_STATUS_READ_ERROR
+CAIRO_STATUS_WRITE_ERROR
+</programlisting>
+ <para>
+ If we look at these, the
+ <constant>CAIRO_STATUS_NO_MEMORY</constant>
+ should map to the native out-of-memory exception, which could
+ happen at any point in any case. Most of the others indicate
+ programmer error, and handling them in user code would be
+ silly. These should be mapped into whatever the language uses
+ for assertion failures, rather than errors that are normally
+ handled. (In Java, a subclass of Error rather than Exception,
+ perhaps.) And <constant>CAIRO_STATUS_READ_ERROR</constant>,
+ and <constant>CAIRO_STATUS_WRITE_ERROR</constant> can occur
+ only in very specific places. (In fact, as described
+ in <xref linkend="bindings-streams"/>, these errors may be
+ mapped into the language's native I/O error types.)
+ So, there really aren't exceptions that the programmer must
+ handle at most points in the Cairo API.
+ </para>
+ </sect1>
+ <sect1 id="bindings-patterns">
+ <title>Patterns</title>
+ <para>
+ The cairo C API allows for creating a number of different types
+ of patterns. All of these different types of patterns map to
+ <link
+ linkend="cairo-pattern-t"><type>cairo_pattern_t</type></link>
+ in C, but in an object oriented language, there should instead
+ be a hierarchy of types. (The functions that should map to
+ constructors for the various types are listed after the type,
+ methods on that type are listed below)
+ </para>
+ <programlisting>
+cairo_pattern_t
+ <link linkend="cairo-pattern-set-matrix"><function>cairo_pattern_set_matrix()</function></link>
+ <link linkend="cairo-pattern-get-matrix"><function>cairo_pattern_get_matrix()</function></link>
+ cairo_solid_pattern_t
+ cairo_surface_pattern_t (<link linkend="cairo-pattern-create-for-surface"><function>cairo_pattern_create_for_surface()</function></link>)
+ <link linkend="cairo-pattern-set-extend"><function>cairo_pattern_set_extend()</function></link>
+ <link linkend="cairo-pattern-get-extend"><function>cairo_pattern_get_extend()</function></link>
+ <link linkend="cairo-pattern-set-filter"><function>cairo_pattern_set_filter()</function></link>
+ <link linkend="cairo-pattern-get-filter"><function>cairo_pattern_get_filter()</function></link>
+ cairo_gradient_t
+ <link linkend="cairo-pattern-add-color-stop-rgb"><function>cairo_pattern_add_color_stop_rgb()</function></link>
+ <link linkend="cairo-pattern-add-color-stop-rgba"><function>cairo_pattern_add_color_stop_rgba()</function></link>
+ cairo_linear_gradient_t (<link linkend="cairo-pattern-create-linear"><function>cairo_pattern_create_linear()</function></link>)
+ cairo_radial_gradient_t (<link linkend="cairo-pattern-create-radial"><function>cairo_pattern_create_radial()</function></link>)
+ </programlisting>
+ <para>
+ </para>
+ </sect1>
+ <sect1 id="bindings-surfaces">
+ <title>Surfaces</title>
+ <para>
+ Like patterns, surfaces, which use only the
+ <link
+ linkend="cairo-surface-t"><type>cairo_surface_t</type></link>
+ type in the C API should be broken up into a heirarchy of types
+ in a language binding.
+ </para>
+ <programlisting>
+cairo_surface_t
+ cairo_image_surface_t
+ cairo_atsui_surface_t
+ cairo_win32_surface_t
+ cairo_xlib_surface_t
+ </programlisting>
+ <para>
+ Unlike patterns, the constructors and methods on these types are
+ clearly named, and can be trivially associated with the
+ appropriate subtype. Many language bindings will want to avoid
+ binding the platform-specific subtypes at all, since the
+ methods on these types are not useful without passing in native
+ C types. Unless there is a language binding for Xlib available,
+ there is no way to represent a XLib <type>Display</type> * in
+ that language.
+ </para>
+ <para>
+ This doesn't mean that platform-specific surface types can't
+ be used in a language binding that doesn't bind the constructor.
+ A very common situation is to use a cairo language binding in
+ combination with a binding for a higher level system like
+ the <ulink url="http://www.gtk.org/">GTK+</ulink> widget
+ toolkit. In such a situation, the higher level toolkit provides
+ ways to get references to platform specific surfaces.
+ </para>
+ <para>
+ The <link
+ linkend="cairo-surface-set-user-data"><function>cairo_surface_set_user_data()</function></link>,
+ and <link
+ linkend="cairo-surface-get-user-data"><function>cairo_surface_get_user_data()</function></link>
+ methods are provided for use in language bindings, and should
+ not be directly exposed to applications. One example of the use
+ of these functions in a language binding is creating a binding for:
+ </para>
+<programlisting>
+cairo_surface_t *
+<link linkend="cairo-image-surface-create-for-data"><function>cairo_image_surface_create_for_data</function></link> (unsigned char *data,
+ cairo_format_t format,
+ int width,
+ int height,
+ int stride);
+</programlisting>
+ <para>
+ The memory block passed in for <parameter>data</parameter> must be
+ kept around until the surface is destroyed, so the language
+ binding must have some way of determining when that happens. The
+ way to do this is to use the <parameter>destroy</parameter>
+ argument to <function>cairo_surface_set_user_data()</function>.
+ </para>
+ <remark>
+ Some languages may not have a suitable “pointer to a block of
+ data” type to pass in for <parameter>data</parameter>. And even
+ where a language does have such a type, the user will be
+ frequently able to cause the backing store to be reallocated
+ to a different location or truncated. Should we recommend a
+ standard type name and binding for a buffer object here?
+ </remark>
+ </sect1>
+ <sect1 id="bindings-fonts">
+ <title>Fonts</title>
+ <para>
+ Fonts are once more an area where there is a hierarchy of types:
+ </para>
+<programlisting>
+cairo_font_face_t
+ cairo_ft_font_face_t
+ cairo_win32_font_face_t
+cairo_scaled_font_t
+ cairo_ft_scaled_font_t
+ cairo_win32_scaled_font_t
+</programlisting>
+ <para>
+ The methods on the subtypes are, however, not useful without
+ bindings for fontconfig and FreeType or for the Win32 GDI,
+ so most language bindings will choose not to bind these
+ types.
+ </para>
+ <para>
+ The <link
+ linkend="cairo-font-face-set-user-data"><function>cairo_font_face_set_user_data()</function></link>,
+ and <link
+ linkend="cairo-font-face-get-user-data"><function>cairo_font_face_get_user_data()</function></link>
+ methods are provided for use in language bindings, and should
+ not be directly exposed to applications.
+ </para>
+ </sect1>
+ <sect1 id="bindings-path">
+ <title>cairo_path_t</title>
+ <para>
+ The <link linkend="cairo-path-t"><type>cairo_path_t</type></link> type is one
+ area in which most language bindings will differ significantly
+ from the C API. The C API for <type>cairo_path_t</type> is
+ designed for efficiency and to avoid auxiliary objects that
+ would be have to be manually memory managed by the
+ application. However,
+ a language binding should not present <type>cairo_path_t</type> as an
+ array, but rather as an opaque that can be iterated
+ over. Different languages have quite different conventions for
+ how iterators work, so it is impossible to give an exact
+ specification for how this API should work, but the type names
+ and methods should be similar to the language's mapping of the following:
+ </para>
+ <programlisting>
+typedef struct cairo_path_iterator cairo_path_iterator_t;
+typedef struct cairo_path_element cairo_path_element_t;
+
+cairo_path_iterator_t *
+cairo_path_get_iterator (cairo_path_t *path);
+
+cairo_bool_t
+cairo_path_iterator_has_next (cairo_path_iterator_t *iterator);
+
+cairo_path_element_t *
+cairo_path_iterator_next (cairo_path_iterator_t *iterator);
+
+cairo_path_element_type_t
+cairo_path_element_get_type (cairo_path_element_t *element);
+
+void
+cairo_path_element_get_point (cairo_path_element_t *element,
+ int index,
+ double *x,
+ double *y);
+ </programlisting>
+ <para>
+ The above is written using the Java conventions for
+ iterators. To illustrate how the API for PathIterator might
+ depend on the native iteration conventions of the API, examine
+ three versions of the loop, first written in a hypothetical Java
+ binding:
+ </para>
+ <programlisting>
+PathIterator iter = cr.copyPath().iterator();
+while (cr.hasNext()) {
+ PathElement element = iter.next();
+ if (element.getType() == PathElementType.MOVE_TO) {
+ Point p = element.getPoint(0);
+ doMoveTo (p.x, p.y);
+ }
+}</programlisting>
+ <para>
+ And then in a hypothetical C++ binding:
+ </para>
+ <programlisting>
+Path path = cr.copyPath();
+for (PathIterator iter = path.begin(); iter != path.end(); iter++) {
+ PathElement element = *iter;
+ if (element.getType() == PathElementType.MOVE_TO) {
+ Point p = element.getPoint(0);
+ doMoveTo (p.x, p.y);
+ }
+}</programlisting>
+ <para>
+ And then finally in a Python binding:
+ </para>
+<programlisting>
+for element in cr.copy_path():
+ if element.getType == cairo.PATH_ELEMENT_MOVE_TO:
+ (x, y) = element.getPoint(0)
+ doMoveTo (x, y);</programlisting>
+ <para>
+ While many of the API elements stay the same in the three
+ examples, the exact iteration mechanism is quite different, to
+ match how users of the language would expect to iterate over
+ a container.
+ </para>
+ <para>
+ You should not present an API for mutating or for creating new
+ <type>cairo_path_t</type> objects. In the future, these
+ guidelines may be extended to present an API for creating a
+ <type>cairo_path_t</type> from scratch for use with
+ <link
+ linkend="cairo-append-path"><function>cairo_append_path()</function></link>
+ but the current expectation is that <function>cairo_append_path()</function> will
+ mostly be used with paths from
+ <link
+ linkend="cairo-append-path"><function>cairo_copy_path()</function></link>.
+ </para>
+ </sect1>
+</appendix>
+<!--
+Local variables:
+mode: sgml
+sgml-parent-document: ("cairo-docs.xml" "book" "book" "appendix")
+End:
+-->
diff --git a/doc/public/tmpl/cairo-atsui.sgml b/doc/public/tmpl/cairo-atsui.sgml
index 0d957ecdf..a47ee8c68 100644
--- a/doc/public/tmpl/cairo-atsui.sgml
+++ b/doc/public/tmpl/cairo-atsui.sgml
@@ -14,6 +14,9 @@ ATSUI Fonts
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### FUNCTION cairo_atsui_font_create ##### -->
<para>
diff --git a/doc/public/tmpl/cairo-font.sgml b/doc/public/tmpl/cairo-font.sgml
new file mode 100644
index 000000000..66502930e
--- /dev/null
+++ b/doc/public/tmpl/cairo-font.sgml
@@ -0,0 +1,148 @@
+<!-- ##### SECTION Title ##### -->
+Fonts
+
+<!-- ##### SECTION Short_Description ##### -->
+Font Handling
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### TYPEDEF cairo_font_face_t ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### TYPEDEF cairo_scaled_font_t ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION cairo_font_face_reference ##### -->
+<para>
+
+</para>
+
+@font_face:
+
+
+<!-- ##### FUNCTION cairo_font_face_destroy ##### -->
+<para>
+
+</para>
+
+@font_face:
+
+
+<!-- ##### FUNCTION cairo_font_face_get_user_data ##### -->
+<para>
+
+</para>
+
+@font_face:
+@key:
+@Returns:
+
+
+<!-- ##### FUNCTION cairo_font_face_set_user_data ##### -->
+<para>
+
+</para>
+
+@font_face:
+@key:
+@user_data:
+@destroy:
+@Returns:
+
+
+<!-- ##### FUNCTION cairo_scaled_font_create ##### -->
+<para>
+
+</para>
+
+@font_face:
+@font_matrix:
+@ctm:
+@Returns:
+
+
+<!-- ##### FUNCTION cairo_scaled_font_reference ##### -->
+<para>
+
+</para>
+
+@scaled_font:
+<!-- # Unused Parameters # -->
+@font:
+
+
+<!-- ##### FUNCTION cairo_scaled_font_destroy ##### -->
+<para>
+
+</para>
+
+@scaled_font:
+<!-- # Unused Parameters # -->
+@font:
+
+
+<!-- ##### STRUCT cairo_font_extents_t ##### -->
+<para>
+
+</para>
+
+@ascent:
+@descent:
+@height:
+@max_x_advance:
+@max_y_advance:
+
+<!-- ##### FUNCTION cairo_scaled_font_extents ##### -->
+<para>
+
+</para>
+
+@scaled_font:
+@extents:
+@Returns:
+<!-- # Unused Parameters # -->
+@font:
+
+
+<!-- ##### STRUCT cairo_text_extents_t ##### -->
+<para>
+
+</para>
+
+@x_bearing:
+@y_bearing:
+@width:
+@height:
+@x_advance:
+@y_advance:
+
+<!-- ##### FUNCTION cairo_scaled_font_glyph_extents ##### -->
+<para>
+
+</para>
+
+@scaled_font:
+@glyphs:
+@num_glyphs:
+@extents:
+<!-- # Unused Parameters # -->
+@font:
+
+
diff --git a/doc/public/tmpl/cairo-ft.sgml b/doc/public/tmpl/cairo-ft.sgml
index bcf52ac34..d9f7cbfc1 100644
--- a/doc/public/tmpl/cairo-ft.sgml
+++ b/doc/public/tmpl/cairo-ft.sgml
@@ -14,50 +14,42 @@ FreeType Fonts
</para>
-<!-- ##### FUNCTION cairo_ft_font_create ##### -->
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### FUNCTION cairo_ft_font_face_create_for_pattern ##### -->
<para>
</para>
@pattern:
-@scale:
@Returns:
-<!-- ##### FUNCTION cairo_ft_font_create_for_ft_face ##### -->
+<!-- ##### FUNCTION cairo_ft_font_face_create_for_ft_face ##### -->
<para>
</para>
@face:
@load_flags:
-@scale:
@Returns:
-<!-- ##### FUNCTION cairo_ft_font_lock_face ##### -->
+<!-- ##### FUNCTION cairo_ft_scaled_font_lock_face ##### -->
<para>
</para>
-@ft_font:
+@scaled_font:
@Returns:
-<!-- ##### FUNCTION cairo_ft_font_unlock_face ##### -->
+<!-- ##### FUNCTION cairo_ft_scaled_font_unlock_face ##### -->
<para>
</para>
-@ft_font:
-
-
-<!-- ##### FUNCTION cairo_ft_font_get_pattern ##### -->
-<para>
-
-</para>
-
-@ft_font:
-@Returns:
+@scaled_font:
diff --git a/doc/public/tmpl/cairo-glitz.sgml b/doc/public/tmpl/cairo-glitz.sgml
index 101eb9e3e..9594d87a5 100644
--- a/doc/public/tmpl/cairo-glitz.sgml
+++ b/doc/public/tmpl/cairo-glitz.sgml
@@ -14,13 +14,7 @@ Glitz backend
</para>
-<!-- ##### FUNCTION cairo_set_target_glitz ##### -->
-<para>
-
-</para>
-
-@cr:
-@surface:
+<!-- ##### SECTION Stability_Level ##### -->
<!-- ##### FUNCTION cairo_glitz_surface_create ##### -->
diff --git a/doc/public/tmpl/cairo-matrix.sgml b/doc/public/tmpl/cairo-matrix.sgml
index dc24c5754..c58abe488 100644
--- a/doc/public/tmpl/cairo-matrix.sgml
+++ b/doc/public/tmpl/cairo-matrix.sgml
@@ -38,77 +38,78 @@ cairo_matrix_t
</para>
-<!-- ##### TYPEDEF cairo_matrix_t ##### -->
-<para>
-
-</para>
+<!-- ##### SECTION Stability_Level ##### -->
-<!-- ##### FUNCTION cairo_matrix_create ##### -->
+<!-- ##### STRUCT cairo_matrix_t ##### -->
<para>
</para>
-@Returns:
-
+@xx:
+@yx:
+@xy:
+@yy:
+@x0:
+@y0:
-<!-- ##### FUNCTION cairo_matrix_destroy ##### -->
+<!-- ##### FUNCTION cairo_matrix_init ##### -->
<para>
</para>
@matrix:
+@xx:
+@yx:
+@xy:
+@yy:
+@x0:
+@y0:
+<!-- # Unused Parameters # -->
+@Param7:
+@a:
+@b:
+@c:
+@d:
+@tx:
+@ty:
-<!-- ##### FUNCTION cairo_matrix_copy ##### -->
+<!-- ##### FUNCTION cairo_matrix_init_identity ##### -->
<para>
</para>
@matrix:
-@other:
-@Returns:
-<!-- ##### FUNCTION cairo_matrix_set_identity ##### -->
+<!-- ##### FUNCTION cairo_matrix_init_translate ##### -->
<para>
</para>
@matrix:
-@Returns:
+@tx:
+@ty:
-<!-- ##### FUNCTION cairo_matrix_set_affine ##### -->
+<!-- ##### FUNCTION cairo_matrix_init_scale ##### -->
<para>
</para>
@matrix:
-@a:
-@b:
-@c:
-@d:
-@tx:
-@ty:
-@Returns:
-<!-- # Unused Parameters # -->
-@cr:
+@sx:
+@sy:
-<!-- ##### FUNCTION cairo_matrix_get_affine ##### -->
+<!-- ##### FUNCTION cairo_matrix_init_rotate ##### -->
<para>
</para>
@matrix:
-@a:
-@b:
-@c:
-@d:
-@tx:
-@ty:
-@Returns:
+@radians:
<!-- ##### FUNCTION cairo_matrix_translate ##### -->
@@ -119,6 +120,7 @@ cairo_matrix_t
@matrix:
@tx:
@ty:
+<!-- # Unused Parameters # -->
@Returns:
@@ -130,6 +132,7 @@ cairo_matrix_t
@matrix:
@sx:
@sy:
+<!-- # Unused Parameters # -->
@Returns:
@@ -140,6 +143,7 @@ cairo_matrix_t
@matrix:
@radians:
+<!-- # Unused Parameters # -->
@Returns:
@@ -160,6 +164,7 @@ cairo_matrix_t
@result:
@a:
@b:
+<!-- # Unused Parameters # -->
@Returns:
@@ -171,6 +176,7 @@ cairo_matrix_t
@matrix:
@dx:
@dy:
+<!-- # Unused Parameters # -->
@Returns:
@@ -181,6 +187,7 @@ cairo_matrix_t
@matrix:
@x:
@y:
+<!-- # Unused Parameters # -->
@Returns:
<!--
diff --git a/doc/public/tmpl/cairo-pattern.sgml b/doc/public/tmpl/cairo-pattern.sgml
index 84728212b..30deec9b8 100644
--- a/doc/public/tmpl/cairo-pattern.sgml
+++ b/doc/public/tmpl/cairo-pattern.sgml
@@ -14,6 +14,9 @@ cairo_pattern_t
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### TYPEDEF cairo_pattern_t ##### -->
<para>
@@ -71,7 +74,20 @@ cairo_pattern_t
@pattern:
-<!-- ##### FUNCTION cairo_pattern_add_color_stop ##### -->
+<!-- ##### FUNCTION cairo_pattern_add_color_stop_rgb ##### -->
+<para>
+
+</para>
+
+@pattern:
+@offset:
+@red:
+@green:
+@blue:
+@Returns:
+
+
+<!-- ##### FUNCTION cairo_pattern_add_color_stop_rgba ##### -->
<para>
</para>
diff --git a/doc/public/tmpl/cairo-pdf.sgml b/doc/public/tmpl/cairo-pdf.sgml
index e627c236e..8ff0ea17e 100644
--- a/doc/public/tmpl/cairo-pdf.sgml
+++ b/doc/public/tmpl/cairo-pdf.sgml
@@ -14,25 +14,35 @@ PDF Backend
</para>
-<!-- ##### FUNCTION cairo_set_target_pdf ##### -->
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### FUNCTION cairo_pdf_surface_create ##### -->
<para>
</para>
-@cr:
-@file:
+@fp:
@width_inches:
@height_inches:
@x_pixels_per_inch:
@y_pixels_per_inch:
+@Returns:
+<!-- # Unused Parameters # -->
+@write_func:
+@destroy_closure_func:
+@closure:
+@file:
-<!-- ##### FUNCTION cairo_pdf_surface_create ##### -->
+<!-- ##### FUNCTION cairo_pdf_surface_create_for_callback ##### -->
<para>
</para>
-@file:
+@write_func:
+@destroy_closure_func:
+@closure:
@width_inches:
@height_inches:
@x_pixels_per_inch:
diff --git a/doc/public/tmpl/cairo-png.sgml b/doc/public/tmpl/cairo-png.sgml
index d4d5a66b5..dd4486c71 100644
--- a/doc/public/tmpl/cairo-png.sgml
+++ b/doc/public/tmpl/cairo-png.sgml
@@ -14,27 +14,46 @@ PNG Backend
</para>
-<!-- ##### FUNCTION cairo_set_target_png ##### -->
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### FUNCTION cairo_image_surface_create_from_png ##### -->
+<para>
+
+</para>
+
+@filename:
+@Returns:
+
+
+<!-- ##### FUNCTION cairo_image_surface_create_from_png_stream ##### -->
<para>
</para>
-@cr:
-@file:
-@format:
-@width:
-@height:
+@read_func:
+@closure:
+@Returns:
+
+
+<!-- ##### FUNCTION cairo_surface_write_to_png ##### -->
+<para>
+
+</para>
+
+@surface:
+@filename:
+@Returns:
-<!-- ##### FUNCTION cairo_png_surface_create ##### -->
+<!-- ##### FUNCTION cairo_surface_write_to_png_stream ##### -->
<para>
</para>
-@file:
-@format:
-@width:
-@height:
+@surface:
+@write_func:
+@closure:
@Returns:
diff --git a/doc/public/tmpl/cairo-ps.sgml b/doc/public/tmpl/cairo-ps.sgml
index 70b2e7e8f..4cb4a0268 100644
--- a/doc/public/tmpl/cairo-ps.sgml
+++ b/doc/public/tmpl/cairo-ps.sgml
@@ -14,17 +14,7 @@ PS Backend
</para>
-<!-- ##### FUNCTION cairo_set_target_ps ##### -->
-<para>
-
-</para>
-
-@cr:
-@file:
-@width_inches:
-@height_inches:
-@x_pixels_per_inch:
-@y_pixels_per_inch:
+<!-- ##### SECTION Stability_Level ##### -->
<!-- ##### FUNCTION cairo_ps_surface_create ##### -->
diff --git a/doc/public/tmpl/cairo-quartz.sgml b/doc/public/tmpl/cairo-quartz.sgml
index 04c9bc61f..c83de6c77 100644
--- a/doc/public/tmpl/cairo-quartz.sgml
+++ b/doc/public/tmpl/cairo-quartz.sgml
@@ -14,15 +14,7 @@ Quartz Backend
</para>
-<!-- ##### FUNCTION cairo_set_target_quartz_context ##### -->
-<para>
-
-</para>
-
-@cr:
-@context:
-@width:
-@height:
+<!-- ##### SECTION Stability_Level ##### -->
<!-- ##### FUNCTION cairo_quartz_surface_create ##### -->
diff --git a/doc/public/tmpl/cairo-surface.sgml b/doc/public/tmpl/cairo-surface.sgml
index 2f8ad470c..e92935a6c 100644
--- a/doc/public/tmpl/cairo-surface.sgml
+++ b/doc/public/tmpl/cairo-surface.sgml
@@ -14,23 +14,27 @@ cairo_surface_t
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### TYPEDEF cairo_surface_t ##### -->
<para>
</para>
-<!-- ##### FUNCTION cairo_surface_create_for_image ##### -->
+<!-- ##### MACRO cairo_surface_create_for_image ##### -->
<para>
</para>
+@Returns:
+<!-- # Unused Parameters # -->
@data:
@format:
@width:
@height:
@stride:
-@Returns:
<!-- ##### FUNCTION cairo_surface_create_similar ##### -->
@@ -61,52 +65,100 @@ cairo_surface_t
@surface:
-<!-- ##### FUNCTION cairo_surface_set_repeat ##### -->
+<!-- ##### FUNCTION cairo_surface_finish ##### -->
<para>
</para>
@surface:
-@repeat:
@Returns:
-<!-- ##### FUNCTION cairo_surface_set_matrix ##### -->
+<!-- ##### MACRO cairo_surface_set_repeat ##### -->
<para>
</para>
-@surface:
-@matrix:
@Returns:
+<!-- # Unused Parameters # -->
+@surface:
+@repeat:
-<!-- ##### FUNCTION cairo_surface_get_matrix ##### -->
+<!-- ##### MACRO cairo_surface_set_matrix ##### -->
<para>
</para>
+@Returns:
+<!-- # Unused Parameters # -->
@surface:
@matrix:
+
+
+<!-- ##### MACRO cairo_surface_get_matrix ##### -->
+<para>
+
+</para>
+
@Returns:
+<!-- # Unused Parameters # -->
+@surface:
+@matrix:
-<!-- ##### FUNCTION cairo_surface_set_filter ##### -->
+<!-- ##### MACRO cairo_surface_set_filter ##### -->
<para>
</para>
+@Returns:
+<!-- # Unused Parameters # -->
@surface:
@filter:
+
+
+<!-- ##### MACRO cairo_surface_get_filter ##### -->
+<para>
+
+</para>
+
@Returns:
+<!-- # Unused Parameters # -->
+@surface:
-<!-- ##### FUNCTION cairo_surface_get_filter ##### -->
+<!-- ##### FUNCTION cairo_surface_set_user_data ##### -->
<para>
</para>
@surface:
+@key:
+@user_data:
+@destroy:
@Returns:
+<!-- # Unused Parameters # -->
+@data:
+
+
+<!-- ##### FUNCTION cairo_surface_get_user_data ##### -->
+<para>
+
+</para>
+
+@surface:
+@key:
+@Returns:
+
+
+<!-- ##### FUNCTION cairo_surface_set_device_offset ##### -->
+<para>
+
+</para>
+
+@surface:
+@x_offset:
+@y_offset:
diff --git a/doc/public/tmpl/cairo-xcb.sgml b/doc/public/tmpl/cairo-xcb.sgml
index e5e1ee912..416d71638 100644
--- a/doc/public/tmpl/cairo-xcb.sgml
+++ b/doc/public/tmpl/cairo-xcb.sgml
@@ -14,15 +14,18 @@ XCB Backend
</para>
-<!-- ##### FUNCTION cairo_set_target_xcb ##### -->
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### FUNCTION cairo_xcb_surface_create ##### -->
<para>
</para>
-@cr:
@dpy:
@drawable:
@visual:
@format:
+@Returns:
diff --git a/doc/public/tmpl/cairo-xlib.sgml b/doc/public/tmpl/cairo-xlib.sgml
index b18e76aae..30282b226 100644
--- a/doc/public/tmpl/cairo-xlib.sgml
+++ b/doc/public/tmpl/cairo-xlib.sgml
@@ -14,17 +14,24 @@ XLib Backend
</para>
-<!-- ##### FUNCTION cairo_set_target_drawable ##### -->
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### FUNCTION cairo_xlib_surface_create ##### -->
<para>
</para>
-@cr:
@dpy:
@drawable:
+@format:
+@Returns:
+<!-- # Unused Parameters # -->
+@visual:
+@colormap:
-<!-- ##### FUNCTION cairo_xlib_surface_create ##### -->
+<!-- ##### FUNCTION cairo_xlib_surface_create_with_visual ##### -->
<para>
</para>
@@ -32,8 +39,16 @@ XLib Backend
@dpy:
@drawable:
@visual:
-@format:
-@colormap:
@Returns:
+<!-- ##### FUNCTION cairo_xlib_surface_set_size ##### -->
+<para>
+
+</para>
+
+@surface:
+@width:
+@height:
+
+
diff --git a/doc/public/tmpl/cairo.sgml b/doc/public/tmpl/cairo.sgml
index a9e195c73..06a5fba6d 100644
--- a/doc/public/tmpl/cairo.sgml
+++ b/doc/public/tmpl/cairo.sgml
@@ -24,6 +24,9 @@ Drawing contexts.
</para>
+<!-- ##### SECTION Stability_Level ##### -->
+
+
<!-- ##### TYPEDEF cairo_t ##### -->
<para>
@@ -35,6 +38,7 @@ Drawing contexts.
</para>
+@target:
@Returns:
@@ -70,24 +74,16 @@ Drawing contexts.
@cr:
-<!-- ##### FUNCTION cairo_copy ##### -->
+<!-- ##### MACRO cairo_copy ##### -->
<para>
</para>
+<!-- # Unused Parameters # -->
@dest:
@src:
-<!-- ##### FUNCTION cairo_set_target_surface ##### -->
-<para>
-
-</para>
-
-@cr:
-@surface:
-
-
<!-- ##### ENUM cairo_format_t ##### -->
<para>
@@ -98,35 +94,22 @@ Drawing contexts.
@CAIRO_FORMAT_A8:
@CAIRO_FORMAT_A1:
-<!-- ##### FUNCTION cairo_set_target_image ##### -->
-<para>
-
-</para>
-
-@cr:
-@data:
-@format:
-@width:
-@height:
-@stride:
-
-
<!-- ##### ENUM cairo_operator_t ##### -->
<para>
</para>
@CAIRO_OPERATOR_CLEAR:
-@CAIRO_OPERATOR_SRC:
-@CAIRO_OPERATOR_DST:
+@CAIRO_OPERATOR_SOURCE:
@CAIRO_OPERATOR_OVER:
-@CAIRO_OPERATOR_OVER_REVERSE:
@CAIRO_OPERATOR_IN:
-@CAIRO_OPERATOR_IN_REVERSE:
@CAIRO_OPERATOR_OUT:
-@CAIRO_OPERATOR_OUT_REVERSE:
@CAIRO_OPERATOR_ATOP:
-@CAIRO_OPERATOR_ATOP_REVERSE:
+@CAIRO_OPERATOR_DEST:
+@CAIRO_OPERATOR_DEST_OVER:
+@CAIRO_OPERATOR_DEST_IN:
+@CAIRO_OPERATOR_DEST_OUT:
+@CAIRO_OPERATOR_DEST_ATOP:
@CAIRO_OPERATOR_XOR:
@CAIRO_OPERATOR_ADD:
@CAIRO_OPERATOR_SATURATE:
@@ -140,7 +123,18 @@ Drawing contexts.
@op:
-<!-- ##### FUNCTION cairo_set_rgb_color ##### -->
+<!-- ##### FUNCTION cairo_set_source_rgb ##### -->
+<para>
+
+</para>
+
+@cr:
+@red:
+@green:
+@blue:
+
+
+<!-- ##### FUNCTION cairo_set_source_rgba ##### -->
<para>
</para>
@@ -149,22 +143,37 @@ Drawing contexts.
@red:
@green:
@blue:
+@alpha:
-<!-- ##### FUNCTION cairo_set_pattern ##### -->
+<!-- ##### FUNCTION cairo_set_source ##### -->
<para>
</para>
@cr:
+@source:
+<!-- # Unused Parameters # -->
@pattern:
-<!-- ##### FUNCTION cairo_set_alpha ##### -->
+<!-- ##### FUNCTION cairo_set_source_surface ##### -->
+<para>
+
+</para>
+
+@cr:
+@surface:
+@x:
+@y:
+
+
+<!-- ##### MACRO cairo_set_alpha ##### -->
<para>
</para>
+<!-- # Unused Parameters # -->
@cr:
@alpha:
@@ -289,7 +298,7 @@ Drawing contexts.
@angle:
-<!-- ##### FUNCTION cairo_concat_matrix ##### -->
+<!-- ##### FUNCTION cairo_transform ##### -->
<para>
</para>
@@ -307,11 +316,12 @@ Drawing contexts.
@matrix:
-<!-- ##### FUNCTION cairo_default_matrix ##### -->
+<!-- ##### MACRO cairo_default_matrix ##### -->
<para>
</para>
+<!-- # Unused Parameters # -->
@cr:
@@ -323,7 +333,7 @@ Drawing contexts.
@cr:
-<!-- ##### FUNCTION cairo_transform_point ##### -->
+<!-- ##### FUNCTION cairo_user_to_device ##### -->
<para>
</para>
@@ -333,7 +343,7 @@ Drawing contexts.
@y:
-<!-- ##### FUNCTION cairo_transform_distance ##### -->
+<!-- ##### FUNCTION cairo_user_to_device_distance ##### -->
<para>
</para>
@@ -343,7 +353,7 @@ Drawing contexts.
@dy:
-<!-- ##### FUNCTION cairo_inverse_transform_point ##### -->
+<!-- ##### FUNCTION cairo_device_to_user ##### -->
<para>
</para>
@@ -353,7 +363,7 @@ Drawing contexts.
@y:
-<!-- ##### FUNCTION cairo_inverse_transform_distance ##### -->
+<!-- ##### FUNCTION cairo_device_to_user_distance ##### -->
<para>
</para>
@@ -485,6 +495,43 @@ Drawing contexts.
@cr:
+<!-- ##### FUNCTION cairo_paint ##### -->
+<para>
+
+</para>
+
+@cr:
+
+
+<!-- ##### FUNCTION cairo_paint_with_alpha ##### -->
+<para>
+
+</para>
+
+@cr:
+@alpha:
+
+
+<!-- ##### FUNCTION cairo_mask ##### -->
+<para>
+
+</para>
+
+@cr:
+@pattern:
+
+
+<!-- ##### FUNCTION cairo_mask_surface ##### -->
+<para>
+
+</para>
+
+@cr:
+@surface:
+@surface_x:
+@surface_y:
+
+
<!-- ##### FUNCTION cairo_stroke ##### -->
<para>
@@ -493,6 +540,14 @@ Drawing contexts.
@cr:
+<!-- ##### FUNCTION cairo_stroke_preserve ##### -->
+<para>
+
+</para>
+
+@cr:
+
+
<!-- ##### FUNCTION cairo_fill ##### -->
<para>
@@ -501,6 +556,14 @@ Drawing contexts.
@cr:
+<!-- ##### FUNCTION cairo_fill_preserve ##### -->
+<para>
+
+</para>
+
+@cr:
+
+
<!-- ##### FUNCTION cairo_copy_page ##### -->
<para>
@@ -569,7 +632,7 @@ Drawing contexts.
@y2:
-<!-- ##### FUNCTION cairo_init_clip ##### -->
+<!-- ##### FUNCTION cairo_clip ##### -->
<para>
</para>
@@ -577,7 +640,7 @@ Drawing contexts.
@cr:
-<!-- ##### FUNCTION cairo_clip ##### -->
+<!-- ##### FUNCTION cairo_clip_preserve ##### -->
<para>
</para>
@@ -585,11 +648,13 @@ Drawing contexts.
@cr:
-<!-- ##### TYPEDEF cairo_font_t ##### -->
+<!-- ##### FUNCTION cairo_reset_clip ##### -->
<para>
</para>
+@cr:
+
<!-- ##### STRUCT cairo_glyph_t ##### -->
<para>
@@ -600,29 +665,6 @@ Drawing contexts.
@x:
@y:
-<!-- ##### STRUCT cairo_text_extents_t ##### -->
-<para>
-
-</para>
-
-@x_bearing:
-@y_bearing:
-@width:
-@height:
-@x_advance:
-@y_advance:
-
-<!-- ##### STRUCT cairo_font_extents_t ##### -->
-<para>
-
-</para>
-
-@ascent:
-@descent:
-@height:
-@max_x_advance:
-@max_y_advance:
-
<!-- ##### ENUM cairo_font_slant_t ##### -->
<para>
@@ -640,7 +682,7 @@ Drawing contexts.
@CAIRO_FONT_WEIGHT_NORMAL:
@CAIRO_FONT_WEIGHT_BOLD:
-<!-- ##### FUNCTION cairo_select_font ##### -->
+<!-- ##### FUNCTION cairo_select_font_face ##### -->
<para>
</para>
@@ -651,16 +693,16 @@ Drawing contexts.
@weight:
-<!-- ##### FUNCTION cairo_scale_font ##### -->
+<!-- ##### FUNCTION cairo_set_font_size ##### -->
<para>
</para>
@cr:
-@scale:
+@size:
-<!-- ##### FUNCTION cairo_transform_font ##### -->
+<!-- ##### FUNCTION cairo_set_font_matrix ##### -->
<para>
</para>
@@ -669,6 +711,16 @@ Drawing contexts.
@matrix:
+<!-- ##### FUNCTION cairo_get_font_matrix ##### -->
+<para>
+
+</para>
+
+@cr:
+@matrix:
+@Returns:
+
+
<!-- ##### FUNCTION cairo_show_text ##### -->
<para>
@@ -688,7 +740,7 @@ Drawing contexts.
@num_glyphs:
-<!-- ##### FUNCTION cairo_current_font ##### -->
+<!-- ##### FUNCTION cairo_get_font_face ##### -->
<para>
</para>
@@ -697,22 +749,26 @@ Drawing contexts.
@Returns:
-<!-- ##### FUNCTION cairo_current_font_extents ##### -->
+<!-- ##### FUNCTION cairo_font_extents ##### -->
<para>
</para>
@cr:
@extents:
+<!-- # Unused Parameters # -->
+@font:
+@Returns:
+@font_matrix:
-<!-- ##### FUNCTION cairo_set_font ##### -->
+<!-- ##### FUNCTION cairo_set_font_face ##### -->
<para>
</para>
@cr:
-@font:
+@font_face:
<!-- ##### FUNCTION cairo_text_extents ##### -->
@@ -755,66 +811,65 @@ Drawing contexts.
@num_glyphs:
-<!-- ##### FUNCTION cairo_font_reference ##### -->
+<!-- ##### MACRO cairo_show_surface ##### -->
<para>
</para>
-@font:
+<!-- # Unused Parameters # -->
+@cr:
+@surface:
+@width:
+@height:
-<!-- ##### FUNCTION cairo_font_destroy ##### -->
+<!-- ##### FUNCTION cairo_get_operator ##### -->
<para>
</para>
-@font:
+@cr:
+@Returns:
-<!-- ##### FUNCTION cairo_font_glyph_extents ##### -->
+<!-- ##### FUNCTION cairo_get_source ##### -->
<para>
</para>
-@font:
-@font_matrix:
-@glyphs:
-@num_glyphs:
-@extents:
+@cr:
+@Returns:
-<!-- ##### FUNCTION cairo_show_surface ##### -->
+<!-- ##### FUNCTION cairo_get_tolerance ##### -->
<para>
</para>
@cr:
-@surface:
-@width:
-@height:
+@Returns:
-<!-- ##### FUNCTION cairo_current_operator ##### -->
+<!-- ##### FUNCTION cairo_get_current_point ##### -->
<para>
</para>
@cr:
-@Returns:
+@x:
+@y:
-<!-- ##### FUNCTION cairo_current_rgb_color ##### -->
+<!-- ##### FUNCTION cairo_get_fill_rule ##### -->
<para>
</para>
@cr:
-@red:
-@green:
-@blue:
+@Returns:
-<!-- ##### FUNCTION cairo_current_pattern ##### -->
+<!-- ##### FUNCTION cairo_get_line_width ##### -->
<para>
</para>
@@ -823,7 +878,7 @@ Drawing contexts.
@Returns:
-<!-- ##### FUNCTION cairo_current_alpha ##### -->
+<!-- ##### FUNCTION cairo_get_line_cap ##### -->
<para>
</para>
@@ -832,7 +887,7 @@ Drawing contexts.
@Returns:
-<!-- ##### FUNCTION cairo_current_tolerance ##### -->
+<!-- ##### FUNCTION cairo_get_line_join ##### -->
<para>
</para>
@@ -841,26 +896,27 @@ Drawing contexts.
@Returns:
-<!-- ##### FUNCTION cairo_current_point ##### -->
+<!-- ##### FUNCTION cairo_get_miter_limit ##### -->
<para>
</para>
@cr:
-@x:
-@y:
+@Returns:
-<!-- ##### FUNCTION cairo_current_fill_rule ##### -->
+<!-- ##### FUNCTION cairo_get_matrix ##### -->
<para>
</para>
@cr:
+@matrix:
+<!-- # Unused Parameters # -->
@Returns:
-<!-- ##### FUNCTION cairo_current_line_width ##### -->
+<!-- ##### FUNCTION cairo_get_target ##### -->
<para>
</para>
@@ -869,25 +925,34 @@ Drawing contexts.
@Returns:
-<!-- ##### FUNCTION cairo_current_line_cap ##### -->
+<!-- ##### MACRO cairo_get_path ##### -->
<para>
</para>
+<!-- # Unused Parameters # -->
@cr:
-@Returns:
+@move_to:
+@line_to:
+@curve_to:
+@close_path:
+@closure:
-<!-- ##### FUNCTION cairo_current_line_join ##### -->
+<!-- ##### MACRO cairo_get_path_flat ##### -->
<para>
</para>
+<!-- # Unused Parameters # -->
@cr:
-@Returns:
+@move_to:
+@line_to:
+@close_path:
+@closure:
-<!-- ##### FUNCTION cairo_current_miter_limit ##### -->
+<!-- ##### FUNCTION cairo_copy_path ##### -->
<para>
</para>
@@ -896,47 +961,38 @@ Drawing contexts.
@Returns:
-<!-- ##### FUNCTION cairo_current_matrix ##### -->
+<!-- ##### FUNCTION cairo_copy_path_flat ##### -->
<para>
</para>
@cr:
-@matrix:
+@Returns:
-<!-- ##### FUNCTION cairo_current_target_surface ##### -->
+<!-- ##### FUNCTION cairo_append_path ##### -->
<para>
</para>
@cr:
-@Returns:
+@path:
-<!-- ##### FUNCTION cairo_current_path ##### -->
+<!-- ##### STRUCT cairo_path_t ##### -->
<para>
</para>
-@cr:
-@move_to:
-@line_to:
-@curve_to:
-@close_path:
-@closure:
-
+@data:
+@num_data:
-<!-- ##### FUNCTION cairo_current_path_flat ##### -->
+<!-- ##### FUNCTION cairo_path_destroy ##### -->
<para>
</para>
-@cr:
-@move_to:
-@line_to:
-@close_path:
-@closure:
+@path:
<!-- ##### ENUM cairo_status_t ##### -->
@@ -953,6 +1009,12 @@ Drawing contexts.
@CAIRO_STATUS_NO_TARGET_SURFACE:
@CAIRO_STATUS_NULL_POINTER:
@CAIRO_STATUS_INVALID_STRING:
+@CAIRO_STATUS_INVALID_PATH_DATA:
+@CAIRO_STATUS_READ_ERROR:
+@CAIRO_STATUS_WRITE_ERROR:
+@CAIRO_STATUS_SURFACE_FINISHED:
+@CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
+@CAIRO_STATUS_BAD_NESTING:
<!-- ##### FUNCTION cairo_status ##### -->
<para>
@@ -1017,3 +1079,58 @@ End:
-->
+<!-- ##### FUNCTION cairo_image_surface_get_width ##### -->
+<para>
+
+</para>
+
+@surface:
+@Returns:
+
+
+<!-- ##### FUNCTION cairo_image_surface_get_height ##### -->
+<para>
+
+</para>
+
+@surface:
+@Returns:
+
+
+<!-- ##### USER_FUNCTION cairo_destroy_func_t ##### -->
+<para>
+
+</para>
+
+@data:
+
+
+<!-- ##### STRUCT cairo_user_data_key_t ##### -->
+<para>
+
+</para>
+
+@unused:
+
+<!-- ##### USER_FUNCTION cairo_read_func_t ##### -->
+<para>
+
+</para>
+
+@closure:
+@data:
+@length:
+@Returns:
+
+
+<!-- ##### USER_FUNCTION cairo_write_func_t ##### -->
+<para>
+
+</para>
+
+@closure:
+@data:
+@length:
+@Returns:
+
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 3f76d2726..8c624f247 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,56 +1,55 @@
if CAIRO_HAS_PS_SURFACE
libcairo_ps_headers = cairo-ps.h
-libcairo_ps_sources = cairo_ps_surface.c
+libcairo_ps_sources = cairo-ps-surface.c
endif
if CAIRO_HAS_PDF_SURFACE
libcairo_pdf_headers = cairo-pdf.h
-libcairo_pdf_sources = cairo_pdf_surface.c
+libcairo_pdf_sources = cairo-pdf-surface.c
endif
-if CAIRO_HAS_PNG_SURFACE
-libcairo_png_headers = cairo-png.h
-libcairo_png_sources = cairo_png_surface.c
+if CAIRO_HAS_PNG_FUNCTIONS
+libcairo_png_sources = cairo-png.c
endif
if CAIRO_HAS_XLIB_SURFACE
-libcairo_xlib_headers = cairo-xlib.h
-libcairo_xlib_sources = cairo_xlib_surface.c
+libcairo_xlib_headers = cairo-xlib.h cairo-xlib-xrender.h
+libcairo_xlib_sources = cairo-xlib-surface.c cairo-xlib-test.h
endif
if CAIRO_HAS_QUARTZ_SURFACE
libcairo_quartz_headers = cairo-quartz.h
-libcairo_quartz_sources = cairo_quartz_surface.c
+libcairo_quartz_sources = cairo-quartz-surface.c
endif
if CAIRO_HAS_XCB_SURFACE
-libcairo_xcb_headers = cairo-xcb.h
-libcairo_xcb_sources = cairo_xcb_surface.c
+libcairo_xcb_headers = cairo-xcb.h cairo-xcb-xrender.h
+libcairo_xcb_sources = cairo-xcb-surface.c
endif
libcairo_win32_sources =
if CAIRO_HAS_WIN32_SURFACE
libcairo_win32_headers = cairo-win32.h
-libcairo_win32_sources += cairo_win32_surface.c cairo-win32-private.h
+libcairo_win32_sources += cairo-win32-surface.c cairo-win32-private.h
endif
if CAIRO_HAS_WIN32_FONT
-libcairo_win32_sources += cairo_win32_font.c
+libcairo_win32_sources += cairo-win32-font.c
endif
if CAIRO_HAS_GLITZ_SURFACE
libcairo_glitz_headers = cairo-glitz.h
-libcairo_glitz_sources = cairo_glitz_surface.c
+libcairo_glitz_sources = cairo-glitz-surface.c
endif
if CAIRO_HAS_ATSUI_FONT
libcairo_atsui_headers = cairo-atsui.h
-libcairo_atsui_sources = cairo_atsui_font.c
+libcairo_atsui_sources = cairo-atsui-font.c
endif
if CAIRO_HAS_FT_FONT
libcairo_ft_headers = cairo-ft.h
-libcairo_ft_sources = cairo_ft_font.c cairo-ft-private.h
+libcairo_ft_sources = cairo-ft-font.c cairo-ft-private.h
endif
# These names match automake style variable definition conventions so
@@ -68,7 +67,6 @@ cairoinclude_HEADERS = \
$(libcairo_ft_headers) \
$(libcairo_glitz_headers) \
$(libcairo_pdf_headers) \
- $(libcairo_png_headers) \
$(libcairo_ps_headers) \
$(libcairo_quartz_headers) \
$(libcairo_win32_headers) \
@@ -80,28 +78,36 @@ lib_LTLIBRARIES = libcairo.la
libcairo_la_SOURCES = \
cairo.c \
cairo.h \
- cairo_array.c \
- cairo_cache.c \
- cairo_color.c \
- cairo_fixed.c \
- cairo_font.c \
- cairo_gstate.c \
- cairo_hull.c \
- cairo_image_surface.c \
- cairo_matrix.c \
- cairo_path.c \
- cairo_path_bounds.c \
- cairo_path_fill.c \
- cairo_path_stroke.c \
- cairo_pen.c \
- cairo_polygon.c \
- cairo_slope.c \
- cairo_spline.c \
- cairo_surface.c \
- cairo_traps.c \
- cairo_pattern.c \
- cairo_unicode.c \
- cairo_wideint.c \
+ cairo-private.h \
+ cairo-arc.c \
+ cairo-arc-private.h \
+ cairo-array.c \
+ cairo-cache.c \
+ cairo-color.c \
+ cairo-fixed.c \
+ cairo-font.c \
+ cairo-gstate.c \
+ cairo-gstate-private.h \
+ cairo-hull.c \
+ cairo-image-surface.c \
+ cairo-matrix.c \
+ cairo-path.c \
+ cairo-path-bounds.c \
+ cairo-path-data.c \
+ cairo-path-data-private.h \
+ cairo-path-fill.c \
+ cairo-path-fixed-private.h \
+ cairo-path-stroke.c \
+ cairo-pen.c \
+ cairo-polygon.c \
+ cairo-slope.c \
+ cairo-spline.c \
+ cairo-surface.c \
+ cairo-traps.c \
+ cairo-pattern.c \
+ cairo-unicode.c \
+ cairo-output-stream.c \
+ cairo-wideint.c \
cairo-wideint.h \
$(libcairo_atsui_sources)\
$(libcairo_ft_sources)\
@@ -113,7 +119,6 @@ libcairo_la_SOURCES = \
$(libcairo_xcb_sources) \
$(libcairo_glitz_sources)\
$(libcairo_win32_sources)\
- $(libcairo_freetype_sources) \
cairoint.h
libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined
@@ -123,7 +128,7 @@ INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS)
libcairo_la_LIBADD = $(CAIRO_LIBS)
install-data-local:
- @if test -f $(includedir)/cairo.h || test -f $(includedir)/cairo-features.h ; then \
+ @if test -f "$(DESTDIR)$(includedir)/cairo.h" || test -f "$(DESTDIR)$(includedir)/cairo-features.h" ; then \
echo "****************************************************************" ; \
echo "*** Error: Old headers found. You should remove the following" ; \
echo "*** files and then type 'make install' again." ; \
diff --git a/src/cairo-arc-private.h b/src/cairo-arc-private.h
new file mode 100644
index 000000000..1cd41cc15
--- /dev/null
+++ b/src/cairo-arc-private.h
@@ -0,0 +1,57 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#ifndef CAIRO_ARC_PRIVATE_H
+#define CAIRO_ARC_PRIVATE_H
+
+#include "cairoint.h"
+
+void
+_cairo_arc_path (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle1,
+ double angle2);
+
+void
+_cairo_arc_path_negative (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle1,
+ double angle2);
+
+#endif /* CAIRO_ARC_PRIVATE_H */
diff --git a/src/cairo-arc.c b/src/cairo-arc.c
new file mode 100644
index 000000000..d3302cdd5
--- /dev/null
+++ b/src/cairo-arc.c
@@ -0,0 +1,296 @@
+/* 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@cworth.org>
+ */
+
+#include <math.h>
+
+#include "cairo-arc-private.h"
+
+/* Spline deviation from the circle in radius would be given by:
+
+ error = sqrt (x**2 + y**2) - 1
+
+ A simpler error function to work with is:
+
+ e = x**2 + y**2 - 1
+
+ From "Good approximation of circles by curvature-continuous Bezier
+ curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
+ Design 8 (1990) 22-41, we learn:
+
+ abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
+
+ and
+ abs (error) =~ 1/2 * e
+
+ Of course, this error value applies only for the particular spline
+ approximation that is used in _cairo_gstate_arc_segment.
+*/
+static double
+_arc_error_normalized (double angle)
+{
+ return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
+}
+
+static double
+_arc_max_angle_for_tolerance_normalized (double tolerance)
+{
+ double angle, error;
+ int i;
+
+ /* Use table lookup to reduce search time in most cases. */
+ struct {
+ double angle;
+ double error;
+ } table[] = {
+ { M_PI / 1.0, 0.0185185185185185036127 },
+ { M_PI / 2.0, 0.000272567143730179811158 },
+ { M_PI / 3.0, 2.38647043651461047433e-05 },
+ { M_PI / 4.0, 4.2455377443222443279e-06 },
+ { M_PI / 5.0, 1.11281001494389081528e-06 },
+ { M_PI / 6.0, 3.72662000942734705475e-07 },
+ { M_PI / 7.0, 1.47783685574284411325e-07 },
+ { M_PI / 8.0, 6.63240432022601149057e-08 },
+ { M_PI / 9.0, 3.2715520137536980553e-08 },
+ { M_PI / 10.0, 1.73863223499021216974e-08 },
+ { M_PI / 11.0, 9.81410988043554039085e-09 },
+ };
+ int table_size = (sizeof (table) / sizeof (table[0]));
+
+ for (i = 0; i < table_size; i++)
+ if (table[i].error < tolerance)
+ return table[i].angle;
+
+ ++i;
+ do {
+ angle = M_PI / i++;
+ error = _arc_error_normalized (angle);
+ } while (error > tolerance);
+
+ return angle;
+}
+
+static int
+_arc_segments_needed (double angle,
+ double radius,
+ cairo_matrix_t *ctm,
+ double tolerance)
+{
+ double l1, l2, lmax;
+ double max_angle;
+
+ _cairo_matrix_compute_eigen_values (ctm, &l1, &l2);
+
+ l1 = fabs (l1);
+ l2 = fabs (l2);
+ if (l1 > l2)
+ lmax = l1;
+ else
+ lmax = l2;
+
+ max_angle = _arc_max_angle_for_tolerance_normalized (tolerance / (radius * lmax));
+
+ return (int) ceil (angle / max_angle);
+}
+
+/* We want to draw a single spline approximating a circular arc radius
+ R from angle A to angle B. Since we want a symmetric spline that
+ matches the endpoints of the arc in position and slope, we know
+ that the spline control points must be:
+
+ (R * cos(A), R * sin(A))
+ (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
+ (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
+ (R * cos(B), R * sin(B))
+
+ for some value of h.
+
+ "Approximation of circular arcs by cubic poynomials", Michael
+ Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
+ various values of h along with error analysis for each.
+
+ From that paper, a very practical value of h is:
+
+ h = 4/3 * tan(angle/4)
+
+ This value does not give the spline with minimal error, but it does
+ provide a very good approximation, (6th-order convergence), and the
+ error expression is quite simple, (see the comment for
+ _arc_error_normalized).
+*/
+static void
+_cairo_arc_segment (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle_A,
+ double angle_B)
+{
+ double r_sin_A, r_cos_A;
+ double r_sin_B, r_cos_B;
+ double h;
+
+ r_sin_A = radius * sin (angle_A);
+ r_cos_A = radius * cos (angle_A);
+ r_sin_B = radius * sin (angle_B);
+ r_cos_B = radius * cos (angle_B);
+
+ h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
+
+ cairo_curve_to (cr,
+ xc + r_cos_A - h * r_sin_A,
+ yc + r_sin_A + h * r_cos_A,
+ xc + r_cos_B + h * r_sin_B,
+ yc + r_sin_B - h * r_cos_B,
+ xc + r_cos_B,
+ yc + r_sin_B);
+}
+
+static void
+_cairo_arc_in_direction (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle_min,
+ double angle_max,
+ cairo_direction_t dir)
+{
+ while (angle_max - angle_min > 4 * M_PI)
+ angle_max -= 2 * M_PI;
+
+ /* Recurse if drawing arc larger than pi */
+ if (angle_max - angle_min > M_PI) {
+ double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
+ /* XXX: Something tells me this block could be condensed. */
+ if (dir == CAIRO_DIRECTION_FORWARD) {
+ _cairo_arc_in_direction (cr, xc, yc, radius,
+ angle_min, angle_mid,
+ dir);
+
+ _cairo_arc_in_direction (cr, xc, yc, radius,
+ angle_mid, angle_max,
+ dir);
+ } else {
+ _cairo_arc_in_direction (cr, xc, yc, radius,
+ angle_mid, angle_max,
+ dir);
+
+ _cairo_arc_in_direction (cr, xc, yc, radius,
+ angle_min, angle_mid,
+ dir);
+ }
+ } else {
+ cairo_matrix_t ctm;
+ int i, segments;
+ double angle, angle_step;
+
+ cairo_get_matrix (cr, &ctm);
+ segments = _arc_segments_needed (angle_max - angle_min,
+ radius, &ctm,
+ cairo_get_tolerance (cr));
+ angle_step = (angle_max - angle_min) / (double) segments;
+
+ if (dir == CAIRO_DIRECTION_FORWARD) {
+ angle = angle_min;
+ } else {
+ angle = angle_max;
+ angle_step = - angle_step;
+ }
+
+ for (i = 0; i < segments; i++, angle += angle_step) {
+ _cairo_arc_segment (cr, xc, yc,
+ radius,
+ angle,
+ angle + angle_step);
+ }
+ }
+}
+
+/**
+ * _cairo_arc_path_negative:
+ * @cr: a cairo context
+ * @xc: X position of the center of the arc
+ * @yc: Y position of the center of the arc
+ * @radius: the radius of the arc
+ * @angle1: the start angle, in radians
+ * @angle2: the end angle, in radians
+ *
+ * Compute a path for the given arc and append it onto the current
+ * path within @cr. The arc will be accurate within the current
+ * tolerance and given the current transformation.
+ **/
+void
+_cairo_arc_path (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle1,
+ double angle2)
+{
+ _cairo_arc_in_direction (cr, xc, yc,
+ radius,
+ angle1, angle2,
+ CAIRO_DIRECTION_FORWARD);
+}
+
+/**
+ * _cairo_arc_path_negative:
+ * @xc: X position of the center of the arc
+ * @yc: Y position of the center of the arc
+ * @radius: the radius of the arc
+ * @angle1: the start angle, in radians
+ * @angle2: the end angle, in radians
+ * @ctm: the current transformation matrix
+ * @tolerance: the current tolerance value
+ * @path: the path onto which th earc will be appended
+ *
+ * Compute a path for the given arc (defined in the negative
+ * direction) and append it onto the current path within @cr. The arc
+ * will be accurate within the current tolerance and given the current
+ * transformation.
+ **/
+void
+_cairo_arc_path_negative (cairo_t *cr,
+ double xc,
+ double yc,
+ double radius,
+ double angle1,
+ double angle2)
+{
+ _cairo_arc_in_direction (cr, xc, yc,
+ radius,
+ angle2, angle1,
+ CAIRO_DIRECTION_REVERSE);
+}
diff --git a/src/cairo-array.c b/src/cairo-array.c
index 2b1cf9d61..a37ea9af5 100644
--- a/src/cairo-array.c
+++ b/src/cairo-array.c
@@ -132,3 +132,142 @@ _cairo_array_num_elements (cairo_array_t *array)
{
return array->num_elements;
}
+
+/* cairo_user_data_array_t */
+
+typedef struct {
+ const cairo_user_data_key_t *key;
+ void *user_data;
+ cairo_destroy_func_t destroy;
+} cairo_user_data_slot_t;
+
+/**
+ * _cairo_user_data_array_init:
+ * @array: a #cairo_user_data_array_t
+ *
+ * Initializes a #cairo_user_data_array_t structure for future
+ * use. After initialization, the array has no keys. Call
+ * _cairo_user_data_array_destroy() to free any allocated memory
+ * when done using the array.
+ **/
+void
+_cairo_user_data_array_init (cairo_user_data_array_t *array)
+{
+ _cairo_array_init (array, sizeof (cairo_user_data_slot_t));
+}
+
+/**
+ * _cairo_user_data_array_destroy:
+ * @array: a #cairo_user_data_array_t
+ *
+ * Destroys all current keys in the user data array and deallocates
+ * any memory allocated for the array itself.
+ **/
+void
+_cairo_user_data_array_destroy (cairo_user_data_array_t *array)
+{
+ int i, num_slots;
+ cairo_user_data_slot_t *slots;
+
+ num_slots = array->num_elements;
+ slots = (cairo_user_data_slot_t *) array->elements;
+ for (i = 0; i < num_slots; i++) {
+ if (slots[i].user_data != NULL && slots[i].destroy != NULL)
+ slots[i].destroy (slots[i].user_data);
+ }
+
+ _cairo_array_fini (array);
+}
+
+/**
+ * _cairo_user_data_array_get_data:
+ * @array: a #cairo_user_data_array_t
+ * @key: the address of the #cairo_user_data_key_t the user data was
+ * attached to
+ *
+ * Returns user data previously attached using the specified
+ * key. If no user data has been attached with the given key this
+ * function returns %NULL.
+ *
+ * Return value: the user data previously attached or %NULL.
+ **/
+void *
+_cairo_user_data_array_get_data (cairo_user_data_array_t *array,
+ const cairo_user_data_key_t *key)
+{
+ int i, num_slots;
+ cairo_user_data_slot_t *slots;
+
+ num_slots = array->num_elements;
+ slots = (cairo_user_data_slot_t *) array->elements;
+ for (i = 0; i < num_slots; i++) {
+ if (slots[i].key == key)
+ return slots[i].user_data;
+ }
+
+ return NULL;
+}
+
+/**
+ * _cairo_user_data_array_set_data:
+ * @array: a #cairo_user_data_array_t
+ * @key: the address of a #cairo_user_data_key_t to attach the user data to
+ * @user_data: the user data to attach
+ * @destroy: a #cairo_destroy_func_t which will be called when the
+ * user data array is destroyed or when new user data is attached using the
+ * same key.
+ *
+ * Attaches user data to a user data array. To remove user data,
+ * call this function with the key that was used to set it and %NULL
+ * for @data.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
+ * slot could not be allocated for the user data.
+ **/
+cairo_status_t
+_cairo_user_data_array_set_data (cairo_user_data_array_t *array,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy)
+{
+ int i, num_slots;
+ cairo_user_data_slot_t *slots, *s;
+
+ s = NULL;
+ num_slots = array->num_elements;
+ slots = (cairo_user_data_slot_t *) array->elements;
+ for (i = 0; i < num_slots; i++) {
+ if (slots[i].key == key) {
+ if (slots[i].user_data != NULL && slots[i].destroy != NULL)
+ slots[i].destroy (slots[i].user_data);
+ s = &slots[i];
+ break;
+ }
+ if (user_data && slots[i].user_data == NULL) {
+ s = &slots[i]; /* Have to keep searching for an exact match */
+ }
+ }
+
+ if (user_data == NULL) {
+ if (s != NULL) {
+ s->key = NULL;
+ s->user_data = NULL;
+ s->destroy = NULL;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+
+ } else {
+ if (s == NULL)
+ s = _cairo_array_append (array, NULL, 1);
+ if (s == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ s->key = key;
+ s->user_data = user_data;
+ s->destroy = destroy;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c
index cb4b1c5d7..a279956df 100644
--- a/src/cairo-atsui-font.c
+++ b/src/cairo-atsui-font.c
@@ -30,778 +30,661 @@
* The Initial Developer of the Original Code is Calum Robinson
*
* Contributor(s):
- * Calum Robinson <calumr@mac.com>
+ * Calum Robinson <calumr@mac.com>
*/
#include <stdlib.h>
#include <math.h>
-
#include "cairo-atsui.h"
#include "cairoint.h"
+#include "cairo.h"
+#include <iconv.h>
+typedef struct {
+ cairo_scaled_font_t base;
+ cairo_matrix_t scale;
+ ATSUStyle style;
+ ATSUStyle unscaled_style;
+ ATSUFontID fontID;
+} cairo_atsui_font_t;
+typedef struct cairo_ATSUI_glyph_path_callback_info_t {
+ cairo_path_fixed_t *path;
+ cairo_matrix_t scale;
+} cairo_ATSUI_glyph_path_callback_info_t;
+const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend;
-#pragma mark Types
+static CGAffineTransform
+CGAffineTransformMakeWithCairoFontScale(cairo_matrix_t *scale)
+{
+ return CGAffineTransformMake(scale->xx, scale->yx,
+ scale->xy, scale->yy,
+ 0, 0);
+}
+static ATSUStyle
+CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_matrix_t *scale)
+{
+ ATSUStyle style;
+ OSStatus err;
-typedef struct {
- cairo_unscaled_font_t base;
-
- ATSUStyle style;
- ATSUFontID fontID;
-} cairo_atsui_font_t;
+ // 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);
-typedef struct cairo_ATSUI_glyph_path_callback_info_t {
- cairo_path_t *path;
- cairo_matrix_t scale;
-} cairo_ATSUI_glyph_path_callback_info_t;
+ err = ATSUSetAttributes(style,
+ sizeof(theFontStyleTags) /
+ sizeof(ATSUAttributeTag), theFontStyleTags,
+ theFontStyleSizes, theFontStyleValues);
+ return style;
+}
+static cairo_status_t
+_cairo_atsui_font_create(const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **font_out)
+{
+ cairo_atsui_font_t *font = NULL;
+ ATSUStyle style;
+ ATSUFontID fontID;
+ OSStatus err;
+ Boolean isItalic, isBold;
+ cairo_matrix_t scale;
+
+ 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);
+
+ if (err != noErr) {
+ // couldn't get the font - remap css names and try again
+
+ if (!strcmp(family, "serif"))
+ family = "Times";
+ else if (!strcmp(family, "sans-serif"))
+ family = "Helvetica";
+ else if (!strcmp(family, "cursive"))
+ family = "Apple Chancery";
+ else if (!strcmp(family, "fantasy"))
+ family = "Gadget";
+ else if (!strcmp(family, "monospace"))
+ family = "Courier";
+ else // anything else - return error instead?
+ family = "Courier";
+
+ 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));
+
+ _cairo_scaled_font_init(&font->base, font_matrix, ctm,
+ &cairo_atsui_scaled_font_backend);
+
+ cairo_matrix_multiply(&scale, font_matrix, ctm);
+ font->style = CreateSizedCopyOfStyle(style, &scale);
+
+ Fixed theSize = FloatToFixed(1.0);
+ const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag };
+ const ByteCount theFontStyleSizes[] = { sizeof(Fixed) };
+ ATSUAttributeValuePtr theFontStyleValues[] = { &theSize };
+ err = ATSUSetAttributes(style,
+ sizeof(theFontStyleTags) /
+ sizeof(ATSUAttributeTag), theFontStyleTags,
+ theFontStyleSizes, theFontStyleValues);
+
+ font->unscaled_style = style;
+
+ font->fontID = fontID;
+ font->scale = scale;
+
+ *font_out = &font->base;
+
+ return CAIRO_STATUS_SUCCESS;
+}
-#pragma mark Private Functions
+static void
+_cairo_atsui_font_destroy_font(void *abstract_font)
+{
+ cairo_atsui_font_t *font = abstract_font;
+ if (font == NULL)
+ return;
+ if (font->style)
+ ATSUDisposeStyle(font->style);
+ if (font->unscaled_style)
+ ATSUDisposeStyle(font->unscaled_style);
+}
-static CGAffineTransform CGAffineTransformMakeWithCairoFontScale(cairo_font_scale_t scale)
+static void
+_cairo_atsui_font_get_glyph_cache_key(void *abstract_font,
+ cairo_glyph_cache_key_t *key)
{
- 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)
+static cairo_status_t
+_cairo_atsui_font_text_to_glyphs(void *abstract_font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
{
- 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;
-}
+ cairo_atsui_font_t *font = abstract_font;
+ size_t i;
+ OSStatus err;
+ ATSUTextLayout textLayout;
+ ATSLayoutRecord *layoutRecords;
+ ItemCount glyphCount, charCount;
+ UniChar *theText;
+ err = ATSUCreateTextLayout(&textLayout);
+#if 1
+ charCount = strlen(utf8);
+ // 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];
+ }
+#endif
-#pragma mark Public Functions
+#if 0
+ // Set the text in the text layout object, so we can measure it
+ charCount = strlen(utf8);
+ theText = (UniChar *) malloc(charCount * sizeof(UniChar));
+ size_t inBytes = charCount, outBytes = charCount;
+ iconv_t converter = iconv_open("UTF-8", "UTF-16");
+ charCount = iconv(converter, utf8, &inBytes, theText, &outBytes);
+#endif
+ err = ATSUSetTextPointerLocation(textLayout,
+ theText, 0, charCount, charCount);
+ // Set the style for all of the text
+ err = ATSUSetRunStyle(textLayout,
+ font->unscaled_style, kATSUFromTextBeginning, kATSUToTextEnd);
-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;
-}
+ // Get the glyphs from the text layout object
+ err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout,
+ 0,
+ kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
+ (void *)
+ &layoutRecords,
+ &glyphCount);
+ *num_glyphs = glyphCount - 1;
-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);
-}
+ *glyphs =
+ (cairo_glyph_t *) malloc(*num_glyphs * (sizeof(cairo_glyph_t)));
+ if (*glyphs == NULL) {
+ return CAIRO_STATUS_NO_MEMORY;
+ }
-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;
+ for (i = 0; i < *num_glyphs; 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);
+
+ 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)
+static cairo_status_t
+_cairo_atsui_font_font_extents(void *abstract_font,
+ 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;
+ 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)
+static cairo_status_t
+_cairo_atsui_font_glyph_extents(void *abstract_font,
+ 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;
+ cairo_atsui_font_t *font = abstract_font;
+ OSStatus err;
+
+ assert(num_glyphs == 1);
+
+ GlyphID theGlyph = glyphs[0].index;
+
+ ATSGlyphIdealMetrics metricsH, metricsV;
+ ATSUStyle style;
+
+ ATSUCreateAndCopyStyle(font->unscaled_style, &style);
+
+ err = ATSUGlyphGetIdealMetrics(style,
+ 1, &theGlyph, 0, &metricsH);
+
+ ATSUVerticalCharacterType verticalType = kATSUStronglyVertical;
+ const ATSUAttributeTag theTag[] = { kATSUVerticalCharacterTag };
+ const ByteCount theSizes[] = { sizeof(verticalType) };
+ ATSUAttributeValuePtr theValues[] = { &verticalType };
+
+ err = ATSUSetAttributes(style, 1, theTag, theSizes, theValues);
+
+ err = ATSUGlyphGetIdealMetrics(style,
+ 1, &theGlyph, 0, &metricsV);
+
+ extents->x_bearing = metricsH.sideBearing.x;
+ extents->y_bearing = metricsV.advance.y;
+ extents->width =
+ metricsH.advance.x - metricsH.sideBearing.x - metricsH.otherSideBearing.x;
+ extents->height =
+ -metricsV.advance.y - metricsV.sideBearing.y - metricsV.otherSideBearing.y;
+ extents->x_advance = metricsH.advance.x;
+ extents->y_advance = 0;
+
+ ATSUDisposeStyle(style);
+
+ 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)
+static cairo_status_t
+_cairo_atsui_font_glyph_bbox(void *abstract_font,
+ 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;
+ cairo_atsui_font_t *font = abstract_font;
+ 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;
+
+
+ for (i = 0; i < num_glyphs; i++) {
+ GlyphID theGlyph = glyphs[i].index;
+
+ ATSGlyphScreenMetrics metrics;
+ ATSUGlyphGetScreenMetrics(font->style,
+ 1, &theGlyph, 0, true, true, &metrics);
+
+ x1 = _cairo_fixed_from_double(glyphs[i].x + metrics.topLeft.x);
+ y1 = _cairo_fixed_from_double(glyphs[i].y - metrics.topLeft.y);
+ x2 = x1 + _cairo_fixed_from_double(metrics.height);
+ y2 = y1 + _cairo_fixed_from_double(metrics.width);
+
+ 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;
+ }
+
+ 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)
+static cairo_status_t
+_cairo_atsui_font_show_glyphs(void *abstract_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *generic_surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
{
- cairo_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
+ cairo_atsui_font_t *font = abstract_font;
+ CGContextRef myBitmapContext;
+ CGColorSpaceRef colorSpace;
+ cairo_image_surface_t *destImageSurface;
+ int i;
+
+ cairo_rectangle_t rect = {dest_x, dest_y, width, height};
+ _cairo_surface_acquire_dest_image(generic_surface,
+ &rect,
+ &destImageSurface,
+ &rect,
+ NULL);
+
+ // 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;
-}
+ myBitmapContext = CGBitmapContextCreate(destImageSurface->data,
+ destImageSurface->width,
+ destImageSurface->height,
+ destImageSurface->depth / 4,
+ destImageSurface->stride,
+ colorSpace,
+ kCGImageAlphaPremultipliedFirst);
+ CGContextTranslateCTM(myBitmapContext, 0, destImageSurface->height);
+ CGContextScaleCTM(myBitmapContext, 1.0f, -1.0f);
+
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(font->fontID);
+ CGFontRef cgFont = CGFontCreateWithPlatformFont(&atsFont);
+
+ CGContextSetFont(myBitmapContext, cgFont);
+
+ CGAffineTransform textTransform =
+ CGAffineTransformMakeWithCairoFontScale(&font->scale);
+
+ textTransform = CGAffineTransformScale(textTransform, 1.0f, -1.0f);
+
+ CGContextSetFontSize(myBitmapContext, 1.0);
+ CGContextSetTextMatrix(myBitmapContext, textTransform);
+
+ if (pattern->type == CAIRO_PATTERN_SOLID &&
+ _cairo_pattern_is_opaque_solid(pattern)) {
+ cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *)pattern;
+ CGContextSetRGBFillColor(myBitmapContext,
+ solid->color.red,
+ solid->color.green,
+ solid->color.blue, 1.0f);
+ } else
+ CGContextSetRGBFillColor(myBitmapContext, 0.0f, 0.0f, 0.0f, 0.0f);
+
+ // 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,
+ glyphs[i].x,
+ glyphs[i].y,
+ &theGlyph, 1);
+ }
+
+
+ CGColorSpaceRelease(colorSpace);
+ CGContextRelease(myBitmapContext);
-#pragma mark -
+ _cairo_surface_release_dest_image(generic_surface,
+ &rect,
+ destImageSurface,
+ &rect,
+ NULL);
+
+ return CAIRO_STATUS_SUCCESS;
+}
-static OSStatus MyATSCubicMoveToCallback(const Float32Point *pt, void *callBackDataPtr)
+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);
-
-
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ double scaledPt[2];
+ cairo_fixed_t x, y;
+
+ scaledPt[0] = pt->x;
+ scaledPt[1] = pt->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ x = _cairo_fixed_from_double(scaledPt[0]);
+ y = _cairo_fixed_from_double(scaledPt[1]);
+
+ _cairo_path_fixed_close_path(info->path);
+ _cairo_path_fixed_move_to(info->path, x, y);
+
return noErr;
}
-static OSStatus MyATSCubicLineToCallback(const Float32Point *pt, void *callBackDataPtr)
+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;
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ double scaledPt[2];
+ cairo_fixed_t x, y;
+
+ scaledPt[0] = pt->x;
+ scaledPt[1] = pt->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ x = _cairo_fixed_from_double(scaledPt[0]);
+ y = _cairo_fixed_from_double(scaledPt[1]);
+
+ _cairo_path_fixed_line_to(info->path, x, y);
+
+
+ return noErr;
}
-static OSStatus MyATSCubicCurveToCallback( const Float32Point *pt1,
- const Float32Point *pt2,
- const Float32Point *pt3,
- void *callBackDataPtr)
+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]);
-
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
+ double scaledPt[2];
+ cairo_fixed_t x0, y0;
+ cairo_fixed_t x1, y1;
+ cairo_fixed_t x2, y2;
+
+
+ scaledPt[0] = pt1->x;
+ scaledPt[1] = pt1->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ x0 = _cairo_fixed_from_double(scaledPt[0]);
+ y0 = _cairo_fixed_from_double(scaledPt[1]);
+
scaledPt[0] = pt2->x;
- scaledPt[1] = pt2->y;
-
- cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+ scaledPt[1] = pt2->y;
+
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
+
+ x1 = _cairo_fixed_from_double(scaledPt[0]);
+ y1 = _cairo_fixed_from_double(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]);
+ scaledPt[1] = pt3->y;
- p2.x = _cairo_fixed_from_double(scaledPt[0]);
- p2.y = _cairo_fixed_from_double(scaledPt[1]);
-
+ cairo_matrix_transform_point(&info->scale, &scaledPt[0], &scaledPt[1]);
- _cairo_path_curve_to(info->path, &p0, &p1, &p2);
-
-
- return noErr;
-}
+ x2 = _cairo_fixed_from_double(scaledPt[0]);
+ y2 = _cairo_fixed_from_double(scaledPt[1]);
-static OSStatus MyCubicClosePathProc(void * callBackDataPtr)
-{
- cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
-
-
- _cairo_path_close_path(info->path);
-
-
- return noErr;
+ _cairo_path_fixed_curve_to(info->path, x0, y0, x1, y1, x2, y2);
+
+
+ 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)
+static OSStatus MyCubicClosePathProc(void *callBackDataPtr)
{
- 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;
-}
+ cairo_ATSUI_glyph_path_callback_info_t *info = callBackDataPtr;
-#pragma mark -
+ _cairo_path_fixed_close_path(info->path);
-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;
+ return noErr;
}
-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;
-}
+static cairo_status_t
+_cairo_atsui_font_glyph_path(void *abstract_font,
+ cairo_glyph_t *glyphs, int num_glyphs,
+ cairo_path_fixed_t *path)
+{
+ int i;
+ cairo_atsui_font_t *font = abstract_font;
+ OSStatus err;
+ cairo_ATSUI_glyph_path_callback_info_t info;
+ 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);
+ }
-#pragma mark Backend
+ info.path = path;
+ for (i = 0; i < num_glyphs; i++) {
+ GlyphID theGlyph = glyphs[i].index;
-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
+ cairo_matrix_init(&info.scale,
+ 1.0, 0.0,
+ 0.0, 1.0, glyphs[i].x, glyphs[i].y);
+
+
+ err = ATSUGlyphGetCubicPaths(font->style,
+ theGlyph,
+ moveProc,
+ lineProc,
+ curveProc,
+ closePathProc, (void *) &info, &err);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = {
+ _cairo_atsui_font_create,
+ _cairo_atsui_font_destroy_font,
+ _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_get_glyph_cache_key,
};
+
diff --git a/src/cairo-atsui.h b/src/cairo-atsui.h
index a5b7308f8..72e2d6d15 100644
--- a/src/cairo-atsui.h
+++ b/src/cairo-atsui.h
@@ -38,7 +38,7 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_ATSUI_FONT
+#if CAIRO_HAS_ATSUI_FONT
/* ATSUI platform-specific font interface */
@@ -46,10 +46,10 @@
CAIRO_BEGIN_DECLS
-cairo_font_t *
-cairo_atsui_font_create(ATSUStyle style);
-
CAIRO_END_DECLS
+#else /* CAIRO_HAS_ATSUI_FONT */
+# error Cairo was not compiled with support for the atsui font backend
#endif /* CAIRO_HAS_ATSUI_FONT */
+
#endif /* CAIRO_ATSUI_H */
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index d1ad5a4e2..e95894960 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -113,7 +113,9 @@ static const cairo_cache_arrangement_t cache_arrangements [] = {
#define LIVE_ENTRY_P(cache, i) \
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
-#ifdef CAIRO_DO_SANITY_CHECKING
+#ifdef NDEBUG
+#define _cache_sane_state(c)
+#else
static void
_cache_sane_state (cairo_cache_t *cache)
{
@@ -125,8 +127,6 @@ _cache_sane_state (cairo_cache_t *cache)
/* assert (cache->used_memory <= cache->max_memory); */
assert (cache->live_entries <= cache->arrangement->size);
}
-#else
-#define _cache_sane_state(c)
#endif
static void
@@ -351,8 +351,9 @@ _cairo_cache_init (cairo_cache_t *cache,
#endif
cache->backend = backend;
- cache->entries = calloc (sizeof(cairo_cache_entry_base_t *),
- cache->arrangement->size);
+ cache->entries = calloc (cache->arrangement->size,
+ sizeof(cairo_cache_entry_base_t *));
+
if (cache->entries == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
diff --git a/src/cairo-color.c b/src/cairo-color.c
index f203d96cc..beb4a3474 100644
--- a/src/cairo-color.c
+++ b/src/cairo-color.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -36,62 +37,127 @@
#include "cairoint.h"
-static cairo_color_t const CAIRO_COLOR_WHITE = {
- 1.0, 1.0, 1.0, 1.0,
+static cairo_color_t const cairo_color_white = {
+ 1.0, 1.0, 1.0, 1.0,
0xffff, 0xffff, 0xffff, 0xffff
};
-static void
-_cairo_color_compute_shorts (cairo_color_t *color);
+static cairo_color_t const cairo_color_black = {
+ 0.0, 0.0, 0.0, 1.0,
+ 0x0, 0x0, 0x0, 0xffff
+};
+
+static cairo_color_t const cairo_color_transparent = {
+ 0.0, 0.0, 0.0, 0.0,
+ 0x0, 0x0, 0x0, 0x0
+};
+
+static cairo_color_t const cairo_color_magenta = {
+ 1.0, 0.0, 1.0, 1.0,
+ 0xffff, 0x0, 0xffff, 0xffff
+};
+
+const cairo_color_t *
+_cairo_stock_color (cairo_stock_t stock)
+{
+ switch (stock) {
+ case CAIRO_STOCK_WHITE:
+ return &cairo_color_white;
+ case CAIRO_STOCK_BLACK:
+ return &cairo_color_black;
+ case CAIRO_STOCK_TRANSPARENT:
+ return &cairo_color_transparent;
+ }
+
+ ASSERT_NOT_REACHED;
+
+ /* If the user can get here somehow, give a color that indicates a
+ * problem. */
+ return &cairo_color_magenta;
+}
void
_cairo_color_init (cairo_color_t *color)
{
- *color = CAIRO_COLOR_WHITE;
+ *color = cairo_color_white;
}
void
-_cairo_color_fini (cairo_color_t *color)
+_cairo_color_init_rgb (cairo_color_t *color,
+ double red, double green, double blue)
{
- /* Nothing to do here */
+ _cairo_color_init_rgba (color, red, green, blue, 1.0);
+}
+
+
+/* XXX: The calculation of:
+
+ channel * 0xffff
+
+ isn't really what we want since:
+
+ (1.0 - epsilon) * 0xffff = 0xfffe
+
+ In other words, given an input range of [0.0, 1.0], we have an
+ infinitely small range tha maps to the output value 0xffff,
+ (while having large, uniformly sized input ranges for all
+ other output values). This is undesirable, particularly when
+ we want to do optimizations for "opaque" colors specfied as
+ floating-point.
+*/
+static void
+_cairo_color_compute_shorts (cairo_color_t *color)
+{
+ color->red_short = color->red * color->alpha * 0xffff;
+ color->green_short = color->green * color->alpha * 0xffff;
+ color->blue_short = color->blue * color->alpha * 0xffff;
+ color->alpha_short = color->alpha * 0xffff;
}
void
-_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue)
+_cairo_color_init_rgba (cairo_color_t *color,
+ double red, double green, double blue,
+ double alpha)
{
color->red = red;
color->green = green;
color->blue = blue;
+ color->alpha = alpha;
_cairo_color_compute_shorts (color);
}
void
-_cairo_color_get_rgb (const cairo_color_t *color,
- double *red, double *green, double *blue)
+_cairo_color_multiply_alpha (cairo_color_t *color,
+ double alpha)
{
- if (red)
- *red = color->red;
- if (green)
- *green = color->green;
- if (blue)
- *blue = color->blue;
+ color->alpha *= alpha;
+
+ _cairo_color_compute_shorts (color);
}
void
-_cairo_color_set_alpha (cairo_color_t *color, double alpha)
+_cairo_color_get_rgba (cairo_color_t *color,
+ double *red,
+ double *green,
+ double *blue,
+ double *alpha)
{
- color->alpha = alpha;
-
- _cairo_color_compute_shorts (color);
+ *red = color->red;
+ *green = color->green;
+ *blue = color->blue;
+ *alpha = color->alpha;
}
-static void
-_cairo_color_compute_shorts (cairo_color_t *color)
+void
+_cairo_color_get_rgba_premultiplied (cairo_color_t *color,
+ double *red,
+ double *green,
+ double *blue,
+ double *alpha)
{
- color->red_short = (color->red * color->alpha) * 0xffff;
- color->green_short = (color->green * color->alpha) * 0xffff;
- color->blue_short = (color->blue * color->alpha) * 0xffff;
- color->alpha_short = color->alpha * 0xffff;
+ *red = color->red * color->alpha;
+ *green = color->green * color->alpha;
+ *blue = color->blue * color->alpha;
+ *alpha = color->alpha;
}
-
diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in
index a13250d97..8065be352 100644
--- a/src/cairo-features.h.in
+++ b/src/cairo-features.h.in
@@ -37,28 +37,26 @@
#ifndef CAIRO_FEATURES_H
#define CAIRO_FEATURES_H
-#define @PS_SURFACE_FEATURE@
+@PS_SURFACE_FEATURE@
-#define @PDF_SURFACE_FEATURE@
+@PDF_SURFACE_FEATURE@
-#define @PNG_SURFACE_FEATURE@
+@XLIB_SURFACE_FEATURE@
-#define @XLIB_SURFACE_FEATURE@
+@QUARTZ_SURFACE_FEATURE@
-#define @QUARTZ_SURFACE_FEATURE@
+@XCB_SURFACE_FEATURE@
-#define @XCB_SURFACE_FEATURE@
+@WIN32_SURFACE_FEATURE@
-#define @WIN32_SURFACE_FEATURE@
+@GLITZ_SURFACE_FEATURE@
-#define @GLITZ_SURFACE_FEATURE@
+@FT_FONT_FEATURE@
-#define @FT_FONT_FEATURE@
+@WIN32_FONT_FEATURE@
-#define @WIN32_FONT_FEATURE@
+@ATSUI_FONT_FEATURE@
-#define @ATSUI_FONT_FEATURE@
-
-#define @SANITY_CHECKING_FEATURE@
+@PNG_FUNCTIONS_FEATURE@
#endif
diff --git a/src/cairo-font.c b/src/cairo-font.c
index 529c1c7c3..3bd1e0318 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -39,185 +39,906 @@
#include "cairoint.h"
-/* Now the internal "unscaled + scale" font API */
+/* cairo_font_face_t */
-cairo_private cairo_status_t
-_cairo_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *sc,
- cairo_font_t **font)
+void
+_cairo_font_face_init (cairo_font_face_t *font_face,
+ const cairo_font_face_backend_t *backend)
{
- const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
+ font_face->refcount = 1;
+ font_face->backend = backend;
- return backend->create (family, slant, weight, sc, font);
+ _cairo_user_data_array_init (&font_face->user_data);
}
+/**
+ * cairo_font_face_reference:
+ * @font_face: a #cairo_font_face_t
+ *
+ * Increases the reference count on @font_face by one. This prevents
+ * @font_face from being destroyed until a matching call to cairo_font_face_destroy()
+ * is made.
+ **/
void
-_cairo_font_init (cairo_font_t *font,
- cairo_font_scale_t *scale,
- const cairo_font_backend_t *backend)
+cairo_font_face_reference (cairo_font_face_t *font_face)
{
- font->scale = *scale;
- font->refcount = 1;
- font->backend = backend;
+ font_face->refcount++;
}
+/**
+ * cairo_font_face_destroy:
+ * @font_face: a #cairo_font_face_t
+ *
+ * Decreases the reference count on @font_face by one. If the result
+ * is zero, then @font_face and all associated resources are freed.
+ * See cairo_font_face_reference().
+ **/
void
-_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const cairo_font_backend_t *backend)
+cairo_font_face_destroy (cairo_font_face_t *font_face)
{
- font->refcount = 1;
- font->backend = backend;
+ if (--(font_face->refcount) > 0)
+ return;
+
+ font_face->backend->destroy (font_face);
+
+ /* We allow resurrection to deal with some memory management for the
+ * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
+ * need to effectively mutually reference each other
+ */
+ if (font_face->refcount > 0)
+ return;
+
+ _cairo_user_data_array_destroy (&font_face->user_data);
+
+ free (font_face);
}
+/**
+ * cairo_font_face_get_user_data:
+ * @font_face: a #cairo_font_face_t
+ * @key: the address of the #cairo_user_data_key_t the user data was
+ * attached to
+ *
+ * Return user data previously attached to @font_face using the specified
+ * key. If no user data has been attached with the given key this
+ * function returns %NULL.
+ *
+ * Return value: the user data previously attached or %NULL.
+ **/
+void *
+cairo_font_face_get_user_data (cairo_font_face_t *font_face,
+ const cairo_user_data_key_t *key)
+{
+ return _cairo_user_data_array_get_data (&font_face->user_data,
+ key);
+}
+
+/**
+ * cairo_font_face_set_user_data:
+ * @font_face: a #cairo_font_face_t
+ * @key: the address of a #cairo_user_data_key_t to attach the user data to
+ * @user_data: the user data to attach to the font face
+ * @destroy: a #cairo_destroy_func_t which will be called when the
+ * font face is destroyed or when new user data is attached using the
+ * same key.
+ *
+ * Attach user data to @font_face. To remove user data from a font face,
+ * call this function with the key that was used to set it and %NULL
+ * for @data.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
+ * slot could not be allocated for the user data.
+ **/
cairo_status_t
-_cairo_font_text_to_glyphs (cairo_font_t *font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
+cairo_font_face_set_user_data (cairo_font_face_t *font_face,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy)
+{
+ return _cairo_user_data_array_set_data (&font_face->user_data,
+ key, user_data, destroy);
+}
+
+/* cairo_simple_font_face_t - simple family/slant/weight font faces used for
+ * the built-in font API
+ */
+
+typedef struct _cairo_simple_font_face cairo_simple_font_face_t;
+
+struct _cairo_simple_font_face {
+ cairo_font_face_t base;
+ char *family;
+ cairo_font_slant_t slant;
+ cairo_font_weight_t weight;
+};
+
+static const cairo_font_face_backend_t _cairo_simple_font_face_backend;
+
+/* We maintain a global cache from family/weight/slant => cairo_font_face_t
+ * for cairo_simple_font_t. The primary purpose of this cache is to provide
+ * unique cairo_font_face_t values so that our cache from
+ * cairo_font_face_t => cairo_scaled_font_t works. For this reason, we don't need
+ * this cache to keep font faces alive; we just add them to the cache and
+ * remove them again when freed.
+ */
+
+typedef struct {
+ cairo_cache_entry_base_t base;
+ const char *family;
+ cairo_font_slant_t slant;
+ cairo_font_weight_t weight;
+} cairo_simple_cache_key_t;
+
+typedef struct {
+ cairo_simple_cache_key_t key;
+ cairo_simple_font_face_t *font_face;
+} cairo_simple_cache_entry_t;
+
+static const cairo_cache_backend_t _cairo_simple_font_cache_backend;
+
+static void
+_lock_global_simple_cache (void)
+{
+ /* FIXME: Perform locking here. */
+}
+
+static void
+_unlock_global_simple_cache (void)
{
- return font->backend->text_to_glyphs (font, utf8, glyphs, num_glyphs);
+ /* FIXME: Perform locking here. */
+}
+
+static cairo_cache_t *
+_get_global_simple_cache (void)
+{
+ static cairo_cache_t *global_simple_cache = NULL;
+
+ if (global_simple_cache == NULL)
+ {
+ global_simple_cache = malloc (sizeof (cairo_cache_t));
+ if (!global_simple_cache)
+ goto FAIL;
+
+ if (_cairo_cache_init (global_simple_cache,
+ &_cairo_simple_font_cache_backend,
+ 0)) /* No memory limit */
+ goto FAIL;
+ }
+ return global_simple_cache;
+
+ FAIL:
+ if (global_simple_cache)
+ free (global_simple_cache);
+ global_simple_cache = NULL;
+ return NULL;
+}
+
+static unsigned long
+_cairo_simple_font_cache_hash (void *cache, void *key)
+{
+ cairo_simple_cache_key_t *k = (cairo_simple_cache_key_t *) key;
+ unsigned long hash;
+
+ /* 1607 and 1451 are just a couple random primes. */
+ hash = _cairo_hash_string (k->family);
+ hash += ((unsigned long) k->slant) * 1607;
+ hash += ((unsigned long) k->weight) * 1451;
+
+ return hash;
+}
+
+static int
+_cairo_simple_font_cache_keys_equal (void *cache,
+ void *k1,
+ void *k2)
+{
+ cairo_simple_cache_key_t *a;
+ cairo_simple_cache_key_t *b;
+ a = (cairo_simple_cache_key_t *) k1;
+ b = (cairo_simple_cache_key_t *) k2;
+
+ return strcmp (a->family, b->family) == 0 &&
+ a->slant == b->slant &&
+ a->weight == b->weight;
+}
+
+static cairo_simple_font_face_t *
+_cairo_simple_font_face_create_from_cache_key (cairo_simple_cache_key_t *key)
+{
+ cairo_simple_font_face_t *simple_face;
+
+ simple_face = malloc (sizeof (cairo_simple_font_face_t));
+ if (!simple_face)
+ return NULL;
+
+ simple_face->family = strdup (key->family);
+ if (!simple_face->family) {
+ free (simple_face);
+ return NULL;
+ }
+
+ simple_face->slant = key->slant;
+ simple_face->weight = key->weight;
+
+ _cairo_font_face_init (&simple_face->base, &_cairo_simple_font_face_backend);
+
+ return simple_face;
+}
+
+static cairo_status_t
+_cairo_simple_font_cache_create_entry (void *cache,
+ void *key,
+ void **return_entry)
+{
+ cairo_simple_cache_key_t *k = (cairo_simple_cache_key_t *) key;
+ cairo_simple_cache_entry_t *entry;
+
+ entry = malloc (sizeof (cairo_simple_cache_entry_t));
+ if (entry == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ entry->font_face = _cairo_simple_font_face_create_from_cache_key (k);
+ if (!entry->font_face) {
+ free (entry);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ entry->key.base.memory = 0;
+ entry->key.family = entry->font_face->family;
+ entry->key.slant = entry->font_face->slant;
+ entry->key.weight = entry->font_face->weight;
+
+ *return_entry = entry;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Entries are never spontaneously destroyed; but only when
+ * we remove them from the cache specifically. We free entry->font_face
+ * in the code that removes the entry from the cache
+ */
+static void
+_cairo_simple_font_cache_destroy_entry (void *cache,
+ void *entry)
+{
+ cairo_simple_cache_entry_t *e = (cairo_simple_cache_entry_t *) entry;
+
+ free (e);
+}
+
+static void
+_cairo_simple_font_cache_destroy_cache (void *cache)
+{
+ free (cache);
+}
+
+static const cairo_cache_backend_t _cairo_simple_font_cache_backend = {
+ _cairo_simple_font_cache_hash,
+ _cairo_simple_font_cache_keys_equal,
+ _cairo_simple_font_cache_create_entry,
+ _cairo_simple_font_cache_destroy_entry,
+ _cairo_simple_font_cache_destroy_cache
+};
+
+static void
+_cairo_simple_font_face_destroy (void *abstract_face)
+{
+ cairo_simple_font_face_t *simple_face = abstract_face;
+ cairo_cache_t *cache;
+ cairo_simple_cache_key_t key;
+
+ _lock_global_simple_cache ();
+ cache = _get_global_simple_cache ();
+ assert (cache);
+
+ key.family = simple_face->family;
+ key.slant = simple_face->slant;
+ key.weight = simple_face->weight;
+
+ _cairo_cache_remove (cache, &key);
+
+ _unlock_global_simple_cache ();
+
+ free (simple_face->family);
+}
+
+static cairo_status_t
+_cairo_simple_font_face_create_font (void *abstract_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **scaled_font)
+{
+ const cairo_scaled_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
+ cairo_simple_font_face_t *simple_face = abstract_face;
+
+ return backend->create (simple_face->family, simple_face->slant, simple_face->weight,
+ font_matrix, ctm, scaled_font);
+}
+
+static const cairo_font_face_backend_t _cairo_simple_font_face_backend = {
+ _cairo_simple_font_face_destroy,
+ _cairo_simple_font_face_create_font,
+};
+
+/**
+ * _cairo_simple_font_face_create:
+ * @family: a font family name, encoded in UTF-8
+ * @slant: the slant for the font
+ * @weight: the weight for the font
+ *
+ * Creates a font face from a triplet of family, slant, and weight.
+ * These font faces are used in implementation of the the #cairo_t "toy"
+ * font API.
+ *
+ * Return value: a newly created #cairo_font_face_t, destroy with
+ * cairo_font_face_destroy()
+ **/
+cairo_private cairo_font_face_t *
+_cairo_simple_font_face_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight)
+{
+ cairo_simple_cache_entry_t *entry;
+ cairo_simple_cache_key_t key;
+ cairo_cache_t *cache;
+ cairo_status_t status;
+ cairo_bool_t created_entry;
+
+ key.family = family;
+ key.slant = slant;
+ key.weight = weight;
+
+ _lock_global_simple_cache ();
+ cache = _get_global_simple_cache ();
+ if (cache == NULL) {
+ _unlock_global_simple_cache ();
+ return NULL;
+ }
+ status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry);
+ if (CAIRO_OK (status) && !created_entry)
+ cairo_font_face_reference (&entry->font_face->base);
+
+ _unlock_global_simple_cache ();
+ if (status)
+ return NULL;
+
+ return &entry->font_face->base;
+}
+
+/* cairo_scaled_font_t */
+
+/* Here we keep a cache from cairo_font_face_t/matrix/ctm => cairo_scaled_font_t.
+ *
+ * The implementation is messy because we want
+ *
+ * - All otherwise referenced cairo_scaled_font_t's to be in the cache
+ * - Some number of not otherwise referenced cairo_scaled_font_t's
+ *
+ * For this reason, we actually use *two* caches ... a finite size
+ * cache that references the cairo_scaled_font_t as a first level (the outer
+ * cache), then an infinite size cache as the second level (the inner
+ * cache). A single cache could be used at the cost of complicating
+ * cairo-cache.c
+ */
+
+/* This defines the size of the outer cache ... that is, the number
+ * of scaled fonts we keep around even when not otherwise referenced
+ */
+#define MAX_CACHED_FONTS 24
+
+typedef struct {
+ cairo_cache_entry_base_t base;
+ cairo_font_face_t *font_face;
+ const cairo_matrix_t *font_matrix;
+ const cairo_matrix_t *ctm;
+} cairo_font_cache_key_t;
+
+typedef struct {
+ cairo_font_cache_key_t key;
+ cairo_scaled_font_t *scaled_font;
+} cairo_font_cache_entry_t;
+
+static const cairo_cache_backend_t _cairo_outer_font_cache_backend;
+static const cairo_cache_backend_t _cairo_inner_font_cache_backend;
+
+static void
+_lock_global_font_cache (void)
+{
+ /* FIXME: Perform locking here. */
+}
+
+static void
+_unlock_global_font_cache (void)
+{
+ /* FIXME: Perform locking here. */
+}
+
+static cairo_cache_t *
+_get_outer_font_cache (void)
+{
+ static cairo_cache_t *outer_font_cache = NULL;
+
+ if (outer_font_cache == NULL)
+ {
+ outer_font_cache = malloc (sizeof (cairo_cache_t));
+ if (!outer_font_cache)
+ goto FAIL;
+
+ if (_cairo_cache_init (outer_font_cache,
+ &_cairo_outer_font_cache_backend,
+ MAX_CACHED_FONTS))
+ goto FAIL;
+ }
+ return outer_font_cache;
+
+ FAIL:
+ if (outer_font_cache)
+ free (outer_font_cache);
+ outer_font_cache = NULL;
+ return NULL;
+}
+
+static cairo_cache_t *
+_get_inner_font_cache (void)
+{
+ static cairo_cache_t *inner_font_cache = NULL;
+
+ if (inner_font_cache == NULL)
+ {
+ inner_font_cache = malloc (sizeof (cairo_cache_t));
+ if (!inner_font_cache)
+ goto FAIL;
+
+ if (_cairo_cache_init (inner_font_cache,
+ &_cairo_inner_font_cache_backend,
+ MAX_CACHED_FONTS))
+ goto FAIL;
+ }
+ return inner_font_cache;
+
+ FAIL:
+ if (inner_font_cache)
+ free (inner_font_cache);
+ inner_font_cache = NULL;
+ return NULL;
+}
+
+
+/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
+ *
+ * Not necessarily better than a lot of other hashes, but should be OK, and
+ * well tested with binary data.
+ */
+
+#define FNV_32_PRIME ((uint32_t)0x01000193)
+#define FNV1_32_INIT ((uint32_t)0x811c9dc5)
+
+static uint32_t
+_hash_bytes_fnv (unsigned char *buffer,
+ int len,
+ uint32_t hval)
+{
+ while (len--) {
+ hval *= FNV_32_PRIME;
+ hval ^= *buffer++;
+ }
+
+ return hval;
+}
+static unsigned long
+_cairo_font_cache_hash (void *cache, void *key)
+{
+ cairo_font_cache_key_t *k = (cairo_font_cache_key_t *) key;
+ uint32_t hash = FNV1_32_INIT;
+
+ /* We do a bytewise hash on the font matrices */
+ hash = _hash_bytes_fnv ((unsigned char *)(&k->font_matrix->xx),
+ sizeof(double) * 4,
+ hash);
+ hash = _hash_bytes_fnv ((unsigned char *)(&k->ctm->xx),
+ sizeof(double) * 4,
+ hash);
+
+ return hash ^ (unsigned long)k->font_face;
+}
+
+static int
+_cairo_font_cache_keys_equal (void *cache,
+ void *k1,
+ void *k2)
+{
+ cairo_font_cache_key_t *a;
+ cairo_font_cache_key_t *b;
+ a = (cairo_font_cache_key_t *) k1;
+ b = (cairo_font_cache_key_t *) k2;
+
+ return (a->font_face == b->font_face &&
+ memcmp ((unsigned char *)(&a->font_matrix->xx),
+ (unsigned char *)(&b->font_matrix->xx),
+ sizeof(double) * 4) == 0 &&
+ memcmp ((unsigned char *)(&a->ctm->xx),
+ (unsigned char *)(&b->ctm->xx),
+ sizeof(double) * 4) == 0);
+}
+
+/* The cache lookup failed in the outer cache, so we pull
+ * the font from the inner cache (if that in turns fails,
+ * it will create the font
+ */
+static cairo_status_t
+_cairo_outer_font_cache_create_entry (void *cache,
+ void *key,
+ void **return_entry)
+{
+ cairo_font_cache_entry_t *entry;
+ cairo_font_cache_entry_t *inner_entry;
+ cairo_bool_t created_entry;
+ cairo_status_t status;
+
+ entry = malloc (sizeof (cairo_font_cache_entry_t));
+ if (entry == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ cache = _get_inner_font_cache ();
+ if (cache == NULL) {
+ _unlock_global_font_cache ();
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ status = _cairo_cache_lookup (cache, key, (void **) &inner_entry, &created_entry);
+ if (!CAIRO_OK (status)) {
+ free (entry);
+ return status;
+ }
+
+ entry->scaled_font = inner_entry->scaled_font;
+ if (!created_entry)
+ cairo_scaled_font_reference (entry->scaled_font);
+
+ entry->key.base.memory = 1;
+ entry->key.font_face = entry->scaled_font->font_face;
+ entry->key.font_matrix = &entry->scaled_font->font_matrix;
+ entry->key.ctm = &entry->scaled_font->ctm;
+
+ *return_entry = entry;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_outer_font_cache_destroy_entry (void *cache,
+ void *entry)
+{
+ cairo_font_cache_entry_t *e = (cairo_font_cache_entry_t *) entry;
+
+ cairo_scaled_font_destroy (e->scaled_font);
+
+ free (e);
+}
+
+/* Called when the lookup fails in the inner cache as well; there
+ * is no existing font, so we have to create one.
+ */
+static cairo_status_t
+_cairo_inner_font_cache_create_entry (void *cache,
+ void *key,
+ void **return_entry)
+{
+ cairo_font_cache_key_t *k = (cairo_font_cache_key_t *) key;
+ cairo_font_cache_entry_t *entry;
+ cairo_status_t status;
+
+ entry = malloc (sizeof (cairo_font_cache_entry_t));
+ if (entry == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ status = k->font_face->backend->create_font (k->font_face,
+ k->font_matrix,
+ k->ctm,
+ &entry->scaled_font);
+ if (!CAIRO_OK (status)) {
+ free (entry);
+ return status;
+ }
+
+ entry->scaled_font->font_face = k->font_face;
+ cairo_font_face_reference (k->font_face);
+
+ entry->key.base.memory = 0;
+ entry->key.font_face = k->font_face;
+ entry->key.font_matrix = &entry->scaled_font->font_matrix;
+ entry->key.ctm = &entry->scaled_font->ctm;
+
+ *return_entry = entry;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Entries in the inner font cache are never spontaneously destroyed;
+ * but only when we remove them from the cache specifically. We free
+ * entry->scaled_font in the code that removes the entry from the cache
+ */
+static void
+_cairo_inner_font_cache_destroy_entry (void *cache,
+ void *entry)
+{
+ free (entry);
+}
+
+static void
+_cairo_font_cache_destroy_cache (void *cache)
+{
+ free (cache);
+}
+
+static const cairo_cache_backend_t _cairo_outer_font_cache_backend = {
+ _cairo_font_cache_hash,
+ _cairo_font_cache_keys_equal,
+ _cairo_outer_font_cache_create_entry,
+ _cairo_outer_font_cache_destroy_entry,
+ _cairo_font_cache_destroy_cache
+};
+
+static const cairo_cache_backend_t _cairo_inner_font_cache_backend = {
+ _cairo_font_cache_hash,
+ _cairo_font_cache_keys_equal,
+ _cairo_inner_font_cache_create_entry,
+ _cairo_inner_font_cache_destroy_entry,
+ _cairo_font_cache_destroy_cache
+};
+
+/**
+ * cairo_scaled_font_create:
+ * @font_face: a #cairo_font_face_t
+ * @font_matrix: font space to user space transformation matrix for the
+ * font. In the simplest case of a N point font, this matrix is
+ * just a scale by N, but it can also be used to shear the font
+ * or stretch it unequally along the two axes. See
+ * cairo_set_font_matrix().
+ * @ctm: user to device transformation matrix with which the font will
+ * be used.
+ *
+ * Creates a #cairo_scaled_font_t object from a font face and matrices that
+ * describe the size of the font and the environment in which it will
+ * be used.
+ *
+ * Return value: a newly created #cairo_scaled_font_t. Destroy with
+ * cairo_scaled_font_destroy()
+ **/
+cairo_scaled_font_t *
+cairo_scaled_font_create (cairo_font_face_t *font_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm)
+{
+ cairo_font_cache_entry_t *entry;
+ cairo_font_cache_key_t key;
+ cairo_cache_t *cache;
+ cairo_status_t status;
+
+ key.font_face = font_face;
+ key.font_matrix = font_matrix;
+ key.ctm = ctm;
+
+ _lock_global_font_cache ();
+ cache = _get_outer_font_cache ();
+ if (cache == NULL) {
+ _unlock_global_font_cache ();
+ return NULL;
+ }
+
+ status = _cairo_cache_lookup (cache, &key, (void **) &entry, NULL);
+ if (CAIRO_OK (status))
+ cairo_scaled_font_reference (entry->scaled_font);
+
+ _unlock_global_font_cache ();
+ if (!CAIRO_OK (status))
+ return NULL;
+
+ return entry->scaled_font;
+}
+
+void
+_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ const cairo_scaled_font_backend_t *backend)
+{
+ scaled_font->font_matrix = *font_matrix;
+ scaled_font->ctm = *ctm;
+ cairo_matrix_multiply (&scaled_font->scale, &scaled_font->font_matrix, &scaled_font->ctm);
+
+ scaled_font->refcount = 1;
+ scaled_font->backend = backend;
}
cairo_status_t
-_cairo_font_glyph_extents (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
+_cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
{
- return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
+ return scaled_font->backend->text_to_glyphs (scaled_font, utf8, glyphs, num_glyphs);
+}
+
+cairo_status_t
+_cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
+{
+ return scaled_font->backend->glyph_extents (scaled_font, glyphs, num_glyphs, extents);
}
cairo_status_t
-_cairo_font_glyph_bbox (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
+_cairo_scaled_font_glyph_bbox (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
{
- return font->backend->glyph_bbox (font, glyphs, num_glyphs, bbox);
+ return scaled_font->backend->glyph_bbox (scaled_font, glyphs, num_glyphs, bbox);
}
cairo_status_t
-_cairo_font_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glyph_t *glyphs,
+ int num_glyphs)
{
cairo_status_t status;
- if (surface->backend->show_glyphs != NULL) {
- status = surface->backend->show_glyphs (font, operator, pattern,
- surface,
- source_x, source_y,
- dest_x, dest_y,
- width, height,
- glyphs, num_glyphs);
- if (status == CAIRO_STATUS_SUCCESS)
- return status;
- }
+
+ status = _cairo_surface_show_glyphs (scaled_font, operator, pattern,
+ surface,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
+ glyphs, num_glyphs);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
/* Surface display routine either does not exist or failed. */
- return font->backend->show_glyphs (font, operator, pattern,
- surface,
- source_x, source_y,
- dest_x, dest_y,
- width, height,
- glyphs, num_glyphs);
+ return scaled_font->backend->show_glyphs (scaled_font, operator, pattern,
+ surface,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
+ glyphs, num_glyphs);
}
cairo_status_t
-_cairo_font_glyph_path (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
+_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path)
{
- return font->backend->glyph_path (font, glyphs, num_glyphs, path);
+ return scaled_font->backend->glyph_path (scaled_font, glyphs, num_glyphs, path);
}
void
-_cairo_font_get_glyph_cache_key (cairo_font_t *font,
- cairo_glyph_cache_key_t *key)
+_cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_cache_key_t *key)
{
- font->backend->get_glyph_cache_key (font, key);
+ scaled_font->backend->get_glyph_cache_key (scaled_font, key);
}
cairo_status_t
-_cairo_font_font_extents (cairo_font_t *font,
- cairo_font_extents_t *extents)
+_cairo_scaled_font_font_extents (cairo_scaled_font_t *scaled_font,
+ cairo_font_extents_t *extents)
{
- return font->backend->font_extents (font, extents);
+ return scaled_font->backend->font_extents (scaled_font, extents);
}
void
-_cairo_unscaled_font_reference (cairo_unscaled_font_t *font)
+_cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font,
+ const cairo_unscaled_font_backend_t *backend)
{
- font->refcount++;
+ unscaled_font->refcount = 1;
+ unscaled_font->backend = backend;
}
void
-_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font)
+_cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font)
+{
+ unscaled_font->refcount++;
+}
+
+void
+_cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
{
- if (--(font->refcount) > 0)
+ if (--(unscaled_font->refcount) > 0)
return;
- font->backend->destroy_unscaled_font (font);
+ unscaled_font->backend->destroy (unscaled_font);
+
+ free (unscaled_font);
}
/* Public font API follows. */
+/**
+ * cairo_scaled_font_reference:
+ * @scaled_font: a #cairo_scaled_font_t
+ *
+ * Increases the reference count on @scaled_font by one. This prevents
+ * @scaled_font from being destroyed until a matching call to
+ * cairo_scaled_font_destroy() is made.
+ **/
void
-cairo_font_reference (cairo_font_t *font)
+cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
{
- font->refcount++;
+ scaled_font->refcount++;
}
+/**
+ * cairo_scaled_font_destroy:
+ * @scaled_font: a #cairo_scaled_font_t
+ *
+ * Decreases the reference count on @font by one. If the result
+ * is zero, then @font and all associated resources are freed.
+ * See cairo_scaled_font_reference().
+ **/
void
-cairo_font_destroy (cairo_font_t *font)
+cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
{
- if (--(font->refcount) > 0)
+ cairo_font_cache_key_t key;
+ cairo_cache_t *cache;
+
+ if (--(scaled_font->refcount) > 0)
return;
- font->backend->destroy_font (font);
+ if (scaled_font->font_face) {
+ _lock_global_font_cache ();
+ cache = _get_inner_font_cache ();
+ assert (cache);
+
+ key.font_face = scaled_font->font_face;
+ key.font_matrix = &scaled_font->font_matrix;
+ key.ctm = &scaled_font->ctm;
+
+ _cairo_cache_remove (cache, &key);
+ _unlock_global_font_cache ();
+
+ cairo_font_face_destroy (scaled_font->font_face);
+ }
+
+ scaled_font->backend->destroy (scaled_font);
+
+ free (scaled_font);
}
/**
- * cairo_font_extents:
- * @font: a #cairo_font_t
- * @font_matrix: the font transformation for which this font was
- * created. (See cairo_transform_font()). This is needed
- * properly convert the metrics from the font into user space.
+ * cairo_scaled_font_extents:
+ * @scaled_font: a #cairo_scaled_font_t
* @extents: a #cairo_font_extents_t which to store the retrieved extents.
*
- * Gets the metrics for a #cairo_font_t.
+ * Gets the metrics for a #cairo_scaled_font_t.
*
* Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an
* error such as %CAIRO_STATUS_NO_MEMORY.
**/
cairo_status_t
-cairo_font_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_font_extents_t *extents)
+cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
+ cairo_font_extents_t *extents)
{
cairo_int_status_t status;
double font_scale_x, font_scale_y;
- status = _cairo_font_font_extents (font, extents);
+ status = _cairo_scaled_font_font_extents (scaled_font, extents);
if (!CAIRO_OK (status))
return status;
- _cairo_matrix_compute_scale_factors (font_matrix,
+ _cairo_matrix_compute_scale_factors (&scaled_font->font_matrix,
&font_scale_x, &font_scale_y,
/* XXX */ 1);
@@ -237,10 +958,7 @@ cairo_font_extents (cairo_font_t *font,
/**
* cairo_font_glyph_extents:
- * @font: a #cairo_font_t
- * @font_matrix: the font transformation for which this font was
- * created. (See cairo_transform_font()). This is needed
- * properly convert the metrics from the font into user space.
+ * @scaled_font: a #cairo_scaled_font_t
* @glyphs: an array of glyph IDs with X and Y offsets.
* @num_glyphs: the number of glyphs in the @glyphs array
* @extents: a #cairo_text_extents_t which to store the retrieved extents.
@@ -249,11 +967,10 @@ cairo_font_extents (cairo_font_t *font,
* glyphs. The X and Y offsets in @glyphs are taken from an origin of 0,0.
**/
void
-cairo_font_glyph_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
+cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_glyph_t origin_glyph;
@@ -283,9 +1000,9 @@ cairo_font_glyph_extents (cairo_font_t *font,
origin_glyph = glyphs[i];
origin_glyph.x = 0.0;
origin_glyph.y = 0.0;
- status = _cairo_font_glyph_extents (font,
- &origin_glyph, 1,
- &origin_extents);
+ status = _cairo_scaled_font_glyph_extents (scaled_font,
+ &origin_glyph, 1,
+ &origin_extents);
/*
* Transform font space metrics into user space metrics
@@ -294,7 +1011,7 @@ cairo_font_glyph_extents (cairo_font_t *font,
*/
x = origin_extents.x_bearing;
y = origin_extents.y_bearing;
- cairo_matrix_transform_point (font_matrix,
+ cairo_matrix_transform_point (&scaled_font->font_matrix,
&x, &y);
for (hm = 0.0; hm <= 1.0; hm += 1.0)
@@ -302,7 +1019,7 @@ cairo_font_glyph_extents (cairo_font_t *font,
{
x = origin_extents.x_bearing + origin_extents.width * wm;
y = origin_extents.y_bearing + origin_extents.height * hm;
- cairo_matrix_transform_point (font_matrix,
+ cairo_matrix_transform_point (&scaled_font->font_matrix,
&x, &y);
x += glyphs[i].x;
y += glyphs[i].y;
@@ -323,7 +1040,7 @@ cairo_font_glyph_extents (cairo_font_t *font,
x = origin_extents.x_advance;
y = origin_extents.y_advance;
- cairo_matrix_transform_point (font_matrix,
+ cairo_matrix_transform_point (&scaled_font->font_matrix,
&x, &y);
x_pos = glyphs[i].x + x;
y_pos = glyphs[i].y + y;
@@ -348,10 +1065,10 @@ _cairo_glyph_cache_hash (void *cache, void *key)
in = (cairo_glyph_cache_key_t *) key;
return
((unsigned long) in->unscaled)
- ^ ((unsigned long) in->scale.matrix[0][0])
- ^ ((unsigned long) in->scale.matrix[0][1])
- ^ ((unsigned long) in->scale.matrix[1][0])
- ^ ((unsigned long) in->scale.matrix[1][1])
+ ^ ((unsigned long) in->scale.xx)
+ ^ ((unsigned long) in->scale.yx)
+ ^ ((unsigned long) in->scale.xy)
+ ^ ((unsigned long) in->scale.yy)
^ (in->flags * 1451) /* 1451 is just an abitrary prime */
^ in->index;
}
@@ -367,10 +1084,10 @@ _cairo_glyph_cache_keys_equal (void *cache,
return (a->index == b->index)
&& (a->unscaled == b->unscaled)
&& (a->flags == b->flags)
- && (a->scale.matrix[0][0] == b->scale.matrix[0][0])
- && (a->scale.matrix[0][1] == b->scale.matrix[0][1])
- && (a->scale.matrix[1][0] == b->scale.matrix[1][0])
- && (a->scale.matrix[1][1] == b->scale.matrix[1][1]);
+ && (a->scale.xx == b->scale.xx)
+ && (a->scale.yx == b->scale.yx)
+ && (a->scale.xy == b->scale.xy)
+ && (a->scale.yy == b->scale.yy);
}
@@ -388,7 +1105,8 @@ _image_glyph_cache_create_entry (void *cache,
return CAIRO_STATUS_NO_MEMORY;
im->key = *k;
- status = im->key.unscaled->backend->create_glyph (im);
+ status = im->key.unscaled->backend->create_glyph (im->key.unscaled,
+ im);
if (status != CAIRO_STATUS_SUCCESS) {
free (im);
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 44e1b0e84..c02cd61e5 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -66,31 +66,42 @@ typedef struct {
/*
* We create an object that corresponds to a single font on the disk;
* (identified by a filename/id pair) these are shared between all
- * fonts using that file. For cairo_ft_font_create_for_ft_face(), we
+ * fonts using that file. For cairo_ft_scaled_font_create_for_ft_face(), we
* just create a one-off version with a permanent face value.
*/
+
+typedef struct _ft_font_face ft_font_face_t;
+
typedef struct {
cairo_unscaled_font_t base;
- int from_face; /* from cairo_ft_font_create_for_ft_face()? */
- FT_Face face; /* provided or cached face */
+ cairo_bool_t from_face; /* from cairo_ft_scaled_font_create_for_ft_face()? */
+ FT_Face face; /* provided or cached face */
/* only set if from_face is false */
- FT_Library library;
char *filename;
int id;
/* We temporarily scale the unscaled font as neede */
int have_scale;
- cairo_font_scale_t current_scale;
+ cairo_matrix_t current_scale;
double x_scale; /* Extracted X scale factor */
double y_scale; /* Extracted Y scale factor */
int lock; /* count of how many times this font has been locked */
+
+ ft_font_face_t *faces; /* Linked list of faces for this font */
} ft_unscaled_font_t;
-const cairo_font_backend_t cairo_ft_font_backend;
+struct _ft_font_face {
+ cairo_font_face_t base;
+ ft_unscaled_font_t *unscaled;
+ int load_flags;
+ ft_font_face_t *next_face;
+};
+
+const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend;
static ft_unscaled_font_t *
_ft_unscaled_font_create_from_face (FT_Face face)
@@ -102,21 +113,21 @@ _ft_unscaled_font_create_from_face (FT_Face face)
unscaled->from_face = 1;
unscaled->face = face;
- unscaled->library = NULL;
unscaled->filename = NULL;
unscaled->id = 0;
unscaled->have_scale = 0;
unscaled->lock = 0;
- _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
- &cairo_ft_font_backend);
+ unscaled->faces = NULL;
+
+ _cairo_unscaled_font_init (&unscaled->base,
+ &cairo_ft_unscaled_font_backend);
return unscaled;
}
static ft_unscaled_font_t *
-_ft_unscaled_font_create_from_filename (FT_Library library,
- const char *filename,
+_ft_unscaled_font_create_from_filename (const char *filename,
int id)
{
ft_unscaled_font_t *unscaled;
@@ -135,15 +146,16 @@ _ft_unscaled_font_create_from_filename (FT_Library library,
unscaled->from_face = 0;
unscaled->face = NULL;
- unscaled->library = library;
unscaled->filename = new_filename;
unscaled->id = id;
unscaled->have_scale = 0;
unscaled->lock = 0;
- _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
- &cairo_ft_font_backend);
+ unscaled->faces = NULL;
+
+ _cairo_unscaled_font_init (&unscaled->base,
+ &cairo_ft_unscaled_font_backend);
return unscaled;
}
@@ -204,7 +216,6 @@ _ft_font_cache_create_entry (void *cache,
void *key,
void **return_entry)
{
- ft_cache_t *ftcache = (ft_cache_t *) cache;
cairo_ft_cache_key_t *k = (cairo_ft_cache_key_t *) key;
cairo_ft_cache_entry_t *entry;
@@ -212,8 +223,7 @@ _ft_font_cache_create_entry (void *cache,
if (entry == NULL)
return CAIRO_STATUS_NO_MEMORY;
- entry->unscaled = _ft_unscaled_font_create_from_filename (ftcache->lib,
- k->filename,
+ entry->unscaled = _ft_unscaled_font_create_from_filename (k->filename,
k->id);
if (!entry->unscaled) {
free (entry);
@@ -327,13 +337,13 @@ _ft_unscaled_font_get_for_pattern (FcPattern *pattern)
}
status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry);
+ if (CAIRO_OK (status) && !created_entry)
+ _cairo_unscaled_font_reference (&entry->unscaled->base);
+
_unlock_global_ft_cache ();
- if (status)
+ if (!CAIRO_OK (status))
return NULL;
- if (!created_entry)
- _cairo_unscaled_font_reference ((cairo_unscaled_font_t *)entry->unscaled);
-
return entry->unscaled;
}
@@ -406,9 +416,9 @@ _ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled)
static void
_compute_transform (ft_font_transform_t *sf,
- cairo_font_scale_t *sc)
+ cairo_matrix_t *scale)
{
- cairo_matrix_t normalized;
+ cairo_matrix_t normalized = *scale;
double tx, ty;
/* The font matrix has x and y "scale" components which we extract and
@@ -418,21 +428,14 @@ _compute_transform (ft_font_transform_t *sf,
* 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);
+ _cairo_matrix_get_affine (&normalized,
+ &sf->shape[0][0], &sf->shape[0][1],
+ &sf->shape[1][0], &sf->shape[1][1],
+ &tx, &ty);
}
/* Temporarily scales an unscaled font to the give scale. We catch
@@ -440,7 +443,7 @@ _compute_transform (ft_font_transform_t *sf,
*/
static void
_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
- cairo_font_scale_t *scale)
+ cairo_matrix_t *scale)
{
ft_font_transform_t sf;
FT_Matrix mat;
@@ -448,10 +451,10 @@ _ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
assert (unscaled->face != NULL);
if (unscaled->have_scale &&
- scale->matrix[0][0] == unscaled->current_scale.matrix[0][0] &&
- scale->matrix[0][1] == unscaled->current_scale.matrix[0][1] &&
- scale->matrix[1][0] == unscaled->current_scale.matrix[1][0] &&
- scale->matrix[1][1] == unscaled->current_scale.matrix[1][1])
+ scale->xx == unscaled->current_scale.xx &&
+ scale->yx == unscaled->current_scale.yx &&
+ scale->xy == unscaled->current_scale.xy &&
+ scale->yy == unscaled->current_scale.yy)
return;
unscaled->have_scale = 1;
@@ -474,14 +477,172 @@ _ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
(FT_UInt) sf.y_scale);
}
-/* implement the font backend interface */
+static void
+_cairo_ft_unscaled_font_destroy (void *abstract_font)
+{
+ ft_unscaled_font_t *unscaled = abstract_font;
+
+ if (unscaled->from_face) {
+ /* See comments in _ft_font_face_destroy about the "zombie" state
+ * for a _ft_font_face.
+ */
+ if (unscaled->faces && !unscaled->faces->unscaled)
+ cairo_font_face_destroy (&unscaled->faces->base);
+ } else {
+ cairo_cache_t *cache;
+ cairo_ft_cache_key_t key;
+
+ _lock_global_ft_cache ();
+ cache = _get_global_ft_cache ();
+ assert (cache);
+
+ key.filename = unscaled->filename;
+ key.id = unscaled->id;
+
+ _cairo_cache_remove (cache, &key);
+
+ _unlock_global_ft_cache ();
+
+ if (unscaled->filename)
+ free (unscaled->filename);
+
+ if (unscaled->face)
+ FT_Done_Face (unscaled->face);
+ }
+}
+
+static cairo_status_t
+_cairo_ft_unscaled_font_create_glyph (void *abstract_font,
+ cairo_image_glyph_cache_entry_t *val)
+{
+ ft_unscaled_font_t *unscaled = abstract_font;
+ FT_GlyphSlot glyphslot;
+ unsigned int width, height, stride;
+ FT_Face face;
+ FT_Outline *outline;
+ FT_BBox cbox;
+ FT_Bitmap bitmap;
+ FT_Glyph_Metrics *metrics;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ face = _ft_unscaled_font_lock_face (unscaled);
+ if (!face)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ glyphslot = face->glyph;
+ metrics = &glyphslot->metrics;
+
+ _ft_unscaled_font_set_scale (unscaled, &val->key.scale);
+
+ if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
+ /*
+ * Note: the font's coordinate system is upside down from ours, so the
+ * Y coordinates of the bearing and advance need to be negated.
+ *
+ * Scale metrics back to glyph space from the scaled glyph space returned
+ * by FreeType
+ */
+
+ val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale;
+ val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale;
+
+ val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale;
+ val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->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 (face->glyph->metrics.horiAdvance) / unscaled->x_scale;
+ val->extents.y_advance = 0 / unscaled->y_scale;
+
+ 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;
+
+ if (width * height == 0)
+ val->image = NULL;
+ else
+ {
+
+ bitmap.pixel_mode = ft_pixel_mode_grays;
+ bitmap.num_grays = 256;
+ bitmap.width = width;
+ bitmap.rows = height;
+ bitmap.pitch = stride;
+ bitmap.buffer = calloc (1, stride * height);
+
+ if (bitmap.buffer == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
+ FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
+
+ if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
+ free (bitmap.buffer);
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
+ val->image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (bitmap.buffer,
+ CAIRO_FORMAT_A8,
+ width, height, stride);
+ if (val->image == NULL) {
+ free (bitmap.buffer);
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto FAIL;
+ }
+
+ _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);
+
+ FAIL:
+ _ft_unscaled_font_unlock_face (unscaled);
+
+ return status;
+}
+
+const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = {
+ _cairo_ft_unscaled_font_destroy,
+ _cairo_ft_unscaled_font_create_glyph
+};
+
+/* cairo_ft_scaled_font_t */
typedef struct {
- cairo_font_t base;
- FcPattern *pattern;
+ cairo_scaled_font_t base;
int load_flags;
ft_unscaled_font_t *unscaled;
-} cairo_ft_font_t;
+} cairo_ft_scaled_font_t;
+
+const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend;
/* for compatibility with older freetype versions */
#ifndef FT_LOAD_TARGET_MONO
@@ -547,51 +708,43 @@ _get_load_flags (FcPattern *pattern)
return load_flags;
}
-/* Like the public cairo_ft_font_create, but takes a cairo_font_scale_t,
- * rather than a cairo_font_t
- */
-static cairo_font_t *
-_ft_font_create (FcPattern *pattern,
- cairo_font_scale_t *scale)
+static cairo_scaled_font_t *
+_ft_scaled_font_create (ft_unscaled_font_t *unscaled,
+ int load_flags,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm)
{
- cairo_ft_font_t *f = NULL;
- ft_unscaled_font_t *unscaled = NULL;
+ cairo_ft_scaled_font_t *f = NULL;
- unscaled = _ft_unscaled_font_get_for_pattern (pattern);
- if (unscaled == NULL)
- return NULL;
-
- f = malloc (sizeof(cairo_ft_font_t));
+ f = malloc (sizeof(cairo_ft_scaled_font_t));
if (f == NULL)
- goto FREE_UNSCALED;
+ return NULL;
f->unscaled = unscaled;
- f->pattern = pattern;
- FcPatternReference (pattern);
- f->load_flags = _get_load_flags (pattern);
-
- _cairo_font_init ((cairo_font_t *)f, scale, &cairo_ft_font_backend);
-
- return (cairo_font_t *)f;
+ _cairo_unscaled_font_reference (&unscaled->base);
+
+ f->load_flags = load_flags;
- FREE_UNSCALED:
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
+ _cairo_scaled_font_init (&f->base, font_matrix, ctm, &cairo_ft_scaled_font_backend);
- return NULL;
+ return (cairo_scaled_font_t *)f;
}
static cairo_status_t
-_cairo_ft_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *scale,
- cairo_font_t **font)
+_cairo_ft_scaled_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **font)
{
FcPattern *pattern, *resolved;
- cairo_font_t *new_font;
+ ft_unscaled_font_t *unscaled;
+ cairo_scaled_font_t *new_font;
FcResult result;
int fcslant;
int fcweight;
+ cairo_matrix_t scale;
ft_font_transform_t sf;
pattern = FcPatternCreate ();
@@ -623,14 +776,15 @@ _cairo_ft_font_create (const char *family,
break;
}
- if (!FcPatternAddString (pattern, FC_FAMILY, family))
+ if (!FcPatternAddString (pattern, FC_FAMILY, (unsigned char *) family))
goto FREE_PATTERN;
if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant))
goto FREE_PATTERN;
if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight))
goto FREE_PATTERN;
- _compute_transform (&sf, scale);
+ cairo_matrix_multiply (&scale, font_matrix, ctm);
+ _compute_transform (&sf, &scale);
FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale);
@@ -641,7 +795,13 @@ _cairo_ft_font_create (const char *family,
if (!resolved)
goto FREE_PATTERN;
- new_font = _ft_font_create (resolved, scale);
+ unscaled = _ft_unscaled_font_get_for_pattern (resolved);
+ if (!unscaled)
+ goto FREE_RESOLVED;
+
+ new_font = _ft_scaled_font_create (unscaled, _get_load_flags (pattern),
+ font_matrix, ctm);
+ _cairo_unscaled_font_destroy (&unscaled->base);
FcPatternDestroy (resolved);
FcPatternDestroy (pattern);
@@ -653,6 +813,9 @@ _cairo_ft_font_create (const char *family,
return CAIRO_STATUS_NO_MEMORY; /* A guess */
}
+ FREE_RESOLVED:
+ FcPatternDestroy (resolved);
+
FREE_PATTERN:
FcPatternDestroy (pattern);
@@ -660,88 +823,50 @@ _cairo_ft_font_create (const char *family,
}
static void
-_cairo_ft_font_destroy_font (void *abstract_font)
+_cairo_ft_scaled_font_destroy (void *abstract_font)
{
- cairo_ft_font_t * font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
- if (font == NULL)
+ if (scaled_font == NULL)
return;
- if (font->pattern != NULL)
- FcPatternDestroy (font->pattern);
-
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)font->unscaled);
-
- free (font);
-}
-
-static void
-_cairo_ft_font_destroy_unscaled_font (void *abstract_font)
-{
- ft_unscaled_font_t *unscaled = abstract_font;
-
- if (!unscaled->from_face) {
- cairo_cache_t *cache;
- cairo_ft_cache_key_t key;
-
- _lock_global_ft_cache ();
- cache = _get_global_ft_cache ();
- assert (cache);
-
- key.filename = unscaled->filename;
- key.id = unscaled->id;
-
- _cairo_cache_remove (cache, &key);
-
- _unlock_global_ft_cache ();
- }
-
- if (unscaled == NULL)
- return;
-
- if (!unscaled->from_face && unscaled->face)
- FT_Done_Face (unscaled->face);
-
- if (unscaled->filename)
- free (unscaled->filename);
-
- free (unscaled);
+ _cairo_unscaled_font_destroy (&scaled_font->unscaled->base);
}
static void
-_cairo_ft_font_get_glyph_cache_key (void *abstract_font,
- cairo_glyph_cache_key_t *key)
+_cairo_ft_scaled_font_get_glyph_cache_key (void *abstract_font,
+ cairo_glyph_cache_key_t *key)
{
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
- key->unscaled = (cairo_unscaled_font_t *)font->unscaled;
- key->scale = font->base.scale;
- key->flags = font->load_flags;
+ key->unscaled = &scaled_font->unscaled->base;
+ key->scale = scaled_font->base.scale;
+ key->flags = scaled_font->load_flags;
}
static cairo_status_t
-_cairo_ft_font_text_to_glyphs (void *abstract_font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *nglyphs)
+_cairo_ft_scaled_font_text_to_glyphs (void *abstract_font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
{
double x = 0., y = 0.;
size_t i;
uint32_t *ucs4 = NULL;
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
FT_Face face;
cairo_glyph_cache_key_t key;
cairo_image_glyph_cache_entry_t *val;
cairo_cache_t *cache = NULL;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- _cairo_ft_font_get_glyph_cache_key (font, &key);
+ _cairo_ft_scaled_font_get_glyph_cache_key (scaled_font, &key);
- status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, nglyphs);
+ status = _cairo_utf8_to_ucs4 ((unsigned char*)utf8, -1, &ucs4, num_glyphs);
if (!CAIRO_OK (status))
return status;
- face = cairo_ft_font_lock_face ((cairo_font_t *)font);
+ face = cairo_ft_scaled_font_lock_face (&scaled_font->base);
if (!face) {
status = CAIRO_STATUS_NO_MEMORY;
goto FAIL1;
@@ -754,13 +879,13 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
goto FAIL2;
}
- *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t)));
+ *glyphs = (cairo_glyph_t *) malloc ((*num_glyphs) * (sizeof (cairo_glyph_t)));
if (*glyphs == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto FAIL2;
}
- for (i = 0; i < *nglyphs; i++)
+ for (i = 0; i < *num_glyphs; i++)
{
(*glyphs)[i].index = FT_Get_Char_Index (face, ucs4[i]);
(*glyphs)[i].x = x;
@@ -781,7 +906,7 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
if (cache)
_cairo_unlock_global_image_glyph_cache ();
- cairo_ft_font_unlock_face ((cairo_font_t *)font);
+ cairo_ft_scaled_font_unlock_face (&scaled_font->base);
FAIL1:
free (ucs4);
@@ -791,49 +916,50 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font,
static cairo_status_t
-_cairo_ft_font_font_extents (void *abstract_font,
- cairo_font_extents_t *extents)
+_cairo_ft_scaled_font_font_extents (void *abstract_font,
+ cairo_font_extents_t *extents)
{
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
FT_Face face;
FT_Size_Metrics *metrics;
- face = _ft_unscaled_font_lock_face (font->unscaled);
+ face = _ft_unscaled_font_lock_face (scaled_font->unscaled);
if (!face)
return CAIRO_STATUS_NO_MEMORY;
metrics = &face->size->metrics;
- _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
+ _ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale);
/*
* Get to unscaled metrics so that the upper level can get back to
* user space
*/
- extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / font->unscaled->y_scale;
- extents->descent = DOUBLE_FROM_26_6(metrics->descender) / font->unscaled->y_scale;
- extents->height = DOUBLE_FROM_26_6(metrics->height) / font->unscaled->y_scale;
- extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / font->unscaled->x_scale;
+ extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / scaled_font->unscaled->y_scale;
+ extents->descent = DOUBLE_FROM_26_6(- metrics->descender) / scaled_font->unscaled->y_scale;
+ extents->height = DOUBLE_FROM_26_6(metrics->height) / scaled_font->unscaled->y_scale;
+ extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / scaled_font->unscaled->x_scale;
/* FIXME: this doesn't do vertical layout atm. */
extents->max_y_advance = 0.0;
- _ft_unscaled_font_unlock_face (font->unscaled);
+ _ft_unscaled_font_unlock_face (scaled_font->unscaled);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_ft_font_glyph_extents (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
+_cairo_ft_scaled_font_glyph_extents (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
int i;
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
cairo_point_double_t origin;
cairo_point_double_t glyph_min, glyph_max;
- cairo_point_double_t total_min, total_max;
+ /* Initialize just to squelch anti-helpful compiler warning. */
+ cairo_point_double_t total_min = { 0, 0}, total_max = {0,0};
cairo_image_glyph_cache_entry_t *img = NULL;
cairo_cache_t *cache;
@@ -861,7 +987,7 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
return CAIRO_STATUS_NO_MEMORY;
}
- _cairo_ft_font_get_glyph_cache_key (font, &key);
+ _cairo_ft_scaled_font_get_glyph_cache_key (scaled_font, &key);
for (i = 0; i < num_glyphs; i++)
{
@@ -874,7 +1000,7 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
/* 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_ft_font_create_for_ft_face accept an
+ cairo_ft_scaled_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;
@@ -910,15 +1036,15 @@ _cairo_ft_font_glyph_extents (void *abstract_font,
static cairo_status_t
-_cairo_ft_font_glyph_bbox (void *abstract_font,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
+_cairo_ft_scaled_font_glyph_bbox (void *abstract_font,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
{
cairo_image_glyph_cache_entry_t *img;
cairo_cache_t *cache;
cairo_glyph_cache_key_t key;
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
cairo_fixed_t x1, y1, x2, y2;
int i;
@@ -930,13 +1056,13 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
cache = _cairo_get_global_image_glyph_cache();
if (cache == NULL
- || font == NULL
+ || scaled_font == NULL
|| glyphs == NULL) {
_cairo_unlock_global_image_glyph_cache ();
return CAIRO_STATUS_NO_MEMORY;
}
- _cairo_ft_font_get_glyph_cache_key (font, &key);
+ _cairo_ft_scaled_font_get_glyph_cache_key (scaled_font, &key);
for (i = 0; i < num_glyphs; i++)
{
@@ -972,23 +1098,23 @@ _cairo_ft_font_glyph_bbox (void *abstract_font,
static cairo_status_t
-_cairo_ft_font_show_glyphs (void *abstract_font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_ft_scaled_font_show_glyphs (void *abstract_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
{
cairo_image_glyph_cache_entry_t *img;
cairo_cache_t *cache;
cairo_glyph_cache_key_t key;
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
cairo_surface_pattern_t glyph_pattern;
cairo_status_t status;
int x, y;
@@ -998,7 +1124,7 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
cache = _cairo_get_global_image_glyph_cache();
if (cache == NULL
- || font == NULL
+ || scaled_font == NULL
|| pattern == NULL
|| surface == NULL
|| glyphs == NULL) {
@@ -1006,9 +1132,9 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
return CAIRO_STATUS_NO_MEMORY;
}
- key.unscaled = (cairo_unscaled_font_t *)font->unscaled;
- key.scale = font->base.scale;
- key.flags = font->load_flags;
+ key.unscaled = &scaled_font->unscaled->base;
+ key.scale = scaled_font->base.scale;
+ key.flags = scaled_font->load_flags;
for (i = 0; i < num_glyphs; i++)
{
@@ -1054,14 +1180,14 @@ _cairo_ft_font_show_glyphs (void *abstract_font,
static int
_move_to (FT_Vector *to, void *closure)
{
- cairo_path_t *path = closure;
- cairo_point_t point;
+ cairo_path_fixed_t *path = closure;
+ cairo_fixed_t x, y;
- point.x = _cairo_fixed_from_26_6 (to->x);
- point.y = _cairo_fixed_from_26_6 (to->y);
+ x = _cairo_fixed_from_26_6 (to->x);
+ y = _cairo_fixed_from_26_6 (to->y);
- _cairo_path_close_path (path);
- _cairo_path_move_to (path, &point);
+ _cairo_path_fixed_close_path (path);
+ _cairo_path_fixed_move_to (path, x, y);
return 0;
}
@@ -1069,13 +1195,13 @@ _move_to (FT_Vector *to, void *closure)
static int
_line_to (FT_Vector *to, void *closure)
{
- cairo_path_t *path = closure;
- cairo_point_t point;
+ cairo_path_fixed_t *path = closure;
+ cairo_fixed_t x, y;
- point.x = _cairo_fixed_from_26_6 (to->x);
- point.y = _cairo_fixed_from_26_6 (to->y);
+ x = _cairo_fixed_from_26_6 (to->x);
+ y = _cairo_fixed_from_26_6 (to->y);
- _cairo_path_line_to (path, &point);
+ _cairo_path_fixed_line_to (path, x, y);
return 0;
}
@@ -1083,27 +1209,32 @@ _line_to (FT_Vector *to, void *closure)
static int
_conic_to (FT_Vector *control, FT_Vector *to, void *closure)
{
- cairo_path_t *path = closure;
+ cairo_path_fixed_t *path = closure;
- cairo_point_t p0, p1, p2, p3;
+ cairo_fixed_t x0, y0;
+ cairo_fixed_t x1, y1;
+ cairo_fixed_t x2, y2;
+ cairo_fixed_t x3, y3;
cairo_point_t conic;
- _cairo_path_current_point (path, &p0);
+ _cairo_path_fixed_get_current_point (path, &x0, &y0);
conic.x = _cairo_fixed_from_26_6 (control->x);
conic.y = _cairo_fixed_from_26_6 (control->y);
- p3.x = _cairo_fixed_from_26_6 (to->x);
- p3.y = _cairo_fixed_from_26_6 (to->y);
+ x3 = _cairo_fixed_from_26_6 (to->x);
+ y3 = _cairo_fixed_from_26_6 (to->y);
- p1.x = p0.x + 2.0/3.0 * (conic.x - p0.x);
- p1.y = p0.y + 2.0/3.0 * (conic.y - p0.y);
+ x1 = x0 + 2.0/3.0 * (conic.x - x0);
+ y1 = y0 + 2.0/3.0 * (conic.y - y0);
- p2.x = p3.x + 2.0/3.0 * (conic.x - p3.x);
- p2.y = p3.y + 2.0/3.0 * (conic.y - p3.y);
+ x2 = x3 + 2.0/3.0 * (conic.x - x3);
+ y2 = y3 + 2.0/3.0 * (conic.y - y3);
- _cairo_path_curve_to (path,
- &p1, &p2, &p3);
+ _cairo_path_fixed_curve_to (path,
+ x1, y1,
+ x2, y2,
+ x3, y3);
return 0;
}
@@ -1111,31 +1242,36 @@ _conic_to (FT_Vector *control, FT_Vector *to, void *closure)
static int
_cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closure)
{
- cairo_path_t *path = closure;
- cairo_point_t p0, p1, p2;
+ cairo_path_fixed_t *path = closure;
+ cairo_fixed_t x0, y0;
+ cairo_fixed_t x1, y1;
+ cairo_fixed_t x2, y2;
- p0.x = _cairo_fixed_from_26_6 (control1->x);
- p0.y = _cairo_fixed_from_26_6 (control1->y);
+ x0 = _cairo_fixed_from_26_6 (control1->x);
+ y0 = _cairo_fixed_from_26_6 (control1->y);
- p1.x = _cairo_fixed_from_26_6 (control2->x);
- p1.y = _cairo_fixed_from_26_6 (control2->y);
+ x1 = _cairo_fixed_from_26_6 (control2->x);
+ y1 = _cairo_fixed_from_26_6 (control2->y);
- p2.x = _cairo_fixed_from_26_6 (to->x);
- p2.y = _cairo_fixed_from_26_6 (to->y);
+ x2 = _cairo_fixed_from_26_6 (to->x);
+ y2 = _cairo_fixed_from_26_6 (to->y);
- _cairo_path_curve_to (path, &p0, &p1, &p2);
+ _cairo_path_fixed_curve_to (path,
+ x0, y0,
+ x1, y1,
+ x2, y2);
return 0;
}
static cairo_status_t
-_cairo_ft_font_glyph_path (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
+_cairo_ft_scaled_font_glyph_path (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path)
{
int i;
- cairo_ft_font_t *font = abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = abstract_font;
FT_GlyphSlot glyph;
FT_Face face;
FT_Error error;
@@ -1148,7 +1284,7 @@ _cairo_ft_font_glyph_path (void *abstract_font,
0, /* delta */
};
- face = cairo_ft_font_lock_face (abstract_font);
+ face = cairo_ft_scaled_font_lock_face (abstract_font);
if (!face)
return CAIRO_STATUS_NO_MEMORY;
@@ -1161,7 +1297,7 @@ _cairo_ft_font_glyph_path (void *abstract_font,
0, DOUBLE_TO_16_16 (-1.0),
};
- error = FT_Load_Glyph (font->unscaled->face, glyphs[i].index, font->load_flags | FT_LOAD_NO_BITMAP);
+ error = FT_Load_Glyph (scaled_font->unscaled->face, glyphs[i].index, scaled_font->load_flags | FT_LOAD_NO_BITMAP);
/* XXX: What to do in this error case? */
if (error)
continue;
@@ -1176,148 +1312,136 @@ _cairo_ft_font_glyph_path (void *abstract_font,
DOUBLE_TO_26_6(glyphs[i].y));
FT_Outline_Decompose (&glyph->outline, &outline_funcs, path);
}
- _cairo_path_close_path (path);
+ _cairo_path_fixed_close_path (path);
- cairo_ft_font_unlock_face (abstract_font);
+ cairo_ft_scaled_font_unlock_face (abstract_font);
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_ft_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
-{
- ft_unscaled_font_t *unscaled = (ft_unscaled_font_t *)val->key.unscaled;
- FT_GlyphSlot glyphslot;
- unsigned int width, height, stride;
- FT_Face face;
- FT_Outline *outline;
- FT_BBox cbox;
- FT_Bitmap bitmap;
- FT_Glyph_Metrics *metrics;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- glyphslot = unscaled->face->glyph;
- metrics = &glyphslot->metrics;
+const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = {
+ _cairo_ft_scaled_font_create,
+ _cairo_ft_scaled_font_destroy,
+ _cairo_ft_scaled_font_font_extents,
+ _cairo_ft_scaled_font_text_to_glyphs,
+ _cairo_ft_scaled_font_glyph_extents,
+ _cairo_ft_scaled_font_glyph_bbox,
+ _cairo_ft_scaled_font_show_glyphs,
+ _cairo_ft_scaled_font_glyph_path,
+ _cairo_ft_scaled_font_get_glyph_cache_key,
+};
- face = _ft_unscaled_font_lock_face (unscaled);
- if (!face)
- return CAIRO_STATUS_NO_MEMORY;
+/* ft_font_face_t */
- _ft_unscaled_font_set_scale (unscaled, &val->key.scale);
-
- if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
+static void
+_ft_font_face_destroy (void *abstract_face)
+{
+ ft_font_face_t *font_face = abstract_face;
+
+ ft_font_face_t *tmp_face = NULL;
+ ft_font_face_t *last_face = NULL;
- /*
- * Note: the font's coordinate system is upside down from ours, so the
- * Y coordinates of the bearing and advance need to be negated.
+ /* When destroying the face created by cairo_ft_font_face_create_for_ft_face,
+ * we have a special "zombie" state for the face when the unscaled font
+ * is still alive but there are no public references to the font face.
*
- * Scale metrics back to glyph space from the scaled glyph space returned
- * by FreeType
+ * We go from:
+ *
+ * font_face ------> unscaled
+ * <-....weak....../
+ *
+ * To:
+ *
+ * font_face <------- unscaled
*/
- val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale;
- val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale;
+ if (font_face->unscaled &&
+ font_face->unscaled->from_face &&
+ font_face->unscaled->base.refcount > 1) {
+ cairo_font_face_reference (&font_face->base);
+
+ _cairo_unscaled_font_destroy (&font_face->unscaled->base);
+ font_face->unscaled = NULL;
+
+ return;
+ }
+
+ if (font_face->unscaled) {
+ /* Remove face from linked list */
+ for (tmp_face = font_face->unscaled->faces; tmp_face; tmp_face = tmp_face->next_face) {
+ if (tmp_face == font_face) {
+ if (last_face)
+ last_face->next_face = tmp_face->next_face;
+ else
+ font_face->unscaled->faces = tmp_face->next_face;
+ }
+
+ last_face = tmp_face;
+ }
- val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale;
- val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale;
+ _cairo_unscaled_font_destroy (&font_face->unscaled->base);
+ font_face->unscaled = NULL;
+ }
+}
- /*
- * use untransformed advance values
- * XXX uses horizontal advance only at present;
- should provide FT_LOAD_VERTICAL_LAYOUT
- */
+static cairo_status_t
+_ft_font_face_create_font (void *abstract_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **scaled_font)
+{
+ ft_font_face_t *font_face = abstract_face;
- val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale;
- val->extents.y_advance = 0 / unscaled->y_scale;
-
- outline = &glyphslot->outline;
+ *scaled_font = _ft_scaled_font_create (font_face->unscaled,
+ font_face->load_flags,
+ font_matrix, ctm);
+ if (*scaled_font)
+ return CAIRO_STATUS_SUCCESS;
+ else
+ return CAIRO_STATUS_NO_MEMORY;
+}
- FT_Outline_Get_CBox (outline, &cbox);
+static const cairo_font_face_backend_t _ft_font_face_backend = {
+ _ft_font_face_destroy,
+ _ft_font_face_create_font,
+};
- 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;
-
- if (width * height == 0)
- val->image = NULL;
- else
- {
+static cairo_font_face_t *
+_ft_font_face_create (ft_unscaled_font_t *unscaled,
+ int load_flags)
+{
+ ft_font_face_t *font_face;
- bitmap.pixel_mode = ft_pixel_mode_grays;
- bitmap.num_grays = 256;
- bitmap.width = width;
- bitmap.rows = height;
- bitmap.pitch = stride;
- bitmap.buffer = calloc (1, stride * height);
-
- if (bitmap.buffer == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
+ /* Looked for an existing matching font face */
+ for (font_face = unscaled->faces; font_face; font_face = font_face->next_face) {
+ if (font_face->load_flags == load_flags) {
+ cairo_font_face_reference (&font_face->base);
+ return &font_face->base;
}
-
- FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
-
- if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
- free (bitmap.buffer);
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- val->image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data ((char *) bitmap.buffer,
- CAIRO_FORMAT_A8,
- width, height, stride);
- if (val->image == NULL) {
- free (bitmap.buffer);
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- _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);
+ /* No match found, create a new one */
+ font_face = malloc (sizeof (ft_font_face_t));
+ if (!font_face)
+ return NULL;
- FAIL:
- _ft_unscaled_font_unlock_face (unscaled);
+ font_face->unscaled = unscaled;
+ _cairo_unscaled_font_reference (&unscaled->base);
- return status;
-}
+ font_face->load_flags = load_flags;
-const cairo_font_backend_t cairo_ft_font_backend = {
- _cairo_ft_font_create,
- _cairo_ft_font_destroy_font,
- _cairo_ft_font_destroy_unscaled_font,
- _cairo_ft_font_font_extents,
- _cairo_ft_font_text_to_glyphs,
- _cairo_ft_font_glyph_extents,
- _cairo_ft_font_glyph_bbox,
- _cairo_ft_font_show_glyphs,
- _cairo_ft_font_glyph_path,
- _cairo_ft_font_get_glyph_cache_key,
- _cairo_ft_font_create_glyph
-};
+ font_face->next_face = unscaled->faces;
+ unscaled->faces = font_face;
+
+ _cairo_font_face_init (&font_face->base, &_ft_font_face_backend);
+
+ return &font_face->base;
+}
/* implement the platform-specific interface */
/**
- * cairo_ft_font_create:
+ * cairo_ft_font_face_create_for_pattern:
* @pattern: A fully resolved fontconfig
* pattern. A pattern can be resolved, by, among other things, calling
* FcConfigSubstitute(), FcDefaultSubstitute(), then
@@ -1325,112 +1449,83 @@ const cairo_font_backend_t cairo_ft_font_backend = {
* pattern, so you should not further modify the pattern, but you can
* release your reference to the pattern with FcPatternDestroy() if
* you no longer need to access it.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
*
- * Creates a new font for the FreeType font backend based on a
+ * Creates a new font face for the FreeType font backend based on a
* fontconfig pattern. This font can then be used with
- * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
- * specific functions like cairo_ft_font_lock_face().
+ * cairo_set_font_face() or cairo_font_create(). The #cairo_scaled_font_t
+ * returned from cairo_font_create() is also for the FreeType backend
+ * and can be used with functions such as cairo_ft_font_lock_face().
*
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
+ * Return value: a newly created #cairo_font_face_t. Free with
+ * cairo_font_face_destroy() when you are done using it.
**/
-cairo_font_t *
-cairo_ft_font_create (FcPattern *pattern,
- cairo_matrix_t *scale)
-{
- cairo_font_scale_t sc;
- double tx, ty;
+cairo_font_face_t *
+cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
+{
+ ft_unscaled_font_t *unscaled;
+ cairo_font_face_t *font_face;
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- &tx, &ty);
+ unscaled = _ft_unscaled_font_get_for_pattern (pattern);
+ if (unscaled == NULL)
+ return NULL;
- return _ft_font_create (pattern, &sc);
+ font_face = _ft_font_face_create (unscaled, _get_load_flags (pattern));
+ _cairo_unscaled_font_destroy (&unscaled->base);
+
+ return font_face;
}
/**
* cairo_ft_font_create_for_ft_face:
* @face: A FreeType face object, already opened. This must
- * be kept around until the font object's refcount drops to
- * zero and it is freed. The font object can be kept alive by
- * internal caching, so it's safest to keep the face object
- * around forever.
+ * be kept around until the face's refcount drops to
+ * zero and it is freed. Since the face may be referenced
+ * internally to Cairo, the best way to determine when it
+ * is safe to free the face is to pass a
+ * #cairo_destroy_func_t to cairo_font_face_set_user_data()
* @load_flags: The flags to pass to FT_Load_Glyph when loading
* glyphs from the font. These flags control aspects of
* rendering such as hinting and antialiasing. See the FreeType
* docs for full information.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
*
- * Creates a new font forthe FreeType font backend from a pre-opened
- * FreeType face. This font can then be used with cairo_set_font(),
- * cairo_font_glyph_extents(), or FreeType backend specific
- * functions like cairo_ft_font_lock_face() Cairo will determine the
- * pixel size and transformation from the @scale parameter and call
- * FT_Set_Transform() and FT_Set_Pixel_Sizes().
+ * Creates a new font face for the FreeType font backend from a pre-opened
+ * FreeType face. This font can then be used with
+ * cairo_set_font_face() or cairo_font_create(). The #cairo_scaled_font_t
+ * returned from cairo_font_create() is also for the FreeType backend
+ * and can be used with functions such as cairo_ft_font_lock_face().
*
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
+ * Return value: a newly created #cairo_font_face_t. Free with
+ * cairo_font_face_destroy() when you are done using it.
**/
-cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face,
- int load_flags,
- cairo_matrix_t *scale)
+cairo_font_face_t *
+cairo_ft_font_face_create_for_ft_face (FT_Face face,
+ int load_flags)
{
- cairo_ft_font_t *f = NULL;
- ft_unscaled_font_t *unscaled = NULL;
- cairo_font_scale_t sc;
- double tx, ty;
+ ft_unscaled_font_t *unscaled;
+ cairo_font_face_t *font_face;
unscaled = _ft_unscaled_font_create_from_face (face);
if (unscaled == NULL)
return NULL;
- f = malloc (sizeof(cairo_ft_font_t));
- if (f == NULL)
- goto FREE_UNSCALED;
-
- f->unscaled = unscaled;
- f->pattern = NULL;
- f->load_flags = load_flags;
-
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- &tx, &ty);
-
- _cairo_font_init ((cairo_font_t *)f, &sc, &cairo_ft_font_backend);
-
- return (cairo_font_t *)f;
-
- FREE_UNSCALED:
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
+ font_face = _ft_font_face_create (unscaled, load_flags);
+ _cairo_unscaled_font_destroy (&unscaled->base);
- return NULL;
+ return font_face;
}
-
/**
- * cairo_ft_font_lock_face:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
+ * cairo_ft_scaled_font_lock_face:
+ * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an
+ * object can be created by calling cairo_scaled_font_create() on a
+ * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(),
+ * cairo_ft_font_face_create_for_face()).
*
* cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType
* backend font and scales it appropriately for the font. You must
* release the face with cairo_ft_font_unlock_face()
* when you are done using it. Since the #FT_Face object can be
- * shared between multiple #cairo_font_t objects, you must not
+ * shared between multiple #cairo_scaled_font_t objects, you must not
* lock any other font objects until you unlock this one. A count is
* kept of the number of times cairo_ft_font_lock_face() is
* called. cairo_ft_font_unlock_face() must be called the same number
@@ -1447,67 +1542,36 @@ cairo_ft_font_create_for_ft_face (FT_Face face,
* Return value: The #FT_Face object for @font, scaled appropriately.
**/
FT_Face
-cairo_ft_font_lock_face (cairo_font_t *abstract_font)
+cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
FT_Face face;
- face = _ft_unscaled_font_lock_face (font->unscaled);
+ face = _ft_unscaled_font_lock_face (scaled_font->unscaled);
if (!face)
return NULL;
- _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
+ _ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale);
return face;
}
/**
- * cairo_ft_font_unlock_face:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
+ * cairo_ft_scaled_font_unlock_face:
+ * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an
+ * object can be created by calling cairo_scaled_font_create() on a
+ * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(),
+ * cairo_ft_font_face_create_for_face()).
*
* Releases a face obtained with cairo_ft_font_lock_face(). See the
* documentation for that function for full details.
**/
void
-cairo_ft_font_unlock_face (cairo_font_t *abstract_font)
-{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
-
- _ft_unscaled_font_unlock_face (font->unscaled);
-}
-
-/**
- * cairo_ft_font_get_pattern:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
- *
- * cairo_ft_font_get_pattern() gets the #FcPattern for a FreeType
- * backend font.
-
- * Return value: The #FcPattenr for @font. The return value is owned
- * by the font, so you must not modify it, and must call
- * FcPatternReference() to keep a persistant reference to the
- * pattern. If the font was created with cairo_ft_font_create_for_ft_face()
- * returns %NULL.
- **/
-FcPattern *
-cairo_ft_font_get_pattern (cairo_font_t *abstract_font)
+cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
-
- if (font == NULL)
- return NULL;
+ cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
- return font->pattern;
+ _ft_unscaled_font_unlock_face (scaled_font->unscaled);
}
/* We expose our unscaled font implementation internally for the the
@@ -1515,11 +1579,11 @@ cairo_ft_font_get_pattern (cairo_font_t *abstract_font)
* fonts-on-disk used by a document, so it can embed them.
*/
cairo_unscaled_font_t *
-_cairo_ft_font_get_unscaled_font (cairo_font_t *abstract_font)
+_cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *abstract_font)
{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+ cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
- return (cairo_unscaled_font_t *)font->unscaled;
+ return &scaled_font->unscaled->base;
}
/* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't
diff --git a/src/cairo-ft-private.h b/src/cairo-ft-private.h
index 37a6feecc..494d8369a 100644
--- a/src/cairo-ft-private.h
+++ b/src/cairo-ft-private.h
@@ -40,7 +40,7 @@
#include <cairo-ft.h>
#include <cairoint.h>
-#ifdef CAIRO_HAS_FT_FONT
+#if CAIRO_HAS_FT_FONT
CAIRO_BEGIN_DECLS
@@ -48,7 +48,7 @@ CAIRO_BEGIN_DECLS
* the different fonts-on-disk used by a document, so it can embed them
*/
cairo_private cairo_unscaled_font_t *
-_cairo_ft_font_get_unscaled_font (cairo_font_t *font);
+_cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *scaled_font);
cairo_private FT_Face
_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font);
diff --git a/src/cairo-ft.h b/src/cairo-ft.h
index f10c67d80..4e8b8bcdb 100644
--- a/src/cairo-ft.h
+++ b/src/cairo-ft.h
@@ -39,7 +39,7 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_FT_FONT
+#if CAIRO_HAS_FT_FONT
/* Fontconfig/Freetype platform-specific font interface */
@@ -49,25 +49,23 @@
CAIRO_BEGIN_DECLS
-cairo_font_t *
-cairo_ft_font_create (FcPattern *pattern,
- cairo_matrix_t *scale);
+cairo_font_face_t *
+cairo_ft_font_face_create_for_pattern (FcPattern *pattern);
-cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face,
- int load_flags,
- cairo_matrix_t *scale);
+cairo_font_face_t *
+cairo_ft_font_face_create_for_ft_face (FT_Face face,
+ int load_flags);
FT_Face
-cairo_ft_font_lock_face (cairo_font_t *ft_font);
+cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *scaled_font);
void
-cairo_ft_font_unlock_face (cairo_font_t *ft_font);
-
-FcPattern *
-cairo_ft_font_get_pattern (cairo_font_t *ft_font);
+cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *scaled_font);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_FT_FONT */
+# error Cairo was not compiled with support for the freetype font backend
#endif /* CAIRO_HAS_FT_FONT */
+
#endif /* CAIRO_FT_H */
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index ee664e1cc..673b972c3 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -27,25 +27,6 @@
#include "cairoint.h"
#include "cairo-glitz.h"
-void
-cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
-{
- cairo_surface_t *crsurface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- crsurface = cairo_glitz_surface_create (surface);
- if (crsurface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, crsurface);
-
- cairo_surface_destroy (crsurface);
-}
-
typedef struct _cairo_glitz_surface {
cairo_surface_t base;
@@ -54,8 +35,8 @@ typedef struct _cairo_glitz_surface {
pixman_region16_t *clip;
} cairo_glitz_surface_t;
-static void
-_cairo_glitz_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_glitz_surface_finish (void *abstract_surface)
{
cairo_glitz_surface_t *surface = abstract_surface;
@@ -66,7 +47,8 @@ _cairo_glitz_surface_destroy (void *abstract_surface)
}
glitz_surface_destroy (surface->surface);
- free (surface);
+
+ return CAIRO_STATUS_SUCCESS;
}
static glitz_format_name_t
@@ -115,12 +97,6 @@ _cairo_glitz_surface_create_similar (void *abstract_src,
return crsurface;
}
-static double
-_cairo_glitz_surface_pixels_per_inch (void *abstract_surface)
-{
- return 96.0;
-}
-
static cairo_status_t
_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
cairo_rectangle_t *interest,
@@ -130,7 +106,7 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
cairo_image_surface_t *image;
int x1, y1, x2, y2;
int width, height;
- char *pixels;
+ unsigned char *pixels;
cairo_format_masks_t format;
glitz_buffer_t *buffer;
glitz_pixel_format_t pf;
@@ -402,17 +378,17 @@ _cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface,
{
glitz_transform_t transform;
- transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
+ transform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
+ transform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy);
+ transform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0);
- transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
+ transform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx);
+ transform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy);
+ transform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0);
transform.matrix[2][0] = 0;
transform.matrix[2][1] = 0;
- transform.matrix[2][2] = 1 << 16;
+ transform.matrix[2][2] = _cairo_fixed_from_double (1);
glitz_surface_set_transform (surface->surface, &transform);
}
@@ -423,32 +399,49 @@ _glitz_operator (cairo_operator_t op)
switch (op) {
case CAIRO_OPERATOR_CLEAR:
return GLITZ_OPERATOR_CLEAR;
- case CAIRO_OPERATOR_SRC:
+
+ case CAIRO_OPERATOR_SOURCE:
return GLITZ_OPERATOR_SRC;
- case CAIRO_OPERATOR_DST:
- return GLITZ_OPERATOR_DST;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return GLITZ_OPERATOR_OVER_REVERSE;
+ case CAIRO_OPERATOR_OVER:
+ return GLITZ_OPERATOR_OVER;
case CAIRO_OPERATOR_IN:
return GLITZ_OPERATOR_IN;
- case CAIRO_OPERATOR_IN_REVERSE:
- return GLITZ_OPERATOR_IN_REVERSE;
case CAIRO_OPERATOR_OUT:
return GLITZ_OPERATOR_OUT;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return GLITZ_OPERATOR_OUT_REVERSE;
case CAIRO_OPERATOR_ATOP:
return GLITZ_OPERATOR_ATOP;
- case CAIRO_OPERATOR_ATOP_REVERSE:
+
+ case CAIRO_OPERATOR_DEST:
+ return GLITZ_OPERATOR_DST;
+ case CAIRO_OPERATOR_DEST_OVER:
+ return GLITZ_OPERATOR_OVER_REVERSE;
+ case CAIRO_OPERATOR_DEST_IN:
+ return GLITZ_OPERATOR_IN_REVERSE;
+ case CAIRO_OPERATOR_DEST_OUT:
+ return GLITZ_OPERATOR_OUT_REVERSE;
+ case CAIRO_OPERATOR_DEST_ATOP:
return GLITZ_OPERATOR_ATOP_REVERSE;
+
case CAIRO_OPERATOR_XOR:
return GLITZ_OPERATOR_XOR;
case CAIRO_OPERATOR_ADD:
return GLITZ_OPERATOR_ADD;
- case CAIRO_OPERATOR_OVER:
- default:
+ case CAIRO_OPERATOR_SATURATE:
+ /* XXX: OVER is definitely not the right thing here, (but it
+ * is what the original glitz backend code has always
+ * done). Cairo's SATURATE operator is the native GL
+ * compositing mode, (from my understanding). So why isn't
+ * there a GLITZ_OPERATOR_SATURATE for us to use here? */
return GLITZ_OPERATOR_OVER;
}
+
+ ASSERT_NOT_REACHED;
+
+ /* Something's very broken if this line of code can be reached, so
+ we want to return something that would give a noticeably
+ incorrect result. The XOR operator seems so rearely desired
+ that it should fit the bill here. */
+ return CAIRO_OPERATOR_XOR;
}
static glitz_status_t
@@ -586,12 +579,12 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
pattern->filter != CAIRO_FILTER_BEST)
break;
- alpha = (gradient->stops[0].color.alpha * pattern->alpha) * 0xffff;
+ alpha = (gradient->stops[0].color.alpha) * 0xffff;
for (i = 1; i < gradient->n_stops; i++)
{
unsigned short a;
- a = (gradient->stops[i].color.alpha * pattern->alpha) * 0xffff;
+ a = (gradient->stops[i].color.alpha) * 0xffff;
if (a != alpha)
break;
}
@@ -733,7 +726,7 @@ _cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst,
_cairo_pattern_release_surface (&dst->base, &surface->base,
&attr->base);
else
- _cairo_glitz_surface_destroy (surface);
+ cairo_surface_destroy (&surface->base);
}
static cairo_int_status_t
@@ -753,50 +746,30 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
{
cairo_int_status_t status;
cairo_pattern_union_t tmp;
- cairo_bool_t src_opaque, mask_opaque;
- double src_alpha, mask_alpha;
- src_opaque = _cairo_pattern_is_opaque (src);
- mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
-
- /* For surface patterns, we move any translucency from src->alpha
- * to mask->alpha so we can use the source unchanged. Otherwise we
- * move the translucency from mask->alpha to src->alpha so that
- * we can drop the mask if possible.
- */
- if (src->type == CAIRO_PATTERN_SURFACE)
- {
- if (mask) {
- mask_opaque = mask_opaque && src_opaque;
- mask_alpha = mask->alpha * src->alpha;
- } else {
- mask_opaque = src_opaque;
- mask_alpha = src->alpha;
- }
-
- src_alpha = 1.0;
- src_opaque = TRUE;
- }
- else
+ /* If src and mask are both solid, then the mask alpha can be
+ * combined into src and mask can be ignored. */
+
+ /* XXX: This optimization assumes that there is no color
+ * information in mask, so this will need to change when we
+ * support RENDER-style 4-channel masks. */
+
+ if (src->type == CAIRO_PATTERN_SOLID &&
+ mask->type == CAIRO_PATTERN_SOLID)
{
- if (mask)
- {
- src_opaque = mask_opaque && src_opaque;
- src_alpha = mask->alpha * src->alpha;
- /* FIXME: This needs changing when we support RENDER
- * style 4-channel masks.
- */
- if (mask->type == CAIRO_PATTERN_SOLID)
- mask = NULL;
- } else
- src_alpha = src->alpha;
+ cairo_color_t combined;
+ cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
+ cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
- mask_alpha = 1.0;
- mask_opaque = TRUE;
- }
+ combined = src_solid->color;
+ _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
- _cairo_pattern_init_copy (&tmp.base, src);
- _cairo_pattern_set_alpha (&tmp.base, src_alpha);
+ _cairo_pattern_init_solid (&tmp.solid, &combined);
+
+ mask = NULL;
+ } else {
+ _cairo_pattern_init_copy (&tmp.base, src);
+ }
status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
src_x, src_y,
@@ -808,14 +781,9 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
if (status)
return status;
- if (mask || !mask_opaque)
+ if (mask)
{
- if (mask)
- _cairo_pattern_init_copy (&tmp.base, mask);
- else
- _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
-
- _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
+ _cairo_pattern_init_copy (&tmp.base, mask);
status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
mask_x, mask_y,
@@ -937,7 +905,7 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
{
cairo_glitz_surface_t *dst = abstract_dst;
- if (op == CAIRO_OPERATOR_SRC)
+ if (op == CAIRO_OPERATOR_SOURCE)
{
glitz_color_t glitz_color;
@@ -969,6 +937,8 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
(cairo_color_t *) color);
if (!src)
return CAIRO_STATUS_NO_MEMORY;
+
+ glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
while (n_rects--)
{
@@ -1025,7 +995,6 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
cairo_pattern_union_t tmp;
_cairo_pattern_init_copy (&tmp.base, pattern);
- _cairo_pattern_set_alpha (&tmp.base, 1.0);
status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
src_x, src_y,
@@ -1033,8 +1002,6 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
&src, &attributes);
_cairo_pattern_fini (&tmp.base);
-
- alpha = pattern->alpha * 0xffff;
}
else
{
@@ -1042,8 +1009,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
src_x, src_y,
width, height,
&src, &attributes);
- alpha = 0xffff;
}
+ alpha = 0xffff;
if (status)
return status;
@@ -1076,7 +1043,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- color.red = color.green = color.blue = color.alpha = alpha;
+ color.red = color.green = color.blue = color.alpha = 0xffff;
glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1);
glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1);
@@ -1135,7 +1102,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
else
{
cairo_image_surface_t *image;
- char *ptr;
+ unsigned char *ptr;
int stride;
stride = (width + 3) & -4;
@@ -1149,7 +1116,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
memset (data, 0, stride * height);
/* using negative stride */
- ptr = (char *) data + stride * (height - 1);
+ ptr = (unsigned char *) data + stride * (height - 1);
image = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (ptr,
@@ -1166,18 +1133,6 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
(pixman_trapezoid_t *) traps, n_traps);
- if (alpha != 0xffff)
- {
- pixman_color_t color;
-
- color.red = color.green = color.blue = color.alpha = alpha;
-
- pixman_fill_rectangle (PIXMAN_OPERATOR_IN,
- image->pixman_image,
- &color,
- 0, 0, width, height);
- }
-
mask = (cairo_glitz_surface_t *)
_cairo_surface_create_similar_scratch (&dst->base,
CAIRO_FORMAT_A8, 0,
@@ -1228,18 +1183,6 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
}
static cairo_int_status_t
-_cairo_glitz_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
_cairo_glitz_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
@@ -1275,10 +1218,902 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
+static cairo_int_status_t
+_cairo_glitz_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
+{
+ cairo_glitz_surface_t *surface = abstract_surface;
+
+ rectangle->x = 0;
+ rectangle->y = 0;
+ rectangle->width = glitz_surface_get_width (surface->surface);
+ rectangle->height = glitz_surface_get_height (surface->surface);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#define CAIRO_GLITZ_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
+
+#define CAIRO_GLITZ_AREA_AVAILABLE 0
+#define CAIRO_GLITZ_AREA_DIVIDED 1
+#define CAIRO_GLITZ_AREA_OCCUPIED 2
+
+typedef struct _cairo_glitz_root_area cairo_glitz_root_area_t;
+
+typedef struct _cairo_glitz_area {
+ int state;
+ int level;
+ int x, y;
+ int width, height;
+ struct _cairo_glitz_area *area[4];
+ cairo_glitz_root_area_t *root;
+ void *closure;
+} cairo_glitz_area_t;
+
+static cairo_glitz_area_t _empty_area = {
+ 0, 0, 0, 0, 0, 0,
+ { NULL, NULL, NULL, NULL },
+ NULL,
+ NULL
+};
+
+typedef struct _cairo_glitz_area_funcs {
+ cairo_status_t (*move_in) (cairo_glitz_area_t *area,
+ void *closure);
+
+ void (*move_out) (cairo_glitz_area_t *area,
+ void *closure);
+
+ int (*compare_score) (cairo_glitz_area_t *area,
+ void *closure1,
+ void *closure2);
+} cairo_glitz_area_funcs_t;
+
+struct _cairo_glitz_root_area {
+ int max_level;
+ int width, height;
+ cairo_glitz_area_t *area;
+ const cairo_glitz_area_funcs_t *funcs;
+};
+
+static cairo_status_t
+_cairo_glitz_area_move_in (cairo_glitz_area_t *area,
+ void *closure)
+{
+ area->closure = closure;
+ area->state = CAIRO_GLITZ_AREA_OCCUPIED;
+
+ return (*area->root->funcs->move_in) (area, area->closure);
+}
+
+static void
+_cairo_glitz_area_move_out (cairo_glitz_area_t *area)
+{
+ (*area->root->funcs->move_out) (area, area->closure);
+
+ area->closure = NULL;
+ area->state = CAIRO_GLITZ_AREA_AVAILABLE;
+}
+
+static cairo_glitz_area_t *
+_cairo_glitz_area_create (cairo_glitz_root_area_t *root,
+ int level,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ cairo_glitz_area_t *area;
+ int n = 4;
+
+ area = malloc (sizeof (cairo_glitz_area_t));
+ if (!area)
+ return NULL;
+
+ area->level = level;
+ area->x = x;
+ area->y = y;
+ area->width = width;
+ area->height = height;
+ area->root = root;
+ area->closure = NULL;
+ area->state = CAIRO_GLITZ_AREA_AVAILABLE;
+
+ while (n--)
+ area->area[n] = NULL;
+
+ return area;
+}
+
+static void
+_cairo_glitz_area_destroy (cairo_glitz_area_t *area)
+{
+ if (!area)
+ return;
+
+ if (area->state == CAIRO_GLITZ_AREA_OCCUPIED)
+ {
+ _cairo_glitz_area_move_out (area);
+ }
+ else
+ {
+ int n = 4;
+
+ while (n--)
+ _cairo_glitz_area_destroy (area->area[n]);
+ }
+
+ free (area);
+}
+
+static cairo_glitz_area_t *
+_cairo_glitz_area_get_top_scored_sub_area (cairo_glitz_area_t *area)
+{
+ if (!area)
+ return NULL;
+
+ switch (area->state) {
+ case CAIRO_GLITZ_AREA_OCCUPIED:
+ return area;
+ case CAIRO_GLITZ_AREA_AVAILABLE:
+ break;
+ case CAIRO_GLITZ_AREA_DIVIDED: {
+ cairo_glitz_area_t *tmp, *top = NULL;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ tmp = _cairo_glitz_area_get_top_scored_sub_area (area->area[i]);
+ if (tmp && top)
+ {
+ if ((*area->root->funcs->compare_score) (tmp,
+ tmp->closure,
+ top->closure) > 0)
+ top = tmp;
+ }
+ else if (tmp)
+ {
+ top = tmp;
+ }
+ }
+ return top;
+ }
+ }
+
+ return NULL;
+}
+
+static cairo_int_status_t
+_cairo_glitz_area_find (cairo_glitz_area_t *area,
+ int width,
+ int height,
+ cairo_bool_t kick_out,
+ void *closure)
+{
+ if (area->width < width || area->height < height)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ switch (area->state) {
+ case CAIRO_GLITZ_AREA_OCCUPIED:
+ if (kick_out)
+ {
+ if ((*area->root->funcs->compare_score) (area,
+ area->closure,
+ closure) >= 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_glitz_area_move_out (area);
+ } else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* fall-through */
+ case CAIRO_GLITZ_AREA_AVAILABLE: {
+ if (area->level == area->root->max_level ||
+ (area->width == width && area->height == height))
+ {
+ return _cairo_glitz_area_move_in (area, closure);
+ }
+ else
+ {
+ int dx[4], dy[4], w[4], h[4], i;
+
+ dx[0] = dx[2] = dy[0] = dy[1] = 0;
+
+ w[0] = w[2] = dx[1] = dx[3] = width;
+ h[0] = h[1] = dy[2] = dy[3] = height;
+
+ w[1] = w[3] = area->width - width;
+ h[2] = h[3] = area->height - height;
+
+ for (i = 0; i < 2; i++)
+ {
+ if (w[i])
+ area->area[i] =
+ _cairo_glitz_area_create (area->root,
+ area->level + 1,
+ area->x + dx[i],
+ area->y + dy[i],
+ w[i], h[i]);
+ }
+
+ for (; i < 4; i++)
+ {
+ if (w[i] && h[i])
+ area->area[i] =
+ _cairo_glitz_area_create (area->root,
+ area->level + 1,
+ area->x + dx[i],
+ area->y + dy[i],
+ w[i], h[i]);
+ }
+
+ area->state = CAIRO_GLITZ_AREA_DIVIDED;
+
+ if (CAIRO_OK (_cairo_glitz_area_find (area->area[0],
+ width, height,
+ kick_out, closure)))
+ return CAIRO_STATUS_SUCCESS;
+ }
+ } break;
+ case CAIRO_GLITZ_AREA_DIVIDED: {
+ cairo_glitz_area_t *to_area;
+ int i, rejected = FALSE;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (area->area[i])
+ {
+ if (area->area[i]->width >= width &&
+ area->area[i]->height >= height)
+ {
+ if (CAIRO_OK (_cairo_glitz_area_find (area->area[i],
+ width, height,
+ kick_out, closure)))
+ return CAIRO_STATUS_SUCCESS;
+
+ rejected = TRUE;
+ }
+ }
+ }
+
+ if (rejected)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ to_area = _cairo_glitz_area_get_top_scored_sub_area (area);
+ if (to_area)
+ {
+ if (kick_out)
+ {
+ if ((*area->root->funcs->compare_score) (to_area,
+ to_area->closure,
+ closure) >= 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ } else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ _cairo_glitz_area_destroy (area->area[i]);
+ area->area[i] = NULL;
+ }
+
+ area->closure = NULL;
+ area->state = CAIRO_GLITZ_AREA_AVAILABLE;
+ if (CAIRO_OK (_cairo_glitz_area_find (area, width, height,
+ TRUE, closure)))
+ return CAIRO_STATUS_SUCCESS;
+
+ } break;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_glitz_root_area_init (cairo_glitz_root_area_t *root,
+ int max_level,
+ int width,
+ int height,
+ const cairo_glitz_area_funcs_t *funcs)
+{
+ root->max_level = max_level;
+ root->funcs = funcs;
+
+ root->area = _cairo_glitz_area_create (root, 0, 0, 0, width, height);
+ if (!root->area)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_glitz_root_area_fini (cairo_glitz_root_area_t *root)
+{
+ _cairo_glitz_area_destroy (root->area);
+}
+
+#define GLYPH_CACHE_TEXTURE_SIZE 512
+#define GLYPH_CACHE_MAX_LEVEL 64
+#define GLYPH_CACHE_MAX_HEIGHT 72
+#define GLYPH_CACHE_MAX_WIDTH 72
+
+#define WRITE_VEC2(ptr, _x, _y) \
+ *(ptr)++ = (_x); \
+ *(ptr)++ = (_y)
+
+#define WRITE_BOX(ptr, _vx1, _vy1, _vx2, _vy2, p1, p2) \
+ WRITE_VEC2 (ptr, _vx1, _vy1); \
+ WRITE_VEC2 (ptr, (p1)->x, (p2)->y); \
+ WRITE_VEC2 (ptr, _vx2, _vy1); \
+ WRITE_VEC2 (ptr, (p2)->x, (p2)->y); \
+ WRITE_VEC2 (ptr, _vx2, _vy2); \
+ WRITE_VEC2 (ptr, (p2)->x, (p1)->y); \
+ WRITE_VEC2 (ptr, _vx1, _vy2); \
+ WRITE_VEC2 (ptr, (p1)->x, (p1)->y)
+
+typedef struct _cairo_glitz_glyph_cache {
+ cairo_cache_t base;
+ cairo_glitz_root_area_t root;
+ glitz_surface_t *surface;
+} cairo_glitz_glyph_cache_t;
+
+typedef struct {
+ cairo_glyph_cache_key_t key;
+ int refcount;
+ cairo_glyph_size_t size;
+ cairo_glitz_area_t *area;
+ cairo_bool_t locked;
+ cairo_point_double_t p1, p2;
+} cairo_glitz_glyph_cache_entry_t;
+
+static cairo_status_t
+_cairo_glitz_glyph_move_in (cairo_glitz_area_t *area,
+ void *closure)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = closure;
+
+ entry->area = area;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_glitz_glyph_move_out (cairo_glitz_area_t *area,
+ void *closure)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = closure;
+
+ entry->area = NULL;
+}
+
+static int
+_cairo_glitz_glyph_compare (cairo_glitz_area_t *area,
+ void *closure1,
+ void *closure2)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = closure1;
+
+ if (entry->locked)
+ return 1;
+
+ return -1;
+}
+
+static const cairo_glitz_area_funcs_t _cairo_glitz_area_funcs = {
+ _cairo_glitz_glyph_move_in,
+ _cairo_glitz_glyph_move_out,
+ _cairo_glitz_glyph_compare
+};
+
+static cairo_status_t
+_cairo_glitz_glyph_cache_entry_create (void *abstract_cache,
+ void *abstract_key,
+ void **return_entry)
+{
+ cairo_glitz_glyph_cache_entry_t *entry;
+ cairo_glyph_cache_key_t *key = abstract_key;
+
+ entry = malloc (sizeof (cairo_glitz_glyph_cache_entry_t));
+ if (!entry)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ entry->refcount = 1;
+ entry->key = *key;
+ entry->area = NULL;
+ entry->locked = FALSE;
+
+ _cairo_unscaled_font_reference (entry->key.unscaled);
+
+ *return_entry = entry;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_glitz_glyph_cache_entry_destroy (void *abstract_cache,
+ void *abstract_entry)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = abstract_entry;
+
+ entry->refcount--;
+ if (entry->refcount)
+ return;
+
+ if (entry->area)
+ _cairo_glitz_area_move_out (entry->area);
+
+ _cairo_unscaled_font_destroy (entry->key.unscaled);
+
+ free (entry);
+}
+
+static void
+_cairo_glitz_glyph_cache_entry_reference (void *abstract_entry)
+{
+ cairo_glitz_glyph_cache_entry_t *entry = abstract_entry;
+
+ entry->refcount++;
+}
+
+static void
+_cairo_glitz_glyph_cache_destroy (void *abstract_cache)
+{
+ cairo_glitz_glyph_cache_t *cache = abstract_cache;
+
+ _cairo_glitz_root_area_fini (&cache->root);
+
+ glitz_surface_destroy (cache->surface);
+}
+
+static const cairo_cache_backend_t _cairo_glitz_glyph_cache_backend = {
+ _cairo_glyph_cache_hash,
+ _cairo_glyph_cache_keys_equal,
+ _cairo_glitz_glyph_cache_entry_create,
+ _cairo_glitz_glyph_cache_entry_destroy,
+ _cairo_glitz_glyph_cache_destroy
+};
+
+static cairo_glitz_glyph_cache_t *_cairo_glitz_glyph_caches = NULL;
+
+static cairo_glitz_glyph_cache_t *
+_cairo_glitz_get_glyph_cache (cairo_glitz_surface_t *surface)
+{
+ cairo_glitz_glyph_cache_t *cache;
+ glitz_drawable_t *drawable;
+ glitz_format_t *format;
+
+ /*
+ * FIXME: caches should be thread specific, display specific and screen
+ * specific.
+ */
+
+ if (_cairo_glitz_glyph_caches)
+ return _cairo_glitz_glyph_caches;
+
+ drawable = glitz_surface_get_drawable (surface->surface);
+
+ format = glitz_find_standard_format (drawable, GLITZ_STANDARD_A8);
+ if (!format)
+ return NULL;
+
+ cache = malloc (sizeof (cairo_glitz_glyph_cache_t));
+ if (!cache)
+ return NULL;
+
+ cache->surface =
+ glitz_surface_create (drawable, format,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ 0, NULL);
+ if (!cache->surface)
+ {
+ free (cache);
+ return NULL;
+ }
+
+ if (_cairo_glitz_root_area_init (&cache->root,
+ GLYPH_CACHE_MAX_LEVEL,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ GLYPH_CACHE_TEXTURE_SIZE,
+ &_cairo_glitz_area_funcs))
+ {
+ glitz_surface_destroy (cache->surface);
+ free (cache);
+ return NULL;
+ }
+
+ if (_cairo_cache_init (&cache->base,
+ &_cairo_glitz_glyph_cache_backend,
+ CAIRO_GLITZ_GLYPH_CACHE_MEMORY_DEFAULT))
+ {
+ _cairo_glitz_root_area_fini (&cache->root);
+ glitz_surface_destroy (cache->surface);
+ free (cache);
+ return NULL;
+ }
+
+ _cairo_glitz_glyph_caches = cache;
+
+ return cache;
+}
+
+#define FIXED_TO_FLOAT(f) (((glitz_float_t) (f)) / 65536)
+
+static cairo_status_t
+_cairo_glitz_cache_glyph (cairo_glitz_glyph_cache_t *cache,
+ cairo_glitz_glyph_cache_entry_t *entry,
+ cairo_image_glyph_cache_entry_t *image_entry)
+{
+ glitz_point_fixed_t p1, p2;
+ glitz_pixel_format_t pf;
+ glitz_buffer_t *buffer;
+ pixman_format_t *format;
+ int am, rm, gm, bm;
+
+ entry->size = image_entry->size;
+
+ if (entry->size.width > GLYPH_CACHE_MAX_WIDTH ||
+ entry->size.height > GLYPH_CACHE_MAX_HEIGHT)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (!image_entry->image)
+ {
+ entry->area = &_empty_area;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ format = pixman_image_get_format (image_entry->image->pixman_image);
+ if (!format)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (_cairo_glitz_area_find (cache->root.area,
+ entry->size.width,
+ entry->size.height,
+ FALSE, entry))
+ {
+ if (_cairo_glitz_area_find (cache->root.area,
+ entry->size.width,
+ entry->size.height,
+ TRUE, entry))
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ buffer = glitz_buffer_create_for_data (image_entry->image->data);
+ if (!buffer)
+ {
+ _cairo_glitz_area_move_out (entry->area);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm);
+
+ pf.masks.alpha_mask = am;
+ pf.masks.red_mask = rm;
+ pf.masks.green_mask = gm;
+ pf.masks.blue_mask = bm;
+
+ pf.bytes_per_line = image_entry->image->stride;
+ pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
+ pf.xoffset = 0;
+ pf.skip_lines = 0;
+
+ glitz_set_pixels (cache->surface,
+ entry->area->x,
+ entry->area->y,
+ entry->size.width,
+ entry->size.height,
+ &pf, buffer);
+
+ glitz_buffer_destroy (buffer);
+
+ p1.x = entry->area->x << 16;
+ p1.y = entry->area->y << 16;
+ p2.x = (entry->area->x + entry->size.width) << 16;
+ p2.y = (entry->area->y + entry->size.height) << 16;
+
+ glitz_surface_translate_point (cache->surface, &p1, &p1);
+ glitz_surface_translate_point (cache->surface, &p2, &p2);
+
+ entry->p1.x = FIXED_TO_FLOAT (p1.x);
+ entry->p1.y = FIXED_TO_FLOAT (p1.y);
+ entry->p2.x = FIXED_TO_FLOAT (p2.x);
+ entry->p2.y = FIXED_TO_FLOAT (p2.y);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#define N_STACK_BUF 256
+
+static cairo_int_status_t
+_cairo_glitz_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t op,
+ cairo_pattern_t *pattern,
+ void *abstract_surface,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_glitz_surface_attributes_t attributes;
+ cairo_glitz_surface_t *dst = abstract_surface;
+ cairo_glitz_surface_t *src;
+ cairo_glitz_glyph_cache_t *cache;
+ cairo_glitz_glyph_cache_entry_t *stack_entries[N_STACK_BUF];
+ cairo_glitz_glyph_cache_entry_t **entries;
+ cairo_glyph_cache_key_t key;
+ glitz_float_t stack_vertices[N_STACK_BUF * 16];
+ glitz_float_t *vertices;
+ glitz_buffer_t *buffer;
+ cairo_int_status_t status;
+ int i, cached_glyphs = 0;
+ int remaining_glyps = num_glyphs;
+ glitz_float_t x1, y1, x2, y2;
+ static glitz_vertex_format_t format = {
+ GLITZ_PRIMITIVE_QUADS,
+ GLITZ_DATA_TYPE_FLOAT,
+ sizeof (glitz_float_t) * 4,
+ GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK,
+ { 0 },
+ {
+ GLITZ_DATA_TYPE_FLOAT,
+ GLITZ_COORDINATE_SIZE_XY,
+ sizeof (glitz_float_t) * 2,
+ }
+ };
+
+ if (op == CAIRO_OPERATOR_SATURATE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (_glitz_ensure_target (dst->surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
+ src_x, src_y,
+ width, height,
+ &src, &attributes);
+ if (status)
+ return status;
+
+ _cairo_glitz_surface_set_attributes (src, &attributes);
+
+ if (num_glyphs > N_STACK_BUF)
+ {
+ char *data;
+
+ data = malloc (num_glyphs * sizeof (void *) +
+ num_glyphs * sizeof (glitz_float_t) * 16);
+ if (!data)
+ goto FAIL1;
+
+ entries = (cairo_glitz_glyph_cache_entry_t **) data;
+ vertices = (glitz_float_t *) (data + num_glyphs * sizeof (void *));
+ }
+ else
+ {
+ entries = stack_entries;
+ vertices = stack_vertices;
+ }
+
+ buffer = glitz_buffer_create_for_data (vertices);
+ if (!buffer)
+ goto FAIL2;
+
+ cache = _cairo_glitz_get_glyph_cache (dst);
+ if (!cache)
+ {
+ num_glyphs = 0;
+ goto UNLOCK;
+ }
+
+ _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key);
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ key.index = glyphs[i].index;
+
+ status = _cairo_cache_lookup (&cache->base,
+ &key,
+ (void **) &entries[i],
+ NULL);
+ if (status)
+ {
+ num_glyphs = i;
+ goto UNLOCK;
+ }
+
+ _cairo_glitz_glyph_cache_entry_reference (entries[i]);
+
+ if (entries[i]->area)
+ {
+ remaining_glyps--;
+
+ if (entries[i]->area->width)
+ {
+ x1 = floor (glyphs[i].x + 0.5) + entries[i]->size.x;
+ y1 = floor (glyphs[i].y + 0.5) + entries[i]->size.y;
+ x2 = x1 + entries[i]->size.width;
+ y2 = y1 + entries[i]->size.height;
+
+ WRITE_BOX (vertices, x1, y1, x2, y2,
+ &entries[i]->p1, &entries[i]->p2);
+
+ entries[i]->locked = TRUE;
+ cached_glyphs++;
+ }
+ }
+ }
+
+ if (remaining_glyps)
+ {
+ cairo_cache_t *image_cache;
+ cairo_image_glyph_cache_entry_t *image_entry;
+ cairo_surface_t *image;
+ cairo_glitz_surface_t *clone;
+
+ _cairo_lock_global_image_glyph_cache ();
+
+ image_cache = _cairo_get_global_image_glyph_cache ();
+ if (!image_cache)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto UNLOCK;
+ }
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ if (!entries[i]->area)
+ {
+ key.index = glyphs[i].index;
+
+ status = _cairo_cache_lookup (image_cache,
+ &key,
+ (void **) &image_entry,
+ NULL);
+ if (status)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+
+ status = _cairo_glitz_cache_glyph (cache,
+ entries[i],
+ image_entry);
+ if (status)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+ }
+
+ x1 = floor (glyphs[i].x + 0.5);
+ y1 = floor (glyphs[i].y + 0.5);
+
+ if (entries[i]->area)
+ {
+ if (entries[i]->area->width)
+ {
+ x1 += entries[i]->size.x;
+ y1 += entries[i]->size.y;
+ x2 = x1 + entries[i]->size.width;
+ y2 = y1 + entries[i]->size.height;
+
+ WRITE_BOX (vertices, x1, y1, x2, y2,
+ &entries[i]->p1, &entries[i]->p2);
+
+ entries[i]->locked = TRUE;
+ cached_glyphs++;
+ }
+ }
+ else
+ {
+ x1 += image_entry->size.x;
+ y1 += image_entry->size.y;
+
+ if (!image_entry->image)
+ continue;
+
+ image = &image_entry->image->base;
+ status =
+ _cairo_glitz_surface_clone_similar (abstract_surface,
+ image,
+ (cairo_surface_t **)
+ &clone);
+ if (status)
+ {
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ clone->surface,
+ dst->surface,
+ src_x + attributes.base.x_offset + x1,
+ src_y + attributes.base.y_offset + y1,
+ 0, 0,
+ x1, y1,
+ image_entry->size.width,
+ image_entry->size.height);
+
+ cairo_surface_destroy (&clone->base);
+
+ if (glitz_surface_get_status (dst->surface) ==
+ GLITZ_STATUS_NOT_SUPPORTED)
+ {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ _cairo_unlock_global_image_glyph_cache ();
+ goto UNLOCK;
+ }
+ }
+ }
+
+ _cairo_unlock_global_image_glyph_cache ();
+ }
+
+ if (cached_glyphs)
+ {
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_VERTEX,
+ (glitz_geometry_format_t *) &format,
+ buffer);
+
+ glitz_set_array (dst->surface, 0, 4, cached_glyphs * 4, 0, 0);
+
+ glitz_composite (_glitz_operator (op),
+ src->surface,
+ cache->surface,
+ dst->surface,
+ src_x + attributes.base.x_offset,
+ src_y + attributes.base.y_offset,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+
+ glitz_set_geometry (dst->surface,
+ GLITZ_GEOMETRY_TYPE_NONE,
+ NULL, NULL);
+ }
+
+UNLOCK:
+ if (cached_glyphs)
+ {
+ for (i = 0; i < num_glyphs; i++)
+ entries[i]->locked = FALSE;
+ }
+
+ for (i = 0; i < num_glyphs; i++)
+ _cairo_glitz_glyph_cache_entry_destroy (cache, entries[i]);
+
+ glitz_buffer_destroy (buffer);
+
+ FAIL2:
+ if (num_glyphs > N_STACK_BUF)
+ free (entries);
+
+ FAIL1:
+ if (attributes.n_params)
+ free (attributes.params);
+
+ _cairo_glitz_pattern_release_surface (dst, src, &attributes);
+
+ if (status)
+ return status;
+
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_create_similar,
- _cairo_glitz_surface_destroy,
- _cairo_glitz_surface_pixels_per_inch,
+ _cairo_glitz_surface_finish,
_cairo_glitz_surface_acquire_source_image,
_cairo_glitz_surface_release_source_image,
_cairo_glitz_surface_acquire_dest_image,
@@ -1287,10 +2122,11 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = {
_cairo_glitz_surface_composite,
_cairo_glitz_surface_fill_rectangles,
_cairo_glitz_surface_composite_trapezoids,
- _cairo_glitz_surface_copy_page,
- _cairo_glitz_surface_show_page,
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_glitz_surface_set_clip_region,
- NULL /* show_glyphs */
+ _cairo_glitz_surface_get_extents,
+ _cairo_glitz_surface_show_glyphs
};
cairo_surface_t *
diff --git a/src/cairo-glitz.h b/src/cairo-glitz.h
index f1917eb28..f5b4f2815 100644
--- a/src/cairo-glitz.h
+++ b/src/cairo-glitz.h
@@ -39,20 +39,19 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_GLITZ_SURFACE
+#if CAIRO_HAS_GLITZ_SURFACE
#include <glitz.h>
CAIRO_BEGIN_DECLS
-void
-cairo_set_target_glitz (cairo_t *cr,
- glitz_surface_t *surface);
-
cairo_surface_t *
cairo_glitz_surface_create (glitz_surface_t *surface);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_GLITZ_SURFACE */
+# error Cairo was not compiled with support for the glitz backend
#endif /* CAIRO_HAS_GLITZ_SURFACE */
+
#endif /* CAIRO_GLITZ_H */
diff --git a/src/cairo-gstate-private.h b/src/cairo-gstate-private.h
new file mode 100644
index 000000000..eeb35b83e
--- /dev/null
+++ b/src/cairo-gstate-private.h
@@ -0,0 +1,80 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#ifndef CAIRO_GSTATE_PRIVATE_H
+#define CAIRO_GSTATE_PRIVATE_H
+
+struct _cairo_gstate {
+ cairo_operator_t operator;
+
+ double tolerance;
+
+ /* stroke style */
+ double line_width;
+ cairo_line_cap_t line_cap;
+ cairo_line_join_t line_join;
+ double miter_limit;
+
+ cairo_fill_rule_t fill_rule;
+
+ double *dash;
+ int num_dashes;
+ double dash_offset;
+
+ char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */
+ cairo_font_slant_t font_slant;
+ cairo_font_weight_t font_weight;
+
+ cairo_font_face_t *font_face;
+ cairo_scaled_font_t *scaled_font; /* Specific to the current CTM */
+
+ cairo_surface_t *surface;
+ int surface_level; /* Used to detect bad nested use */
+
+ cairo_pattern_t *source;
+
+ cairo_clip_rec_t clip;
+
+ cairo_matrix_t font_matrix;
+
+ cairo_matrix_t ctm;
+ cairo_matrix_t ctm_inverse;
+
+ cairo_pen_t pen_regular;
+
+ struct _cairo_gstate *next;
+};
+
+#endif /* CAIRO_GSTATE_PRIVATE_H */
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index d6db560a3..45c729fc9 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -35,10 +36,15 @@
*/
#include <stdlib.h>
-#include <math.h>
#include "cairoint.h"
+#include "cairo-gstate-private.h"
+
+static cairo_status_t
+_cairo_gstate_set_target_surface (cairo_gstate_t *gstate,
+ cairo_surface_t *surface);
+
static cairo_status_t
_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
cairo_pattern_t *src,
@@ -49,11 +55,14 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
static cairo_status_t
_cairo_gstate_ensure_font (cairo_gstate_t *gstate);
+static cairo_status_t
+_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate);
+
static void
_cairo_gstate_unset_font (cairo_gstate_t *gstate);
cairo_gstate_t *
-_cairo_gstate_create ()
+_cairo_gstate_create (cairo_surface_t *target)
{
cairo_status_t status;
cairo_gstate_t *gstate;
@@ -62,7 +71,7 @@ _cairo_gstate_create ()
if (gstate)
{
- status = _cairo_gstate_init (gstate);
+ status = _cairo_gstate_init (gstate, target);
if (status) {
free (gstate);
return NULL;
@@ -73,8 +82,11 @@ _cairo_gstate_create ()
}
cairo_status_t
-_cairo_gstate_init (cairo_gstate_t *gstate)
+_cairo_gstate_init (cairo_gstate_t *gstate,
+ cairo_surface_t *target)
{
+ cairo_status_t status;
+
gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
@@ -90,32 +102,33 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->num_dashes = 0;
gstate->dash_offset = 0.0;
- gstate->font_family = NULL;
- gstate->font_slant = CAIRO_FONT_SLANT_DEFAULT;
- gstate->font_weight = CAIRO_FONT_WEIGHT_DEFAULT;
-
- gstate->font = NULL;
+ gstate->scaled_font = NULL;
+ gstate->font_face = NULL;
+ cairo_matrix_init_scale (&gstate->font_matrix,
+ CAIRO_GSTATE_DEFAULT_FONT_SIZE,
+ CAIRO_GSTATE_DEFAULT_FONT_SIZE);
+
gstate->surface = NULL;
+ gstate->surface_level = 0;
gstate->clip.region = NULL;
gstate->clip.surface = NULL;
-
- gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0);
- if (!gstate->pattern)
- return CAIRO_STATUS_NO_MEMORY;
- gstate->alpha = 1.0;
-
- gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
- _cairo_gstate_default_matrix (gstate);
+ gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
+ if (!gstate->source)
+ return CAIRO_STATUS_NO_MEMORY;
- _cairo_path_init (&gstate->path);
+ _cairo_gstate_identity_matrix (gstate);
_cairo_pen_init_empty (&gstate->pen_regular);
gstate->next = NULL;
+ status = _cairo_gstate_set_target_surface (gstate, target);
+ if (status)
+ return status;
+
return CAIRO_STATUS_SUCCESS;
}
@@ -138,51 +151,41 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
}
- if (other->font_family) {
- gstate->font_family = strdup (other->font_family);
- if (!gstate->font_family)
- goto CLEANUP_DASH;
- }
-
- if (other->font) {
- gstate->font = other->font;
- cairo_font_reference (gstate->font);
- }
-
if (other->clip.region)
{
gstate->clip.region = pixman_region_create ();
pixman_region_copy (gstate->clip.region, other->clip.region);
}
+ if (gstate->font_face)
+ cairo_font_face_reference (gstate->font_face);
+
+ if (gstate->scaled_font)
+ cairo_scaled_font_reference (gstate->scaled_font);
+
cairo_surface_reference (gstate->surface);
cairo_surface_reference (gstate->clip.surface);
- cairo_pattern_reference (gstate->pattern);
+ cairo_pattern_reference (gstate->source);
- status = _cairo_path_init_copy (&gstate->path, &other->path);
+ status = _cairo_pen_init_copy (&gstate->pen_regular, &other->pen_regular);
if (status)
goto CLEANUP_FONT;
- status = _cairo_pen_init_copy (&gstate->pen_regular, &other->pen_regular);
+ status = _cairo_surface_begin (gstate->surface);
if (status)
- goto CLEANUP_PATH;
+ goto CLEANUP_PEN;
+ gstate->surface_level = gstate->surface->level;
return status;
- CLEANUP_PATH:
- _cairo_path_fini (&gstate->path);
+ CLEANUP_PEN:
+ _cairo_pen_fini (&gstate->pen_regular);
CLEANUP_FONT:
- cairo_font_destroy (gstate->font);
- gstate->font = NULL;
+ cairo_scaled_font_destroy (gstate->scaled_font);
+ gstate->scaled_font = NULL;
- if (gstate->font_family) {
- free (gstate->font_family);
- gstate->font_family = NULL;
- }
-
- CLEANUP_DASH:
free (gstate->dash);
gstate->dash = NULL;
@@ -192,15 +195,17 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
void
_cairo_gstate_fini (cairo_gstate_t *gstate)
{
- if (gstate->font_family)
- free (gstate->font_family);
+ if (gstate->font_face)
+ cairo_font_face_destroy (gstate->font_face);
- if (gstate->font)
- cairo_font_destroy (gstate->font);
+ if (gstate->scaled_font)
+ cairo_scaled_font_destroy (gstate->scaled_font);
- if (gstate->surface)
+ if (gstate->surface) {
+ _cairo_surface_end (gstate->surface);
cairo_surface_destroy (gstate->surface);
- gstate->surface = NULL;
+ gstate->surface = NULL;
+ }
if (gstate->clip.surface)
cairo_surface_destroy (gstate->clip.surface);
@@ -210,14 +215,7 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
pixman_region_destroy (gstate->clip.region);
gstate->clip.region = NULL;
- cairo_pattern_destroy (gstate->pattern);
-
- _cairo_matrix_fini (&gstate->font_matrix);
-
- _cairo_matrix_fini (&gstate->ctm);
- _cairo_matrix_fini (&gstate->ctm_inverse);
-
- _cairo_path_fini (&gstate->path);
+ cairo_pattern_destroy (gstate->source);
_cairo_pen_fini (&gstate->pen_regular);
@@ -253,28 +251,12 @@ _cairo_gstate_clone (cairo_gstate_t *gstate)
return clone;
}
-cairo_status_t
-_cairo_gstate_copy (cairo_gstate_t *dest, cairo_gstate_t *src)
-{
- cairo_status_t status;
- cairo_gstate_t *next;
-
- /* Preserve next pointer over fini/init */
- next = dest->next;
- _cairo_gstate_fini (dest);
- status = _cairo_gstate_init_copy (dest, src);
- dest->next = next;
-
- return status;
-}
-
/* Push rendering off to an off-screen group. */
/* XXX: Rethinking this API
cairo_status_t
_cairo_gstate_begin_group (cairo_gstate_t *gstate)
{
Pixmap pix;
- cairo_color_t clear;
unsigned int width, height;
gstate->parent_surface = gstate->surface;
@@ -295,12 +277,9 @@ _cairo_gstate_begin_group (cairo_gstate_t *gstate)
_cairo_surface_set_drawableWH (gstate->surface, pix, width, height);
- _cairo_color_init (&clear);
- _cairo_color_set_alpha (&clear, 0);
-
status = _cairo_surface_fill_rectangle (gstate->surface,
- CAIRO_OPERATOR_SRC,
- &clear,
+ CAIRO_OPERATOR_SOURCE,
+ &CAIRO_COLOR_TRANSPARENT,
0, 0,
_cairo_surface_get_width (gstate->surface),
_cairo_surface_get_height (gstate->surface));
@@ -325,7 +304,6 @@ _cairo_gstate_end_group (cairo_gstate_t *gstate)
_cairo_surface_init (&mask, gstate->dpy);
_cairo_color_init (&mask_color);
- _cairo_color_set_alpha (&mask_color, gstate->alpha);
_cairo_surface_set_solid_color (&mask, &mask_color);
@@ -355,73 +333,93 @@ _cairo_gstate_end_group (cairo_gstate_t *gstate)
}
*/
-cairo_status_t
+static cairo_status_t
_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface)
{
- double scale;
+ cairo_status_t status;
+
+ if (gstate->surface == surface)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (surface) {
+ status = _cairo_surface_begin_reset_clip (surface);
+ if (!CAIRO_OK (status))
+ return status;
+ }
_cairo_gstate_unset_font (gstate);
- if (gstate->surface)
+ if (gstate->surface) {
+ _cairo_surface_end (gstate->surface);
cairo_surface_destroy (gstate->surface);
+ }
gstate->surface = surface;
/* Sometimes the user wants to return to having no target surface,
* (just like after cairo_create). This can be useful for forcing
* the old surface to be destroyed. */
- if (surface == NULL)
+ if (surface == NULL) {
+ gstate->surface_level = 0;
return CAIRO_STATUS_SUCCESS;
+ }
cairo_surface_reference (gstate->surface);
+ gstate->surface_level = surface->level;
- scale = _cairo_surface_pixels_per_inch (surface) / gstate->pixels_per_inch;
- _cairo_gstate_scale (gstate, scale, scale);
- gstate->pixels_per_inch = _cairo_surface_pixels_per_inch (surface);
+ _cairo_gstate_identity_matrix (gstate);
return CAIRO_STATUS_SUCCESS;
}
-/* XXX: Need to decide the memory mangement semantics of this
- function. Should it reference the surface again? */
cairo_surface_t *
-_cairo_gstate_current_target_surface (cairo_gstate_t *gstate)
+_cairo_gstate_get_target (cairo_gstate_t *gstate)
{
if (gstate == NULL)
return NULL;
-/* XXX: Do we want this?
- if (gstate->surface)
- _cairo_surface_reference (gstate->surface);
-*/
-
return gstate->surface;
}
cairo_status_t
-_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern)
+_cairo_gstate_set_source (cairo_gstate_t *gstate,
+ cairo_pattern_t *source)
{
- if (pattern == NULL)
+ if (source == NULL)
return CAIRO_STATUS_NULL_POINTER;
- cairo_pattern_reference (pattern);
- cairo_pattern_destroy (gstate->pattern);
- gstate->pattern = pattern;
+ cairo_pattern_reference (source);
+ cairo_pattern_destroy (gstate->source);
+ gstate->source = source;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gstate_set_source_solid (cairo_gstate_t *gstate,
+ const cairo_color_t *color)
+{
+ cairo_status_t status;
+ cairo_pattern_t *source;
+
+ source = _cairo_pattern_create_solid (color);
+ if (!source)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ status = _cairo_gstate_set_source (gstate, source);
+
+ cairo_pattern_destroy (source);
return CAIRO_STATUS_SUCCESS;
}
cairo_pattern_t *
-_cairo_gstate_current_pattern (cairo_gstate_t *gstate)
+_cairo_gstate_get_source (cairo_gstate_t *gstate)
{
if (gstate == NULL)
return NULL;
-/* XXX: Do we want this?
- cairo_pattern_reference (gstate->pattern);
-*/
-
- return gstate->pattern;
+ return gstate->source;
}
cairo_status_t
@@ -433,30 +431,12 @@ _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator)
}
cairo_operator_t
-_cairo_gstate_current_operator (cairo_gstate_t *gstate)
+_cairo_gstate_get_operator (cairo_gstate_t *gstate)
{
return gstate->operator;
}
cairo_status_t
-_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue)
-{
- cairo_pattern_destroy (gstate->pattern);
-
- gstate->pattern = _cairo_pattern_create_solid (red, green, blue);
- if (!gstate->pattern)
- return CAIRO_STATUS_NO_MEMORY;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_current_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue)
-{
- return _cairo_pattern_get_rgb (gstate->pattern, red, green, blue);
-}
-
-cairo_status_t
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
{
gstate->tolerance = tolerance;
@@ -465,26 +445,12 @@ _cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
}
double
-_cairo_gstate_current_tolerance (cairo_gstate_t *gstate)
+_cairo_gstate_get_tolerance (cairo_gstate_t *gstate)
{
return gstate->tolerance;
}
cairo_status_t
-_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha)
-{
- gstate->alpha = alpha;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-double
-_cairo_gstate_current_alpha (cairo_gstate_t *gstate)
-{
- return gstate->alpha;
-}
-
-cairo_status_t
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule)
{
gstate->fill_rule = fill_rule;
@@ -493,7 +459,7 @@ _cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule
}
cairo_fill_rule_t
-_cairo_gstate_current_fill_rule (cairo_gstate_t *gstate)
+_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate)
{
return gstate->fill_rule;
}
@@ -507,7 +473,7 @@ _cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
}
double
-_cairo_gstate_current_line_width (cairo_gstate_t *gstate)
+_cairo_gstate_get_line_width (cairo_gstate_t *gstate)
{
return gstate->line_width;
}
@@ -521,7 +487,7 @@ _cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
}
cairo_line_cap_t
-_cairo_gstate_current_line_cap (cairo_gstate_t *gstate)
+_cairo_gstate_get_line_cap (cairo_gstate_t *gstate)
{
return gstate->line_cap;
}
@@ -535,7 +501,7 @@ _cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join
}
cairo_line_join_t
-_cairo_gstate_current_line_join (cairo_gstate_t *gstate)
+_cairo_gstate_get_line_join (cairo_gstate_t *gstate)
{
return gstate->line_join;
}
@@ -572,15 +538,15 @@ _cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit)
}
double
-_cairo_gstate_current_miter_limit (cairo_gstate_t *gstate)
+_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate)
{
return gstate->miter_limit;
}
void
-_cairo_gstate_current_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
+_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
{
- cairo_matrix_copy (matrix, &gstate->ctm);
+ *matrix = gstate->ctm;
}
cairo_status_t
@@ -590,10 +556,10 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
_cairo_gstate_unset_font (gstate);
- _cairo_matrix_set_translate (&tmp, tx, ty);
+ cairo_matrix_init_translate (&tmp, tx, ty);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
- _cairo_matrix_set_translate (&tmp, -tx, -ty);
+ cairo_matrix_init_translate (&tmp, -tx, -ty);
cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
return CAIRO_STATUS_SUCCESS;
@@ -609,10 +575,10 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
_cairo_gstate_unset_font (gstate);
- _cairo_matrix_set_scale (&tmp, sx, sy);
+ cairo_matrix_init_scale (&tmp, sx, sy);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
- _cairo_matrix_set_scale (&tmp, 1/sx, 1/sy);
+ cairo_matrix_init_scale (&tmp, 1/sx, 1/sy);
cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
return CAIRO_STATUS_SUCCESS;
@@ -625,24 +591,24 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
_cairo_gstate_unset_font (gstate);
- _cairo_matrix_set_rotate (&tmp, angle);
+ cairo_matrix_init_rotate (&tmp, angle);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
- _cairo_matrix_set_rotate (&tmp, -angle);
+ cairo_matrix_init_rotate (&tmp, -angle);
cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
+_cairo_gstate_transform (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix)
{
cairo_matrix_t tmp;
_cairo_gstate_unset_font (gstate);
- cairo_matrix_copy (&tmp, matrix);
+ tmp = *matrix;
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
cairo_matrix_invert (&tmp);
@@ -652,16 +618,16 @@ _cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
}
cairo_status_t
-_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
+_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix)
{
cairo_status_t status;
_cairo_gstate_unset_font (gstate);
- cairo_matrix_copy (&gstate->ctm, matrix);
+ gstate->ctm = *matrix;
- cairo_matrix_copy (&gstate->ctm_inverse, matrix);
+ gstate->ctm_inverse = *matrix;
status = cairo_matrix_invert (&gstate->ctm_inverse);
if (status)
return status;
@@ -670,37 +636,18 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate,
}
cairo_status_t
-_cairo_gstate_default_matrix (cairo_gstate_t *gstate)
-{
- int scale = gstate->pixels_per_inch / CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT + 0.5;
- if (scale == 0)
- scale = 1;
-
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_set_identity (&gstate->font_matrix);
-
- cairo_matrix_set_identity (&gstate->ctm);
- cairo_matrix_scale (&gstate->ctm, scale, scale);
- cairo_matrix_copy (&gstate->ctm_inverse, &gstate->ctm);
- cairo_matrix_invert (&gstate->ctm_inverse);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
{
_cairo_gstate_unset_font (gstate);
- cairo_matrix_set_identity (&gstate->ctm);
- cairo_matrix_set_identity (&gstate->ctm_inverse);
+ cairo_matrix_init_identity (&gstate->ctm);
+ cairo_matrix_init_identity (&gstate->ctm_inverse);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_transform_point (cairo_gstate_t *gstate, double *x, double *y)
+_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y)
{
cairo_matrix_transform_point (&gstate->ctm, x, y);
@@ -708,7 +655,8 @@ _cairo_gstate_transform_point (cairo_gstate_t *gstate, double *x, double *y)
}
cairo_status_t
-_cairo_gstate_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy)
+_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate,
+ double *dx, double *dy)
{
cairo_matrix_transform_distance (&gstate->ctm, dx, dy);
@@ -716,7 +664,7 @@ _cairo_gstate_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy
}
cairo_status_t
-_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y)
+_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y)
{
cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
@@ -724,610 +672,297 @@ _cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double
}
cairo_status_t
-_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy)
+_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate,
+ double *dx, double *dy)
{
cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy);
return CAIRO_STATUS_SUCCESS;
}
-cairo_status_t
-_cairo_gstate_new_path (cairo_gstate_t *gstate)
-{
- _cairo_path_fini (&gstate->path);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y)
+void
+_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
{
- cairo_point_t point;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
-
- return _cairo_path_move_to (&gstate->path, &point);
+ cairo_matrix_transform_point (&gstate->ctm, x, y);
+ if (gstate->surface) {
+ *x += gstate->surface->device_x_offset;
+ *y += gstate->surface->device_y_offset;
+ }
}
-cairo_status_t
-_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y)
+void
+_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
{
- cairo_point_t point;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
-
- return _cairo_path_line_to (&gstate->path, &point);
+ if (gstate->surface) {
+ *x -= gstate->surface->device_x_offset;
+ *y -= gstate->surface->device_y_offset;
+ }
+ cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
}
+/* XXX: NYI
cairo_status_t
-_cairo_gstate_curve_to (cairo_gstate_t *gstate,
- double x0, double y0,
- double x1, double y1,
- double x2, double y2)
-{
- cairo_point_t p0, p1, p2;
-
- cairo_matrix_transform_point (&gstate->ctm, &x0, &y0);
- cairo_matrix_transform_point (&gstate->ctm, &x1, &y1);
- cairo_matrix_transform_point (&gstate->ctm, &x2, &y2);
-
- p0.x = _cairo_fixed_from_double (x0);
- p0.y = _cairo_fixed_from_double (y0);
-
- p1.x = _cairo_fixed_from_double (x1);
- p1.y = _cairo_fixed_from_double (y1);
-
- p2.x = _cairo_fixed_from_double (x2);
- p2.y = _cairo_fixed_from_double (y2);
-
- return _cairo_path_curve_to (&gstate->path, &p0, &p1, &p2);
-}
-
-/* Spline deviation from the circle in radius would be given by:
-
- error = sqrt (x**2 + y**2) - 1
-
- A simpler error function to work with is:
-
- e = x**2 + y**2 - 1
-
- From "Good approximation of circles by curvature-continuous Bezier
- curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
- Design 8 (1990) 22-41, we learn:
-
- abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
-
- and
- abs (error) =~ 1/2 * e
-
- Of course, this error value applies only for the particular spline
- approximation that is used in _cairo_gstate_arc_segment.
-*/
-static double
-_arc_error_normalized (double angle)
-{
- return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
-}
-
-static double
-_arc_max_angle_for_tolerance_normalized (double tolerance)
-{
- double angle, error;
- int i;
-
- /* Use table lookup to reduce search time in most cases. */
- struct {
- double angle;
- double error;
- } table[] = {
- { M_PI / 1.0, 0.0185185185185185036127 },
- { M_PI / 2.0, 0.000272567143730179811158 },
- { M_PI / 3.0, 2.38647043651461047433e-05 },
- { M_PI / 4.0, 4.2455377443222443279e-06 },
- { M_PI / 5.0, 1.11281001494389081528e-06 },
- { M_PI / 6.0, 3.72662000942734705475e-07 },
- { M_PI / 7.0, 1.47783685574284411325e-07 },
- { M_PI / 8.0, 6.63240432022601149057e-08 },
- { M_PI / 9.0, 3.2715520137536980553e-08 },
- { M_PI / 10.0, 1.73863223499021216974e-08 },
- { M_PI / 11.0, 9.81410988043554039085e-09 },
- };
- int table_size = (sizeof (table) / sizeof (table[0]));
-
- for (i = 0; i < table_size; i++)
- if (table[i].error < tolerance)
- return table[i].angle;
-
- ++i;
- do {
- angle = M_PI / i++;
- error = _arc_error_normalized (angle);
- } while (error > tolerance);
-
- return angle;
-}
-
-static int
-_cairo_gstate_arc_segments_needed (cairo_gstate_t *gstate,
- double angle,
- double radius)
-{
- double l1, l2, lmax;
- double max_angle;
-
- _cairo_matrix_compute_eigen_values (&gstate->ctm, &l1, &l2);
-
- l1 = fabs (l1);
- l2 = fabs (l2);
- if (l1 > l2)
- lmax = l1;
- else
- lmax = l2;
-
- max_angle = _arc_max_angle_for_tolerance_normalized (gstate->tolerance / (radius * lmax));
-
- return (int) ceil (angle / max_angle);
-}
-
-/* We want to draw a single spline approximating a circular arc radius
- R from angle A to angle B. Since we want a symmetric spline that
- matches the endpoints of the arc in position and slope, we know
- that the spline control points must be:
-
- (R * cos(A), R * sin(A))
- (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
- (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
- (R * cos(B), R * sin(B))
-
- for some value of h.
-
- "Approximation of circular arcs by cubic poynomials", Michael
- Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
- various values of h along with error analysis for each.
-
- From that paper, a very practical value of h is:
-
- h = 4/3 * tan(angle/4)
-
- This value does not give the spline with minimal error, but it does
- provide a very good approximation, (6th-order convergence), and the
- error expression is quite simple, (see the comment for
- _arc_error_normalized).
-*/
-static cairo_status_t
-_cairo_gstate_arc_segment (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle_A, double angle_B)
+_cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
{
cairo_status_t status;
- double r_sin_A, r_cos_A;
- double r_sin_B, r_cos_B;
- double h;
-
- r_sin_A = radius * sin (angle_A);
- r_cos_A = radius * cos (angle_A);
- r_sin_B = radius * sin (angle_B);
- r_cos_B = radius * cos (angle_B);
-
- h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
-
- status = _cairo_gstate_curve_to (gstate,
- xc + r_cos_A - h * r_sin_A, yc + r_sin_A + h * r_cos_A,
- xc + r_cos_B + h * r_sin_B, yc + r_sin_B - h * r_cos_B,
- xc + r_cos_B, yc + r_sin_B);
- if (status)
- return status;
+ _cairo_pen_init (&gstate);
return CAIRO_STATUS_SUCCESS;
}
+*/
-static cairo_status_t
-_cairo_gstate_arc_dir (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle_min,
- double angle_max,
- cairo_direction_t dir)
+static void
+_cairo_gstate_pattern_transform (cairo_gstate_t *gstate,
+ cairo_pattern_t *pattern)
{
- cairo_status_t status;
-
- while (angle_max - angle_min > 4 * M_PI)
- angle_max -= 2 * M_PI;
-
- /* Recurse if drawing arc larger than pi */
- if (angle_max - angle_min > M_PI) {
- double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
- /* XXX: Something tells me this block could be condensed. */
- if (dir == CAIRO_DIRECTION_FORWARD) {
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_mid, dir);
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_mid, angle_max, dir);
- if (status)
- return status;
- } else {
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_mid, angle_max, dir);
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_mid, dir);
- if (status)
- return status;
- }
- } else {
- int i, segments;
- double angle, angle_step;
-
- segments = _cairo_gstate_arc_segments_needed (gstate,
- angle_max - angle_min,
- radius);
- angle_step = (angle_max - angle_min) / (double) segments;
-
- if (dir == CAIRO_DIRECTION_FORWARD) {
- angle = angle_min;
- } else {
- angle = angle_max;
- angle_step = - angle_step;
- }
-
- for (i = 0; i < segments; i++, angle += angle_step) {
- _cairo_gstate_arc_segment (gstate,
- xc, yc,
- radius,
- angle,
- angle + angle_step);
- }
-
- }
+ cairo_matrix_t tmp_matrix = gstate->ctm_inverse;
+
+ if (gstate->surface)
+ cairo_matrix_translate (&tmp_matrix,
+ - gstate->surface->device_x_offset,
+ - gstate->surface->device_y_offset);
- return CAIRO_STATUS_SUCCESS;
+ _cairo_pattern_transform (pattern, &tmp_matrix);
}
cairo_status_t
-_cairo_gstate_arc (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2)
+_cairo_gstate_paint (cairo_gstate_t *gstate)
{
+ cairo_rectangle_t rectangle;
cairo_status_t status;
+ cairo_box_t box;
+ cairo_traps_t traps;
- if (radius <= 0.0)
- return CAIRO_STATUS_SUCCESS;
-
- while (angle2 < angle1)
- angle2 += 2 * M_PI;
-
- status = _cairo_gstate_line_to (gstate,
- xc + radius * cos (angle1),
- yc + radius * sin (angle1));
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle1, angle2, CAIRO_DIRECTION_FORWARD);
- if (status)
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
+ status = _cairo_surface_get_clip_extents (gstate->surface, &rectangle);
+ if (!CAIRO_OK (status))
return status;
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2)
-{
- cairo_status_t status;
-
- if (radius <= 0.0)
- return CAIRO_STATUS_SUCCESS;
-
- while (angle2 > angle1)
- angle2 -= 2 * M_PI;
-
- status = _cairo_gstate_line_to (gstate,
- xc + radius * cos (angle1),
- yc + radius * sin (angle1));
- if (status)
+ box.p1.x = _cairo_fixed_from_int (rectangle.x);
+ box.p1.y = _cairo_fixed_from_int (rectangle.y);
+ box.p2.x = _cairo_fixed_from_int (rectangle.x + rectangle.width);
+ box.p2.y = _cairo_fixed_from_int (rectangle.y + rectangle.height);
+ status = _cairo_traps_init_box (&traps, &box);
+ if (!CAIRO_OK (status))
return status;
+
+ _cairo_gstate_clip_and_composite_trapezoids (gstate,
+ gstate->source,
+ gstate->operator,
+ gstate->surface,
+ &traps);
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle2, angle1, CAIRO_DIRECTION_REVERSE);
- if (status)
- return status;
+ _cairo_traps_fini (&traps);
return CAIRO_STATUS_SUCCESS;
}
-/* XXX: NYI
-cairo_status_t
-_cairo_gstate_arc_to (cairo_gstate_t *gstate,
- double x1, double y1,
- double x2, double y2,
- double radius)
-{
-
-}
-*/
-
-cairo_status_t
-_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy)
-{
- cairo_distance_t distance;
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
-
- distance.dx = _cairo_fixed_from_double (dx);
- distance.dy = _cairo_fixed_from_double (dy);
-
- return _cairo_path_rel_move_to (&gstate->path, &distance);
-}
-
-cairo_status_t
-_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy)
-{
- cairo_distance_t distance;
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
-
- distance.dx = _cairo_fixed_from_double (dx);
- distance.dy = _cairo_fixed_from_double (dy);
-
- return _cairo_path_rel_line_to (&gstate->path, &distance);
-}
-
-cairo_status_t
-_cairo_gstate_rel_curve_to (cairo_gstate_t *gstate,
- double dx0, double dy0,
- double dx1, double dy1,
- double dx2, double dy2)
-{
- cairo_distance_t distance[3];
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx0, &dy0);
- cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
- cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
-
- distance[0].dx = _cairo_fixed_from_double (dx0);
- distance[0].dy = _cairo_fixed_from_double (dy0);
-
- distance[1].dx = _cairo_fixed_from_double (dx1);
- distance[1].dy = _cairo_fixed_from_double (dy1);
-
- distance[2].dx = _cairo_fixed_from_double (dx2);
- distance[2].dy = _cairo_fixed_from_double (dy2);
-
- return _cairo_path_rel_curve_to (&gstate->path,
- &distance[0],
- &distance[1],
- &distance[2]);
-}
-
-/* XXX: NYI
-cairo_status_t
-_cairo_gstate_stroke_path (cairo_gstate_t *gstate)
+/* Combines @gstate->clip_surface using the IN operator with
+ * the given intermediate surface, which corresponds to the
+ * rectangle of the destination space given by @extents.
+ */
+static cairo_status_t
+_cairo_gstate_combine_clip_surface (cairo_gstate_t *gstate,
+ cairo_surface_t *intermediate,
+ cairo_rectangle_t *extents)
{
+ cairo_pattern_union_t pattern;
cairo_status_t status;
- _cairo_pen_init (&gstate);
- return CAIRO_STATUS_SUCCESS;
-}
-*/
+ _cairo_pattern_init_for_surface (&pattern.surface,
+ gstate->clip.surface);
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ &pattern.base,
+ NULL,
+ intermediate,
+ extents->x - gstate->clip.rect.x,
+ extents->y - gstate->clip.rect.y,
+ 0, 0,
+ 0, 0,
+ extents->width, extents->height);
+
+ _cairo_pattern_fini (&pattern.base);
-cairo_status_t
-_cairo_gstate_close_path (cairo_gstate_t *gstate)
-{
- return _cairo_path_close_path (&gstate->path);
+ return status;
}
-cairo_status_t
-_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_ret)
-{
- cairo_status_t status;
- cairo_point_t point;
- double x, y;
-
- status = _cairo_path_current_point (&gstate->path, &point);
- if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- x = 0.0;
- y = 0.0;
- } else {
- x = _cairo_fixed_to_double (point.x);
- y = _cairo_fixed_to_double (point.y);
- cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
+/* Creates a region from a cairo_rectangle_t */
+static cairo_status_t
+_region_new_from_rect (cairo_rectangle_t *rect,
+ pixman_region16_t **region)
+{
+ *region = pixman_region_create ();
+ if (pixman_region_union_rect (*region, *region,
+ rect->x, rect->y,
+ rect->width, rect->height) != PIXMAN_REGION_STATUS_SUCCESS) {
+ pixman_region_destroy (*region);
+ return CAIRO_STATUS_NO_MEMORY;
}
- if (x_ret)
- *x_ret = x;
- if (y_ret)
- *y_ret = y;
-
return CAIRO_STATUS_SUCCESS;
}
-typedef struct gstate_path_interpreter {
- cairo_matrix_t ctm_inverse;
- double tolerance;
- cairo_point_t current_point;
-
- cairo_move_to_func_t *move_to;
- cairo_line_to_func_t *line_to;
- cairo_curve_to_func_t *curve_to;
- cairo_close_path_func_t *close_path;
+/* Gets the bounding box of a region as a cairo_rectangle_t */
+static void
+_region_rect_extents (pixman_region16_t *region,
+ cairo_rectangle_t *rect)
+{
+ pixman_box16_t *region_extents = pixman_region_extents (region);
- void *closure;
-} gpi_t;
+ rect->x = region_extents->x1;
+ rect->y = region_extents->y1;
+ rect->width = region_extents->x2 - region_extents->x1;
+ rect->height = region_extents->y2 - region_extents->y1;
+}
+/* Intersects @region with the clipping bounds (both region
+ * and surface) of @gstate
+ */
static cairo_status_t
-_gpi_move_to (void *closure, cairo_point_t *point)
+_cairo_gstate_intersect_clip (cairo_gstate_t *gstate,
+ pixman_region16_t *region)
{
- gpi_t *gpi = closure;
- double x, y;
+ if (gstate->clip.region)
+ pixman_region_intersect (region, gstate->clip.region, region);
- x = _cairo_fixed_to_double (point->x);
- y = _cairo_fixed_to_double (point->y);
+ if (gstate->clip.surface) {
+ pixman_region16_t *clip_rect;
+ cairo_status_t status;
+
+ status = _region_new_from_rect (&gstate->clip.rect, &clip_rect);
+ if (!CAIRO_OK (status))
+ return status;
+
+ if (pixman_region_intersect (region,
+ clip_rect,
+ region) != PIXMAN_REGION_STATUS_SUCCESS)
+ status = CAIRO_STATUS_NO_MEMORY;
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
+ pixman_region_destroy (clip_rect);
- gpi->move_to (gpi->closure, x, y);
- gpi->current_point = *point;
+ if (!CAIRO_OK (status))
+ return status;
+ }
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_gpi_line_to (void *closure, cairo_point_t *point)
+_get_mask_extents (cairo_gstate_t *gstate,
+ cairo_pattern_t *mask,
+ cairo_rectangle_t *extents)
{
- gpi_t *gpi = closure;
- double x, y;
+ cairo_rectangle_t clip_rect;
+ pixman_region16_t *clip_region;
+ cairo_status_t status;
+
+ status = _cairo_surface_get_clip_extents (gstate->surface, &clip_rect);
+ if (!CAIRO_OK (status))
+ return status;
- x = _cairo_fixed_to_double (point->x);
- y = _cairo_fixed_to_double (point->y);
+ status = _region_new_from_rect (&clip_rect, &clip_region);
+ if (!CAIRO_OK (status))
+ return status;
+
+ status = _cairo_gstate_intersect_clip (gstate, clip_region);
+ if (!CAIRO_OK (status))
+ return status;
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
+ _region_rect_extents (clip_region, extents);
- gpi->line_to (gpi->closure, x, y);
- gpi->current_point = *point;
+ pixman_region_destroy (clip_region);
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_gpi_curve_to (void *closure,
- cairo_point_t *p1,
- cairo_point_t *p2,
- cairo_point_t *p3)
+cairo_status_t
+_cairo_gstate_mask (cairo_gstate_t *gstate,
+ cairo_pattern_t *mask)
{
- gpi_t *gpi = closure;
+ cairo_rectangle_t extents;
+ cairo_pattern_union_t pattern;
+ cairo_surface_pattern_t intermediate_pattern;
+ cairo_pattern_t *effective_mask;
cairo_status_t status;
- cairo_spline_t spline;
- double x1, y1, x2, y2, x3, y3;
-
- if (gpi->curve_to) {
- x1 = _cairo_fixed_to_double (p1->x);
- y1 = _cairo_fixed_to_double (p1->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x1, &y1);
-
- x2 = _cairo_fixed_to_double (p2->x);
- y2 = _cairo_fixed_to_double (p2->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x2, &y2);
-
- x3 = _cairo_fixed_to_double (p3->x);
- y3 = _cairo_fixed_to_double (p3->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x3, &y3);
+ int mask_x, mask_y;
- gpi->curve_to (gpi->closure, x1, y1, x2, y2, x3, y3);
- } else {
- cairo_point_t *p0 = &gpi->current_point;
- int i;
- double x, y;
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
+ _get_mask_extents (gstate, mask, &extents);
+
+ if (gstate->clip.surface) {
+ /* When there is clip surface, we'll need to create a
+ * temporary surface that combines the clip and mask
+ */
+ cairo_surface_t *intermediate;
- status = _cairo_spline_init (&spline, p0, p1, p2, p3);
- if (status == CAIRO_INT_STATUS_DEGENERATE)
- return CAIRO_STATUS_SUCCESS;
+ intermediate = cairo_surface_create_similar (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ extents.width,
+ extents.height);
+ if (intermediate == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
- status = _cairo_spline_decompose (&spline, gpi->tolerance);
- if (status)
+ status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
+ mask, NULL, intermediate,
+ extents.x, extents.y,
+ 0, 0,
+ 0, 0,
+ extents.width, extents.height);
+ if (!CAIRO_OK (status)) {
+ cairo_surface_destroy (intermediate);
return status;
-
- for (i=1; i < spline.num_points; i++) {
- x = _cairo_fixed_to_double (spline.points[i].x);
- y = _cairo_fixed_to_double (spline.points[i].y);
-
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
-
- gpi->line_to (gpi->closure, x, y);
}
- }
-
- gpi->current_point = *p3;
-
- return CAIRO_STATUS_SUCCESS;
-}
+
+ status = _cairo_gstate_combine_clip_surface (gstate, intermediate, &extents);
+ if (!CAIRO_OK (status)) {
+ cairo_surface_destroy (intermediate);
+ return status;
+ }
+
+ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+ cairo_surface_destroy (intermediate);
-static cairo_status_t
-_gpi_close_path (void *closure)
-{
- gpi_t *gpi = closure;
+ effective_mask = &intermediate_pattern.base;
+ mask_x = extents.x;
+ mask_y = extents.y;
+
+ } else {
+ effective_mask = mask;
+ mask_x = mask_y = 0;
+ }
- gpi->close_path (gpi->closure);
+ _cairo_pattern_init_copy (&pattern.base, gstate->source);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
- gpi->current_point.x = 0;
- gpi->current_point.y = 0;
+ status = _cairo_surface_composite (gstate->operator,
+ &pattern.base,
+ effective_mask,
+ gstate->surface,
+ extents.x, extents.y,
+ extents.x - mask_x, extents.y - mask_y,
+ extents.x, extents.y,
+ extents.width, extents.height);
- return CAIRO_STATUS_SUCCESS;
-}
+ if (gstate->clip.surface)
+ _cairo_pattern_fini (&intermediate_pattern.base);
-/* It's OK for curve_path to be NULL. In that case, all curves in the
- path will be decomposed into one or more calls to the line_to
- function, (according to the current tolerance). */
-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,
- cairo_curve_to_func_t *curve_to,
- cairo_close_path_func_t *close_path,
- void *closure)
-{
- cairo_path_t path;
- gpi_t gpi;
-
- /* Anything we want from gstate must be copied. We must not retain
- pointers into gstate. */
- _cairo_path_init_copy (&path, &gstate->path);
-
- cairo_matrix_copy (&gpi.ctm_inverse, &gstate->ctm_inverse);
- gpi.tolerance = gstate->tolerance;
-
- gpi.move_to = move_to;
- gpi.line_to = line_to;
- gpi.curve_to = curve_to;
- gpi.close_path = close_path;
- gpi.closure = closure;
-
- gpi.current_point.x = 0;
- gpi.current_point.y = 0;
-
- return _cairo_path_interpret (&path,
- CAIRO_DIRECTION_FORWARD,
- _gpi_move_to,
- _gpi_line_to,
- _gpi_curve_to,
- _gpi_close_path,
- &gpi);
-}
-
-/* XXX: gstate->alpha will be going away before too long, and when it
- * does, it may make sense for this function to just disappear.
- */
-static void
-_cairo_gstate_pattern_init_copy (cairo_gstate_t *gstate,
- cairo_pattern_union_t *pattern,
- cairo_pattern_t *src)
-{
- _cairo_pattern_init_copy (&pattern->base, src);
- _cairo_pattern_transform (&pattern->base, &gstate->ctm_inverse);
- _cairo_pattern_set_alpha (&pattern->base, gstate->alpha);
+ return status;
}
cairo_status_t
-_cairo_gstate_stroke (cairo_gstate_t *gstate)
+_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_traps_t traps;
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
if (gstate->line_width <= 0.0)
return CAIRO_STATUS_SUCCESS;
@@ -1335,41 +970,40 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate)
_cairo_traps_init (&traps);
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_stroke_to_traps (path, gstate, &traps);
if (status) {
_cairo_traps_fini (&traps);
return status;
}
_cairo_gstate_clip_and_composite_trapezoids (gstate,
- gstate->pattern,
+ gstate->source,
gstate->operator,
gstate->surface,
&traps);
_cairo_traps_fini (&traps);
- _cairo_gstate_new_path (gstate);
-
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret)
+_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
+ double x,
+ double y,
+ cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
+ _cairo_gstate_user_to_backend (gstate, &x, &y);
_cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
_cairo_traps_init (&traps);
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_stroke_to_traps (path, gstate, &traps);
if (status)
goto BAIL;
@@ -1433,6 +1067,119 @@ _cairo_rectangle_empty (cairo_rectangle_t *rect)
return rect->width == 0 || rect->height == 0;
}
+/* Given a region representing a set of trapezoids that will be
+ * drawn, clip the region according to the gstate and compute
+ * the overall extents.
+ */
+static cairo_status_t
+_clip_and_compute_extents_region (cairo_gstate_t *gstate,
+ pixman_region16_t *trap_region,
+ cairo_rectangle_t *extents)
+{
+ cairo_status_t status;
+
+ status = _cairo_gstate_intersect_clip (gstate, trap_region);
+ if (!CAIRO_OK (status))
+ return status;
+
+ _region_rect_extents (trap_region, extents);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Given a a set of trapezoids to draw, find a bounding box (non-exact)
+ * of the trapezoids clipped by the gstate
+ */
+static cairo_status_t
+_clip_and_compute_extents_arbitrary (cairo_gstate_t *gstate,
+ cairo_traps_t *traps,
+ cairo_rectangle_t *extents)
+{
+ cairo_box_t trap_extents;
+
+ _cairo_traps_extents (traps, &trap_extents);
+ _cairo_box_round_to_rectangle (&trap_extents, extents);
+
+ if (gstate->clip.region) {
+ pixman_region16_t *intersection;
+ cairo_status_t status;
+
+ status = _region_new_from_rect (extents, &intersection);
+ if (!CAIRO_OK (status))
+ return status;
+
+ if (pixman_region_intersect (intersection,
+ gstate->clip.region,
+ intersection) == PIXMAN_REGION_STATUS_SUCCESS)
+ _region_rect_extents (intersection, extents);
+ else
+ status = CAIRO_STATUS_NO_MEMORY;
+
+ pixman_region_destroy (intersection);
+
+ if (!CAIRO_OK (status))
+ return status;
+ }
+
+ if (gstate->clip.surface)
+ _cairo_rectangle_intersect (extents, &gstate->clip.rect);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Composites a region representing a set of trapezoids.
+ */
+static cairo_status_t
+_composite_trap_region (cairo_gstate_t *gstate,
+ cairo_pattern_t *src,
+ cairo_operator_t operator,
+ cairo_surface_t *dst,
+ pixman_region16_t *trap_region,
+ cairo_rectangle_t *extents)
+{
+ cairo_status_t status, tmp_status;
+ cairo_pattern_union_t pattern;
+ cairo_pattern_union_t mask;
+ int num_rects = pixman_region_num_rects (trap_region);
+
+ if (num_rects == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (num_rects > 1) {
+ status = _cairo_surface_set_clip_region (dst, trap_region);
+ if (!CAIRO_OK (status))
+ return status;
+ }
+
+ _cairo_pattern_init_copy (&pattern.base, src);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
+
+ if (gstate->clip.surface)
+ _cairo_pattern_init_for_surface (&mask.surface, gstate->clip.surface);
+
+ status = _cairo_surface_composite (gstate->operator,
+ &pattern.base,
+ gstate->clip.surface ? &mask.base : NULL,
+ dst,
+ extents->x, extents->y,
+ extents->x - (gstate->clip.surface ? gstate->clip.rect.x : 0),
+ extents->y - (gstate->clip.surface ? gstate->clip.rect.y : 0),
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ _cairo_pattern_fini (&pattern.base);
+ if (gstate->clip.surface)
+ _cairo_pattern_fini (&mask.base);
+
+ if (num_rects > 1) {
+ tmp_status = _cairo_surface_set_clip_region (dst, gstate->clip.region);
+ if (!CAIRO_OK (tmp_status))
+ status = tmp_status;
+ }
+
+ return status;
+}
+
static void
translate_traps (cairo_traps_t *traps, int x, int y)
{
@@ -1462,6 +1209,145 @@ translate_traps (cairo_traps_t *traps, int x, int y)
}
}
+/* Composites a set of trapezoids in the case where we need to create
+ * an intermediate surface to handle gstate->clip.surface
+ *
+ * Warning: This call modifies the coordinates of traps
+ */
+static cairo_status_t
+_composite_traps_intermediate_surface (cairo_gstate_t *gstate,
+ cairo_pattern_t *src,
+ cairo_operator_t operator,
+ cairo_surface_t *dst,
+ cairo_traps_t *traps,
+ cairo_rectangle_t *extents)
+{
+ cairo_pattern_union_t pattern;
+ cairo_surface_t *intermediate;
+ cairo_surface_pattern_t intermediate_pattern;
+ cairo_status_t status;
+
+ translate_traps (traps, -extents->x, -extents->y);
+
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ extents->width,
+ extents->height,
+ CAIRO_COLOR_TRANSPARENT);
+ if (intermediate == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
+
+ status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
+ &pattern.base,
+ intermediate,
+ extents->x, extents->y,
+ 0, 0,
+ extents->width,
+ extents->height,
+ traps->traps,
+ traps->num_traps);
+ _cairo_pattern_fini (&pattern.base);
+
+ if (!CAIRO_OK (status))
+ goto out;
+
+ status = _cairo_gstate_combine_clip_surface (gstate, intermediate, extents);
+ if (!CAIRO_OK (status))
+ goto out;
+
+ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+ _cairo_pattern_init_copy (&pattern.base, src);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
+
+ status = _cairo_surface_composite (operator,
+ &pattern.base,
+ &intermediate_pattern.base,
+ dst,
+ extents->x, extents->y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ _cairo_pattern_fini (&pattern.base);
+ _cairo_pattern_fini (&intermediate_pattern.base);
+
+ out:
+ cairo_surface_destroy (intermediate);
+
+ return status;
+}
+
+/* Composites a region representing a set of trapezoids in the
+ * case of a solid source (so we can use
+ * _cairo_surface_fill_rectangles).
+ */
+static cairo_status_t
+_composite_trap_region_solid (cairo_gstate_t *gstate,
+ cairo_solid_pattern_t *src,
+ cairo_operator_t operator,
+ cairo_surface_t *dst,
+ pixman_region16_t *region)
+{
+ int num_rects = pixman_region_num_rects (region);
+ pixman_box16_t *boxes = pixman_region_rects (region);
+ cairo_rectangle_t *rects;
+ cairo_status_t status;
+ int i;
+
+ if (!num_rects)
+ return CAIRO_STATUS_SUCCESS;
+
+ rects = malloc (sizeof (pixman_rectangle_t) * num_rects);
+ if (!rects)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ for (i = 0; i < num_rects; i++) {
+ rects[i].x = boxes[i].x1;
+ rects[i].y = boxes[i].y1;
+ rects[i].width = boxes[i].x2 - boxes[i].x1;
+ rects[i].height = boxes[i].y2 - boxes[i].y1;
+ }
+
+ status = _cairo_surface_fill_rectangles (dst, operator,
+ &src->color, rects, num_rects);
+
+ free (rects);
+
+ return status;
+}
+
+/* Composites a set of trapezoids in the general case where
+ gstate->clip.surface == NULL
+ */
+static cairo_status_t
+_composite_traps (cairo_gstate_t *gstate,
+ cairo_pattern_t *src,
+ cairo_operator_t operator,
+ cairo_surface_t *dst,
+ cairo_traps_t *traps,
+ cairo_rectangle_t *extents)
+{
+ cairo_pattern_union_t pattern;
+ cairo_status_t status;
+
+ _cairo_pattern_init_copy (&pattern.base, src);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
+
+ status = _cairo_surface_composite_trapezoids (gstate->operator,
+ &pattern.base, dst,
+ extents->x, extents->y,
+ extents->x, extents->y,
+ extents->width,
+ extents->height,
+ traps->traps,
+ traps->num_traps);
+
+ _cairo_pattern_fini (&pattern.base);
+
+ return status;
+}
/* Warning: This call modifies the coordinates of traps */
static cairo_status_t
@@ -1472,197 +1358,124 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
cairo_traps_t *traps)
{
cairo_status_t status;
- cairo_pattern_union_t pattern;
+ pixman_region16_t *trap_region;
cairo_rectangle_t extents;
- cairo_box_t trap_extents;
-
+
if (traps->num_traps == 0)
return CAIRO_STATUS_SUCCESS;
if (gstate->surface == NULL)
return CAIRO_STATUS_NO_TARGET_SURFACE;
- _cairo_traps_extents (traps, &trap_extents);
- _cairo_box_round_to_rectangle (&trap_extents, &extents);
-
- if (gstate->clip.surface) {
- cairo_surface_t *intermediate;
- cairo_surface_pattern_t intermediate_pattern;
- cairo_color_t empty_color;
-
- _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
-
- if (_cairo_rectangle_empty (&extents)) {
- status = CAIRO_STATUS_SUCCESS;
- goto BAIL1;
- }
-
- translate_traps (traps, -extents.x, -extents.y);
+ status = _cairo_traps_extract_region (traps, &trap_region);
+ if (!CAIRO_OK (status))
+ return status;
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, 0.);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_FORMAT_A8,
- extents.width,
- extents.height,
- &empty_color);
- if (intermediate == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
+ if (trap_region)
+ status = _clip_and_compute_extents_region (gstate, trap_region, &extents);
+ else
+ status = _clip_and_compute_extents_arbitrary (gstate, traps, &extents);
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
-
- status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
- &pattern.base,
- intermediate,
- extents.x, extents.y,
- 0, 0,
- extents.width,
- extents.height,
- traps->traps,
- traps->num_traps);
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto BAIL2;
-
-
- _cairo_pattern_init_for_surface (&pattern.surface,
- gstate->clip.surface);
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &pattern.base,
- NULL,
- intermediate,
- extents.x - gstate->clip.rect.x,
- extents.y - gstate->clip.rect.y,
- 0, 0,
- 0, 0,
- extents.width, extents.height);
- _cairo_pattern_fini (&pattern.base);
+ if (!CAIRO_OK (status))
+ goto out;
- if (status)
- goto BAIL2;
-
- _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
-
- status = _cairo_surface_composite (operator,
- &pattern.base,
- &intermediate_pattern.base,
- dst,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- _cairo_pattern_fini (&pattern.base);
- _cairo_pattern_fini (&intermediate_pattern.base);
-
- BAIL2:
- cairo_surface_destroy (intermediate);
- BAIL1:
+ if (_cairo_rectangle_empty (&extents))
+ /* Nothing to do */
+ goto out;
- if (status)
- return status;
+ if (gstate->clip.surface) {
+ if (trap_region) {
+ /* If we are compositing a set of rectangles, we can set them as the
+ * clip region for the destination surface and use the clip surface
+ * as the mask. A clip region might not be supported, in which case
+ * we fall through to the next method
+ */
+ status = _composite_trap_region (gstate, src, operator, dst,
+ trap_region, &extents);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto out;
+ }
+ /* Handle a clip surface by creating an intermediate surface. */
+ status = _composite_traps_intermediate_surface (gstate, src, operator,
+ dst, traps, &extents);
} else {
- if (gstate->clip.region) {
- pixman_box16_t box;
- pixman_box16_t *intersection_extents;
- pixman_region16_t *rect, *intersection;
-
- box.x1 = _cairo_fixed_integer_floor (trap_extents.p1.x);
- box.y1 = _cairo_fixed_integer_floor (trap_extents.p1.y);
- box.x2 = _cairo_fixed_integer_ceil (trap_extents.p2.x);
- box.y2 = _cairo_fixed_integer_ceil (trap_extents.p2.y);
-
- rect = pixman_region_create_simple (&box);
- if (rect == NULL)
- goto bail1;
- intersection = pixman_region_create();
- if (intersection == NULL)
- goto bail2;
-
- if (pixman_region_intersect (intersection, gstate->clip.region,
- rect) != PIXMAN_REGION_STATUS_SUCCESS)
- goto bail3;
- intersection_extents = pixman_region_extents (intersection);
-
- extents.x = intersection_extents->x1;
- extents.y = intersection_extents->y1;
- extents.width = intersection_extents->x2 - intersection_extents->x1;
- extents.height = intersection_extents->y2 - intersection_extents->y1;
- bail3:
- pixman_region_destroy (intersection);
- bail2:
- pixman_region_destroy (rect);
- bail1:
- ;
+ /* No clip surface */
+ if (trap_region && src->type == CAIRO_PATTERN_SOLID) {
+ /* Solid rectangles are handled specially */
+ status = _composite_trap_region_solid (gstate, (cairo_solid_pattern_t *)src,
+ operator, dst, trap_region);
+ } else if (trap_region && pixman_region_num_rects (trap_region) <= 1) {
+ /* For a simple rectangle, we can just use composite(), for more
+ * rectangles, we'd have to set a clip region. That might still
+ * be a win, but it's less obvious. (Depends on the backend)
+ */
+ status = _composite_trap_region (gstate, src, operator, dst,
+ trap_region, &extents);
+ } else {
+ status = _composite_traps (gstate, src, operator,
+ dst, traps, &extents);
}
-
- _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
-
- status = _cairo_surface_composite_trapezoids (gstate->operator,
- &pattern.base, dst,
- extents.x, extents.y,
- extents.x, extents.y,
- extents.width,
- extents.height,
- traps->traps,
- traps->num_traps);
-
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- return status;
}
+
+ out:
+ if (trap_region)
+ pixman_region_destroy (trap_region);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
cairo_status_t
-_cairo_gstate_fill (cairo_gstate_t *gstate)
+_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_traps_t traps;
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
+ status = _cairo_surface_fill_path (gstate->operator,
+ gstate->source,
+ gstate->surface,
+ path);
+
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
_cairo_traps_init (&traps);
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
if (status) {
_cairo_traps_fini (&traps);
return status;
}
_cairo_gstate_clip_and_composite_trapezoids (gstate,
- gstate->pattern,
+ gstate->source,
gstate->operator,
gstate->surface,
&traps);
_cairo_traps_fini (&traps);
- _cairo_gstate_new_path (gstate);
-
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_in_fill (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret)
+_cairo_gstate_in_fill (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
+ double x,
+ double y,
+ cairo_bool_t *inside_ret)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_traps_t traps;
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
+ _cairo_gstate_user_to_backend (gstate, &x, &y);
_cairo_traps_init (&traps);
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
if (status)
goto BAIL;
@@ -1693,7 +1506,8 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate)
}
cairo_status_t
-_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
+_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
@@ -1701,9 +1515,11 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
cairo_traps_t traps;
cairo_box_t extents;
+ _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
+
_cairo_traps_init (&traps);
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_stroke_to_traps (path, gstate, &traps);
if (status)
goto BAIL;
@@ -1714,8 +1530,8 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
*x2 = _cairo_fixed_to_double (extents.p2.x);
*y2 = _cairo_fixed_to_double (extents.p2.y);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2);
+ _cairo_gstate_backend_to_user (gstate, x1, y1);
+ _cairo_gstate_backend_to_user (gstate, x2, y2);
BAIL:
_cairo_traps_fini (&traps);
@@ -1724,7 +1540,8 @@ BAIL:
}
cairo_status_t
-_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
+_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
@@ -1734,7 +1551,7 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
_cairo_traps_init (&traps);
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
+ status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
if (status)
goto BAIL;
@@ -1745,8 +1562,8 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
*x2 = _cairo_fixed_to_double (extents.p2.x);
*y2 = _cairo_fixed_to_double (extents.p2.y);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2);
+ _cairo_gstate_backend_to_user (gstate, x1, y1);
+ _cairo_gstate_backend_to_user (gstate, x2, y2);
BAIL:
_cairo_traps_fini (&traps);
@@ -1755,8 +1572,11 @@ BAIL:
}
cairo_status_t
-_cairo_gstate_init_clip (cairo_gstate_t *gstate)
+_cairo_gstate_reset_clip (cairo_gstate_t *gstate)
{
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
/* destroy any existing clip-region artifacts */
if (gstate->clip.surface)
cairo_surface_destroy (gstate->clip.surface);
@@ -1774,113 +1594,57 @@ _cairo_gstate_init_clip (cairo_gstate_t *gstate)
return CAIRO_STATUS_SUCCESS;
}
-static int
-extract_transformed_rectangle(cairo_matrix_t *mat,
- cairo_traps_t *tr,
- pixman_box16_t *box)
-{
- double a, b, c, d, tx, ty;
- cairo_status_t st;
-
- st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
- if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.))
- return 0;
-
- if (tr->num_traps == 1
- && tr->traps[0].left.p1.x == tr->traps[0].left.p2.x
- && tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
- && tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
- && tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
- && _cairo_fixed_is_integer(tr->traps[0].left.p1.x)
- && _cairo_fixed_is_integer(tr->traps[0].left.p1.y)
- && _cairo_fixed_is_integer(tr->traps[0].left.p2.x)
- && _cairo_fixed_is_integer(tr->traps[0].left.p2.y)
- && _cairo_fixed_is_integer(tr->traps[0].right.p1.x)
- && _cairo_fixed_is_integer(tr->traps[0].right.p1.y)
- && _cairo_fixed_is_integer(tr->traps[0].right.p2.x)
- && _cairo_fixed_is_integer(tr->traps[0].right.p2.y)) {
-
- box->x1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.x);
- box->x2 = (short) _cairo_fixed_integer_part(tr->traps[0].right.p1.x);
- box->y1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.y);
- box->y2 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p2.y);
- return 1;
- }
- 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)
+_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_status_t status;
cairo_pattern_union_t pattern;
cairo_traps_t traps;
- cairo_color_t white_color;
cairo_box_t extents;
- pixman_box16_t box;
+ pixman_region16_t *region;
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
/* Fill the clip region as traps. */
_cairo_traps_init (&traps);
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
- if (status) {
+ status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
+ if (!CAIRO_OK (status)) {
_cairo_traps_fini (&traps);
return status;
}
/* Check to see if we can represent these traps as a PixRegion. */
- if (extract_transformed_rectangle (&gstate->ctm, &traps, &box)) {
-
- pixman_region16_t *rect = NULL;
- pixman_region16_t *intersection = NULL;
-
+ status = _cairo_traps_extract_region (&traps, &region);
+ if (!CAIRO_OK (status)) {
+ _cairo_traps_fini (&traps);
+ return status;
+ }
+
+ if (region) {
status = CAIRO_STATUS_SUCCESS;
- rect = pixman_region_create_simple (&box);
- if (rect == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
-
+ if (gstate->clip.region == NULL) {
+ gstate->clip.region = region;
} else {
-
- if (gstate->clip.region == NULL) {
- gstate->clip.region = rect;
- } else {
- intersection = pixman_region_create();
- if (pixman_region_intersect (intersection,
- gstate->clip.region, rect)
- == PIXMAN_REGION_STATUS_SUCCESS) {
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = intersection;
- } else {
- status = CAIRO_STATUS_NO_MEMORY;
- }
- pixman_region_destroy (rect);
+ pixman_region16_t *intersection = pixman_region_create();
+
+ if (pixman_region_intersect (intersection,
+ gstate->clip.region, region)
+ == PIXMAN_REGION_STATUS_SUCCESS) {
+ pixman_region_destroy (gstate->clip.region);
+ gstate->clip.region = intersection;
+ } else {
+ status = CAIRO_STATUS_NO_MEMORY;
}
-
- if (!status)
- status = _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
+ pixman_region_destroy (region);
}
+
+ if (CAIRO_OK (status))
+ status = _cairo_surface_set_clip_region (gstate->surface,
+ gstate->clip.region);
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
_cairo_traps_fini (&traps);
@@ -1894,8 +1658,6 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
/* Otherwise represent the clip as a mask surface. */
- _cairo_color_init (&white_color);
-
if (gstate->clip.surface == NULL) {
_cairo_traps_extents (&traps, &extents);
_cairo_box_round_to_rectangle (&extents, &gstate->clip.rect);
@@ -1904,13 +1666,13 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
CAIRO_FORMAT_A8,
gstate->clip.rect.width,
gstate->clip.rect.height,
- &white_color);
+ CAIRO_COLOR_WHITE);
if (gstate->clip.surface == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y);
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
+ _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
&pattern.base,
@@ -1929,254 +1691,77 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
return CAIRO_STATUS_SUCCESS;
}
-cairo_status_t
-_cairo_gstate_show_surface (cairo_gstate_t *gstate,
- cairo_surface_t *surface,
- int width,
- int height)
-{
-
- /* 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.
- * it is the surface argument to this function. The surface has a
- * matrix attached to it which maps "user" space (see below) into
- * image space.
- *
- * - "Device" space is the space of the surface we're ultimately writing
- * pixels to. It is the current surface of the gstate argument to
- * this function.
- *
- * - "User" space is an arbitrary space defined by the user, defined
- * implicitly by the gstate's CTM. The CTM maps from user space to
- * device space. The CTM inverse (which is also kept at all times)
- * maps from device space to user space.
- *
- * - "Clip" space is the space of the surface being used to clip pixels
- * during compositing. Space-wise, it is a bounding box (offset+size)
- * within device space. This surface is usually smaller than the device
- * surface (and possibly the image surface too) and logically occupies
- * a bounding box around the "clip path", situated somewhere in device
- * space. The clip path is already painted on the clip surface.
- *
- * - "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 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
- * so that it can be read and written in device coordinates; in a sense
- * this makes it "spatially compatible" with the clip and device spaces.
- *
- *
- * There is also some confusion about the interaction between a clip and
- * a pattern; it is assumed that in this "show surface" operation a pattern
- * is to be used as an auxiliary alpha mask. this might be wrong, but it's
- * what we're doing now.
- *
- * so, to follow the operations below, remember that in the compositing
- * model, each operation is always of the form ((src IN mask) OP dst).
- * that's the basic operation.
- *
- * so the compositing we are trying to do here, in general, involves 2
- * steps, going via a temporary surface:
- *
- * - combining clip and pattern pixels together into a mask channel.
- * this will be ((pattern IN clip) SRC temporary). it ignores the
- * pixels already in the temporary, overwriting it with the
- * pattern, clipped to the clip mask.
- *
- * - combining temporary and "image" pixels with "device" pixels,
- * with a user-provided porter/duff operator. this will be
- * ((image IN temporary) OP device).
- *
- * if there is no clip, the degenerate case is just the second step
- * with pattern standing in for temporary.
- *
- */
-
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_matrix_t image_to_user, image_to_device;
- double device_x, device_y;
- double device_width, device_height;
- cairo_surface_pattern_t pattern;
- cairo_box_t pattern_extents;
- cairo_rectangle_t extents;
-
- cairo_surface_get_matrix (surface, &image_to_user);
- cairo_matrix_invert (&image_to_user);
- cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm);
-
- _cairo_gstate_current_point (gstate, &device_x, &device_y);
- device_width = width;
- device_height = height;
- _cairo_matrix_transform_bounding_box (&image_to_device,
- &device_x, &device_y,
- &device_width, &device_height);
-
- _cairo_pattern_init_for_surface (&pattern, surface);
-
- /* inherit surface attributes while surface attribute functions still
- exist */
- pattern.base.matrix = surface->matrix;
- pattern.base.filter = surface->filter;
- if (surface->repeat)
- pattern.base.extend = CAIRO_EXTEND_REPEAT;
- else
- pattern.base.extend = CAIRO_EXTEND_NONE;
-
- _cairo_pattern_transform (&pattern.base, &gstate->ctm_inverse);
- _cairo_pattern_set_alpha (&pattern.base, gstate->alpha);
-
- pattern_extents.p1.x = _cairo_fixed_from_double (device_x);
- pattern_extents.p1.y = _cairo_fixed_from_double (device_y);
- pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
- pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
- _cairo_box_round_to_rectangle (&pattern_extents, &extents);
-
- if (gstate->clip.surface)
- {
- _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
-
- /* We only need to composite if the rectangle is not empty. */
- if (!_cairo_rectangle_empty (&extents)) {
- cairo_surface_pattern_t clip_pattern;
-
- _cairo_pattern_init_for_surface (&clip_pattern,
- gstate->clip.surface);
-
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- &clip_pattern.base,
- gstate->surface,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- _cairo_pattern_fini (&clip_pattern.base);
- }
- }
- else
- {
- /* XXX: The rendered size is sometimes 1 or 2 pixels short
- * from what I expect. Need to fix this.
- * KRH: I'm guessing this was due to rounding error when
- * passing double coordinates for integer arguments. Using
- * the extents rectangle should fix this, since it's properly
- * rounded. Is this still the case?
- */
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- NULL,
- gstate->surface,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- }
-
- _cairo_pattern_fini (&pattern.base);
-
- return status;
-}
-
static void
_cairo_gstate_unset_font (cairo_gstate_t *gstate)
{
- if (gstate->font) {
- cairo_font_destroy (gstate->font);
- gstate->font = NULL;
+ if (gstate->scaled_font) {
+ cairo_scaled_font_destroy (gstate->scaled_font);
+ gstate->scaled_font = NULL;
}
}
cairo_status_t
-_cairo_gstate_select_font (cairo_gstate_t *gstate,
- const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight)
+_cairo_gstate_select_font_face (cairo_gstate_t *gstate,
+ const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight)
{
- char *new_family;
+ cairo_font_face_t *font_face;
- new_family = strdup (family);
- if (!new_family)
+ font_face = _cairo_simple_font_face_create (family, slant, weight);
+ if (!font_face)
return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_gstate_unset_font (gstate);
-
- gstate->font_family = new_family;
- gstate->font_slant = slant;
- gstate->font_weight = weight;
- cairo_matrix_set_identity (&gstate->font_matrix);
-
+ _cairo_gstate_set_font_face (gstate, font_face);
+ cairo_font_face_destroy (font_face);
+
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_scale_font (cairo_gstate_t *gstate,
- double scale)
+_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
+ double size)
{
_cairo_gstate_unset_font (gstate);
- return cairo_matrix_scale (&gstate->font_matrix, scale, scale);
+ cairo_matrix_init_scale (&gstate->font_matrix, size, size);
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_transform_font (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
+_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix)
{
- cairo_matrix_t tmp;
- double a, b, c, d, tx, ty;
-
_cairo_gstate_unset_font (gstate);
- cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty);
- cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0);
- return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp);
+ gstate->font_matrix = *matrix;
+
+ return CAIRO_STATUS_SUCCESS;
}
+void
+_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
+ cairo_matrix_t *matrix)
+{
+ *matrix = gstate->font_matrix;
+}
cairo_status_t
-_cairo_gstate_current_font (cairo_gstate_t *gstate,
- cairo_font_t **font)
+_cairo_gstate_get_font_face (cairo_gstate_t *gstate,
+ cairo_font_face_t **font_face)
{
cairo_status_t status;
- status = _cairo_gstate_ensure_font (gstate);
+ status = _cairo_gstate_ensure_font_face (gstate);
if (status)
return status;
- *font = gstate->font;
+ *font_face = gstate->font_face;
return CAIRO_STATUS_SUCCESS;
}
-void
-_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_copy (&gstate->font_matrix, matrix);
-}
-
-void
-_cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- cairo_matrix_copy (matrix, &gstate->font_matrix);
-}
-
/*
* Like everything else in this file, fonts involve Too Many Coordinate Spaces;
* it is easy to get confused about what's going on.
@@ -2191,11 +1776,10 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
* independently scale the user coordinate system *or* the font matrix, in
* order to adjust the rendered size of the font.
*
- * The only font type exposed to the user is cairo_font_t which is a
- * a font specialized to a particular scale matrix, CTM, and target
- * surface. The user is responsible for not using a cairo_font_t
- * after changing the parameters; doing so will produce garbled metrics.
- *
+ * Metrics are returned in user space, whether they are obtained from
+ * the currently selected font in a #cairo_t or from a #cairo_scaled_font_t
+ * which is aa font specialized to a particular scale matrix, CTM, and target
+ * surface.
*
* The font's view
* ---------------
@@ -2254,122 +1838,102 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
*
*/
-void
-_cairo_gstate_current_font_scale (cairo_gstate_t *gstate,
- cairo_font_scale_t *sc)
+static cairo_status_t
+_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate)
{
- cairo_matrix_t tmp;
- double dummy;
- cairo_matrix_multiply (&tmp, &gstate->font_matrix, &gstate->ctm);
- cairo_matrix_get_affine (&tmp,
- &sc->matrix[0][0],
- &sc->matrix[0][1],
- &sc->matrix[1][0],
- &sc->matrix[1][1],
- &dummy, &dummy);
+ if (!gstate->font_face) {
+ gstate->font_face = _cairo_simple_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
+ CAIRO_FONT_SLANT_DEFAULT,
+ CAIRO_FONT_WEIGHT_DEFAULT);
+ if (!gstate->font_face)
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
}
-
+
static cairo_status_t
_cairo_gstate_ensure_font (cairo_gstate_t *gstate)
{
- cairo_font_scale_t sc;
cairo_status_t status;
- const char *family;
- if (gstate->font)
+ if (gstate->scaled_font)
return CAIRO_STATUS_SUCCESS;
- _cairo_gstate_current_font_scale (gstate, &sc);
-
- if (gstate->font_family)
- family = gstate->font_family;
- else
- family = CAIRO_FONT_FAMILY_DEFAULT;
-
- status = _cairo_font_create (family,
- gstate->font_slant,
- gstate->font_weight,
- &sc,
- &gstate->font);
-
+ status = _cairo_gstate_ensure_font_face (gstate);
if (status)
return status;
+ gstate->scaled_font = cairo_scaled_font_create (gstate->font_face,
+ &gstate->font_matrix,
+ &gstate->ctm);
+
+ if (!gstate->scaled_font)
+ return CAIRO_STATUS_NO_MEMORY;
+
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
- cairo_font_extents_t *extents)
+_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
+ cairo_font_extents_t *extents)
{
cairo_status_t status = _cairo_gstate_ensure_font (gstate);
if (status)
return status;
- return cairo_font_extents (gstate->font,
- &gstate->font_matrix,
- extents);
+ return cairo_scaled_font_extents (gstate->scaled_font, extents);
}
cairo_status_t
_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
- const unsigned char *utf8,
+ const char *utf8,
+ double x,
+ double y,
cairo_glyph_t **glyphs,
- int *nglyphs)
+ int *num_glyphs)
{
cairo_status_t status;
-
- cairo_point_t point;
- double origin_x, origin_y;
int i;
status = _cairo_gstate_ensure_font (gstate);
if (status)
return status;
- status = _cairo_path_current_point (&gstate->path, &point);
- if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- origin_x = 0.0;
- origin_y = 0.0;
- } else {
- 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_font_text_to_glyphs (gstate->font,
- utf8, glyphs, nglyphs);
+ status = _cairo_scaled_font_text_to_glyphs (gstate->scaled_font,
+ utf8, glyphs, num_glyphs);
- if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
+ if (status || !glyphs || !num_glyphs || !(*glyphs) || !(num_glyphs))
return status;
/* 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) {
+ for (i = 0; i < *num_glyphs; ++i) {
cairo_matrix_transform_point (&gstate->font_matrix,
&((*glyphs)[i].x),
&((*glyphs)[i].y));
- (*glyphs)[i].x += origin_x;
- (*glyphs)[i].y += origin_y;
+ (*glyphs)[i].x += x;
+ (*glyphs)[i].y += y;
}
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gstate_set_font (cairo_gstate_t *gstate,
- cairo_font_t *font)
-{
- if (font != gstate->font) {
- if (gstate->font)
- cairo_font_destroy (gstate->font);
- gstate->font = font;
- if (gstate->font)
- cairo_font_reference (gstate->font);
+_cairo_gstate_set_font_face (cairo_gstate_t *gstate,
+ cairo_font_face_t *font_face)
+{
+ if (font_face != gstate->font_face) {
+ if (gstate->font_face)
+ cairo_font_face_destroy (gstate->font_face);
+ gstate->font_face = font_face;
+ if (gstate->font_face)
+ cairo_font_face_reference (gstate->font_face);
}
+
+ _cairo_gstate_unset_font (gstate);
return CAIRO_STATUS_SUCCESS;
}
@@ -2386,10 +1950,9 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
if (status)
return status;
- cairo_font_glyph_extents (gstate->font,
- &gstate->font_matrix,
- glyphs, num_glyphs,
- extents);
+ cairo_scaled_font_glyph_extents (gstate->scaled_font,
+ glyphs, num_glyphs,
+ extents);
return CAIRO_STATUS_SUCCESS;
}
@@ -2406,6 +1969,9 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_box_t bbox;
cairo_rectangle_t extents;
+ if (gstate->surface->level != gstate->surface_level)
+ return CAIRO_STATUS_BAD_NESTING;
+
status = _cairo_gstate_ensure_font (gstate);
if (status)
return status;
@@ -2417,14 +1983,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
for (i = 0; i < num_glyphs; ++i)
{
transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &transformed_glyphs[i].x,
- &transformed_glyphs[i].y);
+ _cairo_gstate_user_to_backend (gstate,
+ &transformed_glyphs[i].x,
+ &transformed_glyphs[i].y);
}
- status = _cairo_font_glyph_bbox (gstate->font,
- transformed_glyphs, num_glyphs,
- &bbox);
+ status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font,
+ transformed_glyphs, num_glyphs,
+ &bbox);
_cairo_box_round_to_rectangle (&bbox, &extents);
if (status)
@@ -2434,7 +2000,6 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
{
cairo_surface_t *intermediate;
cairo_surface_pattern_t intermediate_pattern;
- cairo_color_t empty_color;
_cairo_rectangle_intersect (&extents, &gstate->clip.rect);
@@ -2444,13 +2009,11 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
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,
extents.width,
extents.height,
- &empty_color);
+ CAIRO_COLOR_TRANSPARENT);
if (intermediate == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto BAIL1;
@@ -2463,15 +2026,15 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
transformed_glyphs[i].y -= extents.y;
}
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
+ _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
- status = _cairo_font_show_glyphs (gstate->font,
- CAIRO_OPERATOR_ADD,
- &pattern.base, intermediate,
- extents.x, extents.y,
- 0, 0,
- extents.width, extents.height,
- transformed_glyphs, num_glyphs);
+ status = _cairo_scaled_font_show_glyphs (gstate->scaled_font,
+ CAIRO_OPERATOR_ADD,
+ &pattern.base, intermediate,
+ extents.x, extents.y,
+ 0, 0,
+ extents.width, extents.height,
+ transformed_glyphs, num_glyphs);
_cairo_pattern_fini (&pattern.base);
@@ -2497,7 +2060,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
goto BAIL2;
_cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
+ _cairo_pattern_init_copy (&pattern.base, gstate->source);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
status = _cairo_surface_composite (gstate->operator,
&pattern.base,
@@ -2517,15 +2081,16 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
}
else
{
- _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
+ _cairo_pattern_init_copy (&pattern.base, gstate->source);
+ _cairo_gstate_pattern_transform (gstate, &pattern.base);
- status = _cairo_font_show_glyphs (gstate->font,
- gstate->operator, &pattern.base,
- gstate->surface,
- extents.x, extents.y,
- extents.x, extents.y,
- extents.width, extents.height,
- transformed_glyphs, num_glyphs);
+ status = _cairo_scaled_font_show_glyphs (gstate->scaled_font,
+ gstate->operator, &pattern.base,
+ gstate->surface,
+ extents.x, extents.y,
+ extents.x, extents.y,
+ extents.width, extents.height,
+ transformed_glyphs, num_glyphs);
_cairo_pattern_fini (&pattern.base);
}
@@ -2537,14 +2102,19 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
}
cairo_status_t
-_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
- cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path)
{
cairo_status_t status;
int i;
cairo_glyph_t *transformed_glyphs = NULL;
+ status = _cairo_gstate_ensure_font (gstate);
+ if (status)
+ return status;
+
transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
if (transformed_glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY;
@@ -2552,14 +2122,14 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
for (i = 0; i < num_glyphs; ++i)
{
transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &(transformed_glyphs[i].x),
- &(transformed_glyphs[i].y));
+ _cairo_gstate_user_to_backend (gstate,
+ &(transformed_glyphs[i].x),
+ &(transformed_glyphs[i].y));
}
- status = _cairo_font_glyph_path (gstate->font,
- transformed_glyphs, num_glyphs,
- &gstate->path);
+ status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
+ transformed_glyphs, num_glyphs,
+ path);
free (transformed_glyphs);
return status;
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index d1ad5a4e2..e95894960 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -113,7 +113,9 @@ static const cairo_cache_arrangement_t cache_arrangements [] = {
#define LIVE_ENTRY_P(cache, i) \
(!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
-#ifdef CAIRO_DO_SANITY_CHECKING
+#ifdef NDEBUG
+#define _cache_sane_state(c)
+#else
static void
_cache_sane_state (cairo_cache_t *cache)
{
@@ -125,8 +127,6 @@ _cache_sane_state (cairo_cache_t *cache)
/* assert (cache->used_memory <= cache->max_memory); */
assert (cache->live_entries <= cache->arrangement->size);
}
-#else
-#define _cache_sane_state(c)
#endif
static void
@@ -351,8 +351,9 @@ _cairo_cache_init (cairo_cache_t *cache,
#endif
cache->backend = backend;
- cache->entries = calloc (sizeof(cairo_cache_entry_base_t *),
- cache->arrangement->size);
+ cache->entries = calloc (cache->arrangement->size,
+ sizeof(cairo_cache_entry_base_t *));
+
if (cache->entries == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 9745b3150..19dc7b611 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -68,7 +68,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->pixman_image = pixman_image;
surface->format = format;
- surface->data = (char *) pixman_image_get_data (pixman_image);
+ surface->data = (unsigned char *) pixman_image_get_data (pixman_image);
surface->owns_data = 0;
surface->width = pixman_image_get_width (pixman_image);
@@ -80,8 +80,8 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
}
cairo_image_surface_t *
-_cairo_image_surface_create_with_masks (char *data,
- cairo_format_masks_t *format,
+_cairo_image_surface_create_with_masks (unsigned char *data,
+ cairo_format_masks_t *format,
int width,
int height,
int stride)
@@ -195,7 +195,7 @@ cairo_image_surface_create (cairo_format_t format,
* be created because of lack of memory
**/
cairo_surface_t *
-cairo_image_surface_create_for_data (char *data,
+cairo_image_surface_create_for_data (unsigned char *data,
cairo_format_t format,
int width,
int height,
@@ -224,6 +224,38 @@ cairo_image_surface_create_for_data (char *data,
return &surface->base;
}
+/**
+ * cairo_image_surface_get_width:
+ * @surface: a #cairo_image_surface_t
+ *
+ * Get the width of the image surface in pixels.
+ *
+ * Return value: the width of the surface in pixels.
+ **/
+int
+cairo_image_surface_get_width (cairo_surface_t *surface)
+{
+ cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
+
+ return image_surface->width;
+}
+
+/**
+ * cairo_image_surface_get_height:
+ * @surface: a #cairo_image_surface_t
+ *
+ * Get the height of the image surface in pixels.
+ *
+ * Return value: the height of the surface in pixels.
+ **/
+int
+cairo_image_surface_get_height (cairo_surface_t *surface)
+{
+ cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
+
+ return image_surface->height;
+}
+
static cairo_surface_t *
_cairo_image_surface_create_similar (void *abstract_src,
cairo_format_t format,
@@ -234,20 +266,22 @@ _cairo_image_surface_create_similar (void *abstract_src,
return cairo_image_surface_create (format, width, height);
}
-static void
-_cairo_image_abstract_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_image_abstract_surface_finish (void *abstract_surface)
{
cairo_image_surface_t *surface = abstract_surface;
- if (surface->pixman_image)
+ if (surface->pixman_image) {
pixman_image_destroy (surface->pixman_image);
+ surface->pixman_image = NULL;
+ }
if (surface->owns_data) {
free (surface->data);
surface->data = NULL;
}
- free (surface);
+ return CAIRO_STATUS_SUCCESS;
}
void
@@ -256,13 +290,6 @@ _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
surface->owns_data = 1;
}
-static double
-_cairo_image_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We'll want a way to let the user set this. */
- return 96.0;
-}
-
static cairo_status_t
_cairo_image_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
@@ -327,17 +354,17 @@ _cairo_image_surface_clone_similar (void *abstract_surface,
cairo_status_t
_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
- cairo_matrix_t *matrix)
+ const cairo_matrix_t *matrix)
{
pixman_transform_t pixman_transform;
- pixman_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- pixman_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- pixman_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
+ pixman_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
+ pixman_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy);
+ pixman_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0);
- pixman_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- pixman_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- pixman_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
+ pixman_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx);
+ pixman_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy);
+ pixman_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0);
pixman_transform.matrix[2][0] = 0;
pixman_transform.matrix[2][1] = 0;
@@ -414,32 +441,40 @@ _cairo_image_surface_set_attributes (cairo_image_surface_t *surface,
return status;
}
+/* XXX: I think we should fix pixman to match the names/order of the
+ * cairo operators, but that will likely be better done at the same
+ * time the X server is ported to pixman, (which will change a lot of
+ * things in pixman I think).
+ */
static pixman_operator_t
_pixman_operator (cairo_operator_t operator)
{
switch (operator) {
case CAIRO_OPERATOR_CLEAR:
return PIXMAN_OPERATOR_CLEAR;
- case CAIRO_OPERATOR_SRC:
+
+ case CAIRO_OPERATOR_SOURCE:
return PIXMAN_OPERATOR_SRC;
- case CAIRO_OPERATOR_DST:
- return PIXMAN_OPERATOR_DST;
case CAIRO_OPERATOR_OVER:
return PIXMAN_OPERATOR_OVER;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return PIXMAN_OPERATOR_OVER_REVERSE;
case CAIRO_OPERATOR_IN:
return PIXMAN_OPERATOR_IN;
- case CAIRO_OPERATOR_IN_REVERSE:
- return PIXMAN_OPERATOR_IN_REVERSE;
case CAIRO_OPERATOR_OUT:
return PIXMAN_OPERATOR_OUT;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return PIXMAN_OPERATOR_OUT_REVERSE;
case CAIRO_OPERATOR_ATOP:
return PIXMAN_OPERATOR_ATOP;
- case CAIRO_OPERATOR_ATOP_REVERSE:
+
+ case CAIRO_OPERATOR_DEST:
+ return PIXMAN_OPERATOR_DST;
+ case CAIRO_OPERATOR_DEST_OVER:
+ return PIXMAN_OPERATOR_OVER_REVERSE;
+ case CAIRO_OPERATOR_DEST_IN:
+ return PIXMAN_OPERATOR_IN_REVERSE;
+ case CAIRO_OPERATOR_DEST_OUT:
+ return PIXMAN_OPERATOR_OUT_REVERSE;
+ case CAIRO_OPERATOR_DEST_ATOP:
return PIXMAN_OPERATOR_ATOP_REVERSE;
+
case CAIRO_OPERATOR_XOR:
return PIXMAN_OPERATOR_XOR;
case CAIRO_OPERATOR_ADD:
@@ -587,7 +622,7 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
* somehow. */
status = _cairo_image_surface_set_attributes (src, &attributes);
if (CAIRO_OK (status))
- pixman_composite_trapezoids (operator,
+ pixman_composite_trapezoids (_pixman_operator (operator),
src->pixman_image,
dst->pixman_image,
render_src_x + attributes.x_offset,
@@ -600,18 +635,6 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
}
static cairo_int_status_t
-_cairo_image_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
_cairo_image_abstract_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
@@ -642,6 +665,27 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
+static cairo_int_status_t
+_cairo_image_surface_get_extents (cairo_image_surface_t *surface,
+ cairo_rectangle_t *rectangle)
+{
+ rectangle->x = 0;
+ rectangle->y = 0;
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_image_abstract_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
+{
+ cairo_image_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_get_extents (surface, rectangle);
+}
+
/**
* _cairo_surface_is_image:
* @surface: a #cairo_surface_t
@@ -658,8 +702,7 @@ _cairo_surface_is_image (cairo_surface_t *surface)
static const cairo_surface_backend_t cairo_image_surface_backend = {
_cairo_image_surface_create_similar,
- _cairo_image_abstract_surface_destroy,
- _cairo_image_surface_pixels_per_inch,
+ _cairo_image_abstract_surface_finish,
_cairo_image_surface_acquire_source_image,
_cairo_image_surface_release_source_image,
_cairo_image_surface_acquire_dest_image,
@@ -668,8 +711,9 @@ static const cairo_surface_backend_t cairo_image_surface_backend = {
_cairo_image_surface_composite,
_cairo_image_surface_fill_rectangles,
_cairo_image_surface_composite_trapezoids,
- _cairo_image_surface_copy_page,
- _cairo_image_surface_show_page,
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_image_abstract_surface_set_clip_region,
+ _cairo_image_abstract_surface_get_extents,
NULL /* show_glyphs */
};
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index 88e536e8a..82ec0dbb7 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -40,14 +40,6 @@
#include "cairoint.h"
-static cairo_matrix_t const CAIRO_MATRIX_IDENTITY = {
- {
- {1, 0},
- {0, 1},
- {0, 0}
- }
-};
-
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
@@ -55,228 +47,185 @@ static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
/**
- * cairo_matrix_create:
- *
- * Creates a new identity matrix.
- *
- * Return value: a newly created matrix; free with cairo_matrix_destroy(),
- * or %NULL if memory couldn't be allocated.
- **/
-cairo_matrix_t *
-cairo_matrix_create (void)
-{
- cairo_matrix_t *matrix;
-
- matrix = malloc (sizeof (cairo_matrix_t));
- if (matrix == NULL)
- return NULL;
-
- _cairo_matrix_init (matrix);
-
- return matrix;
-}
-
-void
-_cairo_matrix_init (cairo_matrix_t *matrix)
-{
- cairo_matrix_set_identity (matrix);
-}
-
-void
-_cairo_matrix_fini (cairo_matrix_t *matrix)
-{
- /* nothing to do here */
-}
-
-/**
- * cairo_matrix_destroy:
- * @matrix: a #cairo_matrix_t
- *
- * Frees a matrix created with cairo_matrix_create.
- **/
-void
-cairo_matrix_destroy (cairo_matrix_t *matrix)
-{
- _cairo_matrix_fini (matrix);
- free (matrix);
-}
-
-/**
- * cairo_matrix_copy:
- * @matrix: a #cairo_matrix_t
- * @other: another #cairo_
- *
- * Modifies @matrix to be identical to @other.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
-{
- *matrix = *other;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_matrix_copy);
-
-/**
- * cairo_matrix_set_identity:
+ * cairo_matrix_init_identity:
* @matrix: a #cairo_matrix_t
*
* Modifies @matrix to be an identity transformation.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
**/
-cairo_status_t
-cairo_matrix_set_identity (cairo_matrix_t *matrix)
+void
+cairo_matrix_init_identity (cairo_matrix_t *matrix)
{
- *matrix = CAIRO_MATRIX_IDENTITY;
-
- return CAIRO_STATUS_SUCCESS;
+ cairo_matrix_init (matrix,
+ 1, 0,
+ 0, 1,
+ 0, 0);
}
-slim_hidden_def(cairo_matrix_set_identity);
+slim_hidden_def(cairo_matrix_init_identity);
/**
- * cairo_matrix_set_affine:
+ * cairo_matrix_init:
* @matrix: a cairo_matrix_t
- * @a: a component of the affine transformation
- * @b: b component of the affine transformation
- * @c: c component of the affine transformation
- * @d: d component of the affine transformation
- * @tx: X translation component of the affine transformation
- * @ty: Y translation component of the affine transformation
+ * @xx: xx component of the affine transformation
+ * @yx: yx component of the affine transformation
+ * @xy: xy component of the affine transformation
+ * @yy: yy component of the affine transformation
+ * @x0: X translation component of the affine transformation
+ * @y0: Y translation component of the affine transformation
*
* Sets @matrix to be the affine transformation given by
- * @a, b, @c, @d, @tx, @ty. The transformation is given
+ * @xx, @yx, @xy, @yy, @x0, @y0. The transformation is given
* by:
* <programlisting>
- * x_new = x * a + y * c + tx;
- * y_new = x * b + y * d + ty;
+ * x_new = xx * x + xy * y + x0;
+ * y_new = yx * x + yy * y + y0;
* </programlisting>
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
**/
-cairo_status_t
-cairo_matrix_set_affine (cairo_matrix_t *matrix,
- double a, double b,
- double c, double d,
- double tx, double ty)
+void
+cairo_matrix_init (cairo_matrix_t *matrix,
+ double xx, double yx,
+ double xy, double yy,
+ double x0, double y0)
{
- matrix->m[0][0] = a; matrix->m[0][1] = b;
- matrix->m[1][0] = c; matrix->m[1][1] = d;
- matrix->m[2][0] = tx; matrix->m[2][1] = ty;
-
- return CAIRO_STATUS_SUCCESS;
+ matrix->xx = xx; matrix->yx = yx;
+ matrix->xy = xy; matrix->yy = yy;
+ matrix->x0 = x0; matrix->y0 = y0;
}
-slim_hidden_def(cairo_matrix_set_affine);
+slim_hidden_def(cairo_matrix_init);
/**
- * cairo_matrix_get_affine:
+ * _cairo_matrix_get_affine:
* @matrix: a @cairo_matrix_t
- * @a: location to store a component of affine transformation, or %NULL
- * @b: location to store b component of affine transformation, or %NULL
- * @c: location to store c component of affine transformation, or %NULL
- * @d: location to store d component of affine transformation, or %NULL
- * @tx: location to store X-translation component of affine transformation, or %NULL
- * @ty: location to store Y-translation component of affine transformation, or %NULL
+ * @xx: location to store xx component of matrix
+ * @yx: location to store yx component of matrix
+ * @xy: location to store xy component of matrix
+ * @yy: location to store yy component of matrix
+ * @x0: location to store x0 (X-translation component) of matrix, or %NULL
+ * @y0: location to store y0 (Y-translation component) of matrix, or %NULL
*
* Gets the matrix values for the affine tranformation that @matrix represents.
- * See cairo_matrix_set_affine().
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
+ * See cairo_matrix_init().
+ *
+ *
+ * This function is a leftover from the old public API, but is still
+ * mildly useful as an internal means for getting at the matrix
+ * members in a positional way. For example, when reassigning to some
+ * external matrix type, or when renaming members to more meaningful
+ * names (such as a,b,c,d,e,f) for particular manipulations.
**/
-cairo_status_t
-cairo_matrix_get_affine (cairo_matrix_t *matrix,
- double *a, double *b,
- double *c, double *d,
- double *tx, double *ty)
+void
+_cairo_matrix_get_affine (const cairo_matrix_t *matrix,
+ double *xx, double *yx,
+ double *xy, double *yy,
+ double *x0, double *y0)
{
- if (a)
- *a = matrix->m[0][0];
- if (b)
- *b = matrix->m[0][1];
+ *xx = matrix->xx;
+ *yx = matrix->yx;
- if (c)
- *c = matrix->m[1][0];
- if (d)
- *d = matrix->m[1][1];
+ *xy = matrix->xy;
+ *yy = matrix->yy;
- if (tx)
- *tx = matrix->m[2][0];
- if (ty)
- *ty = matrix->m[2][1];
-
- return CAIRO_STATUS_SUCCESS;
+ if (x0)
+ *x0 = matrix->x0;
+ if (y0)
+ *y0 = matrix->y0;
}
-cairo_status_t
-_cairo_matrix_set_translate (cairo_matrix_t *matrix,
+/**
+ * cairo_matrix_init_translate:
+ * @matrix: a cairo_matrix_t
+ * @tx: amount to translate in the X direction
+ * @ty: amount to translate in the Y direction
+ *
+ * Initializes @matrix to a transformation that translates by @tx and
+ * @ty in the X and Y dimensions, respectively.
+ **/
+void
+cairo_matrix_init_translate (cairo_matrix_t *matrix,
double tx, double ty)
{
- return cairo_matrix_set_affine (matrix,
- 1, 0,
- 0, 1,
- tx, ty);
+ cairo_matrix_init (matrix,
+ 1, 0,
+ 0, 1,
+ tx, ty);
}
+slim_hidden_def(cairo_matrix_init_translate);
/**
* cairo_matrix_translate:
* @matrix: a cairo_matrix_t
- * @tx: amount to rotate in the X direction
- * @ty: amount to rotate in the Y direction
+ * @tx: amount to translate in the X direction
+ * @ty: amount to translate in the Y direction
*
* Applies a translation by @tx, @ty to the transformation in
- * @matrix. The new transformation is given by first translating by
- * @tx, @ty then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
+ * @matrix. The effect of the new transformation is to first translate
+ * the coordinates by @tx and @ty, then apply the original transformation
+ * to the coordinates.
**/
-cairo_status_t
+void
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
{
cairo_matrix_t tmp;
- _cairo_matrix_set_translate (&tmp, tx, ty);
+ cairo_matrix_init_translate (&tmp, tx, ty);
- return cairo_matrix_multiply (matrix, &tmp, matrix);
+ cairo_matrix_multiply (matrix, &tmp, matrix);
}
-cairo_status_t
-_cairo_matrix_set_scale (cairo_matrix_t *matrix,
+/**
+ * cairo_matrix_init_scale:
+ * @matrix: a cairo_matrix_t
+ * @sx: scale factor in the X direction
+ * @sy: scale factor in the Y direction
+ *
+ * Initializes @matrix to a transformation that scales by @sx and @sy
+ * in the X and Y dimensions, respectively.
+ **/
+void
+cairo_matrix_init_scale (cairo_matrix_t *matrix,
double sx, double sy)
{
- return cairo_matrix_set_affine (matrix,
- sx, 0,
- 0, sy,
- 0, 0);
+ cairo_matrix_init (matrix,
+ sx, 0,
+ 0, sy,
+ 0, 0);
}
+slim_hidden_def(cairo_matrix_init_scale);
/**
* cairo_matrix_scale:
* @matrix: a #cairo_matrix_t
- * @sx: Scale factor in the X direction
- * @sy: Scale factor in the Y direction
+ * @sx: scale factor in the X direction
+ * @sy: scale factor in the Y direction
*
- * Applies scaling by @tx, @ty to the transformation in
- * @matrix. The new transformation is given by first scaling by @sx
- * and @sy then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
+ * Applies scaling by @tx, @ty to the transformation in @matrix. The
+ * effect of the new transformation is to first scale the coordinates
+ * by @sx and @sy, then apply the original transformation to the coordinates.
**/
-cairo_status_t
+void
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
{
cairo_matrix_t tmp;
- _cairo_matrix_set_scale (&tmp, sx, sy);
+ cairo_matrix_init_scale (&tmp, sx, sy);
- return cairo_matrix_multiply (matrix, &tmp, matrix);
+ cairo_matrix_multiply (matrix, &tmp, matrix);
}
slim_hidden_def(cairo_matrix_scale);
-cairo_status_t
-_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
- double radians)
+/**
+ * cairo_matrix_init_rotate:
+ * @matrix: a cairo_matrix_t
+ * @radians: angle of rotation, in radians. The direction of rotation
+ * is defined such that positive angles rotate in the direction from
+ * the positive X axis toward the positive Y axis. With the default
+ * axis orientation of cairo, positive angles rotate in a clockwise
+ * direction.
+ *
+ * Initialized @matrix to a transformation that rotates by @radians.
+ **/
+void
+cairo_matrix_init_rotate (cairo_matrix_t *matrix,
+ double radians)
{
double s;
double c;
@@ -286,35 +235,35 @@ _cairo_matrix_set_rotate (cairo_matrix_t *matrix,
s = sin (radians);
c = cos (radians);
#endif
- return cairo_matrix_set_affine (matrix,
- c, s,
- -s, c,
- 0, 0);
+ cairo_matrix_init (matrix,
+ c, s,
+ -s, c,
+ 0, 0);
}
+slim_hidden_def(cairo_matrix_init_rotate);
/**
* cairo_matrix_rotate:
* @matrix: a @cairo_matrix_t
- * @radians: angle of rotation, in radians. Angles are defined
- * so that an angle of 90 degrees (%M_PI radians) rotates the
- * positive X axis into the positive Y axis. With the default
- * Cairo choice of axis orientation, positive rotations are
- * clockwise.
+ * @radians: angle of rotation, in radians. The direction of rotation
+ * is defined such that positive angles rotate in the direction from
+ * the positive X axis toward the positive Y axis. With the default
+ * axis orientation of cairo, positive angles rotate in a clockwise
+ * direction.
*
* Applies rotation by @radians to the transformation in
- * @matrix. The new transformation is given by first rotating by
- * @radians then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
+ * @matrix. The effect of the new transformation is to first rotate the
+ * coordinates by @radians, then apply the original transformation
+ * to the coordinates.
**/
-cairo_status_t
+void
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
{
cairo_matrix_t tmp;
- _cairo_matrix_set_rotate (&tmp, radians);
+ cairo_matrix_init_rotate (&tmp, radians);
- return cairo_matrix_multiply (matrix, &tmp, matrix);
+ cairo_matrix_multiply (matrix, &tmp, matrix);
}
/**
@@ -324,46 +273,47 @@ cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
* @b: a @cairo_matrix_t
*
* Multiplies the affine transformations in @a and @b together
- * and stores the result in @result. The resulting transformation
- * is given by first applying the transformation in @b then
- * applying the transformation in @a.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
+ * and stores the result in @result. The effect of the resulting
+ * transformation is to first apply the transformation in @a to the
+ * coordinates and then apply the transformation in @b to the
+ * coordinates.
+ *
+ * It is allowable for @result to be identical to either @a or @b.
**/
-cairo_status_t
+/*
+ * XXX: The ordering of the arguments to this function corresponds
+ * to [row_vector]*A*B. If we want to use column vectors instead,
+ * then we need to switch the two arguments and fix up all
+ * uses.
+ */
+void
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
{
cairo_matrix_t r;
- int row, col, n;
- double t;
-
- for (row = 0; row < 3; row++) {
- for (col = 0; col < 2; col++) {
- if (row == 2)
- t = b->m[2][col];
- else
- t = 0;
- for (n = 0; n < 2; n++) {
- t += a->m[row][n] * b->m[n][col];
- }
- r.m[row][col] = t;
- }
- }
- *result = r;
+ r.xx = a->xx * b->xx + a->yx * b->xy;
+ r.yx = a->xx * b->yx + a->yx * b->yy;
- return CAIRO_STATUS_SUCCESS;
+ r.xy = a->xy * b->xx + a->yy * b->xy;
+ r.yy = a->xy * b->yx + a->yy * b->yy;
+
+ r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0;
+ r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0;
+
+ *result = r;
}
slim_hidden_def(cairo_matrix_multiply);
/**
* cairo_matrix_transform_distance:
* @matrix: a @cairo_matrix_t
- * @dx: a distance in the X direction. An in/out parameter
- * @dy: a distance in the Y direction. An in/out parameter
+ * @dx: X component of a distance vector. An in/out parameter
+ * @dy: Y component of a distance vector. An in/out parameter
*
- * Transforms the vector (@dx,@dy) by @matrix. Translation is
- * ignored. In terms of the components of the affine transformation:
+ * Transforms the distance vector (@dx,@dy) by @matrix. This is
+ * similar to cairo_matrix_transform() except that the translation
+ * components of the transformation are ignored. The calculation of
+ * the returned vector is as follows:
*
* <programlisting>
* dx2 = dx1 * a + dy1 * c;
@@ -374,23 +324,17 @@ slim_hidden_def(cairo_matrix_multiply);
* always transforms to the same vector. If (@x1,@y1) transforms
* to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
* (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
**/
-cairo_status_t
-cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
+void
+cairo_matrix_transform_distance (const cairo_matrix_t *matrix, double *dx, double *dy)
{
double new_x, new_y;
- new_x = (matrix->m[0][0] * *dx
- + matrix->m[1][0] * *dy);
- new_y = (matrix->m[0][1] * *dx
- + matrix->m[1][1] * *dy);
+ new_x = (matrix->xx * *dx + matrix->xy * *dy);
+ new_y = (matrix->yx * *dx + matrix->yy * *dy);
*dx = new_x;
*dy = new_y;
-
- return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def(cairo_matrix_transform_distance);
@@ -401,23 +345,19 @@ slim_hidden_def(cairo_matrix_transform_distance);
* @y: Y position. An in/out parameter
*
* Transforms the point (@x, @y) by @matrix.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
**/
-cairo_status_t
-cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y)
+void
+cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y)
{
cairo_matrix_transform_distance (matrix, x, y);
- *x += matrix->m[2][0];
- *y += matrix->m[2][1];
-
- return CAIRO_STATUS_SUCCESS;
+ *x += matrix->x0;
+ *y += matrix->y0;
}
slim_hidden_def(cairo_matrix_transform_point);
-cairo_status_t
-_cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
+void
+_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x, double *y,
double *width, double *height)
{
@@ -466,18 +406,19 @@ _cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
*y = min_y;
*width = max_x - min_x;
*height = max_y - min_y;
-
- return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
{
- int row, col;
+ matrix->xx *= scalar;
+ matrix->yx *= scalar;
+
+ matrix->xy *= scalar;
+ matrix->yy *= scalar;
- for (row = 0; row < 3; row++)
- for (col = 0; col < 2; col++)
- matrix->m[row][col] *= scalar;
+ matrix->x0 *= scalar;
+ matrix->y0 *= scalar;
}
/* This function isn't a correct adjoint in that the implicit 1 in the
@@ -490,14 +431,15 @@ _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
/* adj (A) = transpose (C:cofactor (A,i,j)) */
double a, b, c, d, tx, 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];
+ _cairo_matrix_get_affine (matrix,
+ &a, &b,
+ &c, &d,
+ &tx, &ty);
- cairo_matrix_set_affine (matrix,
- d, -b,
- -c, a,
- c*ty - d*tx, b*tx - a*ty);
+ cairo_matrix_init (matrix,
+ d, -b,
+ -c, a,
+ c*ty - d*tx, b*tx - a*ty);
}
/**
@@ -531,21 +473,21 @@ cairo_matrix_invert (cairo_matrix_t *matrix)
}
slim_hidden_def(cairo_matrix_invert);
-cairo_status_t
-_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det)
+void
+_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix,
+ double *det)
{
double a, b, c, d;
- a = matrix->m[0][0]; b = matrix->m[0][1];
- c = matrix->m[1][0]; d = matrix->m[1][1];
+ a = matrix->xx; b = matrix->yx;
+ c = matrix->xy; d = matrix->yy;
*det = a*d - b*c;
-
- return CAIRO_STATUS_SUCCESS;
}
-cairo_status_t
-_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2)
+void
+_cairo_matrix_compute_eigen_values (const cairo_matrix_t *matrix,
+ double *lambda1, double *lambda2)
{
/* The eigenvalues of an NxN matrix M are found by solving the polynomial:
@@ -566,21 +508,18 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
double a, b, c, d, rad;
- a = matrix->m[0][0];
- b = matrix->m[0][1];
- c = matrix->m[1][0];
- d = matrix->m[1][1];
+ a = matrix->xx; b = matrix->yx;
+ c = matrix->xy; d = matrix->yy;
rad = sqrt (a*a + 2*a*d + d*d - 4*(a*d - b*c));
*lambda1 = (a + d + rad) / 2.0;
*lambda2 = (a + d - rad) / 2.0;
-
- return CAIRO_STATUS_SUCCESS;
}
/* 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, int x_major)
+_cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix,
+ double *sx, double *sy, int x_major)
{
double det;
@@ -621,13 +560,13 @@ _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double
}
cairo_bool_t
-_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
+_cairo_matrix_is_integer_translation(const cairo_matrix_t *mat,
int *itx, int *ity)
{
double a, b, c, d, tx, ty;
int ttx, tty;
int ok = 0;
- cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
+ _cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
ttx = _cairo_fixed_from_double (tx);
tty = _cairo_fixed_from_double (ty);
ok = ((a == 1.0)
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
new file mode 100644
index 000000000..14b4486a6
--- /dev/null
+++ b/src/cairo-output-stream.c
@@ -0,0 +1,285 @@
+/* cairo_output_stream.c: Output stream abstraction
+ *
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is cairo_output_stream.c as distributed with the
+ * cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Author(s):
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include <stdio.h>
+#include <locale.h>
+#include <ctype.h>
+#include "cairoint.h"
+
+struct _cairo_output_stream {
+ cairo_write_func_t write_data;
+ void *closure;
+ cairo_bool_t owns_closure_is_file;
+ unsigned long position;
+ cairo_status_t status;
+};
+
+cairo_output_stream_t *
+_cairo_output_stream_create (cairo_write_func_t write_data,
+ void *closure)
+{
+ cairo_output_stream_t *stream;
+
+ stream = malloc (sizeof (cairo_output_stream_t));
+ if (stream == NULL)
+ return NULL;
+
+ stream->write_data = write_data;
+ stream->closure = closure;
+ stream->owns_closure_is_file = FALSE;
+ stream->position = 0;
+ stream->status = CAIRO_STATUS_SUCCESS;
+
+ return stream;
+}
+
+void
+_cairo_output_stream_destroy (cairo_output_stream_t *stream)
+{
+ if (stream->owns_closure_is_file) {
+ FILE *file = stream->closure;
+ fflush (file);
+ fclose (file);
+ }
+ free (stream);
+}
+
+cairo_status_t
+_cairo_output_stream_write (cairo_output_stream_t *stream,
+ const void *data, size_t length)
+{
+ if (length == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ stream->status = stream->write_data (stream->closure, data, length);
+ stream->position += length;
+
+ return stream->status;
+}
+
+/* Format a double in a locale independent way and trim trailing
+ * zeros. Based on code from Alex Larson <alexl@redhat.com>.
+ * http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
+ */
+
+static int
+dtostr (char *buffer, size_t size, double d)
+{
+ struct lconv *locale_data;
+ const char *decimal_point;
+ int decimal_point_len;
+ char *p;
+ int decimal_len;
+
+ snprintf (buffer, size, "%f", d);
+
+ locale_data = localeconv ();
+ decimal_point = locale_data->decimal_point;
+ decimal_point_len = strlen (decimal_point);
+
+ assert (decimal_point_len != 0);
+ p = buffer;
+
+ if (*p == '+' || *p == '-')
+ p++;
+
+ while (isdigit (*p))
+ p++;
+
+ if (strncmp (p, decimal_point, decimal_point_len) == 0) {
+ *p = '.';
+ decimal_len = strlen (p + decimal_point_len);
+ memmove (p + 1, p + decimal_point_len, decimal_len);
+ p[1 + decimal_len] = 0;
+
+ /* Remove trailing zeros and decimal point if possible. */
+ for (p = p + decimal_len; *p == '0'; p--)
+ *p = 0;
+
+ if (*p == '.') {
+ *p = 0;
+ p--;
+ }
+ }
+
+ return p + 1 - buffer;
+}
+
+
+enum {
+ LENGTH_MODIFIER_LONG = 0x100
+};
+
+/* Here's a limited reimplementation of printf. The reason for doing
+ * this is primarily to special case handling of doubles. We want
+ * locale independent formatting of doubles and we want to trim
+ * trailing zeros. This is handled by dtostr() above, and the code
+ * below handles everything else by calling snprintf() to do the
+ * formatting. This functionality is only for internal use and we
+ * only implement the formats we actually use.
+ */
+
+cairo_status_t
+_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
+ const char *fmt, va_list ap)
+{
+ char buffer[512];
+ char *p;
+ const char *f;
+ int length_modifier;
+
+ f = fmt;
+ p = buffer;
+ while (*f != '\0') {
+ if (p == buffer + sizeof (buffer)) {
+ _cairo_output_stream_write (stream, buffer, sizeof (buffer));
+ p = buffer;
+ }
+
+ if (*f != '%') {
+ *p++ = *f++;
+ continue;
+ }
+
+ f++;
+
+ _cairo_output_stream_write (stream, buffer, p - buffer);
+ p = buffer;
+
+ length_modifier = 0;
+ if (*f == 'l') {
+ length_modifier = LENGTH_MODIFIER_LONG;
+ f++;
+ }
+
+ switch (*f | length_modifier) {
+ case '%':
+ p[0] = *f;
+ p[1] = 0;
+ break;
+ case 'd':
+ snprintf (buffer, sizeof buffer, "%d", va_arg (ap, int));
+ break;
+ case 'd' | LENGTH_MODIFIER_LONG:
+ snprintf (buffer, sizeof buffer, "%ld", va_arg (ap, long int));
+ break;
+ case 'u':
+ snprintf (buffer, sizeof buffer, "%u", va_arg (ap, unsigned int));
+ break;
+ case 'u' | LENGTH_MODIFIER_LONG:
+ snprintf (buffer, sizeof buffer, "%lu", va_arg (ap, long unsigned int));
+ break;
+ case 'o':
+ snprintf (buffer, sizeof buffer, "%o", va_arg (ap, int));
+ break;
+ case 's':
+ snprintf (buffer, sizeof buffer, "%s", va_arg (ap, const char *));
+ break;
+ case 'f':
+ dtostr (buffer, sizeof buffer, va_arg (ap, double));
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ }
+ p = buffer + strlen (buffer);
+ f++;
+ }
+
+ _cairo_output_stream_write (stream, buffer, p - buffer);
+
+ return stream->status;
+}
+
+cairo_status_t
+_cairo_output_stream_printf (cairo_output_stream_t *stream,
+ const char *fmt, ...)
+{
+ va_list ap;
+ cairo_status_t status;
+
+ va_start (ap, fmt);
+
+ status = _cairo_output_stream_vprintf (stream, fmt, ap);
+
+ va_end (ap);
+
+ return status;
+}
+
+long
+_cairo_output_stream_get_position (cairo_output_stream_t *stream)
+{
+ return stream->position;
+}
+
+cairo_status_t
+_cairo_output_stream_get_status (cairo_output_stream_t *stream)
+{
+ return stream->status;
+}
+
+
+/* Maybe this should be a configure time option, so embedded targets
+ * don't have to pull in stdio. */
+
+static cairo_status_t
+stdio_write (void *closure, const unsigned char *data, unsigned int length)
+{
+ FILE *fp = closure;
+
+ if (fwrite (data, 1, length, fp) == length)
+ return CAIRO_STATUS_SUCCESS;
+
+ return CAIRO_STATUS_WRITE_ERROR;
+}
+
+cairo_output_stream_t *
+_cairo_output_stream_create_for_file (const char *filename)
+{
+ FILE *fp;
+ cairo_output_stream_t *stream;
+
+ fp = fopen (filename, "wb");
+ if (fp == NULL)
+ return NULL;
+
+ stream = _cairo_output_stream_create (stdio_write, fp);
+ if (stream == NULL)
+ fclose (fp);
+ stream->owns_closure_is_file = TRUE;
+
+ return stream;
+}
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index 7c5772a82..670036cfd 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -151,7 +151,9 @@ _cairo_path_bounder_close_path (void *closure)
/* XXX: Perhaps this should compute a PixRegion rather than 4 doubles */
cairo_status_t
-_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2)
+_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
+ double *x1, double *y1,
+ double *x2, double *y2)
{
cairo_status_t status;
@@ -159,12 +161,12 @@ _cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, doub
_cairo_path_bounder_init (&bounder);
- status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD,
- _cairo_path_bounder_move_to,
- _cairo_path_bounder_line_to,
- _cairo_path_bounder_curve_to,
- _cairo_path_bounder_close_path,
- &bounder);
+ status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
+ _cairo_path_bounder_move_to,
+ _cairo_path_bounder_line_to,
+ _cairo_path_bounder_curve_to,
+ _cairo_path_bounder_close_path,
+ &bounder);
if (status) {
*x1 = *y1 = *x2 = *y2 = 0.0;
_cairo_path_bounder_fini (&bounder);
diff --git a/src/cairo-path-data-private.h b/src/cairo-path-data-private.h
new file mode 100644
index 000000000..e47eaaef9
--- /dev/null
+++ b/src/cairo-path-data-private.h
@@ -0,0 +1,55 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#ifndef CAIRO_PATH_DATA_PRIVATE_H
+#define CAIRO_PATH_DATA_PRIVATE_H
+
+#include "cairoint.h"
+
+extern cairo_path_t _cairo_path_nil;
+
+cairo_path_t *
+_cairo_path_data_create (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate);
+
+cairo_path_t *
+_cairo_path_data_create_flat (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate);
+
+cairo_status_t
+_cairo_path_data_append_to_context (cairo_path_t *path,
+ cairo_t *cr);
+
+#endif /* CAIRO_PATH_DATA_PRIVATE_H */
diff --git a/src/cairo-path-data.c b/src/cairo-path-data.c
new file mode 100644
index 000000000..95fc3bb26
--- /dev/null
+++ b/src/cairo-path-data.c
@@ -0,0 +1,422 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#include "cairo-path-data-private.h"
+#include "cairo-path-fixed-private.h"
+#include "cairo-gstate-private.h"
+
+cairo_path_t
+_cairo_path_nil = { NULL, 0 };
+
+/* Closure for path interpretation. */
+typedef struct cairo_path_data_count {
+ int count;
+ double tolerance;
+ cairo_point_t current_point;
+} cpdc_t;
+
+static cairo_status_t
+_cpdc_move_to (void *closure, cairo_point_t *point)
+{
+ cpdc_t *cpdc = closure;
+
+ cpdc->count += 2;
+
+ cpdc->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdc_line_to (void *closure, cairo_point_t *point)
+{
+ cpdc_t *cpdc = closure;
+
+ cpdc->count += 2;
+
+ cpdc->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdc_curve_to (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ cpdc_t *cpdc = closure;
+
+ cpdc->count += 4;
+
+ cpdc->current_point = *p3;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdc_curve_to_flatten (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ cpdc_t *cpdc = closure;
+ cairo_status_t status;
+ cairo_spline_t spline;
+ int i;
+
+ cairo_point_t *p0 = &cpdc->current_point;
+
+ status = _cairo_spline_init (&spline, p0, p1, p2, p3);
+ if (status == CAIRO_INT_STATUS_DEGENERATE)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_spline_decompose (&spline, cpdc->tolerance);
+ if (status)
+ return status;
+
+ for (i=1; i < spline.num_points; i++)
+ _cpdc_line_to (cpdc, &spline.points[i]);
+
+ cpdc->current_point = *p3;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdc_close_path (void *closure)
+{
+ cpdc_t *cpdc = closure;
+
+ cpdc->count += 1;
+
+ cpdc->current_point.x = 0;
+ cpdc->current_point.y = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static int
+_cairo_path_data_count (cairo_path_t *path,
+ cairo_path_fixed_t *path_fixed,
+ double tolerance,
+ cairo_bool_t flatten)
+{
+ cpdc_t cpdc;
+
+ cpdc.count = 0;
+ cpdc.tolerance = tolerance;
+ cpdc.current_point.x = 0;
+ cpdc.current_point.y = 0;
+
+ _cairo_path_fixed_interpret (path_fixed,
+ CAIRO_DIRECTION_FORWARD,
+ _cpdc_move_to,
+ _cpdc_line_to,
+ flatten ?
+ _cpdc_curve_to_flatten :
+ _cpdc_curve_to,
+ _cpdc_close_path,
+ &cpdc);
+
+ return cpdc.count;
+}
+
+/* Closure for path interpretation. */
+typedef struct cairo_path_data_populate {
+ cairo_path_data_t *data;
+ cairo_gstate_t *gstate;
+ cairo_point_t current_point;
+} cpdp_t;
+
+static cairo_status_t
+_cpdp_move_to (void *closure, cairo_point_t *point)
+{
+ cpdp_t *cpdp = closure;
+ cairo_path_data_t *data = cpdp->data;
+ double x, y;
+
+ x = _cairo_fixed_to_double (point->x);
+ y = _cairo_fixed_to_double (point->y);
+
+ _cairo_gstate_backend_to_user (cpdp->gstate, &x, &y);
+
+ data->header.type = CAIRO_PATH_MOVE_TO;
+ data->header.length = 2;
+
+ /* We index from 1 to leave room for data->header */
+ data[1].point.x = x;
+ data[1].point.y = y;
+
+ cpdp->data += data->header.length;
+
+ cpdp->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdp_line_to (void *closure, cairo_point_t *point)
+{
+ cpdp_t *cpdp = closure;
+ cairo_path_data_t *data = cpdp->data;
+ double x, y;
+
+ x = _cairo_fixed_to_double (point->x);
+ y = _cairo_fixed_to_double (point->y);
+
+ _cairo_gstate_backend_to_user (cpdp->gstate, &x, &y);
+
+ data->header.type = CAIRO_PATH_LINE_TO;
+ data->header.length = 2;
+
+ /* We index from 1 to leave room for data->header */
+ data[1].point.x = x;
+ data[1].point.y = y;
+
+ cpdp->data += data->header.length;
+
+ cpdp->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdp_curve_to (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ cpdp_t *cpdp = closure;
+ cairo_path_data_t *data = cpdp->data;
+ double x1, y1;
+ double x2, y2;
+ double x3, y3;
+
+ x1 = _cairo_fixed_to_double (p1->x);
+ y1 = _cairo_fixed_to_double (p1->y);
+ _cairo_gstate_backend_to_user (cpdp->gstate, &x1, &y1);
+
+ x2 = _cairo_fixed_to_double (p2->x);
+ y2 = _cairo_fixed_to_double (p2->y);
+ _cairo_gstate_backend_to_user (cpdp->gstate, &x2, &y2);
+
+ x3 = _cairo_fixed_to_double (p3->x);
+ y3 = _cairo_fixed_to_double (p3->y);
+ _cairo_gstate_backend_to_user (cpdp->gstate, &x3, &y3);
+
+ data->header.type = CAIRO_PATH_CURVE_TO;
+ data->header.length = 4;
+
+ /* We index from 1 to leave room for data->header */
+ data[1].point.x = x1;
+ data[1].point.y = y1;
+
+ data[2].point.x = x2;
+ data[2].point.y = y2;
+
+ data[3].point.x = x3;
+ data[3].point.y = y3;
+
+ cpdp->data += data->header.length;
+
+ cpdp->current_point = *p3;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdp_curve_to_flatten (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ cpdp_t *cpdp = closure;
+ cairo_status_t status;
+ cairo_spline_t spline;
+ int i;
+
+ cairo_point_t *p0 = &cpdp->current_point;
+
+ status = _cairo_spline_init (&spline, p0, p1, p2, p3);
+ if (status == CAIRO_INT_STATUS_DEGENERATE)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_spline_decompose (&spline, cpdp->gstate->tolerance);
+ if (status)
+ return status;
+
+ for (i=1; i < spline.num_points; i++)
+ _cpdp_line_to (cpdp, &spline.points[i]);
+
+ cpdp->current_point = *p3;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cpdp_close_path (void *closure)
+{
+ cpdp_t *cpdp = closure;
+ cairo_path_data_t *data = cpdp->data;
+
+ data->header.type = CAIRO_PATH_CLOSE_PATH;
+ data->header.length = 1;
+
+ cpdp->data += data->header.length;
+
+ cpdp->current_point.x = 0;
+ cpdp->current_point.y = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_path_data_populate (cairo_path_t *path,
+ cairo_path_fixed_t *path_fixed,
+ cairo_gstate_t *gstate,
+ cairo_bool_t flatten)
+{
+ cpdp_t cpdp;
+
+ cpdp.data = path->data;
+ cpdp.gstate = gstate;
+ cpdp.current_point.x = 0;
+ cpdp.current_point.y = 0;
+
+ _cairo_path_fixed_interpret (path_fixed,
+ CAIRO_DIRECTION_FORWARD,
+ _cpdp_move_to,
+ _cpdp_line_to,
+ flatten ?
+ _cpdp_curve_to_flatten :
+ _cpdp_curve_to,
+ _cpdp_close_path,
+ &cpdp);
+
+ /* Sanity check the count */
+ assert (cpdp.data - path->data == path->num_data);
+}
+
+static cairo_path_t *
+_cairo_path_data_create_real (cairo_path_fixed_t *path_fixed,
+ cairo_gstate_t *gstate,
+ cairo_bool_t flatten)
+{
+ cairo_path_t *path;
+
+ path = malloc (sizeof (cairo_path_t));
+ if (path == NULL)
+ return &_cairo_path_nil;
+
+ path->num_data = _cairo_path_data_count (path, path_fixed,
+ gstate->tolerance, flatten);
+
+ path->data = malloc (path->num_data * sizeof (cairo_path_data_t));
+ if (path->data == NULL) {
+ free (path);
+ return &_cairo_path_nil;
+ }
+
+ _cairo_path_data_populate (path, path_fixed,
+ gstate, flatten);
+
+ return path;
+}
+
+void
+cairo_path_destroy (cairo_path_t *path)
+{
+ free (path->data);
+ path->num_data = 0;
+ free (path);
+}
+
+cairo_path_t *
+_cairo_path_data_create (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate)
+{
+ return _cairo_path_data_create_real (path, gstate, FALSE);
+}
+
+cairo_path_t *
+_cairo_path_data_create_flat (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate)
+{
+ return _cairo_path_data_create_real (path, gstate, TRUE);
+}
+
+cairo_status_t
+_cairo_path_data_append_to_context (cairo_path_t *path,
+ cairo_t *cr)
+{
+ int i;
+ cairo_path_data_t *p;
+
+ for (i=0; i < path->num_data; i += path->data[i].header.length) {
+ p = &path->data[i];
+ switch (p->header.type) {
+ case CAIRO_PATH_MOVE_TO:
+ cairo_move_to (cr,
+ p[1].point.x, p[1].point.y);
+ if (p->header.length != 2)
+ return CAIRO_STATUS_INVALID_PATH_DATA;
+ break;
+ case CAIRO_PATH_LINE_TO:
+ cairo_line_to (cr,
+ p[1].point.x, p[1].point.y);
+ if (p->header.length != 2)
+ return CAIRO_STATUS_INVALID_PATH_DATA;
+ break;
+ case CAIRO_PATH_CURVE_TO:
+ cairo_curve_to (cr,
+ p[1].point.x, p[1].point.y,
+ p[2].point.x, p[2].point.y,
+ p[3].point.x, p[3].point.y);
+ if (p->header.length != 4)
+ return CAIRO_STATUS_INVALID_PATH_DATA;
+ break;
+ case CAIRO_PATH_CLOSE_PATH:
+ cairo_close_path (cr);
+ if (p->header.length != 1)
+ return CAIRO_STATUS_INVALID_PATH_DATA;
+ break;
+ default:
+ return CAIRO_STATUS_INVALID_PATH_DATA;
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index dc79b6b96..c0015fc96 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -36,6 +36,8 @@
#include "cairoint.h"
+#include "cairo-gstate-private.h"
+
typedef struct cairo_filler {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
@@ -171,20 +173,22 @@ _cairo_filler_close_path (void *closure)
}
cairo_status_t
-_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
+_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate,
+ cairo_traps_t *traps)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t filler;
_cairo_filler_init (&filler, gstate, traps);
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_filler_move_to,
- _cairo_filler_line_to,
- _cairo_filler_curve_to,
- _cairo_filler_close_path,
- &filler);
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_filler_move_to,
+ _cairo_filler_line_to,
+ _cairo_filler_curve_to,
+ _cairo_filler_close_path,
+ &filler);
if (status)
goto BAIL;
diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h
new file mode 100644
index 000000000..e8e0df194
--- /dev/null
+++ b/src/cairo-path-fixed-private.h
@@ -0,0 +1,74 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#ifndef CAIRO_PATH_FIXED_PRIVATE_H
+#define CAIRO_PATH_FIXED_PRIVATE_H
+
+typedef enum cairo_path_op {
+ CAIRO_PATH_OP_MOVE_TO = 0,
+ CAIRO_PATH_OP_LINE_TO = 1,
+ CAIRO_PATH_OP_CURVE_TO = 2,
+ CAIRO_PATH_OP_CLOSE_PATH = 3
+} __attribute__ ((packed)) cairo_path_op_t; /* Don't want 32 bits if we can avoid it. */
+
+#define CAIRO_PATH_BUF_SIZE 64
+
+typedef struct _cairo_path_op_buf {
+ int num_ops;
+ cairo_path_op_t op[CAIRO_PATH_BUF_SIZE];
+
+ struct _cairo_path_op_buf *next, *prev;
+} cairo_path_op_buf_t;
+
+typedef struct _cairo_path_arg_buf {
+ int num_points;
+ cairo_point_t points[CAIRO_PATH_BUF_SIZE];
+
+ struct _cairo_path_arg_buf *next, *prev;
+} cairo_path_arg_buf_t;
+
+struct _cairo_path_fixed {
+ cairo_path_op_buf_t *op_buf_head;
+ cairo_path_op_buf_t *op_buf_tail;
+
+ cairo_path_arg_buf_t *arg_buf_head;
+ cairo_path_arg_buf_t *arg_buf_tail;
+
+ cairo_point_t last_move_point;
+ cairo_point_t current_point;
+ int has_current_point;
+};
+
+#endif /* CAIRO_PATH_FIXED_PRIVATE_H */
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 08b380902..b81d862b9 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -36,6 +36,8 @@
#include "cairoint.h"
+#include "cairo-gstate-private.h"
+
typedef struct cairo_stroker {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
@@ -794,7 +796,9 @@ _cairo_stroker_close_path (void *closure)
}
cairo_status_t
-_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
+_cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate,
+ cairo_traps_t *traps)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker_t stroker;
@@ -802,21 +806,21 @@ _cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_t
_cairo_stroker_init (&stroker, gstate, traps);
if (gstate->dash)
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_stroker_move_to,
- _cairo_stroker_line_to_dashed,
- _cairo_stroker_curve_to,
- _cairo_stroker_close_path,
- &stroker);
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_stroker_move_to,
+ _cairo_stroker_line_to_dashed,
+ _cairo_stroker_curve_to,
+ _cairo_stroker_close_path,
+ &stroker);
else
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_stroker_move_to,
- _cairo_stroker_line_to,
- _cairo_stroker_curve_to,
- _cairo_stroker_close_path,
- &stroker);
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_stroker_move_to,
+ _cairo_stroker_line_to,
+ _cairo_stroker_curve_to,
+ _cairo_stroker_close_path,
+ &stroker);
if (status)
goto BAIL;
diff --git a/src/cairo-path.c b/src/cairo-path.c
index 8314f601c..0940c4d1e 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -1,7 +1,8 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
- *
+ * Copyright © 2005 Red Hat, Inc.
+ *
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
@@ -37,48 +38,52 @@
#include <stdlib.h>
#include "cairoint.h"
+#include "cairo-path-fixed-private.h"
+
/* private functions */
static cairo_status_t
-_cairo_path_add (cairo_path_t *path, cairo_path_op_t op, cairo_point_t *points, int num_pts);
+_cairo_path_fixed_add (cairo_path_fixed_t *path,
+ cairo_path_op_t op,
+ cairo_point_t *points,
+ int num_points);
static void
-_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op);
-
-static cairo_status_t
-_cairo_path_new_op_buf (cairo_path_t *path);
+_cairo_path_fixed_add_op_buf (cairo_path_fixed_t *path,
+ cairo_path_op_buf_t *op_buf);
static void
-_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg);
-
-static cairo_status_t
-_cairo_path_new_arg_buf (cairo_path_t *path);
+_cairo_path_fixed_add_arg_buf (cairo_path_fixed_t *path,
+ cairo_path_arg_buf_t *arg_buf);
static cairo_path_op_buf_t *
_cairo_path_op_buf_create (void);
static void
-_cairo_path_op_buf_destroy (cairo_path_op_buf_t *buf);
+_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf);
static void
-_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op_t op);
+_cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf,
+ cairo_path_op_t op);
static cairo_path_arg_buf_t *
_cairo_path_arg_buf_create (void);
static void
-_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *buf);
+_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf);
static void
-_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, cairo_point_t *points, int num_points);
+_cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf,
+ cairo_point_t *points,
+ int num_points);
void
-_cairo_path_init (cairo_path_t *path)
+_cairo_path_fixed_init (cairo_path_fixed_t *path)
{
- path->op_head = NULL;
- path->op_tail = NULL;
+ path->op_buf_head = NULL;
+ path->op_buf_tail = NULL;
- path->arg_head = NULL;
- path->arg_tail = NULL;
+ path->arg_buf_head = NULL;
+ path->arg_buf_tail = NULL;
path->current_point.x = 0;
path->current_point.y = 0;
@@ -87,72 +92,85 @@ _cairo_path_init (cairo_path_t *path)
}
cairo_status_t
-_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
+_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
+ cairo_path_fixed_t *other)
{
- cairo_path_op_buf_t *op, *other_op;
- cairo_path_arg_buf_t *arg, *other_arg;
+ cairo_path_op_buf_t *op_buf, *other_op_buf;
+ cairo_path_arg_buf_t *arg_buf, *other_arg_buf;
- _cairo_path_init (path);
+ _cairo_path_fixed_init (path);
path->current_point = other->current_point;
path->has_current_point = other->has_current_point;
path->last_move_point = other->last_move_point;
- for (other_op = other->op_head; other_op; other_op = other_op->next) {
- op = _cairo_path_op_buf_create ();
- if (op == NULL) {
- _cairo_path_fini(path);
+ for (other_op_buf = other->op_buf_head;
+ other_op_buf;
+ other_op_buf = other_op_buf->next)
+ {
+ op_buf = _cairo_path_op_buf_create ();
+ if (op_buf == NULL) {
+ _cairo_path_fixed_fini (path);
return CAIRO_STATUS_NO_MEMORY;
}
- *op = *other_op;
- _cairo_path_add_op_buf (path, op);
+ memcpy (op_buf, other_op_buf, sizeof (cairo_path_op_buf_t));
+ _cairo_path_fixed_add_op_buf (path, op_buf);
}
- for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) {
- arg = _cairo_path_arg_buf_create ();
- if (arg == NULL) {
- _cairo_path_fini(path);
+ for (other_arg_buf = other->arg_buf_head;
+ other_arg_buf;
+ other_arg_buf = other_arg_buf->next)
+ {
+ arg_buf = _cairo_path_arg_buf_create ();
+ if (arg_buf == NULL) {
+ _cairo_path_fixed_fini (path);
return CAIRO_STATUS_NO_MEMORY;
}
- *arg = *other_arg;
- _cairo_path_add_arg_buf (path, arg);
+ memcpy (arg_buf, other_arg_buf, sizeof (cairo_path_arg_buf_t));
+ _cairo_path_fixed_add_arg_buf (path, arg_buf);
}
return CAIRO_STATUS_SUCCESS;
}
void
-_cairo_path_fini (cairo_path_t *path)
+_cairo_path_fixed_fini (cairo_path_fixed_t *path)
{
- cairo_path_op_buf_t *op;
- cairo_path_arg_buf_t *arg;
+ cairo_path_op_buf_t *op_buf;
+ cairo_path_arg_buf_t *arg_buf;
- while (path->op_head) {
- op = path->op_head;
- path->op_head = op->next;
- _cairo_path_op_buf_destroy (op);
+ while (path->op_buf_head) {
+ op_buf = path->op_buf_head;
+ path->op_buf_head = op_buf->next;
+ _cairo_path_op_buf_destroy (op_buf);
}
- path->op_tail = NULL;
+ path->op_buf_tail = NULL;
- while (path->arg_head) {
- arg = path->arg_head;
- path->arg_head = arg->next;
- _cairo_path_arg_buf_destroy (arg);
+ while (path->arg_buf_head) {
+ arg_buf = path->arg_buf_head;
+ path->arg_buf_head = arg_buf->next;
+ _cairo_path_arg_buf_destroy (arg_buf);
}
- path->arg_tail = NULL;
+ path->arg_buf_tail = NULL;
path->has_current_point = 0;
}
cairo_status_t
-_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point)
+_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x,
+ cairo_fixed_t y)
{
cairo_status_t status;
+ cairo_point_t point;
+
+ point.x = x;
+ point.y = y;
- status = _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, point, 1);
+ status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
if (status)
return status;
- path->current_point = *point;
+ path->current_point = point;
path->has_current_point = 1;
path->last_move_point = path->current_point;
@@ -160,91 +178,115 @@ _cairo_path_move_to (cairo_path_t *path, cairo_point_t *point)
}
cairo_status_t
-_cairo_path_rel_move_to (cairo_path_t *path, cairo_distance_t *distance)
+_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx,
+ cairo_fixed_t dy)
{
- cairo_point_t point;
+ cairo_fixed_t x, y;
- point.x = path->current_point.x + distance->dx;
- point.y = path->current_point.y + distance->dy;
+ if (!path->has_current_point)
+ return CAIRO_STATUS_NO_CURRENT_POINT;
+
+ x = path->current_point.x + dx;
+ y = path->current_point.y + dy;
- return _cairo_path_move_to (path, &point);
+ return _cairo_path_fixed_move_to (path, x, y);
}
cairo_status_t
-_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point)
+_cairo_path_fixed_line_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x,
+ cairo_fixed_t y)
{
cairo_status_t status;
+ cairo_point_t point;
- status = _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, point, 1);
+ point.x = x;
+ point.y = y;
+
+ status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
if (status)
return status;
- path->current_point = *point;
+ path->current_point = point;
path->has_current_point = 1;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_path_rel_line_to (cairo_path_t *path, cairo_distance_t *distance)
+_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx,
+ cairo_fixed_t dy)
{
- cairo_point_t point;
+ cairo_fixed_t x, y;
+
+ if (!path->has_current_point)
+ return CAIRO_STATUS_NO_CURRENT_POINT;
- point.x = path->current_point.x + distance->dx;
- point.y = path->current_point.y + distance->dy;
+ x = path->current_point.x + dx;
+ y = path->current_point.y + dy;
- return _cairo_path_line_to (path, &point);
+ return _cairo_path_fixed_line_to (path, x, y);
}
cairo_status_t
-_cairo_path_curve_to (cairo_path_t *path,
- cairo_point_t *p0,
- cairo_point_t *p1,
- cairo_point_t *p2)
+_cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x0, cairo_fixed_t y0,
+ cairo_fixed_t x1, cairo_fixed_t y1,
+ cairo_fixed_t x2, cairo_fixed_t y2)
{
cairo_status_t status;
cairo_point_t point[3];
- point[0] = *p0;
- point[1] = *p1;
- point[2] = *p2;
+ point[0].x = x0; point[0].y = y0;
+ point[1].x = x1; point[1].y = y1;
+ point[2].x = x2; point[2].y = y2;
- status = _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
+ status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
if (status)
return status;
- path->current_point = *p2;
+ path->current_point = point[2];
path->has_current_point = 1;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_path_rel_curve_to (cairo_path_t *path,
- cairo_distance_t *d0,
- cairo_distance_t *d1,
- cairo_distance_t *d2)
+_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx0, cairo_fixed_t dy0,
+ cairo_fixed_t dx1, cairo_fixed_t dy1,
+ cairo_fixed_t dx2, cairo_fixed_t dy2)
{
- cairo_point_t p0, p1, p2;
+ cairo_fixed_t x0, y0;
+ cairo_fixed_t x1, y1;
+ cairo_fixed_t x2, y2;
+
+ if (!path->has_current_point)
+ return CAIRO_STATUS_NO_CURRENT_POINT;
- p0.x = path->current_point.x + d0->dx;
- p0.y = path->current_point.y + d0->dy;
+ x0 = path->current_point.x + dx0;
+ y0 = path->current_point.y + dy0;
- p1.x = path->current_point.x + d1->dx;
- p1.y = path->current_point.y + d1->dy;
+ x1 = path->current_point.x + dx1;
+ y1 = path->current_point.y + dy1;
- p2.x = path->current_point.x + d2->dx;
- p2.y = path->current_point.y + d2->dy;
+ x2 = path->current_point.x + dx2;
+ y2 = path->current_point.y + dy2;
- return _cairo_path_curve_to (path, &p0, &p1, &p2);
+ return _cairo_path_fixed_curve_to (path,
+ x0, y0,
+ x1, y1,
+ x2, y2);
}
cairo_status_t
-_cairo_path_close_path (cairo_path_t *path)
+_cairo_path_fixed_close_path (cairo_path_fixed_t *path)
{
cairo_status_t status;
- status = _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
+ status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
if (status)
return status;
@@ -256,120 +298,113 @@ _cairo_path_close_path (cairo_path_t *path)
}
cairo_status_t
-_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point)
+_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
+ cairo_fixed_t *x,
+ cairo_fixed_t *y)
{
if (! path->has_current_point)
return CAIRO_STATUS_NO_CURRENT_POINT;
- *point = path->current_point;
+ *x = path->current_point.x;
+ *y = path->current_point.y;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_path_add (cairo_path_t *path, cairo_path_op_t op, cairo_point_t *points, int num_points)
+_cairo_path_fixed_add (cairo_path_fixed_t *path,
+ cairo_path_op_t op,
+ cairo_point_t *points,
+ int num_points)
{
- cairo_status_t status;
+ if (path->op_buf_tail == NULL ||
+ path->op_buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE)
+ {
+ cairo_path_op_buf_t *op_buf;
- if (path->op_tail == NULL || path->op_tail->num_ops + 1 > CAIRO_PATH_BUF_SZ) {
- status = _cairo_path_new_op_buf (path);
- if (status)
- return status;
- }
- _cairo_path_op_buf_add (path->op_tail, op);
+ op_buf = _cairo_path_op_buf_create ();
+ if (op_buf == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
- if (path->arg_tail == NULL || path->arg_tail->num_points + num_points > CAIRO_PATH_BUF_SZ) {
- status = _cairo_path_new_arg_buf (path);
- if (status)
- return status;
+ _cairo_path_fixed_add_op_buf (path, op_buf);
}
- _cairo_path_arg_buf_add (path->arg_tail, points, num_points);
-
- return CAIRO_STATUS_SUCCESS;
-}
-static void
-_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op)
-{
- op->next = NULL;
- op->prev = path->op_tail;
+ _cairo_path_op_buf_add_op (path->op_buf_tail, op);
- if (path->op_tail) {
- path->op_tail->next = op;
- } else {
- path->op_head = op;
- }
+ if (path->arg_buf_tail == NULL ||
+ path->arg_buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE)
+ {
+ cairo_path_arg_buf_t *arg_buf;
- path->op_tail = op;
-}
+ arg_buf = _cairo_path_arg_buf_create ();
-static cairo_status_t
-_cairo_path_new_op_buf (cairo_path_t *path)
-{
- cairo_path_op_buf_t *op;
+ if (arg_buf == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
- op = _cairo_path_op_buf_create ();
- if (op == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ _cairo_path_fixed_add_arg_buf (path, arg_buf);
+ }
- _cairo_path_add_op_buf (path, op);
+ _cairo_path_arg_buf_add_points (path->arg_buf_tail, points, num_points);
return CAIRO_STATUS_SUCCESS;
}
static void
-_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg)
+_cairo_path_fixed_add_op_buf (cairo_path_fixed_t *path,
+ cairo_path_op_buf_t *op_buf)
{
- arg->next = NULL;
- arg->prev = path->arg_tail;
+ op_buf->next = NULL;
+ op_buf->prev = path->op_buf_tail;
- if (path->arg_tail) {
- path->arg_tail->next = arg;
+ if (path->op_buf_tail) {
+ path->op_buf_tail->next = op_buf;
} else {
- path->arg_head = arg;
+ path->op_buf_head = op_buf;
}
- path->arg_tail = arg;
+ path->op_buf_tail = op_buf;
}
-static cairo_status_t
-_cairo_path_new_arg_buf (cairo_path_t *path)
+static void
+_cairo_path_fixed_add_arg_buf (cairo_path_fixed_t *path,
+ cairo_path_arg_buf_t *arg_buf)
{
- cairo_path_arg_buf_t *arg;
-
- arg = _cairo_path_arg_buf_create ();
-
- if (arg == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ arg_buf->next = NULL;
+ arg_buf->prev = path->arg_buf_tail;
- _cairo_path_add_arg_buf (path, arg);
+ if (path->arg_buf_tail) {
+ path->arg_buf_tail->next = arg_buf;
+ } else {
+ path->arg_buf_head = arg_buf;
+ }
- return CAIRO_STATUS_SUCCESS;
+ path->arg_buf_tail = arg_buf;
}
static cairo_path_op_buf_t *
_cairo_path_op_buf_create (void)
{
- cairo_path_op_buf_t *op;
+ cairo_path_op_buf_t *op_buf;
- op = malloc (sizeof (cairo_path_op_buf_t));
+ op_buf = malloc (sizeof (cairo_path_op_buf_t));
- if (op) {
- op->num_ops = 0;
- op->next = NULL;
+ if (op_buf) {
+ op_buf->num_ops = 0;
+ op_buf->next = NULL;
}
- return op;
+ return op_buf;
}
static void
-_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op)
+_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf)
{
- free (op);
+ free (op_buf);
}
static void
-_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op_t op)
+_cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf,
+ cairo_path_op_t op)
{
op_buf->op[op_buf->num_ops++] = op;
}
@@ -377,31 +412,33 @@ _cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op_t op)
static cairo_path_arg_buf_t *
_cairo_path_arg_buf_create (void)
{
- cairo_path_arg_buf_t *arg;
+ cairo_path_arg_buf_t *arg_buf;
- arg = malloc (sizeof (cairo_path_arg_buf_t));
+ arg_buf = malloc (sizeof (cairo_path_arg_buf_t));
- if (arg) {
- arg->num_points = 0;
- arg->next = NULL;
+ if (arg_buf) {
+ arg_buf->num_points = 0;
+ arg_buf->next = NULL;
}
- return arg;
+ return arg_buf;
}
static void
-_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg)
+_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf)
{
- free (arg);
+ free (arg_buf);
}
static void
-_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, cairo_point_t *points, int num_points)
+_cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf,
+ cairo_point_t *points,
+ int num_points)
{
int i;
for (i=0; i < num_points; i++) {
- arg->points[arg->num_points++] = points[i];
+ arg_buf->points[arg_buf->num_points++] = points[i];
}
}
@@ -416,29 +453,30 @@ static int const num_args[] =
};
cairo_status_t
-_cairo_path_interpret (cairo_path_t *path,
- cairo_direction_t dir,
- cairo_path_move_to_func_t *move_to,
- cairo_path_line_to_func_t *line_to,
- cairo_path_curve_to_func_t *curve_to,
- cairo_path_close_path_func_t *close_path,
- void *closure)
+_cairo_path_fixed_interpret (cairo_path_fixed_t *path,
+ cairo_direction_t dir,
+ cairo_path_fixed_move_to_func_t *move_to,
+ cairo_path_fixed_line_to_func_t *line_to,
+ cairo_path_fixed_curve_to_func_t *curve_to,
+ cairo_path_fixed_close_path_func_t *close_path,
+ void *closure)
{
cairo_status_t status;
int i, arg;
cairo_path_op_buf_t *op_buf;
cairo_path_op_t op;
- cairo_path_arg_buf_t *arg_buf = path->arg_head;
+ cairo_path_arg_buf_t *arg_buf = path->arg_buf_head;
int buf_i = 0;
cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS];
- int step = (dir == CAIRO_DIRECTION_FORWARD) ? 1 : -1;
+ cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
+ int step = forward ? 1 : -1;
- for (op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? path->op_head : path->op_tail;
+ for (op_buf = forward ? path->op_buf_head : path->op_buf_tail;
op_buf;
- op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? op_buf->next : op_buf->prev)
+ op_buf = forward ? op_buf->next : op_buf->prev)
{
int start, stop;
- if (dir == CAIRO_DIRECTION_FORWARD) {
+ if (forward) {
start = 0;
stop = op_buf->num_ops;
} else {
@@ -449,7 +487,7 @@ _cairo_path_interpret (cairo_path_t *path,
for (i=start; i != stop; i += step) {
op = op_buf->op[i];
- if (dir == CAIRO_DIRECTION_REVERSE) {
+ if (! forward) {
if (buf_i == 0) {
arg_buf = arg_buf->prev;
buf_i = arg_buf->num_points;
@@ -466,7 +504,7 @@ _cairo_path_interpret (cairo_path_t *path,
}
}
- if (dir == CAIRO_DIRECTION_REVERSE) {
+ if (! forward) {
buf_i -= num_args[op];
}
@@ -492,4 +530,3 @@ _cairo_path_interpret (cairo_path_t *path,
return CAIRO_STATUS_SUCCESS;
}
-
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 283c36dbd..1746b6b2a 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 David Reveman
+ * 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
@@ -56,9 +57,8 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
pattern->ref_count = 1;
pattern->extend = CAIRO_EXTEND_DEFAULT;
pattern->filter = CAIRO_FILTER_DEFAULT;
- pattern->alpha = 1.0;
- _cairo_matrix_init (&pattern->matrix);
+ cairo_matrix_init_identity (&pattern->matrix);
}
static cairo_status_t
@@ -150,15 +150,10 @@ _cairo_pattern_fini (cairo_pattern_t *pattern)
void
_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
- double red,
- double green,
- double blue)
+ const cairo_color_t *color)
{
_cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SOLID);
-
- pattern->red = red;
- pattern->green = green;
- pattern->blue = blue;
+ pattern->color = *color;
}
void
@@ -209,7 +204,7 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
}
cairo_pattern_t *
-_cairo_pattern_create_solid (double red, double green, double blue)
+_cairo_pattern_create_solid (const cairo_color_t *color)
{
cairo_solid_pattern_t *pattern;
@@ -217,7 +212,7 @@ _cairo_pattern_create_solid (double red, double green, double blue)
if (pattern == NULL)
return NULL;
- _cairo_pattern_init_solid (pattern, red, green, blue);
+ _cairo_pattern_init_solid (pattern, color);
return &pattern->base;
}
@@ -296,11 +291,8 @@ cairo_pattern_destroy (cairo_pattern_t *pattern)
static cairo_status_t
_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
- double offset,
- double red,
- double green,
- double blue,
- double alpha)
+ double offset,
+ cairo_color_t *color)
{
cairo_color_stop_t *stop;
@@ -316,22 +308,48 @@ _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
stop = &pattern->stops[pattern->n_stops - 1];
stop->offset = _cairo_fixed_from_double (offset);
-
- _cairo_color_init (&stop->color);
- _cairo_color_set_rgb (&stop->color, red, green, blue);
- _cairo_color_set_alpha (&stop->color, alpha);
+ stop->color = *color;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
- double offset,
- double red,
- double green,
- double blue,
- double alpha)
+cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern,
+ double offset,
+ double red,
+ double green,
+ double blue)
{
+ cairo_color_t color;
+
+ if (pattern->type != CAIRO_PATTERN_LINEAR &&
+ pattern->type != CAIRO_PATTERN_RADIAL)
+ {
+ /* XXX: CAIRO_STATUS_INVALID_PATTERN? */
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ _cairo_restrict_value (&offset, 0.0, 1.0);
+ _cairo_restrict_value (&red, 0.0, 1.0);
+ _cairo_restrict_value (&green, 0.0, 1.0);
+ _cairo_restrict_value (&blue, 0.0, 1.0);
+
+ _cairo_color_init_rgb (&color, red, green, blue);
+ return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
+ offset,
+ &color);
+}
+
+cairo_status_t
+cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern,
+ double offset,
+ double red,
+ double green,
+ double blue,
+ double alpha)
+{
+ cairo_color_t color;
+
if (pattern->type != CAIRO_PATTERN_LINEAR &&
pattern->type != CAIRO_PATTERN_RADIAL)
{
@@ -345,22 +363,27 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
_cairo_restrict_value (&blue, 0.0, 1.0);
_cairo_restrict_value (&alpha, 0.0, 1.0);
+ _cairo_color_init_rgba (&color, red, green, blue, alpha);
return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
offset,
- red, green, blue,
- alpha);
+ &color);
}
cairo_status_t
-cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
+cairo_pattern_set_matrix (cairo_pattern_t *pattern,
+ const cairo_matrix_t *matrix)
{
- return cairo_matrix_copy (&pattern->matrix, matrix);
+ pattern->matrix = *matrix;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
{
- return cairo_matrix_copy (matrix, &pattern->matrix);
+ *matrix = pattern->matrix;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@@ -391,35 +414,9 @@ cairo_pattern_get_extend (cairo_pattern_t *pattern)
return pattern->extend;
}
-cairo_status_t
-_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
- double *red,
- double *green,
- double *blue)
-{
-
- if (pattern->type == CAIRO_PATTERN_SOLID)
- {
- cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
-
- *red = solid->red;
- *green = solid->green;
- *blue = solid->blue;
- } else
- *red = *green = *blue = 1.0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha)
-{
- pattern->alpha = alpha;
-}
-
void
-_cairo_pattern_transform (cairo_pattern_t *pattern,
- cairo_matrix_t *ctm_inverse)
+_cairo_pattern_transform (cairo_pattern_t *pattern,
+ const cairo_matrix_t *ctm_inverse)
{
cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
}
@@ -506,8 +503,7 @@ _cairo_pattern_shader_init (cairo_gradient_pattern_t *pattern,
op->stops[i].color_char[0] = pattern->stops[i].color.red * 0xff;
op->stops[i].color_char[1] = pattern->stops[i].color.green * 0xff;
op->stops[i].color_char[2] = pattern->stops[i].color.blue * 0xff;
- op->stops[i].color_char[3] = pattern->stops[i].color.alpha *
- pattern->base.alpha * 0xff;
+ op->stops[i].color_char[3] = pattern->stops[i].color.alpha * 0xff;
op->stops[i].offset = pattern->stops[i].offset;
op->stops[i].id = i;
}
@@ -516,6 +512,13 @@ _cairo_pattern_shader_init (cairo_gradient_pattern_t *pattern,
qsort (op->stops, pattern->n_stops, sizeof (cairo_shader_color_stop_t),
_cairo_shader_color_stop_compare);
+ /* this scale value is used only when computing gradient values
+ * before the defined range, in which case stop 0 is used for both
+ * ends of the interpolation, making the value of 'scale' not
+ * actually matter, except that valgrind notices we're using
+ * an undefined value.
+ */
+ op->stops[0].scale = 0;
for (i = 0; i < pattern->n_stops - 1; i++)
{
op->stops[i + 1].scale = op->stops[i + 1].offset - op->stops[i].offset;
@@ -666,8 +669,8 @@ _cairo_image_data_set_linear (cairo_linear_pattern_t *pattern,
point1.x = pattern->point1.x;
point1.y = pattern->point1.y;
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
+ _cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
dx = point1.x - point0.x;
dy = point1.y - point0.y;
@@ -721,8 +724,8 @@ _cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
point1.x = pattern->point1.x;
point1.y = pattern->point1.y;
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
+ _cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
dx = point1.x - point0.x;
dy = point1.y - point0.y;
@@ -795,8 +798,8 @@ _cairo_image_data_set_radial (cairo_radial_pattern_t *pattern,
r1_2 = c0_c1 = 0.0; /* shut up compiler */
}
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
+ _cairo_matrix_get_affine (&pattern->base.base.matrix,
+ &a, &b, &c, &d, &tx, &ty);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
@@ -889,9 +892,9 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
cairo_surface_attributes_t *attr)
{
cairo_image_surface_t *image;
- cairo_status_t status;
- uint32_t *data;
- cairo_bool_t repeat = FALSE;
+ cairo_status_t status;
+ uint32_t *data;
+ cairo_bool_t repeat = FALSE;
if (pattern->base.type == CAIRO_PATTERN_LINEAR) {
cairo_bool_t is_horizontal;
@@ -935,7 +938,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
}
image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data ((char *) data,
+ cairo_image_surface_create_for_data ((unsigned char *) data,
CAIRO_FORMAT_ARGB32,
width, height,
width * 4);
@@ -953,10 +956,11 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
attr->x_offset = -x;
attr->y_offset = -y;
- cairo_matrix_set_identity (&attr->matrix);
+ cairo_matrix_init_identity (&attr->matrix);
attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
attr->filter = CAIRO_FILTER_NEAREST;
attr->acquired = FALSE;
+ attr->clip_saved = FALSE;
return status;
}
@@ -971,53 +975,47 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
cairo_surface_t **out,
cairo_surface_attributes_t *attribs)
{
- cairo_color_t color;
-
- _cairo_color_init (&color);
- _cairo_color_set_rgb (&color, pattern->red, pattern->green, pattern->blue);
- _cairo_color_set_alpha (&color, pattern->base.alpha);
-
*out = _cairo_surface_create_similar_solid (dst,
CAIRO_FORMAT_ARGB32,
1, 1,
- &color);
+ &pattern->color);
if (*out == NULL)
return CAIRO_STATUS_NO_MEMORY;
attribs->x_offset = attribs->y_offset = 0;
- cairo_matrix_set_identity (&attribs->matrix);
+ cairo_matrix_init_identity (&attribs->matrix);
attribs->extend = CAIRO_EXTEND_REPEAT;
attribs->filter = CAIRO_FILTER_NEAREST;
attribs->acquired = FALSE;
+ attribs->clip_saved = FALSE;
return CAIRO_STATUS_SUCCESS;
}
/**
- * _cairo_pattern_is_opaque
+ * _cairo_pattern_is_opaque_solid
*
- * Convenience function to determine whether a pattern has an opaque
- * alpha value. This is done by testing whether the pattern's alpha
- * value when converted to a byte is 255, so if a backend actually
- * supported deep alpha channels this function might not do the right
- * thing.
+ * Convenience function to determine whether a pattern is an opaque
+ * (alpha==1.0) solid color pattern. This is done by testing whether
+ * the pattern's alpha value when converted to a byte is 255, so if a
+ * backend actually supported deep alpha channels this function might
+ * not do the right thing.
*
- * Note that for a gradient or surface pattern, the overall resulting
- * alpha for the pattern can be non-opaque even this function returns
- * %TRUE, since the resulting alpha is the multiplication of the
- * alpha of the gradient or surface with the pattern's alpha. In
- * the future, alpha will be moved from the base pattern to the
- * solid pattern subtype, at which point this function should
- * probably be renamed to _cairo_pattern_is_opaque_solid()
- *
- * Return value: %TRUE if the pattern is opaque
+ * Return value: %TRUE if the pattern is an opaque, solid color.
**/
cairo_bool_t
-_cairo_pattern_is_opaque (cairo_pattern_t *pattern)
+_cairo_pattern_is_opaque_solid (cairo_pattern_t *pattern)
{
- return (pattern->alpha >= ((double)0xff00 / (double)0xffff));
+ cairo_solid_pattern_t *solid;
+
+ if (pattern->type != CAIRO_PATTERN_SOLID)
+ return FALSE;
+
+ solid = (cairo_solid_pattern_t *) pattern;
+
+ return (solid->color.alpha >= ((double)0xff00 / (double)0xffff));
}
static cairo_int_status_t
@@ -1031,84 +1029,54 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
cairo_surface_attributes_t *attr)
{
cairo_int_status_t status;
+ int tx, ty;
attr->acquired = FALSE;
-
- /* handle pattern opacity */
- if (!_cairo_pattern_is_opaque (&pattern->base))
+ attr->clip_saved = FALSE;
+
+ if (_cairo_surface_is_image (dst))
{
- cairo_surface_pattern_t tmp;
- cairo_color_t color;
-
- _cairo_color_init (&color);
- _cairo_color_set_alpha (&color, pattern->base.alpha);
-
- *out = _cairo_surface_create_similar_solid (dst,
- CAIRO_FORMAT_ARGB32,
- width, height,
- &color);
- if (*out == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ cairo_image_surface_t *image;
+
+ status = _cairo_surface_begin_reset_clip (pattern->surface);
+ if (!CAIRO_OK (status))
+ return status;
- status = _cairo_pattern_init_copy (&tmp.base, &pattern->base);
- if (CAIRO_OK (status))
- {
- tmp.base.alpha = 1.0;
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &tmp.base,
- NULL,
- *out,
- x, y, 0, 0, 0, 0,
- width, height);
+ status = _cairo_surface_acquire_source_image (pattern->surface,
+ &image,
+ &attr->extra);
+ if (!CAIRO_OK (status))
+ return status;
- _cairo_pattern_fini (&tmp.base);
- }
+ _cairo_surface_end (pattern->surface);
- if (status) {
- cairo_surface_destroy (*out);
- return status;
- }
-
- attr->x_offset = -x;
- attr->y_offset = -y;
- attr->extend = CAIRO_EXTEND_NONE;
- attr->filter = CAIRO_FILTER_NEAREST;
-
- cairo_matrix_set_identity (&attr->matrix);
+ *out = &image->base;
+ attr->acquired = TRUE;
}
else
{
- int tx, ty;
-
- if (_cairo_surface_is_image (dst))
- {
- cairo_image_surface_t *image;
-
- status = _cairo_surface_acquire_source_image (pattern->surface,
- &image,
- &attr->extra);
- if (CAIRO_OK (status))
- *out = &image->base;
+ status = _cairo_surface_begin_reset_clip (pattern->surface);
+ if (!CAIRO_OK (status))
+ return status;
- attr->acquired = TRUE;
- }
- else
- status = _cairo_surface_clone_similar (dst, pattern->surface, out);
-
- attr->extend = pattern->base.extend;
- attr->filter = pattern->base.filter;
- if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
- &tx, &ty))
- {
- cairo_matrix_set_identity (&attr->matrix);
- attr->x_offset = tx;
- attr->y_offset = ty;
- }
- else
- {
- attr->matrix = pattern->base.matrix;
- attr->x_offset = attr->y_offset = 0;
- }
+ status = _cairo_surface_clone_similar (dst, pattern->surface, out);
+ _cairo_surface_end (pattern->surface);
+ }
+
+ attr->extend = pattern->base.extend;
+ attr->filter = pattern->base.filter;
+ if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
+ &tx, &ty))
+ {
+ cairo_matrix_init_identity (&attr->matrix);
+ attr->x_offset = tx;
+ attr->y_offset = ty;
+ attr->filter = CAIRO_FILTER_NEAREST;
+ }
+ else
+ {
+ attr->matrix = pattern->base.matrix;
+ attr->x_offset = attr->y_offset = 0;
}
return status;
@@ -1141,14 +1109,16 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
cairo_surface_t **surface_out,
cairo_surface_attributes_t *attributes)
{
+ cairo_status_t status;
+
switch (pattern->type) {
case CAIRO_PATTERN_SOLID: {
cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern;
- return _cairo_pattern_acquire_surface_for_solid (src, dst,
- x, y, width, height,
- surface_out,
- attributes);
+ status = _cairo_pattern_acquire_surface_for_solid (src, dst,
+ x, y, width, height,
+ surface_out,
+ attributes);
} break;
case CAIRO_PATTERN_LINEAR:
case CAIRO_PATTERN_RADIAL: {
@@ -1157,47 +1127,53 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
/* fast path for gradients with less than 2 color stops */
if (src->n_stops < 2)
{
+ const cairo_color_t *color;
cairo_solid_pattern_t solid;
if (src->n_stops)
- {
- _cairo_pattern_init_solid (&solid,
- src->stops->color.red,
- src->stops->color.green,
- src->stops->color.blue);
- _cairo_pattern_set_alpha (&solid.base,
- src->stops->color.alpha);
- }
+ color = &src->stops->color;
else
- {
- _cairo_pattern_init_solid (&solid, 0.0, 0.0, 0.0);
- _cairo_pattern_set_alpha (&solid.base, 0.0);
- }
+ color = CAIRO_COLOR_TRANSPARENT;
- return _cairo_pattern_acquire_surface_for_solid (&solid, dst,
- x, y,
- width, height,
- surface_out,
- attributes);
+ _cairo_pattern_init_solid (&solid, color);
+
+ status = _cairo_pattern_acquire_surface_for_solid (&solid, dst,
+ x, y,
+ width, height,
+ surface_out,
+ attributes);
}
else
- return _cairo_pattern_acquire_surface_for_gradient (src, dst,
- x, y,
- width, height,
- surface_out,
- attributes);
+ status = _cairo_pattern_acquire_surface_for_gradient (src, dst,
+ x, y,
+ width, height,
+ surface_out,
+ attributes);
} break;
case CAIRO_PATTERN_SURFACE: {
cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;
- return _cairo_pattern_acquire_surface_for_surface (src, dst,
- x, y, width, height,
- surface_out,
- attributes);
+ status = _cairo_pattern_acquire_surface_for_surface (src, dst,
+ x, y, width, height,
+ surface_out,
+ attributes);
} break;
+ default:
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+
+ if (CAIRO_OK (status) && (*surface_out)->clip_region) {
+ status = _cairo_surface_begin_reset_clip (*surface_out);
+ if (!CAIRO_OK (status)) {
+ _cairo_pattern_release_surface (dst, *surface_out, attributes);
+ return status;
+ }
+
+ attributes->clip_saved = TRUE;
}
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return status;
}
/**
@@ -1213,11 +1189,15 @@ _cairo_pattern_release_surface (cairo_surface_t *dst,
cairo_surface_t *surface,
cairo_surface_attributes_t *attributes)
{
+ if (attributes->clip_saved)
+ _cairo_surface_end (surface);
+
if (attributes->acquired)
+ {
_cairo_surface_release_source_image (dst,
(cairo_image_surface_t *) surface,
attributes->extra);
- else
+ } else
cairo_surface_destroy (surface);
}
@@ -1237,71 +1217,44 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
cairo_surface_attributes_t *mask_attributes)
{
cairo_int_status_t status;
-
cairo_pattern_union_t tmp;
- cairo_bool_t src_opaque, mask_opaque;
- double src_alpha, mask_alpha;
- src_opaque = _cairo_pattern_is_opaque (src);
- mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
-
- /* For surface patterns, we move any translucency from src->alpha
- * to mask->alpha so we can use the source unchanged. Otherwise we
- * move the translucency from mask->alpha to src->alpha so that
- * we can drop the mask if possible.
- */
- if (src->type == CAIRO_PATTERN_SURFACE)
- {
- if (mask) {
- mask_opaque = mask_opaque && src_opaque;
- mask_alpha = mask->alpha * src->alpha;
- } else {
- mask_opaque = src_opaque;
- mask_alpha = src->alpha;
- }
-
- src_alpha = 1.0;
- src_opaque = TRUE;
- }
- else
- {
- if (mask)
- {
- src_opaque = mask_opaque && src_opaque;
- src_alpha = mask->alpha * src->alpha;
- /* FIXME: This needs changing when we support RENDER
- * style 4-channel masks.
- */
- if (mask->type == CAIRO_PATTERN_SOLID)
- mask = NULL;
- } else
- src_alpha = src->alpha;
-
- mask_alpha = 1.0;
- mask_opaque = TRUE;
+ /* If src and mask are both solid, then the mask alpha can be
+ * combined into src and mask can be ignored. */
+
+ /* XXX: This optimization assumes that there is no color
+ * information in mask, so this will need to change when we
+ * support RENDER-style 4-channel masks. */
+ if (src->type == CAIRO_PATTERN_SOLID &&
+ mask && mask->type == CAIRO_PATTERN_SOLID)
+ {
+ cairo_color_t combined;
+ cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
+ cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
+
+ combined = src_solid->color;
+ _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
+
+ _cairo_pattern_init_solid (&tmp.solid, &combined);
+
+ mask = NULL;
+ } else {
+ _cairo_pattern_init_copy (&tmp.base, src);
}
- _cairo_pattern_init_copy (&tmp.base, src);
- _cairo_pattern_set_alpha (&tmp.base, src_alpha);
-
status = _cairo_pattern_acquire_surface (&tmp.base, dst,
src_x, src_y,
width, height,
src_out, src_attributes);
-
+
_cairo_pattern_fini (&tmp.base);
if (status)
return status;
- if (mask || !mask_opaque)
+ if (mask)
{
- if (mask)
- _cairo_pattern_init_copy (&tmp.base, mask);
- else
- _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
-
- _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
+ _cairo_pattern_init_copy (&tmp.base, mask);
status = _cairo_pattern_acquire_surface (&tmp.base, dst,
mask_x, mask_y,
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index fee918355..228c2c89a 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -153,13 +153,15 @@ struct cairo_pdf_stream {
};
struct cairo_pdf_document {
- FILE *file;
+ cairo_output_stream_t *output_stream;
unsigned long refcount;
+ cairo_surface_t *owner;
+ cairo_bool_t finished;
- double width_inches;
- double height_inches;
- double x_ppi;
- double y_ppi;
+ double width;
+ double height;
+ double x_dpi;
+ double y_dpi;
unsigned int next_available_id;
unsigned int pages_id;
@@ -175,8 +177,8 @@ struct cairo_pdf_document {
struct cairo_pdf_surface {
cairo_surface_t base;
- double width_inches;
- double height_inches;
+ double width;
+ double height;
cairo_pdf_document_t *document;
cairo_pdf_stream_t *current_stream;
@@ -188,17 +190,19 @@ struct cairo_pdf_surface {
cairo_array_t fonts;
};
+#define DEFAULT_DPI 300
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_create (cairo_output_stream_t *stream,
+ double width,
+ double height);
static void
_cairo_pdf_document_destroy (cairo_pdf_document_t *document);
+static cairo_status_t
+_cairo_pdf_document_finish (cairo_pdf_document_t *document);
+
static void
_cairo_pdf_document_reference (cairo_pdf_document_t *document);
@@ -214,11 +218,12 @@ _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);
+ const char *fmt,
+ ...);
static cairo_surface_t *
_cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
- double width_inches,
- double height_inches);
+ double width,
+ double height);
static void
_cairo_pdf_surface_add_stream (cairo_pdf_surface_t *surface,
cairo_pdf_stream_t *stream);
@@ -319,8 +324,6 @@ cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
goto fail1;
- font->base.unscaled_font = unscaled_font;
- _cairo_unscaled_font_reference (unscaled_font);
font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
if (font->glyphs == NULL)
goto fail2;
@@ -457,7 +460,7 @@ static int
cairo_pdf_ft_font_write_generic_table (cairo_pdf_ft_font_t *font,
unsigned long tag)
{
- char *buffer;
+ unsigned char *buffer;
unsigned long size;
size = 0;
@@ -475,7 +478,7 @@ cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font,
unsigned long start_offset, index, size;
TT_Header *header;
unsigned long begin, end;
- char *buffer;
+ unsigned char *buffer;
int i;
union {
unsigned char *bytes;
@@ -814,7 +817,7 @@ _cairo_pdf_document_new_object (cairo_pdf_document_t *document)
{
cairo_pdf_object_t object;
- object.offset = ftell (document->file);
+ object.offset = _cairo_output_stream_get_position (document->output_stream);
if (_cairo_array_append (&document->objects, &object, 1) == NULL)
return 0;
@@ -828,7 +831,7 @@ _cairo_pdf_document_update_object (cairo_pdf_document_t *document,
cairo_pdf_object_t *object;
object = _cairo_array_index (&document->objects, id - 1);
- object->offset = ftell (document->file);
+ object->offset = _cairo_output_stream_get_position (document->output_stream);
}
static void
@@ -899,37 +902,70 @@ _cairo_pdf_surface_add_font (cairo_pdf_surface_t *surface, unsigned int 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)
+static cairo_surface_t *
+_cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *stream,
+ double width,
+ double height)
{
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);
+ document = _cairo_pdf_document_create (stream, width, height);
if (document == NULL)
return NULL;
- surface = _cairo_pdf_surface_create_for_document (document,
- width_inches,
- height_inches);
+ surface = _cairo_pdf_surface_create_for_document (document, width, height);
+ document->owner = surface;
_cairo_pdf_document_destroy (document);
return surface;
}
+cairo_surface_t *
+cairo_pdf_surface_create_for_stream (cairo_write_func_t write,
+ void *closure,
+ double width,
+ double height)
+{
+ cairo_output_stream_t *stream;
+
+ stream = _cairo_output_stream_create (write, closure);
+ if (stream == NULL)
+ return NULL;
+
+ return _cairo_pdf_surface_create_for_stream_internal (stream, width, height);
+}
+
+cairo_surface_t *
+cairo_pdf_surface_create (const char *filename,
+ double width,
+ double height)
+{
+ cairo_output_stream_t *stream;
+
+ stream = _cairo_output_stream_create_for_file (filename);
+ if (stream == NULL)
+ return NULL;
+
+ return _cairo_pdf_surface_create_for_stream_internal (stream, width, height);
+}
+
+void
+cairo_pdf_surface_set_dpi (cairo_surface_t *surface,
+ double x_dpi,
+ double y_dpi)
+{
+ cairo_pdf_surface_t *pdf_surface = (cairo_pdf_surface_t *) surface;
+
+ pdf_surface->document->x_dpi = x_dpi;
+ pdf_surface->document->y_dpi = y_dpi;
+}
+
static cairo_surface_t *
_cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
- double width_inches,
- double height_inches)
+ double width,
+ double height)
{
cairo_pdf_surface_t *surface;
@@ -939,8 +975,8 @@ _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
_cairo_surface_init (&surface->base, &cairo_pdf_surface_backend);
- surface->width_inches = width_inches;
- surface->height_inches = height_inches;
+ surface->width = width;
+ surface->height = height;
_cairo_pdf_document_reference (document);
surface->document = document;
@@ -987,10 +1023,12 @@ _cairo_pdf_surface_create_similar (void *abstract_src,
static cairo_pdf_stream_t *
_cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
- const char *extra_entries)
+ const char *fmt,
+ ...)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output_stream = document->output_stream;
cairo_pdf_stream_t *stream;
+ va_list ap;
stream = malloc (sizeof (cairo_pdf_stream_t));
if (stream == NULL) {
@@ -1000,17 +1038,23 @@ _cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
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);
+ _cairo_output_stream_printf (output_stream,
+ "%d 0 obj\r\n"
+ "<< /Length %d 0 R\r\n",
+ stream->id,
+ stream->length_id);
+
+ if (fmt != NULL) {
+ va_start (ap, fmt);
+ _cairo_output_stream_vprintf (output_stream, fmt, ap);
+ va_end (ap);
+ }
- stream->start_offset = ftell (file);
+ _cairo_output_stream_printf (output_stream,
+ ">>\r\n"
+ "stream\r\n");
+
+ stream->start_offset = _cairo_output_stream_get_position (output_stream);
document->current_stream = stream;
@@ -1020,7 +1064,7 @@ _cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
static void
_cairo_pdf_document_close_stream (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output_stream = document->output_stream;
long length;
cairo_pdf_stream_t *stream;
@@ -1028,44 +1072,41 @@ _cairo_pdf_document_close_stream (cairo_pdf_document_t *document)
if (stream == NULL)
return;
- length = ftell(file) - stream->start_offset;
- fprintf (file,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
+ length = _cairo_output_stream_get_position (output_stream) -
+ stream->start_offset;
+ _cairo_output_stream_printf (output_stream,
+ "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);
+ _cairo_output_stream_printf (output_stream,
+ "%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)
+static cairo_status_t
+_cairo_pdf_surface_finish (void *abstract_surface)
{
+ cairo_status_t status;
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);
+ if (document->owner == &surface->base)
+ status = _cairo_pdf_document_finish (document);
+ else
+ status = CAIRO_STATUS_SUCCESS;
- free (surface);
-}
+ _cairo_pdf_document_destroy (document);
-/* 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;
+ return status;
}
static void
@@ -1073,71 +1114,29 @@ _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];
+ cairo_output_stream_t *output = document->output_stream;
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);
+ stream = _cairo_pdf_document_open_stream (document,
+ " /Type /XObject\r\n"
+ " /Subtype /Form\r\n"
+ " /BBox [ 0 0 %f %f ]\r\n",
+ surface->width,
+ surface->height);
+
_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);
+ _cairo_output_stream_printf (output,
+ "1 0 0 -1 0 %f cm\r\n",
+ document->height);
}
}
-static cairo_status_t
-_cairo_pdf_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static void
-_cairo_pdf_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_pdf_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static void
-_cairo_pdf_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_pdf_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static void *
compress_dup (const void *data, unsigned long data_size,
unsigned long *compressed_size)
@@ -1159,9 +1158,8 @@ static unsigned int
emit_image_data (cairo_pdf_document_t *document,
cairo_image_surface_t *image)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_pdf_stream_t *stream;
- char entries[200];
char *rgb, *compressed;
int i, x, y;
unsigned long rgb_size, compressed_size;
@@ -1191,18 +1189,19 @@ emit_image_data (cairo_pdf_document_t *document,
_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);
+ stream = _cairo_pdf_document_open_stream (document,
+ " /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);
+
+ _cairo_output_stream_write (output, compressed, compressed_size);
+ _cairo_output_stream_printf (output,
+ "\r\n");
_cairo_pdf_document_close_stream (document);
free (rgb);
@@ -1216,7 +1215,7 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned id;
cairo_matrix_t i2u;
cairo_status_t status;
@@ -1239,17 +1238,17 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst,
_cairo_pdf_surface_ensure_stream (dst);
- cairo_matrix_copy (&i2u, &pattern->base.matrix);
+ i2u = pattern->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);
+ _cairo_output_stream_printf (output,
+ "q %f %f %f %f %f %f cm /res%d Do Q\r\n",
+ i2u.xx, i2u.yx,
+ i2u.xy, i2u.yy,
+ i2u.x0, i2u.y0,
+ id);
bail:
_cairo_surface_release_source_image (src, image, image_extra);
@@ -1272,7 +1271,7 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_matrix_t i2u;
cairo_pdf_stream_t *stream;
int num_streams, i;
@@ -1282,30 +1281,28 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst,
src = (cairo_pdf_surface_t *) pattern->surface;
- cairo_matrix_copy (&i2u, &src->base.matrix);
+ 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));
+ cairo_matrix_scale (&i2u, 1.0 / src->width, 1.0 / src->height);
- 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]);
+ _cairo_output_stream_printf (output,
+ "q %f %f %f %f %f %f cm",
+ i2u.xx, i2u.yx,
+ i2u.xy, i2u.yy,
+ i2u.x0, i2u.y0);
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_output_stream_printf (output,
+ " /res%d Do",
+ stream->id);
_cairo_pdf_surface_add_xobject (dst, stream->id);
}
- fprintf (file, " Q\r\n");
+ _cairo_output_stream_printf (output, " Q\r\n");
return CAIRO_STATUS_SUCCESS;
}
@@ -1348,20 +1345,20 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface,
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
int i;
_cairo_pdf_surface_ensure_stream (surface);
- fprintf (file,
- "%f %f %f rg\r\n",
- color->red, color->green, color->blue);
+ _cairo_output_stream_printf (output,
+ "%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);
+ _cairo_output_stream_printf (output,
+ "%d %d %d %d re f\r\n",
+ rects[i].x, rects[i].y,
+ rects[i].width, rects[i].height);
}
return CAIRO_STATUS_SUCCESS;
@@ -1372,17 +1369,17 @@ emit_solid_pattern (cairo_pdf_surface_t *surface,
cairo_solid_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int alpha;
- alpha = _cairo_pdf_surface_add_alpha (surface, pattern->base.alpha);
+ 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->red,
- pattern->green,
- pattern->blue,
- alpha);
+ _cairo_output_stream_printf (output,
+ "%f %f %f rg /a%d gs\r\n",
+ pattern->color.red,
+ pattern->color.green,
+ pattern->color.blue,
+ alpha);
}
static void
@@ -1390,12 +1387,11 @@ emit_surface_pattern (cairo_pdf_surface_t *dst,
cairo_surface_pattern_t *pattern)
{
cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_pdf_stream_t *stream;
cairo_image_surface_t *image;
void *image_extra;
cairo_status_t status;
- char entries[250];
unsigned int id, alpha;
cairo_matrix_t pm;
@@ -1414,36 +1410,33 @@ emit_surface_pattern (cairo_pdf_surface_t *dst,
/* BBox must be smaller than XStep by YStep or acroread wont
* display the pattern. */
- cairo_matrix_set_identity (&pm);
+ cairo_matrix_init_identity (&pm);
cairo_matrix_scale (&pm, image->width, image->height);
- cairo_matrix_copy (&pm, &pattern->base.matrix);
+ pm = pattern->base.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,
+ " /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",
+ id, id);
- stream = _cairo_pdf_document_open_stream (document, entries);
- /* FIXME: emit code to show surface here. */
+ _cairo_output_stream_printf (output,
+ " /res%d Do\r\n",
+ id);
_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);
+ _cairo_output_stream_printf (output,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ stream->id, alpha);
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
}
@@ -1452,33 +1445,37 @@ static unsigned int
emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int function_id;
+ char stops[2][3];
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.red * 0xff, file);
- fputc (pattern->stops[0].color.green * 0xff, file);
- fputc (pattern->stops[0].color.blue * 0xff, file);
- fputc (pattern->stops[1].color.red * 0xff, file);
- fputc (pattern->stops[1].color.green * 0xff, file);
- fputc (pattern->stops[1].color.blue * 0xff, file);
-
- fprintf (file,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
+
+ _cairo_output_stream_printf (output,
+ "%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);
+
+ stops[0][0] = pattern->stops[0].color.red * 0xff + 0.5;
+ stops[0][1] = pattern->stops[0].color.green * 0xff + 0.5;
+ stops[0][2] = pattern->stops[0].color.blue * 0xff + 0.5;
+ stops[1][0] = pattern->stops[1].color.red * 0xff + 0.5;
+ stops[1][1] = pattern->stops[1].color.green * 0xff + 0.5;
+ stops[1][2] = pattern->stops[1].color.blue * 0xff + 0.5;
+
+ _cairo_output_stream_write (output, stops, sizeof (stops));
+
+ _cairo_output_stream_printf (output,
+ "\r\n"
+ "endstream\r\n"
+ "endobj\r\n");
return function_id;
}
@@ -1487,7 +1484,7 @@ static void
emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int function_id, pattern_id, alpha;
double x0, y0, x1, y1;
cairo_matrix_t p2u;
@@ -1496,7 +1493,7 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte
function_id = emit_pattern_stops (surface, &pattern->base);
- cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
+ p2u = pattern->base.base.matrix;
cairo_matrix_invert (&p2u);
x0 = pattern->point0.x;
@@ -1507,24 +1504,24 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte
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 [ true true ]\r\n"
- " >>\r\n"
- ">>\r\n"
- "endobj\r\n",
- pattern_id,
- document->height_inches * document->y_ppi,
- x0, y0, x1, y1,
- function_id);
+ _cairo_output_stream_printf (output,
+ "%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 [ true true ]\r\n"
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ pattern_id,
+ document->height,
+ x0, y0, x1, y1,
+ function_id);
_cairo_pdf_surface_add_pattern (surface, pattern_id);
@@ -1532,16 +1529,16 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *patte
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);
+ _cairo_output_stream_printf (output,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ pattern_id, alpha);
}
static void
emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern)
{
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int function_id, pattern_id, alpha;
double x0, y0, x1, y1, r0, r1;
cairo_matrix_t p2u;
@@ -1550,7 +1547,7 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte
function_id = emit_pattern_stops (surface, &pattern->base);
- cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
+ p2u = pattern->base.base.matrix;
cairo_matrix_invert (&p2u);
x0 = pattern->center0.x;
@@ -1574,24 +1571,24 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte
* behavoir, not yet sure how to implement the cairo mirror and
* repeat behaviour. */
pattern_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /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 [ true true ]\r\n"
- " >>\r\n"
- ">>\r\n"
- "endobj\r\n",
- pattern_id,
- document->height_inches * document->y_ppi,
- x0, y0, r0, x1, y1, r1,
- function_id);
+ _cairo_output_stream_printf (output,
+ "%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 [ true true ]\r\n"
+ " >>\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ pattern_id,
+ document->height,
+ x0, y0, r0, x1, y1, r1,
+ function_id);
_cairo_pdf_surface_add_pattern (surface, pattern_id);
@@ -1599,9 +1596,9 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *patte
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);
+ _cairo_output_stream_printf (output,
+ "/Pattern cs /res%d scn /a%d gs\r\n",
+ pattern_id, alpha);
}
static void
@@ -1635,6 +1632,104 @@ intersect (cairo_line_t *line, cairo_fixed_t y)
_cairo_fixed_to_double (line->p2.y - line->p1.y);
}
+typedef struct
+{
+ cairo_output_stream_t *output_stream;
+} pdf_path_info_t;
+
+static cairo_status_t
+_cairo_pdf_path_move_to (void *closure, cairo_point_t *point)
+{
+ pdf_path_info_t *info = closure;
+
+ _cairo_output_stream_printf (info->output_stream,
+ "%f %f m ",
+ _cairo_fixed_to_double (point->x),
+ _cairo_fixed_to_double (point->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_path_line_to (void *closure, cairo_point_t *point)
+{
+ pdf_path_info_t *info = closure;
+
+ _cairo_output_stream_printf (info->output_stream,
+ "%f %f l ",
+ _cairo_fixed_to_double (point->x),
+ _cairo_fixed_to_double (point->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_path_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
+{
+ pdf_path_info_t *info = closure;
+
+ _cairo_output_stream_printf (info->output_stream,
+ "%f %f %f %f %f %f c ",
+ _cairo_fixed_to_double (b->x),
+ _cairo_fixed_to_double (b->y),
+ _cairo_fixed_to_double (c->x),
+ _cairo_fixed_to_double (c->y),
+ _cairo_fixed_to_double (d->x),
+ _cairo_fixed_to_double (d->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_pdf_path_close_path (void *closure)
+{
+ pdf_path_info_t *info = closure;
+
+ _cairo_output_stream_printf (info->output_stream,
+ "h\r\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_fill_path (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ void *abstract_dst,
+ cairo_path_fixed_t *path)
+{
+ cairo_pdf_surface_t *surface = abstract_dst;
+ cairo_pdf_document_t *document = surface->document;
+ cairo_status_t status;
+ pdf_path_info_t info;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ emit_pattern (surface, pattern);
+
+ /* After the above switch the current stream should belong to this
+ * surface, so no need to _cairo_pdf_surface_ensure_stream() */
+ assert (document->current_stream != NULL &&
+ document->current_stream == surface->current_stream);
+
+ info.output_stream = document->output_stream;
+
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_pdf_path_move_to,
+ _cairo_pdf_path_line_to,
+ _cairo_pdf_path_curve_to,
+ _cairo_pdf_path_close_path,
+ &info);
+
+ _cairo_output_stream_printf (document->output_stream,
+ "f\r\n");
+
+ return status;
+}
+
static cairo_int_status_t
_cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator,
cairo_pattern_t *pattern,
@@ -1650,7 +1745,7 @@ _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator,
{
cairo_pdf_surface_t *surface = abstract_dst;
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
int i;
emit_pattern (surface, pattern);
@@ -1668,16 +1763,16 @@ _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator,
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));
+ _cairo_output_stream_printf (output,
+ "%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");
+ _cairo_output_stream_printf (output,
+ "f\r\n");
return CAIRO_STATUS_SUCCESS;
}
@@ -1706,21 +1801,33 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
}
static cairo_int_status_t
-_cairo_pdf_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
+_cairo_pdf_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ rectangle->x = 0;
+ rectangle->y = 0;
+
+ /* XXX: The conversion to integers here is pretty bogus, (not to
+ * mention the aribitray limitation of width to a short(!). We
+ * may need to come up with a better interface for get_size.
+ */
+ rectangle->width = (int) ceil (surface->width);
+ rectangle->height = (int) ceil (surface->height);
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_pdf_font_t *
_cairo_pdf_document_get_font (cairo_pdf_document_t *document,
- cairo_font_t *font)
+ cairo_scaled_font_t *scaled_font)
{
cairo_unscaled_font_t *unscaled_font;
cairo_pdf_font_t *pdf_font;
unsigned int num_fonts, i;
- unscaled_font = _cairo_ft_font_get_unscaled_font (font);
+ unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font);
num_fonts = _cairo_array_num_elements (&document->fonts);
for (i = 0; i < num_fonts; i++) {
@@ -1743,8 +1850,8 @@ _cairo_pdf_document_get_font (cairo_pdf_document_t *document,
return pdf_font;
}
-static cairo_status_t
-_cairo_pdf_surface_show_glyphs (cairo_font_t *font,
+static cairo_int_status_t
+_cairo_pdf_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
cairo_pattern_t *pattern,
void *abstract_surface,
@@ -1759,32 +1866,34 @@ _cairo_pdf_surface_show_glyphs (cairo_font_t *font,
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_pdf_font_t *pdf_font;
int i, index;
- pdf_font = _cairo_pdf_document_get_font (document, font);
+ pdf_font = _cairo_pdf_document_get_font (document, scaled_font);
if (pdf_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
emit_pattern (surface, pattern);
- fprintf (file, "BT /res%u 1 Tf", pdf_font->font_id);
+ _cairo_output_stream_printf (output,
+ "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 (\\%o) Tj",
- font->scale.matrix[0][0],
- font->scale.matrix[0][1],
- font->scale.matrix[1][0],
- -font->scale.matrix[1][1],
- glyphs[i].x,
- glyphs[i].y,
- index);
+ _cairo_output_stream_printf (output,
+ " %f %f %f %f %f %f Tm (\\%o) Tj",
+ scaled_font->scale.xx,
+ scaled_font->scale.yx,
+ scaled_font->scale.xy,
+ -scaled_font->scale.yy,
+ glyphs[i].x,
+ glyphs[i].y,
+ index);
}
- fprintf (file, " ET\r\n");
+ _cairo_output_stream_printf (output,
+ " ET\r\n");
_cairo_pdf_surface_add_font (surface, pdf_font->font_id);
@@ -1793,28 +1902,27 @@ _cairo_pdf_surface_show_glyphs (cairo_font_t *font,
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_acquire_source_image,
- _cairo_pdf_surface_release_source_image,
- _cairo_pdf_surface_acquire_dest_image,
- _cairo_pdf_surface_release_dest_image,
- _cairo_pdf_surface_clone_similar,
+ _cairo_pdf_surface_finish,
+ NULL, /* acquire_source_image */
+ NULL, /* release_source_image */
+ NULL, /* acquire_dest_image */
+ NULL, /* release_dest_image */
+ NULL, /* clone_similar */
_cairo_pdf_surface_composite,
_cairo_pdf_surface_fill_rectangles,
_cairo_pdf_surface_composite_trapezoids,
_cairo_pdf_surface_copy_page,
_cairo_pdf_surface_show_page,
- _cairo_pdf_surface_set_clip_region,
- _cairo_pdf_surface_show_glyphs
+ NULL, /* set_clip_region */
+ _cairo_pdf_surface_get_extents,
+ _cairo_pdf_surface_show_glyphs,
+ _cairo_pdf_surface_fill_path
};
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_create (cairo_output_stream_t *output_stream,
+ double width,
+ double height)
{
cairo_pdf_document_t *document;
@@ -1822,12 +1930,14 @@ _cairo_pdf_document_create (FILE *file,
if (document == NULL)
return NULL;
- document->file = file;
+ document->output_stream = output_stream;
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;
+ document->owner = NULL;
+ document->finished = FALSE;
+ document->width = width;
+ document->height = height;
+ document->x_dpi = DEFAULT_DPI;
+ document->y_dpi = DEFAULT_DPI;
_cairo_array_init (&document->objects, sizeof (cairo_pdf_object_t));
_cairo_array_init (&document->pages, sizeof (unsigned int));
@@ -1840,7 +1950,8 @@ _cairo_pdf_document_create (FILE *file,
_cairo_array_init (&document->fonts, sizeof (cairo_pdf_font_t *));
/* Document header */
- fprintf (file, "%%PDF-1.4\r\n");
+ _cairo_output_stream_printf (output_stream,
+ "%%PDF-1.4\r\n");
return document;
}
@@ -1848,17 +1959,17 @@ _cairo_pdf_document_create (FILE *file,
static unsigned int
_cairo_pdf_document_write_info (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
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);
+ _cairo_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /Creator (cairographics.org)\r\n"
+ " /Producer (cairographics.org)\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ id);
return id;
}
@@ -1866,40 +1977,40 @@ _cairo_pdf_document_write_info (cairo_pdf_document_t *document)
static void
_cairo_pdf_document_write_pages (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *stream = document->output_stream;
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);
+ _cairo_output_stream_printf (stream,
+ "%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);
+ _cairo_output_stream_printf (stream, "%d 0 R ", page_id);
}
- fprintf (file, "]\r\n");
- fprintf (file, " /Count %d\r\n", num_pages);
+ _cairo_output_stream_printf (stream, "]\r\n");
+ _cairo_output_stream_printf (stream, " /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);
+ _cairo_output_stream_printf (stream,
+ " /MediaBox [ 0 0 %f %f ]\r\n"
+ ">>\r\n"
+ "endobj\r\n",
+ document->width,
+ document->height);
}
static cairo_status_t
_cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_pdf_font_t *font;
int num_fonts, i, j;
const char *data;
@@ -1923,76 +2034,76 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
}
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");
+ _cairo_output_stream_printf (output,
+ "%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);
+ _cairo_output_stream_write (output, compressed, compressed_size);
+ _cairo_output_stream_printf (output,
+ "\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 /7%s\r\n"
- " /Flags 4\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_output_stream_printf (output,
+ "%d 0 obj\r\n"
+ "<< /Type /FontDescriptor\r\n"
+ " /FontName /7%s\r\n"
+ " /Flags 4\r\n"
+ " /FontBBox [ %ld %ld %ld %ld ]\r\n"
+ " /ItalicAngle 0\r\n"
+ " /Ascent %ld\r\n"
+ " /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,
- "[");
+ _cairo_output_stream_printf (output,
+ "%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);
+
+ _cairo_output_stream_printf (output,
+ "[");
for (j = 0; j < font->num_glyphs; j++)
- fprintf (file,
- " %d",
- font->widths[j]);
+ _cairo_output_stream_printf (output,
+ " %d",
+ font->widths[j]);
- fprintf (file,
- " ]\r\n"
- ">>\r\n"
- "endobj\r\n");
+ _cairo_output_stream_printf (output,
+ " ]\r\n"
+ ">>\r\n"
+ "endobj\r\n");
fail:
cairo_pdf_ft_font_destroy (font);
@@ -2004,17 +2115,17 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
static unsigned int
_cairo_pdf_document_write_catalog (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
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);
+ _cairo_output_stream_printf (output,
+ "%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;
}
@@ -2022,23 +2133,27 @@ _cairo_pdf_document_write_catalog (cairo_pdf_document_t *document)
static long
_cairo_pdf_document_write_xref (cairo_pdf_document_t *document)
{
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
cairo_pdf_object_t *object;
int num_objects, i;
long offset;
+ char buffer[11];
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);
+ offset = _cairo_output_stream_get_position (output);
+ _cairo_output_stream_printf (output,
+ "xref\r\n"
+ "%d %d\r\n",
+ 0, num_objects + 1);
- fprintf (file, "0000000000 65535 f\r\n");
+ _cairo_output_stream_printf (output,
+ "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);
+ snprintf (buffer, sizeof buffer, "%010ld", object->offset);
+ _cairo_output_stream_printf (output,
+ "%s 00000 n\r\n", buffer);
}
return offset;
@@ -2053,14 +2168,26 @@ _cairo_pdf_document_reference (cairo_pdf_document_t *document)
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_finish (document);
+
+ free (document);
+}
+
+static cairo_status_t
+_cairo_pdf_document_finish (cairo_pdf_document_t *document)
+{
+ cairo_status_t status;
+ cairo_output_stream_t *output = document->output_stream;
+ long offset;
+ unsigned int info_id, catalog_id;
+
+ if (document->finished)
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_pdf_document_close_stream (document);
_cairo_pdf_document_write_pages (document);
_cairo_pdf_document_write_fonts (document);
@@ -2068,23 +2195,28 @@ _cairo_pdf_document_destroy (cairo_pdf_document_t *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);
+ _cairo_output_stream_printf (output,
+ "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);
+
+ _cairo_output_stream_printf (output,
+ "startxref\r\n"
+ "%ld\r\n"
+ "%%%%EOF\r\n",
+ offset);
+
+ status = _cairo_output_stream_get_status (output);
+ _cairo_output_stream_destroy (output);
+
+ document->finished = TRUE;
- free (document);
+ return status;
}
static cairo_status_t
@@ -2093,130 +2225,105 @@ _cairo_pdf_document_add_page (cairo_pdf_document_t *document,
{
cairo_pdf_stream_t *stream;
cairo_pdf_resource_t *res;
- FILE *file = document->file;
+ cairo_output_stream_t *output = document->output_stream;
unsigned int page_id;
double alpha;
int num_streams, num_alphas, num_resources, i;
+ assert (!document->finished);
+
_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);
+ _cairo_output_stream_printf (output,
+ "%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);
+ _cairo_output_stream_printf (output,
+ " %d 0 R",
+ stream->id);
}
- fprintf (file,
- " ]\r\n"
- " /Resources <<\r\n");
+ _cairo_output_stream_printf (output,
+ " ]\r\n"
+ " /Resources <<\r\n");
num_resources = _cairo_array_num_elements (&surface->fonts);
if (num_resources > 0) {
- fprintf (file,
- " /Font <<");
+ _cairo_output_stream_printf (output,
+ " /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);
+ _cairo_output_stream_printf (output,
+ " /res%d %d 0 R",
+ res->id, res->id);
}
- fprintf (file,
- " >>\r\n");
+ _cairo_output_stream_printf (output,
+ " >>\r\n");
}
num_alphas = _cairo_array_num_elements (&surface->alphas);
if (num_alphas > 0) {
- fprintf (file,
- " /ExtGState <<\r\n");
+ _cairo_output_stream_printf (output,
+ " /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);
+ _cairo_output_stream_printf (output,
+ " /a%d << /ca %f >>\r\n",
+ i, alpha);
}
- fprintf (file,
- " >>\r\n");
+ _cairo_output_stream_printf (output,
+ " >>\r\n");
}
num_resources = _cairo_array_num_elements (&surface->patterns);
if (num_resources > 0) {
- fprintf (file,
- " /Pattern <<");
+ _cairo_output_stream_printf (output,
+ " /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);
+ _cairo_output_stream_printf (output,
+ " /res%d %d 0 R",
+ res->id, res->id);
}
- fprintf (file,
- " >>\r\n");
+ _cairo_output_stream_printf (output,
+ " >>\r\n");
}
num_resources = _cairo_array_num_elements (&surface->xobjects);
if (num_resources > 0) {
- fprintf (file,
- " /XObject <<");
+ _cairo_output_stream_printf (output,
+ " /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);
+ _cairo_output_stream_printf (output,
+ " /res%d %d 0 R",
+ res->id, res->id);
}
- fprintf (file,
- " >>\r\n");
+ _cairo_output_stream_printf (output,
+ " >>\r\n");
}
- fprintf (file,
- " >>\r\n"
- ">>\r\n"
- "endobj\r\n");
+ _cairo_output_stream_printf (output,
+ " >>\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
index 701a7b4a7..61bf7a841 100644
--- a/src/cairo-pdf.h
+++ b/src/cairo-pdf.h
@@ -39,29 +39,30 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_PDF_SURFACE
-
-#include <stdio.h>
+#if CAIRO_HAS_PDF_SURFACE
CAIRO_BEGIN_DECLS
-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 (const char *filename,
+ double width_in_points,
+ double height_in_points);
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_surface_create_for_stream (cairo_write_func_t write_func,
+ void *closure,
+ double width_in_points,
+ double height_in_points);
+
+void
+cairo_pdf_surface_set_dpi (cairo_surface_t *surface,
+ double x_dpi,
+ double y_dpi);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_PDF_SURFACE */
+# error Cairo was not compiled with support for the pdf backend
#endif /* CAIRO_HAS_PDF_SURFACE */
+
#endif /* CAIRO_PDF_H */
diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index 6ecaa00b3..18b9ddb59 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -36,6 +36,8 @@
#include "cairoint.h"
+#include "cairo-gstate-private.h"
+
static int
_cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix);
@@ -372,8 +374,8 @@ _cairo_pen_vertices_needed (double tolerance,
double radius,
cairo_matrix_t *matrix)
{
- double a = matrix->m[0][0], c = matrix->m[0][1];
- double b = matrix->m[1][0], d = matrix->m[1][1];
+ double a = matrix->xx, b = matrix->yx;
+ double c = matrix->xy, d = matrix->yy;
double i = a*a + c*c;
double j = b*b + d*d;
diff --git a/src/cairo-png.c b/src/cairo-png.c
new file mode 100644
index 000000000..ecb23ca45
--- /dev/null
+++ b/src/cairo-png.c
@@ -0,0 +1,465 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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
+ * 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@cworth.org>
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include <png.h>
+#include "cairoint.h"
+
+static void
+unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
+{
+ int i;
+
+ for (i = 0; i < row_info->rowbytes; i += 4) {
+ uint8_t *b = &data[i];
+ uint32_t pixel;
+ uint8_t alpha;
+
+ memcpy (&pixel, b, sizeof (uint32_t));
+ alpha = (pixel & 0xff000000) >> 24;
+ if (alpha == 0) {
+ b[0] = b[1] = b[2] = b[3] = 0;
+ } else {
+ b[0] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
+ b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
+ b[2] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
+ b[3] = alpha;
+ }
+ }
+}
+
+static cairo_status_t
+write_png (cairo_surface_t *surface,
+ png_rw_ptr write_func,
+ void *closure)
+{
+ int i;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_image_surface_t *image;
+ void *image_extra;
+ png_struct *png;
+ png_info *info;
+ png_time pt;
+ png_byte **rows;
+ png_color_16 white;
+ int png_color_type;
+ int depth;
+
+ status = _cairo_surface_acquire_source_image (surface,
+ &image,
+ &image_extra);
+
+ if (status == CAIRO_STATUS_NO_MEMORY)
+ return CAIRO_STATUS_NO_MEMORY;
+ else if (status != CAIRO_STATUS_SUCCESS)
+ return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
+
+ rows = malloc (image->height * sizeof(png_byte*));
+ if (rows == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL1;
+ }
+
+ for (i = 0; i < image->height; i++)
+ rows[i] = (png_byte *) image->data + i * image->stride;
+
+ png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL2;
+ }
+
+ info = png_create_info_struct (png);
+ if (info == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL3;
+ }
+
+ if (setjmp (png_jmpbuf (png))) {
+ status = CAIRO_STATUS_NO_MEMORY;
+ goto BAIL3;
+ }
+
+ png_set_write_fn (png, closure, write_func, NULL);
+
+ switch (image->format) {
+ case CAIRO_FORMAT_ARGB32:
+ depth = 8;
+ png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ depth = 8;
+ png_color_type = PNG_COLOR_TYPE_RGB;
+ break;
+ case CAIRO_FORMAT_A8:
+ depth = 8;
+ png_color_type = PNG_COLOR_TYPE_GRAY;
+ break;
+ case CAIRO_FORMAT_A1:
+ depth = 1;
+ png_color_type = PNG_COLOR_TYPE_GRAY;
+ break;
+ default:
+ status = CAIRO_STATUS_NULL_POINTER;
+ goto BAIL3;
+ }
+
+ png_set_IHDR (png, info,
+ image->width,
+ image->height, depth,
+ png_color_type,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+ white.red = 0xff;
+ white.blue = 0xff;
+ white.green = 0xff;
+ png_set_bKGD (png, info, &white);
+
+ png_convert_from_time_t (&pt, time (NULL));
+ png_set_tIME (png, info, &pt);
+
+ png_set_write_user_transform_fn (png, unpremultiply_data);
+ if (image->format == CAIRO_FORMAT_ARGB32 ||
+ image->format == CAIRO_FORMAT_RGB24)
+ png_set_bgr (png);
+ if (image->format == CAIRO_FORMAT_RGB24)
+ png_set_filler (png, 0, PNG_FILLER_AFTER);
+
+ png_write_info (png, info);
+ png_write_image (png, rows);
+ png_write_end (png, info);
+
+BAIL3:
+ png_destroy_write_struct (&png, &info);
+BAIL2:
+ free (rows);
+BAIL1:
+ _cairo_surface_release_source_image (surface, image, image_extra);
+
+ return status;
+}
+
+static void
+stdio_write_func (png_structp png, png_bytep data, png_size_t size)
+{
+ FILE *fp;
+
+ fp = png_get_io_ptr (png);
+ if (fwrite (data, 1, size, fp) != size)
+ png_error(png, "Write Error");
+}
+
+/**
+ * cairo_surface_write_to_png:
+ * @surface: a #cairo_surface_t with pixel contents
+ * @filename: the name of a file to write to
+ *
+ * Writes the contents of @surface to a new file @filename as a PNG
+ * image.
+ *
+ * Return value: CAIRO_STATUS_SUCCESS if the PNG file was written
+ * successfully. Otherwise, CAIRO_STATUS_NO_MEMORY if memory could not
+ * be allocated for the operation or
+ * CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
+ * pixel contents, or CAIRO_STATUS_WRITE_ERROR if an I/O error occurs
+ * while attempting to write the file.
+ **/
+cairo_status_t
+cairo_surface_write_to_png (cairo_surface_t *surface,
+ const char *filename)
+{
+ FILE *fp;
+ cairo_status_t status;
+
+ fp = fopen (filename, "wb");
+ if (fp == NULL)
+ return CAIRO_STATUS_WRITE_ERROR;
+
+ status = write_png (surface, stdio_write_func, fp);
+
+ if (fclose (fp) && CAIRO_OK (status))
+ status = CAIRO_STATUS_WRITE_ERROR;
+
+ return status;
+}
+
+struct png_write_closure_t {
+ cairo_write_func_t write_func;
+ void *closure;
+};
+
+static void
+stream_write_func (png_structp png, png_bytep data, png_size_t size)
+{
+ struct png_write_closure_t *png_closure;
+
+ png_closure = png_get_io_ptr (png);
+ if (!CAIRO_OK (png_closure->write_func (png_closure->closure, data, size)))
+ png_error(png, "Write Error");
+}
+
+/**
+ * cairo_surface_write_to_png_stream:
+ * @surface: a #cairo_surface_t with pixel contents
+ * @write_func: a #cairo_write_func_t
+ * @closure: closure data for the write function
+ *
+ * Writes the image surface to the write function.
+ *
+ * Return value: CAIRO_STATUS_SUCCESS if the PNG file was written
+ * successfully. Otherwise, CAIRO_STATUS_NO_MEMORY is returned if
+ * memory could not be allocated for the operation,
+ * CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
+ * pixel contents.
+ **/
+cairo_status_t
+cairo_surface_write_to_png_stream (cairo_surface_t *surface,
+ cairo_write_func_t write_func,
+ void *closure)
+{
+ struct png_write_closure_t png_closure;
+
+ png_closure.write_func = write_func;
+ png_closure.closure = closure;
+
+ return write_png (surface, stream_write_func, &png_closure);
+}
+
+static void
+premultiply_data (png_structp png,
+ png_row_infop row_info,
+ png_bytep data)
+{
+ int i;
+
+ for (i = 0; i < row_info->rowbytes; i += 4) {
+ uint8_t *base = &data[i];
+ uint8_t blue = base[0];
+ uint8_t green = base[1];
+ uint8_t red = base[2];
+ uint8_t alpha = base[3];
+ uint32_t p;
+
+ red = ((unsigned) red * (unsigned) alpha + 127) / 255;
+ green = ((unsigned) green * (unsigned) alpha + 127) / 255;
+ blue = ((unsigned) blue * (unsigned) alpha + 127) / 255;
+ p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
+ memcpy (base, &p, sizeof (uint32_t));
+ }
+}
+
+static cairo_surface_t *
+read_png (png_rw_ptr read_func,
+ void *closure)
+{
+ cairo_surface_t *surface;
+ png_byte *data;
+ int i;
+ png_struct *png;
+ png_info *info;
+ png_uint_32 png_width, png_height, stride;
+ int depth, color_type, interlace;
+ unsigned int pixel_size;
+ png_byte **row_pointers;
+
+ surface = NULL;
+ data = NULL;
+ row_pointers = NULL;
+
+ /* XXX: Perhaps we'll want some other error handlers? */
+ png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
+ NULL,
+ NULL,
+ NULL);
+ if (png == NULL)
+ return NULL;
+
+ info = png_create_info_struct (png);
+ if (info == NULL)
+ goto BAIL;
+
+ png_set_read_fn (png, closure, read_func);
+
+ if (setjmp (png_jmpbuf (png)))
+ goto BAIL;
+
+ png_read_info (png, info);
+
+ png_get_IHDR (png, info,
+ &png_width, &png_height, &depth,
+ &color_type, &interlace, NULL, NULL);
+ stride = 4 * png_width;
+
+ /* convert palette/gray image to rgb */
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb (png);
+
+ /* expand gray bit depth if needed */
+ if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8)
+ png_set_gray_1_2_4_to_8 (png);
+ /* transform transparency to alpha */
+ if (png_get_valid(png, info, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha (png);
+
+ if (depth == 16)
+ png_set_strip_16 (png);
+
+ if (depth < 8)
+ png_set_packing (png);
+
+ /* convert grayscale to RGB */
+ if (color_type == PNG_COLOR_TYPE_GRAY
+ || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb (png);
+
+ if (interlace != PNG_INTERLACE_NONE)
+ png_set_interlace_handling (png);
+
+ png_set_bgr (png);
+ png_set_filler (png, 0xff, PNG_FILLER_AFTER);
+
+ png_set_read_user_transform_fn (png, premultiply_data);
+
+ png_read_update_info (png, info);
+
+ pixel_size = 4;
+ data = malloc (png_width * png_height * pixel_size);
+ if (data == NULL)
+ goto BAIL;
+
+ row_pointers = malloc (png_height * sizeof(char *));
+ if (row_pointers == NULL)
+ goto BAIL;
+
+ for (i = 0; i < png_height; i++)
+ row_pointers[i] = &data[i * png_width * pixel_size];
+
+ png_read_image (png, row_pointers);
+ png_read_end (png, info);
+
+ surface = cairo_image_surface_create_for_data (data,
+ CAIRO_FORMAT_ARGB32,
+ png_width, png_height, stride);
+ _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
+ data = NULL;
+
+ BAIL:
+ free (row_pointers);
+ free (data);
+ png_destroy_read_struct (&png, NULL, NULL);
+
+ return surface;
+}
+
+static void
+stdio_read_func (png_structp png, png_bytep data, png_size_t size)
+{
+ FILE *fp;
+
+ fp = png_get_io_ptr (png);
+ if (fread (data, 1, size, fp) != size)
+ png_error(png, "Read Error");
+}
+
+/**
+ * cairo_image_surface_create_from_png:
+ * @filename: name of PNG file to load
+ *
+ * Creates a new image surface and initializes the contents to the
+ * given PNG file.
+ *
+ * Return value: a new #cairo_surface_t initialized with the contents
+ * of the PNG file or %NULL if the file is not a valid PNG file or
+ * memory could not be allocated for the operation.
+ **/
+cairo_surface_t *
+cairo_image_surface_create_from_png (const char *filename)
+{
+ FILE *fp;
+ cairo_surface_t *surface;
+
+ fp = fopen (filename, "rb");
+ if (fp == NULL)
+ return NULL;
+
+ surface = read_png (stdio_read_func, fp);
+
+ fclose (fp);
+
+ return surface;
+}
+
+struct png_read_closure_t {
+ cairo_read_func_t read_func;
+ void *closure;
+};
+
+static void
+stream_read_func (png_structp png, png_bytep data, png_size_t size)
+{
+ struct png_read_closure_t *png_closure;
+
+ png_closure = png_get_io_ptr (png);
+ if (!CAIRO_OK (png_closure->read_func (png_closure->closure, data, size)))
+ png_error(png, "Read Error");
+}
+
+/**
+ * cairo_image_surface_create_from_png_stream:
+ * @read_func: function called to read the data of the file
+ * @closure: data to pass to @read_func.
+ *
+ * Creates a new image surface from PNG data read incrementally
+ * via the @read_func function.
+ *
+ * Return value: a new #cairo_surface_t initialized with the contents
+ * of the PNG file or %NULL if the data read is not a valid PNG image or
+ * memory could not be allocated for the operation.
+ **/
+cairo_surface_t *
+cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
+ void *closure)
+{
+ struct png_read_closure_t png_closure;
+
+ png_closure.read_func = read_func;
+ png_closure.closure = closure;
+
+ return read_png (stream_read_func, &closure);
+}
+
diff --git a/src/cairo-private.h b/src/cairo-private.h
new file mode 100644
index 000000000..a43c8ef7f
--- /dev/null
+++ b/src/cairo-private.h
@@ -0,0 +1,51 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@redhat.com>
+ */
+
+#ifndef CAIRO_PRIVATE_H
+#define CAIRO_PRIVATE_H
+
+#include "cairo-gstate-private.h"
+#include "cairo-path-fixed-private.h"
+
+struct _cairo {
+ unsigned int ref_count;
+
+ cairo_gstate_t *gstate;
+ cairo_path_fixed_t path;
+
+ cairo_status_t status;
+};
+
+#endif /* CAIRO_PRIVATE_H */
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 4a45fc679..a79703e1d 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -42,74 +42,34 @@
static const cairo_surface_backend_t cairo_ps_surface_backend;
-/**
- * cairo_set_target_ps:
- * @cr: a #cairo_t
- * @file: an open, writeable file
- * @width_inches: width of the output page, in inches
- * @height_inches: height of the output page, in inches
- * @x_pixels_per_inch: X resolution to use for image fallbacks;
- * not all Cairo drawing can be represented in a postscript
- * file, so Cairo will write out images for some portions
- * of the output.
- * @y_pixels_per_inch: Y resolution to use for image fallbacks.
- *
- * Directs output for a #cairo_t to a postscript file. The file must
- * be kept open until the #cairo_t is destroyed or set to have a
- * different target, and then must be closed by the application.
- **/
-void
-cairo_set_target_ps (cairo_t *cr,
- FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
-{
- cairo_surface_t *surface;
-
- surface = cairo_ps_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);
-}
-
typedef struct cairo_ps_surface {
cairo_surface_t base;
/* PS-specific fields */
- FILE *file;
+ cairo_output_stream_t *stream;
- double width_inches;
- double height_inches;
- double x_ppi;
- double y_ppi;
+ double width_in_points;
+ double height_in_points;
+ double x_dpi;
+ double y_dpi;
int pages;
cairo_image_surface_t *image;
} cairo_ps_surface_t;
+#define PS_SURFACE_DPI_DEFAULT 300.0
+
static void
_cairo_ps_surface_erase (cairo_ps_surface_t *surface);
-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)
+static cairo_surface_t *
+_cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
+ double width_in_points,
+ double height_in_points)
{
cairo_ps_surface_t *surface;
- int width, height;
+ int width_in_pixels, height_in_pixels;
time_t now = time (0);
surface = malloc (sizeof (cairo_ps_surface_t));
@@ -118,20 +78,21 @@ cairo_ps_surface_create (FILE *file,
_cairo_surface_init (&surface->base, &cairo_ps_surface_backend);
- surface->file = file;
+ surface->stream = stream;
- surface->width_inches = width_inches;
- surface->height_inches = height_inches;
- surface->x_ppi = x_pixels_per_inch;
- surface->y_ppi = x_pixels_per_inch;
+ surface->width_in_points = width_in_points;
+ surface->height_in_points = height_in_points;
+ surface->x_dpi = PS_SURFACE_DPI_DEFAULT;
+ surface->y_dpi = PS_SURFACE_DPI_DEFAULT;
surface->pages = 0;
- width = (int) (x_pixels_per_inch * width_inches + 1.0);
- height = (int) (y_pixels_per_inch * height_inches + 1.0);
+ width_in_pixels = (int) (surface->x_dpi * width_in_points / 72.0 + 1.0);
+ height_in_pixels = (int) (surface->y_dpi * height_in_points / 72.0 + 1.0);
surface->image = (cairo_image_surface_t *)
- cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ width_in_pixels, height_in_pixels);
if (surface->image == NULL) {
free (surface);
return NULL;
@@ -140,26 +101,61 @@ cairo_ps_surface_create (FILE *file,
_cairo_ps_surface_erase (surface);
/* Document header */
- fprintf (file,
- "%%!PS-Adobe-3.0\n"
- "%%%%Creator: Cairo (http://cairographics.org)\n");
- fprintf (file,
- "%%%%CreationDate: %s",
- ctime (&now));
- fprintf (file,
- "%%%%BoundingBox: %d %d %d %d\n",
- 0, 0, (int) (surface->width_inches * 72.0), (int) (surface->height_inches * 72.0));
+ _cairo_output_stream_printf (surface->stream,
+ "%%!PS-Adobe-3.0\n"
+ "%%%%Creator: Cairo (http://cairographics.org)\n");
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%CreationDate: %s",
+ ctime (&now));
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%BoundingBox: %f %f %f %f\n",
+ 0.0, 0.0,
+ surface->width_in_points,
+ surface->height_in_points);
/* The "/FlateDecode filter" currently used is a feature of LanguageLevel 3 */
- fprintf (file,
- "%%%%DocumentData: Clean7Bit\n"
- "%%%%LanguageLevel: 3\n");
- fprintf (file,
- "%%%%Orientation: Portrait\n"
- "%%%%EndComments\n");
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%DocumentData: Clean7Bit\n"
+ "%%%%LanguageLevel: 3\n");
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%Orientation: Portrait\n"
+ "%%%%EndComments\n");
return &surface->base;
}
+cairo_surface_t *
+cairo_ps_surface_create (const char *filename,
+ double width_in_points,
+ double height_in_points)
+{
+ cairo_output_stream_t *stream;
+
+ stream = _cairo_output_stream_create_for_file (filename);
+ if (stream == NULL)
+ return NULL;
+
+ return _cairo_ps_surface_create_for_stream_internal (stream,
+ width_in_points,
+ height_in_points);
+}
+
+cairo_surface_t *
+cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
+ void *closure,
+ double width_in_points,
+ double height_in_points)
+{
+ cairo_output_stream_t *stream;
+
+ stream = _cairo_output_stream_create (write_func, closure);
+ if (stream == NULL)
+ return NULL;
+
+ return _cairo_ps_surface_create_for_stream_internal (stream,
+ width_in_points,
+ height_in_points);
+}
+
static cairo_surface_t *
_cairo_ps_surface_create_similar (void *abstract_src,
cairo_format_t format,
@@ -170,44 +166,31 @@ _cairo_ps_surface_create_similar (void *abstract_src,
return NULL;
}
-static void
-_cairo_ps_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_ps_surface_finish (void *abstract_surface)
{
cairo_ps_surface_t *surface = abstract_surface;
/* Document footer */
- fprintf (surface->file, "%%%%EOF\n");
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%EOF\n");
cairo_surface_destroy (&surface->image->base);
- free (surface);
+ return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_ps_surface_erase (cairo_ps_surface_t *surface)
{
- cairo_color_t transparent;
-
- _cairo_color_init (&transparent);
- _cairo_color_set_rgb (&transparent, 0., 0., 0.);
- _cairo_color_set_alpha (&transparent, 0.);
_cairo_surface_fill_rectangle (&surface->image->base,
- CAIRO_OPERATOR_SRC,
- &transparent,
+ CAIRO_OPERATOR_SOURCE,
+ CAIRO_COLOR_TRANSPARENT,
0, 0,
surface->image->width,
surface->image->height);
}
-/* XXX: We should re-work this interface to return both X/Y ppi values. */
-static double
-_cairo_ps_surface_pixels_per_inch (void *abstract_surface)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- return surface->y_ppi;
-}
-
static cairo_status_t
_cairo_ps_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
@@ -220,13 +203,6 @@ _cairo_ps_surface_acquire_source_image (void *abstract_surfac
return CAIRO_STATUS_SUCCESS;
}
-static void
-_cairo_ps_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
static cairo_status_t
_cairo_ps_surface_acquire_dest_image (void *abstract_surface,
cairo_rectangle_t *interest_rect,
@@ -246,66 +222,6 @@ _cairo_ps_surface_acquire_dest_image (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
-static void
-_cairo_ps_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_ps_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src,
- cairo_pattern_t *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_ps_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_ps_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *generic_src,
- void *abstract_dst,
- int x_src,
- int y_src,
- int x_dst,
- int y_dst,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static cairo_int_status_t
_cairo_ps_surface_copy_page (void *abstract_surface)
{
@@ -313,13 +229,13 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
cairo_ps_surface_t *surface = abstract_surface;
int width = surface->image->width;
int height = surface->image->height;
- FILE *file = surface->file;
+ cairo_output_stream_t *stream = surface->stream;
int i, x, y;
cairo_solid_pattern_t white_pattern;
- char *rgb, *compressed;
- long rgb_size, compressed_size;
+ unsigned char *rgb, *compressed;
+ unsigned long rgb_size, compressed_size;
rgb_size = 3 * width * height;
rgb = malloc (rgb_size);
@@ -338,9 +254,9 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
/* PostScript can not represent the alpha channel, so we blend the
current image over a white RGB surface to eliminate it. */
- _cairo_pattern_init_solid (&white_pattern, 1.0, 1.0, 1.0);
+ _cairo_pattern_init_solid (&white_pattern, CAIRO_COLOR_WHITE);
- _cairo_surface_composite (CAIRO_OPERATOR_OVER_REVERSE,
+ _cairo_surface_composite (CAIRO_OPERATOR_DEST_OVER,
&white_pattern.base,
NULL,
&surface->image->base,
@@ -364,34 +280,34 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
compress (compressed, &compressed_size, rgb, rgb_size);
/* Page header */
- fprintf (file, "%%%%Page: %d\n", ++surface->pages);
+ _cairo_output_stream_printf (stream, "%%%%Page: %d\n", ++surface->pages);
- fprintf (file, "gsave\n");
+ _cairo_output_stream_printf (stream, "gsave\n");
/* Image header goop */
- fprintf (file, "%g %g translate\n", 0.0, surface->height_inches * 72.0);
- fprintf (file, "%g %g scale\n", 72.0 / surface->x_ppi, 72.0 / surface->y_ppi);
- fprintf (file, "/DeviceRGB setcolorspace\n");
- fprintf (file, "<<\n");
- fprintf (file, " /ImageType 1\n");
- fprintf (file, " /Width %d\n", width);
- fprintf (file, " /Height %d\n", height);
- fprintf (file, " /BitsPerComponent 8\n");
- fprintf (file, " /Decode [ 0 1 0 1 0 1 ]\n");
- fprintf (file, " /DataSource currentfile /FlateDecode filter\n");
- fprintf (file, " /ImageMatrix [ 1 0 0 -1 0 1 ]\n");
- fprintf (file, ">>\n");
- fprintf (file, "image\n");
+ _cairo_output_stream_printf (stream, "%f %f translate\n",
+ 0.0, surface->height_in_points);
+ _cairo_output_stream_printf (stream, "/DeviceRGB setcolorspace\n");
+ _cairo_output_stream_printf (stream, "<<\n");
+ _cairo_output_stream_printf (stream, " /ImageType 1\n");
+ _cairo_output_stream_printf (stream, " /Width %d\n", width);
+ _cairo_output_stream_printf (stream, " /Height %d\n", height);
+ _cairo_output_stream_printf (stream, " /BitsPerComponent 8\n");
+ _cairo_output_stream_printf (stream, " /Decode [ 0 1 0 1 0 1 ]\n");
+ _cairo_output_stream_printf (stream, " /DataSource currentfile /FlateDecode filter\n");
+ _cairo_output_stream_printf (stream, " /ImageMatrix [ 1 0 0 -1 0 1 ]\n");
+ _cairo_output_stream_printf (stream, ">>\n");
+ _cairo_output_stream_printf (stream, "image\n");
/* Compressed image data */
- fwrite (compressed, 1, compressed_size, file);
+ _cairo_output_stream_write (stream, compressed, compressed_size);
- fprintf (file, "showpage\n");
+ _cairo_output_stream_printf (stream, "showpage\n");
- fprintf (file, "grestore\n");
+ _cairo_output_stream_printf (stream, "grestore\n");
/* Page footer */
- fprintf (file, "%%%%EndPage\n");
+ _cairo_output_stream_printf (stream, "%%%%EndPage\n");
free (compressed);
BAIL1:
@@ -424,20 +340,39 @@ _cairo_ps_surface_set_clip_region (void *abstract_surface,
return _cairo_image_surface_set_clip_region (surface->image, region);
}
+static cairo_int_status_t
+_cairo_ps_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
+{
+ cairo_ps_surface_t *surface = abstract_surface;
+
+ rectangle->x = 0;
+ rectangle->y = 0;
+
+ /* XXX: The conversion to integers here is pretty bogus, (not to
+ * mention the aribitray limitation of width to a short(!). We
+ * may need to come up with a better interface for get_size.
+ */
+ rectangle->width = (surface->width_in_points + 0.5);
+ rectangle->height = (surface->height_in_points + 0.5);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static const cairo_surface_backend_t cairo_ps_surface_backend = {
_cairo_ps_surface_create_similar,
- _cairo_ps_surface_destroy,
- _cairo_ps_surface_pixels_per_inch,
+ _cairo_ps_surface_finish,
_cairo_ps_surface_acquire_source_image,
- _cairo_ps_surface_release_source_image,
+ NULL, /* release_source_image */
_cairo_ps_surface_acquire_dest_image,
- _cairo_ps_surface_release_dest_image,
- _cairo_ps_surface_clone_similar,
- _cairo_ps_surface_composite,
- _cairo_ps_surface_fill_rectangles,
- _cairo_ps_surface_composite_trapezoids,
+ NULL, /* release_dest_image */
+ NULL, /* clone_similar */
+ NULL, /* composite */
+ NULL, /* fill_rectangles */
+ NULL, /* composite_trapezoids */
_cairo_ps_surface_copy_page,
_cairo_ps_surface_show_page,
_cairo_ps_surface_set_clip_region,
+ _cairo_ps_surface_get_extents,
NULL /* show_glyphs */
};
diff --git a/src/cairo-ps.h b/src/cairo-ps.h
index 88382920e..ea2d53d09 100644
--- a/src/cairo-ps.h
+++ b/src/cairo-ps.h
@@ -39,30 +39,34 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_PS_SURFACE
+#if CAIRO_HAS_PS_SURFACE
#include <stdio.h>
CAIRO_BEGIN_DECLS
-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);
+cairo_ps_surface_create (const char *filename,
+ double width_in_points,
+ double height_in_points);
+
+cairo_surface_t *
+cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
+ void *closure,
+ double width_in_points,
+ double height_in_points);
+
+void
+cairo_ps_surface_set_dpi (cairo_surface_t *surface,
+ double x_dpi,
+ double y_dpi);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_PS_SURFACE */
+# error Cairo was not compiled with support for the ps backend
#endif /* CAIRO_HAS_PS_SURFACE */
+
#endif /* CAIRO_PS_H */
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 01b345cdc..292f5b491 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -34,359 +34,224 @@
*/
#include "cairoint.h"
+#include "cairo-private.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;
-
-
-
-
+ cairo_surface_t base;
-#pragma mark Private functions
+ CGContextRef context;
+ int width;
+ int height;
+ cairo_image_surface_t *image;
+ CGImageRef cgImage;
+} cairo_quartz_surface_t;
-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)
+static void
+ImageDataReleaseFunc(void *info, const void *data, size_t size)
{
- 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;
+ if (data != NULL) {
+ free((void *) data);
}
-
- 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)
+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)
+static cairo_status_t
+_cairo_quartz_surface_finish(void *abstract_surface)
{
cairo_quartz_surface_t *surface = abstract_surface;
-
-
- if (surface->cgImage)
- {
- CGImageRelease(surface->cgImage);
- }
-
- free(surface);
-}
+ if (surface->image)
+ cairo_surface_destroy(&surface->image->base);
+ if (surface->cgImage)
+ CGImageRelease(surface->cgImage);
-static double
-_cairo_quartz_surface_pixels_per_inch(void *abstract_surface)
-{
-
-
- // TODO - get this from CGDirectDisplay somehow?
- return 96.0;
+ return CAIRO_STATUS_SUCCESS;
}
-
-static cairo_image_surface_t *
-_cairo_quartz_surface_get_image(void *abstract_surface)
+static cairo_status_t
+_cairo_quartz_surface_acquire_source_image(void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
- cairo_quartz_surface_t *surface = abstract_surface;
- CGColorSpaceRef colorSpace;
- void *imageData;
- UInt32 imageDataSize, rowBytes;
- CGDataProviderRef dataProvider;
-
-
+ 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)
- {
+ if (surface->image) {
cairo_surface_reference(&surface->image->base);
- return surface->image;
+ *image_out = surface->image;
+ return CAIRO_STATUS_SUCCESS;
}
-
+
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);
-
-
+
+ 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);
-
-
+ 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;
-}
+ _cairo_image_surface_set_matrix(surface->image,
+ &(surface->base.matrix));
+ *image_out = surface->image;
+ *image_extra = NULL;
-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;
+ return CAIRO_STATUS_SUCCESS;
}
-
static cairo_status_t
-_cairo_quartz_surface_set_matrix(void *abstract_surface, cairo_matrix_t *matrix)
+_cairo_quartz_surface_acquire_dest_image(void *abstract_surface,
+ cairo_rectangle_t * interest_rect,
+ cairo_image_surface_t **
+ image_out,
+ cairo_rectangle_t * image_rect,
+ void **image_extra)
{
cairo_quartz_surface_t *surface = abstract_surface;
- return _cairo_image_surface_set_matrix(surface->image, matrix);
-}
-
+ image_rect->x = 0;
+ image_rect->y = 0;
+ image_rect->width = surface->image->width;
+ image_rect->height = surface->image->height;
-static cairo_status_t
-_cairo_quartz_surface_set_filter(void *abstract_surface, cairo_filter_t filter)
-{
- cairo_quartz_surface_t *surface = abstract_surface;
+ *image_out = surface->image;
- return _cairo_image_surface_set_filter(surface->image, filter);
+ return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_quartz_surface_set_repeat(void *abstract_surface, int repeat)
+static void
+_cairo_quartz_surface_release_dest_image(void *abstract_surface,
+ cairo_rectangle_t *
+ intersect_rect,
+ cairo_image_surface_t * image,
+ cairo_rectangle_t * image_rect,
+ void *image_extra)
{
cairo_quartz_surface_t *surface = abstract_surface;
- return _cairo_image_surface_set_repeat(surface->image, repeat);
-}
-
+ if (surface->image == image) {
+ CGRect rect;
-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;
-}
+ rect = CGRectMake(0, 0, surface->width, surface->height);
+ CGContextDrawImage(surface->context, rect, surface->cgImage);
-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;
+ memset(surface->image->data, 0, surface->width * surface->height * 4);
+ }
}
-
static cairo_int_status_t
-_cairo_quartz_surface_copy_page(void *abstract_surface)
+_cairo_quartz_surface_set_clip_region(void *abstract_surface,
+ pixman_region16_t * region)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
+ cairo_quartz_surface_t *surface = abstract_surface;
-static cairo_int_status_t
-_cairo_quartz_surface_show_page(void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return _cairo_surface_set_clip_region(&surface->image->base, region);
}
-
static cairo_int_status_t
-_cairo_quartz_surface_set_clip_region( void *abstract_surface,
- pixman_region16_t *region)
+_cairo_quartz_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t * rectangle)
{
cairo_quartz_surface_t *surface = abstract_surface;
- return _cairo_image_surface_set_clip_region(surface->image, region);
-}
-
+ rectangle->x = 0;
+ rectangle->y = 0;
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
-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;
+ return CAIRO_STATUS_SUCCESS;
}
-
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_finish,
+ _cairo_quartz_surface_acquire_source_image,
+ NULL, /* release_source_image */
+ _cairo_quartz_surface_acquire_dest_image,
+ _cairo_quartz_surface_release_dest_image,
+ NULL, /* clone_similar */
+ NULL, /* composite */
+ NULL, /* fill_rectangles */
+ NULL, /* composite_trapezoids */
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_quartz_surface_set_clip_region,
- _cairo_quartz_surface_create_pattern
+ _cairo_quartz_surface_get_extents,
+ NULL /* show_glyphs */
};
-cairo_surface_t *
-cairo_quartz_surface_create( CGContextRef context,
- int width,
- int height)
+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;
-}
+ surface->context = context;
+ surface->width = width;
+ surface->height = height;
+ surface->image = NULL;
+ surface->cgImage = NULL;
-DEPRECATE (cairo_surface_create_for_drawable, cairo_quartz_surface_create);
+ // Set up the image surface which Cairo draws into and we blit to & from.
+ void *foo;
+ _cairo_quartz_surface_acquire_source_image(surface, &surface->image, &foo);
+
+ return (cairo_surface_t *) surface;
+}
diff --git a/src/cairo-quartz.h b/src/cairo-quartz.h
index 5afd46426..6f59f6a79 100644
--- a/src/cairo-quartz.h
+++ b/src/cairo-quartz.h
@@ -39,18 +39,12 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_QUARTZ_SURFACE
+#if CAIRO_HAS_QUARTZ_SURFACE
#include <Carbon/Carbon.h>
CAIRO_BEGIN_DECLS
-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,
@@ -58,6 +52,9 @@ cairo_quartz_surface_create ( CGContextRef context,
CAIRO_END_DECLS
+#else /* CAIRO_HAS_QUARTZ_SURFACE */
+# error Cairo was not compiled with support for the quartz backend
#endif /* CAIRO_HAS_QUARTZ_SURFACE */
+
#endif /* CAIRO_QUARTZ_H */
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 330d58b1e..0bcf80cf8 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -38,6 +39,17 @@
#include "cairoint.h"
+struct _cairo_surface_save {
+ cairo_surface_save_t *next;
+ pixman_region16_t *clip_region;
+};
+
+static cairo_status_t
+_cairo_surface_set_clip_region_internal (cairo_surface_t *surface,
+ pixman_region16_t *region,
+ cairo_bool_t copy_region,
+ cairo_bool_t free_existing);
+
void
_cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend)
@@ -45,22 +57,122 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->backend = backend;
surface->ref_count = 1;
+ surface->finished = FALSE;
- _cairo_matrix_init (&surface->matrix);
- surface->filter = CAIRO_FILTER_NEAREST;
+ _cairo_user_data_array_init (&surface->user_data);
+
+ cairo_matrix_init_identity (&surface->matrix);
+ surface->filter = CAIRO_FILTER_GOOD;
surface->repeat = 0;
+
+ surface->device_x_offset = 0;
+ surface->device_y_offset = 0;
+
+ surface->clip_region = NULL;
+
+ surface->saves = NULL;
+ surface->level = 0;
}
-cairo_surface_t *
-cairo_surface_create_for_image (char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride)
+static cairo_status_t
+_cairo_surface_begin_internal (cairo_surface_t *surface,
+ cairo_bool_t reset_clip)
+{
+ cairo_surface_save_t *save;
+
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ save = malloc (sizeof (cairo_surface_save_t));
+ if (!save)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (surface->clip_region) {
+ if (reset_clip)
+ {
+ cairo_status_t status;
+
+ save->clip_region = surface->clip_region;
+ status = _cairo_surface_set_clip_region_internal (surface, NULL, FALSE, FALSE);
+ if (!CAIRO_OK (status)) {
+ free (save);
+ return status;
+ }
+ }
+ else
+ {
+ save->clip_region = pixman_region_create ();
+ pixman_region_copy (save->clip_region, surface->clip_region);
+ }
+ } else {
+ save->clip_region = NULL;
+ }
+
+ save->next = surface->saves;
+ surface->saves = save;
+ surface->level++;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * _cairo_surface_begin:
+ * @surface: a #cairo_surface_t
+ *
+ * Must be called before beginning to use the surface. State
+ * of the surface like the clip region will be saved then restored
+ * on the matching call _cairo_surface_end().
+ */
+cairo_private cairo_status_t
+_cairo_surface_begin (cairo_surface_t *surface)
+{
+ return _cairo_surface_begin_internal (surface, FALSE);
+}
+
+/**
+ * _cairo_surface_begin_reset_clip:
+ * @surface: a #cairo_surface_t
+ *
+ * Must be called before beginning to use the surface. State
+ * of the surface like the clip region will be saved then restored
+ * on the matching call _cairo_surface_end().
+ *
+ * After the state is saved, the clip region is cleared. This
+ * combination of operations is a little artificial; the caller could
+ * simply call _cairo_surface_set_clip_region (surface, NULL); after
+ * _cairo_surface_save(). Combining the two saves a copy of the clip
+ * region, and also simplifies error handling for the caller.
+ **/
+cairo_private cairo_status_t
+_cairo_surface_begin_reset_clip (cairo_surface_t *surface)
+{
+ return _cairo_surface_begin_internal (surface, TRUE);
+}
+
+/**
+ * _cairo_surface_end:
+ * @surface: a #cairo_surface_t
+ *
+ * Restores any state saved by _cairo_surface_begin()
+ **/
+cairo_private cairo_status_t
+_cairo_surface_end (cairo_surface_t *surface)
{
- return cairo_image_surface_create_for_data (data, format, width, height, stride);
+ cairo_surface_save_t *save;
+ pixman_region16_t *clip_region;
+
+ if (!surface->saves)
+ return CAIRO_STATUS_BAD_NESTING;
+
+ save = surface->saves;
+ surface->saves = save->next;
+ surface->level--;
+
+ clip_region = save->clip_region;
+ free (save);
+
+ return _cairo_surface_set_clip_region_internal (surface, clip_region, FALSE, TRUE);
}
-slim_hidden_def(cairo_surface_create_for_image);
cairo_surface_t *
_cairo_surface_create_similar_scratch (cairo_surface_t *other,
@@ -82,24 +194,20 @@ cairo_surface_create_similar (cairo_surface_t *other,
int width,
int height)
{
- cairo_color_t empty;
-
if (other == NULL)
return NULL;
- _cairo_color_init (&empty);
- _cairo_color_set_rgb (&empty, 0., 0., 0.);
- _cairo_color_set_alpha (&empty, 0.);
-
- return _cairo_surface_create_similar_solid (other, format, width, height, &empty);
+ return _cairo_surface_create_similar_solid (other, format,
+ width, height,
+ CAIRO_COLOR_TRANSPARENT);
}
cairo_surface_t *
-_cairo_surface_create_similar_solid (cairo_surface_t *other,
- cairo_format_t format,
- int width,
- int height,
- cairo_color_t *color)
+_cairo_surface_create_similar_solid (cairo_surface_t *other,
+ cairo_format_t format,
+ int width,
+ int height,
+ const cairo_color_t *color)
{
cairo_status_t status;
cairo_surface_t *surface;
@@ -111,7 +219,7 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
surface = cairo_image_surface_create (format, width, height);
status = _cairo_surface_fill_rectangle (surface,
- CAIRO_OPERATOR_SRC, color,
+ CAIRO_OPERATOR_SOURCE, color,
0, 0, width, height);
if (status) {
cairo_surface_destroy (surface);
@@ -140,15 +248,134 @@ cairo_surface_destroy (cairo_surface_t *surface)
if (surface->ref_count)
return;
- if (surface->backend->destroy)
- surface->backend->destroy (surface);
+ cairo_surface_finish (surface);
+
+ _cairo_user_data_array_destroy (&surface->user_data);
+
+ free (surface);
}
slim_hidden_def(cairo_surface_destroy);
-double
-_cairo_surface_pixels_per_inch (cairo_surface_t *surface)
+/**
+ * cairo_surface_finish:
+ * @surface: the #cairo_surface_t to finish
+ *
+ * This function finishes the surface and drops all references to
+ * external resources. For example, for the Xlib backend it means
+ * that cairo will no longer access the drawable, which can be freed.
+ * After calling cairo_surface_finish() the only valid operations on a
+ * surface are getting and setting user data and referencing and
+ * destroying it. Further drawing the the surface will not affect the
+ * surface but set the surface status to
+ * CAIRO_STATUS_SURFACE_FINISHED.
+ *
+ * When the last call to cairo_surface_destroy() decreases the
+ * reference count to zero, cairo will call cairo_surface_finish() if
+ * it hasn't been called already, before freeing the resources
+ * associated with the surface.
+ *
+ * Return value: CAIRO_STATUS_SUCCESS if the surface was finished
+ * successfully, otherwise CAIRO_STATUS_NO_MEMORY or
+ * CAIRO_STATUS_WRITE_ERROR.
+ **/
+cairo_status_t
+cairo_surface_finish (cairo_surface_t *surface)
+{
+ cairo_status_t status;
+
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (surface->saves)
+ return CAIRO_STATUS_BAD_NESTING;
+
+ if (surface->clip_region) {
+ pixman_region_destroy (surface->clip_region);
+ surface->clip_region = NULL;
+ }
+
+ if (surface->backend->finish) {
+ status = surface->backend->finish (surface);
+ if (status)
+ return status;
+ }
+
+ surface->finished = TRUE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * cairo_surface_get_user_data:
+ * @surface: a #cairo_surface_t
+ * @key: the address of the #cairo_user_data_key_t the user data was
+ * attached to
+ *
+ * Return user data previously attached to @surface using the specified
+ * key. If no user data has been attached with the given key this
+ * function returns %NULL.
+ *
+ * Return value: the user data previously attached or %NULL.
+ **/
+void *
+cairo_surface_get_user_data (cairo_surface_t *surface,
+ const cairo_user_data_key_t *key)
{
- return surface->backend->pixels_per_inch (surface);
+ return _cairo_user_data_array_get_data (&surface->user_data,
+ key);
+}
+
+/**
+ * cairo_surface_set_user_data:
+ * @surface: a #cairo_surface_t
+ * @key: the address of a #cairo_user_data_key_t to attach the user data to
+ * @user_data: the user data to attach to the surface
+ * @destroy: a #cairo_destroy_func_t which will be called when the
+ * surface is destroyed or when new user data is attached using the
+ * same key.
+ *
+ * Attach user data to @surface. To remove user data from a surface,
+ * call this function with the key that was used to set it and %NULL
+ * for @data.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
+ * slot could not be allocated for the user data.
+ **/
+cairo_status_t
+cairo_surface_set_user_data (cairo_surface_t *surface,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy)
+{
+ return _cairo_user_data_array_set_data (&surface->user_data,
+ key, user_data, destroy);
+}
+
+/**
+ * cairo_surface_set_device_offset:
+ * @surface: a #cairo_surface_t
+ * @x_offset: the offset in the X direction, in device units
+ * @y_offset: the offset in the Y direction, in device units
+ *
+ * Sets an offset that is added to the device coordinates determined
+ * by the CTM when drawing to @surface. One use case for this function
+ * is when we want to create a #cairo_surface_t that redirects drawing
+ * for a portion of an onscreen surface to an offscreen surface in a
+ * way that is completely invisible to the user of the cairo
+ * API. Setting a transformation via cairo_translate() isn't
+ * sufficient to do this, since functions like
+ * cairo_device_to_user() will expose the hidden offset.
+ *
+ * Note that the offset only affects drawing to the surface, not using
+ * the surface in a surface pattern.
+ **/
+void
+cairo_surface_set_device_offset (cairo_surface_t *surface,
+ double x_offset,
+ double y_offset)
+{
+ surface->device_x_offset = x_offset;
+ surface->device_y_offset = y_offset;
}
/**
@@ -173,6 +400,8 @@ _cairo_surface_acquire_source_image (cairo_surface_t *surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
+ assert (!surface->finished);
+
return surface->backend->acquire_source_image (surface, image_out, image_extra);
}
@@ -188,7 +417,10 @@ _cairo_surface_release_source_image (cairo_surface_t *surface,
cairo_image_surface_t *image,
void *image_extra)
{
- surface->backend->release_source_image (surface, image, image_extra);
+ assert (!surface->finished);
+
+ if (surface->backend->release_source_image)
+ surface->backend->release_source_image (surface, image, image_extra);
}
/**
@@ -226,6 +458,8 @@ _cairo_surface_acquire_dest_image (cairo_surface_t *surface,
cairo_rectangle_t *image_rect,
void **image_extra)
{
+ assert (!surface->finished);
+
return surface->backend->acquire_dest_image (surface, interest_rect,
image_out, image_rect, image_extra);
}
@@ -249,8 +483,11 @@ _cairo_surface_release_dest_image (cairo_surface_t *surface,
cairo_rectangle_t *image_rect,
void *image_extra)
{
- surface->backend->release_dest_image (surface, interest_rect,
- image, image_rect, image_extra);
+ assert (!surface->finished);
+
+ if (surface->backend->release_dest_image)
+ surface->backend->release_dest_image (surface, interest_rect,
+ image, image_rect, image_extra);
}
/**
@@ -278,9 +515,14 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_image_surface_t *image;
void *image_extra;
- status = surface->backend->clone_similar (surface, src, clone_out);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (surface->backend->clone_similar) {
+ status = surface->backend->clone_similar (surface, src, clone_out);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
if (status != CAIRO_STATUS_SUCCESS)
@@ -298,69 +540,6 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
return status;
}
-cairo_status_t
-cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- return cairo_matrix_copy (&surface->matrix, matrix);
-}
-slim_hidden_def(cairo_surface_set_matrix);
-
-cairo_status_t
-cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- return cairo_matrix_copy (matrix, &surface->matrix);
-}
-slim_hidden_def(cairo_surface_get_matrix);
-
-cairo_status_t
-cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- surface->filter = filter;
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_filter_t
-cairo_surface_get_filter (cairo_surface_t *surface)
-{
- return surface->filter;
-}
-
-/* XXX: NYI
-cairo_status_t
-cairo_surface_clip_rectangle (cairo_surface_t *surface,
- int x, int y,
- int width, int height)
-{
-
-}
-*/
-
-/* XXX: NYI
-cairo_status_t
-cairo_surface_clip_restore (cairo_surface_t *surface);
-*/
-
-cairo_status_t
-cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- surface->repeat = repeat;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_surface_set_repeat);
-
typedef struct {
cairo_surface_t *dst;
cairo_rectangle_t extents;
@@ -444,14 +623,19 @@ _cairo_surface_composite (cairo_operator_t operator,
{
cairo_int_status_t status;
- status = dst->backend->composite (operator,
- src, mask, dst,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ if (dst->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (dst->backend->composite) {
+ status = dst->backend->composite (operator,
+ src, mask, dst,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
return _fallback_composite (operator,
src, mask, dst,
@@ -462,16 +646,19 @@ _cairo_surface_composite (cairo_operator_t operator,
}
cairo_status_t
-_cairo_surface_fill_rectangle (cairo_surface_t *surface,
- cairo_operator_t operator,
- cairo_color_t *color,
- int x,
- int y,
- int width,
- int height)
+_cairo_surface_fill_rectangle (cairo_surface_t *surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ int x,
+ int y,
+ int width,
+ int height)
{
cairo_rectangle_t rect;
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
rect.x = x;
rect.y = y;
rect.width = width;
@@ -505,15 +692,15 @@ _fallback_fill_rectangles (cairo_surface_t *surface,
y2 = rects[0].y + rects[0].height;
for (i = 1; i < num_rects; i++) {
- if (rects[0].x < x1)
- x1 = rects[0].x;
- if (rects[0].y < y1)
- y1 = rects[0].y;
-
- if (rects[0].x + rects[0].width > x2)
- x2 = rects[0].x + rects[0].width;
- if (rects[0].y + rects[0].height > y2)
- y2 = rects[0].y + rects[0].height;
+ if (rects[i].x < x1)
+ x1 = rects[i].x;
+ if (rects[i].y < y1)
+ y1 = rects[i].y;
+
+ if (rects[i].x + rects[i].width > x2)
+ x2 = rects[i].x + rects[i].width;
+ if (rects[i].y + rects[i].height > y2)
+ y2 = rects[i].y + rects[i].height;
}
status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
@@ -560,19 +747,37 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
{
cairo_int_status_t status;
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
if (num_rects == 0)
return CAIRO_STATUS_SUCCESS;
- status = surface->backend->fill_rectangles (surface,
- operator,
- color,
- rects, num_rects);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ if (surface->backend->fill_rectangles) {
+ status = surface->backend->fill_rectangles (surface,
+ operator,
+ color,
+ rects, num_rects);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
return _fallback_fill_rectangles (surface, operator, color, rects, num_rects);
}
+cairo_private cairo_int_status_t
+_cairo_surface_fill_path (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ cairo_path_fixed_t *path)
+{
+ if (dst->backend->fill_path)
+ return dst->backend->fill_path (operator, pattern, dst, path);
+ else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+
static cairo_status_t
_fallback_composite_trapezoids (cairo_operator_t operator,
cairo_pattern_t *pattern,
@@ -655,14 +860,19 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator,
{
cairo_int_status_t status;
- status = dst->backend->composite_trapezoids (operator,
- pattern, dst,
- src_x, src_y,
- dst_x, dst_y,
- width, height,
- traps, num_traps);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ if (dst->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (dst->backend->composite_trapezoids) {
+ status = dst->backend->composite_trapezoids (operator,
+ pattern, dst,
+ src_x, src_y,
+ dst_x, dst_y,
+ width, height,
+ traps, num_traps);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
return _fallback_composite_trapezoids (operator, pattern, dst,
src_x, src_y,
@@ -674,35 +884,116 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator,
cairo_status_t
_cairo_surface_copy_page (cairo_surface_t *surface)
{
- cairo_int_status_t status;
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
- status = surface->backend->copy_page (surface);
/* It's fine if some backends just don't support this. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ if (surface->backend->copy_page == NULL)
return CAIRO_STATUS_SUCCESS;
- if (status)
- return status;
- return CAIRO_STATUS_SUCCESS;
+ return surface->backend->copy_page (surface);
}
cairo_status_t
_cairo_surface_show_page (cairo_surface_t *surface)
{
- cairo_int_status_t status;
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
- status = surface->backend->show_page (surface);
/* It's fine if some backends just don't support this. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ if (surface->backend->show_page == NULL)
return CAIRO_STATUS_SUCCESS;
- if (status)
- return status;
- return CAIRO_STATUS_SUCCESS;
+ return surface->backend->show_page (surface);
}
-cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region)
+static cairo_status_t
+_cairo_surface_set_clip_region_internal (cairo_surface_t *surface,
+ pixman_region16_t *region,
+ cairo_bool_t copy_region,
+ cairo_bool_t free_existing)
{
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (region == surface->clip_region)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (surface->backend->set_clip_region == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (surface->clip_region) {
+ if (free_existing)
+ pixman_region_destroy (surface->clip_region);
+ surface->clip_region = NULL;
+ }
+
+ if (region) {
+ if (copy_region) {
+ surface->clip_region = pixman_region_create ();
+ pixman_region_copy (surface->clip_region, region);
+ } else
+ surface->clip_region = region;
+ }
+
return surface->backend->set_clip_region (surface, region);
}
+
+cairo_status_t
+_cairo_surface_set_clip_region (cairo_surface_t *surface,
+ pixman_region16_t *region)
+{
+ return _cairo_surface_set_clip_region_internal (surface, region, TRUE, TRUE);
+}
+
+cairo_status_t
+_cairo_surface_get_clip_extents (cairo_surface_t *surface,
+ cairo_rectangle_t *rectangle)
+{
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (surface->clip_region) {
+ pixman_box16_t *box = pixman_region_extents (surface->clip_region);
+
+ rectangle->x = box->x1;
+ rectangle->y = box->y1;
+ rectangle->width = box->x2 - box->x1;
+ rectangle->height = box->y2 - box->y1;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return surface->backend->get_extents (surface, rectangle);
+}
+
+cairo_status_t
+_cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_status_t status;
+
+ if (dst->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ if (dst->backend->show_glyphs)
+ status = dst->backend->show_glyphs (scaled_font, operator, pattern, dst,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
+ glyphs, num_glyphs);
+ else
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return status;
+}
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 79c7e16b6..15dfc1bca 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -88,6 +88,43 @@ _cairo_traps_fini (cairo_traps_t *traps)
}
}
+/**
+ * _cairo_traps_init_box:
+ * @traps: a #cairo_traps_t
+ * @box: a box that will be converted to a single trapezoid
+ * to store in @traps.
+ *
+ * Initializes a cairo_traps_t to contain a single rectangular
+ * trapezoid.
+ **/
+cairo_status_t
+_cairo_traps_init_box (cairo_traps_t *traps,
+ cairo_box_t *box)
+{
+ cairo_status_t status;
+
+ _cairo_traps_init (traps);
+
+ status = _cairo_traps_grow_by (traps, 1);
+ if (status)
+ return status;
+
+ traps->num_traps = 1;
+
+ traps->traps[0].top = box->p1.y;
+ traps->traps[0].bottom = box->p2.y;
+ traps->traps[0].left.p1 = box->p1;
+ traps->traps[0].left.p2.x = box->p1.x;
+ traps->traps[0].left.p2.y = box->p2.y;
+ traps->traps[0].right.p1.x = box->p2.x;
+ traps->traps[0].right.p1.y = box->p1.y;
+ traps->traps[0].right.p2 = box->p2;
+
+ traps->extents = *box;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_status_t
_cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
cairo_line_t *left, cairo_line_t *right)
@@ -738,3 +775,65 @@ _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
{
*extents = traps->extents;
}
+
+/**
+ * _cairo_traps_extract_region:
+ * @traps: a #cairo_traps_t
+ * @region: on return, %NULL is stored here if the trapezoids aren't
+ * exactly representable as a pixman region, otherwise a
+ * a pointer to such a region, newly allocated.
+ * (free with pixman region destroy)
+ *
+ * Determines if a set of trapezoids are exactly representable as a
+ * pixman region, and if so creates such a region.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
+ **/
+cairo_status_t
+_cairo_traps_extract_region (cairo_traps_t *traps,
+ pixman_region16_t **region)
+{
+ int i;
+
+ for (i = 0; i < traps->num_traps; i++)
+ if (!(traps->traps[i].left.p1.x == traps->traps[i].left.p2.x
+ && traps->traps[i].right.p1.x == traps->traps[i].right.p2.x
+ && traps->traps[i].left.p1.y == traps->traps[i].right.p1.y
+ && traps->traps[i].left.p2.y == traps->traps[i].right.p2.y
+ && _cairo_fixed_is_integer(traps->traps[i].left.p1.x)
+ && _cairo_fixed_is_integer(traps->traps[i].left.p1.y)
+ && _cairo_fixed_is_integer(traps->traps[i].left.p2.x)
+ && _cairo_fixed_is_integer(traps->traps[i].left.p2.y)
+ && _cairo_fixed_is_integer(traps->traps[i].right.p1.x)
+ && _cairo_fixed_is_integer(traps->traps[i].right.p1.y)
+ && _cairo_fixed_is_integer(traps->traps[i].right.p2.x)
+ && _cairo_fixed_is_integer(traps->traps[i].right.p2.y))) {
+ *region = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ *region = pixman_region_create ();
+
+ for (i = 0; i < traps->num_traps; i++) {
+ int x = _cairo_fixed_integer_part(traps->traps[i].left.p1.x);
+ int y = _cairo_fixed_integer_part(traps->traps[i].left.p1.y);
+ int width = _cairo_fixed_integer_part(traps->traps[i].right.p1.x) - x;
+ int height = _cairo_fixed_integer_part(traps->traps[i].left.p2.y) - y;
+
+ /* Sometimes we get degenerate trapezoids from the tesellator,
+ * if we call pixman_region_union_rect(), it bizarrly fails on such
+ * an empty rectangle, so skip them.
+ */
+ if (width == 0 || height == 0)
+ continue;
+
+ if (pixman_region_union_rect (*region, *region,
+ x, y, width, height) != PIXMAN_REGION_STATUS_SUCCESS) {
+ pixman_region_destroy (*region);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
diff --git a/src/cairo-unicode.c b/src/cairo-unicode.c
index 92201391a..8929baaac 100644
--- a/src/cairo-unicode.c
+++ b/src/cairo-unicode.c
@@ -117,14 +117,14 @@ static const char utf8_skip_data[256] = {
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
};
-#define UTF8_NEXT_CHAR(p) (char *)((p) + utf8_skip_data[*(unsigned char *)(p)])
+#define UTF8_NEXT_CHAR(p) ((p) + utf8_skip_data[*(unsigned char *)(p)])
/* Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
* If @p does not point to a valid UTF-8 encoded character, results are
* undefined.
**/
static uint32_t
-_utf8_get_char (const char *p)
+_utf8_get_char (const unsigned char *p)
{
int i, mask = 0, len;
uint32_t result;
@@ -142,8 +142,8 @@ _utf8_get_char (const char *p)
* and return (uint32_t)-2 on incomplete trailing character
*/
static uint32_t
-_utf8_get_char_extended (const char *p,
- long max_len)
+_utf8_get_char_extended (const unsigned char *p,
+ long max_len)
{
int i, len;
uint32_t wc = (unsigned char) *p;
@@ -220,14 +220,14 @@ _utf8_get_char_extended (const char *p,
* an invalid sequence was found.
**/
cairo_status_t
-_cairo_utf8_to_ucs4 (const char *str,
- int len,
- uint32_t **result,
- int *items_written)
+_cairo_utf8_to_ucs4 (const unsigned char *str,
+ int len,
+ uint32_t **result,
+ int *items_written)
{
uint32_t *str32 = NULL;
int n_chars, i;
- const char *in;
+ const unsigned char *in;
in = str;
n_chars = 0;
@@ -284,14 +284,14 @@ _cairo_utf8_to_ucs4 (const char *str,
* an invalid sequence was found.
**/
cairo_status_t
-_cairo_utf8_to_utf16 (const char *str,
- int len,
- uint16_t **result,
- int *items_written)
+_cairo_utf8_to_utf16 (const unsigned char *str,
+ int len,
+ uint16_t **result,
+ int *items_written)
{
uint16_t *str16 = NULL;
int n16, i;
- const char *in;
+ const unsigned char *in;
in = str;
n16 = 0;
diff --git a/src/cairo-wideint.h b/src/cairo-wideint.h
index abe36f9d4..3afea5a65 100644
--- a/src/cairo-wideint.h
+++ b/src/cairo-wideint.h
@@ -1,5 +1,5 @@
/*
- * $Id: cairo-wideint.h,v 1.6 2005-01-19 15:11:14 cworth Exp $
+ * $Id: cairo-wideint.h,v 1.10 2005-05-10 19:42:32 cworth Exp $
*
* Copyright © 2004 Keith Packard
*
@@ -38,7 +38,15 @@
#ifndef CAIRO_WIDEINT_H
#define CAIRO_WIDEINT_H
-#include <stdint.h>
+#if HAVE_STDINT_H
+# include <stdint.h>
+#elif HAVE_INTTYPES_H
+# include <inttypes.h>
+#elif HAVE_SYS_INT_TYPES_H
+# include <sys/int_types.h>
+#else
+#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
+#endif
/*
* 64-bit datatypes. Two separate implementations, one using
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 02f0cffd6..78b3ca212 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -34,7 +34,7 @@
#include <string.h>
#include <stdio.h>
-
+#include "cairoint.h"
#include "cairo-win32-private.h"
#ifndef SPI_GETFONTSMOOTHINGTYPE
@@ -47,12 +47,12 @@
#define CLEARTYPE_QUALITY 5
#endif
-const cairo_font_backend_t cairo_win32_font_backend;
+const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend;
#define LOGICAL_SCALE 32
typedef struct {
- cairo_font_t base;
+ cairo_scaled_font_t base;
LOGFONTW logfont;
@@ -93,73 +93,69 @@ typedef struct {
*/
int em_square;
- HFONT scaled_font;
- HFONT unscaled_font;
+ HFONT scaled_hfont;
+ HFONT unscaled_hfont;
-} cairo_win32_font_t;
+} cairo_win32_scaled_font_t;
#define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.))
static void
-_compute_transform (cairo_win32_font_t *font,
- cairo_font_scale_t *sc)
+_compute_transform (cairo_win32_scaled_font_t *scaled_font,
+ cairo_matrix_t *sc)
{
- if (NEARLY_ZERO (sc->matrix[0][1]) && NEARLY_ZERO (sc->matrix[1][0])) {
- font->preserve_axes = TRUE;
- font->x_scale = sc->matrix[0][0];
- font->swap_x = (sc->matrix[0][0] < 0);
- font->y_scale = sc->matrix[1][1];
- font->swap_y = (sc->matrix[1][1] < 0);
- font->swap_axes = FALSE;
+ if (NEARLY_ZERO (sc->yx) && NEARLY_ZERO (sc->xy)) {
+ scaled_font->preserve_axes = TRUE;
+ scaled_font->x_scale = sc->xx;
+ scaled_font->swap_x = (sc->xx < 0);
+ scaled_font->y_scale = sc->yy;
+ scaled_font->swap_y = (sc->yy < 0);
+ scaled_font->swap_axes = FALSE;
- } else if (NEARLY_ZERO (sc->matrix[0][0]) && NEARLY_ZERO (sc->matrix[1][1])) {
- font->preserve_axes = TRUE;
- font->x_scale = sc->matrix[0][1];
- font->swap_x = (sc->matrix[0][1] < 0);
- font->y_scale = sc->matrix[1][0];
- font->swap_y = (sc->matrix[1][0] < 0);
- font->swap_axes = TRUE;
+ } else if (NEARLY_ZERO (sc->xx) && NEARLY_ZERO (sc->yy)) {
+ scaled_font->preserve_axes = TRUE;
+ scaled_font->x_scale = sc->yx;
+ scaled_font->swap_x = (sc->yx < 0);
+ scaled_font->y_scale = sc->xy;
+ scaled_font->swap_y = (sc->xy < 0);
+ scaled_font->swap_axes = TRUE;
} else {
- font->preserve_axes = FALSE;
- font->swap_x = font->swap_y = font->swap_axes = FALSE;
+ scaled_font->preserve_axes = FALSE;
+ scaled_font->swap_x = scaled_font->swap_y = scaled_font->swap_axes = FALSE;
}
- if (font->preserve_axes) {
- if (font->swap_x)
- font->x_scale = - font->x_scale;
- if (font->swap_y)
- font->y_scale = - font->y_scale;
+ if (scaled_font->preserve_axes) {
+ if (scaled_font->swap_x)
+ scaled_font->x_scale = - scaled_font->x_scale;
+ if (scaled_font->swap_y)
+ scaled_font->y_scale = - scaled_font->y_scale;
- font->logical_scale = LOGICAL_SCALE * font->y_scale;
- font->logical_size = LOGICAL_SCALE * floor (font->y_scale + 0.5);
+ scaled_font->logical_scale = LOGICAL_SCALE * scaled_font->y_scale;
+ scaled_font->logical_size = LOGICAL_SCALE * floor (scaled_font->y_scale + 0.5);
}
/* The font matrix has x and y "scale" components which we extract and
* use as character scale values.
*/
- cairo_matrix_set_affine (&font->logical_to_device,
- sc->matrix[0][0],
- sc->matrix[0][1],
- sc->matrix[1][0],
- sc->matrix[1][1],
- 0, 0);
-
- if (!font->preserve_axes) {
- _cairo_matrix_compute_scale_factors (&font->logical_to_device,
- &font->x_scale, &font->y_scale,
+ cairo_matrix_init (&scaled_font->logical_to_device,
+ sc->xx, sc->yx, sc->xy, sc->yy, 0, 0);
+
+ if (!scaled_font->preserve_axes) {
+ _cairo_matrix_compute_scale_factors (&scaled_font->logical_to_device,
+ &scaled_font->x_scale, &scaled_font->y_scale,
TRUE); /* XXX: Handle vertical text */
- font->logical_size = floor (LOGICAL_SCALE * font->y_scale + 0.5);
- font->logical_scale = LOGICAL_SCALE * font->y_scale;
+ scaled_font->logical_size = floor (LOGICAL_SCALE * scaled_font->y_scale + 0.5);
+ scaled_font->logical_scale = LOGICAL_SCALE * scaled_font->y_scale;
}
- cairo_matrix_scale (&font->logical_to_device,
- 1.0 / font->logical_scale, 1.0 / font->logical_scale);
+ cairo_matrix_scale (&scaled_font->logical_to_device,
+ 1.0 / scaled_font->logical_scale, 1.0 / scaled_font->logical_scale);
- font->device_to_logical = font->logical_to_device;
- if (!CAIRO_OK (cairo_matrix_invert (&font->device_to_logical)))
- cairo_matrix_set_identity (&font->device_to_logical);
+ scaled_font->device_to_logical = scaled_font->logical_to_device;
+ if (!CAIRO_OK (cairo_matrix_invert (&scaled_font->device_to_logical)))
+ cairo_matrix_init_identity (&scaled_font->device_to_logical);
}
static BYTE
@@ -202,53 +198,56 @@ _get_system_quality (void)
return DEFAULT_QUALITY;
}
-static cairo_font_t *
-_win32_font_create (LOGFONTW *logfont,
- cairo_font_scale_t *scale)
+static cairo_scaled_font_t *
+_win32_scaled_font_create (LOGFONTW *logfont,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm)
{
- cairo_win32_font_t *f;
+ cairo_win32_scaled_font_t *f;
+ cairo_matrix_t scale;
- f = malloc (sizeof(cairo_win32_font_t));
+ f = malloc (sizeof(cairo_win32_scaled_font_t));
if (f == NULL)
return NULL;
f->logfont = *logfont;
f->quality = _get_system_quality ();
f->em_square = 0;
- f->scaled_font = NULL;
- f->unscaled_font = NULL;
+ f->scaled_hfont = NULL;
+ f->unscaled_hfont = NULL;
- _compute_transform (f, scale);
-
- _cairo_font_init ((cairo_font_t *)f, scale, &cairo_win32_font_backend);
+ cairo_matrix_multiply (&scale, font_matrix, ctm);
+ _compute_transform (f, &scale);
+
+ _cairo_scaled_font_init (&f->base, font_matrix, ctm, &cairo_win32_scaled_font_backend);
- return (cairo_font_t *)f;
+ return &f->base;
}
static cairo_status_t
-_win32_font_set_world_transform (cairo_win32_font_t *font,
- HDC hdc)
+_win32_scaled_font_set_world_transform (cairo_win32_scaled_font_t *scaled_font,
+ HDC hdc)
{
XFORM xform;
- xform.eM11 = font->logical_to_device.m[0][0];
- xform.eM21 = font->logical_to_device.m[1][0];
- xform.eM12 = font->logical_to_device.m[0][1];
- xform.eM22 = font->logical_to_device.m[1][1];
- xform.eDx = font->logical_to_device.m[2][0];
- xform.eDy = font->logical_to_device.m[2][1];
+ xform.eM11 = scaled_font->logical_to_device.xx;
+ xform.eM21 = scaled_font->logical_to_device.xy;
+ xform.eM12 = scaled_font->logical_to_device.yx;
+ xform.eM22 = scaled_font->logical_to_device.yy;
+ xform.eDx = scaled_font->logical_to_device.x0;
+ xform.eDy = scaled_font->logical_to_device.y0;
if (!SetWorldTransform (hdc, &xform))
- return _cairo_win32_print_gdi_error ("_win32_font_set_world_transform");
+ return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_world_transform");
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_win32_font_set_identity_transform (HDC hdc)
+_win32_scaled_font_set_identity_transform (HDC hdc)
{
if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY))
- return _cairo_win32_print_gdi_error ("_win32_font_set_identity_transform");
+ return _cairo_win32_print_gdi_error ("_win32_scaled_font_set_identity_transform");
return CAIRO_STATUS_SUCCESS;
}
@@ -276,48 +275,48 @@ _get_global_font_dc (void)
}
static HFONT
-_win32_font_get_scaled_font (cairo_win32_font_t *font)
+_win32_scaled_font_get_scaled_hfont (cairo_win32_scaled_font_t *scaled_font)
{
- if (!font->scaled_font) {
- LOGFONTW logfont = font->logfont;
- logfont.lfHeight = font->logical_size;
+ if (!scaled_font->scaled_hfont) {
+ LOGFONTW logfont = scaled_font->logfont;
+ logfont.lfHeight = scaled_font->logical_size;
logfont.lfWidth = 0;
logfont.lfEscapement = 0;
logfont.lfOrientation = 0;
- logfont.lfQuality = font->quality;
+ logfont.lfQuality = scaled_font->quality;
- font->scaled_font = CreateFontIndirectW (&logfont);
- if (!font->scaled_font) {
- _cairo_win32_print_gdi_error ("_win32_font_get_scaled_font");
+ scaled_font->scaled_hfont = CreateFontIndirectW (&logfont);
+ if (!scaled_font->scaled_hfont) {
+ _cairo_win32_print_gdi_error ("_win32_scaled_font_get_scaled_hfont");
return NULL;
}
}
- return font->scaled_font;
+ return scaled_font->scaled_hfont;
}
static HFONT
-_win32_font_get_unscaled_font (cairo_win32_font_t *font,
- HDC hdc)
+_win32_scaled_font_get_unscaled_hfont (cairo_win32_scaled_font_t *scaled_font,
+ HDC hdc)
{
- if (!font->unscaled_font) {
+ if (!scaled_font->unscaled_hfont) {
OUTLINETEXTMETRIC *otm;
unsigned int otm_size;
- HFONT scaled_font;
+ HFONT scaled_hfont;
LOGFONTW logfont;
- scaled_font = _win32_font_get_scaled_font (font);
- if (!scaled_font)
+ scaled_hfont = _win32_scaled_font_get_scaled_hfont (scaled_font);
+ if (!scaled_hfont)
return NULL;
- if (!SelectObject (hdc, scaled_font)) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:SelectObject");
+ if (!SelectObject (hdc, scaled_hfont)) {
+ _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:SelectObject");
return NULL;
}
otm_size = GetOutlineTextMetrics (hdc, 0, NULL);
if (!otm_size) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
+ _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics");
return NULL;
}
@@ -326,48 +325,48 @@ _win32_font_get_unscaled_font (cairo_win32_font_t *font,
return NULL;
if (!GetOutlineTextMetrics (hdc, otm_size, otm)) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
+ _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics");
free (otm);
return NULL;
}
- font->em_square = otm->otmEMSquare;
+ scaled_font->em_square = otm->otmEMSquare;
free (otm);
- logfont = font->logfont;
- logfont.lfHeight = font->em_square;
+ logfont = scaled_font->logfont;
+ logfont.lfHeight = scaled_font->em_square;
logfont.lfWidth = 0;
logfont.lfEscapement = 0;
logfont.lfOrientation = 0;
- logfont.lfQuality = font->quality;
+ logfont.lfQuality = scaled_font->quality;
- font->unscaled_font = CreateFontIndirectW (&logfont);
- if (!font->unscaled_font) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:CreateIndirect");
+ scaled_font->unscaled_hfont = CreateFontIndirectW (&logfont);
+ if (!scaled_font->unscaled_hfont) {
+ _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:CreateIndirect");
return NULL;
}
}
- return font->unscaled_font;
+ return scaled_font->unscaled_hfont;
}
static cairo_status_t
-_cairo_win32_font_select_unscaled_font (cairo_font_t *font,
- HDC hdc)
+_cairo_win32_scaled_font_select_unscaled_font (cairo_scaled_font_t *scaled_font,
+ HDC hdc)
{
cairo_status_t status;
HFONT hfont;
HFONT old_hfont = NULL;
- hfont = _win32_font_get_unscaled_font ((cairo_win32_font_t *)font, hdc);
+ hfont = _win32_scaled_font_get_unscaled_hfont ((cairo_win32_scaled_font_t *)scaled_font, hdc);
if (!hfont)
return CAIRO_STATUS_NO_MEMORY;
old_hfont = SelectObject (hdc, hfont);
if (!old_hfont)
- return _cairo_win32_print_gdi_error ("_cairo_win32_font_select_unscaled_font");
+ return _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_select_unscaled_font");
- status = _win32_font_set_identity_transform (hdc);
+ status = _win32_scaled_font_set_identity_transform (hdc);
if (!CAIRO_OK (status)) {
SelectObject (hdc, old_hfont);
return status;
@@ -379,21 +378,22 @@ _cairo_win32_font_select_unscaled_font (cairo_font_t *font,
}
static void
-_cairo_win32_font_done_unscaled_font (cairo_font_t *font)
+_cairo_win32_scaled_font_done_unscaled_font (cairo_scaled_font_t *scaled_font)
{
}
/* implement the font backend interface */
static cairo_status_t
-_cairo_win32_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *scale,
- cairo_font_t **font_out)
+_cairo_win32_scaled_font_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **scaled_font_out)
{
LOGFONTW logfont;
- cairo_font_t *font;
+ cairo_scaled_font_t *scaled_font;
uint16_t *face_name;
int face_name_len;
cairo_status_t status;
@@ -451,47 +451,40 @@ _cairo_win32_font_create (const char *family,
if (!logfont.lfFaceName)
return CAIRO_STATUS_NO_MEMORY;
- font = _win32_font_create (&logfont, scale);
- if (!font)
+ scaled_font = _win32_scaled_font_create (&logfont, font_matrix, ctm);
+ if (!scaled_font)
return CAIRO_STATUS_NO_MEMORY;
- *font_out = font;
+ *scaled_font_out = scaled_font;
return CAIRO_STATUS_SUCCESS;
}
static void
-_cairo_win32_font_destroy_font (void *abstract_font)
+_cairo_win32_scaled_font_destroy (void *abstract_font)
{
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
- if (font->scaled_font)
- DeleteObject (font->scaled_font);
+ if (scaled_font->scaled_hfont)
+ DeleteObject (scaled_font->scaled_hfont);
- if (font->unscaled_font)
- DeleteObject (font->unscaled_font);
-
- free (font);
-}
-
-static void
-_cairo_win32_font_destroy_unscaled_font (void *abstract_font)
-{
+ if (scaled_font->unscaled_hfont)
+ DeleteObject (scaled_font->unscaled_hfont);
}
static void
-_cairo_win32_font_get_glyph_cache_key (void *abstract_font,
- cairo_glyph_cache_key_t *key)
+_cairo_win32_scaled_font_get_glyph_cache_key (void *abstract_font,
+ cairo_glyph_cache_key_t *key)
{
}
static cairo_status_t
-_cairo_win32_font_text_to_glyphs (void *abstract_font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
+_cairo_win32_scaled_font_text_to_glyphs (void *abstract_font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs)
{
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
uint16_t *utf16;
int n16;
GCP_RESULTSW gcp_results;
@@ -524,7 +517,7 @@ _cairo_win32_font_text_to_glyphs (void *abstract_font,
goto FAIL1;
}
- status = cairo_win32_font_select_font (&font->base, hdc);
+ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
if (!CAIRO_OK (status))
goto FAIL1;
@@ -553,7 +546,7 @@ _cairo_win32_font_text_to_glyphs (void *abstract_font,
0,
&gcp_results,
GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER)) {
- status = _cairo_win32_print_gdi_error ("_cairo_win32_font_text_to_glyphs");
+ status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_text_to_glyphs");
goto FAIL2;
}
@@ -582,7 +575,7 @@ _cairo_win32_font_text_to_glyphs (void *abstract_font,
(*glyphs)[i].x = x_pos ;
(*glyphs)[i].y = 0;
- x_pos += dx[i] / font->logical_scale;
+ x_pos += dx[i] / scaled_font->logical_scale;
}
FAIL2:
@@ -591,7 +584,7 @@ _cairo_win32_font_text_to_glyphs (void *abstract_font,
if (dx)
free (dx);
- cairo_win32_font_done_font (&font->base);
+ cairo_win32_scaled_font_done_font (&scaled_font->base);
FAIL1:
free (utf16);
@@ -600,10 +593,10 @@ _cairo_win32_font_text_to_glyphs (void *abstract_font,
}
static cairo_status_t
-_cairo_win32_font_font_extents (void *abstract_font,
- cairo_font_extents_t *extents)
+_cairo_win32_scaled_font_font_extents (void *abstract_font,
+ cairo_font_extents_t *extents)
{
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
cairo_status_t status;
TEXTMETRIC metrics;
HDC hdc;
@@ -612,21 +605,21 @@ _cairo_win32_font_font_extents (void *abstract_font,
if (!hdc)
return CAIRO_STATUS_NO_MEMORY;
- if (font->preserve_axes) {
+ if (scaled_font->preserve_axes) {
/* For 90-degree rotations (including 0), we get the metrics
* from the GDI in logical space, then convert back to font space
*/
- status = cairo_win32_font_select_font (&font->base, hdc);
+ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
if (!CAIRO_OK (status))
return status;
GetTextMetrics (hdc, &metrics);
- cairo_win32_font_done_font (&font->base);
+ cairo_win32_scaled_font_done_font (&scaled_font->base);
- extents->ascent = metrics.tmAscent / font->logical_scale;
- extents->descent = metrics.tmDescent / font->logical_scale;
+ extents->ascent = metrics.tmAscent / scaled_font->logical_scale;
+ extents->descent = metrics.tmDescent / scaled_font->logical_scale;
- extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / font->logical_scale;
- extents->max_x_advance = metrics.tmMaxCharWidth / font->logical_scale;
+ extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->logical_scale;
+ extents->max_x_advance = metrics.tmMaxCharWidth / scaled_font->logical_scale;
extents->max_y_advance = 0;
} else {
@@ -635,16 +628,16 @@ _cairo_win32_font_font_extents (void *abstract_font,
* transformed font are inexplicably large and we want to
* avoid them.
*/
- status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
+ status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
if (!CAIRO_OK (status))
return status;
GetTextMetrics (hdc, &metrics);
- _cairo_win32_font_done_unscaled_font (&font->base);
+ _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base);
- extents->ascent = (double)metrics.tmAscent / font->em_square;
- extents->descent = metrics.tmDescent * font->em_square;
- extents->height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / font->em_square;
- extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / font->em_square;
+ extents->ascent = (double)metrics.tmAscent / scaled_font->em_square;
+ extents->descent = metrics.tmDescent * scaled_font->em_square;
+ extents->height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->em_square;
+ extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / scaled_font->em_square;
extents->max_y_advance = 0;
}
@@ -653,12 +646,12 @@ _cairo_win32_font_font_extents (void *abstract_font,
}
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_scaled_font_glyph_extents (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
GLYPHMETRICS metrics;
cairo_status_t status;
@@ -674,39 +667,39 @@ _cairo_win32_font_glyph_extents (void *abstract_font,
*/
assert (num_glyphs == 1);
- if (font->preserve_axes) {
+ if (scaled_font->preserve_axes) {
/* If we aren't rotating / skewing the axes, then we get the metrics
* from the GDI in device space and convert to font space.
*/
- status = cairo_win32_font_select_font (&font->base, hdc);
+ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
if (!CAIRO_OK (status))
return status;
GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
&metrics, 0, NULL, &matrix);
- cairo_win32_font_done_font (&font->base);
-
- if (font->swap_axes) {
- extents->x_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
- extents->y_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
- extents->width = metrics.gmBlackBoxY / font->y_scale;
- extents->height = metrics.gmBlackBoxX / font->x_scale;
- extents->x_advance = metrics.gmCellIncY / font->x_scale;
- extents->y_advance = metrics.gmCellIncX / font->y_scale;
+ cairo_win32_scaled_font_done_font (&scaled_font->base);
+
+ if (scaled_font->swap_axes) {
+ extents->x_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale;
+ extents->y_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale;
+ extents->width = metrics.gmBlackBoxY / scaled_font->y_scale;
+ extents->height = metrics.gmBlackBoxX / scaled_font->x_scale;
+ extents->x_advance = metrics.gmCellIncY / scaled_font->x_scale;
+ extents->y_advance = metrics.gmCellIncX / scaled_font->y_scale;
} else {
- extents->x_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
- extents->y_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
- extents->width = metrics.gmBlackBoxX / font->x_scale;
- extents->height = metrics.gmBlackBoxY / font->y_scale;
- extents->x_advance = metrics.gmCellIncX / font->x_scale;
- extents->y_advance = metrics.gmCellIncY / font->y_scale;
+ extents->x_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale;
+ extents->y_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale;
+ extents->width = metrics.gmBlackBoxX / scaled_font->x_scale;
+ extents->height = metrics.gmBlackBoxY / scaled_font->y_scale;
+ extents->x_advance = metrics.gmCellIncX / scaled_font->x_scale;
+ extents->y_advance = metrics.gmCellIncY / scaled_font->y_scale;
}
- if (font->swap_x) {
+ if (scaled_font->swap_x) {
extents->x_bearing = (- extents->x_bearing - extents->width);
extents->x_advance = - extents->x_advance;
}
- if (font->swap_y) {
+ if (scaled_font->swap_y) {
extents->y_bearing = (- extents->y_bearing - extents->height);
extents->y_advance = - extents->y_advance;
}
@@ -715,17 +708,17 @@ _cairo_win32_font_glyph_extents (void *abstract_font,
/* For all other transformations, we use the design metrics
* of the font.
*/
- status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
+ status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
&metrics, 0, NULL, &matrix);
- _cairo_win32_font_done_unscaled_font (&font->base);
-
- extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / font->em_square;
- extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / font->em_square;
- extents->width = (double)metrics.gmBlackBoxX / font->em_square;
- extents->height = (double)metrics.gmBlackBoxY / font->em_square;
- extents->x_advance = (double)metrics.gmCellIncX / font->em_square;
- extents->y_advance = (double)metrics.gmCellIncY / font->em_square;
+ _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base);
+
+ extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / scaled_font->em_square;
+ extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / scaled_font->em_square;
+ extents->width = (double)metrics.gmBlackBoxX / scaled_font->em_square;
+ extents->height = (double)metrics.gmBlackBoxY / scaled_font->em_square;
+ extents->x_advance = (double)metrics.gmCellIncX / scaled_font->em_square;
+ extents->y_advance = (double)metrics.gmCellIncY / scaled_font->em_square;
}
return CAIRO_STATUS_SUCCESS;
@@ -733,13 +726,13 @@ _cairo_win32_font_glyph_extents (void *abstract_font,
static cairo_status_t
-_cairo_win32_font_glyph_bbox (void *abstract_font,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
+_cairo_win32_scaled_font_glyph_bbox (void *abstract_font,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox)
{
static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
if (num_glyphs > 0) {
@@ -751,7 +744,7 @@ _cairo_win32_font_glyph_bbox (void *abstract_font,
if (!hdc)
return CAIRO_STATUS_NO_MEMORY;
- status = cairo_win32_font_select_font (&font->base, hdc);
+ status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
if (!CAIRO_OK (status))
return status;
@@ -772,7 +765,7 @@ _cairo_win32_font_glyph_bbox (void *abstract_font,
y2 = y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY;
}
- cairo_win32_font_done_font (&font->base);
+ cairo_win32_scaled_font_done_font (&scaled_font->base);
}
bbox->p1.x = _cairo_fixed_from_int (x1);
@@ -784,7 +777,7 @@ _cairo_win32_font_glyph_bbox (void *abstract_font,
}
typedef struct {
- cairo_win32_font_t *font;
+ cairo_win32_scaled_font_t *scaled_font;
HDC hdc;
cairo_array_t glyphs;
@@ -796,12 +789,12 @@ typedef struct {
} cairo_glyph_state_t;
static void
-_start_glyphs (cairo_glyph_state_t *state,
- cairo_win32_font_t *font,
- HDC hdc)
+_start_glyphs (cairo_glyph_state_t *state,
+ cairo_win32_scaled_font_t *scaled_font,
+ HDC hdc)
{
state->hdc = hdc;
- state->font = font;
+ state->scaled_font = scaled_font;
_cairo_array_init (&state->glyphs, sizeof (WCHAR));
_cairo_array_init (&state->dx, sizeof (int));
@@ -841,7 +834,7 @@ _add_glyph (cairo_glyph_state_t *state,
WCHAR glyph_index = index;
int logical_x, logical_y;
- cairo_matrix_transform_point (&state->font->device_to_logical, &user_x, &user_y);
+ cairo_matrix_transform_point (&state->scaled_font->device_to_logical, &user_x, &user_y);
logical_x = floor (user_x + 0.5);
logical_y = floor (user_y + 0.5);
@@ -881,13 +874,13 @@ _finish_glyphs (cairo_glyph_state_t *state)
}
static cairo_status_t
-_draw_glyphs_on_surface (cairo_win32_surface_t *surface,
- cairo_win32_font_t *font,
- COLORREF color,
- int x_offset,
- int y_offset,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
+_draw_glyphs_on_surface (cairo_win32_surface_t *surface,
+ cairo_win32_scaled_font_t *scaled_font,
+ COLORREF color,
+ int x_offset,
+ int y_offset,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
{
cairo_glyph_state_t state;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
@@ -896,7 +889,7 @@ _draw_glyphs_on_surface (cairo_win32_surface_t *surface,
if (!SaveDC (surface->dc))
return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC");
- status = cairo_win32_font_select_font (&font->base, surface->dc);
+ status = cairo_win32_scaled_font_select_font (&scaled_font->base, surface->dc);
if (!CAIRO_OK (status))
goto FAIL1;
@@ -904,7 +897,7 @@ _draw_glyphs_on_surface (cairo_win32_surface_t *surface,
SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT);
SetBkMode (surface->dc, TRANSPARENT);
- _start_glyphs (&state, font, surface->dc);
+ _start_glyphs (&state, scaled_font, surface->dc);
for (i = 0; i < num_glyphs; i++) {
status = _add_glyph (&state, glyphs[i].index,
@@ -915,7 +908,7 @@ _draw_glyphs_on_surface (cairo_win32_surface_t *surface,
FAIL2:
_finish_glyphs (&state);
- cairo_win32_font_done_font (&font->base);
+ cairo_win32_scaled_font_done_font (&scaled_font->base);
FAIL1:
RestoreDC (surface->dc, 1);
@@ -986,20 +979,20 @@ _compute_a8_mask (cairo_win32_surface_t *mask_surface)
}
static cairo_status_t
-_cairo_win32_font_show_glyphs (void *abstract_font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *generic_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_win32_scaled_font_show_glyphs (void *abstract_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *generic_surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
{
- cairo_win32_font_t *font = abstract_font;
+ cairo_win32_scaled_font_t *scaled_font = abstract_font;
cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
cairo_status_t status;
@@ -1009,8 +1002,7 @@ _cairo_win32_font_show_glyphs (void *abstract_font,
if (_cairo_surface_is_win32 (generic_surface) &&
surface->format == CAIRO_FORMAT_RGB24 &&
operator == CAIRO_OPERATOR_OVER &&
- pattern->type == CAIRO_PATTERN_SOLID &&
- _cairo_pattern_is_opaque (pattern)) {
+ _cairo_pattern_is_opaque_solid (pattern)) {
cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)pattern;
@@ -1019,11 +1011,12 @@ _cairo_win32_font_show_glyphs (void *abstract_font,
*/
COLORREF new_color;
- new_color = RGB (((int)(0xffff * solid_pattern->red)) >> 8,
- ((int)(0xffff * solid_pattern->green)) >> 8,
- ((int)(0xffff * solid_pattern->blue)) >> 8);
+ /* XXX Use the unpremultiplied or premultiplied color? */
+ new_color = RGB (((int)solid_pattern->color.red_short) >> 8,
+ ((int)solid_pattern->color.green_short) >> 8,
+ ((int)solid_pattern->color.blue_short) >> 8);
- status = _draw_glyphs_on_surface (surface, font, new_color,
+ status = _draw_glyphs_on_surface (surface, scaled_font, new_color,
0, 0,
glyphs, num_glyphs);
@@ -1050,11 +1043,11 @@ _cairo_win32_font_show_glyphs (void *abstract_font,
r.bottom = height;
FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH));
- _draw_glyphs_on_surface (tmp_surface, font, RGB (0, 0, 0),
+ _draw_glyphs_on_surface (tmp_surface, scaled_font, RGB (0, 0, 0),
dest_x, dest_y,
glyphs, num_glyphs);
- if (font->quality == CLEARTYPE_QUALITY) {
+ if (scaled_font->quality == CLEARTYPE_QUALITY) {
/* For ClearType, we need a 4-channel mask. If we are compositing on
* a surface with alpha, we need to compute the alpha channel of
* the mask (we just copy the green channel). But for a destination
@@ -1101,84 +1094,109 @@ _cairo_win32_font_show_glyphs (void *abstract_font,
}
static cairo_status_t
-_cairo_win32_font_glyph_path (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
+_cairo_win32_scaled_font_glyph_path (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path)
{
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_win32_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
-{
- return CAIRO_STATUS_NO_MEMORY;
-}
+const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend = {
+ _cairo_win32_scaled_font_create,
+ _cairo_win32_scaled_font_destroy,
+ _cairo_win32_scaled_font_font_extents,
+ _cairo_win32_scaled_font_text_to_glyphs,
+ _cairo_win32_scaled_font_glyph_extents,
+ _cairo_win32_scaled_font_glyph_bbox,
+ _cairo_win32_scaled_font_show_glyphs,
+ _cairo_win32_scaled_font_glyph_path,
+ _cairo_win32_scaled_font_get_glyph_cache_key,
+};
+
+/* cairo_win32_font_face_t */
-const cairo_font_backend_t cairo_win32_font_backend = {
- _cairo_win32_font_create,
- _cairo_win32_font_destroy_font,
- _cairo_win32_font_destroy_unscaled_font,
- _cairo_win32_font_font_extents,
- _cairo_win32_font_text_to_glyphs,
- _cairo_win32_font_glyph_extents,
- _cairo_win32_font_glyph_bbox,
- _cairo_win32_font_show_glyphs,
- _cairo_win32_font_glyph_path,
- _cairo_win32_font_get_glyph_cache_key,
- _cairo_win32_font_create_glyph
+typedef struct _cairo_win32_font_face cairo_win32_font_face_t;
+
+struct _cairo_win32_font_face {
+ cairo_font_face_t base;
+ LOGFONTW logfont;
};
/* implement the platform-specific interface */
+static void
+_cairo_win32_font_face_destroy (void *abstract_face)
+{
+}
+
+static cairo_status_t
+_cairo_win32_font_face_create_font (void *abstract_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **font)
+{
+ cairo_win32_font_face_t *font_face = abstract_face;
+
+ *font = _win32_scaled_font_create (&font_face->logfont,
+ font_matrix, ctm);
+ if (*font)
+ return CAIRO_STATUS_SUCCESS;
+ else
+ return CAIRO_STATUS_NO_MEMORY;
+}
+
+static const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
+ _cairo_win32_font_face_destroy,
+ _cairo_win32_font_face_create_font,
+};
+
/**
- * cairo_win32_font_create_for_logfontw:
+ * cairo_win32_scaled_font_create_for_logfontw:
* @logfont: A #LOGFONTW structure specifying the font to use.
* The lfHeight, lfWidth, lfOrientation and lfEscapement
- * fields of this structure are ignored; information from
- * @scale will be used instead.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
+ * fields of this structure are ignored.
*
* Creates a new font for the Win32 font backend based on a
* #LOGFONT. This font can then be used with
- * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
- * specific functions like cairo_win32_font_select_font().
+ * cairo_set_font_face() or cairo_font_create(). The #cairo_scaled_font_t
+ * returned from cairo_font_create() is also for the Win32 backend
+ * and can be used with functions such as cairo_win32_scaled_font_select_font().
*
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
+ * Return value: a newly created #cairo_font_face_t. Free with
+ * cairo_font_face_destroy() when you are done using it.
**/
-cairo_font_t *
-cairo_win32_font_create_for_logfontw (LOGFONTW *logfont,
- cairo_matrix_t *scale)
+cairo_font_face_t *
+cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont)
{
- cairo_font_scale_t sc;
+ cairo_win32_font_face_t *font_face;
+
+ font_face = malloc (sizeof (cairo_win32_font_face_t));
+ if (!font_face)
+ return NULL;
+
+ font_face->logfont = *logfont;
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- NULL, NULL);
+ _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend);
- return _win32_font_create (logfont, &sc);
+ return &font_face->base;
}
/**
- * cairo_win32_font_select_font:
- * @font: A #cairo_font_t from the Win32 font backend. Such an
- * object can be created with cairo_win32_font_create_for_logfontw().
+ * cairo_win32_scaled_font_select_font:
+ * @scaled_font: A #cairo_scaled_font_t from the Win32 font backend. Such an
+ * object can be created with cairo_win32_scaled_font_create_for_logfontw().
* @hdc: a device context
*
* Selects the font into the given device context and changes the
* map mode and world transformation of the device context to match
* that of the font. This function is intended for use when using
* layout APIs such as Uniscribe to do text layout with the
- * Cairo font. After finishing using the device context, you must call
- * cairo_win32_font_done_font() to release any resources allocated
+ * cairo font. After finishing using the device context, you must call
+ * cairo_win32_scaled_font_done_font() to release any resources allocated
* by this function.
*
- * See cairo_win32_font_get_scale_factor() for converting logical
+ * See cairo_win32_scaled_font_get_metrics_factor() for converting logical
* coordinates from the device context to font space.
*
* Normally, calls to SaveDC() and RestoreDC() would be made around
@@ -1189,30 +1207,30 @@ cairo_win32_font_create_for_logfontw (LOGFONTW *logfont,
* the device context is unchanged.
**/
cairo_status_t
-cairo_win32_font_select_font (cairo_font_t *font,
- HDC hdc)
+cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
+ HDC hdc)
{
cairo_status_t status;
HFONT hfont;
HFONT old_hfont = NULL;
int old_mode;
- hfont = _win32_font_get_scaled_font ((cairo_win32_font_t *)font);
+ hfont = _win32_scaled_font_get_scaled_hfont ((cairo_win32_scaled_font_t *)scaled_font);
if (!hfont)
return CAIRO_STATUS_NO_MEMORY;
old_hfont = SelectObject (hdc, hfont);
if (!old_hfont)
- return _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
+ return _cairo_win32_print_gdi_error ("cairo_win32_scaled_font_select_font");
old_mode = SetGraphicsMode (hdc, GM_ADVANCED);
if (!old_mode) {
- status = _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
+ status = _cairo_win32_print_gdi_error ("cairo_win32_scaled_font_select_font");
SelectObject (hdc, old_hfont);
return status;
}
- status = _win32_font_set_world_transform ((cairo_win32_font_t *)font, hdc);
+ status = _win32_scaled_font_set_world_transform ((cairo_win32_scaled_font_t *)scaled_font, hdc);
if (!CAIRO_OK (status)) {
SetGraphicsMode (hdc, old_mode);
SelectObject (hdc, old_hfont);
@@ -1225,28 +1243,30 @@ cairo_win32_font_select_font (cairo_font_t *font,
}
/**
- * cairo_win32_font_done_font:
- * @font: A #cairo_font_t from the Win32 font backend.
+ * cairo_win32_scaled_font_done_font:
+ * @scaled_font: A #cairo_scaled_font_t from the Win32 font backend.
*
- * Releases any resources allocated by cairo_win32_font_select_font()
+ * Releases any resources allocated by cairo_win32_scaled_font_select_font()
**/
void
-cairo_win32_font_done_font (cairo_font_t *font)
+cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font)
{
}
/**
- * cairo_win32_font_get_scale_factor:
- * @font: a #cairo_font_t from the Win32 font backend
+ * cairo_win32_scaled_font_get_metrics_factor:
+ * @scaled_font: a #cairo_scaled_font_t from the Win32 font backend
*
* Gets a scale factor between logical coordinates in the coordinate
- * space used by cairo_win32_font_select_font() and font space coordinates.
+ * space used by cairo_win32_scaled_font_select_font() (that is, the
+ * coordinate system used by the Windows functions to return metrics) and
+ * font space coordinates.
*
* Return value: factor to multiply logical units by to get font space
* coordinates.
**/
double
-cairo_win32_font_get_scale_factor (cairo_font_t *font)
+cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font)
{
- return 1. / ((cairo_win32_font_t *)font)->logical_scale;
+ return 1. / ((cairo_win32_scaled_font_t *)scaled_font)->logical_scale;
}
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index dcfe6d044..9df86380b 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1,6 +1,6 @@
/* Cairo - a vector graphics library with display and print output
*
- * Copyright © 2005 Red Hat, Inc.
+ * Copyright  2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -34,7 +34,7 @@
*/
#include <stdio.h>
-
+#include "cairoint.h"
#include "cairo-win32-private.h"
static const cairo_surface_backend_t cairo_win32_surface_backend;
@@ -46,7 +46,7 @@ static const cairo_surface_backend_t cairo_win32_surface_backend;
* Helper function to dump out a human readable form of the
* current error code.
*
- * Return value: A Cairo status code for the error code
+ * Return value: A cairo status code for the error code
**/
cairo_status_t
_cairo_win32_print_gdi_error (const char *context)
@@ -76,27 +76,6 @@ _cairo_win32_print_gdi_error (const char *context)
return CAIRO_STATUS_NO_MEMORY;
}
-void
-cairo_set_target_win32 (cairo_t *cr,
- HDC hdc)
-{
- cairo_surface_t *surface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_win32_surface_create (hdc);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
-
static cairo_status_t
_create_dc_and_bitmap (cairo_win32_surface_t *surface,
HDC original_dc,
@@ -215,7 +194,7 @@ _create_dc_and_bitmap (cairo_win32_surface_t *surface,
*bits_out = bits;
if (rowstride_out) {
- /* Windows bitmaps are padded to 16-bit (word) boundaries */
+ /* Windows bitmaps are padded to 32-bit (dword) boundaries */
switch (format) {
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
@@ -223,11 +202,11 @@ _create_dc_and_bitmap (cairo_win32_surface_t *surface,
break;
case CAIRO_FORMAT_A8:
- *rowstride_out = (width + 1) & -2;
+ *rowstride_out = (width + 3) & ~3;
break;
case CAIRO_FORMAT_A1:
- *rowstride_out = ((width + 15) & -16) / 8;
+ *rowstride_out = ((width + 31) & ~31) / 8;
break;
}
}
@@ -345,8 +324,8 @@ _cairo_win32_surface_create_dib (cairo_format_t format,
width, height);
}
-static void
-_cairo_win32_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_win32_surface_finish (void *abstract_surface)
{
cairo_win32_surface_t *surface = abstract_surface;
@@ -362,15 +341,8 @@ _cairo_win32_surface_destroy (void *abstract_surface)
DeleteObject (surface->bitmap);
DeleteDC (surface->dc);
}
-
- free (surface);
-}
-static double
-_cairo_win32_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We should really get this value from somewhere */
- return 96.0;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -433,10 +405,6 @@ _cairo_win32_surface_acquire_source_image (void *abstract_sur
surface->clip_rect.width,
surface->clip_rect.height, &local);
if (CAIRO_OK (status)) {
- cairo_surface_set_filter (&local->base, surface->base.filter);
- cairo_surface_set_matrix (&local->base, &surface->base.matrix);
- cairo_surface_set_repeat (&local->base, surface->base.repeat);
-
*image_out = (cairo_image_surface_t *)local->image;
*image_extra = local;
}
@@ -544,14 +512,6 @@ _cairo_win32_surface_release_dest_image (void *abstract_surfac
cairo_surface_destroy ((cairo_surface_t *)local);
}
-static cairo_status_t
-_cairo_win32_surface_clone_similar (void *surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
static cairo_int_status_t
_cairo_win32_surface_composite (cairo_operator_t operator,
cairo_pattern_t *pattern,
@@ -584,9 +544,9 @@ _cairo_win32_surface_composite (cairo_operator_t operator,
if (mask_pattern->type != CAIRO_PATTERN_SOLID)
return CAIRO_INT_STATUS_UNSUPPORTED;
- alpha = (int)(0xffff * pattern->alpha * mask_pattern->alpha) >> 8;
+ alpha = ((cairo_solid_pattern_t *)mask_pattern)->color.alpha_short >> 8;
} else {
- alpha = (int)(0xffff * pattern->alpha) >> 8;
+ alpha = 255;
}
src_surface_pattern = (cairo_surface_pattern_t *)pattern;
@@ -601,7 +561,7 @@ _cairo_win32_surface_composite (cairo_operator_t operator,
if (alpha == 255 &&
src->format == dst->format &&
- (operator == CAIRO_OPERATOR_SRC ||
+ (operator == CAIRO_OPERATOR_SOURCE ||
(src->format == CAIRO_FORMAT_RGB24 && operator == CAIRO_OPERATOR_OVER))) {
if (!BitBlt (dst->dc,
@@ -642,6 +602,81 @@ _cairo_win32_surface_composite (cairo_operator_t operator,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+/* This big function tells us how to optimize operators for the
+ * case of solid destination and constant-alpha source
+ *
+ * NOTE: This function needs revisiting if we add support for
+ * super-luminescent colors (a == 0, r,g,b > 0)
+ */
+static enum { DO_CLEAR, DO_SOURCE, DO_NOTHING, DO_UNSUPPORTED }
+categorize_solid_dest_operator (cairo_operator_t operator,
+ unsigned short alpha)
+{
+ enum { SOURCE_TRANSPARENT, SOURCE_LIGHT, SOURCE_SOLID, SOURCE_OTHER } source;
+
+ if (alpha >= 0xff00)
+ source = SOURCE_SOLID;
+ else if (alpha < 0x100)
+ source = SOURCE_TRANSPARENT;
+ else
+ source = SOURCE_OTHER;
+
+ switch (operator) {
+ case CAIRO_OPERATOR_CLEAR: /* 0 0 */
+ case CAIRO_OPERATOR_OUT: /* 1 - Ab 0 */
+ return DO_CLEAR;
+ break;
+
+ case CAIRO_OPERATOR_SOURCE: /* 1 0 */
+ case CAIRO_OPERATOR_IN: /* Ab 0 */
+ return DO_SOURCE;
+ break;
+
+ case CAIRO_OPERATOR_OVER: /* 1 1 - Aa */
+ case CAIRO_OPERATOR_ATOP: /* Ab 1 - Aa */
+ if (source == SOURCE_SOLID)
+ return DO_SOURCE;
+ else if (source == SOURCE_TRANSPARENT)
+ return DO_NOTHING;
+ else
+ return DO_UNSUPPORTED;
+ break;
+
+ case CAIRO_OPERATOR_DEST_OUT: /* 0 1 - Aa */
+ case CAIRO_OPERATOR_XOR: /* 1 - Ab 1 - Aa */
+ if (source == SOURCE_SOLID)
+ return DO_CLEAR;
+ else if (source == SOURCE_TRANSPARENT)
+ return DO_NOTHING;
+ else
+ return DO_UNSUPPORTED;
+ break;
+
+ case CAIRO_OPERATOR_DEST: /* 0 1 */
+ case CAIRO_OPERATOR_DEST_OVER:/* 1 - Ab 1 */
+ case CAIRO_OPERATOR_SATURATE: /* min(1,(1-Ab)/Aa) 1 */
+ return DO_NOTHING;
+ break;
+
+ case CAIRO_OPERATOR_DEST_IN: /* 0 Aa */
+ case CAIRO_OPERATOR_DEST_ATOP:/* 1 - Ab Aa */
+ if (source == SOURCE_SOLID)
+ return DO_NOTHING;
+ else if (source == SOURCE_TRANSPARENT)
+ return DO_CLEAR;
+ else
+ return DO_UNSUPPORTED;
+ break;
+
+ case CAIRO_OPERATOR_ADD: /* 1 1 */
+ if (source == SOURCE_TRANSPARENT)
+ return DO_NOTHING;
+ else
+ return DO_UNSUPPORTED;
+ break;
+ }
+}
+
static cairo_int_status_t
_cairo_win32_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t operator,
@@ -660,17 +695,24 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
*/
if (surface->image)
return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* We could support possibly support more operators for color->alpha = 0xffff.
- * for CAIRO_OPERATOR_SRC, alpha doesn't matter since we know the destination
- * image doesn't have alpha. (surface->pixman_image is non-NULL for all
+
+ /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
* surfaces with alpha.)
*/
- if (operator != CAIRO_OPERATOR_SRC)
+ switch (categorize_solid_dest_operator (operator, color->alpha_short)) {
+ case DO_CLEAR:
+ new_color = RGB (0, 0, 0);
+ break;
+ case DO_SOURCE:
+ new_color = RGB (color->red_short >> 8, color->blue_short >> 8, color->green_short >> 8);
+ break;
+ case DO_NOTHING:
+ return CAIRO_STATUS_SUCCESS;
+ case DO_UNSUPPORTED:
+ default:
return CAIRO_INT_STATUS_UNSUPPORTED;
-
- new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
-
+ }
+
new_brush = CreateSolidBrush (new_color);
if (!new_brush)
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
@@ -700,35 +742,6 @@ _cairo_win32_surface_fill_rectangles (void *abstract_surface,
}
static cairo_int_status_t
-_cairo_win32_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
_cairo_win32_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
@@ -741,14 +754,14 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
if (surface->image)
_cairo_surface_set_clip_region (surface->image, region);
- /* The semantics we want is that any clip set by Cairo combines
+ /* The semantics we want is that any clip set by cairo combines
* is intersected with the clip on device context that the
* surface was created for. To implement this, we need to
* save the original clip when first setting a clip on surface.
*/
if (region == NULL) {
- /* Clear any clip set by Cairo, return to the original */
+ /* Clear any clip set by cairo, return to the original */
if (surface->set_clip) {
if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
@@ -845,21 +858,22 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
}
}
-static cairo_status_t
-_cairo_win32_surface_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
+static cairo_int_status_t
+_cairo_win32_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ cairo_win32_surface_t *surface = abstract_surface;
+ RECT clip_box;
+
+ if (GetClipBox (surface->dc, &clip_box) == ERROR)
+ return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
+
+ rectangle->x = clip_box.left;
+ rectangle->y = clip_box.top;
+ rectangle->width = clip_box.right - clip_box.left;
+ rectangle->height = clip_box.bottom - clip_box.top;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_surface_t *
@@ -884,6 +898,7 @@ cairo_win32_surface_create (HDC hdc)
surface->dc = hdc;
surface->bitmap = NULL;
+ surface->saved_dc_bitmap = NULL;
surface->clip_rect.x = rect.left;
surface->clip_rect.y = rect.top;
@@ -914,18 +929,18 @@ _cairo_surface_is_win32 (cairo_surface_t *surface)
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_finish,
_cairo_win32_surface_acquire_source_image,
_cairo_win32_surface_release_source_image,
_cairo_win32_surface_acquire_dest_image,
_cairo_win32_surface_release_dest_image,
- _cairo_win32_surface_clone_similar,
+ NULL, /* clone_similar */
_cairo_win32_surface_composite,
_cairo_win32_surface_fill_rectangles,
- _cairo_win32_surface_composite_trapezoids,
- _cairo_win32_surface_copy_page,
- _cairo_win32_surface_show_page,
+ NULL, /* composite_trapezoids */
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_win32_surface_set_clip_region,
- _cairo_win32_surface_show_glyphs
+ _cairo_win32_surface_get_extents,
+ NULL /* show_glyphs */
};
diff --git a/src/cairo-win32.h b/src/cairo-win32.h
index fab497aa4..93983456f 100644
--- a/src/cairo-win32.h
+++ b/src/cairo-win32.h
@@ -34,38 +34,36 @@
*/
#ifndef _CAIRO_WIN32_H_
+#define _CAIRO_WIN32_H_
#include <cairo.h>
-#ifdef CAIRO_HAS_WIN32_SURFACE
+#if CAIRO_HAS_WIN32_SURFACE
#include <windows.h>
CAIRO_BEGIN_DECLS
-void
-cairo_set_target_win32 (cairo_t *cr,
- HDC hdc);
-
cairo_surface_t *
cairo_win32_surface_create (HDC hdc);
-cairo_font_t *
-cairo_win32_font_create_for_logfontw (LOGFONTW *logfont,
- cairo_matrix_t *scale);
+cairo_font_face_t *
+cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont);
cairo_status_t
-cairo_win32_font_select_font (cairo_font_t *font,
- HDC hdc);
+cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
+ HDC hdc);
void
-cairo_win32_font_done_font (cairo_font_t *font);
+cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font);
double
-cairo_win32_font_get_scale_factor (cairo_font_t *font);
-
-#endif /* CAIRO_HAS_WIN32_SURFACE */
+cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_WIN32_SURFACE */
+# error Cairo was not compiled with support for the win32 backend
+#endif /* CAIRO_HAS_WIN32_SURFACE */
+
#endif /* _CAIRO_WIN32_H_ */
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 0694b77a2..95568d608 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -36,12 +36,7 @@
#include "cairoint.h"
#include "cairo-xcb.h"
-
-cairo_surface_t *
-cairo_xcb_surface_create (XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format);
+#include "cairo-xcb-xrender.h"
#define AllPlanes ((unsigned long)~0L)
@@ -71,10 +66,12 @@ format_from_visual(XCBConnection *c, XCBVISUALID visual)
return nil;
}
-static XCBRenderPICTFORMAT
-format_from_cairo(XCBConnection *c, cairo_format_t fmt)
+/* XXX: Why is this ridiculously complex compared to the equivalent
+ * function in cairo-xlib-surface.c */
+static XCBRenderPICTFORMINFO
+_format_from_cairo(XCBConnection *c, cairo_format_t fmt)
{
- XCBRenderPICTFORMAT ret = { 0 };
+ XCBRenderPICTFORMINFO ret = {{ 0 }};
struct tmpl_t {
XCBRenderDIRECTFORMAT direct;
CARD8 depth;
@@ -151,36 +148,20 @@ format_from_cairo(XCBConnection *c, cairo_format_t fmt)
if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift))
continue;
- ret = fi.data->id;
+ ret = *fi.data;
}
free(r);
return ret;
}
-void
-cairo_set_target_xcb (cairo_t *cr,
- XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format)
-{
- cairo_surface_t *surface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_xcb_surface_create (dpy, drawable, visual, format);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
+/*
+ * Instead of taking two round trips for each blending request,
+ * assume that if a particular drawable fails GetImage that it will
+ * fail for a "while"; use temporary pixmaps to avoid the errors
+ */
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
+#define CAIRO_ASSUME_PIXMAP 20
typedef struct cairo_xcb_surface {
cairo_surface_t base;
@@ -190,15 +171,19 @@ typedef struct cairo_xcb_surface {
XCBDRAWABLE drawable;
int owns_pixmap;
XCBVISUALTYPE *visual;
- cairo_format_t format;
+
+ int use_pixmap;
int render_major;
int render_minor;
int width;
int height;
+ int depth;
XCBRenderPICTURE picture;
+ XCBRenderPICTFORMINFO format;
+ int has_format;
} cairo_xcb_surface_t;
#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
@@ -222,6 +207,9 @@ typedef struct cairo_xcb_surface {
#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
+static void
+_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface);
+
static int
_CAIRO_FORMAT_DEPTH (cairo_format_t format)
{
@@ -239,46 +227,43 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
}
static cairo_surface_t *
-_cairo_xcb_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
+_cairo_xcb_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height)
{
cairo_xcb_surface_t *src = abstract_src;
XCBConnection *dpy = src->dpy;
XCBDRAWABLE d;
cairo_xcb_surface_t *surface;
+ XCBRenderPICTFORMINFO xrender_format = _format_from_cairo (dpy, format);
- /* XXX: There's a pretty lame heuristic here. This assumes that
- * all non-Render X servers do not support depth-32 pixmaps, (and
- * that they do support depths 1, 8, and 24). Obviously, it would
- * be much better to check the depths that are actually
- * supported. */
- if (!dpy
- || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)
- && format == CAIRO_FORMAT_ARGB32))
- {
- return NULL;
+ /* As a good first approximation, if the display doesn't have COMPOSITE,
+ * we're better off using image surfaces for all temporary operations
+ */
+ if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) {
+ return cairo_image_surface_create (format, width, height);
}
d.pixmap = XCBPIXMAPNew (dpy);
XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
d.pixmap, src->drawable,
- width, height);
+ width <= 0 ? 1 : width,
+ height <= 0 ? 1 : height);
surface = (cairo_xcb_surface_t *)
- cairo_xcb_surface_create (dpy, d, NULL, format);
- surface->owns_pixmap = 1;
+ cairo_xcb_surface_create_with_xrender_format (dpy, d,
+ &xrender_format,
+ width, height);
- surface->width = width;
- surface->height = height;
+ surface->owns_pixmap = TRUE;
return &surface->base;
}
-static void
-_cairo_xcb_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_xcb_surface_finish (void *abstract_surface)
{
cairo_xcb_surface_t *surface = abstract_surface;
if (surface->picture.xid)
@@ -290,20 +275,13 @@ _cairo_xcb_surface_destroy (void *abstract_surface)
if (surface->gc.xid)
XCBFreeGC (surface->dpy, surface->gc);
- surface->dpy = 0;
+ surface->dpy = NULL;
- free (surface);
-}
-
-static double
-_cairo_xcb_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We should really get this value from somewhere like Xft.dpy */
- return 96.0;
+ return CAIRO_STATUS_SUCCESS;
}
static int
-bits_per_pixel(XCBConnection *c, int depth)
+_bits_per_pixel(XCBConnection *c, int depth)
{
XCBFORMAT *fmt = XCBConnSetupSuccessRepPixmapFormats(XCBGetSetup(c));
XCBFORMAT *fmtend = fmt + XCBConnSetupSuccessRepPixmapFormatsLength(XCBGetSetup(c));
@@ -322,12 +300,52 @@ bits_per_pixel(XCBConnection *c, int depth)
}
static int
-bytes_per_line(XCBConnection *c, int width, int bpp)
+_bytes_per_line(XCBConnection *c, int width, int bpp)
{
int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
}
+static cairo_bool_t
+_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
+{
+ switch (masks->bpp) {
+ case 32:
+ if (masks->alpha_mask == 0xff000000 &&
+ masks->red_mask == 0x00ff0000 &&
+ masks->green_mask == 0x0000ff00 &&
+ masks->blue_mask == 0x000000ff)
+ {
+ *format = CAIRO_FORMAT_ARGB32;
+ return 1;
+ }
+ if (masks->alpha_mask == 0x00000000 &&
+ masks->red_mask == 0x00ff0000 &&
+ masks->green_mask == 0x0000ff00 &&
+ masks->blue_mask == 0x000000ff)
+ {
+ *format = CAIRO_FORMAT_RGB24;
+ return 1;
+ }
+ break;
+ case 8:
+ if (masks->alpha_mask == 0xff)
+ {
+ *format = CAIRO_FORMAT_A8;
+ return 1;
+ }
+ break;
+ case 1:
+ if (masks->alpha_mask == 0x1)
+ {
+ *format = CAIRO_FORMAT_A1;
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
static cairo_status_t
_get_image_surface (cairo_xcb_surface_t *surface,
cairo_rectangle_t *interest_rect,
@@ -335,18 +353,12 @@ _get_image_surface (cairo_xcb_surface_t *surface,
cairo_rectangle_t *image_rect)
{
cairo_image_surface_t *image;
- XCBGetGeometryRep *geomrep;
XCBGetImageRep *imagerep;
- int bpp;
+ int bpp, bytes_per_line;
int x1, y1, x2, y2;
-
- geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0);
- if(!geomrep)
- return 0;
-
- surface->width = geomrep->width;
- surface->height = geomrep->height;
- free(geomrep);
+ unsigned char *data;
+ cairo_format_t format;
+ cairo_format_masks_t masks;
x1 = 0;
y1 = 0;
@@ -354,14 +366,21 @@ _get_image_surface (cairo_xcb_surface_t *surface,
y2 = surface->height;
if (interest_rect) {
- if (interest_rect->x > x1)
- x1 = interest_rect->x;
- if (interest_rect->y > y1)
- y1 = interest_rect->y;
- if (interest_rect->x + interest_rect->width < x2)
- x2 = interest_rect->x + interest_rect->width;
- if (interest_rect->y + interest_rect->height < y2)
- y2 = interest_rect->y + interest_rect->height;
+ cairo_rectangle_t rect;
+
+ rect.x = interest_rect->x;
+ rect.y = interest_rect->y;
+ rect.width = interest_rect->width;
+ rect.height = interest_rect->width;
+
+ if (rect.x > x1)
+ x1 = rect.x;
+ if (rect.y > y1)
+ y1 = rect.y;
+ if (rect.x + rect.width < x2)
+ x2 = rect.x + rect.width;
+ if (rect.y + rect.height < y2)
+ y2 = rect.y + rect.height;
if (x1 >= x2 || y1 >= y2) {
*image_out = NULL;
@@ -376,47 +395,132 @@ _get_image_surface (cairo_xcb_surface_t *surface,
image_rect->height = y2 - y1;
}
- imagerep = XCBGetImageReply(surface->dpy,
- XCBGetImage(surface->dpy, ZPixmap,
- surface->drawable,
- x1, y1,
- x2 - x1, y2 - y1,
- AllPlanes), 0);
- if(!imagerep)
- return 0;
+ /* XXX: This should try to use the XShm extension if available */
- bpp = bits_per_pixel(surface->dpy, imagerep->depth);
+ if (surface->use_pixmap == 0)
+ {
+ XCBGenericError *error;
+ imagerep = XCBGetImageReply(surface->dpy,
+ XCBGetImage(surface->dpy, ZPixmap,
+ surface->drawable,
+ x1, y1,
+ x2 - x1, y2 - y1,
+ AllPlanes), &error);
+
+ /* If we get an error, the surface must have been a window,
+ * so retry with the safe code path.
+ */
+ if (error)
+ surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
+ }
+ else
+ {
+ surface->use_pixmap--;
+ imagerep = NULL;
+ }
- if (surface->visual) {
- cairo_format_masks_t masks;
+ if (!imagerep)
+ {
+ /* XCBGetImage from a window is dangerous because it can
+ * produce errors if the window is unmapped or partially
+ * outside the screen. We could check for errors and
+ * retry, but to keep things simple, we just create a
+ * temporary pixmap
+ */
+ XCBDRAWABLE drawable;
+ drawable.pixmap = XCBPIXMAPNew (surface->dpy);
+ XCBCreatePixmap (surface->dpy,
+ surface->depth,
+ drawable.pixmap,
+ surface->drawable,
+ x2 - x1, y2 - y1);
+ _cairo_xcb_surface_ensure_gc (surface);
+
+ XCBCopyArea (surface->dpy, surface->drawable, drawable, surface->gc,
+ x1, y1, 0, 0, x2 - x1, y2 - y1);
+
+ imagerep = XCBGetImageReply(surface->dpy,
+ XCBGetImage(surface->dpy, ZPixmap,
+ drawable,
+ x1, y1,
+ x2 - x1, y2 - y1,
+ AllPlanes), 0);
+ XCBFreePixmap (surface->dpy, drawable.pixmap);
+
+ }
+ if (!imagerep)
+ return CAIRO_STATUS_NO_MEMORY;
- /* XXX: Add support here for pictures with external alpha? */
+ bpp = _bits_per_pixel(surface->dpy, imagerep->depth);
+ bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp);
+ data = malloc (bytes_per_line * surface->height);
+ if (data == NULL) {
+ free (imagerep);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ memcpy (data, XCBGetImageData (imagerep), bytes_per_line * surface->height);
+ free (imagerep);
+
+ /*
+ * Compute the pixel format masks from either an XCBVISUALTYPE or
+ * a XCBRenderPCTFORMINFO, failing we assume the drawable is an
+ * alpha-only pixmap as it could only have been created that way
+ * through the cairo_xlib_surface_create_for_bitmap function.
+ */
+ if (surface->visual) {
masks.bpp = bpp;
masks.alpha_mask = 0;
masks.red_mask = surface->visual->red_mask;
masks.green_mask = surface->visual->green_mask;
masks.blue_mask = surface->visual->blue_mask;
-
- image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep),
- &masks,
- x2 - x1,
- y2 - y1,
- bytes_per_line(surface->dpy, surface->width, bpp));
+ } else if (surface->has_format) {
+ masks.bpp = bpp;
+ masks.red_mask = surface->format.direct.red_mask << surface->format.direct.red_shift;
+ masks.green_mask = surface->format.direct.green_mask << surface->format.direct.green_shift;
+ masks.blue_mask = surface->format.direct.blue_mask << surface->format.direct.blue_shift;
+ masks.alpha_mask = surface->format.direct.alpha_mask << surface->format.direct.alpha_shift;
} else {
+ masks.bpp = bpp;
+ masks.red_mask = 0;
+ masks.green_mask = 0;
+ masks.blue_mask = 0;
+ if (surface->depth < 32)
+ masks.alpha_mask = (1 << surface->depth) - 1;
+ else
+ masks.alpha_mask = 0xffffffff;
+ }
+
+ /*
+ * Prefer to use a standard pixman format instead of the
+ * general masks case.
+ */
+ if (_CAIRO_MASK_FORMAT (&masks, &format)) {
image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (XCBGetImageData(imagerep),
- surface->format,
+ cairo_image_surface_create_for_data (data,
+ format,
x2 - x1,
y2 - y1,
- bytes_per_line(surface->dpy, surface->width, bpp));
+ bytes_per_line);
+ } else {
+ /*
+ * XXX This can't work. We must convert the data to one of the
+ * supported pixman formats. Pixman needs another function
+ * which takes data in an arbitrary format and converts it
+ * to something supported by that library.
+ */
+ image = _cairo_image_surface_create_with_masks (data,
+ &masks,
+ x2 - x1,
+ y2 - y1,
+ bytes_per_line);
+
}
/* Let the surface take ownership of the data */
- /* XXX: Can probably come up with a cleaner API here. */
_cairo_image_surface_assume_ownership_of_data (image);
- /* FIXME: imagerep can't be freed correctly, I think. must copy. :-( */
-
+
_cairo_image_surface_set_repeat (image, surface->base.repeat);
_cairo_image_surface_set_matrix (image, &(surface->base.matrix));
@@ -443,8 +547,8 @@ _draw_image_surface (cairo_xcb_surface_t *surface,
int bpp, data_len;
_cairo_xcb_surface_ensure_gc (surface);
- bpp = bits_per_pixel(surface->dpy, image->depth);
- data_len = bytes_per_line(surface->dpy, image->width, bpp) * image->height;
+ bpp = _bits_per_pixel(surface->dpy, image->depth);
+ data_len = _bytes_per_line(surface->dpy, image->width, bpp) * image->height;
XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
image->width,
image->height,
@@ -465,13 +569,8 @@ _cairo_xcb_surface_acquire_source_image (void *abstract_surfa
cairo_status_t status;
status = _get_image_surface (surface, NULL, &image, NULL);
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_set_filter (&image->base, surface->base.filter);
- cairo_surface_set_matrix (&image->base, &surface->base.matrix);
- cairo_surface_set_repeat (&image->base, surface->base.repeat);
-
+ if (status == CAIRO_STATUS_SUCCESS)
*image_out = image;
- }
return status;
}
@@ -562,13 +661,13 @@ _cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
if (!surface->picture.xid)
return CAIRO_STATUS_SUCCESS;
- xtransform.matrix11 = _cairo_fixed_from_double (matrix->m[0][0]);
- xtransform.matrix12 = _cairo_fixed_from_double (matrix->m[1][0]);
- xtransform.matrix13 = _cairo_fixed_from_double (matrix->m[2][0]);
+ xtransform.matrix11 = _cairo_fixed_from_double (matrix->xx);
+ xtransform.matrix12 = _cairo_fixed_from_double (matrix->xy);
+ xtransform.matrix13 = _cairo_fixed_from_double (matrix->x0);
- xtransform.matrix21 = _cairo_fixed_from_double (matrix->m[0][1]);
- xtransform.matrix22 = _cairo_fixed_from_double (matrix->m[1][1]);
- xtransform.matrix23 = _cairo_fixed_from_double (matrix->m[2][1]);
+ xtransform.matrix21 = _cairo_fixed_from_double (matrix->yx);
+ xtransform.matrix22 = _cairo_fixed_from_double (matrix->yy);
+ xtransform.matrix23 = _cairo_fixed_from_double (matrix->y0);
xtransform.matrix31 = 0;
xtransform.matrix32 = 0;
@@ -685,25 +784,25 @@ _render_operator (cairo_operator_t operator)
switch (operator) {
case CAIRO_OPERATOR_CLEAR:
return XCBRenderPictOpClear;
- case CAIRO_OPERATOR_SRC:
+ case CAIRO_OPERATOR_SOURCE:
return XCBRenderPictOpSrc;
- case CAIRO_OPERATOR_DST:
+ case CAIRO_OPERATOR_DEST:
return XCBRenderPictOpDst;
case CAIRO_OPERATOR_OVER:
return XCBRenderPictOpOver;
- case CAIRO_OPERATOR_OVER_REVERSE:
+ case CAIRO_OPERATOR_DEST_OVER:
return XCBRenderPictOpOverReverse;
case CAIRO_OPERATOR_IN:
return XCBRenderPictOpIn;
- case CAIRO_OPERATOR_IN_REVERSE:
+ case CAIRO_OPERATOR_DEST_IN:
return XCBRenderPictOpInReverse;
case CAIRO_OPERATOR_OUT:
return XCBRenderPictOpOut;
- case CAIRO_OPERATOR_OUT_REVERSE:
+ case CAIRO_OPERATOR_DEST_OUT:
return XCBRenderPictOpOutReverse;
case CAIRO_OPERATOR_ATOP:
return XCBRenderPictOpAtop;
- case CAIRO_OPERATOR_ATOP_REVERSE:
+ case CAIRO_OPERATOR_DEST_ATOP:
return XCBRenderPictOpAtopReverse;
case CAIRO_OPERATOR_XOR:
return XCBRenderPictOpXor;
@@ -840,6 +939,7 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
cairo_int_status_t status;
int render_reference_x, render_reference_y;
int render_src_x, render_src_y;
+ XCBRenderPICTFORMINFO render_format;
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -863,13 +963,14 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
render_src_y = src_y + render_reference_y - dst_y;
/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
- /* XXX: format_from_cairo is slow. should cache something. */
+ /* XXX: _format_from_cairo is slow. should cache something. */
+ render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
status = _cairo_xcb_surface_set_attributes (src, &attributes);
if (CAIRO_OK (status))
XCBRenderTrapezoids (dst->dpy,
_render_operator (operator),
src->picture, dst->picture,
- format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
+ render_format.id,
render_src_x + attributes.x_offset,
render_src_y + attributes.y_offset,
num_traps, (XCBRenderTRAP *) traps);
@@ -880,29 +981,31 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
}
static cairo_int_status_t
-_cairo_xcb_surface_copy_page (void *abstract_surface)
+_cairo_xcb_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
{
+ /* XXX: FIXME */
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
-_cairo_xcb_surface_show_page (void *abstract_surface)
+_cairo_xcb_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
+ cairo_xcb_surface_t *surface = abstract_surface;
-static cairo_int_status_t
-_cairo_xcb_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- /* FIXME */
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ rectangle->x = 0;
+ rectangle->y = 0;
+
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
+
+ return CAIRO_STATUS_SUCCESS;
}
static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_create_similar,
- _cairo_xcb_surface_destroy,
- _cairo_xcb_surface_pixels_per_inch,
+ _cairo_xcb_surface_finish,
_cairo_xcb_surface_acquire_source_image,
_cairo_xcb_surface_release_source_image,
_cairo_xcb_surface_acquire_dest_image,
@@ -911,12 +1014,27 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_composite,
_cairo_xcb_surface_fill_rectangles,
_cairo_xcb_surface_composite_trapezoids,
- _cairo_xcb_surface_copy_page,
- _cairo_xcb_surface_show_page,
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_xcb_surface_set_clip_region,
+ _cairo_xcb_surface_get_extents,
NULL /* show_glyphs */
};
+/**
+ * _cairo_surface_is_xcb:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is a #cairo_xcb_surface_t
+ *
+ * Return value: True if the surface is an xcb surface
+ **/
+static cairo_bool_t
+_cairo_surface_is_xcb (cairo_surface_t *surface)
+{
+ return surface->backend == &cairo_xcb_surface_backend;
+}
+
static void
query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface)
{
@@ -937,11 +1055,14 @@ query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface)
free(r);
}
-cairo_surface_t *
-cairo_xcb_surface_create (XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format)
+static cairo_surface_t *
+_cairo_xcb_surface_create_internal (XCBConnection *dpy,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ XCBRenderPICTFORMINFO *format,
+ int width,
+ int height,
+ int depth)
{
cairo_xcb_surface_t *surface;
@@ -952,27 +1073,199 @@ cairo_xcb_surface_create (XCBConnection *dpy,
_cairo_surface_init (&surface->base, &cairo_xcb_surface_backend);
surface->dpy = dpy;
+
surface->gc.xid = 0;
surface->drawable = drawable;
- surface->owns_pixmap = 0;
+ surface->owns_pixmap = FALSE;
surface->visual = visual;
- surface->format = format;
+ if (format) {
+ surface->format = *format;
+ surface->has_format = 1;
+ } else {
+ surface->format.id.xid = 0;
+ surface->has_format = 0;
+ }
+ surface->use_pixmap = 0;
+ surface->width = width;
+ surface->height = height;
+ surface->depth = depth;
+
+ if (format) {
+ surface->depth = format->depth;
+ } else if (visual) {
+ XCBSCREENIter roots;
+ XCBDEPTHIter depths;
+ XCBVISUALTYPEIter visuals;
+
+ /* This is ugly, but we have to walk over all visuals
+ * for the display to find the depth.
+ */
+ roots = XCBConnSetupSuccessRepRootsIter(XCBGetSetup(surface->dpy));
+ for(; roots.rem; XCBSCREENNext(&roots))
+ {
+ depths = XCBSCREENAllowedDepthsIter(roots.data);
+ for(; depths.rem; XCBDEPTHNext(&depths))
+ {
+ visuals = XCBDEPTHVisualsIter(depths.data);
+ for(; visuals.rem; XCBVISUALTYPENext(&visuals))
+ {
+ if(visuals.data->visual_id.id == visual->visual_id.id)
+ {
+ surface->depth = depths.data->depth;
+ goto found;
+ }
+ }
+ }
+ }
+ found:
+ ;
+ }
query_render_version(dpy, surface);
+ surface->picture.xid = 0;
+
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
{
- XCBRenderPICTFORMAT fmt;
- if(visual)
- fmt = format_from_visual (dpy, visual->visual_id);
- else
- fmt = format_from_cairo (dpy, format);
+ XCBRenderPICTFORMAT pict_format = {0};
+ XCBRenderPICTFORMINFO format_info;
+
surface->picture = XCBRenderPICTURENew(dpy);
- XCBRenderCreatePicture (dpy, surface->picture, drawable,
- fmt, 0, NULL);
+
+ if (!format) {
+ if (visual) {
+ pict_format = format_from_visual (dpy, visual->visual_id);
+ } else if (depth == 1) {
+ format_info = _format_from_cairo (dpy, CAIRO_FORMAT_A1);
+ pict_format = format_info.id;
+ }
+ XCBRenderCreatePicture (dpy, surface->picture, drawable,
+ pict_format, 0, NULL);
+ } else {
+ XCBRenderCreatePicture (dpy, surface->picture, drawable,
+ format->id, 0, NULL);
+ }
}
- else
- surface->picture.xid = 0;
return (cairo_surface_t *) surface;
}
+
+/**
+ * cairo_xcb_surface_create:
+ * @c: an XCB connection
+ * @drawable: an XCB drawable
+ * @visual: the visual to use for drawing to @drawable. The depth
+ * of the visual must match the depth of the drawable.
+ * Currently, only TrueColor visuals are fully supported.
+ * @width: the current width of @drawable.
+ * @height: the current height of @drawable.
+ *
+ * Creates an XCB surface that draws to the given drawable.
+ * The way that colors are represented in the drawable is specified
+ * by the provided visual.
+ *
+ * NOTE: If @drawable is a window, then the function
+ * cairo_xcb_surface_set_size must be called whenever the size of the
+ * window changes.
+ *
+ * Return value: the newly created surface
+ **/
+cairo_surface_t *
+cairo_xcb_surface_create (XCBConnection *c,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ int width,
+ int height)
+{
+ return _cairo_xcb_surface_create_internal (c, drawable,
+ visual, NULL,
+ width, height, 0);
+}
+
+/**
+ * cairo_xcb_surface_create_for_bitmap:
+ * @c: an XCB connection
+ * @bitmap: an XCB Pixmap (a depth-1 pixmap)
+ * @width: the current width of @bitmap
+ * @height: the current height of @bitmap
+ *
+ * Creates an XCB surface that draws to the given bitmap.
+ * This will be drawn to as a CAIRO_FORMAT_A1 object.
+ *
+ * Return value: the newly created surface
+ **/
+cairo_surface_t *
+cairo_xcb_surface_create_for_bitmap (XCBConnection *c,
+ XCBPIXMAP bitmap,
+ int width,
+ int height)
+{
+ XCBDRAWABLE drawable;
+ drawable.pixmap = bitmap;
+ return _cairo_xcb_surface_create_internal (c, drawable,
+ NULL, NULL,
+ width, height, 1);
+}
+
+/**
+ * cairo_xcb_surface_create_with_xrender_format:
+ * @c: an XCB connection
+ * @drawable: an XCB drawable
+ * @format: the picture format to use for drawing to @drawable. The
+ * depth of @format mush match the depth of the drawable.
+ * @width: the current width of @drawable
+ * @height: the current height of @drawable
+ *
+ * Creates an XCB surface that draws to the given drawable.
+ * The way that colors are represented in the drawable is specified
+ * by the provided picture format.
+ *
+ * NOTE: If @drawable is a Window, then the function
+ * cairo_xlib_surface_set_size must be called whenever the size of the
+ * window changes.
+ *
+ * Return value: the newly created surface.
+ **/
+cairo_surface_t *
+cairo_xcb_surface_create_with_xrender_format (XCBConnection *c,
+ XCBDRAWABLE drawable,
+ XCBRenderPICTFORMINFO *format,
+ int width,
+ int height)
+{
+ return _cairo_xcb_surface_create_internal (c, drawable,
+ NULL, format,
+ width, height, 0);
+}
+
+/**
+ * cairo_xcb_surface_set_size:
+ * @surface: a #cairo_surface_t for the XCB backend
+ * @width: the new width of the surface
+ * @height: the new height of the surface
+ *
+ * Informs cairo of the new size of the XCB drawable underlying the
+ * surface. For a surface created for a window (rather than a pixmap),
+ * this function must be called each time the size of the window
+ * changes. (For a subwindow, you are normally resizing the window
+ * yourself, but for a toplevel window, it is necessary to listen for
+ * ConfigureNotify events.)
+ *
+ * A pixmap can never change size, so it is never necessary to call
+ * this function on a surface created for a pixmap.
+ **/
+void
+cairo_xcb_surface_set_size (cairo_surface_t *surface,
+ int width,
+ int height)
+{
+ cairo_xcb_surface_t *xcb_surface = (cairo_xcb_surface_t *)surface;
+
+ /* XXX: How do we want to handle this error case? */
+ if (! _cairo_surface_is_xcb (surface))
+ return;
+
+ xcb_surface->width = width;
+ xcb_surface->height = height;
+}
+
diff --git a/src/cairo_fixed.c b/src/cairo-xcb-xrender.h
index a4faa1708..ef4baa991 100644
--- a/src/cairo_fixed.c
+++ b/src/cairo-xcb-xrender.h
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2003 University of Southern California
+ * 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
@@ -34,58 +34,29 @@
* Carl D. Worth <cworth@cworth.org>
*/
-#include "cairoint.h"
+#ifndef CAIRO_XCB_XRENDER_H
+#define CAIRO_XCB_XRENDER_H
-cairo_fixed_t
-_cairo_fixed_from_int (int i)
-{
- return i << 16;
-}
+#include <cairo.h>
-cairo_fixed_t
-_cairo_fixed_from_double (double d)
-{
- return (cairo_fixed_t) (d * 65536);
-}
+#if CAIRO_HAS_XCB_SURFACE
-cairo_fixed_t
-_cairo_fixed_from_26_6 (uint32_t i)
-{
- return i << 10;
-}
+#include <X11/XCB/xcb.h>
+#include <X11/XCB/render.h>
-double
-_cairo_fixed_to_double (cairo_fixed_t f)
-{
- return ((double) f) / 65536.0;
-}
+CAIRO_BEGIN_DECLS
-int
-_cairo_fixed_is_integer (cairo_fixed_t f)
-{
- return (f & 0xFFFF) == 0;
-}
+cairo_surface_t *
+cairo_xcb_surface_create_with_xrender_format (XCBConnection *c,
+ XCBDRAWABLE drawable,
+ XCBRenderPICTFORMINFO *format,
+ int width,
+ int height);
-int
-_cairo_fixed_integer_part (cairo_fixed_t f)
-{
- return f >> 16;
-}
+CAIRO_END_DECLS
-int
-_cairo_fixed_integer_floor (cairo_fixed_t f)
-{
- if (f >= 0)
- return f >> 16;
- else
- return -((-f - 1) >> 16) - 1;
-}
+#else /* CAIRO_HAS_XCB_SURFACE */
+# error Cairo was not compiled with support for the xcb backend
+#endif /* CAIRO_HAS_XCB_SURFACE */
-int
-_cairo_fixed_integer_ceil (cairo_fixed_t f)
-{
- if (f >= 0)
- return ((f - 1)>>16) + 1;
- else
- return - (-f >> 16);
-}
+#endif /* CAIRO_XCB_XRENDER_H */
diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h
index a5c65f441..57a7aebd1 100644
--- a/src/cairo-xcb.h
+++ b/src/cairo-xcb.h
@@ -39,21 +39,34 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_XCB_SURFACE
+#if CAIRO_HAS_XCB_SURFACE
#include <X11/XCB/xcb.h>
-#include <X11/XCB/render.h>
CAIRO_BEGIN_DECLS
+cairo_surface_t *
+cairo_xcb_surface_create (XCBConnection *c,
+ XCBDRAWABLE pixmap,
+ XCBVISUALTYPE *visual,
+ int width,
+ int height);
+
+cairo_surface_t *
+cairo_xcb_surface_create_for_bitmap (XCBConnection *c,
+ XCBPIXMAP bitmap,
+ int width,
+ int height);
+
void
-cairo_set_target_xcb (cairo_t *cr,
- XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format);
+cairo_xcb_surface_set_size (cairo_surface_t *surface,
+ int width,
+ int height);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_XCB_SURFACE */
+# error Cairo was not compiled with support for the xcb backend
#endif /* CAIRO_HAS_XCB_SURFACE */
+
#endif /* CAIRO_XCB_H */
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 3eaef57e5..41fb00c44 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -36,66 +36,47 @@
#include "cairoint.h"
#include "cairo-xlib.h"
+#include "cairo-xlib-xrender.h"
+#include "cairo-xlib-test.h"
+#include <X11/extensions/Xrender.h>
-/**
- * cairo_set_target_drawable:
- * @cr: a #cairo_t
- * @dpy: an X display
- * @drawable: a window or pixmap on the default screen of @dpy
- *
- * Directs output for a #cairo_t to an Xlib drawable. @drawable must
- * be a Window or Pixmap on the default screen of @dpy using the
- * default colormap and visual. Using this function is slow because
- * the function must retrieve information about @drawable from the X
- * server.
-
- * The combination of cairo_xlib_surface_create() and
- * cairo_set_target_surface() is somewhat more flexible, although
- * it still is slow.
- **/
-void
-cairo_set_target_drawable (cairo_t *cr,
- Display *dpy,
- Drawable drawable)
-{
- cairo_surface_t *surface;
+/* Xlib doesn't define a typedef, so define one ourselves */
+typedef int (*cairo_xlib_error_func_t) (Display *display,
+ XErrorEvent *event);
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
+typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
- surface = cairo_xlib_surface_create (dpy, drawable,
- DefaultVisual (dpy, DefaultScreen (dpy)),
- 0,
- DefaultColormap (dpy, DefaultScreen (dpy)));
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
+static void _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
- cairo_set_target_surface (cr, surface);
+/*
+ * Instead of taking two round trips for each blending request,
+ * assume that if a particular drawable fails GetImage that it will
+ * fail for a "while"; use temporary pixmaps to avoid the errors
+ */
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
+#define CAIRO_ASSUME_PIXMAP 20
-typedef struct _cairo_xlib_surface {
+struct _cairo_xlib_surface {
cairo_surface_t base;
Display *dpy;
GC gc;
Drawable drawable;
- int owns_pixmap;
+ cairo_bool_t owns_pixmap;
Visual *visual;
- cairo_format_t format;
+
+ int use_pixmap;
int render_major;
int render_minor;
int width;
int height;
+ int depth;
Picture picture;
-} cairo_xlib_surface_t;
+ XRenderPictFormat *format;
+};
#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
(((surface)->render_major > major) || \
@@ -120,6 +101,25 @@ typedef struct _cairo_xlib_surface {
#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
+static cairo_bool_t cairo_xlib_render_disabled = FALSE;
+
+/**
+ * cairo_test_xlib_disable_render:
+ *
+ * Disables the use of the RENDER extension.
+ *
+ * <note>
+ * This function is <emphasis>only</emphasis> intended for internal
+ * testing use within the cairo distribution. It is not installed in
+ * any public header file.
+ * </note>
+ **/
+void
+cairo_test_xlib_disable_render (void)
+{
+ cairo_xlib_render_disabled = TRUE;
+}
+
static int
_CAIRO_FORMAT_DEPTH (cairo_format_t format)
{
@@ -136,15 +136,23 @@ _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 XRenderPictFormat *
+_CAIRO_FORMAT_XRENDER_FORMAT(Display *dpy, cairo_format_t format)
+{
+ int pict_format;
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ pict_format = PictStandardA1; break;
+ case CAIRO_FORMAT_A8:
+ pict_format = PictStandardA8; break;
+ case CAIRO_FORMAT_RGB24:
+ pict_format = PictStandardRGB24; break;
+ case CAIRO_FORMAT_ARGB32:
+ default:
+ pict_format = PictStandardARGB32; break;
+ }
+ return XRenderFindStandardFormat (dpy, pict_format);
+}
static cairo_surface_t *
_cairo_xlib_surface_create_similar (void *abstract_src,
@@ -158,6 +166,9 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
int scr;
Pixmap pix;
cairo_xlib_surface_t *surface;
+ int depth = _CAIRO_FORMAT_DEPTH (format);
+ XRenderPictFormat *xrender_format = _CAIRO_FORMAT_XRENDER_FORMAT (dpy,
+ format);
/* As a good first approximation, if the display doesn't have COMPOSITE,
* we're better off using image surfaces for all temporary operations
@@ -170,22 +181,20 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
pix = XCreatePixmap (dpy, DefaultRootWindow (dpy),
width <= 0 ? 1 : width, height <= 0 ? 1 : height,
- _CAIRO_FORMAT_DEPTH (format));
+ depth);
surface = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_with_size (dpy, pix, NULL, format,
- DefaultColormap (dpy, scr),
- width, height);
- surface->owns_pixmap = 1;
-
- surface->width = width;
- surface->height = height;
+ cairo_xlib_surface_create_with_xrender_format (dpy, pix,
+ xrender_format,
+ width, height);
+
+ surface->owns_pixmap = TRUE;
return &surface->base;
}
-static void
-_cairo_xlib_surface_destroy (void *abstract_surface)
+static cairo_status_t
+_cairo_xlib_surface_finish (void *abstract_surface)
{
cairo_xlib_surface_t *surface = abstract_surface;
if (surface->picture)
@@ -197,16 +206,56 @@ _cairo_xlib_surface_destroy (void *abstract_surface)
if (surface->gc)
XFreeGC (surface->dpy, surface->gc);
- surface->dpy = 0;
+ surface->dpy = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+}
- free (surface);
+static int
+_noop_error_handler (Display *display,
+ XErrorEvent *event)
+{
+ return False; /* return value is ignored */
}
-static double
-_cairo_xlib_surface_pixels_per_inch (void *abstract_surface)
+static cairo_bool_t
+_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
{
- /* XXX: We should really get this value from somewhere like Xft.dpy */
- return 96.0;
+ switch (masks->bpp) {
+ case 32:
+ if (masks->alpha_mask == 0xff000000 &&
+ masks->red_mask == 0x00ff0000 &&
+ masks->green_mask == 0x0000ff00 &&
+ masks->blue_mask == 0x000000ff)
+ {
+ *format = CAIRO_FORMAT_ARGB32;
+ return True;
+ }
+ if (masks->alpha_mask == 0x00000000 &&
+ masks->red_mask == 0x00ff0000 &&
+ masks->green_mask == 0x0000ff00 &&
+ masks->blue_mask == 0x000000ff)
+ {
+ *format = CAIRO_FORMAT_RGB24;
+ return True;
+ }
+ break;
+ case 8:
+ if (masks->alpha_mask == 0xff)
+ {
+ *format = CAIRO_FORMAT_A8;
+ return True;
+ }
+ break;
+ case 1:
+ if (masks->alpha_mask == 0x1)
+ {
+ *format = CAIRO_FORMAT_A1;
+ return True;
+ }
+ break;
+ }
+ return False;
}
static cairo_status_t
@@ -217,15 +266,9 @@ _get_image_surface (cairo_xlib_surface_t *surface,
{
cairo_image_surface_t *image;
XImage *ximage;
- Window root_ignore;
- int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
int x1, y1, x2, y2;
-
- XGetGeometry (surface->dpy,
- surface->drawable,
- &root_ignore, &x_ignore, &y_ignore,
- &surface->width, &surface->height,
- &bwidth_ignore, &depth_ignore);
+ cairo_format_masks_t masks;
+ cairo_format_t format;
x1 = 0;
y1 = 0;
@@ -233,14 +276,21 @@ _get_image_surface (cairo_xlib_surface_t *surface,
y2 = surface->height;
if (interest_rect) {
- if (interest_rect->x > x1)
- x1 = interest_rect->x;
- if (interest_rect->y > y1)
- y1 = interest_rect->y;
- if (interest_rect->x + interest_rect->width < x2)
- x2 = interest_rect->x + interest_rect->width;
- if (interest_rect->y + interest_rect->height < y2)
- y2 = interest_rect->y + interest_rect->height;
+ cairo_rectangle_t rect;
+
+ rect.x = interest_rect->x;
+ rect.y = interest_rect->y;
+ rect.width = interest_rect->width;
+ rect.height = interest_rect->width;
+
+ if (rect.x > x1)
+ x1 = rect.x;
+ if (rect.y > y1)
+ y1 = rect.y;
+ if (rect.x + rect.width < x2)
+ x2 = rect.x + rect.width;
+ if (rect.y + rect.height < y2)
+ y2 = rect.y + rect.height;
if (x1 >= x2 || y1 >= y2) {
*image_out = NULL;
@@ -255,36 +305,118 @@ _get_image_surface (cairo_xlib_surface_t *surface,
image_rect->height = y2 - y1;
}
- /* XXX: This should try to use the XShm extension if availible */
- ximage = XGetImage (surface->dpy,
- surface->drawable,
- x1, y1,
- x2 - x1, y2 - y1,
- AllPlanes, ZPixmap);
+ /* XXX: This should try to use the XShm extension if available */
- if (surface->visual) {
- cairo_format_masks_t masks;
+ if (surface->use_pixmap == 0)
+ {
+ cairo_xlib_error_func_t old_handler;
- /* XXX: Add support here for pictures with external alpha? */
+ old_handler = XSetErrorHandler (_noop_error_handler);
+
+ ximage = XGetImage (surface->dpy,
+ surface->drawable,
+ x1, y1,
+ x2 - x1, y2 - y1,
+ AllPlanes, ZPixmap);
+ XSetErrorHandler (old_handler);
+
+ /* If we get an error, the surface must have been a window,
+ * so retry with the safe code path.
+ */
+ if (!ximage)
+ surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
+ }
+ else
+ {
+ surface->use_pixmap--;
+ ximage = 0;
+ }
+
+ if (!ximage)
+ {
+
+ /* XGetImage from a window is dangerous because it can
+ * produce errors if the window is unmapped or partially
+ * outside the screen. We could check for errors and
+ * retry, but to keep things simple, we just create a
+ * temporary pixmap
+ */
+ Pixmap pixmap = XCreatePixmap (surface->dpy,
+ surface->drawable,
+ x2 - x1, y2 - y1,
+ surface->depth);
+ _cairo_xlib_surface_ensure_gc (surface);
+
+ XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc,
+ x1, y1, x2 - x1, y2 - y1, 0, 0);
+
+ ximage = XGetImage (surface->dpy,
+ pixmap,
+ 0, 0,
+ x2 - x1, y2 - y1,
+ AllPlanes, ZPixmap);
+
+ XFreePixmap (surface->dpy, pixmap);
+ }
+ if (!ximage)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ /*
+ * Compute the pixel format masks from either a visual or a
+ * XRenderFormat, failing we assume the drawable is an
+ * alpha-only pixmap as it could only have been created
+ * that way through the cairo_xlib_surface_create_for_bitmap
+ * function.
+ */
+ if (surface->visual) {
masks.bpp = ximage->bits_per_pixel;
masks.alpha_mask = 0;
masks.red_mask = surface->visual->red_mask;
masks.green_mask = surface->visual->green_mask;
masks.blue_mask = surface->visual->blue_mask;
+ } else if (surface->format) {
+ masks.bpp = ximage->bits_per_pixel;
+ masks.red_mask = surface->format->direct.redMask << surface->format->direct.red;
+ masks.green_mask = surface->format->direct.greenMask << surface->format->direct.green;
+ masks.blue_mask = surface->format->direct.blueMask << surface->format->direct.blue;
+ masks.alpha_mask = surface->format->direct.alphaMask << surface->format->direct.alpha;
+ } else {
+ masks.bpp = ximage->bits_per_pixel;
+ masks.red_mask = 0;
+ masks.green_mask = 0;
+ masks.blue_mask = 0;
+ if (surface->depth < 32)
+ masks.alpha_mask = (1 << surface->depth) - 1;
+ else
+ masks.alpha_mask = 0xffffffff;
+ }
- image = _cairo_image_surface_create_with_masks (ximage->data,
+ /*
+ * Prefer to use a standard pixman format instead of the
+ * general masks case.
+ */
+ if (_CAIRO_MASK_FORMAT (&masks, &format))
+ {
+ image = (cairo_image_surface_t *) cairo_image_surface_create_for_data ((unsigned char *) ximage->data,
+ format,
+ ximage->width,
+ ximage->height,
+ ximage->bytes_per_line);
+ }
+ else
+ {
+ /*
+ * XXX This can't work. We must convert the data to one of the
+ * supported pixman formats. Pixman needs another function
+ * which takes data in an arbitrary format and converts it
+ * to something supported by that library.
+ */
+ image = _cairo_image_surface_create_with_masks ((unsigned char *) ximage->data,
&masks,
ximage->width,
ximage->height,
ximage->bytes_per_line);
- } else {
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (ximage->data,
- surface->format,
- ximage->width,
- ximage->height,
- ximage->bytes_per_line);
}
/* Let the surface take ownership of the data */
@@ -303,10 +435,14 @@ _get_image_surface (cairo_xlib_surface_t *surface,
static void
_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
{
+ XGCValues gcv;
+
if (surface->gc)
return;
- surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
+ gcv.graphics_exposures = False;
+ surface->gc = XCreateGC (surface->dpy, surface->drawable,
+ GCGraphicsExposures, &gcv);
}
static cairo_status_t
@@ -318,6 +454,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
XImage *ximage;
unsigned bitmap_pad;
+ /* XXX this is wrong */
if (image->depth > 16)
bitmap_pad = 32;
else if (image->depth > 8)
@@ -330,7 +467,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
image->depth,
ZPixmap,
0,
- image->data,
+ (char *) image->data,
image->width,
image->height,
bitmap_pad,
@@ -362,13 +499,8 @@ _cairo_xlib_surface_acquire_source_image (void *abstract_surf
cairo_status_t status;
status = _get_image_surface (surface, NULL, &image, NULL);
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_set_filter (&image->base, surface->base.filter);
- cairo_surface_set_matrix (&image->base, &surface->base.matrix);
- cairo_surface_set_repeat (&image->base, surface->base.repeat);
-
+ if (status == CAIRO_STATUS_SUCCESS)
*image_out = image;
- }
return status;
}
@@ -459,13 +591,13 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
- xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
+ xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
+ xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy);
+ xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0);
- xtransform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- xtransform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- xtransform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
+ xtransform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx);
+ xtransform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy);
+ xtransform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0);
xtransform.matrix[2][0] = 0;
xtransform.matrix[2][1] = 0;
@@ -585,26 +717,29 @@ _render_operator (cairo_operator_t operator)
switch (operator) {
case CAIRO_OPERATOR_CLEAR:
return PictOpClear;
- case CAIRO_OPERATOR_SRC:
+
+ case CAIRO_OPERATOR_SOURCE:
return PictOpSrc;
- case CAIRO_OPERATOR_DST:
- return PictOpDst;
case CAIRO_OPERATOR_OVER:
return PictOpOver;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return PictOpOverReverse;
case CAIRO_OPERATOR_IN:
return PictOpIn;
- case CAIRO_OPERATOR_IN_REVERSE:
- return PictOpInReverse;
case CAIRO_OPERATOR_OUT:
return PictOpOut;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return PictOpOutReverse;
case CAIRO_OPERATOR_ATOP:
return PictOpAtop;
- case CAIRO_OPERATOR_ATOP_REVERSE:
+
+ case CAIRO_OPERATOR_DEST:
+ return PictOpDst;
+ case CAIRO_OPERATOR_DEST_OVER:
+ return PictOpOverReverse;
+ case CAIRO_OPERATOR_DEST_IN:
+ return PictOpInReverse;
+ case CAIRO_OPERATOR_DEST_OUT:
+ return PictOpOutReverse;
+ case CAIRO_OPERATOR_DEST_ATOP:
return PictOpAtopReverse;
+
case CAIRO_OPERATOR_XOR:
return PictOpXor;
case CAIRO_OPERATOR_ADD:
@@ -651,10 +786,8 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
return status;
status = _cairo_xlib_surface_set_attributes (src, &src_attr);
- if (CAIRO_OK (status))
- {
- if (mask)
- {
+ if (CAIRO_OK (status)) {
+ if (mask) {
status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
if (CAIRO_OK (status))
XRenderComposite (dst->dpy,
@@ -668,9 +801,7 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
mask_y + mask_attr.y_offset,
dst_x, dst_y,
width, height);
- }
- else
- {
+ } else {
XRenderComposite (dst->dpy,
_render_operator (operator),
src->picture,
@@ -777,83 +908,75 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
}
static cairo_int_status_t
-_cairo_xlib_surface_copy_page (void *abstract_surface)
+_cairo_xlib_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
+ cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
-static cairo_int_status_t
-_cairo_xlib_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (region == NULL) {
+ if (surface->gc)
+ XSetClipMask (surface->dpy, surface->gc, None);
+
+ if (surface->picture) {
+ XRenderPictureAttributes pa;
+ pa.clip_mask = None;
+ XRenderChangePicture (surface->dpy, surface->picture,
+ CPClipMask, &pa);
+ }
+ } else {
+ pixman_box16_t *boxes;
+ XRectangle *rects = NULL;
+ int n_boxes, i;
+
+ n_boxes = pixman_region_num_rects (region);
+ if (n_boxes > 0) {
+ rects = malloc (sizeof(XRectangle) * n_boxes);
+ if (rects == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+ } else {
+ rects = NULL;
+ }
+
+ boxes = pixman_region_rects (region);
+
+ for (i = 0; i < n_boxes; i++) {
+ rects[i].x = boxes[i].x1;
+ rects[i].y = boxes[i].y1;
+ rects[i].width = boxes[i].x2 - boxes[i].x1;
+ rects[i].height = boxes[i].y2 - boxes[i].y1;
+ }
+
+ if (surface->gc)
+ XSetClipRectangles(surface->dpy, surface->gc,
+ 0, 0, rects, n_boxes, YXSorted);
+ if (surface->picture)
+ XRenderSetPictureClipRectangles (surface->dpy, surface->picture,
+ 0, 0, rects, n_boxes);
+
+ if (rects)
+ free (rects);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
-_cairo_xlib_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
+_cairo_xlib_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
{
+ cairo_xlib_surface_t *surface = abstract_surface;
- Region xregion;
- XRectangle xr;
- XRectangle *rects = NULL;
- XGCValues gc_values;
- pixman_box16_t *box;
- cairo_xlib_surface_t *surf;
- int n, m;
-
- surf = (cairo_xlib_surface_t *) abstract_surface;
+ rectangle->x = 0;
+ rectangle->y = 0;
- if (region == NULL) {
- /* NULL region == reset the clip */
- xregion = XCreateRegion();
- xr.x = 0;
- xr.y = 0;
- xr.width = surf->width;
- xr.height = surf->height;
- XUnionRectWithRegion (&xr, xregion, xregion);
- rects = malloc(sizeof(XRectangle));
- if (rects == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- rects[0] = xr;
- m = 1;
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
- } else {
- n = pixman_region_num_rects (region);
- /* XXX: Are we sure these are the semantics we want for an
- * empty, (not null) region? */
- if (n == 0)
- return CAIRO_STATUS_SUCCESS;
- rects = malloc(sizeof(XRectangle) * n);
- if (rects == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- box = pixman_region_rects (region);
- xregion = XCreateRegion();
-
- m = n;
- for (; n > 0; --n, ++box) {
- xr.x = (short) box->x1;
- xr.y = (short) box->y1;
- xr.width = (unsigned short) (box->x2 - box->x1);
- xr.height = (unsigned short) (box->y2 - box->y1);
- rects[n-1] = xr;
- XUnionRectWithRegion (&xr, xregion, xregion);
- }
- }
-
- _cairo_xlib_surface_ensure_gc (surf);
- XGetGCValues(surf->dpy, surf->gc, GCGraphicsExposures, &gc_values);
- XSetGraphicsExposures(surf->dpy, surf->gc, False);
- XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
- free(rects);
- if (surf->picture)
- XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
- XDestroyRegion(xregion);
- XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_font_t *font,
+static cairo_int_status_t
+_cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
cairo_pattern_t *pattern,
void *abstract_surface,
@@ -868,8 +991,7 @@ _cairo_xlib_surface_show_glyphs (cairo_font_t *font,
static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_create_similar,
- _cairo_xlib_surface_destroy,
- _cairo_xlib_surface_pixels_per_inch,
+ _cairo_xlib_surface_finish,
_cairo_xlib_surface_acquire_source_image,
_cairo_xlib_surface_release_source_image,
_cairo_xlib_surface_acquire_dest_image,
@@ -878,23 +1000,37 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_composite,
_cairo_xlib_surface_fill_rectangles,
_cairo_xlib_surface_composite_trapezoids,
- _cairo_xlib_surface_copy_page,
- _cairo_xlib_surface_show_page,
+ NULL, /* copy_page */
+ NULL, /* show_page */
_cairo_xlib_surface_set_clip_region,
+ _cairo_xlib_surface_get_extents,
_cairo_xlib_surface_show_glyphs
};
+/**
+ * _cairo_surface_is_xlib:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is a #cairo_xlib_surface_t
+ *
+ * Return value: True if the surface is an xlib surface
+ **/
+static cairo_bool_t
+_cairo_surface_is_xlib (cairo_surface_t *surface)
+{
+ return surface->backend == &cairo_xlib_surface_backend;
+}
+
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_create_internal (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ XRenderPictFormat *format,
+ int width,
+ int height,
+ int depth)
{
cairo_xlib_surface_t *surface;
- int render_standard;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@@ -902,76 +1038,180 @@ _cairo_xlib_surface_create_with_size (Display *dpy,
_cairo_surface_init (&surface->base, &cairo_xlib_surface_backend);
- surface->visual = visual;
- surface->format = format;
-
surface->dpy = dpy;
- surface->gc = 0;
+ surface->gc = NULL;
surface->drawable = drawable;
- surface->owns_pixmap = 0;
+ surface->owns_pixmap = FALSE;
surface->visual = visual;
+ surface->format = format;
+ surface->use_pixmap = 0;
surface->width = width;
surface->height = height;
+ surface->depth = depth;
- if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
+ if (format) {
+ surface->depth = format->depth;
+ } else if (visual) {
+ int i, j, k;
+
+ /* This is ugly, but we have to walk over all visuals
+ * for the display to find the depth.
+ */
+ for (i = 0; i < ScreenCount (dpy); i++) {
+ Screen *screen = ScreenOfDisplay (dpy, i);
+ for (j = 0; j < screen->ndepths; j++) {
+ Depth *depth = &screen->depths[j];
+ for (k = 0; k < depth->nvisuals; k++) {
+ if (&depth->visuals[k] == visual) {
+ surface->depth = depth->depth;
+ goto found;
+ }
+ }
+ }
+ }
+ found:
+ ;
+ }
+
+ if (cairo_xlib_render_disabled ||
+ ! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
surface->render_major = -1;
surface->render_minor = -1;
}
- switch (format) {
- case CAIRO_FORMAT_A1:
- render_standard = PictStandardA1;
- break;
- case CAIRO_FORMAT_A8:
- render_standard = PictStandardA8;
- break;
- case CAIRO_FORMAT_RGB24:
- render_standard = PictStandardRGB24;
- break;
- case CAIRO_FORMAT_ARGB32:
- default:
- render_standard = PictStandardARGB32;
- break;
- }
+ surface->picture = None;
- /* XXX: I'm currently ignoring the colormap. Is that bad? */
- if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
- surface->picture = XRenderCreatePicture (dpy, drawable,
- visual ?
- XRenderFindVisualFormat (dpy, visual) :
- XRenderFindStandardFormat (dpy, render_standard),
- 0, NULL);
- else
- surface->picture = 0;
+ if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
+
+ if (!format) {
+ if (visual) {
+ format = XRenderFindVisualFormat (dpy, visual);
+ } else if (depth == 1)
+ format = XRenderFindStandardFormat (dpy, PictStandardA1);
+ }
+
+ if (format)
+ surface->picture = XRenderCreatePicture (dpy, drawable,
+ format, 0, NULL);
+ }
return (cairo_surface_t *) surface;
}
+/**
+ * cairo_xlib_surface_create:
+ * @dpy: an X Display
+ * @drawable: an X Drawable, (a Pixmap or a Window)
+ * @visual: the visual to use for drawing to @drawable. The depth
+ * of the visual must match the depth of the drawable.
+ * Currently, only TrueColor visuals are fully supported.
+ * @width: the current width of @drawable.
+ * @height: the current height of @drawable.
+ *
+ * Creates an Xlib surface that draws to the given drawable.
+ * The way that colors are represented in the drawable is specified
+ * by the provided visual.
+ *
+ * NOTE: If @drawable is a Window, then the function
+ * cairo_xlib_surface_set_size must be called whenever the size of the
+ * window changes.
+ *
+ * Return value: the newly created surface
+ **/
cairo_surface_t *
-cairo_xlib_surface_create (Display *dpy,
- Drawable drawable,
- Visual *visual,
- cairo_format_t format,
- Colormap colormap)
+cairo_xlib_surface_create (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ int width,
+ int height)
{
- Window window_ignore;
- unsigned int int_ignore;
- unsigned int width, height;
+ return _cairo_xlib_surface_create_internal (dpy, drawable,
+ visual, NULL, width, height, 0);
+}
- /* 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);
+/**
+ * cairo_xlib_surface_create_for_bitmap:
+ * @dpy: an X Display
+ * @bitmap: an X Drawable, (a depth-1 Pixmap)
+ * @width: the current width of @bitmap.
+ * @height: the current height of @bitmap.
+ *
+ * Creates an Xlib surface that draws to the given bitmap.
+ * This will be drawn to as a CAIRO_FORMAT_A1 object.
+ *
+ * Return value: the newly created surface
+ **/
+cairo_surface_t *
+cairo_xlib_surface_create_for_bitmap (Display *dpy,
+ Pixmap bitmap,
+ int width,
+ int height)
+{
+ return _cairo_xlib_surface_create_internal (dpy, bitmap,
+ NULL, NULL, width, height, 1);
+}
+
+/**
+ * cairo_xlib_surface_create_with_xrender_format:
+ * @dpy: an X Display
+ * @drawable: an X Drawable, (a Pixmap or a Window)
+ * @format: the picture format to use for drawing to @drawable. The depth
+ * of @format must match the depth of the drawable.
+ * @width: the current width of @drawable.
+ * @height: the current height of @drawable.
+ *
+ * Creates an Xlib surface that draws to the given drawable.
+ * The way that colors are represented in the drawable is specified
+ * by the provided picture format.
+ *
+ * NOTE: If @drawable is a Window, then the function
+ * cairo_xlib_surface_set_size must be called whenever the size of the
+ * window changes.
+ *
+ * Return value: the newly created surface
+ **/
+cairo_surface_t *
+cairo_xlib_surface_create_with_xrender_format (Display *dpy,
+ Drawable drawable,
+ XRenderPictFormat *format,
+ int width,
+ int height)
+{
+ return _cairo_xlib_surface_create_internal (dpy, drawable,
+ NULL, format, width, height, 0);
+}
- return _cairo_xlib_surface_create_with_size (dpy, drawable, visual, format,
- colormap, width, height);
+/**
+ * cairo_xlib_surface_set_size:
+ * @surface: a #cairo_surface_t for the XLib backend
+ * @width: the new width of the surface
+ * @height: the new height of the surface
+ *
+ * Informs cairo of the new size of the X Drawable underlying the
+ * surface. For a surface created for a Window (rather than a Pixmap),
+ * this function must be called each time the size of the window
+ * changes. (For a subwindow, you are normally resizing the window
+ * yourself, but for a toplevel window, it is necessary to listen for
+ * ConfigureNotify events.)
+ *
+ * A Pixmap can never change size, so it is never necessary to call
+ * this function on a surface created for a Pixmap.
+ **/
+void
+cairo_xlib_surface_set_size (cairo_surface_t *surface,
+ int width,
+ int height)
+{
+ cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *)surface;
+
+ /* XXX: How do we want to handle this error case? */
+ if (! _cairo_surface_is_xlib (surface))
+ return;
+
+ xlib_surface->width = width;
+ xlib_surface->height = height;
}
-DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
/* RENDER glyphset cache code */
@@ -1079,7 +1319,7 @@ _xlib_glyphset_cache_create_entry (void *cache,
XRenderAddGlyphs (g->display, g->glyphset,
&(v->glyph), &(v->info), 1,
- im->image ? im->image->data : NULL,
+ im->image ? (char *) im->image->data : NULL,
im->image ? v->info.height * v->info.width : 0);
v->key.base.memory = im->image ? im->image->width * im->image->stride : 0;
@@ -1186,7 +1426,7 @@ _get_glyphset_cache (Display *d)
#define N_STACK_BUF 1024
static cairo_status_t
-_cairo_xlib_surface_show_glyphs32 (cairo_font_t *font,
+_cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
@@ -1263,7 +1503,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_font_t *font,
static cairo_status_t
-_cairo_xlib_surface_show_glyphs16 (cairo_font_t *font,
+_cairo_xlib_surface_show_glyphs16 (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
@@ -1339,7 +1579,7 @@ _cairo_xlib_surface_show_glyphs16 (cairo_font_t *font,
}
static cairo_status_t
-_cairo_xlib_surface_show_glyphs8 (cairo_font_t *font,
+_cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
glyphset_cache_t *g,
cairo_glyph_cache_key_t *key,
@@ -1415,8 +1655,8 @@ _cairo_xlib_surface_show_glyphs8 (cairo_font_t *font,
}
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_font_t *font,
+static cairo_int_status_t
+_cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_operator_t operator,
cairo_pattern_t *pattern,
void *abstract_surface,
@@ -1471,7 +1711,7 @@ _cairo_xlib_surface_show_glyphs (cairo_font_t *font,
/* Work out the index size to use. */
elt_size = 8;
- _cairo_font_get_glyph_cache_key (font, &key);
+ _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key);
for (i = 0; i < num_glyphs; ++i) {
key.index = glyphs[i].index;
@@ -1499,17 +1739,17 @@ _cairo_xlib_surface_show_glyphs (cairo_font_t *font,
/* Call the appropriate sub-function. */
if (elt_size == 8)
- status = _cairo_xlib_surface_show_glyphs8 (font, operator, g, &key, src, self,
+ status = _cairo_xlib_surface_show_glyphs8 (scaled_font, operator, g, &key, src, self,
source_x + attributes.x_offset,
source_y + attributes.y_offset,
glyphs, entries, num_glyphs);
else if (elt_size == 16)
- status = _cairo_xlib_surface_show_glyphs16 (font, operator, g, &key, src, self,
+ status = _cairo_xlib_surface_show_glyphs16 (scaled_font, operator, g, &key, src, self,
source_x + attributes.x_offset,
source_y + attributes.y_offset,
glyphs, entries, num_glyphs);
else
- status = _cairo_xlib_surface_show_glyphs32 (font, operator, g, &key, src, self,
+ status = _cairo_xlib_surface_show_glyphs32 (scaled_font, operator, g, &key, src, self,
source_x + attributes.x_offset,
source_y + attributes.y_offset,
glyphs, entries, num_glyphs);
diff --git a/src/cairo-png.h b/src/cairo-xlib-test.h
index 3e86210b0..44b986c7f 100644
--- a/src/cairo-png.h
+++ b/src/cairo-xlib-test.h
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -34,31 +34,22 @@
* Carl D. Worth <cworth@cworth.org>
*/
-#ifndef CAIRO_PNG_H
-#define CAIRO_PNG_H
+#ifndef CAIRO_XLIB_TEST_H
+#define CAIRO_XLIB_TEST_H
#include <cairo.h>
-#ifdef CAIRO_HAS_PNG_SURFACE
+#if CAIRO_HAS_XLIB_SURFACE
-#include <stdio.h>
+#include <cairo-xlib.h>
CAIRO_BEGIN_DECLS
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);
+cairo_test_xlib_disable_render (void);
CAIRO_END_DECLS
-#endif /* CAIRO_HAS_PNG_SURFACE */
-#endif /* CAIRO_PNG_H */
+#endif /* CAIRO_HAS_XLIB_SURFACE */
+#endif /* CAIRO_XLIB_H */
+
diff --git a/src/cairo_color.c b/src/cairo-xlib-xrender.h
index f203d96cc..08a8624e2 100644
--- a/src/cairo_color.c
+++ b/src/cairo-xlib-xrender.h
@@ -34,64 +34,29 @@
* Carl D. Worth <cworth@cworth.org>
*/
-#include "cairoint.h"
+#ifndef CAIRO_XLIB_XRENDER_H
+#define CAIRO_XLIB_XRENDER_H
-static cairo_color_t const CAIRO_COLOR_WHITE = {
- 1.0, 1.0, 1.0, 1.0,
- 0xffff, 0xffff, 0xffff, 0xffff
-};
+#include <cairo.h>
-static void
-_cairo_color_compute_shorts (cairo_color_t *color);
+#if CAIRO_HAS_XLIB_SURFACE
-void
-_cairo_color_init (cairo_color_t *color)
-{
- *color = CAIRO_COLOR_WHITE;
-}
+#include <X11/extensions/Xrender.h>
-void
-_cairo_color_fini (cairo_color_t *color)
-{
- /* Nothing to do here */
-}
+CAIRO_BEGIN_DECLS
-void
-_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue)
-{
- color->red = red;
- color->green = green;
- color->blue = blue;
+cairo_surface_t *
+cairo_xlib_surface_create_with_xrender_format (Display *dpy,
+ Drawable drawable,
+ XRenderPictFormat *format,
+ int width,
+ int height);
- _cairo_color_compute_shorts (color);
-}
-void
-_cairo_color_get_rgb (const cairo_color_t *color,
- double *red, double *green, double *blue)
-{
- if (red)
- *red = color->red;
- if (green)
- *green = color->green;
- if (blue)
- *blue = color->blue;
-}
+CAIRO_END_DECLS
-void
-_cairo_color_set_alpha (cairo_color_t *color, double alpha)
-{
- color->alpha = alpha;
-
- _cairo_color_compute_shorts (color);
-}
-
-static void
-_cairo_color_compute_shorts (cairo_color_t *color)
-{
- color->red_short = (color->red * color->alpha) * 0xffff;
- color->green_short = (color->green * color->alpha) * 0xffff;
- color->blue_short = (color->blue * color->alpha) * 0xffff;
- color->alpha_short = color->alpha * 0xffff;
-}
+#else /* CAIRO_HAS_XLIB_SURFACE */
+# error Cairo was not compiled with support for the xlib backend
+#endif /* CAIRO_HAS_XLIB_SURFACE */
+#endif /* CAIRO_XLIB_XRENDER_H */
diff --git a/src/cairo-xlib.h b/src/cairo-xlib.h
index 18db7b114..3fe285fdb 100644
--- a/src/cairo-xlib.h
+++ b/src/cairo-xlib.h
@@ -39,38 +39,35 @@
#include <cairo.h>
-#ifdef CAIRO_HAS_XLIB_SURFACE
+#if CAIRO_HAS_XLIB_SURFACE
-#include <X11/extensions/Xrender.h>
+#include <X11/Xlib.h>
CAIRO_BEGIN_DECLS
-/* 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);
+cairo_surface_t *
+cairo_xlib_surface_create (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ int width,
+ int height);
-/* 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);
-*/
+cairo_xlib_surface_create_for_bitmap (Display *dpy,
+ Pixmap bitmap,
+ int width,
+ int height);
+
+void
+cairo_xlib_surface_set_size (cairo_surface_t *surface,
+ int width,
+ int height);
CAIRO_END_DECLS
+#else /* CAIRO_HAS_XLIB_SURFACE */
+# error Cairo was not compiled with support for the xlib backend
#endif /* CAIRO_HAS_XLIB_SURFACE */
+
#endif /* CAIRO_XLIB_H */
diff --git a/src/cairo.c b/src/cairo.c
index fd10b5cac..f825c733e 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -34,13 +35,18 @@
* Carl D. Worth <cworth@cworth.org>
*/
-
#include "cairoint.h"
+#include "cairo-private.h"
+
+#include "cairo-arc-private.h"
+#include "cairo-path-data-private.h"
#define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */
-#ifdef CAIRO_DO_SANITY_CHECKING
#include <assert.h>
+#ifdef NDEBUG
+#define CAIRO_CHECK_SANITY(cr)
+#else
static int
cairo_sane_state (cairo_t *cr)
{
@@ -56,6 +62,8 @@ cairo_sane_state (cairo_t *cr)
case CAIRO_STATUS_INVALID_MATRIX:
case CAIRO_STATUS_NO_TARGET_SURFACE:
case CAIRO_STATUS_NULL_POINTER:
+ case CAIRO_STATUS_INVALID_STRING:
+ case CAIRO_STATUS_INVALID_PATH_DATA:
break;
default:
return 0;
@@ -63,25 +71,38 @@ cairo_sane_state (cairo_t *cr)
return 1;
}
#define CAIRO_CHECK_SANITY(cr) assert(cairo_sane_state ((cr)))
-#else
-#define CAIRO_CHECK_SANITY(cr)
#endif
-
-/**
+/*
* cairo_create:
+ * @target: target surface for the context
*
- * Creates a new #cairo_t with default values. The target
- * surface must be set on the #cairo_t with cairo_set_target_surface(),
- * or a backend-specific function like cairo_set_target_image() before
- * drawing with the #cairo_t.
+ * Creates a new #cairo_t with all graphics state parameters set to
+ * default values and with @target as a target surface. The target
+ * surface should be constructed with a backend-specific function such
+ * as cairo_image_surface_create (or any other
+ * cairo_<backend>_surface_create variant).
+ *
+ * This function references @target, so you can immediately
+ * call cairo_surface_destroy() on it if you don't need to
+ * maintain a separate reference to it.
+ *
+ * Note that there are restrictions on using the same surface in
+ * multiple contexts at the same time. If, after creating @cr_a with
+ * @surface you also create @cr_b with the same surface, you must
+ * ensure that @cr_b has finished using @surface before resuming use
+ * of @cr_a. Currently, the only way time at which this is guaranteed
+ * is when the the last reference to @cr_b is released with
+ * cairo_destroy(). (XXX: We need to add a cairo_finish() call to
+ * provide a way to achieve this explicitly). See also the
+ * %CAIRO_STATUS_BAD_NESTING status.
*
* Return value: a newly allocated #cairo_t with a reference
* count of 1. The initial reference count should be released
* with cairo_destroy() when you are done using the #cairo_t.
- **/
+ */
cairo_t *
-cairo_create (void)
+cairo_create (cairo_surface_t *target)
{
cairo_t *cr;
@@ -92,7 +113,15 @@ cairo_create (void)
cr->status = CAIRO_STATUS_SUCCESS;
cr->ref_count = 1;
- cr->gstate = _cairo_gstate_create ();
+ _cairo_path_fixed_init (&cr->path);
+
+ if (target == NULL) {
+ cr->gstate = NULL;
+ cr->status = CAIRO_STATUS_NULL_POINTER;
+ return cr;
+ }
+
+ cr->gstate = _cairo_gstate_create (target);
if (cr->gstate == NULL)
cr->status = CAIRO_STATUS_NO_MEMORY;
@@ -125,7 +154,7 @@ cairo_reference (cairo_t *cr)
*
* Decreases the reference count on @cr by one. If the result
* is zero, then @cr and all associated resources are freed.
- * See cairo_destroy().
+ * See cairo_reference().
**/
void
cairo_destroy (cairo_t *cr)
@@ -142,6 +171,8 @@ cairo_destroy (cairo_t *cr)
_cairo_gstate_destroy (tmp);
}
+ _cairo_path_fixed_fini (&cr->path);
+
free (cr);
}
@@ -170,11 +201,7 @@ cairo_save (cairo_t *cr)
if (cr->status)
return;
- if (cr->gstate) {
- top = _cairo_gstate_clone (cr->gstate);
- } else {
- top = _cairo_gstate_create ();
- }
+ top = _cairo_gstate_clone (cr->gstate);
if (top == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
@@ -216,44 +243,10 @@ cairo_restore (cairo_t *cr)
if (cr->status)
return;
- cr->status = _cairo_gstate_restore_external_state (cr->gstate);
-
CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_restore);
-/**
- * cairo_copy:
- * @dest: a #cairo_t
- * @src: another #cairo_t
- *
- * This function copies all current state information from src to
- * dest. This includes the current point and path, the target surface,
- * the transformation matrix, and so forth.
- *
- * The stack of states saved with cairo_save() is <emphasis>not</emphasis>
- * not copied; nor are any saved states on @dest cleared. The
- * operation only copies the current state of @src to the current
- * state of @dest.
- **/
-void
-cairo_copy (cairo_t *dest, cairo_t *src)
-{
- CAIRO_CHECK_SANITY (src);
- CAIRO_CHECK_SANITY (dest);
- if (dest->status)
- return;
-
- if (src->status) {
- dest->status = src->status;
- return;
- }
-
- dest->status = _cairo_gstate_copy (dest->gstate, src->gstate);
- CAIRO_CHECK_SANITY (src);
- CAIRO_CHECK_SANITY (dest);
-}
-
/* XXX: I want to rethink this API
void
cairo_push_group (cairo_t *cr)
@@ -283,130 +276,176 @@ cairo_pop_group (cairo_t *cr)
*/
/**
- * cairo_set_target_surface:
+ * cairo_set_operator:
* @cr: a #cairo_t
- * @surface: a #cairo_surface_t
+ * @op: a compositing operator, specified as a #cairo_operator_t
*
- * Directs output for a #cairo_t to a given surface. The surface
- * will be referenced by the #cairo_t, so you can immediately
- * call cairo_surface_destroy() on it if you don't need to
- * keep a reference to it around.
+ * Sets the compositing operator to be used for all drawing
+ * operations. See #cairo_operator_t for details on the semantics of
+ * each available drawing operator.
+ *
+ * XXX: I'd also like to direct the reader's attention to some
+ * (not-yet-written) section on cairo's imaging model. How would I do
+ * that if such a section existed? (cworth).
**/
void
-cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface)
+cairo_set_operator (cairo_t *cr, cairo_operator_t op)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_set_target_surface (cr->gstate, surface);
+ cr->status = _cairo_gstate_set_operator (cr->gstate, op);
CAIRO_CHECK_SANITY (cr);
}
-slim_hidden_def(cairo_set_target_surface);
/**
- * cairo_set_target_image:
- * @cr: a #cairo_t
- * @data: a pointer to a buffer supplied by the application
- * in which to write contents.
- * @format: the format of pixels in the buffer
- * @width: the width of the image to be stored in the buffer
- * @height: the eight of the image to be stored in the buffer
- * @stride: the number of bytes between the start of rows
- * in the buffer. Having this be specified separate from @width
- * allows for padding at the end of rows, or for writing
- * to a subportion of a larger image.
- *
- * Directs output for a #cairo_t to an in-memory image. The output
- * buffer must be kept around until the #cairo_t is destroyed or set
- * to to have a different target. The initial contents of @buffer
- * will be used as the inital image contents; you must explicitely
- * clear the buffer, using, for example, cairo_rectangle() and
- * cairo_fill() if you want it cleared.
+ * cairo_set_source_rgb
+ * @cr: a cairo context
+ * @red: red component of color
+ * @green: green component of color
+ * @blue: blue component of color
+ *
+ * Sets the source pattern within @cr to an opaque color. This opaque
+ * color will then be used for any subsequent drawing operation until
+ * a new source pattern is set.
+ *
+ * The color components are floating point numbers in the range 0 to
+ * 1. If the values passed in are outside that range, they will be
+ * clamped.
**/
void
-cairo_set_target_image (cairo_t *cr,
- char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride)
+cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue)
{
- cairo_surface_t *surface;
+ cairo_color_t color;
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- surface = cairo_surface_create_for_image (data,
- format,
- width, height, stride);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- CAIRO_CHECK_SANITY (cr);
- return;
- }
+ _cairo_restrict_value (&red, 0.0, 1.0);
+ _cairo_restrict_value (&green, 0.0, 1.0);
+ _cairo_restrict_value (&blue, 0.0, 1.0);
- cairo_set_target_surface (cr, surface);
+ _cairo_color_init_rgb (&color, red, green, blue);
- cairo_surface_destroy (surface);
+ cr->status = _cairo_gstate_set_source_solid (cr->gstate, &color);
+
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_source_rgba:
+ * @cr: a cairo context
+ * @red: red component of color
+ * @green: green component of color
+ * @blue: blue component of color
+ * @alpha: alpha component of color
+ *
+ * Sets the source pattern within @cr to a translucent color. This
+ * color will then be used for any subsequent drawing operation until
+ * a new source pattern is set.
+ *
+ * The color and alpha components are floating point numbers in the
+ * range 0 to 1. If the values passed in are outside that range, they
+ * will be clamped.
+ **/
void
-cairo_set_operator (cairo_t *cr, cairo_operator_t op)
+cairo_set_source_rgba (cairo_t *cr,
+ double red, double green, double blue,
+ double alpha)
{
+ cairo_color_t color;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_set_operator (cr->gstate, op);
+ _cairo_restrict_value (&red, 0.0, 1.0);
+ _cairo_restrict_value (&green, 0.0, 1.0);
+ _cairo_restrict_value (&blue, 0.0, 1.0);
+ _cairo_restrict_value (&alpha, 0.0, 1.0);
+
+ _cairo_color_init_rgba (&color, red, green, blue, alpha);
+
+ cr->status = _cairo_gstate_set_source_solid (cr->gstate, &color);
+
CAIRO_CHECK_SANITY (cr);
}
-/**
- * cairo_set_rgb_color:
- * @cr: a #cairo_t
- * @red: red component of color
- * @green: green component of color
- * @blue: blue component of color
- *
- * Sets a constant color for filling and stroking. This replaces any
- * pattern set with cairo_set_pattern(). The color components are
- * floating point numbers in the range 0 to 1. If the values passed in
- * are outside that range, they will be clamped.
- **/
void
-cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue)
+cairo_set_source_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double x,
+ double y)
{
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- _cairo_restrict_value (&red, 0.0, 1.0);
- _cairo_restrict_value (&green, 0.0, 1.0);
- _cairo_restrict_value (&blue, 0.0, 1.0);
+ pattern = cairo_pattern_create_for_surface (surface);
+ if (!pattern) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_matrix_init_translate (&matrix, -x, -y);
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
- cr->status = _cairo_gstate_set_rgb_color (cr->gstate, red, green, blue);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_source
+ * @cr: a cairo context
+ * @source: a #cairo_pattern_t to be used as the source for
+ * subsequent drawing operations.
+ *
+ * Sets the source pattern within @cr to @source. This pattern
+ * will then be used for any subsequent drawing operation until a new
+ * source pattern is set.
+ *
+ * XXX: I'd also like to direct the reader's attention to some
+ * (not-yet-written) section on cairo's imaging model. How would I do
+ * that if such a section existed? (cworth).
+ **/
void
-cairo_set_pattern (cairo_t *cr, cairo_pattern_t *pattern)
+cairo_set_source (cairo_t *cr, cairo_pattern_t *source)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_set_pattern (cr->gstate, pattern);
+ cr->status = _cairo_gstate_set_source (cr->gstate, source);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_get_source:
+ * @cr: a cairo context
+ *
+ * Gets the current source pattern for @cr.
+ *
+ * Return value: the current source pattern. This object is owned by
+ * cairo. To keep a reference to it, you must call
+ * cairo_pattern_reference().
+ **/
cairo_pattern_t *
-cairo_current_pattern (cairo_t *cr)
+cairo_get_source (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_pattern (cr->gstate);
+ /* XXX: We'll want to do something like this:
+ if (cr->status)
+ return cairo_pattern_nil;
+ */
+
+ return _cairo_gstate_get_source (cr->gstate);
}
/**
@@ -436,30 +475,17 @@ cairo_set_tolerance (cairo_t *cr, double tolerance)
}
/**
- * cairo_set_alpha:
+ * cairo_set_fill_rule:
* @cr: a #cairo_t
- * @alpha: the alpha value. 0 is transparent, 1 fully opaque.
- * if the value is outside the range 0 to 1, it will be
- * clamped to that range.
- *
- * Sets an overall alpha value used for stroking and filling. This
- * value is multiplied with any alpha value coming from a gradient or
- * image pattern.
+ * @fill_rule: a fill rule, specified as a #cairo_fill_rule_t
+ *
+ * Set the current fill rule within the cairo context. The fill rule
+ * is used to determine which regions are inside or outside a complex
+ * (potentially self-intersecting) path. The current fill rule affects
+ * both cairo_fill and cairo_clip. See #cairo_fill_rule_t for details
+ * on the semantics of each available fill rule.
**/
void
-cairo_set_alpha (cairo_t *cr, double alpha)
-{
- CAIRO_CHECK_SANITY (cr);
- if (cr->status)
- return;
-
- _cairo_restrict_value (&alpha, 0.0, 1.0);
-
- cr->status = _cairo_gstate_set_alpha (cr->gstate, alpha);
- CAIRO_CHECK_SANITY (cr);
-}
-
-void
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
{
CAIRO_CHECK_SANITY (cr);
@@ -470,6 +496,20 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_line_width:
+ * @cr: a #cairo_t
+ * @width: a line width, as a user-space value
+ *
+ * Sets the current line width within the cairo context. The line
+ * width specifies the diameter of a pen that is circular in
+ * user-space.
+ *
+ * As with the other stroke parameters, the current line cap style is
+ * examined by cairo_stroke(), cairo_stroke_extents(), and
+ * cairo_stroke_to_path(), but does not have any effect during path
+ * construction.
+ **/
void
cairo_set_line_width (cairo_t *cr, double width)
{
@@ -483,6 +523,20 @@ cairo_set_line_width (cairo_t *cr, double width)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_line_cap:
+ * @cr: a cairo context, as a #cairo_t
+ * @line_cap: a line cap style, as a #cairo_line_cap_t
+ *
+ * Sets the current line cap style within the cairo context. See
+ * #cairo_line_cap_t for details about how the available line cap
+ * styles are drawn.
+ *
+ * As with the other stroke parameters, the current line cap style is
+ * examined by cairo_stroke(), cairo_stroke_extents(), and
+ * cairo_stroke_to_path(), but does not have any effect during path
+ * construction.
+ **/
void
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
{
@@ -494,6 +548,20 @@ cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_line_join:
+ * @cr: a cairo context, as a #cairo_t
+ * @line_join: a line joint style, as a #cairo_line_join_t
+ *
+ * Sets the current line join style within the cairo context. See
+ * #cairo_line_join_t for details about how the available line join
+ * styles are drawn.
+ *
+ * As with the other stroke parameters, the current line join style is
+ * examined by cairo_stroke(), cairo_stroke_extents(), and
+ * cairo_stroke_to_path(), but does not have any effect during path
+ * construction.
+ **/
void
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
{
@@ -527,6 +595,19 @@ cairo_set_miter_limit (cairo_t *cr, double limit)
CAIRO_CHECK_SANITY (cr);
}
+
+/**
+ * cairo_translate:
+ * @cr: a cairo context
+ * @tx: amount to translate in the X direction
+ * @ty: amount to translate in the Y direction
+ *
+ * Modifies the current transformation matrix (CTM) by tanslating the
+ * user-space origin by (@tx, @ty). This offset is interpreted as a
+ * user-space coordinate according to the CTM in place before the new
+ * call to cairo_translate. In other words, the translation of the
+ * user-space origin takes place after any existing transformation.
+ **/
void
cairo_translate (cairo_t *cr, double tx, double ty)
{
@@ -538,6 +619,17 @@ cairo_translate (cairo_t *cr, double tx, double ty)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_scale:
+ * @cr: a cairo context
+ * @sx: scale factor for the X dimension
+ * @sy: scale factor for the Y dimension
+ *
+ * Modifies the current transformation matrix (CTM) by scaling the X
+ * and Y user-space axes by @sx and @sy respectively. The scaling of
+ * the axes takes place after any existing transformation of user
+ * space.
+ **/
void
cairo_scale (cairo_t *cr, double sx, double sy)
{
@@ -549,6 +641,19 @@ cairo_scale (cairo_t *cr, double sx, double sy)
CAIRO_CHECK_SANITY (cr);
}
+
+/**
+ * cairo_rotate:
+ * @cr: a cairo context
+ * @angle: angle (in radians) by which the user-space axes will be
+ * rotated
+ *
+ * Modifies the current transformation matrix (CTM) by rotating the
+ * user-space axes by @angle radians. The rotation of the axes takes
+ * places after any existing transformation of user space. The
+ * rotation direction for positive angles is from the positive X axis
+ * toward the positive Y axis.
+ **/
void
cairo_rotate (cairo_t *cr, double angle)
{
@@ -560,21 +665,38 @@ cairo_rotate (cairo_t *cr, double angle)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_transform:
+ * @cr: a cairo context
+ * @matrix: a transformation to be applied to the user-space axes
+ *
+ * Modifies the current transformation matrix (CTM) by applying
+ * @matrix as an additional transformation. The new transformation of
+ * user space takes place after any existing transformation.
+ **/
void
-cairo_concat_matrix (cairo_t *cr,
- cairo_matrix_t *matrix)
+cairo_transform (cairo_t *cr,
+ const cairo_matrix_t *matrix)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_concat_matrix (cr->gstate, matrix);
+ cr->status = _cairo_gstate_transform (cr->gstate, matrix);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_matrix:
+ * @cr: a cairo context
+ * @matrix: a transformation matrix from user space to device space
+ *
+ * Modifies the current transformation matrix (CTM) by setting it
+ * equal to @matrix.
+ **/
void
-cairo_set_matrix (cairo_t *cr,
- cairo_matrix_t *matrix)
+cairo_set_matrix (cairo_t *cr,
+ const cairo_matrix_t *matrix)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
@@ -584,17 +706,15 @@ cairo_set_matrix (cairo_t *cr,
CAIRO_CHECK_SANITY (cr);
}
-void
-cairo_default_matrix (cairo_t *cr)
-{
- CAIRO_CHECK_SANITY (cr);
- if (cr->status)
- return;
-
- cr->status = _cairo_gstate_default_matrix (cr->gstate);
- CAIRO_CHECK_SANITY (cr);
-}
-
+/**
+ * cairo_identity_matrix:
+ * @cr: a cairo context
+ *
+ * Resets the current transformation matrix (CTM) by setting it equal
+ * to the identity matrix. That is, the user-space and device-space
+ * axes will be aligned and one user-space unit will transform to one
+ * device-space unit.
+ **/
void
cairo_identity_matrix (cairo_t *cr)
{
@@ -606,47 +726,89 @@ cairo_identity_matrix (cairo_t *cr)
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_user_to_device:
+ * @cr: a cairo context
+ * @x: X value of coordinate (in/out parameter)
+ * @y: Y value of coordinate (in/out parameter)
+ *
+ * Transform a coordinate from user space to device space by
+ * multiplying the given point by the current transformation matrix
+ * (CTM).
+ **/
void
-cairo_transform_point (cairo_t *cr, double *x, double *y)
+cairo_user_to_device (cairo_t *cr, double *x, double *y)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_transform_point (cr->gstate, x, y);
+ cr->status = _cairo_gstate_user_to_device (cr->gstate, x, y);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_user_to_device_distance:
+ * @cr: a cairo context
+ * @dx: X component of a distance vector (in/out parameter)
+ * @dy: Y component of a distance vector (in/out parameter)
+ *
+ * Transform a distance vector from user space to device space. This
+ * function is similar to cairo_user_to_device() except that the
+ * translation components of the CTM will be ignored when transforming
+ * (@dx,@dy).
+ **/
void
-cairo_transform_distance (cairo_t *cr, double *dx, double *dy)
+cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_transform_distance (cr->gstate, dx, dy);
+ cr->status = _cairo_gstate_user_to_device_distance (cr->gstate, dx, dy);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_device_to_user:
+ * @cr: a cairo
+ * @x: X value of coordinate (in/out parameter)
+ * @y: Y value of coordinate (in/out parameter)
+ *
+ * Transform a coordinate from device space to user space by
+ * multiplying the given point by the inverse of the current
+ * transformation matrix (CTM).
+ **/
void
-cairo_inverse_transform_point (cairo_t *cr, double *x, double *y)
+cairo_device_to_user (cairo_t *cr, double *x, double *y)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_inverse_transform_point (cr->gstate, x, y);
+ cr->status = _cairo_gstate_device_to_user (cr->gstate, x, y);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_device_to_user_distance:
+ * @cr: a cairo context
+ * @dx: X component of a distance vector (in/out parameter)
+ * @dy: Y component of a distance vector (in/out parameter)
+ *
+ * Transform a distance vector from device space to user space. This
+ * function is similar to cairo_device_to_user() except that the
+ * translation components of the inverse CTM will be ignored when
+ * transforming (@dx,@dy).
+ **/
void
-cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy)
+cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_inverse_transform_distance (cr->gstate, dx, dy);
+ cr->status = _cairo_gstate_device_to_user_distance (cr->gstate, dx, dy);
CAIRO_CHECK_SANITY (cr);
}
@@ -657,18 +819,27 @@ cairo_new_path (cairo_t *cr)
if (cr->status)
return;
- cr->status = _cairo_gstate_new_path (cr->gstate);
+ _cairo_path_fixed_fini (&cr->path);
+
CAIRO_CHECK_SANITY (cr);
}
+slim_hidden_def(cairo_new_path);
void
cairo_move_to (cairo_t *cr, double x, double y)
{
+ cairo_fixed_t x_fixed, y_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_move_to (cr->gstate, x, y);
+ _cairo_gstate_user_to_backend (cr->gstate, &x, &y);
+ x_fixed = _cairo_fixed_from_double (x);
+ y_fixed = _cairo_fixed_from_double (y);
+
+ cr->status = _cairo_path_fixed_move_to (&cr->path, x_fixed, y_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_move_to);
@@ -676,11 +847,18 @@ slim_hidden_def(cairo_move_to);
void
cairo_line_to (cairo_t *cr, double x, double y)
{
+ cairo_fixed_t x_fixed, y_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_line_to (cr->gstate, x, y);
+ _cairo_gstate_user_to_backend (cr->gstate, &x, &y);
+ x_fixed = _cairo_fixed_from_double (x);
+ y_fixed = _cairo_fixed_from_double (y);
+
+ cr->status = _cairo_path_fixed_line_to (&cr->path, x_fixed, y_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
@@ -690,20 +868,38 @@ cairo_curve_to (cairo_t *cr,
double x2, double y2,
double x3, double y3)
{
+ cairo_fixed_t x1_fixed, y1_fixed;
+ cairo_fixed_t x2_fixed, y2_fixed;
+ cairo_fixed_t x3_fixed, y3_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_curve_to (cr->gstate,
- x1, y1,
- x2, y2,
- x3, y3);
+ _cairo_gstate_user_to_backend (cr->gstate, &x1, &y1);
+ _cairo_gstate_user_to_backend (cr->gstate, &x2, &y2);
+ _cairo_gstate_user_to_backend (cr->gstate, &x3, &y3);
+
+ x1_fixed = _cairo_fixed_from_double (x1);
+ y1_fixed = _cairo_fixed_from_double (y1);
+
+ x2_fixed = _cairo_fixed_from_double (x2);
+ y2_fixed = _cairo_fixed_from_double (y2);
+
+ x3_fixed = _cairo_fixed_from_double (x3);
+ y3_fixed = _cairo_fixed_from_double (y3);
+
+ cr->status = _cairo_path_fixed_curve_to (&cr->path,
+ x1_fixed, y1_fixed,
+ x2_fixed, y2_fixed,
+ x3_fixed, y3_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
/**
* cairo_arc:
- * @cr: a Cairo context
+ * @cr: a cairo context
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
@@ -744,16 +940,26 @@ cairo_arc (cairo_t *cr,
if (cr->status)
return;
- cr->status = _cairo_gstate_arc (cr->gstate,
- xc, yc,
- radius,
- angle1, angle2);
+ /* Do nothing, successfully, if radius is <= 0 */
+ if (radius <= 0.0)
+ return;
+
+ while (angle2 < angle1)
+ angle2 += 2 * M_PI;
+
+ cairo_line_to (cr,
+ xc + radius * cos (angle1),
+ yc + radius * sin (angle1));
+
+ _cairo_arc_path (cr, xc, yc, radius,
+ angle1, angle2);
+
CAIRO_CHECK_SANITY (cr);
}
/**
* cairo_arc_negative:
- * @cr: a Cairo context
+ * @cr: a cairo context
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
@@ -775,10 +981,20 @@ cairo_arc_negative (cairo_t *cr,
if (cr->status)
return;
- cr->status = _cairo_gstate_arc_negative (cr->gstate,
- xc, yc,
- radius,
- angle1, angle2);
+ /* Do nothing, successfully, if radius is <= 0 */
+ if (radius <= 0.0)
+ return;
+
+ while (angle2 > angle1)
+ angle2 -= 2 * M_PI;
+
+ cairo_line_to (cr,
+ xc + radius * cos (angle1),
+ yc + radius * sin (angle1));
+
+ _cairo_arc_path_negative (cr, xc, yc, radius,
+ angle1, angle2);
+
CAIRO_CHECK_SANITY (cr);
}
@@ -802,22 +1018,36 @@ cairo_arc_to (cairo_t *cr,
void
cairo_rel_move_to (cairo_t *cr, double dx, double dy)
{
+ cairo_fixed_t dx_fixed, dy_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_rel_move_to (cr->gstate, dx, dy);
+ _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy);
+ dx_fixed = _cairo_fixed_from_double (dx);
+ dy_fixed = _cairo_fixed_from_double (dy);
+
+ cr->status = _cairo_path_fixed_rel_move_to (&cr->path, dx_fixed, dy_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
void
cairo_rel_line_to (cairo_t *cr, double dx, double dy)
{
+ cairo_fixed_t dx_fixed, dy_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_rel_line_to (cr->gstate, dx, dy);
+ _cairo_gstate_user_to_device_distance (cr->gstate, &dx, &dy);
+ dx_fixed = _cairo_fixed_from_double (dx);
+ dy_fixed = _cairo_fixed_from_double (dy);
+
+ cr->status = _cairo_path_fixed_rel_line_to (&cr->path, dx_fixed, dy_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_rel_line_to);
@@ -828,14 +1058,32 @@ cairo_rel_curve_to (cairo_t *cr,
double dx2, double dy2,
double dx3, double dy3)
{
+ cairo_fixed_t dx1_fixed, dy1_fixed;
+ cairo_fixed_t dx2_fixed, dy2_fixed;
+ cairo_fixed_t dx3_fixed, dy3_fixed;
+
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_rel_curve_to (cr->gstate,
- dx1, dy1,
- dx2, dy2,
- dx3, dy3);
+ _cairo_gstate_user_to_device_distance (cr->gstate, &dx1, &dy1);
+ _cairo_gstate_user_to_device_distance (cr->gstate, &dx2, &dy2);
+ _cairo_gstate_user_to_device_distance (cr->gstate, &dx3, &dy3);
+
+ dx1_fixed = _cairo_fixed_from_double (dx1);
+ dy1_fixed = _cairo_fixed_from_double (dy1);
+
+ dx2_fixed = _cairo_fixed_from_double (dx2);
+ dy2_fixed = _cairo_fixed_from_double (dy2);
+
+ dx3_fixed = _cairo_fixed_from_double (dx3);
+ dy3_fixed = _cairo_fixed_from_double (dy3);
+
+ cr->status = _cairo_path_fixed_rel_curve_to (&cr->path,
+ dx1_fixed, dy1_fixed,
+ dx2_fixed, dy2_fixed,
+ dx3_fixed, dy3_fixed);
+
CAIRO_CHECK_SANITY (cr);
}
@@ -858,7 +1106,7 @@ cairo_rectangle (cairo_t *cr,
/* XXX: NYI
void
-cairo_stroke_path (cairo_t *cr)
+cairo_stroke_to_path (cairo_t *cr)
{
if (cr->status)
return;
@@ -874,32 +1122,208 @@ cairo_close_path (cairo_t *cr)
if (cr->status)
return;
- cr->status = _cairo_gstate_close_path (cr->gstate);
+ cr->status = _cairo_path_fixed_close_path (&cr->path);
+
CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_close_path);
+/**
+ * cairo_paint:
+ * @cr: a cairo context
+ *
+ * A drawing operator that paints the current source everywhere within
+ * the current clip region.
+ **/
+void
+cairo_paint (cairo_t *cr)
+{
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_paint (cr->gstate);
+
+ CAIRO_CHECK_SANITY (cr);
+}
+
+/**
+ * cairo_paint_with_alpha:
+ * @cr: a cairo context
+ * @alpha: alpha value, between 0 (transparent) and 1 (opaque)
+ *
+ * A drawing operator that paints the current source everywhere within
+ * the current clip region using a mask of constant alpha value
+ * @alpha. The effect is similar to cairo_paint(), but the drawing
+ * is faded out using the alpha value.
+ **/
+void
+cairo_paint_with_alpha (cairo_t *cr,
+ double alpha)
+{
+ cairo_color_t color;
+ cairo_pattern_union_t pattern;
+
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return;
+
+ _cairo_color_init_rgba (&color, 1., 1., 1., alpha);
+ _cairo_pattern_init_solid (&pattern.solid, &color);
+
+ cr->status = _cairo_gstate_mask (cr->gstate, &pattern.base);
+
+ _cairo_pattern_fini (&pattern.base);
+
+ CAIRO_CHECK_SANITY (cr);
+}
+
+/**
+ * cairo_mask:
+ * @cr: a cairo context
+ * @pattern: a #cairo_pattern_t
+ *
+ * A drawing operator that paints the current source
+ * using the alpha channel of @pattern as a mask. (Opaque
+ * areas of @mask are painted with the source, transparent
+ * areas are not painted.)
+ */
+void
+cairo_mask (cairo_t *cr,
+ cairo_pattern_t *pattern)
+{
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_mask (cr->gstate, pattern);
+
+ CAIRO_CHECK_SANITY (cr);
+}
+
+/**
+ * cairo_mask_surface:
+ * @cr: a cairo context
+ * @surface: a #cairo_surface_t
+ * @surface_x: X coordinate at which to place the origin of @surface
+ * @surface_y: Y coordinate at which to place the origin of @surface
+ *
+ * A drawing operator that paints the current source
+ * using the alpha channel of @surface as a mask. (Opaque
+ * areas of @surface are painted with the source, transparent
+ * areas are not painted.)
+ */
+void
+cairo_mask_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double surface_x,
+ double surface_y)
+{
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return;
+
+ pattern = cairo_pattern_create_for_surface (surface);
+ if (!pattern) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_matrix_init_translate (&matrix, - surface_x, - surface_y);
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ cairo_mask (cr, pattern);
+
+ cairo_pattern_destroy (pattern);
+}
+
+/**
+ * cairo_stroke:
+ * @cr: a cairo context
+ *
+ * A drawing operator that strokes the current path according to the
+ * current line width, line join, line cap, and dash settings. After
+ * cairo_stroke, the current path will be cleared from the cairo
+ * context. See cairo_set_line_width(), cairo_set_line_join(),
+ * cairo_set_line_cap(), cairo_set_dash(), and
+ * cairo_stroke_preserve().
+ **/
void
cairo_stroke (cairo_t *cr)
{
+ cairo_stroke_preserve (cr);
+
+ cairo_new_path (cr);
+}
+
+/**
+ * cairo_stroke_preserve:
+ * @cr: a cairo context
+ *
+ * A drawing operator that strokes the current path according to the
+ * current line width, line join, line cap, and dash settings. Unlike
+ * cairo_stroke(), cairo_stroke_preserve preserves the path within the
+ * cairo context.
+ *
+ * See cairo_set_line_width(), cairo_set_line_join(),
+ * cairo_set_line_cap(), cairo_set_dash(), and
+ * cairo_stroke_preserve().
+ **/
+void
+cairo_stroke_preserve (cairo_t *cr)
+{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_stroke (cr->gstate);
+ cr->status = _cairo_gstate_stroke (cr->gstate, &cr->path);
+
CAIRO_CHECK_SANITY (cr);
}
+slim_hidden_def(cairo_stroke_preserve);
+/**
+ * cairo_fill:
+ * @cr: a cairo context
+ *
+ * A drawing operator that fills the current path according to the
+ * current fill rule. After cairo_fill, the current path will be
+ * cleared from the cairo context. See cairo_set_fill_rule() and
+ * cairo_fill_preserve().
+ **/
void
cairo_fill (cairo_t *cr)
{
+ cairo_fill_preserve (cr);
+
+ cairo_new_path (cr);
+}
+
+/**
+ * cairo_fill_preserve:
+ * @cr: a cairo context
+ *
+ * A drawing operator that fills the current path according to the
+ * current fill rule. Unlike cairo_fill(), cairo_fill_preserve
+ * preserves the path within the cairo context.
+ *
+ * See cairo_set_fill_rule() and cairo_fill().
+ **/
+void
+cairo_fill_preserve (cairo_t *cr)
+{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_fill (cr->gstate);
+ cr->status = _cairo_gstate_fill (cr->gstate, &cr->path);
+
CAIRO_CHECK_SANITY (cr);
}
+slim_hidden_def(cairo_fill_preserve);
void
cairo_copy_page (cairo_t *cr)
@@ -932,7 +1356,9 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
if (cr->status)
return 0;
- cr->status = _cairo_gstate_in_stroke (cr->gstate, x, y, &inside);
+ cr->status = _cairo_gstate_in_stroke (cr->gstate,
+ &cr->path,
+ x, y, &inside);
CAIRO_CHECK_SANITY (cr);
@@ -951,7 +1377,9 @@ cairo_in_fill (cairo_t *cr, double x, double y)
if (cr->status)
return 0;
- cr->status = _cairo_gstate_in_fill (cr->gstate, x, y, &inside);
+ cr->status = _cairo_gstate_in_fill (cr->gstate,
+ &cr->path,
+ x, y, &inside);
CAIRO_CHECK_SANITY (cr);
@@ -969,7 +1397,9 @@ cairo_stroke_extents (cairo_t *cr,
if (cr->status)
return;
- cr->status = _cairo_gstate_stroke_extents (cr->gstate, x1, y1, x2, y2);
+ cr->status = _cairo_gstate_stroke_extents (cr->gstate,
+ &cr->path,
+ x1, y1, x2, y2);
CAIRO_CHECK_SANITY (cr);
}
@@ -981,143 +1411,288 @@ cairo_fill_extents (cairo_t *cr,
if (cr->status)
return;
- cr->status = _cairo_gstate_fill_extents (cr->gstate, x1, y1, x2, y2);
+ cr->status = _cairo_gstate_fill_extents (cr->gstate,
+ &cr->path,
+ x1, y1, x2, y2);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_clip:
+ * @cr: a cairo context
+ *
+ * Establishes a new clip region by intersecting the current clip
+ * region with the current path as it would be filled by cairo_fill()
+ * and according to the current fill rule (see cairo_set_fill_rule()).
+ *
+ * After cairo_clip, the current path will be cleared from the cairo
+ * context.
+ *
+ * The current clip region affects all drawing operations by
+ * effectively masking out any changes to the surface that are outside
+ * the current clip region.
+ *
+ * Calling cairo_clip() can only make the clip region smaller, never
+ * larger. But the current clip is part of the graphics state, so a
+ * tempoarary restriction of the clip region can be achieved by
+ * calling cairo_clip() within a cairo_save()/cairo_restore()
+ * pair. The only other means of increasing the size of the clip
+ * region is cairo_reset_clip().
+ **/
+void
+cairo_clip (cairo_t *cr)
+{
+ cairo_clip_preserve (cr);
+
+ cairo_new_path (cr);
+}
+
+/**
+ * cairo_clip_preserve:
+ * @cr: a cairo context
+ *
+ * Establishes a new clip region by intersecting the current clip
+ * region with the current path as it would be filled by cairo_fill()
+ * and according to the current fill rule (see cairo_set_fill_rule()).
+ *
+ * Unlike cairo_clip(), cairo_clip_preserve preserves the path within
+ * the cairo context.
+ *
+ * The current clip region affects all drawing operations by
+ * effectively masking out any changes to the surface that are outside
+ * the current clip region.
+ *
+ * Calling cairo_clip() can only make the clip region smaller, never
+ * larger. But the current clip is part of the graphics state, so a
+ * tempoarary restriction of the clip region can be achieved by
+ * calling cairo_clip() within a cairo_save()/cairo_restore()
+ * pair. The only other means of increasing the size of the clip
+ * region is cairo_reset_clip().
+ **/
void
-cairo_init_clip (cairo_t *cr)
+cairo_clip_preserve (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_init_clip (cr->gstate);
+ cr->status = _cairo_gstate_clip (cr->gstate, &cr->path);
CAIRO_CHECK_SANITY (cr);
}
+slim_hidden_def(cairo_clip_preserve);
+/**
+ * cairo_reset_clip:
+ * @cr: a cairo context
+ *
+ * Reset the current clip region to its original, unrestricted
+ * state. That is, set the clip region to an infinitely large shape
+ * containing the target surface. Equivalently, if infinity is too
+ * hard to grasp, one can imagine the clip region being reset to the
+ * exact bounds of the target surface.
+ *
+ * Note that code meant to be reusable should not call
+ * cairo_reset_clip() as it will cause results unexpected by
+ * higher-level code which calls cairo_clip(). Consider using
+ * cairo_save() and cairo_restore() around cairo_clip() as a more
+ * robust means of temporarily restricting the clip region.
+ **/
void
-cairo_clip (cairo_t *cr)
+cairo_reset_clip (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_clip (cr->gstate);
+ cr->status = _cairo_gstate_reset_clip (cr->gstate);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_select_font_face:
+ * @cr: a #cairo_t
+ * @family: a font family name, encoded in UTF-8
+ * @slant: the slant for the font
+ * @weight: the weight for the font
+ *
+ * Selects a family and style of font from a simplified description as
+ * a family name, slant and weight. This function is meant to be used
+ * only for applications with simple font needs: Cairo doesn't provide
+ * for operations such as listing all available fonts on the system,
+ * and it is expected that most applications will need to use a more
+ * comprehensive font handling and text layout library in addition to
+ * Cairo.
+ **/
void
-cairo_select_font (cairo_t *cr,
- const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight)
+cairo_select_font_face (cairo_t *cr,
+ const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_select_font (cr->gstate, family, slant, weight);
+ cr->status = _cairo_gstate_select_font_face (cr->gstate, family, slant, weight);
CAIRO_CHECK_SANITY (cr);
}
/**
- * cairo_current_font:
+ * cairo_get_font_face:
* @cr: a #cairo_t
*
- * Gets the current font object for a #cairo_t. If there is no current
- * font object, because the font parameters, transform, or target
- * surface has been changed since a font was last used, a font object
- * will be created and stored in in the #cairo_t.
+ * Gets the current font face for a #cairo_t.
*
* Return value: the current font object. Can return %NULL
* on out-of-memory or if the context is already in
- * an error state. This object is owned by Cairo. To keep
+ * an error state. This object is owned by cairo. To keep
* a reference to it, you must call cairo_font_reference().
**/
-cairo_font_t *
-cairo_current_font (cairo_t *cr)
+cairo_font_face_t *
+cairo_get_font_face (cairo_t *cr)
{
- cairo_font_t *ret;
+ cairo_font_face_t *font_face;
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return NULL;
- cr->status = _cairo_gstate_current_font (cr->gstate, &ret);
+ cr->status = _cairo_gstate_get_font_face (cr->gstate, &font_face);
CAIRO_CHECK_SANITY (cr);
- return ret;
+ return font_face;
}
+/**
+ * cairo_font_extents:
+ * @cr: a #cairo_t
+ * @extents: a #cairo_font_extents_t object into which the results
+ * will be stored.
+ *
+ * Gets the font extents for the currently selected font.
+ **/
void
-cairo_current_font_extents (cairo_t *cr,
- cairo_font_extents_t *extents)
+cairo_font_extents (cairo_t *cr,
+ cairo_font_extents_t *extents)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_current_font_extents (cr->gstate, extents);
+ cr->status = _cairo_gstate_get_font_extents (cr->gstate, extents);
CAIRO_CHECK_SANITY (cr);
}
-
/**
- * cairo_set_font:
+ * cairo_set_font_face:
* @cr: a #cairo_t
- * @font: a #cairo_font_t, or %NULL to unset any previously set font.
- *
- * Replaces the current #cairo_font_t object in the #cairo_t with
- * @font. The replaced font in the #cairo_t will be destroyed if there
- * are no other references to it. Since a #cairo_font_t is specific to
- * a particular output device and size, changing the transformation,
- * font transformation, or target surfaces of a #cairo_t will clear
- * any previously set font. Setting the font using cairo_set_font() is
- * exclusive with the simple font selection API provided by
- * cairo_select_font(). The size and transformation set by
- * cairo_scale_font() and cairo_transform_font() are ignored unless
- * they were taken into account when creating @font.
+ * @font_face: a #cairo_font_face_t, or %NULL to restore to the default font
+ *
+ * Replaces the current #cairo_font_face_t object in the #cairo_t with
+ * @font_face. The replaced font face in the #cairo_t will be
+ * destroyed if there are no other references to it.
**/
void
-cairo_set_font (cairo_t *cr, cairo_font_t *font)
+cairo_set_font_face (cairo_t *cr,
+ cairo_font_face_t *font_face)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_set_font (cr->gstate, font);
+ cr->status = _cairo_gstate_set_font_face (cr->gstate, font_face);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_font_size:
+ * @cr: a #cairo_t
+ * @size: the new font size, in user space units
+ *
+ * Sets the current font matrix to a scale by a factor of @size, replacing
+ * any font matrix previously set with cairo_set_font_size() or
+ * cairo_set_font_matrix(). This results in a font size of @size user space
+ * units. (More precisely, this matrix will result in the font's
+ * em-square being a @size by @size square in user space.)
+ **/
void
-cairo_scale_font (cairo_t *cr, double scale)
+cairo_set_font_size (cairo_t *cr, double size)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_scale_font (cr->gstate, scale);
+ cr->status = _cairo_gstate_set_font_size (cr->gstate, size);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_set_font_matrix
+ * @cr: a #cairo_t
+ * @matrix: a #cairo_matrix_t describing a transform to be applied to
+ * the current font.
+ *
+ * Sets the current font matrix to @matrix. The font matrix gives a
+ * transformation from the design space of the font (in this space,
+ * the em-square is 1 unit by 1 unit) to user space. Normally, a
+ * simple scale is used (see cairo_set_font_size()), but a more
+ * complex font matrix can be used to shear the font
+ * or stretch it unequally along the two axes
+ **/
void
-cairo_transform_font (cairo_t *cr, cairo_matrix_t *matrix)
+cairo_set_font_matrix (cairo_t *cr,
+ const cairo_matrix_t *matrix)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_transform_font (cr->gstate, matrix);
+ cr->status = _cairo_gstate_set_font_matrix (cr->gstate, matrix);
CAIRO_CHECK_SANITY (cr);
}
+/**
+ * cairo_get_font_matrix
+ * @cr: a #cairo_t
+ * @matrix: return value for the matrix
+ *
+ * Stores the current font matrix into @matrix. See
+ * cairo_set_font_matrix().
+ **/
+void
+cairo_get_font_matrix (cairo_t *cr, cairo_matrix_t *matrix)
+{
+ CAIRO_CHECK_SANITY (cr);
+ _cairo_gstate_get_font_matrix (cr->gstate, matrix);
+}
+
+/**
+ * cairo_text_extents:
+ * @cr: a #cairo_t
+ * @utf8: a string of text, encoded in utf-8
+ * @extents: a #cairo_text_extents_t object into which the results
+ * will be stored.
+ *
+ * Gets the extents for a string of text. The extents describe a
+ * user-space rectangle that encloses the "inked" portion of the text,
+ * (as it would be drawn by cairo_show_text). Additionally, the
+ * x_advance and y_advance values indicate the amount by which the
+ * current point would be advanced by cairo_show_text.
+ *
+ * Note that whitespace characters do not directly contribute to the
+ * size of the rectangle (extents.width and extents.height). They do
+ * contribute indirectly by changing the position of non-whitespace
+ * characters. In particular, trailing whitespace characters are
+ * likely to not affect the size of the rectangle, though they will
+ * affect the x_advance and y_advance values.
+ **/
void
-cairo_text_extents (cairo_t *cr,
- const unsigned char *utf8,
- cairo_text_extents_t *extents)
+cairo_text_extents (cairo_t *cr,
+ const char *utf8,
+ cairo_text_extents_t *extents)
{
cairo_glyph_t *glyphs = NULL;
- int nglyphs;
+ int num_glyphs;
+ double x, y;
CAIRO_CHECK_SANITY (cr);
if (cr->status)
@@ -1133,7 +1708,11 @@ cairo_text_extents (cairo_t *cr,
return;
}
- cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
+ cairo_get_current_point (cr, &x, &y);
+
+ cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8,
+ x, y,
+ &glyphs, &num_glyphs);
CAIRO_CHECK_SANITY (cr);
if (cr->status) {
@@ -1142,13 +1721,31 @@ cairo_text_extents (cairo_t *cr,
return;
}
- cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, nglyphs, extents);
+ cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, extents);
CAIRO_CHECK_SANITY (cr);
if (glyphs)
free (glyphs);
}
+/**
+ * cairo_glyph_extents:
+ * @cr: a #cairo_t
+ * @glyphs: an array of #cairo_glyph_t objects
+ * @num_glyphs: the number of elements in @glyphs
+ * @extents: a #cairo_text_extents_t object into which the results
+ * will be stored
+ *
+ * Gets the extents for an array of glyphs. The extents describe a
+ * user-space rectangle that encloses the "inked" portion of the
+ * glyphs, (as they would be drawn by cairo_show_glyphs).
+ * Additionally, the x_advance and y_advance values indicate the
+ * amount by which the current point would be advanced by
+ * cairo_show_glyphs.
+ *
+ * Note that whitespace glyphs do not contribute to the size of the
+ * rectangle (extents.width and extents.height).
+ **/
void
cairo_glyph_extents (cairo_t *cr,
cairo_glyph_t *glyphs,
@@ -1165,10 +1762,11 @@ cairo_glyph_extents (cairo_t *cr,
}
void
-cairo_show_text (cairo_t *cr, const unsigned char *utf8)
+cairo_show_text (cairo_t *cr, const char *utf8)
{
cairo_glyph_t *glyphs = NULL;
- int nglyphs;
+ int num_glyphs;
+ double x, y;
CAIRO_CHECK_SANITY (cr);
if (cr->status)
@@ -1177,7 +1775,11 @@ cairo_show_text (cairo_t *cr, const unsigned char *utf8)
if (utf8 == NULL)
return;
- cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
+ cairo_get_current_point (cr, &x, &y);
+
+ cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8,
+ x, y,
+ &glyphs, &num_glyphs);
CAIRO_CHECK_SANITY (cr);
if (cr->status) {
@@ -1186,7 +1788,7 @@ cairo_show_text (cairo_t *cr, const unsigned char *utf8)
return;
}
- cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, nglyphs);
+ cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs);
CAIRO_CHECK_SANITY (cr);
if (glyphs)
@@ -1205,16 +1807,21 @@ cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
}
void
-cairo_text_path (cairo_t *cr, const unsigned char *utf8)
+cairo_text_path (cairo_t *cr, const char *utf8)
{
cairo_glyph_t *glyphs = NULL;
- int nglyphs;
+ int num_glyphs;
+ double x, y;
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs);
+ cairo_get_current_point (cr, &x, &y);
+
+ cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8,
+ x, y,
+ &glyphs, &num_glyphs);
CAIRO_CHECK_SANITY (cr);
if (cr->status) {
@@ -1223,7 +1830,9 @@ cairo_text_path (cairo_t *cr, const unsigned char *utf8)
return;
}
- cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, nglyphs);
+ cr->status = _cairo_gstate_glyph_path (cr->gstate,
+ glyphs, num_glyphs,
+ &cr->path);
CAIRO_CHECK_SANITY (cr);
if (glyphs)
@@ -1237,162 +1846,281 @@ cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
if (cr->status)
return;
- cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs);
+ cr->status = _cairo_gstate_glyph_path (cr->gstate,
+ glyphs, num_glyphs,
+ &cr->path);
+
CAIRO_CHECK_SANITY (cr);
}
-void
-cairo_show_surface (cairo_t *cr,
- cairo_surface_t *surface,
- int width,
- int height)
+/**
+ * cairo_get_operator:
+ * @cr: a cairo context
+ *
+ * Gets the current compositing operator for a cairo context.
+ *
+ * Return value: the current compositing operator.
+ **/
+cairo_operator_t
+cairo_get_operator (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- if (cr->status)
- return;
-
- cr->status = _cairo_gstate_show_surface (cr->gstate,
- surface, width, height);
- CAIRO_CHECK_SANITY (cr);
+ return _cairo_gstate_get_operator (cr->gstate);
}
-cairo_operator_t
-cairo_current_operator (cairo_t *cr)
+/**
+ * cairo_get_tolerance:
+ * @cr: a cairo context
+ *
+ * Gets the current tolerance value, as set by cairo_set_tolerance().
+ *
+ * Return value: the current tolerance value.
+ **/
+double
+cairo_get_tolerance (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_operator (cr->gstate);
+ return _cairo_gstate_get_tolerance (cr->gstate);
}
-DEPRECATE (cairo_get_operator, cairo_current_operator);
+/**
+ * cairo_get_current_point:
+ * @cr: a cairo context
+ * @x: return value for X coordinate of the current point
+ * @y: return value for Y coordinate of the current point
+ *
+ * Gets the current point of the current path, which is
+ * conceptually the final point reached by the path so far.
+ *
+ * The current point is returned in the user-space coordinate
+ * system. If there is no defined current point then @x and @y will
+ * both be set to 0.0.
+ *
+ * Most path construction functions alter the current point. See the
+ * following for details on how they affect the current point:
+ *
+ * cairo_new_path(), cairo_move_to(), cairo_line_to(),
+ * cairo_curve_to(), cairo_arc(), cairo_rel_move_to(),
+ * cairo_rel_line_to(), cairo_rel_curve_to(), cairo_arc(),
+ * cairo_text_path(), cairo_stroke_to_path()
+ **/
void
-cairo_current_rgb_color (cairo_t *cr, double *red, double *green, double *blue)
+cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret)
{
- CAIRO_CHECK_SANITY (cr);
- _cairo_gstate_current_rgb_color (cr->gstate, red, green, blue);
- CAIRO_CHECK_SANITY (cr);
-}
-DEPRECATE (cairo_get_rgb_color, cairo_current_rgb_color);
+ cairo_status_t status;
+ cairo_fixed_t x_fixed, y_fixed;
+ double x, y;
-double
-cairo_current_alpha (cairo_t *cr)
-{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_alpha (cr->gstate);
-}
-DEPRECATE (cairo_get_alpha, cairo_current_alpha);
-double
-cairo_current_tolerance (cairo_t *cr)
-{
- CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_tolerance (cr->gstate);
-}
-DEPRECATE (cairo_get_tolerance, cairo_current_tolerance);
+ status = _cairo_path_fixed_get_current_point (&cr->path, &x_fixed, &y_fixed);
+ if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
+ x = 0.0;
+ y = 0.0;
+ } else {
+ x = _cairo_fixed_to_double (x_fixed);
+ y = _cairo_fixed_to_double (y_fixed);
+ _cairo_gstate_backend_to_user (cr->gstate, &x, &y);
+ }
+
+ if (x_ret)
+ *x_ret = x;
+ if (y_ret)
+ *y_ret = y;
-void
-cairo_current_point (cairo_t *cr, double *x, double *y)
-{
- CAIRO_CHECK_SANITY (cr);
- _cairo_gstate_current_point (cr->gstate, x, y);
CAIRO_CHECK_SANITY (cr);
}
-DEPRECATE (cairo_get_current_point, cairo_current_point);
+slim_hidden_def(cairo_get_current_point);
+/**
+ * cairo_get_fill_rule:
+ * @cr: a cairo context
+ *
+ * Gets the current fill rule, as set by cairo_set_fill_rule().
+ *
+ * Return value: the current fill rule.
+ **/
cairo_fill_rule_t
-cairo_current_fill_rule (cairo_t *cr)
+cairo_get_fill_rule (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_fill_rule (cr->gstate);
+ return _cairo_gstate_get_fill_rule (cr->gstate);
}
-DEPRECATE (cairo_get_fill_rule, cairo_current_fill_rule);
+/**
+ * cairo_get_line_width:
+ * @cr: a cairo context
+ *
+ * Gets the current line width, as set by cairo_set_line_width().
+ *
+ * Return value: the current line width, in user-space units.
+ **/
double
-cairo_current_line_width (cairo_t *cr)
+cairo_get_line_width (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_line_width (cr->gstate);
+ return _cairo_gstate_get_line_width (cr->gstate);
}
-DEPRECATE (cairo_get_line_width, cairo_current_line_width);
+/**
+ * cairo_get_line_cap:
+ * @cr: a cairo context
+ *
+ * Gets the current line cap style, as set by cairo_set_line_cap().
+ *
+ * Return value: the current line cap style.
+ **/
cairo_line_cap_t
-cairo_current_line_cap (cairo_t *cr)
+cairo_get_line_cap (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_line_cap (cr->gstate);
+ return _cairo_gstate_get_line_cap (cr->gstate);
}
-DEPRECATE (cairo_get_line_cap, cairo_current_line_cap);
+/**
+ * cairo_get_line_join:
+ * @cr: a cairo context
+ *
+ * Gets the current line join style, as set by cairo_set_line_join().
+ *
+ * Return value: the current line join style.
+ **/
cairo_line_join_t
-cairo_current_line_join (cairo_t *cr)
+cairo_get_line_join (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_line_join (cr->gstate);
+ return _cairo_gstate_get_line_join (cr->gstate);
}
-DEPRECATE (cairo_get_line_join, cairo_current_line_join);
+/**
+ * cairo_get_miter_limit:
+ * @cr: a cairo context
+ *
+ * Gets the current miter limit, as set by cairo_set_miter_limit().
+ *
+ * Return value: the current miter limit.
+ **/
double
-cairo_current_miter_limit (cairo_t *cr)
+cairo_get_miter_limit (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_miter_limit (cr->gstate);
+ return _cairo_gstate_get_miter_limit (cr->gstate);
}
-DEPRECATE (cairo_get_miter_limit, cairo_current_miter_limit);
+/**
+ * cairo_get_matrix:
+ * @cr: a cairo context
+ * @matrix: return value for the matrix
+ *
+ * Stores the current transformation matrix (CTM) into @matrix.
+ **/
void
-cairo_current_matrix (cairo_t *cr, cairo_matrix_t *matrix)
+cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix)
{
CAIRO_CHECK_SANITY (cr);
- _cairo_gstate_current_matrix (cr->gstate, matrix);
- CAIRO_CHECK_SANITY (cr);
+ _cairo_gstate_get_matrix (cr->gstate, matrix);
}
-DEPRECATE (cairo_get_matrix, cairo_current_matrix);
+/**
+ * cairo_get_target:
+ * @cr: a cairo context
+ *
+ * Gets the target surface for the cairo context as passed to
+ * cairo_create().
+ *
+ * Return value: the target surface, (or NULL if @cr is in an error
+ * state). This object is owned by cairo. To keep a reference to it,
+ * you must call cairo_pattern_reference().
+ **/
cairo_surface_t *
-cairo_current_target_surface (cairo_t *cr)
+cairo_get_target (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
- return _cairo_gstate_current_target_surface (cr->gstate);
+ if (cr->status)
+ return NULL;
+
+ return _cairo_gstate_get_target (cr->gstate);
}
-DEPRECATE (cairo_get_target_surface, cairo_current_target_surface);
-void
-cairo_current_path (cairo_t *cr,
- cairo_move_to_func_t *move_to,
- cairo_line_to_func_t *line_to,
- cairo_curve_to_func_t *curve_to,
- cairo_close_path_func_t *close_path,
- void *closure)
+/**
+ * cairo_copy_path:
+ * @cr: a cairo context
+ *
+ * Creates a copy of the current path and returns it to the user as a
+ * #cairo_path_t. See #cairo_path_data_t for hints on how to iterate
+ * over the returned data structure.
+ *
+ * Return value: the copy of the current path. The caller owns the
+ * returned object and should call cairo_path_destroy() when finished
+ * with it.
+ **/
+cairo_path_t *
+cairo_copy_path (cairo_t *cr)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
- return;
-
- cr->status = _cairo_gstate_interpret_path (cr->gstate,
- move_to,
- line_to,
- curve_to,
- close_path,
- closure);
+ return &_cairo_path_nil;
+
+ return _cairo_path_data_create (&cr->path, cr->gstate);
+}
+
+/**
+ * cairo_copy_path_flat:
+ * @cr: a cairo context
+ *
+ * Gets a flattened copy of the current path and returns it to the
+ * user as a #cairo_path_t. See #cairo_path_data_t for hints on
+ * how to iterate over the returned data structure.
+ *
+ * This function is like cairo_copy_path() except that any curves
+ * in the path will be approximated with piecewise-linear
+ * approximations, (accurate to within the current tolerance
+ * value). That is, the result is guaranteed to not have any elements
+ * of type CAIRO_PATH_CURVE_TO which will instead be replaced by a
+ * series of CAIRO_PATH_LINE_TO elements.
+ *
+ * Return value: the copy of the current path. The caller owns the
+ * returned object and should call cairo_path_destroy() when finished
+ * with it.
+ **/
+cairo_path_t *
+cairo_copy_path_flat (cairo_t *cr)
+{
CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return &_cairo_path_nil;
+
+ return _cairo_path_data_create_flat (&cr->path, cr->gstate);
}
+/**
+ * cairo_append_path:
+ * @cr: a cairo context
+ * @path: path to be appended
+ *
+ * Append the @path onto the current path. See #cairo_path_t
+ * for details on how the path data structure must be initialized.
+ **/
void
-cairo_current_path_flat (cairo_t *cr,
- cairo_move_to_func_t *move_to,
- cairo_line_to_func_t *line_to,
- cairo_close_path_func_t *close_path,
- void *closure)
+cairo_append_path (cairo_t *cr,
+ cairo_path_t *path)
{
CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
- cr->status = _cairo_gstate_interpret_path (cr->gstate,
- move_to,
- line_to,
- NULL,
- close_path,
- closure);
+ if (path == NULL || path->data == NULL) {
+ cr->status = CAIRO_STATUS_NULL_POINTER;
+ return;
+ }
+
+ if (path == &_cairo_path_nil) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cr->status = _cairo_path_data_append_to_context (path, cr);
+
CAIRO_CHECK_SANITY (cr);
}
@@ -1402,7 +2130,6 @@ cairo_status (cairo_t *cr)
CAIRO_CHECK_SANITY (cr);
return cr->status;
}
-DEPRECATE (cairo_get_status, cairo_status);
const char *
cairo_status_string (cairo_t *cr)
@@ -1426,11 +2153,22 @@ cairo_status_string (cairo_t *cr)
return "NULL pointer";
case CAIRO_STATUS_INVALID_STRING:
return "input string not valid UTF-8";
+ case CAIRO_STATUS_INVALID_PATH_DATA:
+ return "input path data not valid";
+ case CAIRO_STATUS_READ_ERROR:
+ return "error while reading from input stream";
+ case CAIRO_STATUS_WRITE_ERROR:
+ return "error while writing to output stream";
+ case CAIRO_STATUS_SURFACE_FINISHED:
+ return "the target surface has been finished";
+ case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
+ return "the surface type is not appropriate for the operation";
+ case CAIRO_STATUS_BAD_NESTING:
+ return "drawing operations interleaved for two contexts for the same surface";
}
return "<unknown error status>";
}
-DEPRECATE (cairo_get_status_string, cairo_status_string);
void
_cairo_restrict_value (double *value, double min, double max)
diff --git a/src/cairo.h b/src/cairo.h
index 03e063242..4cb3a023e 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -46,7 +47,6 @@
#endif
#include <cairo-features.h>
-#include <pixman.h>
CAIRO_BEGIN_DECLS
@@ -55,7 +55,7 @@ CAIRO_BEGIN_DECLS
*
* #cairo_bool_t is used for boolean values. Returns of type
* #cairo_bool_t will always be either 0 or 1, but testing against
- * these values explicitely is not encouraged; just use the
+ * these values explicitly is not encouraged; just use the
* value as a boolean condition.
*
* <informalexample><programlisting>
@@ -94,9 +94,62 @@ typedef struct _cairo_surface cairo_surface_t;
* A #cairo_matrix_t holds an affine transformation, such as a scale,
* rotation, or shear, or a combination of those.
**/
-typedef struct _cairo_matrix cairo_matrix_t;
+typedef struct _cairo_matrix {
+ double xx; double yx;
+ double xy; double yy;
+ double x0; double y0;
+} cairo_matrix_t;
+
typedef struct _cairo_pattern cairo_pattern_t;
+/**
+ * cairo_destroy_func_t
+ *
+ * #cairo_destroy_func_t the type of function which is called when a
+ * data element is destroyed. It is passed the pointer to the data
+ * element and should free any memory and resources allocated for it.
+ */
+typedef void (*cairo_destroy_func_t) (void *data);
+
+/**
+ * cairo_user_data_key_t
+ *
+ * #cairo_user_data_key_t is used for attaching user data to cairo
+ * data structures. The actual contents of the struct is never used,
+ * and there is no need to initialize the object; only the unique
+ * address of a #cairo_data_key_t object is used. Typically, you
+ * would just use the address of a static #cairo_data_key_t object.
+ */
+typedef struct _cairo_user_data_key {
+ int unused;
+} cairo_user_data_key_t;
+
+/**
+ * cairo_status_t
+ * @CAIRO_STATUS_SUCCESS: no error has occurred
+ * @CAIRO_STATUS_NO_MEMORY:
+ * @CAIRO_STATUS_INVALID_RESTORE:
+ * @CAIRO_STATUS_INVALID_POP_GROUP:
+ * @CAIRO_STATUS_INVALID_MATRIX:
+ * @CAIRO_STATUS_NO_TARGET_SURFACE:
+ * @CAIRO_STATUS_NULL_POINTER:
+ * @CAIRO_STATUS_INVALID_STRING:
+ * @CAIRO_STATUS_INVALID_PATH_DATA:
+ * @CAIRO_STATUS_READ_ERROR:
+ * @CAIRO_STATUS_WRITE_ERROR:
+ * @CAIRO_STATUS_SURFACE_FINISHED:
+ * @CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
+ * @CAIRO_STATUS_BAD_NESTING: the same surface was used as the
+ * target surface for two different cairo contexts at once,
+ * and more drawing was done on the first context before the
+ * surface was unset as the target for the second context.
+ * See the documentation for cairo_create().
+ *
+ * #cairo_status_t is used to indicate errors that can occur when
+ * using Cairo. In some cases it is returned directly by functions.
+ * but when using #cairo_t, the last error, if any, is stored in
+ * the context and can be retrieved with cairo_status().
+ **/
typedef enum cairo_status {
CAIRO_STATUS_SUCCESS = 0,
CAIRO_STATUS_NO_MEMORY,
@@ -106,12 +159,48 @@ typedef enum cairo_status {
CAIRO_STATUS_INVALID_MATRIX,
CAIRO_STATUS_NO_TARGET_SURFACE,
CAIRO_STATUS_NULL_POINTER,
- CAIRO_STATUS_INVALID_STRING
+ CAIRO_STATUS_INVALID_STRING,
+ CAIRO_STATUS_INVALID_PATH_DATA,
+ CAIRO_STATUS_READ_ERROR,
+ CAIRO_STATUS_WRITE_ERROR,
+ CAIRO_STATUS_SURFACE_FINISHED,
+ CAIRO_STATUS_SURFACE_TYPE_MISMATCH,
+ CAIRO_STATUS_BAD_NESTING
} cairo_status_t;
+/**
+ * cairo_write_func_t
+ *
+ * #cairo_write_func_t is the type of function which is called when a
+ * backend needs to write data to an output stream. It is passed the
+ * closure which was specified by the user at the time the write
+ * function was registered, the data to write and the length of the
+ * data in bytes. The write function should return
+ * CAIRO_STATUS_SUCCESS if all the data was successfully written,
+ * CAIRO_STATUS_WRITE_ERROR otherwise.
+ */
+typedef cairo_status_t (*cairo_write_func_t) (void *closure,
+ const unsigned char *data,
+ unsigned int length);
+
+/**
+ * cairo_read_func_t
+ *
+ * #cairo_read_func_t is the type of function which is called when a
+ * backend needs to read data from an intput stream. It is passed the
+ * closure which was specified by the user at the time the read
+ * function was registered, the buffer to read the data into and the
+ * length of the data in bytes. The read function should return
+ * CAIRO_STATUS_SUCCESS if all the data was successfully written,
+ * CAIRO_STATUS_READ_ERROR otherwise.
+ */
+typedef cairo_status_t (*cairo_read_func_t) (void *closure,
+ unsigned char *data,
+ unsigned int length);
+
/* Functions for manipulating state objects */
cairo_t *
-cairo_create (void);
+cairo_create (cairo_surface_t *target);
void
cairo_reference (cairo_t *cr);
@@ -125,10 +214,6 @@ cairo_save (cairo_t *cr);
void
cairo_restore (cairo_t *cr);
-/* XXX: Replace with cairo_current_gstate/cairo_set_gstate */
-void
-cairo_copy (cairo_t *dest, cairo_t *src);
-
/* XXX: I want to rethink this API
void
cairo_push_group (cairo_t *cr);
@@ -138,59 +223,22 @@ cairo_pop_group (cairo_t *cr);
*/
/* Modify state */
-void
-cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface);
-
-/**
- * cairo_format_t
- * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with
- * alpha in the upper 8 bits, then red, then green, then blue.
- * The 32-bit quanties are stored native-endian. Pre-multiplied
- * alpha is used. (That is, 50% transparent red is 0x80800000,
- * not 0x80ff0000.)
- * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with
- * the upper 8 bits unused. Red, Green, and Blue are stored
- * in the remaining 24 bits in that order.
- * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding
- * an alpha value.
- * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding
- * an alpha value. Pixels are packed together into 32-bit
- * quantities. The ordering of the bits matches the
- * endianess of the platform. On a big-endian machine, the
- * first pixel is in the uppermost bit, on a little-endian
- * machine the first pixel is in the least-significant bit.
- *
- * #cairo_format_t is used to identify the memory format of
- * image data.
- */
-typedef enum cairo_format {
- CAIRO_FORMAT_ARGB32,
- CAIRO_FORMAT_RGB24,
- CAIRO_FORMAT_A8,
- CAIRO_FORMAT_A1
-} cairo_format_t;
-
-/* XXX: Need to add cairo_set_target_image_data */
-void
-cairo_set_target_image (cairo_t *cr,
- char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride);
-typedef enum cairo_operator {
+typedef enum cairo_operator {
CAIRO_OPERATOR_CLEAR,
- CAIRO_OPERATOR_SRC,
- CAIRO_OPERATOR_DST,
+
+ CAIRO_OPERATOR_SOURCE,
CAIRO_OPERATOR_OVER,
- CAIRO_OPERATOR_OVER_REVERSE,
CAIRO_OPERATOR_IN,
- CAIRO_OPERATOR_IN_REVERSE,
CAIRO_OPERATOR_OUT,
- CAIRO_OPERATOR_OUT_REVERSE,
CAIRO_OPERATOR_ATOP,
- CAIRO_OPERATOR_ATOP_REVERSE,
+
+ CAIRO_OPERATOR_DEST,
+ CAIRO_OPERATOR_DEST_OVER,
+ CAIRO_OPERATOR_DEST_IN,
+ CAIRO_OPERATOR_DEST_OUT,
+ CAIRO_OPERATOR_DEST_ATOP,
+
CAIRO_OPERATOR_XOR,
CAIRO_OPERATOR_ADD,
CAIRO_OPERATOR_SATURATE
@@ -199,36 +247,23 @@ typedef enum cairo_operator {
void
cairo_set_operator (cairo_t *cr, cairo_operator_t op);
-/* XXX: Probably want to bite the bullet and expose a cairo_color_t object */
-
-/* XXX: I've been trying to come up with a sane way to specify:
-
- cairo_set_color (cairo_t *cr, cairo_color_t *color);
-
- Keith wants to be able to support super-luminescent colors,
- (premultiplied colors with R/G/B greater than alpha). The current
- API does not allow that. Adding a premulitplied RGBA cairo_color_t
- would do the trick.
-
- One problem though is that alpha is currently orthogonal to
- color. For example, show_surface uses gstate->alpha but ignores the
- color. So, it doesn't seem be right to have cairo_set_color modify
- the behavior of cairo_show_surface.
-*/
+void
+cairo_set_source (cairo_t *cr, cairo_pattern_t *source);
void
-cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue);
+cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue);
void
-cairo_set_pattern (cairo_t *cr, cairo_pattern_t *pattern);
+cairo_set_source_rgba (cairo_t *cr,
+ double red, double green, double blue,
+ double alpha);
void
-cairo_set_alpha (cairo_t *cr, double alpha);
+cairo_set_source_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double x,
+ double y);
-/* XXX: Currently, the tolerance value is specified by the user in
- terms of device-space units. If I'm not mistaken, this is the only
- value in this API that is not expressed in user-space units. I
- should think whether this value should be user-space instead. */
void
cairo_set_tolerance (cairo_t *cr, double tolerance);
@@ -307,32 +342,27 @@ void
cairo_rotate (cairo_t *cr, double angle);
void
-cairo_concat_matrix (cairo_t *cr,
- cairo_matrix_t *matrix);
-
-void
-cairo_set_matrix (cairo_t *cr,
- cairo_matrix_t *matrix);
+cairo_transform (cairo_t *cr,
+ const cairo_matrix_t *matrix);
void
-cairo_default_matrix (cairo_t *cr);
-
-/* XXX: There's been a proposal to add cairo_default_matrix_exact */
+cairo_set_matrix (cairo_t *cr,
+ const cairo_matrix_t *matrix);
void
cairo_identity_matrix (cairo_t *cr);
void
-cairo_transform_point (cairo_t *cr, double *x, double *y);
+cairo_user_to_device (cairo_t *cr, double *x, double *y);
void
-cairo_transform_distance (cairo_t *cr, double *dx, double *dy);
+cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy);
void
-cairo_inverse_transform_point (cairo_t *cr, double *x, double *y);
+cairo_device_to_user (cairo_t *cr, double *x, double *y);
void
-cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy);
+cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy);
/* Path creation functions */
void
@@ -387,16 +417,9 @@ cairo_rectangle (cairo_t *cr,
double x, double y,
double width, double height);
-/* XXX: This is the same name that PostScript uses, but to me the name
- suggests an actual drawing operation ala cairo_stroke --- especially
- since I want to add a cairo_path_t and with that it would be
- natural to have "cairo_stroke_path (cairo_t *, cairo_path_t *)"
-
- Maybe we could use something like "cairo_outline_path (cairo_t *)"?
-*/
/* XXX: NYI
void
-cairo_stroke_path (cairo_t *cr);
+cairo_stroke_to_path (cairo_t *cr);
*/
void
@@ -404,12 +427,35 @@ cairo_close_path (cairo_t *cr);
/* Painting functions */
void
+cairo_paint (cairo_t *cr);
+
+void
+cairo_paint_with_alpha (cairo_t *cr,
+ double alpha);
+
+void
+cairo_mask (cairo_t *cr,
+ cairo_pattern_t *pattern);
+
+void
+cairo_mask_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double surface_x,
+ double surface_y);
+
+void
cairo_stroke (cairo_t *cr);
void
+cairo_stroke_preserve (cairo_t *cr);
+
+void
cairo_fill (cairo_t *cr);
void
+cairo_fill_preserve (cairo_t *cr);
+
+void
cairo_copy_page (cairo_t *cr);
void
@@ -435,25 +481,37 @@ cairo_fill_extents (cairo_t *cr,
/* Clipping */
void
-cairo_init_clip (cairo_t *cr);
+cairo_reset_clip (cairo_t *cr);
-/* Note: cairo_clip does not consume the current path */
void
cairo_clip (cairo_t *cr);
+void
+cairo_clip_preserve (cairo_t *cr);
+
/* Font/Text functions */
/**
- * cairo_font_t:
- *
- * A #cairo_font_t is a font scaled to a particular size and device
- * resolution. A font can be set on a #cairo_t by using
- * cairo_set_font() assuming that the current transformation and
- * target surface of the #cairo_t match that for which the
- * #cairo_font_t was created. The effect of using a mismatched
- * #cairo_font_t will be incorrect font metrics.
+ * cairo_scaled_font_t:
+ *
+ * A #cairo_scaled_font_t is a font scaled to a particular size and device
+ * resolution. A cairo_scaled_font_t is most useful for low-level font
+ * usage where a library or application wants to cache a reference
+ * to a scaled font to speed up the computation of metrics.
*/
-typedef struct _cairo_font cairo_font_t;
+typedef struct _cairo_scaled_font cairo_scaled_font_t;
+
+/**
+ * cairo_font_face_t:
+ *
+ * A #cairo_font_face_t specifies all aspects of a font other
+ * than the size or font matrix (a font matrix is used to distort
+ * a font by sheering it or scaling it unequally in the two
+ * directions) . A font face can be set on a #cairo_t by using
+ * cairo_set_font_face(); the size and font matrix are set with
+ * cairo_set_font_size() and cairo_set_font_matrix().
+ */
+typedef struct _cairo_font_face cairo_font_face_t;
/**
* cairo_glyph_t:
@@ -502,10 +560,10 @@ typedef struct {
* after drawing these glyphs. Will typically be zero except
* for vertical text layout as found in East-Asian languages.
*
- * The #cairo_text_extents_t< structure stores the extents of a single
+ * The #cairo_text_extents_t structure stores the extents of a single
* glyph or a string of glyphs in user-space coordinates. Because text
- * extents are in user-space coordinates, they don't scale along with
- * the current transformation matrix. If you call
+ * extents are in user-space coordinates, they are mostly, but not
+ * entirely, independent of the current transformation matrix. If you call
* <literal>cairo_scale(cr, 2.0, 2.0)</literal>, text will
* be drawn twice as big, but the reported text extents will not be
* doubled. They will change slightly due to hinting (so you can't
@@ -521,6 +579,47 @@ typedef struct {
double y_advance;
} cairo_text_extents_t;
+/**
+ * cairo_font_extents_t:
+ * @ascent: the distance that the font extends above the baseline.
+ * Note that this is not always exactly equal to the maximum
+ * of the extents of all the glyphs in the font, but rather
+ * is picked to express the font designer's intent as to
+ * how the font should align with elements above it.
+ * @descent: the distance that the font extends below the baseline.
+ * This value is positive for typical fonts that include
+ * portions below the baseline. Note that this is not always
+ * exactly equal to the maximum of the extents of all the
+ * glyphs in the font, but rather is picked to express the
+ * font designer's intent as to how the the font should
+ * align with elements below it.
+ * @height: the recommended vertical distance between baselines when
+ * setting consecutive lines of text with the font. This
+ * is greater than @ascent+@descent by a
+ * quantity known as the <firstterm>line spacing</firstterm>
+ * or <firstterm>external leading</firstterm>. When space
+ * is at a premium, most fonts can be set with only
+ * a distance of @ascent+@descent between lines.
+ * @max_x_advance: the maximum distance in the X direction that
+ * the the origin is advanced for any glyph in the font.
+ * @max_y_advance: the maximum distance in the Y direction that
+ * the the origin is advanced for any glyph in the font.
+ * this will be zero for normal fonts used for horizontal
+ * writing. (The scripts of East Asia are sometimes written
+ * vertically.)
+ *
+ * The #cairo_text_extents_t structure stores metric information for
+ * a font. Values are given in the current user-space coordinate
+ * system.
+ *
+ * Because font metrics are in user-space coordinates, they are
+ * mostly, but not entirely, independent of the current transformation
+ * matrix. If you call <literal>cairo_scale(cr, 2.0, 2.0)</literal>,
+ * text will be drawn twice as big, but the reported text extents will
+ * not be doubled. They will change slightly due to hinting (so you
+ * can't assume that metrics are independent of the transformation
+ * matrix), but otherwise will remain unchanged.
+ */
typedef struct {
double ascent;
double descent;
@@ -544,37 +643,42 @@ typedef enum cairo_font_weight {
font object inside the the cairo_t. */
void
-cairo_select_font (cairo_t *cr,
- const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight);
+cairo_select_font_face (cairo_t *cr,
+ const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight);
+
+void
+cairo_set_font_size (cairo_t *cr, double size);
void
-cairo_scale_font (cairo_t *cr, double scale);
+cairo_set_font_matrix (cairo_t *cr,
+ const cairo_matrix_t *matrix);
void
-cairo_transform_font (cairo_t *cr, cairo_matrix_t *matrix);
+cairo_get_font_matrix (cairo_t *cr,
+ cairo_matrix_t *matrix);
void
-cairo_show_text (cairo_t *cr, const unsigned char *utf8);
+cairo_show_text (cairo_t *cr, const char *utf8);
void
cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs);
-cairo_font_t *
-cairo_current_font (cairo_t *cr);
+cairo_font_face_t *
+cairo_get_font_face (cairo_t *cr);
void
-cairo_current_font_extents (cairo_t *cr,
- cairo_font_extents_t *extents);
+cairo_font_extents (cairo_t *cr,
+ cairo_font_extents_t *extents);
void
-cairo_set_font (cairo_t *cr, cairo_font_t *font);
+cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face);
void
-cairo_text_extents (cairo_t *cr,
- const unsigned char *utf8,
- cairo_text_extents_t *extents);
+cairo_text_extents (cairo_t *cr,
+ const char *utf8,
+ cairo_text_extents_t *extents);
void
cairo_glyph_extents (cairo_t *cr,
@@ -583,119 +687,197 @@ cairo_glyph_extents (cairo_t *cr,
cairo_text_extents_t *extents);
void
-cairo_text_path (cairo_t *cr, const unsigned char *utf8);
+cairo_text_path (cairo_t *cr, const char *utf8);
void
cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs);
-/* Portable interface to general font features. */
-
+/* Generic identifier for a font style */
+
void
-cairo_font_reference (cairo_font_t *font);
+cairo_font_face_reference (cairo_font_face_t *font_face);
void
-cairo_font_destroy (cairo_font_t *font);
+cairo_font_face_destroy (cairo_font_face_t *font_face);
+
+void *
+cairo_font_face_get_user_data (cairo_font_face_t *font_face,
+ const cairo_user_data_key_t *key);
cairo_status_t
-cairo_font_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_font_extents_t *extents);
+cairo_font_face_set_user_data (cairo_font_face_t *font_face,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy);
+
+/* Portable interface to general font features. */
+
+cairo_scaled_font_t *
+cairo_scaled_font_create (cairo_font_face_t *font_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm);
void
-cairo_font_glyph_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents);
+cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font);
-/* Image functions */
+void
+cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font);
+
+cairo_status_t
+cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
+ cairo_font_extents_t *extents);
-/* XXX: Eliminate width/height here */
void
-cairo_show_surface (cairo_t *cr,
- cairo_surface_t *surface,
- int width,
- int height);
+cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents);
/* Query functions */
-/* XXX: It would be nice if I could find a simpler way to make the
- definitions for the deprecated functions. Ideally, I would just
- have to put DEPRECATE (cairo_get_operator, cairo_current_operator)
- into one file and be done with it. For now, I've got a little more
- typing than that. */
-
cairo_operator_t
-cairo_current_operator (cairo_t *cr);
+cairo_get_operator (cairo_t *cr);
-void
-cairo_current_rgb_color (cairo_t *cr, double *red, double *green, double *blue);
cairo_pattern_t *
-cairo_current_pattern (cairo_t *cr);
-
-double
-cairo_current_alpha (cairo_t *cr);
-
-/* XXX: Do we want cairo_current_pattern as well? */
+cairo_get_source (cairo_t *cr);
double
-cairo_current_tolerance (cairo_t *cr);
+cairo_get_tolerance (cairo_t *cr);
void
-cairo_current_point (cairo_t *cr, double *x, double *y);
+cairo_get_current_point (cairo_t *cr, double *x, double *y);
cairo_fill_rule_t
-cairo_current_fill_rule (cairo_t *cr);
+cairo_get_fill_rule (cairo_t *cr);
double
-cairo_current_line_width (cairo_t *cr);
+cairo_get_line_width (cairo_t *cr);
cairo_line_cap_t
-cairo_current_line_cap (cairo_t *cr);
+cairo_get_line_cap (cairo_t *cr);
cairo_line_join_t
-cairo_current_line_join (cairo_t *cr);
+cairo_get_line_join (cairo_t *cr);
double
-cairo_current_miter_limit (cairo_t *cr);
+cairo_get_miter_limit (cairo_t *cr);
-/* XXX: How to do cairo_current_dash??? Do we want to switch to a cairo_dash object? */
+/* XXX: How to do cairo_get_dash??? Do we want to switch to a cairo_dash object? */
void
-cairo_current_matrix (cairo_t *cr, cairo_matrix_t *matrix);
+cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix);
-/* XXX: Need to decide the memory mangement semantics of this
+/* XXX: Need to decide the memory management semantics of this
function. Should it reference the surface again? */
cairo_surface_t *
-cairo_current_target_surface (cairo_t *cr);
+cairo_get_target (cairo_t *cr);
-typedef void (cairo_move_to_func_t) (void *closure,
- double x, double y);
+/**
+ * cairo_path_data_t:
+ *
+ * A data structure for holding path data---appears within
+ * #cairo_path_t.
+ *
+ * The data structure is designed to try to balance the demands of
+ * efficiency and ease-of-use. A path is represented as an array of
+ * cairo_path_data_t which is a union of headers and points.
+ *
+ * Each portion of the path is represented by one or more elements in
+ * the array, (one header followed by 0 or more points). The length
+ * value of the header is the number of array elements for the current
+ * portion including the header, (ie. length == 1 + # of points), and
+ * where the number of points for each element type must be as
+ * follows:
+ *
+ * CAIRO_PATH_MOVE_TO: 1 point
+ * CAIRO_PATH_LINE_TO: 1 point
+ * CAIRO_PATH_CURVE_TO: 3 points
+ * CAIRO_PATH_CLOSE_PATH: 0 points
+ *
+ * The semantics and ordering of the coordinate values are consistent
+ * with cairo_move_to(), cairo_line_to(), cairo_curve_to(), and
+ * cairo_close_path().
+ *
+ * Here is sample code for iterating through a #cairo_path_t:
+ *
+ * <informalexample><programlisting>
+ * int i;
+ * cairo_path_t *path;
+ * cairo_path_data_t *data;
+ *
+ * path = cairo_copy_path (cr);
+ *
+ * for (i=0; i < path->num_data; i += path->data[i].header.length) {
+ * data = &path->data[i];
+ * switch (data->header.type) {
+ * case CAIRO_PATH_MOVE_TO:
+ * do_move_to_things (data[1].point.x, data[1].point.y);
+ * break;
+ * case CAIRO_PATH_LINE_TO:
+ * do_line_to_things (data[1].point.x, data[1].point.y);
+ * break;
+ * case CAIRO_PATH_CURVE_TO:
+ * do_curve_to_things (data[1].point.x, data[1].point.y,
+ * data[2].point.x, data[2].point.y,
+ * data[3].point.x, data[3].point.y);
+ * break;
+ * case CAIRO_PATH_CLOSE_PATH:
+ * do_close_path_things ();
+ * break;
+ * }
+ * }
+ *
+ * cairo_path_destroy (path);
+ * </programlisting></informalexample>
+ */
+typedef union {
+ struct {
+ enum {
+ CAIRO_PATH_MOVE_TO,
+ CAIRO_PATH_LINE_TO,
+ CAIRO_PATH_CURVE_TO,
+ CAIRO_PATH_CLOSE_PATH
+ } type;
+ int length;
+ } header;
+ struct {
+ double x, y;
+ } point;
+} cairo_path_data_t;
-typedef void (cairo_line_to_func_t) (void *closure,
- double x, double y);
+/**
+ * cairo_path_t:
+ *
+ * A data structure for holding a path. This data structure serves as
+ * the return value for cairo_copy_path_data() and
+ * cairo_copy_path_data_flat() as well the input value for
+ * cairo_append_path().
+ *
+ * See #cairo_path_data_t for hints on how to iterate over the
+ * actual data within the path.
+ *
+ * The num_data member gives the number of elements in the data
+ * array. This number is larger than the number of independent path
+ * portions (MOVE_TO, LINE_TO, CURVE_TO, CLOSE_PATH), since the data
+ * includes both headers and coordinates for each portion.
+ **/
+typedef struct cairo_path {
+ cairo_path_data_t *data;
+ int num_data;
+} cairo_path_t;
-typedef void (cairo_curve_to_func_t) (void *closure,
- double x1, double y1,
- double x2, double y2,
- double x3, double y3);
+cairo_path_t *
+cairo_copy_path (cairo_t *cr);
-typedef void (cairo_close_path_func_t) (void *closure);
+cairo_path_t *
+cairo_copy_path_flat (cairo_t *cr);
-extern void
-cairo_current_path (cairo_t *cr,
- cairo_move_to_func_t *move_to,
- cairo_line_to_func_t *line_to,
- cairo_curve_to_func_t *curve_to,
- cairo_close_path_func_t *close_path,
- void *closure);
+void
+cairo_append_path (cairo_t *cr,
+ cairo_path_t *path);
-extern void
-cairo_current_path_flat (cairo_t *cr,
- cairo_move_to_func_t *move_to,
- cairo_line_to_func_t *line_to,
- cairo_close_path_func_t *close_path,
- void *closure);
+void
+cairo_path_destroy (cairo_path_t *path);
/* Error status queries */
@@ -706,17 +888,38 @@ const char *
cairo_status_string (cairo_t *cr);
/* Surface manipulation */
-/* XXX: We may want to rename this function in light of the new
- virtualized surface backends... */
-cairo_surface_t *
-cairo_surface_create_for_image (char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride);
+
+/**
+ * cairo_format_t
+ * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with
+ * alpha in the upper 8 bits, then red, then green, then blue.
+ * The 32-bit quantities are stored native-endian. Pre-multiplied
+ * alpha is used. (That is, 50% transparent red is 0x80800000,
+ * not 0x80ff0000.)
+ * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with
+ * the upper 8 bits unused. Red, Green, and Blue are stored
+ * in the remaining 24 bits in that order.
+ * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding
+ * an alpha value.
+ * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding
+ * an alpha value. Pixels are packed together into 32-bit
+ * quantities. The ordering of the bits matches the
+ * endianess of the platform. On a big-endian machine, the
+ * first pixel is in the uppermost bit, on a little-endian
+ * machine the first pixel is in the least-significant bit.
+ *
+ * #cairo_format_t is used to identify the memory format of
+ * image data.
+ */
+typedef enum cairo_format {
+ CAIRO_FORMAT_ARGB32,
+ CAIRO_FORMAT_RGB24,
+ CAIRO_FORMAT_A8,
+ CAIRO_FORMAT_A1
+} cairo_format_t;
/* XXX: I want to remove this function, (replace with
- cairo_set_target_scratch or similar). */
+ cairo_begin_group and friends). */
cairo_surface_t *
cairo_surface_create_similar (cairo_surface_t *other,
cairo_format_t format,
@@ -729,35 +932,36 @@ cairo_surface_reference (cairo_surface_t *surface);
void
cairo_surface_destroy (cairo_surface_t *surface);
-/* XXX: Note: The current Render/Ic implementations don't do the right
- thing with repeat when the surface has a non-identity matrix. */
-/* XXX: Rework this as a cairo function with an enum: cairo_set_pattern_extend */
cairo_status_t
-cairo_surface_set_repeat (cairo_surface_t *surface, int repeat);
+cairo_surface_finish (cairo_surface_t *surface);
+
+#if CAIRO_HAS_PNG_FUNCTIONS
-/* XXX: Rework this as a cairo function: cairo_set_pattern_transform */
cairo_status_t
-cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix);
+cairo_surface_write_to_png (cairo_surface_t *surface,
+ const char *filename);
-/* XXX: Rework this as a cairo function: cairo_current_pattern_transform */
cairo_status_t
-cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix);
+cairo_surface_write_to_png_stream (cairo_surface_t *surface,
+ cairo_write_func_t write_func,
+ void *closure);
+
+#endif
+
+void *
+cairo_surface_get_user_data (cairo_surface_t *surface,
+ const cairo_user_data_key_t *key);
-typedef enum {
- CAIRO_FILTER_FAST,
- CAIRO_FILTER_GOOD,
- CAIRO_FILTER_BEST,
- CAIRO_FILTER_NEAREST,
- CAIRO_FILTER_BILINEAR,
- CAIRO_FILTER_GAUSSIAN
-} cairo_filter_t;
-
-/* XXX: Rework this as a cairo function: cairo_set_pattern_filter */
cairo_status_t
-cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter);
+cairo_surface_set_user_data (cairo_surface_t *surface,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy);
-cairo_filter_t
-cairo_surface_get_filter (cairo_surface_t *surface);
+void
+cairo_surface_set_device_offset (cairo_surface_t *surface,
+ double x_offset,
+ double y_offset);
/* Image-surface functions */
@@ -767,12 +971,29 @@ cairo_image_surface_create (cairo_format_t format,
int height);
cairo_surface_t *
-cairo_image_surface_create_for_data (char *data,
+cairo_image_surface_create_for_data (unsigned char *data,
cairo_format_t format,
int width,
int height,
int stride);
+int
+cairo_image_surface_get_width (cairo_surface_t *surface);
+
+int
+cairo_image_surface_get_height (cairo_surface_t *surface);
+
+#if CAIRO_HAS_PNG_FUNCTIONS
+
+cairo_surface_t *
+cairo_image_surface_create_from_png (const char *filename);
+
+cairo_surface_t *
+cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
+ void *closure);
+
+#endif
+
/* Pattern creation functions */
cairo_pattern_t *
cairo_pattern_create_for_surface (cairo_surface_t *surface);
@@ -792,16 +1013,23 @@ void
cairo_pattern_destroy (cairo_pattern_t *pattern);
cairo_status_t
-cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
- double offset,
- double red, double green, double blue,
- double alpha);
-
+cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern,
+ double offset,
+ double red, double green, double blue);
+
cairo_status_t
-cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix);
+cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern,
+ double offset,
+ double red, double green, double blue,
+ double alpha);
cairo_status_t
-cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix);
+cairo_pattern_set_matrix (cairo_pattern_t *pattern,
+ const cairo_matrix_t *matrix);
+
+cairo_status_t
+cairo_pattern_get_matrix (cairo_pattern_t *pattern,
+ cairo_matrix_t *matrix);
typedef enum {
CAIRO_EXTEND_NONE,
@@ -815,6 +1043,15 @@ cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend);
cairo_extend_t
cairo_pattern_get_extend (cairo_pattern_t *pattern);
+typedef enum {
+ CAIRO_FILTER_FAST,
+ CAIRO_FILTER_GOOD,
+ CAIRO_FILTER_BEST,
+ CAIRO_FILTER_NEAREST,
+ CAIRO_FILTER_BILINEAR,
+ CAIRO_FILTER_GAUSSIAN
+} cairo_filter_t;
+
cairo_status_t
cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter);
@@ -823,72 +1060,135 @@ cairo_pattern_get_filter (cairo_pattern_t *pattern);
/* Matrix functions */
-/* XXX: Rename all of these to cairo_transform_t */
-
-cairo_matrix_t *
-cairo_matrix_create (void);
-
void
-cairo_matrix_destroy (cairo_matrix_t *matrix);
+cairo_matrix_init (cairo_matrix_t *matrix,
+ double xx, double yx,
+ double xy, double yy,
+ double x0, double y0);
-cairo_status_t
-cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other);
+void
+cairo_matrix_init_identity (cairo_matrix_t *matrix);
-cairo_status_t
-cairo_matrix_set_identity (cairo_matrix_t *matrix);
+void
+cairo_matrix_init_translate (cairo_matrix_t *matrix,
+ double tx, double ty);
-cairo_status_t
-cairo_matrix_set_affine (cairo_matrix_t *matrix,
- double a, double b,
- double c, double d,
- double tx, double ty);
+void
+cairo_matrix_init_scale (cairo_matrix_t *matrix,
+ double sx, double sy);
-cairo_status_t
-cairo_matrix_get_affine (cairo_matrix_t *matrix,
- double *a, double *b,
- double *c, double *d,
- double *tx, double *ty);
+void
+cairo_matrix_init_rotate (cairo_matrix_t *matrix,
+ double radians);
-cairo_status_t
+void
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty);
-cairo_status_t
+void
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy);
-cairo_status_t
+void
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians);
cairo_status_t
cairo_matrix_invert (cairo_matrix_t *matrix);
-cairo_status_t
-cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b);
+void
+cairo_matrix_multiply (cairo_matrix_t *result,
+ const cairo_matrix_t *a,
+ const cairo_matrix_t *b);
-cairo_status_t
-cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy);
+/* XXX: Need a new name here perhaps. */
+void
+cairo_matrix_transform_distance (const cairo_matrix_t *matrix,
+ double *dx, double *dy);
-cairo_status_t
-cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y);
+/* XXX: Need a new name here perhaps. */
+void
+cairo_matrix_transform_point (const cairo_matrix_t *matrix,
+ double *x, double *y);
-/* Deprecated functions. We've made some effort to allow the
- deprecated functions to continue to work for now, (with useful
- warnings). But the deprecated functions will not appear in the next
- release. */
#ifndef _CAIROINT_H_
-#define cairo_get_operator cairo_get_operator_DEPRECATED_BY_cairo_current_operator
-#define cairo_get_rgb_color cairo_get_rgb_color_DEPRECATED_BY_cairo_current_rgb_color
-#define cairo_get_alpha cairo_get_alpha_DEPRECATED_BY_cairo_current_alpha
-#define cairo_get_tolerance cairo_get_tolerance_DEPRECATED_BY_cairo_current_tolerance
-#define cairo_get_current_point cairo_get_current_point_DEPRECATED_BY_cairo_current_point
-#define cairo_get_fill_rule cairo_get_fill_rule_DEPRECATED_BY_cairo_current_fill_rule
-#define cairo_get_line_width cairo_get_line_width_DEPRECATED_BY_cairo_current_line_width
-#define cairo_get_line_cap cairo_get_line_cap_DEPRECATED_BY_cairo_current_line_cap
-#define cairo_get_line_join cairo_get_line_join_DEPRECATED_BY_cairo_current_line_join
-#define cairo_get_miter_limit cairo_get_miter_limit_DEPRECATED_BY_cairo_current_miter_limit
-#define cairo_get_matrix cairo_get_matrix_DEPRECATED_BY_cairo_current_matrix
-#define cairo_get_target_surface cairo_get_target_surface_DEPRECATED_BY_cairo_current_target_surface
-#define cairo_get_status cairo_get_status_DEPRECATED_BY_cairo_status
-#define cairo_get_status_string cairo_get_status_string_DEPRECATED_BY_cairo_status_string
+
+/* Obsolete functions. These definitions exist to coerce the compiler
+ * into providing a little bit of guidance with its error
+ * messages. The idea is to help users port their old code without
+ * having to dig through lots of documentation.
+ *
+ * The first set of REPLACED_BY functions is for functions whose names
+ * have just been changed. So fixing these up is mechanical, (and
+ * automated by means of the cairo/util/cairo-api-update script.
+ *
+ * The second set of DEPRECATED_BY functions is for functions where
+ * the replacement is used in a different way, (ie. different
+ * arguments, multiple functions instead of one, etc). Fixing these up
+ * will require a bit more work on the user's part, (and hopefully we
+ * can get cairo-api-update to find these and print some guiding
+ * information).
+ */
+#define cairo_current_font_extents cairo_current_font_extents_REPLACED_BY_cairo_font_extents
+#define cairo_get_font_extents cairo_get_font_extents_REPLACED_BY_cairo_font_extents
+#define cairo_current_operator cairo_current_operator_REPLACED_BY_cairo_get_operator
+#define cairo_current_tolerance cairo_current_tolerance_REPLACED_BY_cairo_get_tolerance
+#define cairo_current_point cairo_current_point_REPLACED_BY_cairo_get_current_point
+#define cairo_current_fill_rule cairo_current_fill_rule_REPLACED_BY_cairo_get_fill_rule
+#define cairo_current_line_width cairo_current_line_width_REPLACED_BY_cairo_get_line_width
+#define cairo_current_line_cap cairo_current_line_cap_REPLACED_BY_cairo_get_line_cap
+#define cairo_current_line_join cairo_current_line_join_REPLACED_BY_cairo_get_line_join
+#define cairo_current_miter_limit cairo_current_miter_limit_REPLACED_BY_cairo_get_miter_limit
+#define cairo_current_matrix cairo_current_matrix_REPLACED_BY_cairo_get_matrix
+#define cairo_current_target_surface cairo_current_target_surface_REPLACED_BY_cairo_get_target
+#define cairo_get_status cairo_get_status_REPLACED_BY_cairo_status
+#define cairo_get_status_string cairo_get_status_string_REPLACED_BY_cairo_status_string
+#define cairo_concat_matrix cairo_concat_matrix_REPLACED_BY_cairo_transform
+#define cairo_scale_font cairo_scale_font_REPLACED_BY_cairo_set_font_size
+#define cairo_select_font cairo_select_font_REPLACED_BY_cairo_select_font_face
+#define cairo_transform_font cairo_transform_font_REPLACED_BY_cairo_set_font_matrix
+#define cairo_transform_point cairo_transform_point_REPLACED_BY_cairo_user_to_device
+#define cairo_transform_distance cairo_transform_distance_REPLACED_BY_cairo_user_to_device_distance
+#define cairo_inverse_transform_point cairo_inverse_transform_point_REPLACED_BY_cairo_device_to_user
+#define cairo_inverse_transform_distance cairo_inverse_transform_distance_REPLACED_BY_cairo_device_to_user_distance
+#define cairo_init_clip cairo_init_clip_REPLACED_BY_cairo_reset_clip
+#define cairo_surface_create_for_image cairo_surface_create_for_image_REPLACED_BY_cairo_image_surface_create_for_data
+#define cairo_default_matrix cairo_default_matrix_REPLACED_BY_cairo_identity_matrix
+#define cairo_matrix_set_affine cairo_matrix_set_affine_REPLACED_BY_cairo_matrix_init
+#define cairo_matrix_set_identity cairo_matrix_set_identity_REPLACED_BY_cairo_matrix_init_identity
+#define cairo_pattern_add_color_stop cairo_pattern_add_color_stop_REPLACED_BY_cairo_pattern_add_color_stop_rgba
+#define cairo_set_rgb_color cairo_set_rgb_color_REPLACED_BY_cairo_set_source_rgb
+#define cairo_set_pattern cairo_set_pattern_REPLACED_BY_cairo_set_source
+#define cairo_xlib_surface_create_for_pixmap_with_visual cairo_xlib_surface_create_for_pixmap_with_visual_REPLACED_BY_cairo_xlib_surface_create
+#define cairo_xlib_surface_create_for_window_with_visual cairo_xlib_surface_create_for_window_with_visual_REPLACED_BY_cairo_xlib_surface_create
+#define cairo_xcb_surface_create_for_pixmap_with_visual cairo_xcb_surface_create_for_pixmap_with_visual_REPLACED_BY_cairo_xcb_surface_create
+#define cairo_xcb_surface_create_for_window_with_visual cairo_xcb_surface_create_for_window_with_visual_REPLACED_BY_cairo_xcb_surface_create
+
+
+#define cairo_current_path cairo_current_path_DEPRECATED_BY_cairo_copy_path
+#define cairo_current_path_flat cairo_current_path_flat_DEPRECATED_BY_cairo_copy_path_flat
+#define cairo_get_path cairo_get_path_DEPRECATED_BY_cairo_copy_path
+#define cairo_get_path_flat cairo_get_path_flat_DEPRECATED_BY_cairo_get_path_flat
+#define cairo_set_alpha cairo_set_alpha_DEPRECATED_BY_cairo_set_source_rgba_OR_cairo_paint_with_alpha
+#define cairo_show_surface cairo_show_surface_DEPRECATED_BY_cairo_set_source_surface_AND_cairo_paint
+#define cairo_copy cairo_copy_DEPRECATED_BY_cairo_create_AND_MANY_INDIVIDUAL_FUNCTIONS
+#define cairo_surface_set_repeat cairo_surface_set_repeat_DEPRECATED_BY_cairo_pattern_set_extend
+#define cairo_surface_set_matrix cairo_surface_set_matrix_DEPRECATED_BY_cairo_pattern_set_matrix
+#define cairo_surface_get_matrix cairo_surface_get_matrix_DEPRECATED_BY_cairo_pattern_get_matrix
+#define cairo_surface_set_filter cairo_surface_set_filter_DEPRECATED_BY_cairo_pattern_set_filter
+#define cairo_surface_get_filter cairo_surface_get_filter_DEPRECATED_BY_cairo_pattern_get_filter
+#define cairo_matrix_create cairo_matrix_create_DEPRECATED_BY_cairo_matrix_t
+#define cairo_matrix_destroy cairo_matrix_destroy_DEPRECATED_BY_cairo_matrix_t
+#define cairo_matrix_copy cairo_matrix_copy_DEPRECATED_BY_cairo_matrix_t
+#define cairo_matrix_get_affine cairo_matrix_get_affine_DEPRECATED_BY_cairo_matrix_t
+#define cairo_set_target_surface cairo_set_target_surface_DEPRECATED_BY_cairo_create
+#define cairo_set_target_glitz cairo_set_target_glitz_DEPRECATED_BY_cairo_glitz_surface_create
+#define cairo_set_target_image cairo_set_target_image_DEPRECATED_BY_cairo_image_surface_create_for_data
+#define cairo_set_target_pdf cairo_set_target_pdf_DEPRECATED_BY_cairo_pdf_surface_create
+#define cairo_set_target_png cairo_set_target_png_DEPRECATED_BY_cairo_surface_write_to_png
+#define cairo_set_target_ps cairo_set_target_ps_DEPRECATED_BY_cairo_ps_surface_create
+#define cairo_set_target_quartz cairo_set_target_quartz_DEPRECATED_BY_cairo_quartz_surface_create
+#define cairo_set_target_win32 cairo_set_target_win32_DEPRECATED_BY_cairo_win32_surface_create
+#define cairo_set_target_xcb cairo_set_target_xcb_DEPRECATED_BY_cairo_xcb_surface_create
+#define cairo_set_target_drawable cairo_set_target_drawable_DEPRECATED_BY_cairo_xlib_surface_create
+
#endif
CAIRO_END_DECLS
diff --git a/src/cairo_array.c b/src/cairo_array.c
deleted file mode 100644
index 2b1cf9d61..000000000
--- a/src/cairo_array.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/* 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
deleted file mode 100644
index cb4b1c5d7..000000000
--- a/src/cairo_atsui_font.c
+++ /dev/null
@@ -1,807 +0,0 @@
-/* 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
deleted file mode 100644
index d1ad5a4e2..000000000
--- a/src/cairo_cache.c
+++ /dev/null
@@ -1,518 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * This file is Copyright © 2004 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Red Hat, Inc.
- *
- * Contributor(s):
- * Keith Packard
- * Graydon Hoare <graydon@redhat.com>
- */
-
-#include "cairoint.h"
-
-/*
- * This structure, and accompanying table, is borrowed/modified from the
- * file xserver/render/glyph.c in the freedesktop.org x server, with
- * permission (and suggested modification of doubling sizes) by Keith
- * Packard.
- */
-
-static const cairo_cache_arrangement_t cache_arrangements [] = {
- { 16, 43, 41 },
- { 32, 73, 71 },
- { 64, 151, 149 },
- { 128, 283, 281 },
- { 256, 571, 569 },
- { 512, 1153, 1151 },
- { 1024, 2269, 2267 },
- { 2048, 4519, 4517 },
- { 4096, 9013, 9011 },
- { 8192, 18043, 18041 },
- { 16384, 36109, 36107 },
- { 32768, 72091, 72089 },
- { 65536, 144409, 144407 },
- { 131072, 288361, 288359 },
- { 262144, 576883, 576881 },
- { 524288, 1153459, 1153457 },
- { 1048576, 2307163, 2307161 },
- { 2097152, 4613893, 4613891 },
- { 4194304, 9227641, 9227639 },
- { 8388608, 18455029, 18455027 },
- { 16777216, 36911011, 36911009 },
- { 33554432, 73819861, 73819859 },
- { 67108864, 147639589, 147639587 },
- { 134217728, 295279081, 295279079 },
- { 268435456, 590559793, 590559791 }
-};
-
-#define N_CACHE_SIZES (sizeof(cache_arrangements)/sizeof(cache_arrangements[0]))
-
-/*
- * Entries 'e' are poiners, in one of 3 states:
- *
- * e == NULL: The entry has never had anything put in it
- * e != DEAD_ENTRY: The entry has an active value in it currently
- * e == DEAD_ENTRY: The entry *had* a value in it at some point, but the
- * entry has been killed. Lookups requesting free space can
- * reuse these entries; lookups requesting a precise match
- * should neither return these entries nor stop searching when
- * seeing these entries.
- *
- * We expect keys will not be destroyed frequently, so our table does not
- * contain any explicit shrinking code nor any chain-coalescing code for
- * entries randomly deleted by memory pressure (except during rehashing, of
- * course). These assumptions are potentially bad, but they make the
- * implementation straightforward.
- *
- * Revisit later if evidence appears that we're using excessive memory from
- * a mostly-dead table.
- *
- * Generally you do not need to worry about freeing cache entries; the
- * cache will expire entries randomly as it experiences memory pressure.
- * If max_memory is set, entries are not expired, and must be explicitely
- * removed.
- *
- * This table is open-addressed with double hashing. Each table size is a
- * prime chosen to be a little more than double the high water mark for a
- * given arrangement, so the tables should remain < 50% full. The table
- * size makes for the "first" hash modulus; a second prime (2 less than the
- * first prime) serves as the "second" hash modulus, which is co-prime and
- * thus guarantees a complete permutation of table indices.
- *
- */
-
-#define DEAD_ENTRY ((cairo_cache_entry_base_t *) 1)
-#define NULL_ENTRY_P(cache, i) ((cache)->entries[i] == NULL)
-#define DEAD_ENTRY_P(cache, i) ((cache)->entries[i] == DEAD_ENTRY)
-#define LIVE_ENTRY_P(cache, i) \
- (!((NULL_ENTRY_P((cache),(i))) || (DEAD_ENTRY_P((cache),(i)))))
-
-#ifdef CAIRO_DO_SANITY_CHECKING
-static void
-_cache_sane_state (cairo_cache_t *cache)
-{
- assert (cache != NULL);
- assert (cache->entries != NULL);
- assert (cache->backend != NULL);
- assert (cache->arrangement != NULL);
- /* 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)
-#endif
-
-static void
-_entry_destroy (cairo_cache_t *cache, unsigned long i)
-{
- _cache_sane_state (cache);
-
- if (LIVE_ENTRY_P(cache, i))
- {
- cairo_cache_entry_base_t *entry = cache->entries[i];
- assert(cache->live_entries > 0);
- assert(cache->used_memory >= entry->memory);
-
- cache->live_entries--;
- cache->used_memory -= entry->memory;
- cache->backend->destroy_entry (cache, entry);
- cache->entries[i] = DEAD_ENTRY;
- }
-}
-
-static cairo_cache_entry_base_t **
-_cache_lookup (cairo_cache_t *cache,
- void *key,
- int (*predicate)(void*,void*,void*))
-{
-
- cairo_cache_entry_base_t **probe;
- unsigned long hash;
- unsigned long table_size, i, idx, step;
-
- _cache_sane_state (cache);
- assert (key != NULL);
-
- table_size = cache->arrangement->size;
- hash = cache->backend->hash (cache, key);
- idx = hash % table_size;
- step = 0;
-
- for (i = 0; i < table_size; ++i)
- {
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
- cache->probes++;
-#endif
- assert(idx < table_size);
- probe = cache->entries + idx;
-
- /*
- * There are two lookup modes: searching for a free slot and searching
- * for an exact entry.
- */
-
- if (predicate != NULL)
- {
- /* We are looking up an exact entry. */
- if (*probe == NULL)
- /* 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
- {
- /* We are just looking for a free slot. */
- if (*probe == NULL
- || *probe == DEAD_ENTRY)
- return probe;
- }
-
- if (step == 0) {
- step = hash % cache->arrangement->rehash;
- if (step == 0)
- step = 1;
- }
-
- idx += step;
- if (idx >= table_size)
- idx -= table_size;
- }
-
- /*
- * The table should not have permitted you to get here if you were just
- * looking for a free slot: there should have been room.
- */
- assert(predicate != NULL);
- return NULL;
-}
-
-static cairo_cache_entry_base_t **
-_find_available_entry_for (cairo_cache_t *cache,
- void *key)
-{
- return _cache_lookup (cache, key, NULL);
-}
-
-static cairo_cache_entry_base_t **
-_find_exact_live_entry_for (cairo_cache_t *cache,
- void *key)
-{
- return _cache_lookup (cache, key, cache->backend->keys_equal);
-}
-
-static const cairo_cache_arrangement_t *
-_find_cache_arrangement (unsigned long proposed_size)
-{
- unsigned long idx;
-
- for (idx = 0; idx < N_CACHE_SIZES; ++idx)
- if (cache_arrangements[idx].high_water_mark >= proposed_size)
- return &cache_arrangements[idx];
- return NULL;
-}
-
-static cairo_status_t
-_resize_cache (cairo_cache_t *cache, unsigned long proposed_size)
-{
- cairo_cache_t tmp;
- cairo_cache_entry_base_t **e;
- unsigned long new_size, i;
-
- tmp = *cache;
- tmp.arrangement = _find_cache_arrangement (proposed_size);
- assert(tmp.arrangement != NULL);
- if (tmp.arrangement == cache->arrangement)
- return CAIRO_STATUS_SUCCESS;
-
- new_size = tmp.arrangement->size;
- tmp.entries = calloc (new_size, sizeof (cairo_cache_entry_base_t *));
- if (tmp.entries == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < cache->arrangement->size; ++i) {
- if (LIVE_ENTRY_P(cache, i)) {
- e = _find_available_entry_for (&tmp, cache->entries[i]);
- assert (e != NULL);
- *e = cache->entries[i];
- }
- }
- free (cache->entries);
- cache->entries = tmp.entries;
- cache->arrangement = tmp.arrangement;
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
-static double
-_load_factor (cairo_cache_t *cache)
-{
- return ((double) cache->live_entries)
- / ((double) cache->arrangement->size);
-}
-#endif
-
-/* Find a random in the cache matching the given predicate. We use the
- * same algorithm as the probing algorithm to walk over the entries in
- * the hash table in a pseudo-random order. Walking linearly would
- * favor entries following gaps in the hash table. We could also
- * call rand() repeatedly, which works well for almost-full tables,
- * but degrades when the table is almost empty, or predicate
- * returns false for most entries.
- */
-static cairo_cache_entry_base_t **
-_random_entry (cairo_cache_t *cache,
- int (*predicate)(void*))
-{
- cairo_cache_entry_base_t **probe;
- unsigned long hash;
- unsigned long table_size, i, idx, step;
-
- _cache_sane_state (cache);
-
- table_size = cache->arrangement->size;
- hash = rand ();
- idx = hash % table_size;
- step = 0;
-
- for (i = 0; i < table_size; ++i)
- {
- assert(idx < table_size);
- probe = cache->entries + idx;
-
- if (LIVE_ENTRY_P(cache, idx)
- && (!predicate || predicate (*probe)))
- return probe;
-
- if (step == 0) {
- step = hash % cache->arrangement->rehash;
- if (step == 0)
- step = 1;
- }
-
- idx += step;
- if (idx >= table_size)
- idx -= table_size;
- }
-
- return NULL;
-}
-
-/* public API follows */
-
-cairo_status_t
-_cairo_cache_init (cairo_cache_t *cache,
- const cairo_cache_backend_t *backend,
- unsigned long max_memory)
-{
- assert (backend != NULL);
-
- if (cache != NULL){
- cache->arrangement = &cache_arrangements[0];
- cache->refcount = 1;
- cache->max_memory = max_memory;
- cache->used_memory = 0;
- cache->live_entries = 0;
-
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
- cache->hits = 0;
- cache->misses = 0;
- cache->probes = 0;
-#endif
-
- cache->backend = backend;
- cache->entries = calloc (sizeof(cairo_cache_entry_base_t *),
- cache->arrangement->size);
- if (cache->entries == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- }
- _cache_sane_state (cache);
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_cache_reference (cairo_cache_t *cache)
-{
- _cache_sane_state (cache);
- cache->refcount++;
-}
-
-void
-_cairo_cache_destroy (cairo_cache_t *cache)
-{
- unsigned long i;
- if (cache != NULL) {
-
- _cache_sane_state (cache);
-
- if (--cache->refcount > 0)
- return;
-
- for (i = 0; i < cache->arrangement->size; ++i) {
- _entry_destroy (cache, i);
- }
-
- free (cache->entries);
- cache->entries = NULL;
- cache->backend->destroy_cache (cache);
- }
-}
-
-cairo_status_t
-_cairo_cache_lookup (cairo_cache_t *cache,
- void *key,
- void **entry_return,
- int *created_entry)
-{
-
- unsigned long idx;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_cache_entry_base_t **slot = NULL, *new_entry;
-
- _cache_sane_state (cache);
-
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
- if ((cache->hits + cache->misses) % 0xffff == 0)
- printf("cache %p stats: size %ld, live %ld, load %.2f\n"
- " mem %ld/%ld, hit %ld, miss %ld\n"
- " probe %ld, %.2f probe/access\n",
- cache,
- cache->arrangement->size,
- cache->live_entries,
- _load_factor (cache),
- cache->used_memory,
- cache->max_memory,
- cache->hits,
- cache->misses,
- cache->probes,
- ((double) cache->probes)
- / ((double) (cache->hits +
- cache->misses + 1)));
-#endif
-
- /* See if we have an entry in the table already. */
- slot = _find_exact_live_entry_for (cache, key);
- if (slot != NULL) {
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
- cache->hits++;
-#endif
- *entry_return = *slot;
- if (created_entry)
- *created_entry = 0;
- return status;
- }
-
-#ifdef CAIRO_MEASURE_CACHE_PERFORMANCE
- cache->misses++;
-#endif
-
- /* Build the new entry. */
- status = cache->backend->create_entry (cache, key,
- (void **)&new_entry);
- if (status != CAIRO_STATUS_SUCCESS)
- return status;
-
- /* Store the hash value in case the backend forgot. */
- new_entry->hashcode = cache->backend->hash (cache, key);
-
- /* Make some entries die if we're under memory pressure. */
- while (cache->live_entries > 0 &&
- cache->max_memory > 0 &&
- ((cache->max_memory - cache->used_memory) < new_entry->memory)) {
- idx = _random_entry (cache, NULL) - cache->entries;
- assert (idx < cache->arrangement->size);
- _entry_destroy (cache, idx);
- }
-
- /* 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);
- if (status != CAIRO_STATUS_SUCCESS) {
- cache->backend->destroy_entry (cache, new_entry);
- return status;
- }
-
- slot = _find_available_entry_for (cache, key);
- assert(slot != NULL);
-
- /* Store entry in slot and increment statistics. */
- *slot = new_entry;
- cache->live_entries++;
- cache->used_memory += new_entry->memory;
-
- _cache_sane_state (cache);
-
- *entry_return = new_entry;
- if (created_entry)
- *created_entry = 1;
-
- return status;
-}
-
-cairo_status_t
-_cairo_cache_remove (cairo_cache_t *cache,
- void *key)
-{
- cairo_cache_entry_base_t **slot;
-
- _cache_sane_state (cache);
-
- /* See if we have an entry in the table already. */
- slot = _find_exact_live_entry_for (cache, key);
- if (slot != NULL)
- _entry_destroy (cache, slot - cache->entries);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void *
-_cairo_cache_random_entry (cairo_cache_t *cache,
- int (*predicate)(void*))
-{
- cairo_cache_entry_base_t **slot = _random_entry (cache, predicate);
-
- return slot ? *slot : NULL;
-}
-
-unsigned long
-_cairo_hash_string (const char *c)
-{
- /* This is the djb2 hash. */
- unsigned long hash = 5381;
- while (*c)
- hash = ((hash << 5) + hash) + *c++;
- return hash;
-}
-
diff --git a/src/cairo_font.c b/src/cairo_font.c
deleted file mode 100644
index 529c1c7c3..000000000
--- a/src/cairo_font.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- * Copyright © 2005 Red Hat Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * 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@cworth.org>
- * Graydon Hoare <graydon@redhat.com>
- * Owen Taylor <otaylor@redhat.com>
- */
-
-#include "cairoint.h"
-
-/* Now the internal "unscaled + scale" font API */
-
-cairo_private cairo_status_t
-_cairo_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *sc,
- cairo_font_t **font)
-{
- const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT;
-
- return backend->create (family, slant, weight, sc, font);
-}
-
-void
-_cairo_font_init (cairo_font_t *font,
- cairo_font_scale_t *scale,
- const cairo_font_backend_t *backend)
-{
- font->scale = *scale;
- font->refcount = 1;
- font->backend = backend;
-}
-
-void
-_cairo_unscaled_font_init (cairo_unscaled_font_t *font,
- const cairo_font_backend_t *backend)
-{
- font->refcount = 1;
- font->backend = backend;
-}
-
-cairo_status_t
-_cairo_font_text_to_glyphs (cairo_font_t *font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
-{
- return font->backend->text_to_glyphs (font, utf8, glyphs, num_glyphs);
-}
-
-cairo_status_t
-_cairo_font_glyph_extents (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- return font->backend->glyph_extents(font, glyphs, num_glyphs, extents);
-}
-
-
-cairo_status_t
-_cairo_font_glyph_bbox (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
-{
- return font->backend->glyph_bbox (font, glyphs, num_glyphs, bbox);
-}
-
-cairo_status_t
-_cairo_font_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_status_t status;
- if (surface->backend->show_glyphs != NULL) {
- status = surface->backend->show_glyphs (font, operator, pattern,
- surface,
- source_x, source_y,
- dest_x, dest_y,
- width, height,
- glyphs, num_glyphs);
- if (status == CAIRO_STATUS_SUCCESS)
- return status;
- }
-
- /* Surface display routine either does not exist or failed. */
- return font->backend->show_glyphs (font, operator, pattern,
- surface,
- source_x, source_y,
- dest_x, dest_y,
- width, height,
- glyphs, num_glyphs);
-}
-
-cairo_status_t
-_cairo_font_glyph_path (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
-{
- return font->backend->glyph_path (font, glyphs, num_glyphs, path);
-}
-
-void
-_cairo_font_get_glyph_cache_key (cairo_font_t *font,
- cairo_glyph_cache_key_t *key)
-{
- font->backend->get_glyph_cache_key (font, key);
-}
-
-cairo_status_t
-_cairo_font_font_extents (cairo_font_t *font,
- cairo_font_extents_t *extents)
-{
- return font->backend->font_extents (font, extents);
-}
-
-void
-_cairo_unscaled_font_reference (cairo_unscaled_font_t *font)
-{
- font->refcount++;
-}
-
-void
-_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font)
-{
- if (--(font->refcount) > 0)
- return;
-
- font->backend->destroy_unscaled_font (font);
-}
-
-
-
-/* Public font API follows. */
-
-void
-cairo_font_reference (cairo_font_t *font)
-{
- font->refcount++;
-}
-
-void
-cairo_font_destroy (cairo_font_t *font)
-{
- if (--(font->refcount) > 0)
- return;
-
- font->backend->destroy_font (font);
-}
-
-/**
- * cairo_font_extents:
- * @font: a #cairo_font_t
- * @font_matrix: the font transformation for which this font was
- * created. (See cairo_transform_font()). This is needed
- * properly convert the metrics from the font into user space.
- * @extents: a #cairo_font_extents_t which to store the retrieved extents.
- *
- * Gets the metrics for a #cairo_font_t.
- *
- * Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an
- * error such as %CAIRO_STATUS_NO_MEMORY.
- **/
-cairo_status_t
-cairo_font_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_font_extents_t *extents)
-{
- cairo_int_status_t status;
- double font_scale_x, font_scale_y;
-
- status = _cairo_font_font_extents (font, extents);
-
- if (!CAIRO_OK (status))
- return status;
-
- _cairo_matrix_compute_scale_factors (font_matrix,
- &font_scale_x, &font_scale_y,
- /* XXX */ 1);
-
- /*
- * The font responded in unscaled units, scale by the font
- * matrix scale factors to get to user space
- */
-
- extents->ascent *= font_scale_y;
- extents->descent *= font_scale_y;
- extents->height *= font_scale_y;
- extents->max_x_advance *= font_scale_x;
- extents->max_y_advance *= font_scale_y;
-
- return status;
-}
-
-/**
- * cairo_font_glyph_extents:
- * @font: a #cairo_font_t
- * @font_matrix: the font transformation for which this font was
- * created. (See cairo_transform_font()). This is needed
- * properly convert the metrics from the font into user space.
- * @glyphs: an array of glyph IDs with X and Y offsets.
- * @num_glyphs: the number of glyphs in the @glyphs array
- * @extents: a #cairo_text_extents_t which to store the retrieved extents.
- *
- * cairo_font_glyph_extents() gets the overall metrics for a string of
- * glyphs. The X and Y offsets in @glyphs are taken from an origin of 0,0.
- **/
-void
-cairo_font_glyph_extents (cairo_font_t *font,
- cairo_matrix_t *font_matrix,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_glyph_t origin_glyph;
- cairo_text_extents_t origin_extents;
- int i;
- double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
- double x_pos = 0.0, y_pos = 0.0;
- int set = 0;
-
- if (!num_glyphs)
- {
- extents->x_bearing = 0.0;
- extents->y_bearing = 0.0;
- extents->width = 0.0;
- extents->height = 0.0;
- extents->x_advance = 0.0;
- extents->y_advance = 0.0;
-
- return;
- }
-
- for (i = 0; i < num_glyphs; i++)
- {
- double x, y;
- double wm, hm;
-
- origin_glyph = glyphs[i];
- origin_glyph.x = 0.0;
- origin_glyph.y = 0.0;
- status = _cairo_font_glyph_extents (font,
- &origin_glyph, 1,
- &origin_extents);
-
- /*
- * Transform font space metrics into user space metrics
- * by running the corners through the font matrix and
- * expanding the bounding box as necessary
- */
- x = origin_extents.x_bearing;
- y = origin_extents.y_bearing;
- cairo_matrix_transform_point (font_matrix,
- &x, &y);
-
- for (hm = 0.0; hm <= 1.0; hm += 1.0)
- for (wm = 0.0; wm <= 1.0; wm += 1.0)
- {
- x = origin_extents.x_bearing + origin_extents.width * wm;
- y = origin_extents.y_bearing + origin_extents.height * hm;
- cairo_matrix_transform_point (font_matrix,
- &x, &y);
- x += glyphs[i].x;
- y += glyphs[i].y;
- if (!set)
- {
- min_x = max_x = x;
- min_y = max_y = y;
- set = 1;
- }
- else
- {
- if (x < min_x) min_x = x;
- if (x > max_x) max_x = x;
- if (y < min_y) min_y = y;
- if (y > max_y) max_y = y;
- }
- }
-
- x = origin_extents.x_advance;
- y = origin_extents.y_advance;
- cairo_matrix_transform_point (font_matrix,
- &x, &y);
- x_pos = glyphs[i].x + x;
- y_pos = glyphs[i].y + y;
- }
-
- extents->x_bearing = min_x - glyphs[0].x;
- extents->y_bearing = min_y - glyphs[0].y;
- extents->width = max_x - min_x;
- extents->height = max_y - min_y;
- extents->x_advance = x_pos - glyphs[0].x;
- extents->y_advance = y_pos - glyphs[0].y;
-}
-
-/* Now we implement functions to access a default global image & metrics
- * cache.
- */
-
-unsigned long
-_cairo_glyph_cache_hash (void *cache, void *key)
-{
- cairo_glyph_cache_key_t *in;
- in = (cairo_glyph_cache_key_t *) key;
- return
- ((unsigned long) in->unscaled)
- ^ ((unsigned long) in->scale.matrix[0][0])
- ^ ((unsigned long) in->scale.matrix[0][1])
- ^ ((unsigned long) in->scale.matrix[1][0])
- ^ ((unsigned long) in->scale.matrix[1][1])
- ^ (in->flags * 1451) /* 1451 is just an abitrary prime */
- ^ in->index;
-}
-
-int
-_cairo_glyph_cache_keys_equal (void *cache,
- void *k1,
- void *k2)
-{
- cairo_glyph_cache_key_t *a, *b;
- a = (cairo_glyph_cache_key_t *) k1;
- b = (cairo_glyph_cache_key_t *) k2;
- return (a->index == b->index)
- && (a->unscaled == b->unscaled)
- && (a->flags == b->flags)
- && (a->scale.matrix[0][0] == b->scale.matrix[0][0])
- && (a->scale.matrix[0][1] == b->scale.matrix[0][1])
- && (a->scale.matrix[1][0] == b->scale.matrix[1][0])
- && (a->scale.matrix[1][1] == b->scale.matrix[1][1]);
-}
-
-
-static cairo_status_t
-_image_glyph_cache_create_entry (void *cache,
- void *key,
- void **return_value)
-{
- cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *) key;
- cairo_image_glyph_cache_entry_t *im;
- cairo_status_t status;
-
- im = calloc (1, sizeof (cairo_image_glyph_cache_entry_t));
- if (im == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- im->key = *k;
- status = im->key.unscaled->backend->create_glyph (im);
-
- if (status != CAIRO_STATUS_SUCCESS) {
- free (im);
- return status;
- }
-
- _cairo_unscaled_font_reference (im->key.unscaled);
-
- im->key.base.memory =
- sizeof (cairo_image_glyph_cache_entry_t)
- + (im->image ?
- sizeof (cairo_image_surface_t)
- + 28 * sizeof (int) /* rough guess at size of pixman image structure */
- + (im->image->height * im->image->stride) : 0);
-
- *return_value = im;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static void
-_image_glyph_cache_destroy_entry (void *cache,
- void *value)
-{
- cairo_image_glyph_cache_entry_t *im;
-
- im = (cairo_image_glyph_cache_entry_t *) value;
- _cairo_unscaled_font_destroy (im->key.unscaled);
- cairo_surface_destroy (&(im->image->base));
- free (im);
-}
-
-static void
-_image_glyph_cache_destroy_cache (void *cache)
-{
- free (cache);
-}
-
-static const cairo_cache_backend_t cairo_image_cache_backend = {
- _cairo_glyph_cache_hash,
- _cairo_glyph_cache_keys_equal,
- _image_glyph_cache_create_entry,
- _image_glyph_cache_destroy_entry,
- _image_glyph_cache_destroy_cache
-};
-
-void
-_cairo_lock_global_image_glyph_cache()
-{
- /* FIXME: implement locking. */
-}
-
-void
-_cairo_unlock_global_image_glyph_cache()
-{
- /* FIXME: implement locking. */
-}
-
-static cairo_cache_t *
-_global_image_glyph_cache = NULL;
-
-cairo_cache_t *
-_cairo_get_global_image_glyph_cache ()
-{
- if (_global_image_glyph_cache == NULL) {
- _global_image_glyph_cache = malloc (sizeof (cairo_cache_t));
-
- if (_global_image_glyph_cache == NULL)
- goto FAIL;
-
- if (_cairo_cache_init (_global_image_glyph_cache,
- &cairo_image_cache_backend,
- CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT))
- goto FAIL;
- }
-
- return _global_image_glyph_cache;
-
- FAIL:
- if (_global_image_glyph_cache)
- free (_global_image_glyph_cache);
- _global_image_glyph_cache = NULL;
- return NULL;
-}
diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c
deleted file mode 100644
index 44e1b0e84..000000000
--- a/src/cairo_ft_font.c
+++ /dev/null
@@ -1,1538 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2005 Red Hat, Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Red Hat, Inc.
- *
- * Contributor(s):
- * Graydon Hoare <graydon@redhat.com>
- * Owen Taylor <otaylor@redhat.com>
- */
-
-#include "cairo-ft-private.h"
-
-#include <fontconfig/fontconfig.h>
-#include <fontconfig/fcfreetype.h>
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_OUTLINE_H
-#include FT_IMAGE_H
-
-#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0))
-#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0)
-#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))
-#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0)
-
-/* This is the max number of FT_face objects we keep open at once
- */
-#define MAX_OPEN_FACES 10
-
-/*
- * 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;
-
-/*
- * We create an object that corresponds to a single font on the disk;
- * (identified by a filename/id pair) these are shared between all
- * fonts using that file. For cairo_ft_font_create_for_ft_face(), we
- * just create a one-off version with a permanent face value.
- */
-
-typedef struct {
- cairo_unscaled_font_t base;
-
- int from_face; /* from cairo_ft_font_create_for_ft_face()? */
- FT_Face face; /* provided or cached face */
-
- /* only set if from_face is false */
- FT_Library library;
- char *filename;
- int id;
-
- /* We temporarily scale the unscaled font as neede */
- int have_scale;
- cairo_font_scale_t current_scale;
- double x_scale; /* Extracted X scale factor */
- double y_scale; /* Extracted Y scale factor */
-
- int lock; /* count of how many times this font has been locked */
-} ft_unscaled_font_t;
-
-const cairo_font_backend_t cairo_ft_font_backend;
-
-static ft_unscaled_font_t *
-_ft_unscaled_font_create_from_face (FT_Face face)
-{
- ft_unscaled_font_t *unscaled = malloc (sizeof(ft_unscaled_font_t));
- if (!unscaled)
- return NULL;
-
- unscaled->from_face = 1;
- unscaled->face = face;
-
- unscaled->library = NULL;
- unscaled->filename = NULL;
- unscaled->id = 0;
-
- unscaled->have_scale = 0;
- unscaled->lock = 0;
-
- _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
- &cairo_ft_font_backend);
- return unscaled;
-}
-
-static ft_unscaled_font_t *
-_ft_unscaled_font_create_from_filename (FT_Library library,
- const char *filename,
- int id)
-{
- ft_unscaled_font_t *unscaled;
- char *new_filename;
-
- new_filename = strdup (filename);
- if (!new_filename)
- return NULL;
-
- unscaled = malloc (sizeof (ft_unscaled_font_t));
- if (!unscaled) {
- free (new_filename);
- return NULL;
- }
-
- unscaled->from_face = 0;
- unscaled->face = NULL;
-
- unscaled->library = library;
- unscaled->filename = new_filename;
- unscaled->id = id;
-
- unscaled->have_scale = 0;
- unscaled->lock = 0;
-
- _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled,
- &cairo_ft_font_backend);
- return unscaled;
-}
-
-/*
- * We keep a global cache from [file/id] => [ft_unscaled_font_t]. This
- * hash isn't limited in size. However, we limit the number of
- * FT_Face objects we keep around; when we've exceeeded that
- * limit and need to create a new FT_Face, we dump the FT_Face from
- * a random ft_unscaled_font_t.
- */
-
-typedef struct {
- cairo_cache_entry_base_t base;
- char *filename;
- int id;
-} cairo_ft_cache_key_t;
-
-typedef struct {
- cairo_ft_cache_key_t key;
- ft_unscaled_font_t *unscaled;
-} cairo_ft_cache_entry_t;
-
-typedef struct {
- cairo_cache_t base;
- FT_Library lib;
- int n_faces; /* Number of open FT_Face objects */
-} ft_cache_t;
-
-static unsigned long
-_ft_font_cache_hash (void *cache, void *key)
-{
- cairo_ft_cache_key_t *in = (cairo_ft_cache_key_t *) key;
- unsigned long hash;
-
- /* 1607 is just a random prime. */
- hash = _cairo_hash_string (in->filename);
- hash += ((unsigned long) in->id) * 1607;
-
- return hash;
-}
-
-static int
-_ft_font_cache_keys_equal (void *cache,
- void *k1,
- void *k2)
-{
- cairo_ft_cache_key_t *a;
- cairo_ft_cache_key_t *b;
- a = (cairo_ft_cache_key_t *) k1;
- b = (cairo_ft_cache_key_t *) k2;
-
- return strcmp (a->filename, b->filename) == 0 &&
- a->id == b->id;
-}
-
-static cairo_status_t
-_ft_font_cache_create_entry (void *cache,
- void *key,
- void **return_entry)
-{
- ft_cache_t *ftcache = (ft_cache_t *) cache;
- cairo_ft_cache_key_t *k = (cairo_ft_cache_key_t *) key;
- cairo_ft_cache_entry_t *entry;
-
- entry = malloc (sizeof (cairo_ft_cache_entry_t));
- if (entry == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- entry->unscaled = _ft_unscaled_font_create_from_filename (ftcache->lib,
- k->filename,
- k->id);
- if (!entry->unscaled) {
- free (entry);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- entry->key.base.memory = 0;
- entry->key.filename = entry->unscaled->filename;
- entry->key.id = entry->unscaled->id;
-
- *return_entry = entry;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Entries are never spontaneously destroyed; but only when
- * we remove them from the cache specifically. We free entry->unscaled
- * in the code that removes the entry from the cache
- */
-static void
-_ft_font_cache_destroy_entry (void *cache,
- void *entry)
-{
- cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry;
-
- free (e);
-}
-
-static void
-_ft_font_cache_destroy_cache (void *cache)
-{
- ft_cache_t *fc = (ft_cache_t *) cache;
- FT_Done_FreeType (fc->lib);
- free (fc);
-}
-
-static const cairo_cache_backend_t _ft_font_cache_backend = {
- _ft_font_cache_hash,
- _ft_font_cache_keys_equal,
- _ft_font_cache_create_entry,
- _ft_font_cache_destroy_entry,
- _ft_font_cache_destroy_cache
-};
-
-static ft_cache_t *_global_ft_cache = NULL;
-
-static void
-_lock_global_ft_cache (void)
-{
- /* FIXME: Perform locking here. */
-}
-
-static void
-_unlock_global_ft_cache (void)
-{
- /* FIXME: Perform locking here. */
-}
-
-static cairo_cache_t *
-_get_global_ft_cache (void)
-{
- if (_global_ft_cache == NULL)
- {
- _global_ft_cache = malloc (sizeof(ft_cache_t));
- if (!_global_ft_cache)
- goto FAIL;
-
- if (_cairo_cache_init (&_global_ft_cache->base,
- &_ft_font_cache_backend,
- 0)) /* No memory limit */
- goto FAIL;
-
- if (FT_Init_FreeType (&_global_ft_cache->lib))
- goto FAIL;
- _global_ft_cache->n_faces = 0;
- }
- return &_global_ft_cache->base;
-
- FAIL:
- if (_global_ft_cache)
- free (_global_ft_cache);
- _global_ft_cache = NULL;
- return NULL;
-}
-
-/* Finds or creates a ft_unscaled_font for the filename/id from pattern.
- * Returns a new reference to the unscaled font.
- */
-static ft_unscaled_font_t *
-_ft_unscaled_font_get_for_pattern (FcPattern *pattern)
-{
- cairo_ft_cache_entry_t *entry;
- cairo_ft_cache_key_t key;
- cairo_cache_t *cache;
- cairo_status_t status;
- FcChar8 *filename;
- int created_entry;
-
- if (FcPatternGetString (pattern, FC_FILE, 0, &filename) != FcResultMatch)
- return NULL;
- key.filename = (char *)filename;
-
- if (FcPatternGetInteger (pattern, FC_INDEX, 0, &key.id) != FcResultMatch)
- return NULL;
-
- _lock_global_ft_cache ();
- cache = _get_global_ft_cache ();
- if (cache == NULL) {
- _unlock_global_ft_cache ();
- return NULL;
- }
-
- status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry);
- _unlock_global_ft_cache ();
- if (status)
- return NULL;
-
- if (!created_entry)
- _cairo_unscaled_font_reference ((cairo_unscaled_font_t *)entry->unscaled);
-
- return entry->unscaled;
-}
-
-static int
-_has_unlocked_face (void *entry)
-{
- cairo_ft_cache_entry_t *e = entry;
-
- return (e->unscaled->lock == 0 && e->unscaled->face);
-}
-
-/* Ensures that an unscaled font has a face object. If we exceed
- * MAX_OPEN_FACES, try to close some.
- */
-static FT_Face
-_ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled)
-{
- ft_cache_t *ftcache;
- FT_Face face = NULL;
-
- if (unscaled->face) {
- unscaled->lock++;
- return unscaled->face;
- }
-
- assert (!unscaled->from_face);
-
- _lock_global_ft_cache ();
- ftcache = (ft_cache_t *) _get_global_ft_cache ();
- assert (ftcache != NULL);
-
- while (ftcache->n_faces >= MAX_OPEN_FACES) {
- cairo_ft_cache_entry_t *entry;
-
- entry = _cairo_cache_random_entry ((cairo_cache_t *)ftcache, _has_unlocked_face);
- if (entry) {
- FT_Done_Face (entry->unscaled->face);
- entry->unscaled->face = NULL;
- entry->unscaled->have_scale = 0;
- ftcache->n_faces--;
- } else {
- break;
- }
- }
-
- if (FT_New_Face (ftcache->lib,
- unscaled->filename,
- unscaled->id,
- &face) != FT_Err_Ok)
- goto FAIL;
-
- unscaled->face = face;
- unscaled->lock++;
- ftcache->n_faces++;
-
- FAIL:
- _unlock_global_ft_cache ();
- return face;
-}
-
-/* Unlock unscaled font locked with _ft_unscaled_font_lock_face
- */
-static void
-_ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled)
-{
- assert (unscaled->lock > 0);
-
- unscaled->lock--;
-}
-
-static void
-_compute_transform (ft_font_transform_t *sf,
- cairo_font_scale_t *sc)
-{
- cairo_matrix_t normalized;
- double tx, ty;
-
- /* The font matrix has x and y "scale" components which we extract and
- * use as character scale values. These influence the way freetype
- * chooses hints, as well as selecting different bitmaps in
- * hand-rendered fonts. We also copy the normalized matrix to
- * freetype's transformation.
- */
-
- cairo_matrix_set_affine (&normalized,
- sc->matrix[0][0],
- sc->matrix[0][1],
- sc->matrix[1][0],
- sc->matrix[1][1],
- 0, 0);
-
- _cairo_matrix_compute_scale_factors (&normalized,
- &sf->x_scale, &sf->y_scale,
- /* XXX */ 1);
- cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale);
- cairo_matrix_get_affine (&normalized,
- &sf->shape[0][0], &sf->shape[0][1],
- &sf->shape[1][0], &sf->shape[1][1],
- &tx, &ty);
-}
-
-/* Temporarily scales an unscaled font to the give scale. We catch
- * scaling to the same size, since changing a FT_Face is expensive.
- */
-static void
-_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled,
- cairo_font_scale_t *scale)
-{
- ft_font_transform_t sf;
- FT_Matrix mat;
-
- assert (unscaled->face != NULL);
-
- if (unscaled->have_scale &&
- scale->matrix[0][0] == unscaled->current_scale.matrix[0][0] &&
- scale->matrix[0][1] == unscaled->current_scale.matrix[0][1] &&
- scale->matrix[1][0] == unscaled->current_scale.matrix[1][0] &&
- scale->matrix[1][1] == unscaled->current_scale.matrix[1][1])
- return;
-
- unscaled->have_scale = 1;
- unscaled->current_scale = *scale;
-
- _compute_transform (&sf, scale);
-
- unscaled->x_scale = sf.x_scale;
- unscaled->y_scale = sf.y_scale;
-
- mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]);
- mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]);
- mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]);
- mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]);
-
- FT_Set_Transform(unscaled->face, &mat, NULL);
-
- FT_Set_Pixel_Sizes(unscaled->face,
- (FT_UInt) sf.x_scale,
- (FT_UInt) sf.y_scale);
-}
-
-/* implement the font backend interface */
-
-typedef struct {
- cairo_font_t base;
- FcPattern *pattern;
- int load_flags;
- ft_unscaled_font_t *unscaled;
-} cairo_ft_font_t;
-
-/* for compatibility with older freetype versions */
-#ifndef FT_LOAD_TARGET_MONO
-#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME
-#endif
-
-/* The load flags passed to FT_Load_Glyph control aspects like hinting and
- * antialiasing. Here we compute them from the fields of a FcPattern.
- */
-static int
-_get_load_flags (FcPattern *pattern)
-{
- FcBool antialias, hinting, autohint;
-#ifdef FC_HINT_STYLE
- int hintstyle;
-#endif
- int load_flags = 0;
-
- /* disable antialiasing if requested */
- if (FcPatternGetBool (pattern,
- FC_ANTIALIAS, 0, &antialias) != FcResultMatch)
- antialias = FcTrue;
-
- if (antialias)
- load_flags |= FT_LOAD_NO_BITMAP;
- else
- load_flags |= FT_LOAD_TARGET_MONO;
-
- /* disable hinting if requested */
- if (FcPatternGetBool (pattern,
- FC_HINTING, 0, &hinting) != FcResultMatch)
- hinting = FcTrue;
-
-#ifdef FC_HINT_STYLE
- if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch)
- hintstyle = FC_HINT_FULL;
-
- if (!hinting || hintstyle == FC_HINT_NONE)
- load_flags |= FT_LOAD_NO_HINTING;
-
- switch (hintstyle) {
- case FC_HINT_SLIGHT:
- case FC_HINT_MEDIUM:
- load_flags |= FT_LOAD_TARGET_LIGHT;
- break;
- default:
- load_flags |= FT_LOAD_TARGET_NORMAL;
- break;
- }
-#else /* !FC_HINT_STYLE */
- if (!hinting)
- load_flags |= FT_LOAD_NO_HINTING;
-#endif /* FC_FHINT_STYLE */
-
- /* force autohinting if requested */
- if (FcPatternGetBool (pattern,
- FC_AUTOHINT, 0, &autohint) != FcResultMatch)
- autohint = FcFalse;
-
- if (autohint)
- load_flags |= FT_LOAD_FORCE_AUTOHINT;
-
- return load_flags;
-}
-
-/* Like the public cairo_ft_font_create, but takes a cairo_font_scale_t,
- * rather than a cairo_font_t
- */
-static cairo_font_t *
-_ft_font_create (FcPattern *pattern,
- cairo_font_scale_t *scale)
-{
- cairo_ft_font_t *f = NULL;
- ft_unscaled_font_t *unscaled = NULL;
-
- unscaled = _ft_unscaled_font_get_for_pattern (pattern);
- if (unscaled == NULL)
- return NULL;
-
- f = malloc (sizeof(cairo_ft_font_t));
- if (f == NULL)
- goto FREE_UNSCALED;
-
- f->unscaled = unscaled;
- f->pattern = pattern;
- FcPatternReference (pattern);
- f->load_flags = _get_load_flags (pattern);
-
- _cairo_font_init ((cairo_font_t *)f, scale, &cairo_ft_font_backend);
-
- return (cairo_font_t *)f;
-
- FREE_UNSCALED:
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
-
- return NULL;
-}
-
-static cairo_status_t
-_cairo_ft_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *scale,
- cairo_font_t **font)
-{
- FcPattern *pattern, *resolved;
- cairo_font_t *new_font;
- FcResult result;
- int fcslant;
- int fcweight;
- ft_font_transform_t sf;
-
- pattern = FcPatternCreate ();
- if (!pattern)
- return CAIRO_STATUS_NO_MEMORY;
-
- switch (weight)
- {
- case CAIRO_FONT_WEIGHT_BOLD:
- fcweight = FC_WEIGHT_BOLD;
- break;
- case CAIRO_FONT_WEIGHT_NORMAL:
- default:
- fcweight = FC_WEIGHT_MEDIUM;
- break;
- }
-
- switch (slant)
- {
- case CAIRO_FONT_SLANT_ITALIC:
- fcslant = FC_SLANT_ITALIC;
- break;
- case CAIRO_FONT_SLANT_OBLIQUE:
- fcslant = FC_SLANT_OBLIQUE;
- break;
- case CAIRO_FONT_SLANT_NORMAL:
- default:
- fcslant = FC_SLANT_ROMAN;
- break;
- }
-
- if (!FcPatternAddString (pattern, FC_FAMILY, family))
- goto FREE_PATTERN;
- if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant))
- goto FREE_PATTERN;
- if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight))
- goto FREE_PATTERN;
-
- _compute_transform (&sf, scale);
-
- FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale);
-
- FcConfigSubstitute (NULL, pattern, FcMatchPattern);
- FcDefaultSubstitute (pattern);
-
- resolved = FcFontMatch (NULL, pattern, &result);
- if (!resolved)
- goto FREE_PATTERN;
-
- new_font = _ft_font_create (resolved, scale);
-
- FcPatternDestroy (resolved);
- FcPatternDestroy (pattern);
-
- if (new_font) {
- *font = new_font;
- return CAIRO_STATUS_SUCCESS;
- } else {
- return CAIRO_STATUS_NO_MEMORY; /* A guess */
- }
-
- FREE_PATTERN:
- FcPatternDestroy (pattern);
-
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-static void
-_cairo_ft_font_destroy_font (void *abstract_font)
-{
- cairo_ft_font_t * font = abstract_font;
-
- if (font == NULL)
- return;
-
- if (font->pattern != NULL)
- FcPatternDestroy (font->pattern);
-
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)font->unscaled);
-
- free (font);
-}
-
-static void
-_cairo_ft_font_destroy_unscaled_font (void *abstract_font)
-{
- ft_unscaled_font_t *unscaled = abstract_font;
-
- if (!unscaled->from_face) {
- cairo_cache_t *cache;
- cairo_ft_cache_key_t key;
-
- _lock_global_ft_cache ();
- cache = _get_global_ft_cache ();
- assert (cache);
-
- key.filename = unscaled->filename;
- key.id = unscaled->id;
-
- _cairo_cache_remove (cache, &key);
-
- _unlock_global_ft_cache ();
- }
-
- if (unscaled == NULL)
- return;
-
- if (!unscaled->from_face && unscaled->face)
- FT_Done_Face (unscaled->face);
-
- if (unscaled->filename)
- free (unscaled->filename);
-
- free (unscaled);
-}
-
-static void
-_cairo_ft_font_get_glyph_cache_key (void *abstract_font,
- cairo_glyph_cache_key_t *key)
-{
- cairo_ft_font_t *font = abstract_font;
-
- key->unscaled = (cairo_unscaled_font_t *)font->unscaled;
- key->scale = font->base.scale;
- key->flags = font->load_flags;
-}
-
-static cairo_status_t
-_cairo_ft_font_text_to_glyphs (void *abstract_font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *nglyphs)
-{
- double x = 0., y = 0.;
- size_t i;
- uint32_t *ucs4 = NULL;
- cairo_ft_font_t *font = abstract_font;
- FT_Face face;
- cairo_glyph_cache_key_t key;
- cairo_image_glyph_cache_entry_t *val;
- cairo_cache_t *cache = NULL;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- _cairo_ft_font_get_glyph_cache_key (font, &key);
-
- status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, nglyphs);
- if (!CAIRO_OK (status))
- return status;
-
- face = cairo_ft_font_lock_face ((cairo_font_t *)font);
- if (!face) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL1;
- }
-
- _cairo_lock_global_image_glyph_cache ();
- cache = _cairo_get_global_image_glyph_cache ();
- if (cache == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL2;
- }
-
- *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t)));
- if (*glyphs == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL2;
- }
-
- for (i = 0; i < *nglyphs; i++)
- {
- (*glyphs)[i].index = FT_Get_Char_Index (face, ucs4[i]);
- (*glyphs)[i].x = x;
- (*glyphs)[i].y = y;
-
- val = NULL;
- key.index = (*glyphs)[i].index;
-
- if (_cairo_cache_lookup (cache, &key, (void **) &val, NULL)
- != CAIRO_STATUS_SUCCESS || val == NULL)
- continue;
-
- x += val->extents.x_advance;
- y += val->extents.y_advance;
- }
-
- FAIL2:
- if (cache)
- _cairo_unlock_global_image_glyph_cache ();
-
- cairo_ft_font_unlock_face ((cairo_font_t *)font);
-
- FAIL1:
- free (ucs4);
-
- return status;
-}
-
-
-static cairo_status_t
-_cairo_ft_font_font_extents (void *abstract_font,
- cairo_font_extents_t *extents)
-{
- cairo_ft_font_t *font = abstract_font;
- FT_Face face;
- FT_Size_Metrics *metrics;
-
- face = _ft_unscaled_font_lock_face (font->unscaled);
- if (!face)
- return CAIRO_STATUS_NO_MEMORY;
-
- metrics = &face->size->metrics;
-
- _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
-
- /*
- * Get to unscaled metrics so that the upper level can get back to
- * user space
- */
- extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / font->unscaled->y_scale;
- extents->descent = DOUBLE_FROM_26_6(metrics->descender) / font->unscaled->y_scale;
- extents->height = DOUBLE_FROM_26_6(metrics->height) / font->unscaled->y_scale;
- extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / font->unscaled->x_scale;
-
- /* FIXME: this doesn't do vertical layout atm. */
- extents->max_y_advance = 0.0;
-
- _ft_unscaled_font_unlock_face (font->unscaled);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ft_font_glyph_extents (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- int i;
- cairo_ft_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;
-
- cairo_image_glyph_cache_entry_t *img = NULL;
- cairo_cache_t *cache;
- cairo_glyph_cache_key_t key;
-
- 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;
-
- _cairo_lock_global_image_glyph_cache ();
- cache = _cairo_get_global_image_glyph_cache ();
- if (cache == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- _cairo_ft_font_get_glyph_cache_key (font, &key);
-
- for (i = 0; i < num_glyphs; i++)
- {
- img = NULL;
- key.index = glyphs[i].index;
- if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
- != CAIRO_STATUS_SUCCESS || img == NULL)
- 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_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_max.x = glyph_min.x + img->extents.width;
- glyph_max.y = glyph_min.y + img->extents.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;
- }
- }
- _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_advance = glyphs[i-1].x + (img == NULL ? 0 : img->extents.x_advance) - origin.x;
- extents->y_advance = glyphs[i-1].y + (img == NULL ? 0 : img->extents.y_advance) - origin.y;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static cairo_status_t
-_cairo_ft_font_glyph_bbox (void *abstract_font,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
-{
- cairo_image_glyph_cache_entry_t *img;
- cairo_cache_t *cache;
- cairo_glyph_cache_key_t key;
- cairo_ft_font_t *font = abstract_font;
-
- 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;
-
- _cairo_lock_global_image_glyph_cache ();
- cache = _cairo_get_global_image_glyph_cache();
-
- if (cache == NULL
- || font == NULL
- || glyphs == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- _cairo_ft_font_get_glyph_cache_key (font, &key);
-
- for (i = 0; i < num_glyphs; i++)
- {
-
- img = NULL;
- key.index = glyphs[i].index;
-
- if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
- != CAIRO_STATUS_SUCCESS || img == NULL)
- continue;
-
- x1 = _cairo_fixed_from_double (glyphs[i].x + img->size.x);
- 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);
-
- 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;
- }
- _cairo_unlock_global_image_glyph_cache ();
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static cairo_status_t
-_cairo_ft_font_show_glyphs (void *abstract_font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_image_glyph_cache_entry_t *img;
- cairo_cache_t *cache;
- cairo_glyph_cache_key_t key;
- cairo_ft_font_t *font = abstract_font;
- cairo_surface_pattern_t glyph_pattern;
- cairo_status_t status;
- int x, y;
- int i;
-
- _cairo_lock_global_image_glyph_cache ();
- cache = _cairo_get_global_image_glyph_cache();
-
- if (cache == NULL
- || font == NULL
- || pattern == NULL
- || surface == NULL
- || glyphs == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- key.unscaled = (cairo_unscaled_font_t *)font->unscaled;
- key.scale = font->base.scale;
- key.flags = font->load_flags;
-
- for (i = 0; i < num_glyphs; i++)
- {
- img = NULL;
- key.index = glyphs[i].index;
-
- if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL)
- != CAIRO_STATUS_SUCCESS
- || img == NULL
- || img->image == NULL)
- continue;
-
- x = (int) floor (glyphs[i].x + 0.5);
- y = (int) floor (glyphs[i].y + 0.5);
-
- _cairo_pattern_init_for_surface (&glyph_pattern, &(img->image->base));
-
- status = _cairo_surface_composite (operator, pattern,
- &glyph_pattern.base,
- surface,
- x + img->size.x,
- y + img->size.y,
- 0, 0,
- x + img->size.x,
- y + img->size.y,
- (double) img->size.width,
- (double) img->size.height);
-
- _cairo_pattern_fini (&glyph_pattern.base);
-
- if (status) {
- _cairo_unlock_global_image_glyph_cache ();
- return status;
- }
- }
-
- _cairo_unlock_global_image_glyph_cache ();
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static int
-_move_to (FT_Vector *to, void *closure)
-{
- cairo_path_t *path = closure;
- cairo_point_t point;
-
- point.x = _cairo_fixed_from_26_6 (to->x);
- point.y = _cairo_fixed_from_26_6 (to->y);
-
- _cairo_path_close_path (path);
- _cairo_path_move_to (path, &point);
-
- return 0;
-}
-
-static int
-_line_to (FT_Vector *to, void *closure)
-{
- cairo_path_t *path = closure;
- cairo_point_t point;
-
- point.x = _cairo_fixed_from_26_6 (to->x);
- point.y = _cairo_fixed_from_26_6 (to->y);
-
- _cairo_path_line_to (path, &point);
-
- return 0;
-}
-
-static int
-_conic_to (FT_Vector *control, FT_Vector *to, void *closure)
-{
- cairo_path_t *path = closure;
-
- cairo_point_t p0, p1, p2, p3;
- cairo_point_t conic;
-
- _cairo_path_current_point (path, &p0);
-
- conic.x = _cairo_fixed_from_26_6 (control->x);
- conic.y = _cairo_fixed_from_26_6 (control->y);
-
- p3.x = _cairo_fixed_from_26_6 (to->x);
- p3.y = _cairo_fixed_from_26_6 (to->y);
-
- p1.x = p0.x + 2.0/3.0 * (conic.x - p0.x);
- p1.y = p0.y + 2.0/3.0 * (conic.y - p0.y);
-
- p2.x = p3.x + 2.0/3.0 * (conic.x - p3.x);
- p2.y = p3.y + 2.0/3.0 * (conic.y - p3.y);
-
- _cairo_path_curve_to (path,
- &p1, &p2, &p3);
-
- return 0;
-}
-
-static int
-_cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closure)
-{
- cairo_path_t *path = closure;
- cairo_point_t p0, p1, p2;
-
- p0.x = _cairo_fixed_from_26_6 (control1->x);
- p0.y = _cairo_fixed_from_26_6 (control1->y);
-
- p1.x = _cairo_fixed_from_26_6 (control2->x);
- p1.y = _cairo_fixed_from_26_6 (control2->y);
-
- p2.x = _cairo_fixed_from_26_6 (to->x);
- p2.y = _cairo_fixed_from_26_6 (to->y);
-
- _cairo_path_curve_to (path, &p0, &p1, &p2);
-
- return 0;
-}
-
-static cairo_status_t
-_cairo_ft_font_glyph_path (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
-{
- int i;
- cairo_ft_font_t *font = abstract_font;
- FT_GlyphSlot glyph;
- FT_Face face;
- FT_Error error;
- FT_Outline_Funcs outline_funcs = {
- _move_to,
- _line_to,
- _conic_to,
- _cubic_to,
- 0, /* shift */
- 0, /* delta */
- };
-
- face = cairo_ft_font_lock_face (abstract_font);
- if (!face)
- return CAIRO_STATUS_NO_MEMORY;
-
- glyph = face->glyph;
-
- 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->unscaled->face, glyphs[i].index, font->load_flags | FT_LOAD_NO_BITMAP);
- /* 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);
-
- cairo_ft_font_unlock_face (abstract_font);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ft_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
-{
- ft_unscaled_font_t *unscaled = (ft_unscaled_font_t *)val->key.unscaled;
- FT_GlyphSlot glyphslot;
- unsigned int width, height, stride;
- FT_Face face;
- FT_Outline *outline;
- FT_BBox cbox;
- FT_Bitmap bitmap;
- FT_Glyph_Metrics *metrics;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- glyphslot = unscaled->face->glyph;
- metrics = &glyphslot->metrics;
-
- face = _ft_unscaled_font_lock_face (unscaled);
- if (!face)
- return CAIRO_STATUS_NO_MEMORY;
-
- _ft_unscaled_font_set_scale (unscaled, &val->key.scale);
-
- if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- /*
- * Note: the font's coordinate system is upside down from ours, so the
- * Y coordinates of the bearing and advance need to be negated.
- *
- * Scale metrics back to glyph space from the scaled glyph space returned
- * by FreeType
- */
-
- val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale;
- val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale;
-
- val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale;
- val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->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 (face->glyph->metrics.horiAdvance) / unscaled->x_scale;
- val->extents.y_advance = 0 / unscaled->y_scale;
-
- 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;
-
- if (width * height == 0)
- val->image = NULL;
- else
- {
-
- bitmap.pixel_mode = ft_pixel_mode_grays;
- bitmap.num_grays = 256;
- bitmap.width = width;
- bitmap.rows = height;
- bitmap.pitch = stride;
- bitmap.buffer = calloc (1, stride * height);
-
- if (bitmap.buffer == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin);
-
- if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
- free (bitmap.buffer);
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- val->image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data ((char *) bitmap.buffer,
- CAIRO_FORMAT_A8,
- width, height, stride);
- if (val->image == NULL) {
- free (bitmap.buffer);
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- _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);
-
- FAIL:
- _ft_unscaled_font_unlock_face (unscaled);
-
- return status;
-}
-
-const cairo_font_backend_t cairo_ft_font_backend = {
- _cairo_ft_font_create,
- _cairo_ft_font_destroy_font,
- _cairo_ft_font_destroy_unscaled_font,
- _cairo_ft_font_font_extents,
- _cairo_ft_font_text_to_glyphs,
- _cairo_ft_font_glyph_extents,
- _cairo_ft_font_glyph_bbox,
- _cairo_ft_font_show_glyphs,
- _cairo_ft_font_glyph_path,
- _cairo_ft_font_get_glyph_cache_key,
- _cairo_ft_font_create_glyph
-};
-
-/* implement the platform-specific interface */
-
-/**
- * cairo_ft_font_create:
- * @pattern: A fully resolved fontconfig
- * pattern. A pattern can be resolved, by, among other things, calling
- * FcConfigSubstitute(), FcDefaultSubstitute(), then
- * FcFontMatch(). Cairo will call FcPatternReference() on this
- * pattern, so you should not further modify the pattern, but you can
- * release your reference to the pattern with FcPatternDestroy() if
- * you no longer need to access it.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
- *
- * Creates a new font for the FreeType font backend based on a
- * fontconfig pattern. This font can then be used with
- * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
- * specific functions like cairo_ft_font_lock_face().
- *
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
- **/
-cairo_font_t *
-cairo_ft_font_create (FcPattern *pattern,
- cairo_matrix_t *scale)
-{
- cairo_font_scale_t sc;
- double tx, ty;
-
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- &tx, &ty);
-
- return _ft_font_create (pattern, &sc);
-}
-
-/**
- * cairo_ft_font_create_for_ft_face:
- * @face: A FreeType face object, already opened. This must
- * be kept around until the font object's refcount drops to
- * zero and it is freed. The font object can be kept alive by
- * internal caching, so it's safest to keep the face object
- * around forever.
- * @load_flags: The flags to pass to FT_Load_Glyph when loading
- * glyphs from the font. These flags control aspects of
- * rendering such as hinting and antialiasing. See the FreeType
- * docs for full information.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
- *
- * Creates a new font forthe FreeType font backend from a pre-opened
- * FreeType face. This font can then be used with cairo_set_font(),
- * cairo_font_glyph_extents(), or FreeType backend specific
- * functions like cairo_ft_font_lock_face() Cairo will determine the
- * pixel size and transformation from the @scale parameter and call
- * FT_Set_Transform() and FT_Set_Pixel_Sizes().
- *
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
- **/
-cairo_font_t *
-cairo_ft_font_create_for_ft_face (FT_Face face,
- int load_flags,
- cairo_matrix_t *scale)
-{
- cairo_ft_font_t *f = NULL;
- ft_unscaled_font_t *unscaled = NULL;
- cairo_font_scale_t sc;
- double tx, ty;
-
- unscaled = _ft_unscaled_font_create_from_face (face);
- if (unscaled == NULL)
- return NULL;
-
- f = malloc (sizeof(cairo_ft_font_t));
- if (f == NULL)
- goto FREE_UNSCALED;
-
- f->unscaled = unscaled;
- f->pattern = NULL;
- f->load_flags = load_flags;
-
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- &tx, &ty);
-
- _cairo_font_init ((cairo_font_t *)f, &sc, &cairo_ft_font_backend);
-
- return (cairo_font_t *)f;
-
- FREE_UNSCALED:
- _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled);
-
- return NULL;
-}
-
-
-/**
- * cairo_ft_font_lock_face:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
- *
- * cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType
- * backend font and scales it appropriately for the font. You must
- * release the face with cairo_ft_font_unlock_face()
- * when you are done using it. Since the #FT_Face object can be
- * shared between multiple #cairo_font_t objects, you must not
- * lock any other font objects until you unlock this one. A count is
- * kept of the number of times cairo_ft_font_lock_face() is
- * called. cairo_ft_font_unlock_face() must be called the same number
- * of times.
- *
- * You must be careful when using this function in a library or in a
- * threaded application, because other threads may lock faces that
- * share the same #FT_Face object. For this reason, you must call
- * cairo_ft_lock() before locking any face objects, and
- * cairo_ft_unlock() after you are done. (These functions are not yet
- * implemented, so this function cannot be currently safely used in a
- * threaded application.)
-
- * Return value: The #FT_Face object for @font, scaled appropriately.
- **/
-FT_Face
-cairo_ft_font_lock_face (cairo_font_t *abstract_font)
-{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
- FT_Face face;
-
- face = _ft_unscaled_font_lock_face (font->unscaled);
- if (!face)
- return NULL;
-
- _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale);
-
- return face;
-}
-
-/**
- * cairo_ft_font_unlock_face:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
- *
- * Releases a face obtained with cairo_ft_font_lock_face(). See the
- * documentation for that function for full details.
- **/
-void
-cairo_ft_font_unlock_face (cairo_font_t *abstract_font)
-{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
-
- _ft_unscaled_font_unlock_face (font->unscaled);
-}
-
-/**
- * cairo_ft_font_get_pattern:
- * @ft_font: A #cairo_font_t from the FreeType font backend. Such an
- * object can be created with cairo_ft_font_create() or
- * cairo_ft_font_create_for_ft_face(). On some platforms the font from
- * cairo_current_font() will also be a FreeType font, but using this
- * functionality with fonts you don't create yourself is not
- * recommended.
- *
- * cairo_ft_font_get_pattern() gets the #FcPattern for a FreeType
- * backend font.
-
- * Return value: The #FcPattenr for @font. The return value is owned
- * by the font, so you must not modify it, and must call
- * FcPatternReference() to keep a persistant reference to the
- * pattern. If the font was created with cairo_ft_font_create_for_ft_face()
- * returns %NULL.
- **/
-FcPattern *
-cairo_ft_font_get_pattern (cairo_font_t *abstract_font)
-{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
-
- if (font == NULL)
- return NULL;
-
- return font->pattern;
-}
-
-/* We expose our unscaled font implementation internally for the the
- * PDF backend, which needs to keep track of the the different
- * fonts-on-disk used by a document, so it can embed them.
- */
-cairo_unscaled_font_t *
-_cairo_ft_font_get_unscaled_font (cairo_font_t *abstract_font)
-{
- cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
-
- return (cairo_unscaled_font_t *)font->unscaled;
-}
-
-/* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't
- * set the scale on the face, but just returns it at the last scale.
- */
-FT_Face
-_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font)
-{
- return _ft_unscaled_font_lock_face ((ft_unscaled_font_t *)unscaled_font);
-}
-
-void
-_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font)
-{
- _ft_unscaled_font_unlock_face ((ft_unscaled_font_t *)unscaled_font);
-}
diff --git a/src/cairo_glitz_surface.c b/src/cairo_glitz_surface.c
deleted file mode 100644
index ee664e1cc..000000000
--- a/src/cairo_glitz_surface.c
+++ /dev/null
@@ -1,1317 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 David Reveman
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of David
- * Reveman not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. David Reveman makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: David Reveman <davidr@novell.com>
- */
-
-#include "cairoint.h"
-#include "cairo-glitz.h"
-
-void
-cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface)
-{
- cairo_surface_t *crsurface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- crsurface = cairo_glitz_surface_create (surface);
- if (crsurface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, crsurface);
-
- cairo_surface_destroy (crsurface);
-}
-
-typedef struct _cairo_glitz_surface {
- cairo_surface_t base;
-
- glitz_surface_t *surface;
- glitz_format_t *format;
- pixman_region16_t *clip;
-} cairo_glitz_surface_t;
-
-static void
-_cairo_glitz_surface_destroy (void *abstract_surface)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
-
- if (surface->clip)
- {
- glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
- pixman_region_destroy (surface->clip);
- }
-
- glitz_surface_destroy (surface->surface);
- free (surface);
-}
-
-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 draw,
- int width,
- int height)
-{
- cairo_glitz_surface_t *src = abstract_src;
- cairo_surface_t *crsurface;
- glitz_drawable_t *drawable;
- glitz_surface_t *surface;
- glitz_format_t *gformat;
-
- drawable = glitz_surface_get_drawable (src->surface);
-
- gformat = glitz_find_standard_format (drawable, _glitz_format (format));
- if (!gformat)
- return NULL;
-
- surface = glitz_surface_create (drawable, gformat, width, height, 0, NULL);
- if (!surface)
- return NULL;
-
- crsurface = cairo_glitz_surface_create (surface);
-
- glitz_surface_destroy (surface);
-
- return crsurface;
-}
-
-static double
-_cairo_glitz_surface_pixels_per_inch (void *abstract_surface)
-{
- return 96.0;
-}
-
-static cairo_status_t
-_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
- cairo_rectangle_t *interest,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *rect_out)
-{
- cairo_image_surface_t *image;
- int x1, y1, x2, y2;
- int width, height;
- char *pixels;
- cairo_format_masks_t format;
- glitz_buffer_t *buffer;
- glitz_pixel_format_t pf;
-
- x1 = 0;
- y1 = 0;
- x2 = glitz_surface_get_width (surface->surface);
- y2 = glitz_surface_get_height (surface->surface);
-
- if (interest)
- {
- if (interest->x > x1)
- x1 = interest->x;
- if (interest->y > y1)
- y1 = interest->y;
- if (interest->x + interest->width < x2)
- x2 = interest->x + interest->width;
- if (interest->y + interest->height < y2)
- y2 = interest->y + interest->height;
-
- if (x1 >= x2 || y1 >= y2)
- {
- *image_out = NULL;
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
- width = x2 - x1;
- height = y2 - y1;
-
- if (rect_out)
- {
- rect_out->x = x1;
- rect_out->y = y1;
- rect_out->width = width;
- rect_out->height = height;
- }
-
- if (surface->format->type == GLITZ_FORMAT_TYPE_COLOR) {
- if (surface->format->color.red_size > 0) {
- format.bpp = 32;
-
- 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;
- format.alpha_mask = 0xff000000;
- format.red_mask = 0xff0000;
- format.green_mask = 0xff00;
- format.blue_mask = 0xff;
- }
-
- pf.masks.bpp = format.bpp;
- pf.masks.alpha_mask = format.alpha_mask;
- pf.masks.red_mask = format.red_mask;
- pf.masks.green_mask = format.green_mask;
- pf.masks.blue_mask = format.blue_mask;
- pf.xoffset = 0;
- pf.skip_lines = 0;
-
- /* XXX: we should eventually return images with negative stride,
- need to verify that libpixman have no problem with this first. */
- pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4;
- pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
-
- pixels = malloc (height * pf.bytes_per_line);
- if (!pixels)
- return CAIRO_STATUS_NO_MEMORY;
-
- buffer = glitz_buffer_create_for_data (pixels);
- if (!buffer) {
- free (pixels);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- glitz_get_pixels (surface->surface,
- x1, y1,
- width, height,
- &pf,
- buffer);
-
- glitz_buffer_destroy (buffer);
-
- image = (cairo_image_surface_t *)
- _cairo_image_surface_create_with_masks (pixels,
- &format,
- width, height,
- pf.bytes_per_line);
-
- if (!image)
- {
- free (pixels);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- _cairo_image_surface_assume_ownership_of_data (image);
-
- _cairo_image_surface_set_repeat (image, surface->base.repeat);
- _cairo_image_surface_set_matrix (image, &(surface->base.matrix));
-
- *image_out = image;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_glitz_surface_set_image (void *abstract_surface,
- cairo_image_surface_t *image,
- int x_dst,
- int y_dst)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
- glitz_buffer_t *buffer;
- glitz_pixel_format_t pf;
- pixman_format_t *format;
- int am, rm, gm, bm;
- char *data;
-
- format = pixman_image_get_format (image->pixman_image);
- if (!format)
- return CAIRO_STATUS_NO_MEMORY;
-
- pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm);
-
- pf.masks.alpha_mask = am;
- pf.masks.red_mask = rm;
- pf.masks.green_mask = gm;
- pf.masks.blue_mask = bm;
- pf.xoffset = 0;
- pf.skip_lines = 0;
-
- /* check for negative stride */
- if (image->stride < 0)
- {
- pf.bytes_per_line = -image->stride;
- pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
- data = (char *) image->data + image->stride * (image->height - 1);
- }
- else
- {
- pf.bytes_per_line = image->stride;
- pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
- data = (char *) image->data;
- }
-
- buffer = glitz_buffer_create_for_data (data);
- if (!buffer)
- return CAIRO_STATUS_NO_MEMORY;
-
- glitz_set_pixels (surface->surface,
- x_dst, y_dst,
- image->width, image->height,
- &pf,
- buffer);
-
- glitz_buffer_destroy (buffer);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_glitz_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
-
- *image_extra = NULL;
-
- return _cairo_glitz_surface_get_image (surface, NULL, image_out, NULL);
-}
-
-static void
-_cairo_glitz_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_glitz_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect_out,
- void **image_extra)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
-
- status = _cairo_glitz_surface_get_image (surface, interest_rect, &image,
- image_rect_out);
- if (status)
- return status;
-
- *image_out = image;
- *image_extra = NULL;
-
- return status;
-}
-
-static void
-_cairo_glitz_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
-
- _cairo_glitz_surface_set_image (surface, image,
- image_rect->x, image_rect->y);
-
- cairo_surface_destroy (&image->base);
-}
-
-
-static cairo_status_t
-_cairo_glitz_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
- cairo_glitz_surface_t *clone;
-
- if (src->backend == surface->base.backend)
- {
- *clone_out = src;
- cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
- else if (_cairo_surface_is_image (src))
- {
- cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
-
- clone = (cairo_glitz_surface_t *)
- _cairo_glitz_surface_create_similar (surface, image_src->format, 0,
- image_src->width,
- image_src->height);
- if (!clone)
- return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_glitz_surface_set_image (clone, image_src, 0, 0);
-
- *clone_out = &clone->base;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static void
-_cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface,
- cairo_matrix_t *matrix)
-{
- glitz_transform_t transform;
-
- transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
-
- transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
-
- transform.matrix[2][0] = 0;
- transform.matrix[2][1] = 0;
- transform.matrix[2][2] = 1 << 16;
-
- glitz_surface_set_transform (surface->surface, &transform);
-}
-
-static glitz_operator_t
-_glitz_operator (cairo_operator_t op)
-{
- switch (op) {
- case CAIRO_OPERATOR_CLEAR:
- return GLITZ_OPERATOR_CLEAR;
- case CAIRO_OPERATOR_SRC:
- return GLITZ_OPERATOR_SRC;
- case CAIRO_OPERATOR_DST:
- return GLITZ_OPERATOR_DST;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return GLITZ_OPERATOR_OVER_REVERSE;
- case CAIRO_OPERATOR_IN:
- return GLITZ_OPERATOR_IN;
- case CAIRO_OPERATOR_IN_REVERSE:
- return GLITZ_OPERATOR_IN_REVERSE;
- case CAIRO_OPERATOR_OUT:
- return GLITZ_OPERATOR_OUT;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return GLITZ_OPERATOR_OUT_REVERSE;
- case CAIRO_OPERATOR_ATOP:
- return GLITZ_OPERATOR_ATOP;
- case CAIRO_OPERATOR_ATOP_REVERSE:
- return GLITZ_OPERATOR_ATOP_REVERSE;
- case CAIRO_OPERATOR_XOR:
- return GLITZ_OPERATOR_XOR;
- case CAIRO_OPERATOR_ADD:
- return GLITZ_OPERATOR_ADD;
- case CAIRO_OPERATOR_OVER:
- default:
- return GLITZ_OPERATOR_OVER;
- }
-}
-
-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;
- 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;
-
- pbuffer =
- glitz_create_pbuffer_drawable (drawable, dformat,
- glitz_surface_get_width (surface),
- glitz_surface_get_height (surface));
- if (!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;
-}
-
-typedef struct _cairo_glitz_surface_attributes {
- cairo_surface_attributes_t base;
-
- glitz_fill_t fill;
- glitz_filter_t filter;
- glitz_fixed16_16_t *params;
- int n_params;
- cairo_bool_t acquired;
-} cairo_glitz_surface_attributes_t;
-
-static cairo_int_status_t
-_cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
- cairo_glitz_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_glitz_surface_t **surface_out,
- cairo_glitz_surface_attributes_t *attr)
-{
- cairo_glitz_surface_t *src = NULL;
-
- attr->acquired = FALSE;
-
- switch (pattern->type) {
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- cairo_gradient_pattern_t *gradient =
- (cairo_gradient_pattern_t *) pattern;
- glitz_drawable_t *drawable;
- glitz_fixed16_16_t *params;
- int n_params;
- int i;
- unsigned short alpha;
-
- /* XXX: the current color gradient acceleration provided by glitz is
- * experimental, it's been proven inappropriate in a number of ways,
- * most importantly, it's currently implemented as filters and
- * gradients are not filters. eventually, it will be replaced with
- * something more appropriate.
- */
-
- if (gradient->n_stops < 2)
- break;
-
- /* glitz doesn't support inner and outer circle with different
- center points. */
- if (pattern->type == CAIRO_PATTERN_RADIAL)
- {
- cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
-
- if (grad->center0.x != grad->center1.x ||
- grad->center0.y != grad->center1.y)
- break;
- }
-
- drawable = glitz_surface_get_drawable (dst->surface);
- if (!(glitz_drawable_get_features (drawable) &
- GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
- break;
-
- if (pattern->filter != CAIRO_FILTER_BILINEAR &&
- pattern->filter != CAIRO_FILTER_GOOD &&
- pattern->filter != CAIRO_FILTER_BEST)
- break;
-
- alpha = (gradient->stops[0].color.alpha * pattern->alpha) * 0xffff;
- for (i = 1; i < gradient->n_stops; i++)
- {
- unsigned short a;
-
- a = (gradient->stops[i].color.alpha * pattern->alpha) * 0xffff;
- if (a != alpha)
- break;
- }
-
- /* we can't have color stops with different alpha as gradient color
- interpolation should be done to unpremultiplied colors. */
- if (i < gradient->n_stops)
- break;
-
- n_params = gradient->n_stops * 3 + 4;
-
- params = malloc (sizeof (glitz_fixed16_16_t) * n_params);
- if (!params)
- return CAIRO_STATUS_NO_MEMORY;
-
- src = (cairo_glitz_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- CAIRO_FORMAT_ARGB32, 0,
- gradient->n_stops, 1);
- if (!src)
- {
- free (params);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- for (i = 0; i < gradient->n_stops; i++) {
- glitz_color_t color;
-
- color.red = gradient->stops[i].color.red * alpha;
- color.green = gradient->stops[i].color.green * alpha;
- color.blue = gradient->stops[i].color.blue * alpha;
- color.alpha = alpha;
-
- glitz_set_rectangle (src->surface, &color, i, 0, 1, 1);
-
- params[4 + 3 * i] = gradient->stops[i].offset;
- params[5 + 3 * i] = i << 16;
- params[6 + 3 * i] = 0;
- }
-
- if (pattern->type == CAIRO_PATTERN_LINEAR)
- {
- cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern;
-
- params[0] = _cairo_fixed_from_double (grad->point0.x);
- params[1] = _cairo_fixed_from_double (grad->point0.y);
- params[2] = _cairo_fixed_from_double (grad->point1.x);
- params[3] = _cairo_fixed_from_double (grad->point1.y);
- attr->filter = GLITZ_FILTER_LINEAR_GRADIENT;
- }
- else
- {
- cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
-
- params[0] = _cairo_fixed_from_double (grad->center0.x);
- params[1] = _cairo_fixed_from_double (grad->center0.y);
- params[2] = _cairo_fixed_from_double (grad->radius0);
- params[3] = _cairo_fixed_from_double (grad->radius1);
- attr->filter = GLITZ_FILTER_RADIAL_GRADIENT;
- }
-
- switch (pattern->extend) {
- case CAIRO_EXTEND_NONE:
- attr->fill = GLITZ_FILL_NEAREST;
- break;
- case CAIRO_EXTEND_REPEAT:
- attr->fill = GLITZ_FILL_REPEAT;
- break;
- case CAIRO_EXTEND_REFLECT:
- attr->fill = GLITZ_FILL_REFLECT;
- break;
- }
-
- attr->params = params;
- attr->n_params = n_params;
- attr->base.matrix = pattern->matrix;
- attr->base.x_offset = 0;
- attr->base.y_offset = 0;
- } break;
- default:
- break;
- }
-
- if (!src)
- {
- cairo_int_status_t status;
-
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- x, y, width, height,
- (cairo_surface_t **) &src,
- &attr->base);
- if (status)
- return status;
-
- if (src)
- {
- switch (attr->base.extend) {
- case CAIRO_EXTEND_NONE:
- attr->fill = GLITZ_FILL_TRANSPARENT;
- break;
- case CAIRO_EXTEND_REPEAT:
- attr->fill = GLITZ_FILL_REPEAT;
- break;
- case CAIRO_EXTEND_REFLECT:
- attr->fill = GLITZ_FILL_REFLECT;
- break;
- }
-
- switch (attr->base.filter) {
- case CAIRO_FILTER_FAST:
- case CAIRO_FILTER_NEAREST:
- attr->filter = GLITZ_FILTER_NEAREST;
- break;
- case CAIRO_FILTER_GOOD:
- case CAIRO_FILTER_BEST:
- case CAIRO_FILTER_BILINEAR:
- default:
- attr->filter = GLITZ_FILTER_BILINEAR;
- break;
- }
-
- attr->params = NULL;
- attr->n_params = 0;
- attr->acquired = TRUE;
- }
- }
-
- *surface_out = src;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst,
- cairo_glitz_surface_t *surface,
- cairo_glitz_surface_attributes_t *attr)
-{
- if (attr->acquired)
- _cairo_pattern_release_surface (&dst->base, &surface->base,
- &attr->base);
- else
- _cairo_glitz_surface_destroy (surface);
-}
-
-static cairo_int_status_t
-_cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
- cairo_pattern_t *mask,
- cairo_glitz_surface_t *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- unsigned int width,
- unsigned int height,
- cairo_glitz_surface_t **src_out,
- cairo_glitz_surface_t **mask_out,
- cairo_glitz_surface_attributes_t *sattr,
- cairo_glitz_surface_attributes_t *mattr)
-{
- cairo_int_status_t status;
- cairo_pattern_union_t tmp;
- cairo_bool_t src_opaque, mask_opaque;
- double src_alpha, mask_alpha;
-
- src_opaque = _cairo_pattern_is_opaque (src);
- mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
-
- /* For surface patterns, we move any translucency from src->alpha
- * to mask->alpha so we can use the source unchanged. Otherwise we
- * move the translucency from mask->alpha to src->alpha so that
- * we can drop the mask if possible.
- */
- if (src->type == CAIRO_PATTERN_SURFACE)
- {
- if (mask) {
- mask_opaque = mask_opaque && src_opaque;
- mask_alpha = mask->alpha * src->alpha;
- } else {
- mask_opaque = src_opaque;
- mask_alpha = src->alpha;
- }
-
- src_alpha = 1.0;
- src_opaque = TRUE;
- }
- else
- {
- if (mask)
- {
- src_opaque = mask_opaque && src_opaque;
- src_alpha = mask->alpha * src->alpha;
- /* FIXME: This needs changing when we support RENDER
- * style 4-channel masks.
- */
- if (mask->type == CAIRO_PATTERN_SOLID)
- mask = NULL;
- } else
- src_alpha = src->alpha;
-
- mask_alpha = 1.0;
- mask_opaque = TRUE;
- }
-
- _cairo_pattern_init_copy (&tmp.base, src);
- _cairo_pattern_set_alpha (&tmp.base, src_alpha);
-
- status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
- src_x, src_y,
- width, height,
- src_out, sattr);
-
- _cairo_pattern_fini (&tmp.base);
-
- if (status)
- return status;
-
- if (mask || !mask_opaque)
- {
- if (mask)
- _cairo_pattern_init_copy (&tmp.base, mask);
- else
- _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
-
- _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
-
- status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
- mask_x, mask_y,
- width, height,
- mask_out, mattr);
-
- _cairo_pattern_fini (&tmp.base);
-
- if (status)
- {
- _cairo_glitz_pattern_release_surface (dst, *src_out, sattr);
- return status;
- }
- }
- else
- {
- *mask_out = NULL;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface,
- cairo_glitz_surface_attributes_t *a)
-{
- _cairo_glitz_surface_set_matrix (surface, &a->base.matrix);
- glitz_surface_set_fill (surface->surface, a->fill);
- glitz_surface_set_filter (surface->surface, a->filter,
- a->params, a->n_params);
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_composite (cairo_operator_t op,
- cairo_pattern_t *src_pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_glitz_surface_attributes_t src_attr, mask_attr;
- cairo_glitz_surface_t *dst = abstract_dst;
- cairo_glitz_surface_t *src;
- cairo_glitz_surface_t *mask;
- cairo_int_status_t status;
-
- if (op == CAIRO_OPERATOR_SATURATE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (_glitz_ensure_target (dst->surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern,
- dst,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- &src, &mask,
- &src_attr, &mask_attr);
- if (status)
- return status;
-
- _cairo_glitz_surface_set_attributes (src, &src_attr);
- if (mask)
- {
- _cairo_glitz_surface_set_attributes (mask, &mask_attr);
- glitz_composite (_glitz_operator (op),
- src->surface,
- mask->surface,
- dst->surface,
- src_x + src_attr.base.x_offset,
- src_y + src_attr.base.y_offset,
- mask_x + mask_attr.base.x_offset,
- mask_y + mask_attr.base.y_offset,
- dst_x, dst_y,
- width, height);
-
- if (mask_attr.n_params)
- free (mask_attr.params);
-
- _cairo_glitz_pattern_release_surface (dst, mask, &mask_attr);
- }
- else
- {
- glitz_composite (_glitz_operator (op),
- src->surface,
- NULL,
- dst->surface,
- src_x + src_attr.base.x_offset,
- src_y + src_attr.base.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- }
-
- if (src_attr.n_params)
- free (src_attr.params);
-
- _cairo_glitz_pattern_release_surface (dst, src, &src_attr);
-
- if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_fill_rectangles (void *abstract_dst,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int n_rects)
-{
- cairo_glitz_surface_t *dst = abstract_dst;
-
- if (op == CAIRO_OPERATOR_SRC)
- {
- glitz_color_t glitz_color;
-
- glitz_color.red = color->red_short;
- glitz_color.green = color->green_short;
- glitz_color.blue = color->blue_short;
- glitz_color.alpha = color->alpha_short;
-
- if (glitz_surface_get_width (dst->surface) != 1 ||
- glitz_surface_get_height (dst->surface) != 1)
- _glitz_ensure_target (dst->surface);
-
- glitz_set_rectangles (dst->surface, &glitz_color,
- (glitz_rectangle_t *) rects, n_rects);
- }
- else
- {
- cairo_glitz_surface_t *src;
-
- if (op == CAIRO_OPERATOR_SATURATE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (_glitz_ensure_target (dst->surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- src = (cairo_glitz_surface_t *)
- _cairo_surface_create_similar_solid (&dst->base,
- CAIRO_FORMAT_ARGB32, 1, 1,
- (cairo_color_t *) color);
- if (!src)
- return CAIRO_STATUS_NO_MEMORY;
-
- while (n_rects--)
- {
- glitz_composite (_glitz_operator (op),
- src->surface,
- NULL,
- dst->surface,
- 0, 0,
- 0, 0,
- rects->x, rects->y,
- rects->width, rects->height);
- rects++;
- }
-
- cairo_surface_destroy (&src->base);
- }
-
- if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int n_traps)
-{
- cairo_glitz_surface_attributes_t attributes;
- cairo_glitz_surface_t *dst = abstract_dst;
- cairo_glitz_surface_t *src;
- cairo_glitz_surface_t *mask = NULL;
- glitz_buffer_t *buffer = NULL;
- void *data = NULL;
- cairo_int_status_t status;
- unsigned short alpha;
-
- if (op == CAIRO_OPERATOR_SATURATE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (_glitz_ensure_target (dst->surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (pattern->type == CAIRO_PATTERN_SURFACE)
- {
- cairo_pattern_union_t tmp;
-
- _cairo_pattern_init_copy (&tmp.base, pattern);
- _cairo_pattern_set_alpha (&tmp.base, 1.0);
-
- status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
- src_x, src_y,
- width, height,
- &src, &attributes);
-
- _cairo_pattern_fini (&tmp.base);
-
- alpha = pattern->alpha * 0xffff;
- }
- else
- {
- status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
- src_x, src_y,
- width, height,
- &src, &attributes);
- alpha = 0xffff;
- }
-
- if (status)
- return status;
-
- if (op == CAIRO_OPERATOR_ADD || n_traps <= 1)
- {
- static glitz_color_t clear_black = { 0, 0, 0, 0 };
- glitz_color_t color;
- glitz_geometry_format_t format;
- int n_trap_added;
- int offset = 0;
- int data_size = 0;
- int size = 30 * n_traps; /* just a guess */
-
- format.vertex.primitive = GLITZ_PRIMITIVE_QUADS;
- format.vertex.type = GLITZ_DATA_TYPE_FLOAT;
- format.vertex.bytes_per_vertex = 3 * sizeof (glitz_float_t);
- format.vertex.attributes = GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK;
- format.vertex.mask.type = GLITZ_DATA_TYPE_FLOAT;
- format.vertex.mask.size = GLITZ_COORDINATE_SIZE_X;
- format.vertex.mask.offset = 2 * sizeof (glitz_float_t);
-
- mask = (cairo_glitz_surface_t *)
- _cairo_glitz_surface_create_similar (&dst->base,
- CAIRO_FORMAT_A8, 0,
- 2, 1);
- if (!mask)
- {
- _cairo_glitz_pattern_release_surface (dst, src, &attributes);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- color.red = color.green = color.blue = color.alpha = alpha;
-
- glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1);
- glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1);
-
- glitz_surface_set_fill (mask->surface, GLITZ_FILL_NEAREST);
- glitz_surface_set_filter (mask->surface,
- GLITZ_FILTER_BILINEAR,
- NULL, 0);
-
- size *= format.vertex.bytes_per_vertex;
-
- while (n_traps)
- {
- if (data_size < size)
- {
- data_size = size;
- data = realloc (data, data_size);
- if (!data)
- {
- _cairo_glitz_pattern_release_surface (dst, src,
- &attributes);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- if (buffer)
- glitz_buffer_destroy (buffer);
-
- buffer = glitz_buffer_create_for_data (data);
- if (!buffer) {
- free (data);
- _cairo_glitz_pattern_release_surface (dst, src,
- &attributes);
- return CAIRO_STATUS_NO_MEMORY;
- }
- }
-
- offset +=
- glitz_add_trapezoids (buffer,
- offset, size - offset,
- format.vertex.type, mask->surface,
- (glitz_trapezoid_t *) traps, n_traps,
- &n_trap_added);
-
- n_traps -= n_trap_added;
- traps += n_trap_added;
- size *= 2;
- }
-
- glitz_set_geometry (dst->surface,
- GLITZ_GEOMETRY_TYPE_VERTEX,
- &format, buffer);
- glitz_set_array (dst->surface, 0, 3,
- offset / format.vertex.bytes_per_vertex,
- 0, 0);
- }
- else
- {
- cairo_image_surface_t *image;
- char *ptr;
- int stride;
-
- stride = (width + 3) & -4;
- data = malloc (stride * height);
- if (!data)
- {
- _cairo_glitz_pattern_release_surface (dst, src, &attributes);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- memset (data, 0, stride * height);
-
- /* using negative stride */
- ptr = (char *) data + stride * (height - 1);
-
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (ptr,
- CAIRO_FORMAT_A8,
- width, height,
- -stride);
- if (!image)
- {
- cairo_surface_destroy (&src->base);
- free (data);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
- (pixman_trapezoid_t *) traps, n_traps);
-
- if (alpha != 0xffff)
- {
- pixman_color_t color;
-
- color.red = color.green = color.blue = color.alpha = alpha;
-
- pixman_fill_rectangle (PIXMAN_OPERATOR_IN,
- image->pixman_image,
- &color,
- 0, 0, width, height);
- }
-
- mask = (cairo_glitz_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- CAIRO_FORMAT_A8, 0,
- width, height);
- if (!mask)
- {
- _cairo_glitz_pattern_release_surface (dst, src, &attributes);
- free (data);
- cairo_surface_destroy (&image->base);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- _cairo_glitz_surface_set_image (mask, image, 0, 0);
- }
-
- _cairo_glitz_surface_set_attributes (src, &attributes);
-
- glitz_composite (_glitz_operator (op),
- src->surface,
- mask->surface,
- dst->surface,
- src_x + attributes.base.x_offset,
- src_y + attributes.base.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
-
- if (attributes.n_params)
- free (attributes.params);
-
- glitz_set_geometry (dst->surface,
- GLITZ_GEOMETRY_TYPE_NONE,
- NULL, NULL);
-
- if (buffer)
- glitz_buffer_destroy (buffer);
-
- free (data);
-
- _cairo_glitz_pattern_release_surface (dst, src, &attributes);
- if (mask)
- cairo_surface_destroy (&mask->base);
-
- if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_glitz_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_glitz_surface_t *surface = abstract_surface;
-
- if (region)
- {
- glitz_box_t *box;
- int n;
-
- if (!surface->clip)
- {
- surface->clip = pixman_region_create ();
- if (!surface->clip)
- return CAIRO_STATUS_NO_MEMORY;
- }
- pixman_region_copy (surface->clip, region);
-
- box = (glitz_box_t *) pixman_region_rects (surface->clip);
- n = pixman_region_num_rects (surface->clip);
- glitz_surface_set_clip_region (surface->surface, 0, 0, box, n);
- }
- else
- {
- glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
-
- if (surface->clip)
- pixman_region_destroy (surface->clip);
-
- surface->clip = NULL;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static const cairo_surface_backend_t cairo_glitz_surface_backend = {
- _cairo_glitz_surface_create_similar,
- _cairo_glitz_surface_destroy,
- _cairo_glitz_surface_pixels_per_inch,
- _cairo_glitz_surface_acquire_source_image,
- _cairo_glitz_surface_release_source_image,
- _cairo_glitz_surface_acquire_dest_image,
- _cairo_glitz_surface_release_dest_image,
- _cairo_glitz_surface_clone_similar,
- _cairo_glitz_surface_composite,
- _cairo_glitz_surface_fill_rectangles,
- _cairo_glitz_surface_composite_trapezoids,
- _cairo_glitz_surface_copy_page,
- _cairo_glitz_surface_show_page,
- _cairo_glitz_surface_set_clip_region,
- NULL /* show_glyphs */
-};
-
-cairo_surface_t *
-cairo_glitz_surface_create (glitz_surface_t *surface)
-{
- cairo_glitz_surface_t *crsurface;
-
- if (!surface)
- return NULL;
-
- crsurface = malloc (sizeof (cairo_glitz_surface_t));
- if (crsurface == NULL)
- return NULL;
-
- _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend);
-
- glitz_surface_reference (surface);
-
- crsurface->surface = surface;
- crsurface->format = glitz_surface_get_format (surface);
- crsurface->clip = NULL;
-
- return (cairo_surface_t *) crsurface;
-}
diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c
deleted file mode 100644
index d6db560a3..000000000
--- a/src/cairo_gstate.c
+++ /dev/null
@@ -1,2566 +0,0 @@
-/* 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@cworth.org>
- */
-
-#include <stdlib.h>
-#include <math.h>
-
-#include "cairoint.h"
-
-static cairo_status_t
-_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
- cairo_pattern_t *src,
- cairo_operator_t operator,
- cairo_surface_t *dst,
- cairo_traps_t *traps);
-
-static cairo_status_t
-_cairo_gstate_ensure_font (cairo_gstate_t *gstate);
-
-static void
-_cairo_gstate_unset_font (cairo_gstate_t *gstate);
-
-cairo_gstate_t *
-_cairo_gstate_create ()
-{
- cairo_status_t status;
- cairo_gstate_t *gstate;
-
- gstate = malloc (sizeof (cairo_gstate_t));
-
- if (gstate)
- {
- status = _cairo_gstate_init (gstate);
- if (status) {
- free (gstate);
- return NULL;
- }
- }
-
- return gstate;
-}
-
-cairo_status_t
-_cairo_gstate_init (cairo_gstate_t *gstate)
-{
- gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
-
- gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
-
- gstate->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT;
- gstate->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT;
- gstate->line_join = CAIRO_GSTATE_LINE_JOIN_DEFAULT;
- gstate->miter_limit = CAIRO_GSTATE_MITER_LIMIT_DEFAULT;
-
- gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
-
- gstate->dash = NULL;
- gstate->num_dashes = 0;
- gstate->dash_offset = 0.0;
-
- gstate->font_family = NULL;
- gstate->font_slant = CAIRO_FONT_SLANT_DEFAULT;
- gstate->font_weight = CAIRO_FONT_WEIGHT_DEFAULT;
-
- gstate->font = NULL;
-
- gstate->surface = NULL;
-
- gstate->clip.region = NULL;
- gstate->clip.surface = NULL;
-
- gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0);
- if (!gstate->pattern)
- return CAIRO_STATUS_NO_MEMORY;
-
- gstate->alpha = 1.0;
-
- gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
- _cairo_gstate_default_matrix (gstate);
-
- _cairo_path_init (&gstate->path);
-
- _cairo_pen_init_empty (&gstate->pen_regular);
-
- gstate->next = NULL;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
-{
- cairo_status_t status;
- cairo_gstate_t *next;
-
- /* Copy all members, but don't smash the next pointer */
- next = gstate->next;
- *gstate = *other;
- gstate->next = next;
-
- /* Now fix up pointer data that needs to be cloned/referenced */
- if (other->dash) {
- gstate->dash = malloc (other->num_dashes * sizeof (double));
- if (gstate->dash == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
- }
-
- if (other->font_family) {
- gstate->font_family = strdup (other->font_family);
- if (!gstate->font_family)
- goto CLEANUP_DASH;
- }
-
- if (other->font) {
- gstate->font = other->font;
- cairo_font_reference (gstate->font);
- }
-
- if (other->clip.region)
- {
- gstate->clip.region = pixman_region_create ();
- pixman_region_copy (gstate->clip.region, other->clip.region);
- }
-
- cairo_surface_reference (gstate->surface);
- cairo_surface_reference (gstate->clip.surface);
-
- cairo_pattern_reference (gstate->pattern);
-
- status = _cairo_path_init_copy (&gstate->path, &other->path);
- if (status)
- goto CLEANUP_FONT;
-
- status = _cairo_pen_init_copy (&gstate->pen_regular, &other->pen_regular);
- if (status)
- goto CLEANUP_PATH;
-
- return status;
-
- CLEANUP_PATH:
- _cairo_path_fini (&gstate->path);
-
- CLEANUP_FONT:
- cairo_font_destroy (gstate->font);
- gstate->font = NULL;
-
- if (gstate->font_family) {
- free (gstate->font_family);
- gstate->font_family = NULL;
- }
-
- CLEANUP_DASH:
- free (gstate->dash);
- gstate->dash = NULL;
-
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-void
-_cairo_gstate_fini (cairo_gstate_t *gstate)
-{
- if (gstate->font_family)
- free (gstate->font_family);
-
- if (gstate->font)
- cairo_font_destroy (gstate->font);
-
- if (gstate->surface)
- cairo_surface_destroy (gstate->surface);
- gstate->surface = NULL;
-
- if (gstate->clip.surface)
- cairo_surface_destroy (gstate->clip.surface);
- gstate->clip.surface = NULL;
-
- if (gstate->clip.region)
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = NULL;
-
- cairo_pattern_destroy (gstate->pattern);
-
- _cairo_matrix_fini (&gstate->font_matrix);
-
- _cairo_matrix_fini (&gstate->ctm);
- _cairo_matrix_fini (&gstate->ctm_inverse);
-
- _cairo_path_fini (&gstate->path);
-
- _cairo_pen_fini (&gstate->pen_regular);
-
- if (gstate->dash) {
- free (gstate->dash);
- gstate->dash = NULL;
- }
-}
-
-void
-_cairo_gstate_destroy (cairo_gstate_t *gstate)
-{
- _cairo_gstate_fini (gstate);
- free (gstate);
-}
-
-cairo_gstate_t*
-_cairo_gstate_clone (cairo_gstate_t *gstate)
-{
- cairo_status_t status;
- cairo_gstate_t *clone;
-
- clone = malloc (sizeof (cairo_gstate_t));
- if (clone) {
- status = _cairo_gstate_init_copy (clone, gstate);
- if (status) {
- free (clone);
- return NULL;
- }
- }
- clone->next = NULL;
-
- return clone;
-}
-
-cairo_status_t
-_cairo_gstate_copy (cairo_gstate_t *dest, cairo_gstate_t *src)
-{
- cairo_status_t status;
- cairo_gstate_t *next;
-
- /* Preserve next pointer over fini/init */
- next = dest->next;
- _cairo_gstate_fini (dest);
- status = _cairo_gstate_init_copy (dest, src);
- dest->next = next;
-
- return status;
-}
-
-/* Push rendering off to an off-screen group. */
-/* XXX: Rethinking this API
-cairo_status_t
-_cairo_gstate_begin_group (cairo_gstate_t *gstate)
-{
- Pixmap pix;
- cairo_color_t clear;
- unsigned int width, height;
-
- gstate->parent_surface = gstate->surface;
-
- width = _cairo_surface_get_width (gstate->surface);
- height = _cairo_surface_get_height (gstate->surface);
-
- pix = XCreatePixmap (gstate->dpy,
- _cairo_surface_get_drawable (gstate->surface),
- width, height,
- _cairo_surface_get_depth (gstate->surface));
- if (pix == 0)
- return CAIRO_STATUS_NO_MEMORY;
-
- gstate->surface = cairo_surface_create (gstate->dpy);
- if (gstate->surface == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_surface_set_drawableWH (gstate->surface, pix, width, height);
-
- _cairo_color_init (&clear);
- _cairo_color_set_alpha (&clear, 0);
-
- status = _cairo_surface_fill_rectangle (gstate->surface,
- CAIRO_OPERATOR_SRC,
- &clear,
- 0, 0,
- _cairo_surface_get_width (gstate->surface),
- _cairo_surface_get_height (gstate->surface));
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-*/
-
-/* Complete the current offscreen group, composing its contents onto the parent surface. */
-/* XXX: Rethinking this API
-cairo_status_t
-_cairo_gstate_end_group (cairo_gstate_t *gstate)
-{
- Pixmap pix;
- cairo_color_t mask_color;
- cairo_surface_t mask;
-
- if (gstate->parent_surface == NULL)
- return CAIRO_STATUS_INVALID_POP_GROUP;
-
- _cairo_surface_init (&mask, gstate->dpy);
- _cairo_color_init (&mask_color);
- _cairo_color_set_alpha (&mask_color, gstate->alpha);
-
- _cairo_surface_set_solid_color (&mask, &mask_color);
-
- * XXX: This could be made much more efficient by using
- _cairo_surface_get_damaged_width/Height if cairo_surface_t actually kept
- track of such informaton. *
- _cairo_surface_composite (gstate->operator,
- gstate->surface,
- mask,
- gstate->parent_surface,
- 0, 0,
- 0, 0,
- 0, 0,
- _cairo_surface_get_width (gstate->surface),
- _cairo_surface_get_height (gstate->surface));
-
- _cairo_surface_fini (&mask);
-
- pix = _cairo_surface_get_drawable (gstate->surface);
- XFreePixmap (gstate->dpy, pix);
-
- cairo_surface_destroy (gstate->surface);
- gstate->surface = gstate->parent_surface;
- gstate->parent_surface = NULL;
-
- return CAIRO_STATUS_SUCCESS;
-}
-*/
-
-cairo_status_t
-_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface)
-{
- double scale;
-
- _cairo_gstate_unset_font (gstate);
-
- if (gstate->surface)
- cairo_surface_destroy (gstate->surface);
-
- gstate->surface = surface;
-
- /* Sometimes the user wants to return to having no target surface,
- * (just like after cairo_create). This can be useful for forcing
- * the old surface to be destroyed. */
- if (surface == NULL)
- return CAIRO_STATUS_SUCCESS;
-
- cairo_surface_reference (gstate->surface);
-
- scale = _cairo_surface_pixels_per_inch (surface) / gstate->pixels_per_inch;
- _cairo_gstate_scale (gstate, scale, scale);
- gstate->pixels_per_inch = _cairo_surface_pixels_per_inch (surface);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* XXX: Need to decide the memory mangement semantics of this
- function. Should it reference the surface again? */
-cairo_surface_t *
-_cairo_gstate_current_target_surface (cairo_gstate_t *gstate)
-{
- if (gstate == NULL)
- return NULL;
-
-/* XXX: Do we want this?
- if (gstate->surface)
- _cairo_surface_reference (gstate->surface);
-*/
-
- return gstate->surface;
-}
-
-cairo_status_t
-_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern)
-{
- if (pattern == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- cairo_pattern_reference (pattern);
- cairo_pattern_destroy (gstate->pattern);
- gstate->pattern = pattern;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_pattern_t *
-_cairo_gstate_current_pattern (cairo_gstate_t *gstate)
-{
- if (gstate == NULL)
- return NULL;
-
-/* XXX: Do we want this?
- cairo_pattern_reference (gstate->pattern);
-*/
-
- return gstate->pattern;
-}
-
-cairo_status_t
-_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator)
-{
- gstate->operator = operator;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_operator_t
-_cairo_gstate_current_operator (cairo_gstate_t *gstate)
-{
- return gstate->operator;
-}
-
-cairo_status_t
-_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue)
-{
- cairo_pattern_destroy (gstate->pattern);
-
- gstate->pattern = _cairo_pattern_create_solid (red, green, blue);
- if (!gstate->pattern)
- return CAIRO_STATUS_NO_MEMORY;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_current_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue)
-{
- return _cairo_pattern_get_rgb (gstate->pattern, red, green, blue);
-}
-
-cairo_status_t
-_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
-{
- gstate->tolerance = tolerance;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-double
-_cairo_gstate_current_tolerance (cairo_gstate_t *gstate)
-{
- return gstate->tolerance;
-}
-
-cairo_status_t
-_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha)
-{
- gstate->alpha = alpha;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-double
-_cairo_gstate_current_alpha (cairo_gstate_t *gstate)
-{
- return gstate->alpha;
-}
-
-cairo_status_t
-_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule)
-{
- gstate->fill_rule = fill_rule;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_fill_rule_t
-_cairo_gstate_current_fill_rule (cairo_gstate_t *gstate)
-{
- return gstate->fill_rule;
-}
-
-cairo_status_t
-_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
-{
- gstate->line_width = width;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-double
-_cairo_gstate_current_line_width (cairo_gstate_t *gstate)
-{
- return gstate->line_width;
-}
-
-cairo_status_t
-_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
-{
- gstate->line_cap = line_cap;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_line_cap_t
-_cairo_gstate_current_line_cap (cairo_gstate_t *gstate)
-{
- return gstate->line_cap;
-}
-
-cairo_status_t
-_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join)
-{
- gstate->line_join = line_join;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_line_join_t
-_cairo_gstate_current_line_join (cairo_gstate_t *gstate)
-{
- return gstate->line_join;
-}
-
-cairo_status_t
-_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset)
-{
- if (gstate->dash) {
- free (gstate->dash);
- gstate->dash = NULL;
- }
-
- gstate->num_dashes = num_dashes;
- if (gstate->num_dashes) {
- gstate->dash = malloc (gstate->num_dashes * sizeof (double));
- if (gstate->dash == NULL) {
- gstate->num_dashes = 0;
- return CAIRO_STATUS_NO_MEMORY;
- }
- }
-
- memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double));
- gstate->dash_offset = offset;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit)
-{
- gstate->miter_limit = limit;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-double
-_cairo_gstate_current_miter_limit (cairo_gstate_t *gstate)
-{
- return gstate->miter_limit;
-}
-
-void
-_cairo_gstate_current_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
-{
- cairo_matrix_copy (matrix, &gstate->ctm);
-}
-
-cairo_status_t
-_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
-{
- cairo_matrix_t tmp;
-
- _cairo_gstate_unset_font (gstate);
-
- _cairo_matrix_set_translate (&tmp, tx, ty);
- cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
-
- _cairo_matrix_set_translate (&tmp, -tx, -ty);
- cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
-{
- cairo_matrix_t tmp;
-
- if (sx == 0 || sy == 0)
- return CAIRO_STATUS_INVALID_MATRIX;
-
- _cairo_gstate_unset_font (gstate);
-
- _cairo_matrix_set_scale (&tmp, sx, sy);
- cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
-
- _cairo_matrix_set_scale (&tmp, 1/sx, 1/sy);
- cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
-{
- cairo_matrix_t tmp;
-
- _cairo_gstate_unset_font (gstate);
-
- _cairo_matrix_set_rotate (&tmp, angle);
- cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
-
- _cairo_matrix_set_rotate (&tmp, -angle);
- cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- cairo_matrix_t tmp;
-
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_copy (&tmp, matrix);
- cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
-
- cairo_matrix_invert (&tmp);
- cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- cairo_status_t status;
-
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_copy (&gstate->ctm, matrix);
-
- cairo_matrix_copy (&gstate->ctm_inverse, matrix);
- status = cairo_matrix_invert (&gstate->ctm_inverse);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_default_matrix (cairo_gstate_t *gstate)
-{
- int scale = gstate->pixels_per_inch / CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT + 0.5;
- if (scale == 0)
- scale = 1;
-
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_set_identity (&gstate->font_matrix);
-
- cairo_matrix_set_identity (&gstate->ctm);
- cairo_matrix_scale (&gstate->ctm, scale, scale);
- cairo_matrix_copy (&gstate->ctm_inverse, &gstate->ctm);
- cairo_matrix_invert (&gstate->ctm_inverse);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
-{
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_set_identity (&gstate->ctm);
- cairo_matrix_set_identity (&gstate->ctm_inverse);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_transform_point (cairo_gstate_t *gstate, double *x, double *y)
-{
- cairo_matrix_transform_point (&gstate->ctm, x, y);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy)
-{
- cairo_matrix_transform_distance (&gstate->ctm, dx, dy);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y)
-{
- cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy)
-{
- cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_new_path (cairo_gstate_t *gstate)
-{
- _cairo_path_fini (&gstate->path);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y)
-{
- cairo_point_t point;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
-
- return _cairo_path_move_to (&gstate->path, &point);
-}
-
-cairo_status_t
-_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y)
-{
- cairo_point_t point;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
-
- return _cairo_path_line_to (&gstate->path, &point);
-}
-
-cairo_status_t
-_cairo_gstate_curve_to (cairo_gstate_t *gstate,
- double x0, double y0,
- double x1, double y1,
- double x2, double y2)
-{
- cairo_point_t p0, p1, p2;
-
- cairo_matrix_transform_point (&gstate->ctm, &x0, &y0);
- cairo_matrix_transform_point (&gstate->ctm, &x1, &y1);
- cairo_matrix_transform_point (&gstate->ctm, &x2, &y2);
-
- p0.x = _cairo_fixed_from_double (x0);
- p0.y = _cairo_fixed_from_double (y0);
-
- p1.x = _cairo_fixed_from_double (x1);
- p1.y = _cairo_fixed_from_double (y1);
-
- p2.x = _cairo_fixed_from_double (x2);
- p2.y = _cairo_fixed_from_double (y2);
-
- return _cairo_path_curve_to (&gstate->path, &p0, &p1, &p2);
-}
-
-/* Spline deviation from the circle in radius would be given by:
-
- error = sqrt (x**2 + y**2) - 1
-
- A simpler error function to work with is:
-
- e = x**2 + y**2 - 1
-
- From "Good approximation of circles by curvature-continuous Bezier
- curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
- Design 8 (1990) 22-41, we learn:
-
- abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
-
- and
- abs (error) =~ 1/2 * e
-
- Of course, this error value applies only for the particular spline
- approximation that is used in _cairo_gstate_arc_segment.
-*/
-static double
-_arc_error_normalized (double angle)
-{
- return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
-}
-
-static double
-_arc_max_angle_for_tolerance_normalized (double tolerance)
-{
- double angle, error;
- int i;
-
- /* Use table lookup to reduce search time in most cases. */
- struct {
- double angle;
- double error;
- } table[] = {
- { M_PI / 1.0, 0.0185185185185185036127 },
- { M_PI / 2.0, 0.000272567143730179811158 },
- { M_PI / 3.0, 2.38647043651461047433e-05 },
- { M_PI / 4.0, 4.2455377443222443279e-06 },
- { M_PI / 5.0, 1.11281001494389081528e-06 },
- { M_PI / 6.0, 3.72662000942734705475e-07 },
- { M_PI / 7.0, 1.47783685574284411325e-07 },
- { M_PI / 8.0, 6.63240432022601149057e-08 },
- { M_PI / 9.0, 3.2715520137536980553e-08 },
- { M_PI / 10.0, 1.73863223499021216974e-08 },
- { M_PI / 11.0, 9.81410988043554039085e-09 },
- };
- int table_size = (sizeof (table) / sizeof (table[0]));
-
- for (i = 0; i < table_size; i++)
- if (table[i].error < tolerance)
- return table[i].angle;
-
- ++i;
- do {
- angle = M_PI / i++;
- error = _arc_error_normalized (angle);
- } while (error > tolerance);
-
- return angle;
-}
-
-static int
-_cairo_gstate_arc_segments_needed (cairo_gstate_t *gstate,
- double angle,
- double radius)
-{
- double l1, l2, lmax;
- double max_angle;
-
- _cairo_matrix_compute_eigen_values (&gstate->ctm, &l1, &l2);
-
- l1 = fabs (l1);
- l2 = fabs (l2);
- if (l1 > l2)
- lmax = l1;
- else
- lmax = l2;
-
- max_angle = _arc_max_angle_for_tolerance_normalized (gstate->tolerance / (radius * lmax));
-
- return (int) ceil (angle / max_angle);
-}
-
-/* We want to draw a single spline approximating a circular arc radius
- R from angle A to angle B. Since we want a symmetric spline that
- matches the endpoints of the arc in position and slope, we know
- that the spline control points must be:
-
- (R * cos(A), R * sin(A))
- (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
- (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
- (R * cos(B), R * sin(B))
-
- for some value of h.
-
- "Approximation of circular arcs by cubic poynomials", Michael
- Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
- various values of h along with error analysis for each.
-
- From that paper, a very practical value of h is:
-
- h = 4/3 * tan(angle/4)
-
- This value does not give the spline with minimal error, but it does
- provide a very good approximation, (6th-order convergence), and the
- error expression is quite simple, (see the comment for
- _arc_error_normalized).
-*/
-static cairo_status_t
-_cairo_gstate_arc_segment (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle_A, double angle_B)
-{
- cairo_status_t status;
- double r_sin_A, r_cos_A;
- double r_sin_B, r_cos_B;
- double h;
-
- r_sin_A = radius * sin (angle_A);
- r_cos_A = radius * cos (angle_A);
- r_sin_B = radius * sin (angle_B);
- r_cos_B = radius * cos (angle_B);
-
- h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
-
- status = _cairo_gstate_curve_to (gstate,
- xc + r_cos_A - h * r_sin_A, yc + r_sin_A + h * r_cos_A,
- xc + r_cos_B + h * r_sin_B, yc + r_sin_B - h * r_cos_B,
- xc + r_cos_B, yc + r_sin_B);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gstate_arc_dir (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle_min,
- double angle_max,
- cairo_direction_t dir)
-{
- cairo_status_t status;
-
- while (angle_max - angle_min > 4 * M_PI)
- angle_max -= 2 * M_PI;
-
- /* Recurse if drawing arc larger than pi */
- if (angle_max - angle_min > M_PI) {
- double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
- /* XXX: Something tells me this block could be condensed. */
- if (dir == CAIRO_DIRECTION_FORWARD) {
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_mid, dir);
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_mid, angle_max, dir);
- if (status)
- return status;
- } else {
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_mid, angle_max, dir);
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle_min, angle_mid, dir);
- if (status)
- return status;
- }
- } else {
- int i, segments;
- double angle, angle_step;
-
- segments = _cairo_gstate_arc_segments_needed (gstate,
- angle_max - angle_min,
- radius);
- angle_step = (angle_max - angle_min) / (double) segments;
-
- if (dir == CAIRO_DIRECTION_FORWARD) {
- angle = angle_min;
- } else {
- angle = angle_max;
- angle_step = - angle_step;
- }
-
- for (i = 0; i < segments; i++, angle += angle_step) {
- _cairo_gstate_arc_segment (gstate,
- xc, yc,
- radius,
- angle,
- angle + angle_step);
- }
-
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_arc (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2)
-{
- cairo_status_t status;
-
- if (radius <= 0.0)
- return CAIRO_STATUS_SUCCESS;
-
- while (angle2 < angle1)
- angle2 += 2 * M_PI;
-
- status = _cairo_gstate_line_to (gstate,
- xc + radius * cos (angle1),
- yc + radius * sin (angle1));
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle1, angle2, CAIRO_DIRECTION_FORWARD);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2)
-{
- cairo_status_t status;
-
- if (radius <= 0.0)
- return CAIRO_STATUS_SUCCESS;
-
- while (angle2 > angle1)
- angle2 -= 2 * M_PI;
-
- status = _cairo_gstate_line_to (gstate,
- xc + radius * cos (angle1),
- yc + radius * sin (angle1));
- if (status)
- return status;
-
- status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
- angle2, angle1, CAIRO_DIRECTION_REVERSE);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* XXX: NYI
-cairo_status_t
-_cairo_gstate_arc_to (cairo_gstate_t *gstate,
- double x1, double y1,
- double x2, double y2,
- double radius)
-{
-
-}
-*/
-
-cairo_status_t
-_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy)
-{
- cairo_distance_t distance;
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
-
- distance.dx = _cairo_fixed_from_double (dx);
- distance.dy = _cairo_fixed_from_double (dy);
-
- return _cairo_path_rel_move_to (&gstate->path, &distance);
-}
-
-cairo_status_t
-_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy)
-{
- cairo_distance_t distance;
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
-
- distance.dx = _cairo_fixed_from_double (dx);
- distance.dy = _cairo_fixed_from_double (dy);
-
- return _cairo_path_rel_line_to (&gstate->path, &distance);
-}
-
-cairo_status_t
-_cairo_gstate_rel_curve_to (cairo_gstate_t *gstate,
- double dx0, double dy0,
- double dx1, double dy1,
- double dx2, double dy2)
-{
- cairo_distance_t distance[3];
-
- cairo_matrix_transform_distance (&gstate->ctm, &dx0, &dy0);
- cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
- cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
-
- distance[0].dx = _cairo_fixed_from_double (dx0);
- distance[0].dy = _cairo_fixed_from_double (dy0);
-
- distance[1].dx = _cairo_fixed_from_double (dx1);
- distance[1].dy = _cairo_fixed_from_double (dy1);
-
- distance[2].dx = _cairo_fixed_from_double (dx2);
- distance[2].dy = _cairo_fixed_from_double (dy2);
-
- return _cairo_path_rel_curve_to (&gstate->path,
- &distance[0],
- &distance[1],
- &distance[2]);
-}
-
-/* XXX: NYI
-cairo_status_t
-_cairo_gstate_stroke_path (cairo_gstate_t *gstate)
-{
- cairo_status_t status;
-
- _cairo_pen_init (&gstate);
- return CAIRO_STATUS_SUCCESS;
-}
-*/
-
-cairo_status_t
-_cairo_gstate_close_path (cairo_gstate_t *gstate)
-{
- return _cairo_path_close_path (&gstate->path);
-}
-
-cairo_status_t
-_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_ret)
-{
- cairo_status_t status;
- cairo_point_t point;
- double x, y;
-
- status = _cairo_path_current_point (&gstate->path, &point);
- if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- x = 0.0;
- y = 0.0;
- } else {
- x = _cairo_fixed_to_double (point.x);
- y = _cairo_fixed_to_double (point.y);
- cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
- }
-
- if (x_ret)
- *x_ret = x;
- if (y_ret)
- *y_ret = y;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-typedef struct gstate_path_interpreter {
- cairo_matrix_t ctm_inverse;
- double tolerance;
- cairo_point_t current_point;
-
- cairo_move_to_func_t *move_to;
- cairo_line_to_func_t *line_to;
- cairo_curve_to_func_t *curve_to;
- cairo_close_path_func_t *close_path;
-
- void *closure;
-} gpi_t;
-
-static cairo_status_t
-_gpi_move_to (void *closure, cairo_point_t *point)
-{
- gpi_t *gpi = closure;
- double x, y;
-
- x = _cairo_fixed_to_double (point->x);
- y = _cairo_fixed_to_double (point->y);
-
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
-
- gpi->move_to (gpi->closure, x, y);
- gpi->current_point = *point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_gpi_line_to (void *closure, cairo_point_t *point)
-{
- gpi_t *gpi = closure;
- double x, y;
-
- x = _cairo_fixed_to_double (point->x);
- y = _cairo_fixed_to_double (point->y);
-
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
-
- gpi->line_to (gpi->closure, x, y);
- gpi->current_point = *point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_gpi_curve_to (void *closure,
- cairo_point_t *p1,
- cairo_point_t *p2,
- cairo_point_t *p3)
-{
- gpi_t *gpi = closure;
- cairo_status_t status;
- cairo_spline_t spline;
- double x1, y1, x2, y2, x3, y3;
-
- if (gpi->curve_to) {
- x1 = _cairo_fixed_to_double (p1->x);
- y1 = _cairo_fixed_to_double (p1->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x1, &y1);
-
- x2 = _cairo_fixed_to_double (p2->x);
- y2 = _cairo_fixed_to_double (p2->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x2, &y2);
-
- x3 = _cairo_fixed_to_double (p3->x);
- y3 = _cairo_fixed_to_double (p3->y);
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x3, &y3);
-
- gpi->curve_to (gpi->closure, x1, y1, x2, y2, x3, y3);
- } else {
- cairo_point_t *p0 = &gpi->current_point;
- int i;
- double x, y;
-
- status = _cairo_spline_init (&spline, p0, p1, p2, p3);
- if (status == CAIRO_INT_STATUS_DEGENERATE)
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_spline_decompose (&spline, gpi->tolerance);
- if (status)
- return status;
-
- for (i=1; i < spline.num_points; i++) {
- x = _cairo_fixed_to_double (spline.points[i].x);
- y = _cairo_fixed_to_double (spline.points[i].y);
-
- cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
-
- gpi->line_to (gpi->closure, x, y);
- }
- }
-
- gpi->current_point = *p3;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_gpi_close_path (void *closure)
-{
- gpi_t *gpi = closure;
-
- gpi->close_path (gpi->closure);
-
- gpi->current_point.x = 0;
- gpi->current_point.y = 0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* It's OK for curve_path to be NULL. In that case, all curves in the
- path will be decomposed into one or more calls to the line_to
- function, (according to the current tolerance). */
-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,
- cairo_curve_to_func_t *curve_to,
- cairo_close_path_func_t *close_path,
- void *closure)
-{
- cairo_path_t path;
- gpi_t gpi;
-
- /* Anything we want from gstate must be copied. We must not retain
- pointers into gstate. */
- _cairo_path_init_copy (&path, &gstate->path);
-
- cairo_matrix_copy (&gpi.ctm_inverse, &gstate->ctm_inverse);
- gpi.tolerance = gstate->tolerance;
-
- gpi.move_to = move_to;
- gpi.line_to = line_to;
- gpi.curve_to = curve_to;
- gpi.close_path = close_path;
- gpi.closure = closure;
-
- gpi.current_point.x = 0;
- gpi.current_point.y = 0;
-
- return _cairo_path_interpret (&path,
- CAIRO_DIRECTION_FORWARD,
- _gpi_move_to,
- _gpi_line_to,
- _gpi_curve_to,
- _gpi_close_path,
- &gpi);
-}
-
-/* XXX: gstate->alpha will be going away before too long, and when it
- * does, it may make sense for this function to just disappear.
- */
-static void
-_cairo_gstate_pattern_init_copy (cairo_gstate_t *gstate,
- cairo_pattern_union_t *pattern,
- cairo_pattern_t *src)
-{
- _cairo_pattern_init_copy (&pattern->base, src);
- _cairo_pattern_transform (&pattern->base, &gstate->ctm_inverse);
- _cairo_pattern_set_alpha (&pattern->base, gstate->alpha);
-}
-
-cairo_status_t
-_cairo_gstate_stroke (cairo_gstate_t *gstate)
-{
- cairo_status_t status;
- cairo_traps_t traps;
-
- if (gstate->line_width <= 0.0)
- return CAIRO_STATUS_SUCCESS;
-
- _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
- if (status) {
- _cairo_traps_fini (&traps);
- return status;
- }
-
- _cairo_gstate_clip_and_composite_trapezoids (gstate,
- gstate->pattern,
- gstate->operator,
- gstate->surface,
- &traps);
-
- _cairo_traps_fini (&traps);
-
- _cairo_gstate_new_path (gstate);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_traps_t traps;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
- if (status)
- goto BAIL;
-
- *inside_ret = _cairo_traps_contain (&traps, x, y);
-
-BAIL:
- _cairo_traps_fini (&traps);
-
- return status;
-}
-
-/* XXX We currently have a confusing mix of boxes and rectangles as
- * exemplified by this function. A cairo_box_t is a rectangular area
- * represented by the coordinates of the upper left and lower right
- * corners, expressed in fixed point numbers. A cairo_rectangle_t is
- * also a rectangular area, but represented by the upper left corner
- * and the width and the height, as integer numbers.
- *
- * This function converts a cairo_box_t to a cairo_rectangle_t by
- * increasing the area to the nearest integer coordinates. We should
- * standardize on cairo_rectangle_t and cairo_rectangle_fixed_t, and
- * this function could be renamed to the more reasonable
- * _cairo_rectangle_fixed_round.
- */
-
-static void
-_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle)
-{
- rectangle->x = _cairo_fixed_integer_floor (box->p1.x);
- rectangle->y = _cairo_fixed_integer_floor (box->p1.y);
- rectangle->width = _cairo_fixed_integer_ceil (box->p2.x) - rectangle->x;
- rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y;
-}
-
-static void
-_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src)
-{
- int x1, y1, x2, y2;
-
- x1 = MAX (dest->x, src->x);
- y1 = MAX (dest->y, src->y);
- x2 = MIN (dest->x + dest->width, src->x + src->width);
- y2 = MIN (dest->y + dest->height, src->y + src->height);
-
- if (x1 >= x2 || y1 >= y2) {
- dest->x = 0;
- dest->y = 0;
- dest->width = 0;
- dest->height = 0;
- } else {
- dest->x = x1;
- dest->y = y1;
- dest->width = x2 - x1;
- dest->height = y2 - y1;
- }
-}
-
-static int
-_cairo_rectangle_empty (cairo_rectangle_t *rect)
-{
- return rect->width == 0 || rect->height == 0;
-}
-
-static void
-translate_traps (cairo_traps_t *traps, int x, int y)
-{
- cairo_fixed_t xoff, yoff;
- cairo_trapezoid_t *t;
- int i;
-
- /* Ugh. The cairo_composite/(Render) interface doesn't allow
- an offset for the trapezoids. Need to manually shift all
- the coordinates to align with the offset origin of the
- intermediate surface. */
-
- xoff = _cairo_fixed_from_int (x);
- yoff = _cairo_fixed_from_int (y);
-
- for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
- t->top += yoff;
- t->bottom += yoff;
- t->left.p1.x += xoff;
- t->left.p1.y += yoff;
- t->left.p2.x += xoff;
- t->left.p2.y += yoff;
- t->right.p1.x += xoff;
- t->right.p1.y += yoff;
- t->right.p2.x += xoff;
- t->right.p2.y += yoff;
- }
-}
-
-
-/* Warning: This call modifies the coordinates of traps */
-static cairo_status_t
-_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
- cairo_pattern_t *src,
- cairo_operator_t operator,
- cairo_surface_t *dst,
- cairo_traps_t *traps)
-{
- cairo_status_t status;
- cairo_pattern_union_t pattern;
- cairo_rectangle_t extents;
- cairo_box_t trap_extents;
-
- if (traps->num_traps == 0)
- return CAIRO_STATUS_SUCCESS;
-
- if (gstate->surface == NULL)
- return CAIRO_STATUS_NO_TARGET_SURFACE;
-
- _cairo_traps_extents (traps, &trap_extents);
- _cairo_box_round_to_rectangle (&trap_extents, &extents);
-
- if (gstate->clip.surface) {
- cairo_surface_t *intermediate;
- cairo_surface_pattern_t intermediate_pattern;
- cairo_color_t empty_color;
-
- _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
-
- if (_cairo_rectangle_empty (&extents)) {
- status = CAIRO_STATUS_SUCCESS;
- goto BAIL1;
- }
-
- translate_traps (traps, -extents.x, -extents.y);
-
- _cairo_color_init (&empty_color);
- _cairo_color_set_alpha (&empty_color, 0.);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_FORMAT_A8,
- extents.width,
- extents.height,
- &empty_color);
- if (intermediate == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
-
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
-
- status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
- &pattern.base,
- intermediate,
- extents.x, extents.y,
- 0, 0,
- extents.width,
- extents.height,
- traps->traps,
- traps->num_traps);
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto BAIL2;
-
-
- _cairo_pattern_init_for_surface (&pattern.surface,
- gstate->clip.surface);
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &pattern.base,
- NULL,
- intermediate,
- extents.x - gstate->clip.rect.x,
- extents.y - gstate->clip.rect.y,
- 0, 0,
- 0, 0,
- extents.width, extents.height);
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto BAIL2;
-
- _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
-
- status = _cairo_surface_composite (operator,
- &pattern.base,
- &intermediate_pattern.base,
- dst,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- _cairo_pattern_fini (&pattern.base);
- _cairo_pattern_fini (&intermediate_pattern.base);
-
- BAIL2:
- cairo_surface_destroy (intermediate);
- BAIL1:
-
- if (status)
- return status;
-
- } else {
- if (gstate->clip.region) {
- pixman_box16_t box;
- pixman_box16_t *intersection_extents;
- pixman_region16_t *rect, *intersection;
-
- box.x1 = _cairo_fixed_integer_floor (trap_extents.p1.x);
- box.y1 = _cairo_fixed_integer_floor (trap_extents.p1.y);
- box.x2 = _cairo_fixed_integer_ceil (trap_extents.p2.x);
- box.y2 = _cairo_fixed_integer_ceil (trap_extents.p2.y);
-
- rect = pixman_region_create_simple (&box);
- if (rect == NULL)
- goto bail1;
- intersection = pixman_region_create();
- if (intersection == NULL)
- goto bail2;
-
- if (pixman_region_intersect (intersection, gstate->clip.region,
- rect) != PIXMAN_REGION_STATUS_SUCCESS)
- goto bail3;
- intersection_extents = pixman_region_extents (intersection);
-
- extents.x = intersection_extents->x1;
- extents.y = intersection_extents->y1;
- extents.width = intersection_extents->x2 - intersection_extents->x1;
- extents.height = intersection_extents->y2 - intersection_extents->y1;
- bail3:
- pixman_region_destroy (intersection);
- bail2:
- pixman_region_destroy (rect);
- bail1:
- ;
- }
-
- _cairo_gstate_pattern_init_copy (gstate, &pattern, src);
-
- status = _cairo_surface_composite_trapezoids (gstate->operator,
- &pattern.base, dst,
- extents.x, extents.y,
- extents.x, extents.y,
- extents.width,
- extents.height,
- traps->traps,
- traps->num_traps);
-
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- return status;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_fill (cairo_gstate_t *gstate)
-{
- cairo_status_t status;
- cairo_traps_t traps;
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
- if (status) {
- _cairo_traps_fini (&traps);
- return status;
- }
-
- _cairo_gstate_clip_and_composite_trapezoids (gstate,
- gstate->pattern,
- gstate->operator,
- gstate->surface,
- &traps);
-
- _cairo_traps_fini (&traps);
-
- _cairo_gstate_new_path (gstate);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_in_fill (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_traps_t traps;
-
- cairo_matrix_transform_point (&gstate->ctm, &x, &y);
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
- if (status)
- goto BAIL;
-
- *inside_ret = _cairo_traps_contain (&traps, x, y);
-
-BAIL:
- _cairo_traps_fini (&traps);
-
- return status;
-}
-
-cairo_status_t
-_cairo_gstate_copy_page (cairo_gstate_t *gstate)
-{
- if (gstate->surface == NULL)
- return CAIRO_STATUS_NO_TARGET_SURFACE;
-
- return _cairo_surface_copy_page (gstate->surface);
-}
-
-cairo_status_t
-_cairo_gstate_show_page (cairo_gstate_t *gstate)
-{
- if (gstate->surface == NULL)
- return CAIRO_STATUS_NO_TARGET_SURFACE;
-
- return _cairo_surface_show_page (gstate->surface);
-}
-
-cairo_status_t
-_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
- double *x1, double *y1,
- double *x2, double *y2)
-{
- cairo_status_t status;
- cairo_traps_t traps;
- cairo_box_t extents;
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
- if (status)
- goto BAIL;
-
- _cairo_traps_extents (&traps, &extents);
-
- *x1 = _cairo_fixed_to_double (extents.p1.x);
- *y1 = _cairo_fixed_to_double (extents.p1.y);
- *x2 = _cairo_fixed_to_double (extents.p2.x);
- *y2 = _cairo_fixed_to_double (extents.p2.y);
-
- cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2);
-
-BAIL:
- _cairo_traps_fini (&traps);
-
- return status;
-}
-
-cairo_status_t
-_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
- double *x1, double *y1,
- double *x2, double *y2)
-{
- cairo_status_t status;
- cairo_traps_t traps;
- cairo_box_t extents;
-
- _cairo_traps_init (&traps);
-
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
- if (status)
- goto BAIL;
-
- _cairo_traps_extents (&traps, &extents);
-
- *x1 = _cairo_fixed_to_double (extents.p1.x);
- *y1 = _cairo_fixed_to_double (extents.p1.y);
- *x2 = _cairo_fixed_to_double (extents.p2.x);
- *y2 = _cairo_fixed_to_double (extents.p2.y);
-
- cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1);
- cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2);
-
-BAIL:
- _cairo_traps_fini (&traps);
-
- return status;
-}
-
-cairo_status_t
-_cairo_gstate_init_clip (cairo_gstate_t *gstate)
-{
- /* destroy any existing clip-region artifacts */
- if (gstate->clip.surface)
- cairo_surface_destroy (gstate->clip.surface);
- gstate->clip.surface = NULL;
-
- if (gstate->clip.region)
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = NULL;
-
- /* reset the surface's clip to the whole surface */
- if (gstate->surface)
- _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static int
-extract_transformed_rectangle(cairo_matrix_t *mat,
- cairo_traps_t *tr,
- pixman_box16_t *box)
-{
- double a, b, c, d, tx, ty;
- cairo_status_t st;
-
- st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
- if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.))
- return 0;
-
- if (tr->num_traps == 1
- && tr->traps[0].left.p1.x == tr->traps[0].left.p2.x
- && tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
- && tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
- && tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
- && _cairo_fixed_is_integer(tr->traps[0].left.p1.x)
- && _cairo_fixed_is_integer(tr->traps[0].left.p1.y)
- && _cairo_fixed_is_integer(tr->traps[0].left.p2.x)
- && _cairo_fixed_is_integer(tr->traps[0].left.p2.y)
- && _cairo_fixed_is_integer(tr->traps[0].right.p1.x)
- && _cairo_fixed_is_integer(tr->traps[0].right.p1.y)
- && _cairo_fixed_is_integer(tr->traps[0].right.p2.x)
- && _cairo_fixed_is_integer(tr->traps[0].right.p2.y)) {
-
- box->x1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.x);
- box->x2 = (short) _cairo_fixed_integer_part(tr->traps[0].right.p1.x);
- box->y1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.y);
- box->y2 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p2.y);
- return 1;
- }
- 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)
-{
- cairo_status_t status;
- cairo_pattern_union_t pattern;
- cairo_traps_t traps;
- cairo_color_t white_color;
- cairo_box_t extents;
- pixman_box16_t box;
-
- /* Fill the clip region as traps. */
-
- _cairo_traps_init (&traps);
- status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
- if (status) {
- _cairo_traps_fini (&traps);
- return status;
- }
-
- /* Check to see if we can represent these traps as a PixRegion. */
-
- if (extract_transformed_rectangle (&gstate->ctm, &traps, &box)) {
-
- pixman_region16_t *rect = NULL;
- pixman_region16_t *intersection = NULL;
-
- status = CAIRO_STATUS_SUCCESS;
- rect = pixman_region_create_simple (&box);
-
- if (rect == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
-
- } else {
-
- if (gstate->clip.region == NULL) {
- gstate->clip.region = rect;
- } else {
- intersection = pixman_region_create();
- if (pixman_region_intersect (intersection,
- gstate->clip.region, rect)
- == PIXMAN_REGION_STATUS_SUCCESS) {
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = intersection;
- } else {
- status = CAIRO_STATUS_NO_MEMORY;
- }
- pixman_region_destroy (rect);
- }
-
- if (!status)
- status = _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
- }
-
- if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
- _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. */
-
- _cairo_color_init (&white_color);
-
- if (gstate->clip.surface == NULL) {
- _cairo_traps_extents (&traps, &extents);
- _cairo_box_round_to_rectangle (&extents, &gstate->clip.rect);
- gstate->clip.surface =
- _cairo_surface_create_similar_solid (gstate->surface,
- CAIRO_FORMAT_A8,
- gstate->clip.rect.width,
- gstate->clip.rect.height,
- &white_color);
- if (gstate->clip.surface == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y);
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
-
- status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
- &pattern.base,
- gstate->clip.surface,
- 0, 0,
- 0, 0,
- gstate->clip.rect.width,
- gstate->clip.rect.height,
- traps.traps,
- traps.num_traps);
-
- _cairo_pattern_fini (&pattern.base);
-
- _cairo_traps_fini (&traps);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_show_surface (cairo_gstate_t *gstate,
- cairo_surface_t *surface,
- int width,
- int height)
-{
-
- /* 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.
- * it is the surface argument to this function. The surface has a
- * matrix attached to it which maps "user" space (see below) into
- * image space.
- *
- * - "Device" space is the space of the surface we're ultimately writing
- * pixels to. It is the current surface of the gstate argument to
- * this function.
- *
- * - "User" space is an arbitrary space defined by the user, defined
- * implicitly by the gstate's CTM. The CTM maps from user space to
- * device space. The CTM inverse (which is also kept at all times)
- * maps from device space to user space.
- *
- * - "Clip" space is the space of the surface being used to clip pixels
- * during compositing. Space-wise, it is a bounding box (offset+size)
- * within device space. This surface is usually smaller than the device
- * surface (and possibly the image surface too) and logically occupies
- * a bounding box around the "clip path", situated somewhere in device
- * space. The clip path is already painted on the clip surface.
- *
- * - "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 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
- * so that it can be read and written in device coordinates; in a sense
- * this makes it "spatially compatible" with the clip and device spaces.
- *
- *
- * There is also some confusion about the interaction between a clip and
- * a pattern; it is assumed that in this "show surface" operation a pattern
- * is to be used as an auxiliary alpha mask. this might be wrong, but it's
- * what we're doing now.
- *
- * so, to follow the operations below, remember that in the compositing
- * model, each operation is always of the form ((src IN mask) OP dst).
- * that's the basic operation.
- *
- * so the compositing we are trying to do here, in general, involves 2
- * steps, going via a temporary surface:
- *
- * - combining clip and pattern pixels together into a mask channel.
- * this will be ((pattern IN clip) SRC temporary). it ignores the
- * pixels already in the temporary, overwriting it with the
- * pattern, clipped to the clip mask.
- *
- * - combining temporary and "image" pixels with "device" pixels,
- * with a user-provided porter/duff operator. this will be
- * ((image IN temporary) OP device).
- *
- * if there is no clip, the degenerate case is just the second step
- * with pattern standing in for temporary.
- *
- */
-
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_matrix_t image_to_user, image_to_device;
- double device_x, device_y;
- double device_width, device_height;
- cairo_surface_pattern_t pattern;
- cairo_box_t pattern_extents;
- cairo_rectangle_t extents;
-
- cairo_surface_get_matrix (surface, &image_to_user);
- cairo_matrix_invert (&image_to_user);
- cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm);
-
- _cairo_gstate_current_point (gstate, &device_x, &device_y);
- device_width = width;
- device_height = height;
- _cairo_matrix_transform_bounding_box (&image_to_device,
- &device_x, &device_y,
- &device_width, &device_height);
-
- _cairo_pattern_init_for_surface (&pattern, surface);
-
- /* inherit surface attributes while surface attribute functions still
- exist */
- pattern.base.matrix = surface->matrix;
- pattern.base.filter = surface->filter;
- if (surface->repeat)
- pattern.base.extend = CAIRO_EXTEND_REPEAT;
- else
- pattern.base.extend = CAIRO_EXTEND_NONE;
-
- _cairo_pattern_transform (&pattern.base, &gstate->ctm_inverse);
- _cairo_pattern_set_alpha (&pattern.base, gstate->alpha);
-
- pattern_extents.p1.x = _cairo_fixed_from_double (device_x);
- pattern_extents.p1.y = _cairo_fixed_from_double (device_y);
- pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
- pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
- _cairo_box_round_to_rectangle (&pattern_extents, &extents);
-
- if (gstate->clip.surface)
- {
- _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
-
- /* We only need to composite if the rectangle is not empty. */
- if (!_cairo_rectangle_empty (&extents)) {
- cairo_surface_pattern_t clip_pattern;
-
- _cairo_pattern_init_for_surface (&clip_pattern,
- gstate->clip.surface);
-
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- &clip_pattern.base,
- gstate->surface,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- _cairo_pattern_fini (&clip_pattern.base);
- }
- }
- else
- {
- /* XXX: The rendered size is sometimes 1 or 2 pixels short
- * from what I expect. Need to fix this.
- * KRH: I'm guessing this was due to rounding error when
- * passing double coordinates for integer arguments. Using
- * the extents rectangle should fix this, since it's properly
- * rounded. Is this still the case?
- */
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- NULL,
- gstate->surface,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
-
- }
-
- _cairo_pattern_fini (&pattern.base);
-
- return status;
-}
-
-static void
-_cairo_gstate_unset_font (cairo_gstate_t *gstate)
-{
- if (gstate->font) {
- cairo_font_destroy (gstate->font);
- gstate->font = NULL;
- }
-}
-
-cairo_status_t
-_cairo_gstate_select_font (cairo_gstate_t *gstate,
- const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight)
-{
- char *new_family;
-
- new_family = strdup (family);
- if (!new_family)
- return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_gstate_unset_font (gstate);
-
- gstate->font_family = new_family;
- gstate->font_slant = slant;
- gstate->font_weight = weight;
-
- cairo_matrix_set_identity (&gstate->font_matrix);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_scale_font (cairo_gstate_t *gstate,
- double scale)
-{
- _cairo_gstate_unset_font (gstate);
-
- return cairo_matrix_scale (&gstate->font_matrix, scale, scale);
-}
-
-cairo_status_t
-_cairo_gstate_transform_font (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- cairo_matrix_t tmp;
- double a, b, c, d, tx, ty;
-
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty);
- cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0);
- return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp);
-}
-
-
-cairo_status_t
-_cairo_gstate_current_font (cairo_gstate_t *gstate,
- cairo_font_t **font)
-{
- cairo_status_t status;
-
- status = _cairo_gstate_ensure_font (gstate);
- if (status)
- return status;
-
- *font = gstate->font;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- _cairo_gstate_unset_font (gstate);
-
- cairo_matrix_copy (&gstate->font_matrix, matrix);
-}
-
-void
-_cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix)
-{
- cairo_matrix_copy (matrix, &gstate->font_matrix);
-}
-
-/*
- * Like everything else in this file, fonts involve Too Many Coordinate Spaces;
- * it is easy to get confused about what's going on.
- *
- * The user's view
- * ---------------
- *
- * Users ask for things in user space. When cairo starts, a user space unit
- * is about 1/96 inch, which is similar to (but importantly different from)
- * the normal "point" units most users think in terms of. When a user
- * selects a font, its scale is set to "one user unit". The user can then
- * independently scale the user coordinate system *or* the font matrix, in
- * order to adjust the rendered size of the font.
- *
- * The only font type exposed to the user is cairo_font_t which is a
- * a font specialized to a particular scale matrix, CTM, and target
- * surface. The user is responsible for not using a cairo_font_t
- * after changing the parameters; doing so will produce garbled metrics.
- *
- *
- * The font's view
- * ---------------
- *
- * Fonts are designed and stored (in say .ttf files) in "font space", which
- * describes an "EM Square" (a design tile) and has some abstract number
- * such as 1000, 1024, or 2048 units per "EM". This is basically an
- * uninteresting space for us, but we need to remember that it exists.
- *
- * Font resources (from libraries or operating systems) render themselves
- * to a particular device. Since they do not want to make most programmers
- * worry about the font design space, the scaling API is simplified to
- * involve just telling the font the required pixel size of the EM square
- * (that is, in device space).
- *
- *
- * Cairo's gstate view
- * -------------------
- *
- * In addition to the CTM and CTM inverse, we keep a matrix in the gstate
- * called the "font matrix" which describes the user's most recent
- * font-scaling or font-transforming request. This is kept in terms of an
- * abstract scale factor, composed with the CTM and used to set the font's
- * pixel size. So if the user asks to "scale the font by 12", the matrix
- * is:
- *
- * [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ]
- *
- * It is an affine matrix, like all cairo matrices, but its tx and ty
- * components are always set to zero; we don't permit "nudging" fonts
- * around.
- *
- * In order to perform any action on a font, we must build an object
- * called a cairo_font_scale_t; this contains the central 2x2 matrix
- * resulting from "font matrix * CTM".
- *
- * We pass this to the font when making requests of it, which causes it to
- * reply for a particular [user request, device] combination, under the CTM
- * (to accomodate the "zoom in" == "bigger fonts" issue above).
- *
- * The other terms in our communication with the font are therefore in
- * device space. When we ask it to perform text->glyph conversion, it will
- * produce a glyph string in device space. Glyph vectors we pass to it for
- * measuring or rendering should be in device space. The metrics which we
- * get back from the font will be in device space. The contents of the
- * global glyph image cache will be in device space.
- *
- *
- * Cairo's public view
- * -------------------
- *
- * Since the values entering and leaving via public API calls are in user
- * space, the gstate functions typically need to multiply argumens by the
- * CTM (for user-input glyph vectors), and return values by the CTM inverse
- * (for font responses such as metrics or glyph vectors).
- *
- */
-
-void
-_cairo_gstate_current_font_scale (cairo_gstate_t *gstate,
- cairo_font_scale_t *sc)
-{
- cairo_matrix_t tmp;
- double dummy;
- cairo_matrix_multiply (&tmp, &gstate->font_matrix, &gstate->ctm);
- cairo_matrix_get_affine (&tmp,
- &sc->matrix[0][0],
- &sc->matrix[0][1],
- &sc->matrix[1][0],
- &sc->matrix[1][1],
- &dummy, &dummy);
-}
-
-static cairo_status_t
-_cairo_gstate_ensure_font (cairo_gstate_t *gstate)
-{
- cairo_font_scale_t sc;
- cairo_status_t status;
- const char *family;
-
- if (gstate->font)
- return CAIRO_STATUS_SUCCESS;
-
- _cairo_gstate_current_font_scale (gstate, &sc);
-
- if (gstate->font_family)
- family = gstate->font_family;
- else
- family = CAIRO_FONT_FAMILY_DEFAULT;
-
- status = _cairo_font_create (family,
- gstate->font_slant,
- gstate->font_weight,
- &sc,
- &gstate->font);
-
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
- cairo_font_extents_t *extents)
-{
- cairo_status_t status = _cairo_gstate_ensure_font (gstate);
- if (status)
- return status;
-
- return cairo_font_extents (gstate->font,
- &gstate->font_matrix,
- extents);
-}
-
-cairo_status_t
-_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *nglyphs)
-{
- cairo_status_t status;
-
- cairo_point_t point;
- double origin_x, origin_y;
- int i;
-
- status = _cairo_gstate_ensure_font (gstate);
- if (status)
- return status;
-
- status = _cairo_path_current_point (&gstate->path, &point);
- if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
- origin_x = 0.0;
- origin_y = 0.0;
- } else {
- 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_font_text_to_glyphs (gstate->font,
- utf8, glyphs, nglyphs);
-
- if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs))
- return status;
-
- /* 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) {
- 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;
-}
-
-cairo_status_t
-_cairo_gstate_set_font (cairo_gstate_t *gstate,
- cairo_font_t *font)
-{
- if (font != gstate->font) {
- if (gstate->font)
- cairo_font_destroy (gstate->font);
- gstate->font = font;
- if (gstate->font)
- cairo_font_reference (gstate->font);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- cairo_status_t status;
-
- status = _cairo_gstate_ensure_font (gstate);
- if (status)
- return status;
-
- cairo_font_glyph_extents (gstate->font,
- &gstate->font_matrix,
- glyphs, num_glyphs,
- extents);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
- cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_status_t status;
- int i;
- cairo_glyph_t *transformed_glyphs = NULL;
- cairo_pattern_union_t pattern;
- cairo_box_t bbox;
- cairo_rectangle_t extents;
-
- status = _cairo_gstate_ensure_font (gstate);
- if (status)
- return status;
-
- transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
- if (transformed_glyphs == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < num_glyphs; ++i)
- {
- transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &transformed_glyphs[i].x,
- &transformed_glyphs[i].y);
- }
-
- status = _cairo_font_glyph_bbox (gstate->font,
- transformed_glyphs, num_glyphs,
- &bbox);
- _cairo_box_round_to_rectangle (&bbox, &extents);
-
- if (status)
- goto CLEANUP_GLYPHS;
-
- if (gstate->clip.surface)
- {
- cairo_surface_t *intermediate;
- cairo_surface_pattern_t intermediate_pattern;
- cairo_color_t empty_color;
-
- _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
-
- /* Shortcut if empty */
- if (_cairo_rectangle_empty (&extents)) {
- status = CAIRO_STATUS_SUCCESS;
- 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,
- extents.width,
- extents.height,
- &empty_color);
- if (intermediate == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
-
- /* move the glyphs again, from dev space to intermediate space */
- for (i = 0; i < num_glyphs; ++i)
- {
- transformed_glyphs[i].x -= extents.x;
- transformed_glyphs[i].y -= extents.y;
- }
-
- _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
-
- status = _cairo_font_show_glyphs (gstate->font,
- CAIRO_OPERATOR_ADD,
- &pattern.base, intermediate,
- extents.x, extents.y,
- 0, 0,
- extents.width, extents.height,
- transformed_glyphs, num_glyphs);
-
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto BAIL2;
-
- _cairo_pattern_init_for_surface (&pattern.surface,
- gstate->clip.surface);
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &pattern.base,
- NULL,
- intermediate,
- extents.x - gstate->clip.rect.x,
- extents.y - gstate->clip.rect.y,
- 0, 0,
- 0, 0,
- extents.width, extents.height);
-
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto BAIL2;
-
- _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
-
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- &intermediate_pattern.base,
- gstate->surface,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
- _cairo_pattern_fini (&pattern.base);
- _cairo_pattern_fini (&intermediate_pattern.base);
-
- BAIL2:
- cairo_surface_destroy (intermediate);
- BAIL1:
- ;
- }
- else
- {
- _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern);
-
- status = _cairo_font_show_glyphs (gstate->font,
- gstate->operator, &pattern.base,
- gstate->surface,
- extents.x, extents.y,
- extents.x, extents.y,
- extents.width, extents.height,
- transformed_glyphs, num_glyphs);
-
- _cairo_pattern_fini (&pattern.base);
- }
-
- CLEANUP_GLYPHS:
- free (transformed_glyphs);
-
- return status;
-}
-
-cairo_status_t
-_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
- cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_status_t status;
- int i;
- cairo_glyph_t *transformed_glyphs = NULL;
-
- 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)
- {
- transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &(transformed_glyphs[i].x),
- &(transformed_glyphs[i].y));
- }
-
- status = _cairo_font_glyph_path (gstate->font,
- transformed_glyphs, num_glyphs,
- &gstate->path);
-
- free (transformed_glyphs);
- return status;
-}
diff --git a/src/cairo_hull.c b/src/cairo_hull.c
deleted file mode 100644
index c93d70625..000000000
--- a/src/cairo_hull.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * 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
- * 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@cworth.org>
- */
-
-#include "cairoint.h"
-
-typedef struct cairo_hull
-{
- cairo_point_t point;
- cairo_slope_t slope;
- int discard;
-} cairo_hull_t;
-
-static cairo_hull_t *
-_cairo_hull_create (cairo_pen_vertex_t *vertices, int num_vertices)
-{
- int i;
- cairo_hull_t *hull;
- cairo_point_t *p, *extremum, tmp;
-
- extremum = &vertices[0].point;
- for (i = 1; i < num_vertices; i++) {
- p = &vertices[i].point;
- if (p->y < extremum->y || (p->y == extremum->y && p->x < extremum->x))
- extremum = p;
- }
- /* Put the extremal point at the beginning of the array */
- tmp = *extremum;
- *extremum = vertices[0].point;
- vertices[0].point = tmp;
-
- hull = malloc (num_vertices * sizeof (cairo_hull_t));
- if (hull == NULL)
- return NULL;
-
- for (i = 0; i < num_vertices; i++) {
- hull[i].point = vertices[i].point;
- _cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);
-
- /* Discard all points coincident with the extremal point */
- if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
- hull[i].discard = 1;
- else
- hull[i].discard = 0;
- }
-
- return hull;
-}
-
-static int
-_cairo_hull_vertex_compare (const void *av, const void *bv)
-{
- cairo_hull_t *a = (cairo_hull_t *) av;
- cairo_hull_t *b = (cairo_hull_t *) bv;
- int ret;
-
- ret = _cairo_slope_compare (&a->slope, &b->slope);
-
- /* In the case of two vertices with identical slope from the
- extremal point discard the nearer point. */
-
- if (ret == 0) {
- cairo_fixed_48_16_t a_dist, b_dist;
- a_dist = ((cairo_fixed_48_16_t) a->slope.dx * a->slope.dx +
- (cairo_fixed_48_16_t) a->slope.dy * a->slope.dy);
- b_dist = ((cairo_fixed_48_16_t) b->slope.dx * b->slope.dx +
- (cairo_fixed_48_16_t) b->slope.dy * b->slope.dy);
- if (a_dist < b_dist) {
- a->discard = 1;
- ret = -1;
- } else {
- b->discard = 1;
- ret = 1;
- }
- }
-
- return ret;
-}
-
-static int
-_cairo_hull_prev_valid (cairo_hull_t *hull, int num_hull, int index)
-{
- do {
- /* hull[0] is always valid, so don't test and wraparound */
- index--;
- } while (hull[index].discard);
-
- return index;
-}
-
-static int
-_cairo_hull_next_valid (cairo_hull_t *hull, int num_hull, int index)
-{
- do {
- index = (index + 1) % num_hull;
- } while (hull[index].discard);
-
- return index;
-}
-
-static cairo_status_t
-_cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
-{
- int i, j, k;
- cairo_slope_t slope_ij, slope_jk;
-
- i = 0;
- j = _cairo_hull_next_valid (hull, num_hull, i);
- k = _cairo_hull_next_valid (hull, num_hull, j);
-
- do {
- _cairo_slope_init (&slope_ij, &hull[i].point, &hull[j].point);
- _cairo_slope_init (&slope_jk, &hull[j].point, &hull[k].point);
-
- /* Is the angle formed by ij and jk concave? */
- if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) {
- if (i == k)
- return CAIRO_STATUS_SUCCESS;
- hull[j].discard = 1;
- j = i;
- i = _cairo_hull_prev_valid (hull, num_hull, j);
- } else {
- i = j;
- j = k;
- k = _cairo_hull_next_valid (hull, num_hull, j);
- }
- } while (j != 0);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_vertices)
-{
- int i, j = 0;
-
- for (i = 0; i < *num_vertices; i++) {
- if (hull[i].discard)
- continue;
- vertices[j++].point = hull[i].point;
- }
-
- *num_vertices = j;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Given a set of vertices, compute the convex hull using the Graham
- scan algorithm. */
-cairo_status_t
-_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
-{
- cairo_hull_t *hull;
- int num_hull = *num_vertices;
-
- hull = _cairo_hull_create (vertices, num_hull);
- if (hull == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- qsort (hull + 1, num_hull - 1,
- sizeof (cairo_hull_t), _cairo_hull_vertex_compare);
-
- _cairo_hull_eliminate_concave (hull, num_hull);
-
- _cairo_hull_to_pen (hull, vertices, num_vertices);
-
- free (hull);
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c
deleted file mode 100644
index 9745b3150..000000000
--- a/src/cairo_image_surface.c
+++ /dev/null
@@ -1,675 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * 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
- * 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@cworth.org>
- */
-
-#include "cairoint.h"
-
-static const cairo_surface_backend_t cairo_image_surface_backend;
-
-static int
-_cairo_format_bpp (cairo_format_t format)
-{
- switch (format) {
- case CAIRO_FORMAT_A1:
- return 1;
- case CAIRO_FORMAT_A8:
- return 8;
- case CAIRO_FORMAT_RGB24:
- case CAIRO_FORMAT_ARGB32:
- default:
- return 32;
- }
-}
-
-static cairo_image_surface_t *
-_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
- cairo_format_t format)
-{
- cairo_image_surface_t *surface;
-
- surface = malloc (sizeof (cairo_image_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init (&surface->base, &cairo_image_surface_backend);
-
- surface->pixman_image = pixman_image;
-
- surface->format = format;
- surface->data = (char *) pixman_image_get_data (pixman_image);
- surface->owns_data = 0;
-
- surface->width = pixman_image_get_width (pixman_image);
- surface->height = pixman_image_get_height (pixman_image);
- surface->stride = pixman_image_get_stride (pixman_image);
- surface->depth = pixman_image_get_depth (pixman_image);
-
- return surface;
-}
-
-cairo_image_surface_t *
-_cairo_image_surface_create_with_masks (char *data,
- cairo_format_masks_t *format,
- int width,
- int height,
- int stride)
-{
- cairo_image_surface_t *surface;
- pixman_format_t *pixman_format;
- pixman_image_t *pixman_image;
-
- pixman_format = pixman_format_create_masks (format->bpp,
- format->alpha_mask,
- format->red_mask,
- format->green_mask,
- format->blue_mask);
-
- if (pixman_format == NULL)
- return NULL;
-
- pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
- width, height, format->bpp, stride);
-
- pixman_format_destroy (pixman_format);
-
- if (pixman_image == NULL)
- return NULL;
-
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
- (cairo_format_t)-1);
-
- return surface;
-}
-
-static pixman_format_t *
-_create_pixman_format (cairo_format_t format)
-{
- switch (format) {
- case CAIRO_FORMAT_A1:
- return pixman_format_create (PIXMAN_FORMAT_NAME_A1);
- break;
- case CAIRO_FORMAT_A8:
- return pixman_format_create (PIXMAN_FORMAT_NAME_A8);
- break;
- case CAIRO_FORMAT_RGB24:
- return pixman_format_create (PIXMAN_FORMAT_NAME_RGB24);
- break;
- case CAIRO_FORMAT_ARGB32:
- default:
- return pixman_format_create (PIXMAN_FORMAT_NAME_ARGB32);
- break;
- }
-}
-
-/**
- * cairo_image_surface_create:
- * @format: format of pixels in the surface to create
- * @width: width of the surface, in pixels
- * @height: height of the surface, in pixels
- *
- * Creates an image surface of the specified format and
- * dimensions. The initial contents of the surface is undefined; you
- * must explicitely clear the buffer, using, for example,
- * cairo_rectangle() and cairo_fill() if you want it cleared.
- *
- * Return value: the newly created surface, or %NULL if it couldn't
- * be created because of lack of memory
- **/
-cairo_surface_t *
-cairo_image_surface_create (cairo_format_t format,
- int width,
- int height)
-{
- cairo_image_surface_t *surface;
- pixman_format_t *pixman_format;
- pixman_image_t *pixman_image;
-
- pixman_format = _create_pixman_format (format);
- if (pixman_format == NULL)
- return NULL;
-
- pixman_image = pixman_image_create (pixman_format, width, height);
-
- pixman_format_destroy (pixman_format);
-
- if (pixman_image == NULL)
- return NULL;
-
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
-
- return &surface->base;
-}
-
-/**
- * cairo_image_surface_create_for_data:
- * @data: a pointer to a buffer supplied by the application
- * in which to write contents.
- * @format: the format of pixels in the buffer
- * @width: the width of the image to be stored in the buffer
- * @height: the height of the image to be stored in the buffer
- * @stride: the number of bytes between the start of rows
- * in the buffer. Having this be specified separate from @width
- * allows for padding at the end of rows, or for writing
- * to a subportion of a larger image.
- *
- * Creates an image surface for the provided pixel data. The output
- * buffer must be kept around until the #cairo_surface_t is destroyed
- * or cairo_surface_finish() is called on the surface. The initial
- * contents of @buffer will be used as the inital image contents; you
- * must explicitely clear the buffer, using, for example,
- * cairo_rectangle() and cairo_fill() if you want it cleared.
- *
- * Return value: the newly created surface, or %NULL if it couldn't
- * be created because of lack of memory
- **/
-cairo_surface_t *
-cairo_image_surface_create_for_data (char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride)
-{
- cairo_image_surface_t *surface;
- pixman_format_t *pixman_format;
- pixman_image_t *pixman_image;
-
- 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),
- stride);
-
- pixman_format_destroy (pixman_format);
-
- if (pixman_image == NULL)
- return NULL;
-
- surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format);
-
- return &surface->base;
-}
-
-static cairo_surface_t *
-_cairo_image_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- return cairo_image_surface_create (format, width, height);
-}
-
-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);
-
- if (surface->owns_data) {
- free (surface->data);
- surface->data = NULL;
- }
-
- free (surface);
-}
-
-void
-_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
-{
- surface->owns_data = 1;
-}
-
-static double
-_cairo_image_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We'll want a way to let the user set this. */
- return 96.0;
-}
-
-static cairo_status_t
-_cairo_image_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- *image_out = abstract_surface;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_image_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_image_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect_out,
- void **image_extra)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- image_rect_out->x = 0;
- image_rect_out->y = 0;
- image_rect_out->width = surface->width;
- image_rect_out->height = surface->height;
-
- *image_out = surface;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_image_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_image_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- if (src->backend == surface->base.backend) {
- *clone_out = src;
- cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_status_t
-_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
- cairo_matrix_t *matrix)
-{
- pixman_transform_t pixman_transform;
-
- pixman_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- pixman_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- pixman_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
-
- pixman_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- pixman_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- pixman_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
-
- pixman_transform.matrix[2][0] = 0;
- pixman_transform.matrix[2][1] = 0;
- pixman_transform.matrix[2][2] = _cairo_fixed_from_double (1);
-
- pixman_image_set_transform (surface->pixman_image, &pixman_transform);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter)
-{
- pixman_filter_t pixman_filter;
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- pixman_filter = PIXMAN_FILTER_FAST;
- break;
- case CAIRO_FILTER_GOOD:
- pixman_filter = PIXMAN_FILTER_GOOD;
- break;
- case CAIRO_FILTER_BEST:
- pixman_filter = PIXMAN_FILTER_BEST;
- break;
- case CAIRO_FILTER_NEAREST:
- pixman_filter = PIXMAN_FILTER_NEAREST;
- break;
- case CAIRO_FILTER_BILINEAR:
- pixman_filter = PIXMAN_FILTER_BILINEAR;
- break;
- default:
- pixman_filter = PIXMAN_FILTER_BEST;
- }
-
- pixman_image_set_filter (surface->pixman_image, pixman_filter);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat)
-{
- pixman_image_set_repeat (surface->pixman_image, repeat);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_set_attributes (cairo_image_surface_t *surface,
- cairo_surface_attributes_t *attributes)
-{
- cairo_int_status_t status;
-
- status = _cairo_image_surface_set_matrix (surface, &attributes->matrix);
- if (status)
- return status;
-
- switch (attributes->extend) {
- case CAIRO_EXTEND_NONE:
- _cairo_image_surface_set_repeat (surface, 0);
- break;
- case CAIRO_EXTEND_REPEAT:
- _cairo_image_surface_set_repeat (surface, 1);
- break;
- case CAIRO_EXTEND_REFLECT:
- /* XXX: Obviously wrong. */
- _cairo_image_surface_set_repeat (surface, 1);
- break;
- }
-
- status = _cairo_image_surface_set_filter (surface, attributes->filter);
-
- return status;
-}
-
-static pixman_operator_t
-_pixman_operator (cairo_operator_t operator)
-{
- switch (operator) {
- case CAIRO_OPERATOR_CLEAR:
- return PIXMAN_OPERATOR_CLEAR;
- case CAIRO_OPERATOR_SRC:
- return PIXMAN_OPERATOR_SRC;
- case CAIRO_OPERATOR_DST:
- return PIXMAN_OPERATOR_DST;
- case CAIRO_OPERATOR_OVER:
- return PIXMAN_OPERATOR_OVER;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return PIXMAN_OPERATOR_OVER_REVERSE;
- case CAIRO_OPERATOR_IN:
- return PIXMAN_OPERATOR_IN;
- case CAIRO_OPERATOR_IN_REVERSE:
- return PIXMAN_OPERATOR_IN_REVERSE;
- case CAIRO_OPERATOR_OUT:
- return PIXMAN_OPERATOR_OUT;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return PIXMAN_OPERATOR_OUT_REVERSE;
- case CAIRO_OPERATOR_ATOP:
- return PIXMAN_OPERATOR_ATOP;
- case CAIRO_OPERATOR_ATOP_REVERSE:
- return PIXMAN_OPERATOR_ATOP_REVERSE;
- case CAIRO_OPERATOR_XOR:
- return PIXMAN_OPERATOR_XOR;
- case CAIRO_OPERATOR_ADD:
- return PIXMAN_OPERATOR_ADD;
- case CAIRO_OPERATOR_SATURATE:
- return PIXMAN_OPERATOR_SATURATE;
- default:
- return PIXMAN_OPERATOR_OVER;
- }
-}
-
-static cairo_int_status_t
-_cairo_image_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src_pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_surface_attributes_t src_attr, mask_attr;
- cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_t *src;
- cairo_image_surface_t *mask;
- cairo_int_status_t status;
-
- status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
- &dst->base,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- (cairo_surface_t **) &src,
- (cairo_surface_t **) &mask,
- &src_attr, &mask_attr);
- if (status)
- return status;
-
- status = _cairo_image_surface_set_attributes (src, &src_attr);
- if (CAIRO_OK (status))
- {
- if (mask)
- {
- status = _cairo_image_surface_set_attributes (mask, &mask_attr);
- if (CAIRO_OK (status))
- pixman_composite (_pixman_operator (operator),
- src->pixman_image,
- mask->pixman_image,
- dst->pixman_image,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- mask_x + mask_attr.x_offset,
- mask_y + mask_attr.y_offset,
- dst_x, dst_y,
- width, height);
- }
- else
- {
- pixman_composite (_pixman_operator (operator),
- src->pixman_image,
- NULL,
- dst->pixman_image,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- }
- }
-
- if (mask)
- _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- pixman_color_t pixman_color;
-
- pixman_color.red = color->red_short;
- pixman_color.green = color->green_short;
- pixman_color.blue = color->blue_short;
- pixman_color.alpha = color->alpha_short;
-
- /* XXX: The pixman_rectangle_t cast is evil... it needs to go away somehow. */
- pixman_fill_rectangles (_pixman_operator(operator), surface->pixman_image,
- &pixman_color, (pixman_rectangle_t *) rects, num_rects);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_surface_attributes_t attributes;
- cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_t *src;
- cairo_int_status_t status;
- int render_reference_x, render_reference_y;
- int render_src_x, render_src_y;
-
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- src_x, src_y, width, height,
- (cairo_surface_t **) &src,
- &attributes);
- if (status)
- return status;
-
- if (traps[0].left.p1.y < traps[0].left.p2.y) {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
- } else {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
- }
-
- render_src_x = src_x + render_reference_x - dst_x;
- render_src_y = src_y + render_reference_y - dst_y;
-
- /* XXX: The pixman_trapezoid_t cast is evil and needs to go away
- * somehow. */
- status = _cairo_image_surface_set_attributes (src, &attributes);
- if (CAIRO_OK (status))
- pixman_composite_trapezoids (operator,
- src->pixman_image,
- dst->pixman_image,
- render_src_x + attributes.x_offset,
- render_src_y + attributes.y_offset,
- (pixman_trapezoid_t *) traps, num_traps);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_image_abstract_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
-
- return _cairo_image_surface_set_clip_region (surface, region);
-}
-
-cairo_int_status_t
-_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
- pixman_region16_t *region)
-{
- if (region) {
- pixman_region16_t *rcopy;
-
- rcopy = pixman_region_create();
- /* pixman_image_set_clip_region expects to take ownership of the
- * passed-in region, so we create a copy to give it. */
- /* XXX: I think that's probably a bug in pixman. But its
- * memory management issues need auditing anyway, so a
- * workaround like this is fine for now. */
- pixman_region_copy (rcopy, region);
- pixman_image_set_clip_region (surface->pixman_image, rcopy);
- } else {
- pixman_image_set_clip_region (surface->pixman_image, region);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * _cairo_surface_is_image:
- * @surface: a #cairo_surface_t
- *
- * Checks if a surface is an #cairo_image_surface_t
- *
- * Return value: True if the surface is an image surface
- **/
-int
-_cairo_surface_is_image (cairo_surface_t *surface)
-{
- return surface->backend == &cairo_image_surface_backend;
-}
-
-static const cairo_surface_backend_t cairo_image_surface_backend = {
- _cairo_image_surface_create_similar,
- _cairo_image_abstract_surface_destroy,
- _cairo_image_surface_pixels_per_inch,
- _cairo_image_surface_acquire_source_image,
- _cairo_image_surface_release_source_image,
- _cairo_image_surface_acquire_dest_image,
- _cairo_image_surface_release_dest_image,
- _cairo_image_surface_clone_similar,
- _cairo_image_surface_composite,
- _cairo_image_surface_fill_rectangles,
- _cairo_image_surface_composite_trapezoids,
- _cairo_image_surface_copy_page,
- _cairo_image_surface_show_page,
- _cairo_image_abstract_surface_set_clip_region,
- NULL /* show_glyphs */
-};
diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c
deleted file mode 100644
index 88e536e8a..000000000
--- a/src/cairo_matrix.c
+++ /dev/null
@@ -1,645 +0,0 @@
-/* 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@cworth.org>
- */
-
-#define _GNU_SOURCE
-#include <stdlib.h>
-#include <math.h>
-
-#include "cairoint.h"
-
-static cairo_matrix_t const CAIRO_MATRIX_IDENTITY = {
- {
- {1, 0},
- {0, 1},
- {0, 0}
- }
-};
-
-static void
-_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
-
-static void
-_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
-
-/**
- * cairo_matrix_create:
- *
- * Creates a new identity matrix.
- *
- * Return value: a newly created matrix; free with cairo_matrix_destroy(),
- * or %NULL if memory couldn't be allocated.
- **/
-cairo_matrix_t *
-cairo_matrix_create (void)
-{
- cairo_matrix_t *matrix;
-
- matrix = malloc (sizeof (cairo_matrix_t));
- if (matrix == NULL)
- return NULL;
-
- _cairo_matrix_init (matrix);
-
- return matrix;
-}
-
-void
-_cairo_matrix_init (cairo_matrix_t *matrix)
-{
- cairo_matrix_set_identity (matrix);
-}
-
-void
-_cairo_matrix_fini (cairo_matrix_t *matrix)
-{
- /* nothing to do here */
-}
-
-/**
- * cairo_matrix_destroy:
- * @matrix: a #cairo_matrix_t
- *
- * Frees a matrix created with cairo_matrix_create.
- **/
-void
-cairo_matrix_destroy (cairo_matrix_t *matrix)
-{
- _cairo_matrix_fini (matrix);
- free (matrix);
-}
-
-/**
- * cairo_matrix_copy:
- * @matrix: a #cairo_matrix_t
- * @other: another #cairo_
- *
- * Modifies @matrix to be identical to @other.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other)
-{
- *matrix = *other;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_matrix_copy);
-
-/**
- * cairo_matrix_set_identity:
- * @matrix: a #cairo_matrix_t
- *
- * Modifies @matrix to be an identity transformation.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_set_identity (cairo_matrix_t *matrix)
-{
- *matrix = CAIRO_MATRIX_IDENTITY;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_matrix_set_identity);
-
-/**
- * cairo_matrix_set_affine:
- * @matrix: a cairo_matrix_t
- * @a: a component of the affine transformation
- * @b: b component of the affine transformation
- * @c: c component of the affine transformation
- * @d: d component of the affine transformation
- * @tx: X translation component of the affine transformation
- * @ty: Y translation component of the affine transformation
- *
- * Sets @matrix to be the affine transformation given by
- * @a, b, @c, @d, @tx, @ty. The transformation is given
- * by:
- * <programlisting>
- * x_new = x * a + y * c + tx;
- * y_new = x * b + y * d + ty;
- * </programlisting>
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_set_affine (cairo_matrix_t *matrix,
- double a, double b,
- double c, double d,
- double tx, double ty)
-{
- matrix->m[0][0] = a; matrix->m[0][1] = b;
- matrix->m[1][0] = c; matrix->m[1][1] = d;
- matrix->m[2][0] = tx; matrix->m[2][1] = ty;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_matrix_set_affine);
-
-/**
- * cairo_matrix_get_affine:
- * @matrix: a @cairo_matrix_t
- * @a: location to store a component of affine transformation, or %NULL
- * @b: location to store b component of affine transformation, or %NULL
- * @c: location to store c component of affine transformation, or %NULL
- * @d: location to store d component of affine transformation, or %NULL
- * @tx: location to store X-translation component of affine transformation, or %NULL
- * @ty: location to store Y-translation component of affine transformation, or %NULL
- *
- * Gets the matrix values for the affine tranformation that @matrix represents.
- * See cairo_matrix_set_affine().
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_get_affine (cairo_matrix_t *matrix,
- double *a, double *b,
- double *c, double *d,
- double *tx, double *ty)
-{
- 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;
-}
-
-cairo_status_t
-_cairo_matrix_set_translate (cairo_matrix_t *matrix,
- double tx, double ty)
-{
- return cairo_matrix_set_affine (matrix,
- 1, 0,
- 0, 1,
- tx, ty);
-}
-
-/**
- * cairo_matrix_translate:
- * @matrix: a cairo_matrix_t
- * @tx: amount to rotate in the X direction
- * @ty: amount to rotate in the Y direction
- *
- * Applies a translation by @tx, @ty to the transformation in
- * @matrix. The new transformation is given by first translating by
- * @tx, @ty then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
-{
- cairo_matrix_t tmp;
-
- _cairo_matrix_set_translate (&tmp, tx, ty);
-
- return cairo_matrix_multiply (matrix, &tmp, matrix);
-}
-
-cairo_status_t
-_cairo_matrix_set_scale (cairo_matrix_t *matrix,
- double sx, double sy)
-{
- return cairo_matrix_set_affine (matrix,
- sx, 0,
- 0, sy,
- 0, 0);
-}
-
-/**
- * cairo_matrix_scale:
- * @matrix: a #cairo_matrix_t
- * @sx: Scale factor in the X direction
- * @sy: Scale factor in the Y direction
- *
- * Applies scaling by @tx, @ty to the transformation in
- * @matrix. The new transformation is given by first scaling by @sx
- * and @sy then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
-{
- cairo_matrix_t tmp;
-
- _cairo_matrix_set_scale (&tmp, sx, sy);
-
- return cairo_matrix_multiply (matrix, &tmp, matrix);
-}
-slim_hidden_def(cairo_matrix_scale);
-
-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,
- c, s,
- -s, c,
- 0, 0);
-}
-
-/**
- * cairo_matrix_rotate:
- * @matrix: a @cairo_matrix_t
- * @radians: angle of rotation, in radians. Angles are defined
- * so that an angle of 90 degrees (%M_PI radians) rotates the
- * positive X axis into the positive Y axis. With the default
- * Cairo choice of axis orientation, positive rotations are
- * clockwise.
- *
- * Applies rotation by @radians to the transformation in
- * @matrix. The new transformation is given by first rotating by
- * @radians then applying the original transformation
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
-{
- cairo_matrix_t tmp;
-
- _cairo_matrix_set_rotate (&tmp, radians);
-
- return cairo_matrix_multiply (matrix, &tmp, matrix);
-}
-
-/**
- * cairo_matrix_multiply:
- * @result: a @cairo_matrix_t in which to store the result
- * @a: a @cairo_matrix_t
- * @b: a @cairo_matrix_t
- *
- * Multiplies the affine transformations in @a and @b together
- * and stores the result in @result. The resulting transformation
- * is given by first applying the transformation in @b then
- * applying the transformation in @a.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
-{
- cairo_matrix_t r;
- int row, col, n;
- double t;
-
- for (row = 0; row < 3; row++) {
- for (col = 0; col < 2; col++) {
- if (row == 2)
- t = b->m[2][col];
- else
- t = 0;
- for (n = 0; n < 2; n++) {
- t += a->m[row][n] * b->m[n][col];
- }
- r.m[row][col] = t;
- }
- }
-
- *result = r;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_matrix_multiply);
-
-/**
- * cairo_matrix_transform_distance:
- * @matrix: a @cairo_matrix_t
- * @dx: a distance in the X direction. An in/out parameter
- * @dy: a distance in the Y direction. An in/out parameter
- *
- * Transforms the vector (@dx,@dy) by @matrix. Translation is
- * ignored. In terms of the components of the affine transformation:
- *
- * <programlisting>
- * dx2 = dx1 * a + dy1 * c;
- * dy2 = dx1 * b + dy1 * d;
- * </programlisting>
- *
- * Affine transformations are position invariant, so the same vector
- * always transforms to the same vector. If (@x1,@y1) transforms
- * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
- * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy)
-{
- double new_x, new_y;
-
- new_x = (matrix->m[0][0] * *dx
- + matrix->m[1][0] * *dy);
- new_y = (matrix->m[0][1] * *dx
- + matrix->m[1][1] * *dy);
-
- *dx = new_x;
- *dy = new_y;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_matrix_transform_distance);
-
-/**
- * cairo_matrix_transform_point:
- * @matrix: a @cairo_matrix_t
- * @x: X position. An in/out parameter
- * @y: Y position. An in/out parameter
- *
- * Transforms the point (@x, @y) by @matrix.
- *
- * Return value: %CAIRO_STATUS_SUCCESS, always.
- **/
-cairo_status_t
-cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y)
-{
- cairo_matrix_transform_distance (matrix, x, y);
-
- *x += matrix->m[2][0];
- *y += matrix->m[2][1];
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_matrix_transform_point);
-
-cairo_status_t
-_cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
- double *x, double *y,
- double *width, double *height)
-{
- int i;
- double quad_x[4], quad_y[4];
- double dx1, dy1;
- double dx2, dy2;
- double min_x, max_x;
- double min_y, max_y;
-
- quad_x[0] = *x;
- quad_y[0] = *y;
- cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
-
- dx1 = *width;
- dy1 = 0;
- cairo_matrix_transform_distance (matrix, &dx1, &dy1);
- quad_x[1] = quad_x[0] + dx1;
- quad_y[1] = quad_y[0] + dy1;
-
- dx2 = 0;
- dy2 = *height;
- cairo_matrix_transform_distance (matrix, &dx2, &dy2);
- quad_x[2] = quad_x[0] + dx2;
- quad_y[2] = quad_y[0] + dy2;
-
- quad_x[3] = quad_x[0] + dx1 + dx2;
- quad_y[3] = quad_y[0] + dy1 + dy2;
-
- min_x = max_x = quad_x[0];
- min_y = max_y = quad_y[0];
-
- for (i=1; i < 4; i++) {
- if (quad_x[i] < min_x)
- min_x = quad_x[i];
- if (quad_x[i] > max_x)
- max_x = quad_x[i];
-
- if (quad_y[i] < min_y)
- min_y = quad_y[i];
- if (quad_y[i] > max_y)
- max_y = quad_y[i];
- }
-
- *x = min_x;
- *y = min_y;
- *width = max_x - min_x;
- *height = max_y - min_y;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
-{
- int row, col;
-
- for (row = 0; row < 3; row++)
- for (col = 0; col < 2; col++)
- matrix->m[row][col] *= scalar;
-}
-
-/* This function isn't a correct adjoint in that the implicit 1 in the
- homogeneous result should actually be ad-bc instead. But, since this
- adjoint is only used in the computation of the inverse, which
- divides by det (A)=ad-bc anyway, everything works out in the end. */
-static void
-_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
-{
- /* adj (A) = transpose (C:cofactor (A,i,j)) */
- double a, b, c, d, tx, 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];
-
- cairo_matrix_set_affine (matrix,
- d, -b,
- -c, a,
- c*ty - d*tx, b*tx - a*ty);
-}
-
-/**
- * cairo_matrix_invert:
- * @matrix: a @cairo_matrix_t
- *
- * Changes @matrix to be the inverse of it's original value. Not
- * all transformation matrices have inverses; if the matrix
- * collapses points together (it is <firstterm>degenerate</firstterm>),
- * then it has no inverse and this function will fail.
- *
- * Returns: If @matrix has an inverse, modifies @matrix to
- * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise,
- * returns %CAIRO_STATUS_INVALID_MATRIX.
- **/
-cairo_status_t
-cairo_matrix_invert (cairo_matrix_t *matrix)
-{
- /* inv (A) = 1/det (A) * adj (A) */
- double det;
-
- _cairo_matrix_compute_determinant (matrix, &det);
-
- if (det == 0)
- return CAIRO_STATUS_INVALID_MATRIX;
-
- _cairo_matrix_compute_adjoint (matrix);
- _cairo_matrix_scalar_multiply (matrix, 1 / det);
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_matrix_invert);
-
-cairo_status_t
-_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det)
-{
- double a, b, c, d;
-
- a = matrix->m[0][0]; b = matrix->m[0][1];
- c = matrix->m[1][0]; d = matrix->m[1][1];
-
- *det = a*d - b*c;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2)
-{
- /* The eigenvalues of an NxN matrix M are found by solving the polynomial:
-
- det (M - lI) = 0
-
- The zeros in our homogeneous 3x3 matrix make this equation equal
- to that formed by the sub-matrix:
-
- M = a b
- c d
-
- by which:
-
- l^2 - (a+d)l + (ad - bc) = 0
-
- l = (a+d +/- sqrt (a^2 + 2ad + d^2 - 4 (ad-bc))) / 2;
- */
-
- double a, b, c, d, rad;
-
- a = matrix->m[0][0];
- b = matrix->m[0][1];
- c = matrix->m[1][0];
- d = matrix->m[1][1];
-
- rad = sqrt (a*a + 2*a*d + d*d - 4*(a*d - b*c));
- *lambda1 = (a + d + rad) / 2.0;
- *lambda2 = (a + d - rad) / 2.0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* 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, int x_major)
-{
- double det;
-
- _cairo_matrix_compute_determinant (matrix, &det);
-
- 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;
-}
-
-cairo_bool_t
-_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
- int *itx, int *ity)
-{
- double a, b, c, d, tx, ty;
- int ttx, tty;
- int ok = 0;
- cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
- ttx = _cairo_fixed_from_double (tx);
- tty = _cairo_fixed_from_double (ty);
- ok = ((a == 1.0)
- && (b == 0.0)
- && (c == 0.0)
- && (d == 1.0)
- && (_cairo_fixed_is_integer(ttx))
- && (_cairo_fixed_is_integer(tty)));
- if (ok) {
- *itx = _cairo_fixed_integer_part(ttx);
- *ity = _cairo_fixed_integer_part(tty);
- return TRUE;
- }
- return FALSE;
-}
diff --git a/src/cairo_path.c b/src/cairo_path.c
deleted file mode 100644
index 8314f601c..000000000
--- a/src/cairo_path.c
+++ /dev/null
@@ -1,495 +0,0 @@
-/* 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@cworth.org>
- */
-
-#include <stdlib.h>
-#include "cairoint.h"
-
-/* private functions */
-static cairo_status_t
-_cairo_path_add (cairo_path_t *path, cairo_path_op_t op, cairo_point_t *points, int num_pts);
-
-static void
-_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op);
-
-static cairo_status_t
-_cairo_path_new_op_buf (cairo_path_t *path);
-
-static void
-_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg);
-
-static cairo_status_t
-_cairo_path_new_arg_buf (cairo_path_t *path);
-
-static cairo_path_op_buf_t *
-_cairo_path_op_buf_create (void);
-
-static void
-_cairo_path_op_buf_destroy (cairo_path_op_buf_t *buf);
-
-static void
-_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op_t op);
-
-static cairo_path_arg_buf_t *
-_cairo_path_arg_buf_create (void);
-
-static void
-_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *buf);
-
-static void
-_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, cairo_point_t *points, int num_points);
-
-void
-_cairo_path_init (cairo_path_t *path)
-{
- path->op_head = NULL;
- path->op_tail = NULL;
-
- path->arg_head = NULL;
- path->arg_tail = NULL;
-
- path->current_point.x = 0;
- path->current_point.y = 0;
- path->has_current_point = 0;
- path->last_move_point = path->current_point;
-}
-
-cairo_status_t
-_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
-{
- cairo_path_op_buf_t *op, *other_op;
- cairo_path_arg_buf_t *arg, *other_arg;
-
- _cairo_path_init (path);
- path->current_point = other->current_point;
- path->has_current_point = other->has_current_point;
- path->last_move_point = other->last_move_point;
-
- for (other_op = other->op_head; other_op; other_op = other_op->next) {
- op = _cairo_path_op_buf_create ();
- if (op == NULL) {
- _cairo_path_fini(path);
- return CAIRO_STATUS_NO_MEMORY;
- }
- *op = *other_op;
- _cairo_path_add_op_buf (path, op);
- }
-
- for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) {
- arg = _cairo_path_arg_buf_create ();
- if (arg == NULL) {
- _cairo_path_fini(path);
- return CAIRO_STATUS_NO_MEMORY;
- }
- *arg = *other_arg;
- _cairo_path_add_arg_buf (path, arg);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_path_fini (cairo_path_t *path)
-{
- cairo_path_op_buf_t *op;
- cairo_path_arg_buf_t *arg;
-
- while (path->op_head) {
- op = path->op_head;
- path->op_head = op->next;
- _cairo_path_op_buf_destroy (op);
- }
- path->op_tail = NULL;
-
- while (path->arg_head) {
- arg = path->arg_head;
- path->arg_head = arg->next;
- _cairo_path_arg_buf_destroy (arg);
- }
- path->arg_tail = NULL;
-
- path->has_current_point = 0;
-}
-
-cairo_status_t
-_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point)
-{
- cairo_status_t status;
-
- status = _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, point, 1);
- if (status)
- return status;
-
- path->current_point = *point;
- path->has_current_point = 1;
- path->last_move_point = path->current_point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_rel_move_to (cairo_path_t *path, cairo_distance_t *distance)
-{
- cairo_point_t point;
-
- point.x = path->current_point.x + distance->dx;
- point.y = path->current_point.y + distance->dy;
-
- return _cairo_path_move_to (path, &point);
-}
-
-cairo_status_t
-_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point)
-{
- cairo_status_t status;
-
- status = _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, point, 1);
- if (status)
- return status;
-
- path->current_point = *point;
- path->has_current_point = 1;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_rel_line_to (cairo_path_t *path, cairo_distance_t *distance)
-{
- cairo_point_t point;
-
- point.x = path->current_point.x + distance->dx;
- point.y = path->current_point.y + distance->dy;
-
- return _cairo_path_line_to (path, &point);
-}
-
-cairo_status_t
-_cairo_path_curve_to (cairo_path_t *path,
- cairo_point_t *p0,
- cairo_point_t *p1,
- cairo_point_t *p2)
-{
- cairo_status_t status;
- cairo_point_t point[3];
-
- point[0] = *p0;
- point[1] = *p1;
- point[2] = *p2;
-
- status = _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
- if (status)
- return status;
-
- path->current_point = *p2;
- path->has_current_point = 1;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_rel_curve_to (cairo_path_t *path,
- cairo_distance_t *d0,
- cairo_distance_t *d1,
- cairo_distance_t *d2)
-{
- cairo_point_t p0, p1, p2;
-
- p0.x = path->current_point.x + d0->dx;
- p0.y = path->current_point.y + d0->dy;
-
- p1.x = path->current_point.x + d1->dx;
- p1.y = path->current_point.y + d1->dy;
-
- p2.x = path->current_point.x + d2->dx;
- p2.y = path->current_point.y + d2->dy;
-
- return _cairo_path_curve_to (path, &p0, &p1, &p2);
-}
-
-cairo_status_t
-_cairo_path_close_path (cairo_path_t *path)
-{
- cairo_status_t status;
-
- status = _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
- if (status)
- return status;
-
- path->current_point.x = path->last_move_point.x;
- path->current_point.y = path->last_move_point.y;
- path->has_current_point = 1;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point)
-{
- if (! path->has_current_point)
- return CAIRO_STATUS_NO_CURRENT_POINT;
-
- *point = path->current_point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_add (cairo_path_t *path, cairo_path_op_t op, cairo_point_t *points, int num_points)
-{
- cairo_status_t status;
-
- if (path->op_tail == NULL || path->op_tail->num_ops + 1 > CAIRO_PATH_BUF_SZ) {
- status = _cairo_path_new_op_buf (path);
- if (status)
- return status;
- }
- _cairo_path_op_buf_add (path->op_tail, op);
-
- if (path->arg_tail == NULL || path->arg_tail->num_points + num_points > CAIRO_PATH_BUF_SZ) {
- status = _cairo_path_new_arg_buf (path);
- if (status)
- return status;
- }
- _cairo_path_arg_buf_add (path->arg_tail, points, num_points);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_path_add_op_buf (cairo_path_t *path, cairo_path_op_buf_t *op)
-{
- op->next = NULL;
- op->prev = path->op_tail;
-
- if (path->op_tail) {
- path->op_tail->next = op;
- } else {
- path->op_head = op;
- }
-
- path->op_tail = op;
-}
-
-static cairo_status_t
-_cairo_path_new_op_buf (cairo_path_t *path)
-{
- cairo_path_op_buf_t *op;
-
- op = _cairo_path_op_buf_create ();
- if (op == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_path_add_op_buf (path, op);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_path_add_arg_buf (cairo_path_t *path, cairo_path_arg_buf_t *arg)
-{
- arg->next = NULL;
- arg->prev = path->arg_tail;
-
- if (path->arg_tail) {
- path->arg_tail->next = arg;
- } else {
- path->arg_head = arg;
- }
-
- path->arg_tail = arg;
-}
-
-static cairo_status_t
-_cairo_path_new_arg_buf (cairo_path_t *path)
-{
- cairo_path_arg_buf_t *arg;
-
- arg = _cairo_path_arg_buf_create ();
-
- if (arg == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_path_add_arg_buf (path, arg);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_path_op_buf_t *
-_cairo_path_op_buf_create (void)
-{
- cairo_path_op_buf_t *op;
-
- op = malloc (sizeof (cairo_path_op_buf_t));
-
- if (op) {
- op->num_ops = 0;
- op->next = NULL;
- }
-
- return op;
-}
-
-static void
-_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op)
-{
- free (op);
-}
-
-static void
-_cairo_path_op_buf_add (cairo_path_op_buf_t *op_buf, cairo_path_op_t op)
-{
- op_buf->op[op_buf->num_ops++] = op;
-}
-
-static cairo_path_arg_buf_t *
-_cairo_path_arg_buf_create (void)
-{
- cairo_path_arg_buf_t *arg;
-
- arg = malloc (sizeof (cairo_path_arg_buf_t));
-
- if (arg) {
- arg->num_points = 0;
- arg->next = NULL;
- }
-
- return arg;
-}
-
-static void
-_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg)
-{
- free (arg);
-}
-
-static void
-_cairo_path_arg_buf_add (cairo_path_arg_buf_t *arg, cairo_point_t *points, int num_points)
-{
- int i;
-
- for (i=0; i < num_points; i++) {
- arg->points[arg->num_points++] = points[i];
- }
-}
-
-#define CAIRO_PATH_OP_MAX_ARGS 3
-
-static int const num_args[] =
-{
- 1, /* cairo_path_move_to */
- 1, /* cairo_path_op_line_to */
- 3, /* cairo_path_op_curve_to */
- 0, /* cairo_path_op_close_path */
-};
-
-cairo_status_t
-_cairo_path_interpret (cairo_path_t *path,
- cairo_direction_t dir,
- cairo_path_move_to_func_t *move_to,
- cairo_path_line_to_func_t *line_to,
- cairo_path_curve_to_func_t *curve_to,
- cairo_path_close_path_func_t *close_path,
- void *closure)
-{
- cairo_status_t status;
- int i, arg;
- cairo_path_op_buf_t *op_buf;
- cairo_path_op_t op;
- cairo_path_arg_buf_t *arg_buf = path->arg_head;
- int buf_i = 0;
- cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS];
- int step = (dir == CAIRO_DIRECTION_FORWARD) ? 1 : -1;
-
- for (op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? path->op_head : path->op_tail;
- op_buf;
- op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? op_buf->next : op_buf->prev)
- {
- int start, stop;
- if (dir == CAIRO_DIRECTION_FORWARD) {
- start = 0;
- stop = op_buf->num_ops;
- } else {
- start = op_buf->num_ops - 1;
- stop = -1;
- }
-
- for (i=start; i != stop; i += step) {
- op = op_buf->op[i];
-
- if (dir == CAIRO_DIRECTION_REVERSE) {
- if (buf_i == 0) {
- arg_buf = arg_buf->prev;
- buf_i = arg_buf->num_points;
- }
- buf_i -= num_args[op];
- }
-
- for (arg = 0; arg < num_args[op]; arg++) {
- point[arg] = arg_buf->points[buf_i];
- buf_i++;
- if (buf_i >= arg_buf->num_points) {
- arg_buf = arg_buf->next;
- buf_i = 0;
- }
- }
-
- if (dir == CAIRO_DIRECTION_REVERSE) {
- buf_i -= num_args[op];
- }
-
- switch (op) {
- case CAIRO_PATH_OP_MOVE_TO:
- status = (*move_to) (closure, &point[0]);
- break;
- case CAIRO_PATH_OP_LINE_TO:
- status = (*line_to) (closure, &point[0]);
- break;
- case CAIRO_PATH_OP_CURVE_TO:
- status = (*curve_to) (closure, &point[0], &point[1], &point[2]);
- break;
- case CAIRO_PATH_OP_CLOSE_PATH:
- default:
- status = (*close_path) (closure);
- break;
- }
- if (status)
- return status;
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
diff --git a/src/cairo_path_bounds.c b/src/cairo_path_bounds.c
deleted file mode 100644
index 7c5772a82..000000000
--- a/src/cairo_path_bounds.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * 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
- * 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@cworth.org>
- */
-
-#include "cairoint.h"
-
-typedef struct cairo_path_bounder {
- int has_point;
-
- cairo_fixed_t min_x;
- cairo_fixed_t min_y;
- cairo_fixed_t max_x;
- cairo_fixed_t max_y;
-} cairo_path_bounder_t;
-
-static void
-_cairo_path_bounder_init (cairo_path_bounder_t *bounder);
-
-static void
-_cairo_path_bounder_fini (cairo_path_bounder_t *bounder);
-
-static cairo_status_t
-_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_path_bounder_move_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_path_bounder_line_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_path_bounder_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d);
-
-static cairo_status_t
-_cairo_path_bounder_close_path (void *closure);
-
-static void
-_cairo_path_bounder_init (cairo_path_bounder_t *bounder)
-{
- bounder->has_point = 0;
-}
-
-static void
-_cairo_path_bounder_fini (cairo_path_bounder_t *bounder)
-{
- bounder->has_point = 0;
-}
-
-static cairo_status_t
-_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point)
-{
- if (bounder->has_point) {
- if (point->x < bounder->min_x)
- bounder->min_x = point->x;
-
- if (point->y < bounder->min_y)
- bounder->min_y = point->y;
-
- if (point->x > bounder->max_x)
- bounder->max_x = point->x;
-
- if (point->y > bounder->max_y)
- bounder->max_y = point->y;
- } else {
- bounder->min_x = point->x;
- bounder->min_y = point->y;
- bounder->max_x = point->x;
- bounder->max_y = point->y;
-
- bounder->has_point = 1;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_bounder_move_to (void *closure, cairo_point_t *point)
-{
- cairo_path_bounder_t *bounder = closure;
-
- _cairo_path_bounder_add_point (bounder, point);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_bounder_line_to (void *closure, cairo_point_t *point)
-{
- cairo_path_bounder_t *bounder = closure;
-
- _cairo_path_bounder_add_point (bounder, point);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_bounder_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- cairo_path_bounder_t *bounder = closure;
-
- _cairo_path_bounder_add_point (bounder, b);
- _cairo_path_bounder_add_point (bounder, c);
- _cairo_path_bounder_add_point (bounder, d);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_path_bounder_close_path (void *closure)
-{
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* XXX: Perhaps this should compute a PixRegion rather than 4 doubles */
-cairo_status_t
-_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2)
-{
- cairo_status_t status;
-
- cairo_path_bounder_t bounder;
-
- _cairo_path_bounder_init (&bounder);
-
- status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD,
- _cairo_path_bounder_move_to,
- _cairo_path_bounder_line_to,
- _cairo_path_bounder_curve_to,
- _cairo_path_bounder_close_path,
- &bounder);
- if (status) {
- *x1 = *y1 = *x2 = *y2 = 0.0;
- _cairo_path_bounder_fini (&bounder);
- return status;
- }
-
- *x1 = _cairo_fixed_to_double (bounder.min_x);
- *y1 = _cairo_fixed_to_double (bounder.min_y);
- *x2 = _cairo_fixed_to_double (bounder.max_x);
- *y2 = _cairo_fixed_to_double (bounder.max_y);
-
- _cairo_path_bounder_fini (&bounder);
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_path_fill.c b/src/cairo_path_fill.c
deleted file mode 100644
index dc79b6b96..000000000
--- a/src/cairo_path_fill.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/* 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@cworth.org>
- */
-
-#include "cairoint.h"
-
-typedef struct cairo_filler {
- cairo_gstate_t *gstate;
- cairo_traps_t *traps;
-
- cairo_point_t current_point;
-
- cairo_polygon_t polygon;
-} cairo_filler_t;
-
-static void
-_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps);
-
-static void
-_cairo_filler_fini (cairo_filler_t *filler);
-
-static cairo_status_t
-_cairo_filler_move_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_filler_line_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_filler_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d);
-
-static cairo_status_t
-_cairo_filler_close_path (void *closure);
-
-static void
-_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps)
-{
- filler->gstate = gstate;
- filler->traps = traps;
-
- filler->current_point.x = 0;
- filler->current_point.y = 0;
-
- _cairo_polygon_init (&filler->polygon);
-}
-
-static void
-_cairo_filler_fini (cairo_filler_t *filler)
-{
- _cairo_polygon_fini (&filler->polygon);
-}
-
-static cairo_status_t
-_cairo_filler_move_to (void *closure, cairo_point_t *point)
-{
- cairo_status_t status;
- cairo_filler_t *filler = closure;
- cairo_polygon_t *polygon = &filler->polygon;
-
- status = _cairo_polygon_close (polygon);
- if (status)
- return status;
-
- status = _cairo_polygon_move_to (polygon, point);
- if (status)
- return status;
-
- filler->current_point = *point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_filler_line_to (void *closure, cairo_point_t *point)
-{
- cairo_status_t status;
- cairo_filler_t *filler = closure;
- cairo_polygon_t *polygon = &filler->polygon;
-
- status = _cairo_polygon_line_to (polygon, point);
- if (status)
- return status;
-
- filler->current_point = *point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_filler_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- int i;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_filler_t *filler = closure;
- cairo_polygon_t *polygon = &filler->polygon;
- cairo_gstate_t *gstate = filler->gstate;
- cairo_spline_t spline;
-
- status = _cairo_spline_init (&spline, &filler->current_point, b, c, d);
-
- if (status == CAIRO_INT_STATUS_DEGENERATE)
- return CAIRO_STATUS_SUCCESS;
-
- _cairo_spline_decompose (&spline, gstate->tolerance);
- if (status)
- goto CLEANUP_SPLINE;
-
- for (i = 1; i < spline.num_points; i++) {
- status = _cairo_polygon_line_to (polygon, &spline.points[i]);
- if (status)
- break;
- }
-
- CLEANUP_SPLINE:
- _cairo_spline_fini (&spline);
-
- filler->current_point = *d;
-
- return status;
-}
-
-static cairo_status_t
-_cairo_filler_close_path (void *closure)
-{
- cairo_status_t status;
- cairo_filler_t *filler = closure;
- cairo_polygon_t *polygon = &filler->polygon;
-
- status = _cairo_polygon_close (polygon);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_filler_t filler;
-
- _cairo_filler_init (&filler, gstate, traps);
-
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_filler_move_to,
- _cairo_filler_line_to,
- _cairo_filler_curve_to,
- _cairo_filler_close_path,
- &filler);
- if (status)
- goto BAIL;
-
- status = _cairo_polygon_close (&filler.polygon);
- if (status)
- goto BAIL;
-
- status = _cairo_traps_tessellate_polygon (filler.traps,
- &filler.polygon,
- filler.gstate->fill_rule);
- if (status)
- goto BAIL;
-
-BAIL:
- _cairo_filler_fini (&filler);
-
- return status;
-}
-
diff --git a/src/cairo_path_stroke.c b/src/cairo_path_stroke.c
deleted file mode 100644
index 08b380902..000000000
--- a/src/cairo_path_stroke.c
+++ /dev/null
@@ -1,848 +0,0 @@
-/* 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@cworth.org>
- */
-
-#include "cairoint.h"
-
-typedef struct cairo_stroker {
- cairo_gstate_t *gstate;
- cairo_traps_t *traps;
-
- int has_current_point;
- cairo_point_t current_point;
- cairo_point_t first_point;
-
- int has_current_face;
- cairo_stroke_face_t current_face;
-
- int has_first_face;
- cairo_stroke_face_t first_face;
-
- int dashed;
- int dash_index;
- int dash_on;
- double dash_remain;
-} cairo_stroker_t;
-
-/* private functions */
-static void
-_cairo_stroker_init (cairo_stroker_t *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps);
-
-static void
-_cairo_stroker_fini (cairo_stroker_t *stroker);
-
-static cairo_status_t
-_cairo_stroker_move_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_stroker_line_to (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point);
-
-static cairo_status_t
-_cairo_stroker_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d);
-
-static cairo_status_t
-_cairo_stroker_close_path (void *closure);
-
-static void
-_translate_point (cairo_point_t *point, cairo_point_t *offset);
-
-static int
-_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out);
-
-static cairo_status_t
-_cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out);
-
-static void
-_cairo_stroker_start_dash (cairo_stroker_t *stroker)
-{
- cairo_gstate_t *gstate = stroker->gstate;
- double offset;
- int on = 1;
- int i = 0;
-
- offset = gstate->dash_offset;
- while (offset >= gstate->dash[i]) {
- offset -= gstate->dash[i];
- on = 1-on;
- if (++i == gstate->num_dashes)
- i = 0;
- }
- stroker->dashed = 1;
- stroker->dash_index = i;
- stroker->dash_on = on;
- stroker->dash_remain = gstate->dash[i] - offset;
-}
-
-static void
-_cairo_stroker_step_dash (cairo_stroker_t *stroker, double step)
-{
- cairo_gstate_t *gstate = stroker->gstate;
- stroker->dash_remain -= step;
- if (stroker->dash_remain <= 0) {
- stroker->dash_index++;
- if (stroker->dash_index == gstate->num_dashes)
- stroker->dash_index = 0;
- stroker->dash_on = 1-stroker->dash_on;
- stroker->dash_remain = gstate->dash[stroker->dash_index];
- }
-}
-
-static void
-_cairo_stroker_init (cairo_stroker_t *stroker, cairo_gstate_t *gstate, cairo_traps_t *traps)
-{
- stroker->gstate = gstate;
- stroker->traps = traps;
-
- stroker->has_current_point = 0;
- stroker->has_current_face = 0;
- stroker->has_first_face = 0;
-
- if (gstate->dash)
- _cairo_stroker_start_dash (stroker);
- else
- stroker->dashed = 0;
-}
-
-static void
-_cairo_stroker_fini (cairo_stroker_t *stroker)
-{
- /* nothing to do here */
-}
-
-static void
-_translate_point (cairo_point_t *point, cairo_point_t *offset)
-{
- point->x += offset->x;
- point->y += offset->y;
-}
-
-static int
-_cairo_stroker_face_clockwise (cairo_stroke_face_t *in, cairo_stroke_face_t *out)
-{
- cairo_slope_t in_slope, out_slope;
-
- _cairo_slope_init (&in_slope, &in->point, &in->cw);
- _cairo_slope_init (&out_slope, &out->point, &out->cw);
-
- return _cairo_slope_clockwise (&in_slope, &out_slope);
-}
-
-static cairo_status_t
-_cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out)
-{
- cairo_status_t status;
- cairo_gstate_t *gstate = stroker->gstate;
- int clockwise = _cairo_stroker_face_clockwise (out, in);
- cairo_point_t *inpt, *outpt;
-
- if (in->cw.x == out->cw.x
- && in->cw.y == out->cw.y
- && in->ccw.x == out->ccw.x
- && in->ccw.y == out->ccw.y) {
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (clockwise) {
- inpt = &in->ccw;
- outpt = &out->ccw;
- } else {
- inpt = &in->cw;
- outpt = &out->cw;
- }
-
- switch (gstate->line_join) {
- case CAIRO_LINE_JOIN_ROUND: {
- int i;
- int start, step, stop;
- cairo_point_t tri[3];
- cairo_pen_t *pen = &gstate->pen_regular;
-
- tri[0] = in->point;
- if (clockwise) {
- _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start);
- step = -1;
- _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop);
- } else {
- _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start);
- step = +1;
- _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop);
- }
-
- i = start;
- tri[1] = *inpt;
- while (i != stop) {
- tri[2] = in->point;
- _translate_point (&tri[2], &pen->vertices[i].point);
- _cairo_traps_tessellate_triangle (stroker->traps, tri);
- tri[1] = tri[2];
- i += step;
- if (i < 0)
- i = pen->num_vertices - 1;
- if (i >= pen->num_vertices)
- i = 0;
- }
-
- tri[2] = *outpt;
-
- return _cairo_traps_tessellate_triangle (stroker->traps, tri);
- }
- case CAIRO_LINE_JOIN_MITER:
- default: {
- /* dot product of incoming slope vector with outgoing slope vector */
- double in_dot_out = ((-in->usr_vector.x * out->usr_vector.x)+
- (-in->usr_vector.y * out->usr_vector.y));
- double ml = gstate->miter_limit;
-
- /*
- * Check the miter limit -- lines meeting at an acute angle
- * can generate long miters, the limit converts them to bevel
- *
- * We want to know when the miter is within the miter limit.
- * That's straightforward to specify:
- *
- * secant (psi / 2) <= ml
- *
- * where psi is the angle between in and out
- *
- * secant(psi/2) = 1/sin(psi/2)
- * 1/sin(psi/2) <= ml
- * 1 <= ml sin(psi/2)
- * 1 <= ml² sin²(psi/2)
- * 2 <= ml² 2 sin²(psi/2)
- * 2·sin²(psi/2) = 1-cos(psi)
- * 2 <= ml² (1-cos(psi))
- *
- * in · out = |in| |out| cos (psi)
- *
- * in and out are both unit vectors, so:
- *
- * in · out = cos (psi)
- *
- * 2 <= ml² (1 - in · out)
- *
- */
- if (2 <= ml * ml * (1 - in_dot_out)) {
- double x1, y1, x2, y2;
- double mx, my;
- double dx1, dx2, dy1, dy2;
- cairo_polygon_t polygon;
- cairo_point_t outer;
-
- /*
- * we've got the points already transformed to device
- * space, but need to do some computation with them and
- * also need to transform the slope from user space to
- * device space
- */
- /* outer point of incoming line face */
- x1 = _cairo_fixed_to_double (inpt->x);
- y1 = _cairo_fixed_to_double (inpt->y);
- dx1 = in->usr_vector.x;
- dy1 = in->usr_vector.y;
- cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
-
- /* outer point of outgoing line face */
- x2 = _cairo_fixed_to_double (outpt->x);
- y2 = _cairo_fixed_to_double (outpt->y);
- dx2 = out->usr_vector.x;
- dy2 = out->usr_vector.y;
- cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
-
- /*
- * Compute the location of the outer corner of the miter.
- * That's pretty easy -- just the intersection of the two
- * outer edges. We've got slopes and points on each
- * of those edges. Compute my directly, then compute
- * mx by using the edge with the larger dy; that avoids
- * dividing by values close to zero.
- */
- my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
- (dx1 * dy2 - dx2 * dy1));
- if (fabs (dy1) >= fabs (dy2))
- mx = (my - y1) * dx1 / dy1 + x1;
- else
- mx = (my - y2) * dx2 / dy2 + x2;
-
- /*
- * Draw the quadrilateral
- */
- outer.x = _cairo_fixed_from_double (mx);
- outer.y = _cairo_fixed_from_double (my);
- _cairo_polygon_init (&polygon);
- _cairo_polygon_move_to (&polygon, &in->point);
- _cairo_polygon_line_to (&polygon, inpt);
- _cairo_polygon_line_to (&polygon, &outer);
- _cairo_polygon_line_to (&polygon, outpt);
- _cairo_polygon_close (&polygon);
- status = _cairo_traps_tessellate_polygon (stroker->traps,
- &polygon,
- CAIRO_FILL_RULE_WINDING);
- _cairo_polygon_fini (&polygon);
-
- return status;
- }
- /* fall through ... */
- }
- case CAIRO_LINE_JOIN_BEVEL: {
- cairo_point_t tri[3];
- tri[0] = in->point;
- tri[1] = *inpt;
- tri[2] = *outpt;
-
- return _cairo_traps_tessellate_triangle (stroker->traps, tri);
- }
- }
-}
-
-static cairo_status_t
-_cairo_stroker_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f)
-{
- cairo_status_t status;
- cairo_gstate_t *gstate = stroker->gstate;
-
- if (gstate->line_cap == CAIRO_LINE_CAP_BUTT)
- return CAIRO_STATUS_SUCCESS;
-
- switch (gstate->line_cap) {
- case CAIRO_LINE_CAP_ROUND: {
- int i;
- int start, stop;
- cairo_slope_t slope;
- cairo_point_t tri[3];
- cairo_pen_t *pen = &gstate->pen_regular;
-
- slope = f->dev_vector;
- _cairo_pen_find_active_cw_vertex_index (pen, &slope, &start);
- slope.dx = -slope.dx;
- slope.dy = -slope.dy;
- _cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop);
-
- tri[0] = f->point;
- tri[1] = f->cw;
- for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
- tri[2] = f->point;
- _translate_point (&tri[2], &pen->vertices[i].point);
- _cairo_traps_tessellate_triangle (stroker->traps, tri);
- tri[1] = tri[2];
- }
- tri[2] = f->ccw;
-
- return _cairo_traps_tessellate_triangle (stroker->traps, tri);
- }
- case CAIRO_LINE_CAP_SQUARE: {
- double dx, dy;
- cairo_slope_t fvector;
- cairo_point_t occw, ocw;
- cairo_polygon_t polygon;
-
- dx = f->usr_vector.x;
- dy = f->usr_vector.y;
- dx *= gstate->line_width / 2.0;
- dy *= gstate->line_width / 2.0;
- cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
- fvector.dx = _cairo_fixed_from_double (dx);
- fvector.dy = _cairo_fixed_from_double (dy);
- occw.x = f->ccw.x + fvector.dx;
- occw.y = f->ccw.y + fvector.dy;
- ocw.x = f->cw.x + fvector.dx;
- ocw.y = f->cw.y + fvector.dy;
-
- _cairo_polygon_init (&polygon);
- _cairo_polygon_move_to (&polygon, &f->cw);
- _cairo_polygon_line_to (&polygon, &ocw);
- _cairo_polygon_line_to (&polygon, &occw);
- _cairo_polygon_line_to (&polygon, &f->ccw);
- _cairo_polygon_close (&polygon);
-
- status = _cairo_traps_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING);
- _cairo_polygon_fini (&polygon);
-
- return status;
- }
- case CAIRO_LINE_CAP_BUTT:
- default:
- return CAIRO_STATUS_SUCCESS;
- }
-}
-
-static void
-_compute_face (cairo_point_t *point, cairo_slope_t *slope, cairo_gstate_t *gstate, cairo_stroke_face_t *face)
-{
- double mag, det;
- double line_dx, line_dy;
- double face_dx, face_dy;
- cairo_point_double_t usr_vector;
- cairo_point_t offset_ccw, offset_cw;
-
- line_dx = _cairo_fixed_to_double (slope->dx);
- line_dy = _cairo_fixed_to_double (slope->dy);
-
- /* faces are normal in user space, not device space */
- cairo_matrix_transform_distance (&gstate->ctm_inverse, &line_dx, &line_dy);
-
- mag = sqrt (line_dx * line_dx + line_dy * line_dy);
- if (mag == 0) {
- /* XXX: Can't compute other face points. Do we want a tag in the face for this case? */
- return;
- }
-
- /* normalize to unit length */
- line_dx /= mag;
- line_dy /= mag;
-
- usr_vector.x = line_dx;
- usr_vector.y = line_dy;
-
- /*
- * rotate to get a line_width/2 vector along the face, note that
- * the vector must be rotated the right direction in device space,
- * but by 90° in user space. So, the rotation depends on
- * whether the ctm reflects or not, and that can be determined
- * by looking at the determinant of the matrix.
- */
- _cairo_matrix_compute_determinant (&gstate->ctm, &det);
- if (det >= 0)
- {
- face_dx = - line_dy * (gstate->line_width / 2.0);
- face_dy = line_dx * (gstate->line_width / 2.0);
- }
- else
- {
- face_dx = line_dy * (gstate->line_width / 2.0);
- face_dy = - line_dx * (gstate->line_width / 2.0);
- }
-
- /* back to device space */
- cairo_matrix_transform_distance (&gstate->ctm, &face_dx, &face_dy);
-
- offset_ccw.x = _cairo_fixed_from_double (face_dx);
- offset_ccw.y = _cairo_fixed_from_double (face_dy);
- offset_cw.x = -offset_ccw.x;
- offset_cw.y = -offset_ccw.y;
-
- face->ccw = *point;
- _translate_point (&face->ccw, &offset_ccw);
-
- face->point = *point;
-
- face->cw = *point;
- _translate_point (&face->cw, &offset_cw);
-
- face->usr_vector.x = usr_vector.x;
- face->usr_vector.y = usr_vector.y;
-
- face->dev_vector = *slope;
-}
-
-static cairo_status_t
-_cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, cairo_point_t *p1, cairo_point_t *p2,
- cairo_stroke_face_t *start, cairo_stroke_face_t *end)
-{
- cairo_status_t status;
- cairo_gstate_t *gstate = stroker->gstate;
- cairo_polygon_t polygon;
- cairo_slope_t slope;
-
- if (p1->x == p2->x && p1->y == p2->y) {
- /* XXX: Need to rethink how this case should be handled, (both
- here and in _compute_face). The key behavior is that
- degenerate paths should draw as much as possible. */
- return CAIRO_STATUS_SUCCESS;
- }
-
- _cairo_slope_init (&slope, p1, p2);
- _compute_face (p1, &slope, gstate, start);
-
- /* XXX: This could be optimized slightly by not calling
- _compute_face again but rather translating the relevant
- fields from start. */
- _compute_face (p2, &slope, gstate, end);
-
- /* XXX: I should really check the return value of the
- move_to/line_to functions here to catch out of memory
- conditions. But since that would be ugly, I'd prefer to add a
- status flag to the polygon object that I could check only once
- at then end of this sequence, (like we do with cairo_t
- already). */
- _cairo_polygon_init (&polygon);
- _cairo_polygon_move_to (&polygon, &start->cw);
- _cairo_polygon_line_to (&polygon, &start->ccw);
- _cairo_polygon_line_to (&polygon, &end->ccw);
- _cairo_polygon_line_to (&polygon, &end->cw);
- _cairo_polygon_close (&polygon);
-
- /* XXX: We can't use tessellate_rectangle as the matrix may have
- skewed this into a non-rectangular shape. Perhaps it would be
- worth checking the matrix for skew so that the common case
- could use the faster tessellate_rectangle rather than
- tessellate_polygon? */
- status = _cairo_traps_tessellate_polygon (stroker->traps,
- &polygon, CAIRO_FILL_RULE_WINDING);
-
- _cairo_polygon_fini (&polygon);
-
- return status;
-}
-
-static cairo_status_t
-_cairo_stroker_move_to (void *closure, cairo_point_t *point)
-{
- cairo_stroker_t *stroker = closure;
-
- stroker->first_point = *point;
- stroker->current_point = *point;
- stroker->has_current_point = 1;
-
- stroker->has_first_face = 0;
- stroker->has_current_face = 0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_stroker_line_to (void *closure, cairo_point_t *point)
-{
- cairo_status_t status;
- cairo_stroker_t *stroker = closure;
- cairo_stroke_face_t start, end;
- cairo_point_t *p1 = &stroker->current_point;
- cairo_point_t *p2 = point;
-
- if (!stroker->has_current_point)
- return _cairo_stroker_move_to (stroker, point);
-
- if (p1->x == p2->x && p1->y == p2->y) {
- /* XXX: Need to rethink how this case should be handled, (both
- here and in cairo_stroker_add_sub_edge and in _compute_face). The
- key behavior is that degenerate paths should draw as much
- as possible. */
- return CAIRO_STATUS_SUCCESS;
- }
-
- status = _cairo_stroker_add_sub_edge (stroker, p1, p2, &start, &end);
- if (status)
- return status;
-
- if (stroker->has_current_face) {
- status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
- if (status)
- return status;
- } else {
- if (!stroker->has_first_face) {
- stroker->first_face = start;
- stroker->has_first_face = 1;
- }
- }
- stroker->current_face = end;
- stroker->has_current_face = 1;
-
- stroker->current_point = *point;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/*
- * Dashed lines. Cap each dash end, join around turns when on
- */
-static cairo_status_t
-_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_stroker_t *stroker = closure;
- cairo_gstate_t *gstate = stroker->gstate;
- double mag, remain, tmp;
- double dx, dy;
- double dx2, dy2;
- cairo_point_t fd1, fd2;
- int first = 1;
- cairo_stroke_face_t sub_start, sub_end;
- cairo_point_t *p1 = &stroker->current_point;
- cairo_point_t *p2 = point;
-
- if (!stroker->has_current_point)
- return _cairo_stroker_move_to (stroker, point);
-
- dx = _cairo_fixed_to_double (p2->x - p1->x);
- dy = _cairo_fixed_to_double (p2->y - p1->y);
-
- cairo_matrix_transform_distance (&gstate->ctm_inverse, &dx, &dy);
-
- mag = sqrt (dx *dx + dy * dy);
- remain = mag;
- fd1 = *p1;
- while (remain) {
- tmp = stroker->dash_remain;
- if (tmp > remain)
- tmp = remain;
- remain -= tmp;
- dx2 = dx * (mag - remain)/mag;
- dy2 = dy * (mag - remain)/mag;
- cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
- fd2.x = _cairo_fixed_from_double (dx2);
- fd2.y = _cairo_fixed_from_double (dy2);
- fd2.x += p1->x;
- fd2.y += p1->y;
- /*
- * XXX simplify this case analysis
- */
- if (stroker->dash_on) {
- status = _cairo_stroker_add_sub_edge (stroker, &fd1, &fd2, &sub_start, &sub_end);
- if (status)
- return status;
- if (!first) {
- /*
- * Not first dash in this segment, cap start
- */
- status = _cairo_stroker_cap (stroker, &sub_start);
- if (status)
- return status;
- } else {
- /*
- * First in this segment, join to any current_face, else
- * if at start of sub-path, mark position, else
- * cap
- */
- if (stroker->has_current_face) {
- status = _cairo_stroker_join (stroker, &stroker->current_face, &sub_start);
- if (status)
- return status;
- } else {
- if (!stroker->has_first_face) {
- stroker->first_face = sub_start;
- stroker->has_first_face = 1;
- } else {
- status = _cairo_stroker_cap (stroker, &sub_start);
- if (status)
- return status;
- }
- }
- }
- if (remain) {
- /*
- * Cap if not at end of segment
- */
- status = _cairo_stroker_cap (stroker, &sub_end);
- if (status)
- return status;
- } else {
- /*
- * Mark previous line face and fix up next time
- * through
- */
- stroker->current_face = sub_end;
- stroker->has_current_face = 1;
- }
- } else {
- /*
- * If starting with off dash, check previous face
- * and cap if necessary
- */
- if (first) {
- if (stroker->has_current_face) {
- status = _cairo_stroker_cap (stroker, &stroker->current_face);
- if (status)
- return status;
- }
- }
- if (!remain)
- stroker->has_current_face = 0;
- }
- _cairo_stroker_step_dash (stroker, tmp);
- fd1 = fd2;
- first = 0;
- }
-
- stroker->current_point = *point;
-
- return status;
-}
-
-static cairo_status_t
-_cairo_stroker_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_stroker_t *stroker = closure;
- cairo_gstate_t *gstate = stroker->gstate;
- cairo_spline_t spline;
- cairo_pen_t pen;
- cairo_stroke_face_t start, end;
- cairo_point_t extra_points[4];
- cairo_point_t *a = &stroker->current_point;
-
- status = _cairo_spline_init (&spline, a, b, c, d);
- if (status == CAIRO_INT_STATUS_DEGENERATE)
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_pen_init_copy (&pen, &gstate->pen_regular);
- if (status)
- goto CLEANUP_SPLINE;
-
- _compute_face (a, &spline.initial_slope, gstate, &start);
- _compute_face (d, &spline.final_slope, gstate, &end);
-
- if (stroker->has_current_face) {
- status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
- if (status)
- return status;
- } else {
- if (!stroker->has_first_face) {
- stroker->first_face = start;
- stroker->has_first_face = 1;
- }
- }
- stroker->current_face = end;
- stroker->has_current_face = 1;
-
- extra_points[0] = start.cw;
- extra_points[0].x -= start.point.x;
- extra_points[0].y -= start.point.y;
- extra_points[1] = start.ccw;
- extra_points[1].x -= start.point.x;
- extra_points[1].y -= start.point.y;
- extra_points[2] = end.cw;
- extra_points[2].x -= end.point.x;
- extra_points[2].y -= end.point.y;
- extra_points[3] = end.ccw;
- extra_points[3].x -= end.point.x;
- extra_points[3].y -= end.point.y;
-
- status = _cairo_pen_add_points (&pen, extra_points, 4);
- if (status)
- goto CLEANUP_PEN;
-
- status = _cairo_pen_stroke_spline (&pen, &spline, gstate->tolerance, stroker->traps);
- if (status)
- goto CLEANUP_PEN;
-
- CLEANUP_PEN:
- _cairo_pen_fini (&pen);
- CLEANUP_SPLINE:
- _cairo_spline_fini (&spline);
-
- stroker->current_point = *d;
-
- return status;
-}
-
-static cairo_status_t
-_cairo_stroker_close_path (void *closure)
-{
- cairo_status_t status;
- cairo_stroker_t *stroker = closure;
-
- if (stroker->has_current_point) {
- if (stroker->dashed)
- status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
- else
- status = _cairo_stroker_line_to (stroker, &stroker->first_point);
- if (status)
- return status;
- }
-
- if (stroker->has_first_face && stroker->has_current_face) {
- status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face);
- if (status)
- return status;
- }
-
- stroker->has_first_face = 0;
- stroker->has_current_face = 0;
- stroker->has_current_point = 0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_stroker_t stroker;
-
- _cairo_stroker_init (&stroker, gstate, traps);
-
- if (gstate->dash)
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_stroker_move_to,
- _cairo_stroker_line_to_dashed,
- _cairo_stroker_curve_to,
- _cairo_stroker_close_path,
- &stroker);
- else
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_stroker_move_to,
- _cairo_stroker_line_to,
- _cairo_stroker_curve_to,
- _cairo_stroker_close_path,
- &stroker);
- if (status)
- goto BAIL;
-
- if (stroker.has_first_face) {
- cairo_point_t t;
- /* The initial cap needs an outward facing vector. Reverse everything */
- stroker.first_face.usr_vector.x = -stroker.first_face.usr_vector.x;
- stroker.first_face.usr_vector.y = -stroker.first_face.usr_vector.y;
- stroker.first_face.dev_vector.dx = -stroker.first_face.dev_vector.dx;
- stroker.first_face.dev_vector.dy = -stroker.first_face.dev_vector.dy;
- t = stroker.first_face.cw;
- stroker.first_face.cw = stroker.first_face.ccw;
- stroker.first_face.ccw = t;
- status = _cairo_stroker_cap (&stroker, &stroker.first_face);
- if (status)
- goto BAIL;
- }
-
- if (stroker.has_current_face) {
- status = _cairo_stroker_cap (&stroker, &stroker.current_face);
- if (status)
- goto BAIL;
- }
-
-BAIL:
- _cairo_stroker_fini (&stroker);
-
- return status;
-}
diff --git a/src/cairo_pattern.c b/src/cairo_pattern.c
deleted file mode 100644
index 283c36dbd..000000000
--- a/src/cairo_pattern.c
+++ /dev/null
@@ -1,1325 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 David Reveman
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of David
- * Reveman not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. David Reveman makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: David Reveman <davidr@novell.com>
- */
-
-#include "cairoint.h"
-
-typedef void (*cairo_shader_function_t) (unsigned char *color0,
- unsigned char *color1,
- cairo_fixed_t factor,
- uint32_t *pixel);
-
-typedef struct _cairo_shader_color_stop {
- cairo_fixed_t offset;
- cairo_fixed_48_16_t scale;
- int id;
- unsigned char color_char[4];
-} cairo_shader_color_stop_t;
-
-typedef struct _cairo_shader_op {
- cairo_shader_color_stop_t *stops;
- int n_stops;
- cairo_extend_t extend;
- cairo_shader_function_t shader_function;
-} cairo_shader_op_t;
-
-#define MULTIPLY_COLORCOMP(c1, c2) \
- ((unsigned char) \
- ((((unsigned char) (c1)) * (int) ((unsigned char) (c2))) / 0xff))
-
-static void
-_cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
-{
- pattern->type = type;
- pattern->ref_count = 1;
- pattern->extend = CAIRO_EXTEND_DEFAULT;
- pattern->filter = CAIRO_FILTER_DEFAULT;
- pattern->alpha = 1.0;
-
- _cairo_matrix_init (&pattern->matrix);
-}
-
-static cairo_status_t
-_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
- cairo_gradient_pattern_t *other)
-{
- if (other->base.type == CAIRO_PATTERN_LINEAR)
- {
- cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern;
- cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other;
-
- *dst = *src;
- }
- else
- {
- cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern;
- cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other;
-
- *dst = *src;
- }
-
- if (other->n_stops)
- {
- pattern->stops = malloc (other->n_stops * sizeof (cairo_color_stop_t));
- if (!pattern->stops)
- return CAIRO_STATUS_NO_MEMORY;
-
- memcpy (pattern->stops, other->stops,
- other->n_stops * sizeof (cairo_color_stop_t));
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other)
-{
- switch (other->type) {
- case CAIRO_PATTERN_SOLID: {
- cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern;
- cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other;
-
- *dst = *src;
- } break;
- case CAIRO_PATTERN_SURFACE: {
- cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern;
- cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other;
-
- *dst = *src;
- cairo_surface_reference (dst->surface);
- } break;
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern;
- cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other;
- cairo_status_t status;
-
- status = _cairo_gradient_pattern_init_copy (dst, src);
- if (status)
- return status;
- } break;
- }
-
- pattern->ref_count = 1;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_pattern_fini (cairo_pattern_t *pattern)
-{
- switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
- break;
- case CAIRO_PATTERN_SURFACE: {
- cairo_surface_pattern_t *fini = (cairo_surface_pattern_t *) pattern;
-
- cairo_surface_destroy (fini->surface);
- } break;
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- cairo_gradient_pattern_t *fini = (cairo_gradient_pattern_t *) pattern;
-
- if (fini->n_stops)
- free (fini->stops);
- } break;
- }
-}
-
-void
-_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
- double red,
- double green,
- double blue)
-{
- _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SOLID);
-
- pattern->red = red;
- pattern->green = green;
- pattern->blue = blue;
-}
-
-void
-_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
- cairo_surface_t *surface)
-{
- _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SURFACE);
-
- pattern->surface = surface;
- cairo_surface_reference (surface);
-}
-
-static void
-_cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern,
- cairo_pattern_type_t type)
-{
- _cairo_pattern_init (&pattern->base, type);
-
- pattern->stops = 0;
- pattern->n_stops = 0;
-}
-
-void
-_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
- double x0, double y0, double x1, double y1)
-{
- _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_LINEAR);
-
- pattern->point0.x = x0;
- pattern->point0.y = y0;
- pattern->point1.x = x1;
- pattern->point1.y = y1;
-}
-
-void
-_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
- double cx0, double cy0, double radius0,
- double cx1, double cy1, double radius1)
-{
- _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_RADIAL);
-
- pattern->center0.x = cx0;
- pattern->center0.y = cy0;
- pattern->radius0 = fabs (radius0);
- pattern->center1.x = cx1;
- pattern->center1.y = cy1;
- pattern->radius1 = fabs (radius1);
-}
-
-cairo_pattern_t *
-_cairo_pattern_create_solid (double red, double green, double blue)
-{
- cairo_solid_pattern_t *pattern;
-
- pattern = malloc (sizeof (cairo_solid_pattern_t));
- if (pattern == NULL)
- return NULL;
-
- _cairo_pattern_init_solid (pattern, red, green, blue);
-
- return &pattern->base;
-}
-
-cairo_pattern_t *
-cairo_pattern_create_for_surface (cairo_surface_t *surface)
-{
- cairo_surface_pattern_t *pattern;
-
- pattern = malloc (sizeof (cairo_surface_pattern_t));
- if (pattern == NULL)
- return NULL;
-
- _cairo_pattern_init_for_surface (pattern, surface);
-
- /* this will go away when we completely remove the surface attributes */
- if (surface->repeat)
- pattern->base.extend = CAIRO_EXTEND_REPEAT;
- else
- pattern->base.extend = CAIRO_EXTEND_DEFAULT;
-
- return &pattern->base;
-}
-
-cairo_pattern_t *
-cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
-{
- cairo_linear_pattern_t *pattern;
-
- pattern = malloc (sizeof (cairo_linear_pattern_t));
- if (pattern == NULL)
- return NULL;
-
- _cairo_pattern_init_linear (pattern, x0, y0, x1, y1);
-
- return &pattern->base.base;
-}
-
-cairo_pattern_t *
-cairo_pattern_create_radial (double cx0, double cy0, double radius0,
- double cx1, double cy1, double radius1)
-{
- cairo_radial_pattern_t *pattern;
-
- pattern = malloc (sizeof (cairo_radial_pattern_t));
- if (pattern == NULL)
- return NULL;
-
- _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1);
-
- return &pattern->base.base;
-}
-
-void
-cairo_pattern_reference (cairo_pattern_t *pattern)
-{
- if (pattern == NULL)
- return;
-
- pattern->ref_count++;
-}
-
-void
-cairo_pattern_destroy (cairo_pattern_t *pattern)
-{
- if (pattern == NULL)
- return;
-
- pattern->ref_count--;
- if (pattern->ref_count)
- return;
-
- _cairo_pattern_fini (pattern);
- free (pattern);
-}
-
-static cairo_status_t
-_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
- double offset,
- double red,
- double green,
- double blue,
- double alpha)
-{
- cairo_color_stop_t *stop;
-
- pattern->n_stops++;
- pattern->stops = realloc (pattern->stops,
- pattern->n_stops * sizeof (cairo_color_stop_t));
- if (pattern->stops == NULL) {
- pattern->n_stops = 0;
-
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- stop = &pattern->stops[pattern->n_stops - 1];
-
- stop->offset = _cairo_fixed_from_double (offset);
-
- _cairo_color_init (&stop->color);
- _cairo_color_set_rgb (&stop->color, red, green, blue);
- _cairo_color_set_alpha (&stop->color, alpha);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
- double offset,
- double red,
- double green,
- double blue,
- double alpha)
-{
- if (pattern->type != CAIRO_PATTERN_LINEAR &&
- pattern->type != CAIRO_PATTERN_RADIAL)
- {
- /* XXX: CAIRO_STATUS_INVALID_PATTERN? */
- return CAIRO_STATUS_SUCCESS;
- }
-
- _cairo_restrict_value (&offset, 0.0, 1.0);
- _cairo_restrict_value (&red, 0.0, 1.0);
- _cairo_restrict_value (&green, 0.0, 1.0);
- _cairo_restrict_value (&blue, 0.0, 1.0);
- _cairo_restrict_value (&alpha, 0.0, 1.0);
-
- return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
- offset,
- red, green, blue,
- alpha);
-}
-
-cairo_status_t
-cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
-{
- return cairo_matrix_copy (&pattern->matrix, matrix);
-}
-
-cairo_status_t
-cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
-{
- return cairo_matrix_copy (matrix, &pattern->matrix);
-}
-
-cairo_status_t
-cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
-{
- pattern->filter = filter;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_filter_t
-cairo_pattern_get_filter (cairo_pattern_t *pattern)
-{
- return pattern->filter;
-}
-
-cairo_status_t
-cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
-{
- pattern->extend = extend;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_extend_t
-cairo_pattern_get_extend (cairo_pattern_t *pattern)
-{
- return pattern->extend;
-}
-
-cairo_status_t
-_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
- double *red,
- double *green,
- double *blue)
-{
-
- if (pattern->type == CAIRO_PATTERN_SOLID)
- {
- cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
-
- *red = solid->red;
- *green = solid->green;
- *blue = solid->blue;
- } else
- *red = *green = *blue = 1.0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha)
-{
- pattern->alpha = alpha;
-}
-
-void
-_cairo_pattern_transform (cairo_pattern_t *pattern,
- cairo_matrix_t *ctm_inverse)
-{
- cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
-}
-
-#define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \
- ((factor < 32768)? c1: c2)
-
-static void
-_cairo_pattern_shader_nearest (unsigned char *color0,
- unsigned char *color1,
- cairo_fixed_t factor,
- uint32_t *pixel)
-{
- *pixel =
- ((INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor) << 24) |
- (INTERPOLATE_COLOR_NEAREST (color0[0], color1[0], factor) << 16) |
- (INTERPOLATE_COLOR_NEAREST (color0[1], color1[1], factor) << 8) |
- (INTERPOLATE_COLOR_NEAREST (color0[2], color1[2], factor) << 0));
-}
-
-#undef INTERPOLATE_COLOR_NEAREST
-
-#define INTERPOLATE_COLOR_LINEAR(c1, c2, factor) \
- (((c2 * factor) + (c1 * (65536 - factor))) / 65536)
-
-static void
-_cairo_pattern_shader_linear (unsigned char *color0,
- unsigned char *color1,
- cairo_fixed_t factor,
- uint32_t *pixel)
-{
- *pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) |
- (INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) |
- (INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor) << 8) |
- (INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor) << 0));
-}
-
-#define E_MINUS_ONE 1.7182818284590452354
-
-static void
-_cairo_pattern_shader_gaussian (unsigned char *color0,
- unsigned char *color1,
- cairo_fixed_t factor,
- uint32_t *pixel)
-{
- double f = ((double) factor) / 65536.0;
-
- factor = (cairo_fixed_t) (((exp (f * f) - 1.0) / E_MINUS_ONE) * 65536);
-
- *pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) |
- (INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) |
- (INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor) << 8) |
- (INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor) << 0));
-}
-
-#undef INTERPOLATE_COLOR_LINEAR
-
-static int
-_cairo_shader_color_stop_compare (const void *elem1, const void *elem2)
-{
- cairo_shader_color_stop_t *s1 = (cairo_shader_color_stop_t *) elem1;
- cairo_shader_color_stop_t *s2 = (cairo_shader_color_stop_t *) elem2;
-
- return
- (s1->offset == s2->offset) ?
- /* equal offsets, sort on id */
- ((s1->id < s2->id) ? -1 : 1) :
- /* sort on offset */
- ((s1->offset < s2->offset) ? -1 : 1);
-}
-
-static cairo_status_t
-_cairo_pattern_shader_init (cairo_gradient_pattern_t *pattern,
- cairo_shader_op_t *op)
-{
- int i;
-
- op->stops = malloc (pattern->n_stops * sizeof (cairo_shader_color_stop_t));
- if (!op->stops)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < pattern->n_stops; i++)
- {
- op->stops[i].color_char[0] = pattern->stops[i].color.red * 0xff;
- op->stops[i].color_char[1] = pattern->stops[i].color.green * 0xff;
- op->stops[i].color_char[2] = pattern->stops[i].color.blue * 0xff;
- op->stops[i].color_char[3] = pattern->stops[i].color.alpha *
- pattern->base.alpha * 0xff;
- op->stops[i].offset = pattern->stops[i].offset;
- op->stops[i].id = i;
- }
-
- /* sort stops in ascending order */
- qsort (op->stops, pattern->n_stops, sizeof (cairo_shader_color_stop_t),
- _cairo_shader_color_stop_compare);
-
- for (i = 0; i < pattern->n_stops - 1; i++)
- {
- op->stops[i + 1].scale = op->stops[i + 1].offset - op->stops[i].offset;
- if (op->stops[i + 1].scale == 65536)
- op->stops[i + 1].scale = 0;
- }
-
- op->n_stops = pattern->n_stops;
- op->extend = pattern->base.extend;
-
- /* XXX: this is wrong, the filter should not be used for selecting
- color stop interpolation function. function should always be 'linear'
- and filter should be used for computing pixels. */
- switch (pattern->base.filter) {
- case CAIRO_FILTER_FAST:
- case CAIRO_FILTER_NEAREST:
- op->shader_function = _cairo_pattern_shader_nearest;
- break;
- case CAIRO_FILTER_GAUSSIAN:
- op->shader_function = _cairo_pattern_shader_gaussian;
- break;
- case CAIRO_FILTER_GOOD:
- case CAIRO_FILTER_BEST:
- case CAIRO_FILTER_BILINEAR:
- op->shader_function = _cairo_pattern_shader_linear;
- break;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_pattern_shader_fini (cairo_shader_op_t *op)
-{
- if (op->stops)
- free (op->stops);
-}
-
-/* Find two color stops bounding the given offset. If the given offset
- * is before the first or after the last stop offset, the nearest
- * offset is returned twice.
- */
-static void
-_cairo_shader_op_find_color_stops (cairo_shader_op_t *op,
- cairo_fixed_t offset,
- cairo_shader_color_stop_t *stops[2])
-{
- int i;
-
- /* Before first stop. */
- if (offset <= op->stops[0].offset) {
- stops[0] = &op->stops[0];
- stops[1] = &op->stops[0];
- return;
- }
-
- /* Between two stops. */
- for (i = 0; i < op->n_stops - 1; i++) {
- if (offset <= op->stops[i + 1].offset) {
- stops[0] = &op->stops[i];
- stops[1] = &op->stops[i + 1];
- return;
- }
- }
-
- /* After last stop. */
- stops[0] = &op->stops[op->n_stops - 1];
- stops[1] = &op->stops[op->n_stops - 1];
-}
-
-static void
-_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
- cairo_fixed_t factor,
- uint32_t *pixel)
-{
- cairo_shader_color_stop_t *stops[2];
-
- switch (op->extend) {
- case CAIRO_EXTEND_REPEAT:
- factor -= factor & 0xffff0000;
- break;
- case CAIRO_EXTEND_REFLECT:
- if (factor < 0 || factor > 65536) {
- if ((factor >> 16) % 2)
- factor = 65536 - (factor - (factor & 0xffff0000));
- else
- factor -= factor & 0xffff0000;
- }
- break;
- case CAIRO_EXTEND_NONE:
- break;
- }
-
- _cairo_shader_op_find_color_stops (op, factor, stops);
-
- /* take offset as new 0 of coordinate system */
- factor -= stops[0]->offset;
-
- /* difference between two offsets == 0, abrubt change */
- if (stops[1]->scale)
- factor = ((cairo_fixed_48_16_t) factor << 16) /
- stops[1]->scale;
-
- op->shader_function (stops[0]->color_char,
- stops[1]->color_char,
- factor, pixel);
-
- /* multiply alpha */
- if (((unsigned char) (*pixel >> 24)) != 0xff) {
- *pixel = (*pixel & 0xff000000) |
- (MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) |
- (MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) |
- (MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0);
- }
-}
-
-static cairo_status_t
-_cairo_image_data_set_linear (cairo_linear_pattern_t *pattern,
- double offset_x,
- double offset_y,
- uint32_t *pixels,
- int width,
- int height)
-{
- int x, y;
- cairo_point_double_t point0, point1;
- double a, b, c, d, tx, ty;
- double scale, start, dx, dy, factor;
- cairo_shader_op_t op;
- cairo_status_t status;
-
- status = _cairo_pattern_shader_init (&pattern->base, &op);
- if (status)
- return status;
-
- /* We compute the position in the linear gradient for
- * a point q as:
- *
- * [q . (p1 - p0) - p0 . (p1 - p0)] / (p1 - p0) ^ 2
- *
- * The computation is done in pattern space. The
- * calculation could be heavily optimized by using the
- * fact that 'factor' increases linearly in both
- * directions.
- */
- point0.x = pattern->point0.x;
- point0.y = pattern->point0.y;
- point1.x = pattern->point1.x;
- point1.y = pattern->point1.y;
-
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
-
- dx = point1.x - point0.x;
- dy = point1.y - point0.y;
- scale = dx * dx + dy * dy;
- scale = (scale) ? 1.0 / scale : 1.0;
-
- start = dx * point0.x + dy * point0.y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- double qx_device = x + offset_x;
- double qy_device = y + offset_y;
-
- /* transform fragment into pattern space */
- double qx = a * qx_device + c * qy_device + tx;
- double qy = b * qx_device + d * qy_device + ty;
-
- factor = ((dx * qx + dy * qy) - start) * scale;
-
- _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
- }
- }
-
- _cairo_pattern_shader_fini (&op);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
- double offset_x,
- double offset_y,
- int width,
- int height,
- cairo_bool_t *is_horizontal,
- cairo_bool_t *is_vertical)
-{
- cairo_point_double_t point0, point1;
- double a, b, c, d, tx, ty;
- double scale, start, dx, dy;
- cairo_fixed_t factors[3];
- int i;
-
- /* To classidy a pattern as horizontal or vertical, we first
- * compute the (fixed point) factors at the corners of the
- * pattern. We actually only need 3/4 corners, so we skip the
- * fourth.
- */
- point0.x = pattern->point0.x;
- point0.y = pattern->point0.y;
- point1.x = pattern->point1.x;
- point1.y = pattern->point1.y;
-
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
-
- dx = point1.x - point0.x;
- dy = point1.y - point0.y;
- scale = dx * dx + dy * dy;
- scale = (scale) ? 1.0 / scale : 1.0;
-
- start = dx * point0.x + dy * point0.y;
-
- for (i = 0; i < 3; i++) {
- double qx_device = (i % 2) * (width - 1) + offset_x;
- double qy_device = (i / 2) * (height - 1) + offset_y;
-
- /* transform fragment into pattern space */
- double qx = a * qx_device + c * qy_device + tx;
- double qy = b * qx_device + d * qy_device + ty;
-
- factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale);
- }
-
- /* We consider a pattern to be vertical if the fixed point factor
- * at the two upper corners is the same. We could accept a small
- * change, but determining what change is acceptable would require
- * sorting the stops in the pattern and looking at the differences.
- *
- * Horizontal works the same way with the two left corners.
- */
-
- *is_vertical = factors[1] == factors[0];
- *is_horizontal = factors[2] == factors[0];
-}
-
-static cairo_status_t
-_cairo_image_data_set_radial (cairo_radial_pattern_t *pattern,
- double offset_x,
- double offset_y,
- uint32_t *pixels,
- int width,
- int height)
-{
- int x, y, aligned_circles;
- cairo_point_double_t c0, c1;
- double px, py, ex, ey;
- double a, b, c, d, tx, ty;
- double r0, r1, c0_e_x, c0_e_y, c0_e, c1_e_x, c1_e_y, c1_e,
- c0_c1_x, c0_c1_y, c0_c1, angle_c0, c1_y, y_x, c0_y, c0_x, r1_2,
- denumerator, fraction, factor;
- cairo_shader_op_t op;
- cairo_status_t status;
-
- status = _cairo_pattern_shader_init (&pattern->base, &op);
- if (status)
- return status;
-
- c0.x = pattern->center0.x;
- c0.y = pattern->center0.y;
- r0 = pattern->radius0;
- c1.x = pattern->center1.x;
- c1.y = pattern->center1.y;
- r1 = pattern->radius1;
-
- if (c0.x != c1.x || c0.y != c1.y) {
- aligned_circles = 0;
- c0_c1_x = c1.x - c0.x;
- c0_c1_y = c1.y - c0.y;
- c0_c1 = sqrt (c0_c1_x * c0_c1_x + c0_c1_y * c0_c1_y);
- r1_2 = r1 * r1;
- } else {
- aligned_circles = 1;
- r1 = 1.0 / (r1 - r0);
- r1_2 = c0_c1 = 0.0; /* shut up compiler */
- }
-
- cairo_matrix_get_affine (&pattern->base.base.matrix,
- &a, &b, &c, &d, &tx, &ty);
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- px = x + offset_x;
- py = y + offset_y;
-
- /* transform fragment */
- ex = a * px + c * py + tx;
- ey = b * px + d * py + ty;
-
- if (aligned_circles) {
- ex = ex - c1.x;
- ey = ey - c1.y;
-
- factor = (sqrt (ex * ex + ey * ey) - r0) * r1;
- } else {
- /*
- y (ex, ey)
- c0 -------------------+---------- x
- \ | __--
- \ | __--
- \ | __--
- \ | __-- r1
- \ | __--
- c1 --
-
- We need to calulate distance c0->x; the distance from
- the inner circle center c0, through fragment position
- (ex, ey) to point x where it crosses the outer circle.
-
- From points c0, c1 and (ex, ey) we get angle C0. With
- angle C0 we calculate distance c1->y and c0->y and by
- knowing c1->y and r1, we also know y->x. Adding y->x to
- c0->y gives us c0->x. The gradient offset can then be
- calculated as:
-
- offset = (c0->e - r0) / (c0->x - r0)
-
- */
-
- c0_e_x = ex - c0.x;
- c0_e_y = ey - c0.y;
- c0_e = sqrt (c0_e_x * c0_e_x + c0_e_y * c0_e_y);
-
- c1_e_x = ex - c1.x;
- c1_e_y = ey - c1.y;
- c1_e = sqrt (c1_e_x * c1_e_x + c1_e_y * c1_e_y);
-
- denumerator = -2.0 * c0_e * c0_c1;
-
- if (denumerator != 0.0) {
- fraction = (c1_e * c1_e - c0_e * c0_e - c0_c1 * c0_c1) /
- denumerator;
-
- if (fraction > 1.0)
- fraction = 1.0;
- else if (fraction < -1.0)
- fraction = -1.0;
-
- angle_c0 = acos (fraction);
-
- c0_y = cos (angle_c0) * c0_c1;
- c1_y = sin (angle_c0) * c0_c1;
-
- y_x = sqrt (r1_2 - c1_y * c1_y);
- c0_x = y_x + c0_y;
-
- factor = (c0_e - r0) / (c0_x - r0);
- } else
- factor = -r0;
- }
-
- _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
- }
- }
-
- _cairo_pattern_shader_fini (&op);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **out,
- cairo_surface_attributes_t *attr)
-{
- cairo_image_surface_t *image;
- cairo_status_t status;
- uint32_t *data;
- cairo_bool_t repeat = FALSE;
-
- if (pattern->base.type == CAIRO_PATTERN_LINEAR) {
- cairo_bool_t is_horizontal;
- cairo_bool_t is_vertical;
-
- _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern,
- x, y, width, height,
- &is_horizontal, &is_vertical);
- if (is_horizontal) {
- height = 1;
- repeat = TRUE;
- }
- if (is_vertical) {
- width = 1;
- repeat = TRUE;
- }
- }
-
- data = malloc (width * height * 4);
- if (!data)
- return CAIRO_STATUS_NO_MEMORY;
-
- if (pattern->base.type == CAIRO_PATTERN_LINEAR)
- {
- cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
-
- status = _cairo_image_data_set_linear (linear, x, y, data,
- width, height);
- }
- else
- {
- cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
-
- status = _cairo_image_data_set_radial (radial, x, y, data,
- width, height);
- }
-
- if (status) {
- free (data);
- return status;
- }
-
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data ((char *) data,
- CAIRO_FORMAT_ARGB32,
- width, height,
- width * 4);
-
- if (image == NULL) {
- free (data);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- _cairo_image_surface_assume_ownership_of_data (image);
-
- status = _cairo_surface_clone_similar (dst, &image->base, out);
-
- cairo_surface_destroy (&image->base);
-
- attr->x_offset = -x;
- attr->y_offset = -y;
- cairo_matrix_set_identity (&attr->matrix);
- attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
- attr->filter = CAIRO_FILTER_NEAREST;
- attr->acquired = FALSE;
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **out,
- cairo_surface_attributes_t *attribs)
-{
- cairo_color_t color;
-
- _cairo_color_init (&color);
- _cairo_color_set_rgb (&color, pattern->red, pattern->green, pattern->blue);
- _cairo_color_set_alpha (&color, pattern->base.alpha);
-
- *out = _cairo_surface_create_similar_solid (dst,
- CAIRO_FORMAT_ARGB32,
- 1, 1,
- &color);
-
- if (*out == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- attribs->x_offset = attribs->y_offset = 0;
- cairo_matrix_set_identity (&attribs->matrix);
- attribs->extend = CAIRO_EXTEND_REPEAT;
- attribs->filter = CAIRO_FILTER_NEAREST;
- attribs->acquired = FALSE;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-/**
- * _cairo_pattern_is_opaque
- *
- * Convenience function to determine whether a pattern has an opaque
- * alpha value. This is done by testing whether the pattern's alpha
- * value when converted to a byte is 255, so if a backend actually
- * supported deep alpha channels this function might not do the right
- * thing.
- *
- * Note that for a gradient or surface pattern, the overall resulting
- * alpha for the pattern can be non-opaque even this function returns
- * %TRUE, since the resulting alpha is the multiplication of the
- * alpha of the gradient or surface with the pattern's alpha. In
- * the future, alpha will be moved from the base pattern to the
- * solid pattern subtype, at which point this function should
- * probably be renamed to _cairo_pattern_is_opaque_solid()
- *
- * Return value: %TRUE if the pattern is opaque
- **/
-cairo_bool_t
-_cairo_pattern_is_opaque (cairo_pattern_t *pattern)
-{
- return (pattern->alpha >= ((double)0xff00 / (double)0xffff));
-}
-
-static cairo_int_status_t
-_cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **out,
- cairo_surface_attributes_t *attr)
-{
- cairo_int_status_t status;
-
- attr->acquired = FALSE;
-
- /* handle pattern opacity */
- if (!_cairo_pattern_is_opaque (&pattern->base))
- {
- cairo_surface_pattern_t tmp;
- cairo_color_t color;
-
- _cairo_color_init (&color);
- _cairo_color_set_alpha (&color, pattern->base.alpha);
-
- *out = _cairo_surface_create_similar_solid (dst,
- CAIRO_FORMAT_ARGB32,
- width, height,
- &color);
- if (*out == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- status = _cairo_pattern_init_copy (&tmp.base, &pattern->base);
- if (CAIRO_OK (status))
- {
- tmp.base.alpha = 1.0;
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &tmp.base,
- NULL,
- *out,
- x, y, 0, 0, 0, 0,
- width, height);
-
- _cairo_pattern_fini (&tmp.base);
- }
-
- if (status) {
- cairo_surface_destroy (*out);
- return status;
- }
-
- attr->x_offset = -x;
- attr->y_offset = -y;
- attr->extend = CAIRO_EXTEND_NONE;
- attr->filter = CAIRO_FILTER_NEAREST;
-
- cairo_matrix_set_identity (&attr->matrix);
- }
- else
- {
- int tx, ty;
-
- if (_cairo_surface_is_image (dst))
- {
- cairo_image_surface_t *image;
-
- status = _cairo_surface_acquire_source_image (pattern->surface,
- &image,
- &attr->extra);
- if (CAIRO_OK (status))
- *out = &image->base;
-
- attr->acquired = TRUE;
- }
- else
- status = _cairo_surface_clone_similar (dst, pattern->surface, out);
-
- attr->extend = pattern->base.extend;
- attr->filter = pattern->base.filter;
- if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
- &tx, &ty))
- {
- cairo_matrix_set_identity (&attr->matrix);
- attr->x_offset = tx;
- attr->y_offset = ty;
- }
- else
- {
- attr->matrix = pattern->base.matrix;
- attr->x_offset = attr->y_offset = 0;
- }
- }
-
- return status;
-}
-
-/**
- * _cairo_pattern_acquire_surface:
- * @pattern: a #cairo_pattern_t
- * @dst: destination surface
- * @x: X coordinate in source corresponding to left side of destination area
- * @y: Y coordinate in source corresponding to top side of destination area
- * @width: width of destination area
- * @height: height of destination area
- * @surface_out: location to store a pointer to a surface
- * @attributes: surface attributes that destination backend should apply to
- * the returned surface
- *
- * A convenience function to obtain a surface to use as the source for
- * drawing on @dst.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out.
- **/
-cairo_int_status_t
-_cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- int x,
- int y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **surface_out,
- cairo_surface_attributes_t *attributes)
-{
- switch (pattern->type) {
- case CAIRO_PATTERN_SOLID: {
- cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern;
-
- return _cairo_pattern_acquire_surface_for_solid (src, dst,
- x, y, width, height,
- surface_out,
- attributes);
- } break;
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
- cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern;
-
- /* fast path for gradients with less than 2 color stops */
- if (src->n_stops < 2)
- {
- cairo_solid_pattern_t solid;
-
- if (src->n_stops)
- {
- _cairo_pattern_init_solid (&solid,
- src->stops->color.red,
- src->stops->color.green,
- src->stops->color.blue);
- _cairo_pattern_set_alpha (&solid.base,
- src->stops->color.alpha);
- }
- else
- {
- _cairo_pattern_init_solid (&solid, 0.0, 0.0, 0.0);
- _cairo_pattern_set_alpha (&solid.base, 0.0);
- }
-
- return _cairo_pattern_acquire_surface_for_solid (&solid, dst,
- x, y,
- width, height,
- surface_out,
- attributes);
- }
- else
- return _cairo_pattern_acquire_surface_for_gradient (src, dst,
- x, y,
- width, height,
- surface_out,
- attributes);
- } break;
- case CAIRO_PATTERN_SURFACE: {
- cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;
-
- return _cairo_pattern_acquire_surface_for_surface (src, dst,
- x, y, width, height,
- surface_out,
- attributes);
- } break;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-/**
- * _cairo_pattern_release_surface:
- * @pattern: a #cairo_pattern_t
- * @info: pointer to #cairo_surface_attributes_t filled in by
- * _cairo_pattern_acquire_surface
- *
- * Releases resources obtained by _cairo_pattern_acquire_surface.
- **/
-void
-_cairo_pattern_release_surface (cairo_surface_t *dst,
- cairo_surface_t *surface,
- cairo_surface_attributes_t *attributes)
-{
- if (attributes->acquired)
- _cairo_surface_release_source_image (dst,
- (cairo_image_surface_t *) surface,
- attributes->extra);
- else
- cairo_surface_destroy (surface);
-}
-
-cairo_int_status_t
-_cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
- cairo_pattern_t *mask,
- cairo_surface_t *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- unsigned int width,
- unsigned int height,
- cairo_surface_t **src_out,
- cairo_surface_t **mask_out,
- cairo_surface_attributes_t *src_attributes,
- cairo_surface_attributes_t *mask_attributes)
-{
- cairo_int_status_t status;
-
- cairo_pattern_union_t tmp;
- cairo_bool_t src_opaque, mask_opaque;
- double src_alpha, mask_alpha;
-
- src_opaque = _cairo_pattern_is_opaque (src);
- mask_opaque = !mask || _cairo_pattern_is_opaque (mask);
-
- /* For surface patterns, we move any translucency from src->alpha
- * to mask->alpha so we can use the source unchanged. Otherwise we
- * move the translucency from mask->alpha to src->alpha so that
- * we can drop the mask if possible.
- */
- if (src->type == CAIRO_PATTERN_SURFACE)
- {
- if (mask) {
- mask_opaque = mask_opaque && src_opaque;
- mask_alpha = mask->alpha * src->alpha;
- } else {
- mask_opaque = src_opaque;
- mask_alpha = src->alpha;
- }
-
- src_alpha = 1.0;
- src_opaque = TRUE;
- }
- else
- {
- if (mask)
- {
- src_opaque = mask_opaque && src_opaque;
- src_alpha = mask->alpha * src->alpha;
- /* FIXME: This needs changing when we support RENDER
- * style 4-channel masks.
- */
- if (mask->type == CAIRO_PATTERN_SOLID)
- mask = NULL;
- } else
- src_alpha = src->alpha;
-
- mask_alpha = 1.0;
- mask_opaque = TRUE;
- }
-
- _cairo_pattern_init_copy (&tmp.base, src);
- _cairo_pattern_set_alpha (&tmp.base, src_alpha);
-
- status = _cairo_pattern_acquire_surface (&tmp.base, dst,
- src_x, src_y,
- width, height,
- src_out, src_attributes);
-
- _cairo_pattern_fini (&tmp.base);
-
- if (status)
- return status;
-
- if (mask || !mask_opaque)
- {
- if (mask)
- _cairo_pattern_init_copy (&tmp.base, mask);
- else
- _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0);
-
- _cairo_pattern_set_alpha (&tmp.base, mask_alpha);
-
- status = _cairo_pattern_acquire_surface (&tmp.base, dst,
- mask_x, mask_y,
- width, height,
- mask_out, mask_attributes);
-
- _cairo_pattern_fini (&tmp.base);
-
- if (status)
- {
- _cairo_pattern_release_surface (dst, *src_out, src_attributes);
- return status;
- }
- }
- else
- {
- *mask_out = NULL;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_pdf_surface.c b/src/cairo_pdf_surface.c
deleted file mode 100644
index fee918355..000000000
--- a/src/cairo_pdf_surface.c
+++ /dev/null
@@ -1,2222 +0,0 @@
-/* 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: Eventually, we need to handle other font backends */
-#include "cairo-ft-private.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?
- *
- * - 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;
-
- 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
-
-#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)
-{
- FT_Face face;
- cairo_pdf_ft_font_t *font;
- unsigned long size;
- int i, j;
-
- face = _cairo_ft_unscaled_font_lock_face (unscaled_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->base.unscaled_font = unscaled_font;
- _cairo_unscaled_font_reference (unscaled_font);
- font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
- if (font->glyphs == NULL)
- goto fail2;
-
- 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;
-
- _cairo_ft_unscaled_font_unlock_face (unscaled_font);
-
- 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, 1);
- 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;
-
- font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font);
-
- if (cairo_pdf_ft_font_write_offset_table (font))
- goto fail;
-
- start = cairo_pdf_ft_font_align_output (font);
- end = start;
-
- end = 0;
- for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) {
- if (truetype_tables[i].write (font, truetype_tables[i].tag))
- goto fail;
-
- 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:
- _cairo_ft_unscaled_font_unlock_face (font->base.unscaled_font);
- font->face = NULL;
-
- 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;
-
- _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_resource_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_status_t
-_cairo_pdf_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static void
-_cairo_pdf_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_pdf_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static void
-_cairo_pdf_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_pdf_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-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_surface_pattern_t *pattern)
-{
- cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
- unsigned id;
- cairo_matrix_t i2u;
- cairo_status_t status;
- cairo_image_surface_t *image;
- cairo_surface_t *src;
- void *image_extra;
-
- src = pattern->surface;
- status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
- if (!CAIRO_OK (status))
- return status;
-
- id = emit_image_data (dst->document, image);
- if (id == 0) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto bail;
- }
-
- _cairo_pdf_surface_add_xobject (dst, id);
-
- _cairo_pdf_surface_ensure_stream (dst);
-
- cairo_matrix_copy (&i2u, &pattern->base.matrix);
- cairo_matrix_invert (&i2u);
- cairo_matrix_translate (&i2u, 0, image->height);
- cairo_matrix_scale (&i2u, image->width, -image->height);
-
- 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);
-
- bail:
- _cairo_surface_release_source_image (src, image, image_extra);
-
- return status;
-}
-
-/* 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_surface_pattern_t *pattern)
-{
- cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
- cairo_matrix_t i2u;
- cairo_pdf_stream_t *stream;
- int num_streams, i;
- cairo_pdf_surface_t *src;
-
- _cairo_pdf_surface_ensure_stream (dst);
-
- src = (cairo_pdf_surface_t *) pattern->surface;
-
- cairo_matrix_copy (&i2u, &src->base.matrix);
- cairo_matrix_invert (&i2u);
- cairo_matrix_scale (&i2u,
- 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_pattern_t *src_pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_pdf_surface_t *dst = abstract_dst;
- cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) src_pattern;
-
- if (mask_pattern)
- return CAIRO_STATUS_SUCCESS;
-
- if (src_pattern->type != CAIRO_PATTERN_SURFACE)
- return CAIRO_STATUS_SUCCESS;
-
- if (src->surface->backend == &cairo_pdf_surface_backend)
- return _cairo_pdf_surface_composite_pdf (dst, src);
- else
- return _cairo_pdf_surface_composite_image (dst, src);
-}
-
-static cairo_int_status_t
-_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;
-
- _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_solid_pattern (cairo_pdf_surface_t *surface,
- cairo_solid_pattern_t *pattern)
-{
- cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
- unsigned int alpha;
-
- alpha = _cairo_pdf_surface_add_alpha (surface, pattern->base.alpha);
- _cairo_pdf_surface_ensure_stream (surface);
- fprintf (file,
- "%f %f %f rg /a%d gs\r\n",
- pattern->red,
- pattern->green,
- pattern->blue,
- alpha);
-}
-
-static void
-emit_surface_pattern (cairo_pdf_surface_t *dst,
- cairo_surface_pattern_t *pattern)
-{
- cairo_pdf_document_t *document = dst->document;
- FILE *file = document->file;
- cairo_pdf_stream_t *stream;
- cairo_image_surface_t *image;
- void *image_extra;
- cairo_status_t status;
- char entries[250];
- unsigned int id, alpha;
- cairo_matrix_t pm;
-
- if (pattern->surface->backend == &cairo_pdf_surface_backend) {
- return;
- }
-
- status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
- if (!CAIRO_OK (status))
- return;
-
- _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->base.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);
-
- /* FIXME: emit code to show surface here. */
-
- _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);
-
- _cairo_surface_release_source_image (pattern->surface, image, image_extra);
-}
-
-static unsigned int
-emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_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.red * 0xff, file);
- fputc (pattern->stops[0].color.green * 0xff, file);
- fputc (pattern->stops[0].color.blue * 0xff, file);
- fputc (pattern->stops[1].color.red * 0xff, file);
- fputc (pattern->stops[1].color.green * 0xff, file);
- fputc (pattern->stops[1].color.blue * 0xff, file);
-
- fprintf (file,
- "\r\n"
- "endstream\r\n"
- "endobj\r\n");
-
- return function_id;
-}
-
-static void
-emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_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->base);
-
- cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
- cairo_matrix_invert (&p2u);
-
- x0 = pattern->point0.x;
- y0 = pattern->point0.y;
- cairo_matrix_transform_point (&p2u, &x0, &y0);
- x1 = pattern->point1.x;
- y1 = pattern->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 [ true true ]\r\n"
- " >>\r\n"
- ">>\r\n"
- "endobj\r\n",
- pattern_id,
- document->height_inches * document->y_ppi,
- x0, y0, x1, y1,
- function_id);
-
- _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_radial_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->base);
-
- cairo_matrix_copy (&p2u, &pattern->base.base.matrix);
- cairo_matrix_invert (&p2u);
-
- x0 = pattern->center0.x;
- y0 = pattern->center0.y;
- r0 = pattern->radius0;
- cairo_matrix_transform_point (&p2u, &x0, &y0);
- x1 = pattern->center1.x;
- y1 = pattern->center1.y;
- r1 = pattern->radius1;
- cairo_matrix_transform_point (&p2u, &x1, &y1);
-
- /* FIXME: This is surely crack, but how should you scale a radius
- * in a non-orthogonal coordinate system? */
- cairo_matrix_transform_distance (&p2u, &r0, &r1);
-
- /* FIXME: There is a difference between the cairo gradient extend
- * semantics and PDF extend semantics. PDFs extend=false means
- * that nothing is painted outside the gradient boundaries,
- * whereas cairo takes this to mean that the end color is padded
- * to infinity. Setting extend=true in PDF gives the cairo default
- * behavoir, not yet sure how to implement the cairo mirror and
- * repeat behaviour. */
- pattern_id = _cairo_pdf_document_new_object (document);
- fprintf (file,
- "%d 0 obj\r\n"
- "<< /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 [ true true ]\r\n"
- " >>\r\n"
- ">>\r\n"
- "endobj\r\n",
- pattern_id,
- document->height_inches * document->y_ppi,
- x0, y0, r0, x1, y1, r1,
- function_id);
-
- _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_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
-{
- switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
- emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
- break;
-
- case CAIRO_PATTERN_SURFACE:
- emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
- break;
-
- case CAIRO_PATTERN_LINEAR:
- emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
- break;
-
- case CAIRO_PATTERN_RADIAL:
- emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
- break;
- }
-}
-
-static double
-intersect (cairo_line_t *line, cairo_fixed_t y)
-{
- 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_pattern_t *pattern,
- void *abstract_dst,
- int x_src,
- int y_src,
- int x_dst,
- int y_dst,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_pdf_surface_t *surface = abstract_dst;
- cairo_pdf_document_t *document = surface->document;
- FILE *file = document->file;
- int i;
-
- emit_pattern (surface, pattern);
-
- /* After the above switch the current stream should belong to this
- * surface, so no need to _cairo_pdf_surface_ensure_stream() */
- 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_pdf_font_t *
-_cairo_pdf_document_get_font (cairo_pdf_document_t *document,
- cairo_font_t *font)
-{
- cairo_unscaled_font_t *unscaled_font;
- cairo_pdf_font_t *pdf_font;
- unsigned int num_fonts, i;
-
- unscaled_font = _cairo_ft_font_get_unscaled_font (font);
-
- num_fonts = _cairo_array_num_elements (&document->fonts);
- for (i = 0; i < num_fonts; i++) {
- _cairo_array_copy_element (&document->fonts, i, &pdf_font);
- if (pdf_font->unscaled_font == unscaled_font)
- return pdf_font;
- }
-
- /* FIXME: Figure out here which font backend is in use and call
- * the appropriate constructor. */
- pdf_font = cairo_pdf_ft_font_create (document, unscaled_font);
- if (pdf_font == NULL)
- return NULL;
-
- if (_cairo_array_append (&document->fonts, &pdf_font, 1) == NULL) {
- cairo_pdf_font_destroy (pdf_font);
- return NULL;
- }
-
- return pdf_font;
-}
-
-static cairo_status_t
-_cairo_pdf_surface_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- 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);
- if (pdf_font == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- emit_pattern (surface, pattern);
-
- fprintf (file, "BT /res%u 1 Tf", pdf_font->font_id);
- for (i = 0; i < num_glyphs; i++) {
-
- index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index);
-
- fprintf (file,
- " %f %f %f %f %f %f Tm (\\%o) Tj",
- font->scale.matrix[0][0],
- font->scale.matrix[0][1],
- font->scale.matrix[1][0],
- -font->scale.matrix[1][1],
- glyphs[i].x,
- glyphs[i].y,
- index);
- }
- 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_acquire_source_image,
- _cairo_pdf_surface_release_source_image,
- _cairo_pdf_surface_acquire_dest_image,
- _cairo_pdf_surface_release_dest_image,
- _cairo_pdf_surface_clone_similar,
- _cairo_pdf_surface_composite,
- _cairo_pdf_surface_fill_rectangles,
- _cairo_pdf_surface_composite_trapezoids,
- _cairo_pdf_surface_copy_page,
- _cairo_pdf_surface_show_page,
- _cairo_pdf_surface_set_clip_region,
- _cairo_pdf_surface_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 /7%s\r\n"
- " /Flags 4\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_pen.c b/src/cairo_pen.c
deleted file mode 100644
index 6ecaa00b3..000000000
--- a/src/cairo_pen.c
+++ /dev/null
@@ -1,587 +0,0 @@
-/* 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@cworth.org>
- */
-
-#include "cairoint.h"
-
-static int
-_cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix);
-
-static void
-_cairo_pen_compute_slopes (cairo_pen_t *pen);
-
-static cairo_status_t
-_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon);
-
-cairo_status_t
-_cairo_pen_init_empty (cairo_pen_t *pen)
-{
- pen->radius = 0;
- pen->tolerance = 0;
- pen->vertices = NULL;
- pen->num_vertices = 0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
-{
- int i;
- int reflect;
- double det;
-
- if (pen->num_vertices) {
- /* XXX: It would be nice to notice that the pen is already properly constructed.
- However, this test would also have to account for possible changes in the transformation
- matrix.
- if (pen->radius == radius && pen->tolerance == tolerance)
- return CAIRO_STATUS_SUCCESS;
- */
- _cairo_pen_fini (pen);
- }
-
- pen->radius = radius;
- pen->tolerance = gstate->tolerance;
-
- _cairo_matrix_compute_determinant (&gstate->ctm, &det);
- if (det >= 0) {
- reflect = 0;
- } else {
- reflect = 1;
- }
-
- pen->num_vertices = _cairo_pen_vertices_needed (gstate->tolerance,
- radius,
- &gstate->ctm);
-
- pen->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
- if (pen->vertices == NULL) {
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- /*
- * Compute pen coordinates. To generate the right ellipse, compute points around
- * a circle in user space and transform them to device space. To get a consistent
- * orientation in device space, flip the pen if the transformation matrix
- * is reflecting
- */
- for (i=0; i < pen->num_vertices; i++) {
- double theta = 2 * M_PI * i / (double) pen->num_vertices;
- double dx = radius * cos (reflect ? -theta : theta);
- double dy = radius * sin (reflect ? -theta : theta);
- cairo_pen_vertex_t *v = &pen->vertices[i];
- cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
- v->point.x = _cairo_fixed_from_double (dx);
- v->point.y = _cairo_fixed_from_double (dy);
- }
-
- _cairo_pen_compute_slopes (pen);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_pen_fini (cairo_pen_t *pen)
-{
- free (pen->vertices);
- pen->vertices = NULL;
-
- _cairo_pen_init_empty (pen);
-}
-
-cairo_status_t
-_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
-{
- *pen = *other;
-
- if (pen->num_vertices) {
- pen->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
- if (pen->vertices == NULL) {
- return CAIRO_STATUS_NO_MEMORY;
- }
- memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t));
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
-{
- cairo_pen_vertex_t *vertices;
- int num_vertices;
- int i;
-
- num_vertices = pen->num_vertices + num_points;
- vertices = realloc (pen->vertices, num_vertices * sizeof (cairo_pen_vertex_t));
- if (vertices == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- pen->vertices = vertices;
- pen->num_vertices = num_vertices;
-
- /* initialize new vertices */
- for (i=0; i < num_points; i++)
- pen->vertices[pen->num_vertices-num_points+i].point = point[i];
-
- _cairo_hull_compute (pen->vertices, &pen->num_vertices);
-
- _cairo_pen_compute_slopes (pen);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/*
-The circular pen in user space is transformed into an ellipse in
-device space.
-
-We construct the pen by computing points along the circumference
-using equally spaced angles.
-
-We show below that this approximation to the ellipse has
-maximum error at the major axis of the ellipse.
-So, we need to compute the length of the major axis and then
-use that to compute the number of sides needed in our pen.
-
-Thanks to Walter Brisken <wbrisken@aoc.nrao.edu> for this
-derivation:
-
-1. First some notation:
-
-All capital letters represent vectors in two dimensions. A prime '
-represents a transformed coordinate. Matrices are written in underlined
-form, ie _R_. Lowercase letters represent scalar real values.
-
-The letter t is used to represent the greek letter theta.
-
-2. The question has been posed: What is the maximum expansion factor
-achieved by the linear transformation
-
-X' = _R_ X
-
-where _R_ is a real-valued 2x2 matrix with entries:
-
-_R_ = [a b]
- [c d] .
-
-In other words, what is the maximum radius, MAX[ |X'| ], reached for any
-X on the unit circle ( |X| = 1 ) ?
-
-
-3. Some useful formulae
-
-(A) through (C) below are standard double-angle formulae. (D) is a lesser
-known result and is derived below:
-
-(A) sin^2(t) = (1 - cos(2*t))/2
-(B) cos^2(t) = (1 + cos(2*t))/2
-(C) sin(t)*cos(t) = sin(2*t)/2
-(D) MAX[a*cos(t) + b*sin(t)] = sqrt(a^2 + b^2)
-
-Proof of (D):
-
-find the maximum of the function by setting the derivative to zero:
-
- -a*sin(t)+b*cos(t) = 0
-
-From this it follows that
-
- tan(t) = b/a
-
-and hence
-
- sin(t) = b/sqrt(a^2 + b^2)
-
-and
-
- cos(t) = a/sqrt(a^2 + b^2)
-
-Thus the maximum value is
-
- MAX[a*cos(t) + b*sin(t)] = (a^2 + b^2)/sqrt(a^2 + b^2)
- = sqrt(a^2 + b^2)
-
-
-4. Derivation of maximum expansion
-
-To find MAX[ |X'| ] we search brute force method using calculus. The unit
-circle on which X is constrained is to be parameterized by t:
-
- X(t) = (cos(t), sin(t))
-
-Thus
-
- X'(t) = (a*cos(t) + b*sin(t), c*cos(t) + d*sin(t)) .
-
-Define
-
- r(t) = |X'(t)|
-
-Thus
-
- r^2(t) = (a*cos(t) + b*sin(t))^2 + (c*cos(t) + d*sin(t))^2
- = (a^2 + c^2)*cos^2(t) + (b^2 + d^2)*sin^2(t)
- + 2*(a*b + c*d)*cos(t)*sin(t)
-
-Now apply the double angle formulae (A) to (C) from above:
-
- r^2(t) = (a^2 + b^2 + c^2 + d^2)/2
- + (a^2 - b^2 + c^2 - d^2)*cos(2*t)/2
- + (a*b + c*d)*sin(2*t)
- = f + g*cos(u) + h*sin(u)
-
-Where
-
- f = (a^2 + b^2 + c^2 + d^2)/2
- g = (a^2 - b^2 + c^2 - d^2)/2
- h = (a*b + c*d)
- u = 2*t
-
-It is clear that MAX[ |X'| ] = sqrt(MAX[ r^2 ]). Here we determine MAX[ r^2 ]
-using (D) from above:
-
- MAX[ r^2 ] = f + sqrt(g^2 + h^2)
-
-And finally
-
- MAX[ |X'| ] = sqrt( f + sqrt(g^2 + h^2) )
-
-Which is the solution to this problem.
-
-
-Walter Brisken
-2004/10/08
-
-(Note that the minor axis length is at the minimum of the above solution,
-which is just sqrt (f - sqrt (g^2 + h^2)) given the symmetry of (D)).
-
-Now to compute how many sides to use for the pen formed by
-a regular polygon.
-
-Set
-
- M = major axis length (computed by above formula)
- m = minor axis length (computed by above formula)
-
-Align 'M' along the X axis and 'm' along the Y axis and draw
-an ellipse parameterized by angle 't':
-
- x = M cos t y = m sin t
-
-Perturb t by ± d and compute two new points (x+,y+), (x-,y-).
-The distance from the average of these two points to (x,y) represents
-the maximum error in approximating the ellipse with a polygon formed
-from vertices 2∆ radians apart.
-
- x+ = M cos (t+∆) y+ = m sin (t+∆)
- x- = M cos (t-∆) y- = m sin (t-∆)
-
-Now compute the approximation error, E:
-
- Ex = (x - (x+ + x-) / 2)
- Ex = (M cos(t) - (Mcos(t+∆) + Mcos(t-∆))/2)
- = M (cos(t) - (cos(t)cos(∆) + sin(t)sin(∆) +
- cos(t)cos(∆) - sin(t)sin(∆))/2)
- = M(cos(t) - cos(t)cos(∆))
- = M cos(t) (1 - cos(∆))
-
- Ey = y - (y+ - y-) / 2
- = m sin (t) - (m sin(t+∆) + m sin(t-∆)) / 2
- = m (sin(t) - (sin(t)cos(∆) + cos(t)sin(∆) +
- sin(t)cos(∆) - cos(t)sin(∆))/2)
- = m (sin(t) - sin(t)cos(∆))
- = m sin(t) (1 - cos(∆))
-
- E² = Ex² + Ey²
- = (M cos(t) (1 - cos (∆)))² + (m sin(t) (1-cos(∆)))²
- = (1 - cos(∆))² (M² cos²(t) + m² sin²(t))
- = (1 - cos(∆))² ((m² + M² - m²) cos² (t) + m² sin²(t))
- = (1 - cos(∆))² (M² - m²) cos² (t) + (1 - cos(∆))² m²
-
-Find the extremum by differentiation wrt t and setting that to zero
-
-∂(E²)/∂(t) = (1-cos(∆))² (M² - m²) (-2 cos(t) sin(t))
-
- 0 = 2 cos (t) sin (t)
- 0 = sin (2t)
- t = nπ
-
-Which is to say that the maximum and minimum errors occur on the
-axes of the ellipse at 0 and π radians:
-
- E²(0) = (1-cos(∆))² (M² - m²) + (1-cos(∆))² m²
- = (1-cos(∆))² M²
- E²(π) = (1-cos(∆))² m²
-
-maximum error = M (1-cos(∆))
-minimum error = m (1-cos(∆))
-
-We must make maximum error ≤ tolerance, so compute the ∆ needed:
-
- tolerance = M (1-cos(∆))
- tolerance / M = 1 - cos (∆)
- cos(∆) = 1 - tolerance/M
- ∆ = acos (1 - tolerance / M);
-
-Remembering that ∆ is half of our angle between vertices,
-the number of vertices is then
-
-vertices = ceil(2π/2∆).
- = ceil(π/∆).
-
-Note that this also equation works for M == m (a circle) as it
-doesn't matter where on the circle the error is computed.
-
-*/
-
-static int
-_cairo_pen_vertices_needed (double tolerance,
- double radius,
- cairo_matrix_t *matrix)
-{
- double a = matrix->m[0][0], c = matrix->m[0][1];
- double b = matrix->m[1][0], d = matrix->m[1][1];
-
- double i = a*a + c*c;
- double j = b*b + d*d;
-
- double f = 0.5 * (i + j);
- double g = 0.5 * (i - j);
- double h = a*b + c*d;
-
- /*
- * compute major and minor axes lengths for
- * a pen with the specified radius
- */
-
- double major_axis = radius * sqrt (f + sqrt (g*g+h*h));
-
- /*
- * we don't need the minor axis length, which is
- * double min = radius * sqrt (f - sqrt (g*g+h*h));
- */
-
- /*
- * compute number of vertices needed
- */
- int num_vertices;
-
- /* Where tolerance / M is > 1, we use 4 points */
- if (tolerance >= major_axis) {
- num_vertices = 4;
- } else {
- double delta = acos (1 - tolerance / major_axis);
- num_vertices = ceil (M_PI / delta);
-
- /* number of vertices must be even */
- if (num_vertices % 2)
- num_vertices++;
- }
- return num_vertices;
-}
-
-static void
-_cairo_pen_compute_slopes (cairo_pen_t *pen)
-{
- int i, i_prev;
- cairo_pen_vertex_t *prev, *v, *next;
-
- for (i=0, i_prev = pen->num_vertices - 1;
- i < pen->num_vertices;
- i_prev = i++) {
- prev = &pen->vertices[i_prev];
- v = &pen->vertices[i];
- next = &pen->vertices[(i + 1) % pen->num_vertices];
-
- _cairo_slope_init (&v->slope_cw, &prev->point, &v->point);
- _cairo_slope_init (&v->slope_ccw, &v->point, &next->point);
- }
-}
-/*
- * Find active pen vertex for clockwise edge of stroke at the given slope.
- *
- * NOTE: The behavior of this function is sensitive to the sense of
- * the inequality within _cairo_slope_clockwise/_cairo_slope_counter_clockwise.
- *
- * The issue is that the slope_ccw member of one pen vertex will be
- * equivalent to the slope_cw member of the next pen vertex in a
- * counterclockwise order. However, for this function, we care
- * strongly about which vertex is returned.
- */
-cairo_status_t
-_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
- cairo_slope_t *slope,
- int *active)
-{
- int i;
-
- for (i=0; i < pen->num_vertices; i++) {
- if (_cairo_slope_clockwise (slope, &pen->vertices[i].slope_ccw)
- && _cairo_slope_counter_clockwise (slope, &pen->vertices[i].slope_cw))
- break;
- }
-
- *active = i;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
- *
- * NOTE: The behavior of this function is sensitive to the sense of
- * the inequality within _cairo_slope_clockwise/_cairo_slope_counter_clockwise.
- */
-cairo_status_t
-_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
- cairo_slope_t *slope,
- int *active)
-{
- int i;
- cairo_slope_t slope_reverse;
-
- slope_reverse = *slope;
- slope_reverse.dx = -slope_reverse.dx;
- slope_reverse.dy = -slope_reverse.dy;
-
- for (i=pen->num_vertices-1; i >= 0; i--) {
- if (_cairo_slope_counter_clockwise (&pen->vertices[i].slope_ccw, &slope_reverse)
- && _cairo_slope_clockwise (&pen->vertices[i].slope_cw, &slope_reverse))
- break;
- }
-
- *active = i;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
- cairo_spline_t *spline,
- cairo_direction_t dir,
- cairo_polygon_t *polygon)
-{
- int i;
- cairo_status_t status;
- int start, stop, step;
- int active = 0;
- cairo_point_t hull_point;
- cairo_slope_t slope, initial_slope, final_slope;
- cairo_point_t *point = spline->points;
- int num_points = spline->num_points;
-
- if (dir == CAIRO_DIRECTION_FORWARD) {
- start = 0;
- stop = num_points;
- step = 1;
- initial_slope = spline->initial_slope;
- final_slope = spline->final_slope;
- } else {
- start = num_points - 1;
- stop = -1;
- step = -1;
- initial_slope = spline->final_slope;
- initial_slope.dx = -initial_slope.dx;
- initial_slope.dy = -initial_slope.dy;
- final_slope = spline->initial_slope;
- final_slope.dx = -final_slope.dx;
- final_slope.dy = -final_slope.dy;
- }
-
- _cairo_pen_find_active_cw_vertex_index (pen, &initial_slope, &active);
-
- i = start;
- while (i != stop) {
- hull_point.x = point[i].x + pen->vertices[active].point.x;
- hull_point.y = point[i].y + pen->vertices[active].point.y;
- status = _cairo_polygon_line_to (polygon, &hull_point);
- if (status)
- return status;
-
- if (i + step == stop)
- slope = final_slope;
- else
- _cairo_slope_init (&slope, &point[i], &point[i+step]);
- if (_cairo_slope_counter_clockwise (&slope, &pen->vertices[active].slope_ccw)) {
- if (++active == pen->num_vertices)
- active = 0;
- } else if (_cairo_slope_clockwise (&slope, &pen->vertices[active].slope_cw)) {
- if (--active == -1)
- active = pen->num_vertices - 1;
- } else {
- i += step;
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Compute outline of a given spline using the pen.
- The trapezoids needed to fill that outline will be added to traps
-*/
-cairo_status_t
-_cairo_pen_stroke_spline (cairo_pen_t *pen,
- cairo_spline_t *spline,
- double tolerance,
- cairo_traps_t *traps)
-{
- cairo_status_t status;
- cairo_polygon_t polygon;
-
- /* If the line width is so small that the pen is reduced to a
- single point, then we have nothing to do. */
- if (pen->num_vertices <= 1)
- return CAIRO_STATUS_SUCCESS;
-
- _cairo_polygon_init (&polygon);
-
- status = _cairo_spline_decompose (spline, tolerance);
- if (status)
- return status;
-
- status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_FORWARD, &polygon);
- if (status)
- return status;
-
- status = _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon);
- if (status)
- return status;
-
- _cairo_polygon_close (&polygon);
- _cairo_traps_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
- _cairo_polygon_fini (&polygon);
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c
deleted file mode 100644
index 1ae745cb5..000000000
--- a/src/cairo_png_surface.c
+++ /dev/null
@@ -1,425 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2004 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):
- * Olivier Andrieu <oliv__a@users.sourceforge.net>
- * Carl D. Worth <cworth@cworth.org>
- */
-
-#include <png.h>
-
-#include "cairoint.h"
-#include "cairo-png.h"
-
-static const cairo_surface_backend_t cairo_png_surface_backend;
-
-static cairo_int_status_t
-_cairo_png_surface_copy_page (void *abstract_surface);
-
-void
-cairo_set_target_png (cairo_t *cr,
- FILE *file,
- cairo_format_t format,
- int width,
- int height)
-{
- cairo_surface_t *surface;
-
- surface = cairo_png_surface_create (file, format,
- 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);
-}
-
-typedef struct cairo_png_surface {
- cairo_surface_t base;
-
- /* PNG-specific fields */
- cairo_image_surface_t *image;
- FILE *file;
- int copied;
-
- cairo_format_t format;
-
-} cairo_png_surface_t;
-
-
-static void
-_cairo_png_surface_erase (cairo_png_surface_t *surface);
-
-cairo_surface_t *
-cairo_png_surface_create (FILE *file,
- cairo_format_t format,
- int width,
- int height)
-{
- cairo_png_surface_t *surface;
-
- surface = malloc (sizeof (cairo_png_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init (&surface->base, &cairo_png_surface_backend);
-
- surface->image = (cairo_image_surface_t *)
- cairo_image_surface_create (format, width, height);
-
- if (surface->image == NULL) {
- free (surface);
- return NULL;
- }
-
- _cairo_png_surface_erase (surface);
-
- surface->file = file;
- surface->copied = 0;
-
- surface->format = format;
-
- return &surface->base;
-}
-
-
-static cairo_surface_t *
-_cairo_png_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- return NULL;
-}
-
-static void
-unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
-{
- int i;
-
- for (i = 0; i < row_info->rowbytes; i += 4) {
- unsigned char *b = &data[i];
- unsigned int pixel;
- unsigned char alpha;
-
- memcpy (&pixel, b, sizeof (unsigned int));
- alpha = (pixel & 0xff000000) >> 24;
- if (alpha == 0) {
- b[0] = b[1] = b[2] = b[3] = 0;
- } else {
- b[0] = (((pixel & 0x0000ff) >> 0) * 255) / alpha;
- b[1] = (((pixel & 0x00ff00) >> 8) * 255) / alpha;
- b[2] = (((pixel & 0xff0000) >> 16) * 255) / alpha;
- b[3] = alpha;
- }
- }
-}
-
-static void
-_cairo_png_surface_destroy (void *abstract_surface)
-{
- cairo_png_surface_t *surface = abstract_surface;
-
- if (! surface->copied)
- _cairo_png_surface_copy_page (surface);
-
- cairo_surface_destroy (&surface->image->base);
-
- free (surface);
-}
-
-static void
-_cairo_png_surface_erase (cairo_png_surface_t *surface)
-{
- cairo_color_t transparent;
-
- _cairo_color_init (&transparent);
- _cairo_color_set_rgb (&transparent, 0., 0., 0.);
- _cairo_color_set_alpha (&transparent, 0.);
- _cairo_surface_fill_rectangle (&surface->image->base,
- CAIRO_OPERATOR_SRC,
- &transparent,
- 0, 0,
- surface->image->width,
- surface->image->height);
-}
-
-static double
-_cairo_png_surface_pixels_per_inch (void *abstract_surface)
-{
- return 96.0;
-}
-
-static cairo_status_t
-_cairo_png_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_png_surface_t *surface = abstract_surface;
-
- *image_out = surface->image;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_png_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_png_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- cairo_png_surface_t *surface = abstract_surface;
-
- image_rect->x = 0;
- image_rect->y = 0;
- image_rect->width = surface->image->width;
- image_rect->height = surface->image->height;
-
- *image_out = surface->image;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_png_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_png_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_png_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src,
- cairo_pattern_t *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_png_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_png_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_png_surface_copy_page (void *abstract_surface)
-{
- int i;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_png_surface_t *surface = abstract_surface;
- png_struct *png;
- png_info *info;
- png_byte **rows;
- png_color_16 white;
- int png_color_type;
- int depth;
-
- rows = malloc (surface->image->height * sizeof(png_byte*));
- if (rows == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < surface->image->height; i++)
- rows[i] = surface->image->data + i * surface->image->stride;
-
- png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (png == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
-
- info = png_create_info_struct (png);
- if (info == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL2;
- }
-
- if (setjmp (png_jmpbuf (png))) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL2;
- }
-
- png_init_io (png, surface->file);
-
- switch (surface->format) {
- case CAIRO_FORMAT_ARGB32:
- depth = 8;
- png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- break;
- case CAIRO_FORMAT_RGB24:
- depth = 8;
- png_color_type = PNG_COLOR_TYPE_RGB;
- break;
- case CAIRO_FORMAT_A8:
- depth = 8;
- png_color_type = PNG_COLOR_TYPE_GRAY;
- break;
- case CAIRO_FORMAT_A1:
- depth = 1;
- png_color_type = PNG_COLOR_TYPE_GRAY;
- break;
- default:
- status = CAIRO_STATUS_NULL_POINTER;
- goto BAIL2;
- }
-
- png_set_IHDR (png, info,
- surface->image->width,
- surface->image->height, depth,
- png_color_type,
- PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT);
-
- white.red = 0xff;
- white.blue = 0xff;
- white.green = 0xff;
- png_set_bKGD (png, info, &white);
-
-/* XXX: Setting the time is interfereing with the image comparison
- png_convert_from_time_t (&png_time, time (NULL));
- png_set_tIME (png, info, &png_time);
-*/
-
- png_set_write_user_transform_fn (png, unpremultiply_data);
- if (surface->format == CAIRO_FORMAT_ARGB32 || surface->format == CAIRO_FORMAT_RGB24)
- png_set_bgr (png);
- if (surface->format == CAIRO_FORMAT_RGB24)
- png_set_filler (png, 0, PNG_FILLER_AFTER);
-
- png_write_info (png, info);
- png_write_image (png, rows);
- png_write_end (png, info);
-
- surface->copied = 1;
-
-BAIL2:
- png_destroy_write_struct (&png, &info);
-BAIL1:
- free (rows);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_png_surface_show_page (void *abstract_surface)
-{
- cairo_int_status_t status;
- cairo_png_surface_t *surface = abstract_surface;
-
- status = _cairo_png_surface_copy_page (surface);
- if (status)
- return status;
-
- _cairo_png_surface_erase (surface);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_png_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_png_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_clip_region (surface->image, region);
-}
-
-static const cairo_surface_backend_t cairo_png_surface_backend = {
- _cairo_png_surface_create_similar,
- _cairo_png_surface_destroy,
- _cairo_png_surface_pixels_per_inch,
- _cairo_png_surface_acquire_source_image,
- _cairo_png_surface_release_source_image,
- _cairo_png_surface_acquire_dest_image,
- _cairo_png_surface_release_dest_image,
- _cairo_png_surface_clone_similar,
- _cairo_png_surface_composite,
- _cairo_png_surface_fill_rectangles,
- _cairo_png_surface_composite_trapezoids,
- _cairo_png_surface_copy_page,
- _cairo_png_surface_show_page,
- _cairo_png_surface_set_clip_region,
- NULL /* show_glyphs */
-};
diff --git a/src/cairo_polygon.c b/src/cairo_polygon.c
deleted file mode 100644
index 59c615da2..000000000
--- a/src/cairo_polygon.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/* 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@cworth.org>
- */
-
-#include <stdlib.h>
-#include "cairoint.h"
-
-/* private functions */
-
-static cairo_status_t
-_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional);
-
-void
-_cairo_polygon_init (cairo_polygon_t *polygon)
-{
- polygon->num_edges = 0;
-
- polygon->edges_size = 0;
- polygon->edges = NULL;
-
- polygon->has_current_point = 0;
-}
-
-void
-_cairo_polygon_fini (cairo_polygon_t *polygon)
-{
- if (polygon->edges_size) {
- free (polygon->edges);
- polygon->edges = NULL;
- polygon->edges_size = 0;
- polygon->num_edges = 0;
- }
-
- polygon->has_current_point = 0;
-}
-
-static cairo_status_t
-_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional)
-{
- cairo_edge_t *new_edges;
- int old_size = polygon->edges_size;
- int new_size = polygon->num_edges + additional;
-
- if (new_size <= polygon->edges_size) {
- return CAIRO_STATUS_SUCCESS;
- }
-
- polygon->edges_size = new_size;
- new_edges = realloc (polygon->edges, polygon->edges_size * sizeof (cairo_edge_t));
-
- if (new_edges == NULL) {
- polygon->edges_size = old_size;
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- polygon->edges = new_edges;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2)
-{
- cairo_status_t status;
- cairo_edge_t *edge;
-
- /* drop horizontal edges */
- if (p1->y == p2->y) {
- goto DONE;
- }
-
- if (polygon->num_edges >= polygon->edges_size) {
- int additional = polygon->edges_size ? polygon->edges_size : 16;
- status = _cairo_polygon_grow_by (polygon, additional);
- if (status) {
- return status;
- }
- }
-
- edge = &polygon->edges[polygon->num_edges];
- if (p1->y < p2->y) {
- edge->edge.p1 = *p1;
- edge->edge.p2 = *p2;
- edge->clockWise = 1;
- } else {
- edge->edge.p1 = *p2;
- edge->edge.p2 = *p1;
- edge->clockWise = 0;
- }
-
- polygon->num_edges++;
-
- DONE:
- _cairo_polygon_move_to (polygon, p2);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point)
-{
- if (! polygon->has_current_point)
- polygon->first_point = *point;
- polygon->current_point = *point;
- polygon->has_current_point = 1;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- if (polygon->has_current_point) {
- status = _cairo_polygon_add_edge (polygon, &polygon->current_point, point);
- } else {
- _cairo_polygon_move_to (polygon, point);
- }
-
- return status;
-}
-
-cairo_status_t
-_cairo_polygon_close (cairo_polygon_t *polygon)
-{
- cairo_status_t status;
-
- if (polygon->has_current_point) {
- status = _cairo_polygon_add_edge (polygon,
- &polygon->current_point,
- &polygon->first_point);
- if (status)
- return status;
-
- polygon->has_current_point = 0;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c
deleted file mode 100644
index 4a45fc679..000000000
--- a/src/cairo_ps_surface.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * 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
- * 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@cworth.org>
- */
-
-#include "cairoint.h"
-#include "cairo-ps.h"
-
-#include <time.h>
-#include <zlib.h>
-
-static const cairo_surface_backend_t cairo_ps_surface_backend;
-
-/**
- * cairo_set_target_ps:
- * @cr: a #cairo_t
- * @file: an open, writeable file
- * @width_inches: width of the output page, in inches
- * @height_inches: height of the output page, in inches
- * @x_pixels_per_inch: X resolution to use for image fallbacks;
- * not all Cairo drawing can be represented in a postscript
- * file, so Cairo will write out images for some portions
- * of the output.
- * @y_pixels_per_inch: Y resolution to use for image fallbacks.
- *
- * Directs output for a #cairo_t to a postscript file. The file must
- * be kept open until the #cairo_t is destroyed or set to have a
- * different target, and then must be closed by the application.
- **/
-void
-cairo_set_target_ps (cairo_t *cr,
- FILE *file,
- double width_inches,
- double height_inches,
- double x_pixels_per_inch,
- double y_pixels_per_inch)
-{
- cairo_surface_t *surface;
-
- surface = cairo_ps_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);
-}
-
-typedef struct cairo_ps_surface {
- cairo_surface_t base;
-
- /* PS-specific fields */
- FILE *file;
-
- double width_inches;
- double height_inches;
- double x_ppi;
- double y_ppi;
-
- int pages;
-
- cairo_image_surface_t *image;
-} cairo_ps_surface_t;
-
-static void
-_cairo_ps_surface_erase (cairo_ps_surface_t *surface);
-
-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)
-{
- cairo_ps_surface_t *surface;
- int width, height;
- time_t now = time (0);
-
- surface = malloc (sizeof (cairo_ps_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init (&surface->base, &cairo_ps_surface_backend);
-
- surface->file = file;
-
- surface->width_inches = width_inches;
- surface->height_inches = height_inches;
- surface->x_ppi = x_pixels_per_inch;
- surface->y_ppi = x_pixels_per_inch;
-
- surface->pages = 0;
-
- width = (int) (x_pixels_per_inch * width_inches + 1.0);
- height = (int) (y_pixels_per_inch * height_inches + 1.0);
-
- surface->image = (cairo_image_surface_t *)
- cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
- if (surface->image == NULL) {
- free (surface);
- return NULL;
- }
-
- _cairo_ps_surface_erase (surface);
-
- /* Document header */
- fprintf (file,
- "%%!PS-Adobe-3.0\n"
- "%%%%Creator: Cairo (http://cairographics.org)\n");
- fprintf (file,
- "%%%%CreationDate: %s",
- ctime (&now));
- 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 */
- fprintf (file,
- "%%%%DocumentData: Clean7Bit\n"
- "%%%%LanguageLevel: 3\n");
- fprintf (file,
- "%%%%Orientation: Portrait\n"
- "%%%%EndComments\n");
-
- return &surface->base;
-}
-
-static cairo_surface_t *
-_cairo_ps_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- return NULL;
-}
-
-static void
-_cairo_ps_surface_destroy (void *abstract_surface)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- /* Document footer */
- fprintf (surface->file, "%%%%EOF\n");
-
- cairo_surface_destroy (&surface->image->base);
-
- free (surface);
-}
-
-static void
-_cairo_ps_surface_erase (cairo_ps_surface_t *surface)
-{
- cairo_color_t transparent;
-
- _cairo_color_init (&transparent);
- _cairo_color_set_rgb (&transparent, 0., 0., 0.);
- _cairo_color_set_alpha (&transparent, 0.);
- _cairo_surface_fill_rectangle (&surface->image->base,
- CAIRO_OPERATOR_SRC,
- &transparent,
- 0, 0,
- surface->image->width,
- surface->image->height);
-}
-
-/* XXX: We should re-work this interface to return both X/Y ppi values. */
-static double
-_cairo_ps_surface_pixels_per_inch (void *abstract_surface)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- return surface->y_ppi;
-}
-
-static cairo_status_t
-_cairo_ps_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- *image_out = surface->image;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_ps_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_ps_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- image_rect->x = 0;
- image_rect->y = 0;
- image_rect->width = surface->image->width;
- image_rect->height = surface->image->height;
-
- *image_out = surface->image;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_ps_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_ps_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src,
- cairo_pattern_t *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_ps_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_ps_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *generic_src,
- void *abstract_dst,
- int x_src,
- int y_src,
- int x_dst,
- int y_dst,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_copy_page (void *abstract_surface)
-{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_ps_surface_t *surface = abstract_surface;
- int width = surface->image->width;
- int height = surface->image->height;
- FILE *file = surface->file;
-
- int i, x, y;
-
- cairo_solid_pattern_t white_pattern;
- char *rgb, *compressed;
- long rgb_size, compressed_size;
-
- rgb_size = 3 * width * height;
- rgb = malloc (rgb_size);
- if (rgb == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL0;
- }
-
- compressed_size = (int) (1.0 + 1.1 * rgb_size);
- compressed = malloc (compressed_size);
- if (compressed == NULL) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
-
- /* PostScript can not represent the alpha channel, so we blend the
- current image over a white RGB surface to eliminate it. */
-
- _cairo_pattern_init_solid (&white_pattern, 1.0, 1.0, 1.0);
-
- _cairo_surface_composite (CAIRO_OPERATOR_OVER_REVERSE,
- &white_pattern.base,
- NULL,
- &surface->image->base,
- 0, 0,
- 0, 0,
- 0, 0,
- width, height);
-
- _cairo_pattern_fini (&white_pattern.base);
-
- i = 0;
- for (y = 0; y < height; y++) {
- pixman_bits_t *pixel = (pixman_bits_t *) (surface->image->data + y * surface->image->stride);
- for (x = 0; x < width; x++, pixel++) {
- rgb[i++] = (*pixel & 0x00ff0000) >> 16;
- rgb[i++] = (*pixel & 0x0000ff00) >> 8;
- rgb[i++] = (*pixel & 0x000000ff) >> 0;
- }
- }
-
- compress (compressed, &compressed_size, rgb, rgb_size);
-
- /* Page header */
- fprintf (file, "%%%%Page: %d\n", ++surface->pages);
-
- fprintf (file, "gsave\n");
-
- /* Image header goop */
- fprintf (file, "%g %g translate\n", 0.0, surface->height_inches * 72.0);
- fprintf (file, "%g %g scale\n", 72.0 / surface->x_ppi, 72.0 / surface->y_ppi);
- fprintf (file, "/DeviceRGB setcolorspace\n");
- fprintf (file, "<<\n");
- fprintf (file, " /ImageType 1\n");
- fprintf (file, " /Width %d\n", width);
- fprintf (file, " /Height %d\n", height);
- fprintf (file, " /BitsPerComponent 8\n");
- fprintf (file, " /Decode [ 0 1 0 1 0 1 ]\n");
- fprintf (file, " /DataSource currentfile /FlateDecode filter\n");
- fprintf (file, " /ImageMatrix [ 1 0 0 -1 0 1 ]\n");
- fprintf (file, ">>\n");
- fprintf (file, "image\n");
-
- /* Compressed image data */
- fwrite (compressed, 1, compressed_size, file);
-
- fprintf (file, "showpage\n");
-
- fprintf (file, "grestore\n");
-
- /* Page footer */
- fprintf (file, "%%%%EndPage\n");
-
- free (compressed);
- BAIL1:
- free (rgb);
- BAIL0:
- return status;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_show_page (void *abstract_surface)
-{
- cairo_int_status_t status;
- cairo_ps_surface_t *surface = abstract_surface;
-
- status = _cairo_ps_surface_copy_page (surface);
- if (status)
- return status;
-
- _cairo_ps_surface_erase (surface);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_ps_surface_t *surface = abstract_surface;
-
- return _cairo_image_surface_set_clip_region (surface->image, region);
-}
-
-static const cairo_surface_backend_t cairo_ps_surface_backend = {
- _cairo_ps_surface_create_similar,
- _cairo_ps_surface_destroy,
- _cairo_ps_surface_pixels_per_inch,
- _cairo_ps_surface_acquire_source_image,
- _cairo_ps_surface_release_source_image,
- _cairo_ps_surface_acquire_dest_image,
- _cairo_ps_surface_release_dest_image,
- _cairo_ps_surface_clone_similar,
- _cairo_ps_surface_composite,
- _cairo_ps_surface_fill_rectangles,
- _cairo_ps_surface_composite_trapezoids,
- _cairo_ps_surface_copy_page,
- _cairo_ps_surface_show_page,
- _cairo_ps_surface_set_clip_region,
- NULL /* show_glyphs */
-};
diff --git a/src/cairo_quartz_surface.c b/src/cairo_quartz_surface.c
deleted file mode 100644
index 01b345cdc..000000000
--- a/src/cairo_quartz_surface.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/* 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_slope.c b/src/cairo_slope.c
deleted file mode 100644
index a2edec038..000000000
--- a/src/cairo_slope.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/* 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@cworth.org>
- */
-
-#include "cairoint.h"
-
-void
-_cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b)
-{
- slope->dx = b->x - a->x;
- slope->dy = b->y - a->y;
-}
-
-/* Compare two slopes. Slope angles begin at 0 in the direction of the
- positive X axis and increase in the direction of the positive Y
- axis.
-
- WARNING: This function only gives correct results if the angular
- difference between a and b is less than PI.
-
- < 0 => a less positive than b
- == 0 => a equal to be
- > 0 => a more positive than b
-*/
-int
-_cairo_slope_compare (cairo_slope_t *a, cairo_slope_t *b)
-{
- cairo_fixed_48_16_t diff;
-
- diff = ((cairo_fixed_48_16_t) a->dy * (cairo_fixed_48_16_t) b->dx
- - (cairo_fixed_48_16_t) b->dy * (cairo_fixed_48_16_t) a->dx);
-
- if (diff > 0)
- return 1;
- if (diff < 0)
- return -1;
-
- if (a->dx == 0 && a->dy == 0)
- return 1;
- if (b->dx == 0 && b->dy ==0)
- return -1;
-
- return 0;
-}
-
-/* XXX: It might be cleaner to move away from usage of
- _cairo_slope_clockwise/_cairo_slope_counter_clockwise in favor of
- directly using _cairo_slope_compare.
-*/
-
-/* Is a clockwise of b?
- *
- * NOTE: The strict equality here is not significant in and of itself,
- * but there are functions up above that are sensitive to it,
- * (cf. _cairo_pen_find_active_cw_vertex_index).
- */
-int
-_cairo_slope_clockwise (cairo_slope_t *a, cairo_slope_t *b)
-{
- return _cairo_slope_compare (a, b) < 0;
-}
-
-int
-_cairo_slope_counter_clockwise (cairo_slope_t *a, cairo_slope_t *b)
-{
- return ! _cairo_slope_clockwise (a, b);
-}
-
-
-
-
diff --git a/src/cairo_spline.c b/src/cairo_spline.c
deleted file mode 100644
index 5119a8e2b..000000000
--- a/src/cairo_spline.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/* 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@cworth.org>
- */
-
-#include "cairoint.h"
-
-static cairo_status_t
-_cairo_spline_grow_by (cairo_spline_t *spline, int additional);
-
-static cairo_status_t
-_cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point);
-
-static void
-_lerp_half (cairo_point_t *a, cairo_point_t *b, cairo_point_t *result);
-
-static void
-_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2);
-
-static double
-_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);
-
-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)
-{
- spline->a = *a;
- spline->b = *b;
- spline->c = *c;
- spline->d = *d;
-
- if (a->x != b->x || a->y != b->y) {
- _cairo_slope_init (&spline->initial_slope, &spline->a, &spline->b);
- } else if (a->x != c->x || a->y != c->y) {
- _cairo_slope_init (&spline->initial_slope, &spline->a, &spline->c);
- } else if (a->x != d->x || a->y != d->y) {
- _cairo_slope_init (&spline->initial_slope, &spline->a, &spline->d);
- } else {
- return CAIRO_INT_STATUS_DEGENERATE;
- }
-
- if (c->x != d->x || c->y != d->y) {
- _cairo_slope_init (&spline->final_slope, &spline->c, &spline->d);
- } else if (b->x != d->x || b->y != d->y) {
- _cairo_slope_init (&spline->final_slope, &spline->b, &spline->d);
- } else {
- _cairo_slope_init (&spline->final_slope, &spline->a, &spline->d);
- }
-
- spline->num_points = 0;
- spline->points_size = 0;
- spline->points = NULL;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_spline_fini (cairo_spline_t *spline)
-{
- spline->num_points = 0;
- spline->points_size = 0;
- free (spline->points);
- spline->points = NULL;
-}
-
-static cairo_status_t
-_cairo_spline_grow_by (cairo_spline_t *spline, int additional)
-{
- cairo_point_t *new_points;
- int old_size = spline->points_size;
- int new_size = spline->num_points + additional;
-
- if (new_size <= spline->points_size)
- return CAIRO_STATUS_SUCCESS;
-
- spline->points_size = new_size;
- new_points = realloc (spline->points, spline->points_size * sizeof (cairo_point_t));
-
- if (new_points == NULL) {
- spline->points_size = old_size;
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- spline->points = new_points;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point)
-{
- cairo_status_t status;
- cairo_point_t *prev;
-
- if (spline->num_points) {
- prev = &spline->points[spline->num_points - 1];
- if (prev->x == point->x && prev->y == point->y)
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (spline->num_points >= spline->points_size) {
- int additional = spline->points_size ? spline->points_size : 32;
- status = _cairo_spline_grow_by (spline, additional);
- if (status)
- return status;
- }
-
- spline->points[spline->num_points] = *point;
- spline->num_points++;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_lerp_half (cairo_point_t *a, cairo_point_t *b, cairo_point_t *result)
-{
- result->x = a->x + ((b->x - a->x) >> 1);
- result->y = a->y + ((b->y - a->y) >> 1);
-}
-
-static void
-_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2)
-{
- cairo_point_t ab, bc, cd;
- cairo_point_t abbc, bccd;
- cairo_point_t final;
-
- _lerp_half (&spline->a, &spline->b, &ab);
- _lerp_half (&spline->b, &spline->c, &bc);
- _lerp_half (&spline->c, &spline->d, &cd);
- _lerp_half (&ab, &bc, &abbc);
- _lerp_half (&bc, &cd, &bccd);
- _lerp_half (&abbc, &bccd, &final);
-
- s1->a = spline->a;
- s1->b = ab;
- s1->c = abbc;
- s1->d = final;
-
- s2->a = final;
- s2->b = bccd;
- s2->c = cd;
- s2->d = spline->d;
-}
-
-static double
-_PointDistanceSquaredToPoint (cairo_point_t *a, cairo_point_t *b)
-{
- double dx = _cairo_fixed_to_double (b->x - a->x);
- double dy = _cairo_fixed_to_double (b->y - a->y);
-
- return dx*dx + dy*dy;
-}
-
-static double
-_PointDistanceSquaredToSegment (cairo_point_t *p, cairo_point_t *p1, cairo_point_t *p2)
-{
- double u;
- double dx, dy;
- double pdx, pdy;
- cairo_point_t px;
-
- /* intersection point (px):
-
- px = p1 + u(p2 - p1)
- (p - px) . (p2 - p1) = 0
-
- Thus:
-
- u = ((p - p1) . (p2 - p1)) / (||(p2 - p1)|| ^ 2);
- */
-
- dx = _cairo_fixed_to_double (p2->x - p1->x);
- dy = _cairo_fixed_to_double (p2->y - p1->y);
-
- if (dx == 0 && dy == 0)
- return _PointDistanceSquaredToPoint (p, p1);
-
- pdx = _cairo_fixed_to_double (p->x - p1->x);
- pdy = _cairo_fixed_to_double (p->y - p1->y);
-
- u = (pdx * dx + pdy * dy) / (dx*dx + dy*dy);
-
- if (u <= 0)
- return _PointDistanceSquaredToPoint (p, p1);
- else if (u >= 1)
- return _PointDistanceSquaredToPoint (p, p2);
-
- px.x = p1->x + u * (p2->x - p1->x);
- px.y = p1->y + u * (p2->y - p1->y);
-
- return _PointDistanceSquaredToPoint (p, &px);
-}
-
-/* Return an upper bound on the error (squared) that could result from approximating
- a spline as a line segment connecting the two endpoints */
-static double
-_cairo_spline_error_squared (cairo_spline_t *spline)
-{
- double berr, cerr;
-
- berr = _PointDistanceSquaredToSegment (&spline->b, &spline->a, &spline->d);
- cerr = _PointDistanceSquaredToSegment (&spline->c, &spline->a, &spline->d);
-
- if (berr > cerr)
- return berr;
- else
- return cerr;
-}
-
-static cairo_status_t
-_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result)
-{
- cairo_status_t status;
- cairo_spline_t s1, s2;
-
- if (_cairo_spline_error_squared (spline) < tolerance_squared) {
- return _cairo_spline_add_point (result, &spline->a);
- }
-
- _de_casteljau (spline, &s1, &s2);
-
- status = _cairo_spline_decompose_into (&s1, tolerance_squared, result);
- if (status)
- return status;
-
- status = _cairo_spline_decompose_into (&s2, tolerance_squared, result);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_spline_decompose (cairo_spline_t *spline, double tolerance)
-{
- cairo_status_t status;
-
- if (spline->points_size) {
- _cairo_spline_fini (spline);
- }
-
- status = _cairo_spline_decompose_into (spline, tolerance * tolerance, spline);
- if (status)
- return status;
-
- status = _cairo_spline_add_point (spline, &spline->d);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
diff --git a/src/cairo_surface.c b/src/cairo_surface.c
deleted file mode 100644
index 330d58b1e..000000000
--- a/src/cairo_surface.c
+++ /dev/null
@@ -1,708 +0,0 @@
-/* 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@cworth.org>
- */
-
-#include <stdlib.h>
-
-#include "cairoint.h"
-
-void
-_cairo_surface_init (cairo_surface_t *surface,
- const cairo_surface_backend_t *backend)
-{
- surface->backend = backend;
-
- surface->ref_count = 1;
-
- _cairo_matrix_init (&surface->matrix);
- surface->filter = CAIRO_FILTER_NEAREST;
- surface->repeat = 0;
-}
-
-cairo_surface_t *
-cairo_surface_create_for_image (char *data,
- cairo_format_t format,
- int width,
- int height,
- int stride)
-{
- return cairo_image_surface_create_for_data (data, format, width, height, stride);
-}
-slim_hidden_def(cairo_surface_create_for_image);
-
-cairo_surface_t *
-_cairo_surface_create_similar_scratch (cairo_surface_t *other,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- if (other == NULL)
- return NULL;
-
- return other->backend->create_similar (other, format, drawable,
- width, height);
-}
-
-cairo_surface_t *
-cairo_surface_create_similar (cairo_surface_t *other,
- cairo_format_t format,
- int width,
- int height)
-{
- cairo_color_t empty;
-
- if (other == NULL)
- return NULL;
-
- _cairo_color_init (&empty);
- _cairo_color_set_rgb (&empty, 0., 0., 0.);
- _cairo_color_set_alpha (&empty, 0.);
-
- return _cairo_surface_create_similar_solid (other, format, width, height, &empty);
-}
-
-cairo_surface_t *
-_cairo_surface_create_similar_solid (cairo_surface_t *other,
- cairo_format_t format,
- int width,
- int height,
- cairo_color_t *color)
-{
- cairo_status_t status;
- cairo_surface_t *surface;
-
- surface = _cairo_surface_create_similar_scratch (other, format, 1,
- width, height);
-
- if (surface == NULL)
- surface = cairo_image_surface_create (format, width, height);
-
- status = _cairo_surface_fill_rectangle (surface,
- CAIRO_OPERATOR_SRC, color,
- 0, 0, width, height);
- if (status) {
- cairo_surface_destroy (surface);
- return NULL;
- }
-
- return surface;
-}
-
-void
-cairo_surface_reference (cairo_surface_t *surface)
-{
- if (surface == NULL)
- return;
-
- surface->ref_count++;
-}
-
-void
-cairo_surface_destroy (cairo_surface_t *surface)
-{
- if (surface == NULL)
- return;
-
- surface->ref_count--;
- if (surface->ref_count)
- return;
-
- if (surface->backend->destroy)
- surface->backend->destroy (surface);
-}
-slim_hidden_def(cairo_surface_destroy);
-
-double
-_cairo_surface_pixels_per_inch (cairo_surface_t *surface)
-{
- return surface->backend->pixels_per_inch (surface);
-}
-
-/**
- * _cairo_surface_acquire_source_image:
- * @surface: a #cairo_surface_t
- * @image_out: location to store a pointer to an image surface that includes at least
- * the intersection of @interest_rect with the visible area of @surface.
- * This surface could be @surface itself, a surface held internal to @surface,
- * or it could be a new surface with a copy of the relevant portion of @surface.
- * @image_extra: location to store image specific backend data
- *
- * Gets an image surface to use when drawing as a fallback when drawing with
- * @surface as a source. _cairo_surface_release_source_image() must be called
- * when finished.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if a an image was stored in @image_out.
- * %CAIRO_INT_STATUS_UNSUPPORTED if an image cannot be retrieved for the specified
- * surface. Or %CAIRO_STATUS_NO_MEMORY.
- **/
-cairo_private cairo_status_t
-_cairo_surface_acquire_source_image (cairo_surface_t *surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- return surface->backend->acquire_source_image (surface, image_out, image_extra);
-}
-
-/**
- * _cairo_surface_release_source_image:
- * @surface: a #cairo_surface_t
- * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image()
- *
- * Releases any resources obtained with _cairo_surface_acquire_source_image()
- **/
-cairo_private void
-_cairo_surface_release_source_image (cairo_surface_t *surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- surface->backend->release_source_image (surface, image, image_extra);
-}
-
-/**
- * _cairo_surface_acquire_dest_image:
- * @surface: a #cairo_surface_t
- * @interest_rect: area of @surface for which fallback drawing is being done.
- * A value of %NULL indicates that the entire surface is desired.
- * @image_out: location to store a pointer to an image surface that includes at least
- * the intersection of @interest_rect with the visible area of @surface.
- * This surface could be @surface itself, a surface held internal to @surface,
- * or it could be a new surface with a copy of the relevant portion of @surface.
- * @image_rect: location to store area of the original surface occupied
- * by the surface stored in @image.
- * @image_extra: location to store image specific backend data
- *
- * Retrieves a local image for a surface for implementing a fallback drawing
- * operation. After calling this function, the implementation of the fallback
- * drawing operation draws the primitive to the surface stored in @image_out
- * then calls _cairo_surface_release_dest_fallback(),
- * which, if a temporary surface was created, copies the bits back to the
- * main surface and frees the temporary surface.
- *
- * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY.
- * %CAIRO_INT_STATUS_UNSUPPORTED can be returned but this will mean that
- * the backend can't draw with fallbacks. It's possible for the routine
- * to store NULL in @local_out and return %CAIRO_STATUS_SUCCESS;
- * that indicates that no part of @interest_rect is visible, so no drawing
- * is necessary. _cairo_surface_release_dest_fallback() should not be called in that
- * case.
- **/
-cairo_status_t
-_cairo_surface_acquire_dest_image (cairo_surface_t *surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- return surface->backend->acquire_dest_image (surface, interest_rect,
- image_out, image_rect, image_extra);
-}
-
-/**
- * _cairo_surface_end_fallback:
- * @surface: a #cairo_surface_t
- * @interest_rect: same as passed to the matching _cairo_surface_acquire_dest_image()
- * @image: same as returned from the matching _cairo_surface_acquire_dest_image()
- * @image_rect: same as returned from the matching _cairo_surface_acquire_dest_image()
- * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image()
- *
- * Finishes the operation started with _cairo_surface_acquire_dest_image(), by, if
- * necessary, copying the image from @image back to @surface and freeing any
- * resources that were allocated.
- **/
-void
-_cairo_surface_release_dest_image (cairo_surface_t *surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
- surface->backend->release_dest_image (surface, interest_rect,
- image, image_rect, image_extra);
-}
-
-/**
- * _cairo_surface_clone_similar:
- * @surface: a #cairo_surface_t
- * @src: the source image
- * @clone_out: location to store a surface compatible with @surface
- * and with contents identical to @src. The caller must call
- * cairo_surface_destroy() on the result.
- *
- * Creates a surface with contents identical to @src but that
- * can be used efficiently with @surface. If @surface and @src are
- * already compatible then it may return a new reference to @src.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if a surface was created and stored
- * in @clone_out. Otherwise %CAIRO_INT_STATUS_UNSUPPORTED or another
- * error like %CAIRO_STATUS_NO_MEMORY.
- **/
-cairo_status_t
-_cairo_surface_clone_similar (cairo_surface_t *surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- cairo_status_t status;
- cairo_image_surface_t *image;
- void *image_extra;
-
- status = surface->backend->clone_similar (surface, src, clone_out);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
- if (status != CAIRO_STATUS_SUCCESS)
- return status;
-
- status = surface->backend->clone_similar (surface, &image->base, clone_out);
-
- /* If the above failed point, we could implement a full fallback
- * using acquire_dest_image, but that's going to be very
- * inefficient compared to a backend-specific implementation of
- * clone_similar() with an image source. So we don't bother
- */
-
- _cairo_surface_release_source_image (src, image, image_extra);
- return status;
-}
-
-cairo_status_t
-cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- return cairo_matrix_copy (&surface->matrix, matrix);
-}
-slim_hidden_def(cairo_surface_set_matrix);
-
-cairo_status_t
-cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- return cairo_matrix_copy (matrix, &surface->matrix);
-}
-slim_hidden_def(cairo_surface_get_matrix);
-
-cairo_status_t
-cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- surface->filter = filter;
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_filter_t
-cairo_surface_get_filter (cairo_surface_t *surface)
-{
- return surface->filter;
-}
-
-/* XXX: NYI
-cairo_status_t
-cairo_surface_clip_rectangle (cairo_surface_t *surface,
- int x, int y,
- int width, int height)
-{
-
-}
-*/
-
-/* XXX: NYI
-cairo_status_t
-cairo_surface_clip_restore (cairo_surface_t *surface);
-*/
-
-cairo_status_t
-cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
-{
- if (surface == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- surface->repeat = repeat;
-
- return CAIRO_STATUS_SUCCESS;
-}
-slim_hidden_def(cairo_surface_set_repeat);
-
-typedef struct {
- cairo_surface_t *dst;
- cairo_rectangle_t extents;
- cairo_image_surface_t *image;
- cairo_rectangle_t image_rect;
- void *image_extra;
-} fallback_state_t;
-
-static cairo_status_t
-_fallback_init (fallback_state_t *state,
- cairo_surface_t *dst,
- int x,
- int y,
- int width,
- int height)
-{
- state->extents.x = x;
- state->extents.y = y;
- state->extents.width = width;
- state->extents.height = height;
-
- state->dst = dst;
-
- return _cairo_surface_acquire_dest_image (dst, &state->extents,
- &state->image, &state->image_rect, &state->image_extra);
-}
-
-static void
-_fallback_cleanup (fallback_state_t *state)
-{
- _cairo_surface_release_dest_image (state->dst, &state->extents,
- state->image, &state->image_rect, state->image_extra);
-}
-
-static cairo_status_t
-_fallback_composite (cairo_operator_t operator,
- cairo_pattern_t *src,
- cairo_pattern_t *mask,
- cairo_surface_t *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- fallback_state_t state;
- cairo_status_t status;
-
- status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
- if (!CAIRO_OK (status) || !state.image)
- return status;
-
- state.image->base.backend->composite (operator, src, mask,
- &state.image->base,
- src_x, src_y, mask_x, mask_y,
- dst_x - state.image_rect.x,
- dst_y - state.image_rect.y,
- width, height);
-
- _fallback_cleanup (&state);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src,
- cairo_pattern_t *mask,
- cairo_surface_t *dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_int_status_t status;
-
- status = dst->backend->composite (operator,
- src, mask, dst,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- return _fallback_composite (operator,
- src, mask, dst,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
-}
-
-cairo_status_t
-_cairo_surface_fill_rectangle (cairo_surface_t *surface,
- cairo_operator_t operator,
- cairo_color_t *color,
- int x,
- int y,
- int width,
- int height)
-{
- cairo_rectangle_t rect;
-
- rect.x = x;
- rect.y = y;
- rect.width = width;
- rect.height = height;
-
- return _cairo_surface_fill_rectangles (surface, operator, color, &rect, 1);
-}
-
-static cairo_status_t
-_fallback_fill_rectangles (cairo_surface_t *surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- fallback_state_t state;
- cairo_rectangle_t *offset_rects = NULL;
- cairo_status_t status;
- int x1, y1, x2, y2;
- int i;
-
- if (num_rects <= 0)
- return CAIRO_STATUS_SUCCESS;
-
- /* Compute the bounds of the rectangles, so that we know what area of the
- * destination surface to fetch
- */
- x1 = rects[0].x;
- y1 = rects[0].y;
- x2 = rects[0].x + rects[0].width;
- y2 = rects[0].y + rects[0].height;
-
- for (i = 1; i < num_rects; i++) {
- if (rects[0].x < x1)
- x1 = rects[0].x;
- if (rects[0].y < y1)
- y1 = rects[0].y;
-
- if (rects[0].x + rects[0].width > x2)
- x2 = rects[0].x + rects[0].width;
- if (rects[0].y + rects[0].height > y2)
- y2 = rects[0].y + rects[0].height;
- }
-
- status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
- if (!CAIRO_OK (status) || !state.image)
- return status;
-
- /* If the fetched image isn't at 0,0, we need to offset the rectangles */
-
- if (state.image_rect.x != 0 || state.image_rect.y != 0) {
- offset_rects = malloc (sizeof (cairo_rectangle_t) * num_rects);
- if (!offset_rects) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- for (i = 0; i < num_rects; i++) {
- offset_rects[i].x = rects[i].x - state.image_rect.x;
- offset_rects[i].y = rects[i].y - state.image_rect.y;
- offset_rects[i].width = rects[i].width;
- offset_rects[i].height = rects[i].height;
- }
-
- rects = offset_rects;
- }
-
- state.image->base.backend->fill_rectangles (&state.image->base, operator, color,
- rects, num_rects);
-
- if (offset_rects)
- free (offset_rects);
-
- FAIL:
- _fallback_cleanup (&state);
-
- return status;
-}
-
-cairo_status_t
-_cairo_surface_fill_rectangles (cairo_surface_t *surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_int_status_t status;
-
- if (num_rects == 0)
- return CAIRO_STATUS_SUCCESS;
-
- status = surface->backend->fill_rectangles (surface,
- operator,
- color,
- rects, num_rects);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- return _fallback_fill_rectangles (surface, operator, color, rects, num_rects);
-}
-
-static cairo_status_t
-_fallback_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- fallback_state_t state;
- cairo_trapezoid_t *offset_traps = NULL;
- cairo_status_t status;
- int i;
-
- status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
- if (!CAIRO_OK (status) || !state.image)
- return status;
-
- /* If the destination image isn't at 0,0, we need to offset the trapezoids */
-
- if (state.image_rect.x != 0 || state.image_rect.y != 0) {
-
- cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x);
- cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y);
-
- offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
- if (!offset_traps) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL;
- }
-
- for (i = 0; i < num_traps; i++) {
- offset_traps[i].top = traps[i].top - yoff;
- offset_traps[i].bottom = traps[i].bottom - yoff;
- offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff;
- offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff;
- offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff;
- offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff;
- offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff;
- offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff;
- offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff;
- offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff;
- }
-
- traps = offset_traps;
- }
-
- state.image->base.backend->composite_trapezoids (operator, pattern,
- &state.image->base,
- src_x, src_y,
- dst_x - state.image_rect.x,
- dst_y - state.image_rect.y,
- width, height, traps, num_traps);
- if (offset_traps)
- free (offset_traps);
-
- FAIL:
- _fallback_cleanup (&state);
-
- return status;
-}
-
-
-cairo_status_t
-_cairo_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_int_status_t status;
-
- status = dst->backend->composite_trapezoids (operator,
- pattern, dst,
- src_x, src_y,
- dst_x, dst_y,
- width, height,
- traps, num_traps);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- return _fallback_composite_trapezoids (operator, pattern, dst,
- src_x, src_y,
- dst_x, dst_y,
- width, height,
- traps, num_traps);
-}
-
-cairo_status_t
-_cairo_surface_copy_page (cairo_surface_t *surface)
-{
- cairo_int_status_t status;
-
- status = surface->backend->copy_page (surface);
- /* It's fine if some backends just don't support this. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- return CAIRO_STATUS_SUCCESS;
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_surface_show_page (cairo_surface_t *surface)
-{
- cairo_int_status_t status;
-
- status = surface->backend->show_page (surface);
- /* It's fine if some backends just don't support this. */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- return CAIRO_STATUS_SUCCESS;
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region)
-{
- return surface->backend->set_clip_region (surface, region);
-}
diff --git a/src/cairo_traps.c b/src/cairo_traps.c
deleted file mode 100644
index 79c7e16b6..000000000
--- a/src/cairo_traps.c
+++ /dev/null
@@ -1,740 +0,0 @@
-/*
- * Copyright © 2002 Keith Packard
- *
- * 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>
- * Carl D. Worth <cworth@cworth.org>
- *
- * 2002-07-15: Converted from XRenderCompositeDoublePoly to cairo_trap. Carl D. Worth
- */
-
-#include "cairoint.h"
-
-/* private functions */
-
-static cairo_status_t
-_cairo_traps_grow_by (cairo_traps_t *traps, int additional);
-
-static cairo_status_t
-_cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
- cairo_line_t *left, cairo_line_t *right);
-
-static cairo_status_t
-_cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
- cairo_point_t left_p1, cairo_point_t left_p2,
- cairo_point_t right_p1, cairo_point_t right_p2);
-
-static int
-_compare_point_fixed_by_y (const void *av, const void *bv);
-
-static int
-_compare_cairo_edge_by_top (const void *av, const void *bv);
-
-static int
-_compare_cairo_edge_by_slope (const void *av, const void *bv);
-
-static cairo_fixed_16_16_t
-_compute_x (cairo_line_t *line, cairo_fixed_t y);
-
-static int
-_line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret);
-
-void
-_cairo_traps_init (cairo_traps_t *traps)
-{
- traps->num_traps = 0;
-
- traps->traps_size = 0;
- traps->traps = NULL;
- traps->extents.p1.x = traps->extents.p1.y = CAIRO_MAXSHORT << 16;
- traps->extents.p2.x = traps->extents.p2.y = CAIRO_MINSHORT << 16;
-}
-
-void
-_cairo_traps_fini (cairo_traps_t *traps)
-{
- if (traps->traps_size) {
- free (traps->traps);
- traps->traps = NULL;
- traps->traps_size = 0;
- traps->num_traps = 0;
- }
-}
-
-static cairo_status_t
-_cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
- cairo_line_t *left, cairo_line_t *right)
-{
- cairo_status_t status;
- cairo_trapezoid_t *trap;
-
- if (top == bottom) {
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (traps->num_traps >= traps->traps_size) {
- int inc = traps->traps_size ? traps->traps_size : 32;
- status = _cairo_traps_grow_by (traps, inc);
- if (status)
- return status;
- }
-
- trap = &traps->traps[traps->num_traps];
- trap->top = top;
- trap->bottom = bottom;
- trap->left = *left;
- trap->right = *right;
-
- if (top < traps->extents.p1.y)
- traps->extents.p1.y = top;
- if (bottom > traps->extents.p2.y)
- traps->extents.p2.y = bottom;
- /*
- * This isn't generally accurate, but it is close enough for
- * this purpose. Assuming that the left and right segments always
- * contain the trapezoid vertical extents, these compares will
- * yield a containing box. Assuming that the points all come from
- * the same figure which will eventually be completely drawn, then
- * the compares will yield the correct overall extents
- */
- if (left->p1.x < traps->extents.p1.x)
- traps->extents.p1.x = left->p1.x;
- if (left->p2.x < traps->extents.p1.x)
- traps->extents.p1.x = left->p2.x;
-
- if (right->p1.x > traps->extents.p2.x)
- traps->extents.p2.x = right->p1.x;
- if (right->p2.x > traps->extents.p2.x)
- traps->extents.p2.x = right->p2.x;
-
- traps->num_traps++;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_traps_add_trap_from_points (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bottom,
- cairo_point_t left_p1, cairo_point_t left_p2,
- cairo_point_t right_p1, cairo_point_t right_p2)
-{
- cairo_line_t left;
- cairo_line_t right;
-
- left.p1 = left_p1;
- left.p2 = left_p2;
-
- right.p1 = right_p1;
- right.p2 = right_p2;
-
- return _cairo_traps_add_trap (traps, top, bottom, &left, &right);
-}
-
-static cairo_status_t
-_cairo_traps_grow_by (cairo_traps_t *traps, int additional)
-{
- cairo_trapezoid_t *new_traps;
- int old_size = traps->traps_size;
- int new_size = traps->num_traps + additional;
-
- if (new_size <= traps->traps_size) {
- return CAIRO_STATUS_SUCCESS;
- }
-
- traps->traps_size = new_size;
- new_traps = realloc (traps->traps, traps->traps_size * sizeof (cairo_trapezoid_t));
-
- if (new_traps == NULL) {
- traps->traps_size = old_size;
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- traps->traps = new_traps;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static int
-_compare_point_fixed_by_y (const void *av, const void *bv)
-{
- const cairo_point_t *a = av, *b = bv;
-
- int ret = a->y - b->y;
- if (ret == 0) {
- ret = a->x - b->x;
- }
- return ret;
-}
-
-cairo_status_t
-_cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3])
-{
- cairo_status_t status;
- cairo_line_t line;
- cairo_fixed_16_16_t intersect;
- cairo_point_t tsort[3];
-
- memcpy (tsort, t, 3 * sizeof (cairo_point_t));
- qsort (tsort, 3, sizeof (cairo_point_t), _compare_point_fixed_by_y);
-
- /* horizontal top edge requires special handling */
- if (tsort[0].y == tsort[1].y) {
- if (tsort[0].x < tsort[1].x)
- status = _cairo_traps_add_trap_from_points (traps,
- tsort[1].y, tsort[2].y,
- tsort[0], tsort[2],
- tsort[1], tsort[2]);
- else
- status = _cairo_traps_add_trap_from_points (traps,
- tsort[1].y, tsort[2].y,
- tsort[1], tsort[2],
- tsort[0], tsort[2]);
- return status;
- }
-
- line.p1 = tsort[0];
- line.p2 = tsort[1];
-
- intersect = _compute_x (&line, tsort[2].y);
-
- if (intersect < tsort[2].x) {
- status = _cairo_traps_add_trap_from_points (traps,
- tsort[0].y, tsort[1].y,
- tsort[0], tsort[1],
- tsort[0], tsort[2]);
- if (status)
- return status;
- status = _cairo_traps_add_trap_from_points (traps,
- tsort[1].y, tsort[2].y,
- tsort[1], tsort[2],
- tsort[0], tsort[2]);
- if (status)
- return status;
- } else {
- status = _cairo_traps_add_trap_from_points (traps,
- tsort[0].y, tsort[1].y,
- tsort[0], tsort[2],
- tsort[0], tsort[1]);
- if (status)
- return status;
- status = _cairo_traps_add_trap_from_points (traps,
- tsort[1].y, tsort[2].y,
- tsort[0], tsort[2],
- tsort[1], tsort[2]);
- if (status)
- return status;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Warning: This function reorders the elements of the array provided. */
-cairo_status_t
-_cairo_traps_tessellate_rectangle (cairo_traps_t *traps, cairo_point_t q[4])
-{
- cairo_status_t status;
-
- qsort (q, 4, sizeof (cairo_point_t), _compare_point_fixed_by_y);
-
- if (q[1].x > q[2].x) {
- status = _cairo_traps_add_trap_from_points (traps,
- q[0].y, q[1].y, q[0], q[2], q[0], q[1]);
- if (status)
- return status;
- status = _cairo_traps_add_trap_from_points (traps,
- q[1].y, q[2].y, q[0], q[2], q[1], q[3]);
- if (status)
- return status;
- status = _cairo_traps_add_trap_from_points (traps,
- q[2].y, q[3].y, q[2], q[3], q[1], q[3]);
- if (status)
- return status;
- } else {
- status = _cairo_traps_add_trap_from_points (traps,
- q[0].y, q[1].y, q[0], q[1], q[0], q[2]);
- if (status)
- return status;
- status = _cairo_traps_add_trap_from_points (traps,
- q[1].y, q[2].y, q[1], q[3], q[0], q[2]);
- if (status)
- return status;
- status = _cairo_traps_add_trap_from_points (traps,
- q[2].y, q[3].y, q[1], q[3], q[2], q[3]);
- if (status)
- return status;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static int
-_compare_cairo_edge_by_top (const void *av, const void *bv)
-{
- const cairo_edge_t *a = av, *b = bv;
-
- return a->edge.p1.y - b->edge.p1.y;
-}
-
-/* Return value is:
- > 0 if a is "clockwise" from b, (in a mathematical, not a graphical sense)
- == 0 if slope (a) == slope (b)
- < 0 if a is "counter-clockwise" from b
-*/
-static int
-_compare_cairo_edge_by_slope (const void *av, const void *bv)
-{
- const cairo_edge_t *a = av, *b = bv;
- cairo_fixed_32_32_t d;
-
- cairo_fixed_48_16_t a_dx = a->edge.p2.x - a->edge.p1.x;
- cairo_fixed_48_16_t a_dy = a->edge.p2.y - a->edge.p1.y;
- cairo_fixed_48_16_t b_dx = b->edge.p2.x - b->edge.p1.x;
- cairo_fixed_48_16_t b_dy = b->edge.p2.y - b->edge.p1.y;
-
- d = b_dy * a_dx - a_dy * b_dx;
-
- if (d > 0)
- return 1;
- else if (d == 0)
- return 0;
- else
- return -1;
-}
-
-static int
-_compare_cairo_edge_by_current_x_slope (const void *av, const void *bv)
-{
- const cairo_edge_t *a = av, *b = bv;
- int ret;
-
- ret = a->current_x - b->current_x;
- if (ret == 0)
- ret = _compare_cairo_edge_by_slope (a, b);
- return ret;
-}
-
-/* XXX: Both _compute_x and _compute_inverse_slope will divide by zero
- for horizontal lines. Now, we "know" that when we are tessellating
- polygons that the polygon data structure discards all horizontal
- edges, but there's nothing here to guarantee that. I suggest the
- following:
-
- A) Move all of the polygon tessellation code out of xrtraps.c and
- into xrpoly.c, (in order to be in the same module as the code
- discarding horizontal lines).
-
- OR
-
- B) Re-implement the line intersection in a way that avoids all
- division by zero. Here's one approach. The only disadvantage
- might be that that there are not meaningful names for all of the
- sub-computations -- just a bunch of determinants. I haven't
- looked at complexity, (both are probably similar and it probably
- doesn't matter much anyway).
- */
-
-/* XXX: Keith's new intersection code is much cleaner, and uses
- * sufficient precision for correctly sorting intersections according
- * to the analysis in Hobby's paper.
- *
- * But, when we enable this code, some things are failing, (eg. the
- * stars in test/fill_rule get filled wrong). This could indicate a
- * bug in one of tree places:
- *
- * 1) The new intersection code in this file
- *
- * 2) cairo_wideint.c (which is only exercised here)
- *
- * 3) In the current tessellator, (where the old intersection
- * code, with its mystic increments could be masking the bug).
- *
- * It will likely be easier to revisit this when the new tessellation
- * code is in place. So, for now, we'll simply disable the new
- * intersection code.
- */
-
-#define CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE 0
-
-#if CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
-static const cairo_fixed_32_32_t
-_det16_32 (cairo_fixed_16_16_t a,
- cairo_fixed_16_16_t b,
- cairo_fixed_16_16_t c,
- cairo_fixed_16_16_t d)
-{
- return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),
- _cairo_int32x32_64_mul (b, c));
-}
-
-static const cairo_fixed_64_64_t
-_det32_64 (cairo_fixed_32_32_t a,
- cairo_fixed_32_32_t b,
- cairo_fixed_32_32_t c,
- cairo_fixed_32_32_t d)
-{
- return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d),
- _cairo_int64x64_128_mul (b, c));
-}
-
-static const cairo_fixed_32_32_t
-_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a)
-{
- return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16);
-}
-
-static int
-_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection)
-{
- cairo_fixed_16_16_t dx1, dx2, dy1, dy2;
- cairo_fixed_32_32_t den_det;
- cairo_fixed_32_32_t l1_det, l2_det;
- cairo_fixed_64_64_t num_det;
- cairo_fixed_32_32_t intersect_32_32;
- cairo_fixed_48_16_t intersect_48_16;
- cairo_fixed_16_16_t intersect_16_16;
- cairo_quorem128_t qr;
-
- dx1 = l1->p1.x - l1->p2.x;
- dy1 = l1->p1.y - l1->p2.y;
- dx2 = l2->p1.x - l2->p2.x;
- dy2 = l2->p1.y - l2->p2.y;
- den_det = _det16_32 (dx1, dy1,
- dx2, dy2);
-
- if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0)))
- return 0;
-
- l1_det = _det16_32 (l1->p1.x, l1->p1.y,
- l1->p2.x, l1->p2.y);
- l2_det = _det16_32 (l2->p1.x, l2->p1.y,
- l2->p2.x, l2->p2.y);
-
-
- num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1),
- l2_det, _fixed_16_16_to_fixed_32_32 (dy2));
-
- /*
- * Ok, this one is a bit tricky in fixed point, the denominator
- * needs to be left with 32-bits of fraction so that the
- * result of the divide ends up with 32-bits of fraction (64 - 32 = 32)
- */
- qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det));
-
- intersect_32_32 = _cairo_int128_to_int64 (qr.quo);
-
- /*
- * Find the ceiling of the quotient -- divrem returns
- * the quotient truncated towards zero, so if the
- * quotient should be positive (num_den and den_det have same sign)
- * bump the quotient up by one.
- */
-
- if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) &&
- (_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) ==
- _cairo_int64_ge (den_det, _cairo_int32_to_int64 (0))))
- {
- intersect_32_32 = _cairo_int64_add (intersect_32_32,
- _cairo_int32_to_int64 (1));
- }
-
- /*
- * Now convert from 32.32 to 48.16 and take the ceiling;
- * this requires adding in 15 1 bits and shifting the result
- */
-
- intersect_32_32 = _cairo_int64_add (intersect_32_32,
- _cairo_int32_to_int64 ((1 << 16) - 1));
- intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16);
-
- /*
- * And drop the top bits
- */
- intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16);
-
- *y_intersection = intersect_16_16;
-
- return 1;
-}
-#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
-
-static cairo_fixed_16_16_t
-_compute_x (cairo_line_t *line, cairo_fixed_t y)
-{
- cairo_fixed_16_16_t dx = line->p2.x - line->p1.x;
- cairo_fixed_32_32_t ex = (cairo_fixed_48_16_t) (y - line->p1.y) * (cairo_fixed_48_16_t) dx;
- cairo_fixed_16_16_t dy = line->p2.y - line->p1.y;
-
- return line->p1.x + (ex / dy);
-}
-
-#if ! CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE
-static double
-_compute_inverse_slope (cairo_line_t *l)
-{
- return (_cairo_fixed_to_double (l->p2.x - l->p1.x) /
- _cairo_fixed_to_double (l->p2.y - l->p1.y));
-}
-
-static double
-_compute_x_intercept (cairo_line_t *l, double inverse_slope)
-{
- return _cairo_fixed_to_double (l->p1.x) - inverse_slope * _cairo_fixed_to_double (l->p1.y);
-}
-
-static int
-_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ret)
-{
- /*
- * x = m1y + b1
- * x = m2y + b2
- * m1y + b1 = m2y + b2
- * y * (m1 - m2) = b2 - b1
- * y = (b2 - b1) / (m1 - m2)
- */
- cairo_fixed_16_16_t y_intersect;
- double m1 = _compute_inverse_slope (l1);
- double b1 = _compute_x_intercept (l1, m1);
- double m2 = _compute_inverse_slope (l2);
- double b2 = _compute_x_intercept (l2, m2);
-
- if (m1 == m2)
- return 0;
-
- y_intersect = _cairo_fixed_from_double ((b2 - b1) / (m1 - m2));
-
- if (m1 < m2) {
- cairo_line_t *t;
- t = l1;
- l1 = l2;
- l2 = t;
- }
-
- /* Assuming 56 bits of floating point precision, the intersection
- is accurate within one sub-pixel coordinate. We must ensure
- that we return a value that is at or after the intersection. At
- most, we must increment once. */
- if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
- y_intersect++;
- /* XXX: Hmm... Keith's error calculations said we'd at most be off
- by one sub-pixel. But, I found that the paint-fill-BE-01.svg
- test from the W3C SVG conformance suite definitely requires two
- increments.
-
- It could be that we need one to overcome the error, and another
- to round up.
-
- It would be nice to be sure this code is correct, (but we can't
- do the while loop as it will work for way to long on
- exceedingly distant intersections with large errors that we
- really don't care about anyway as they will be ignored by the
- calling function.
- */
- if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
- y_intersect++;
- /* XXX: hmm... now I found "intersection_killer" inside xrspline.c
- that requires 3 increments. Clearly, we haven't characterized
- this completely yet. */
- if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))
- y_intersect++;
- /* I think I've found the answer to our problems. The insight is
- that everytime we round we are changing the slopes of the
- relevant lines, so we may be introducing new intersections that
- we miss, so everything breaks apart. John Hobby wrote a paper
- on how to fix this:
-
- [Hobby93c] John D. Hobby, Practical Segment Intersection with
- Finite Precision Output, Computation Geometry Theory and
- Applications, 13(4), 1999.
-
- Available online (2003-08017):
-
- http://cm.bell-labs.com/cm/cs/doc/93/2-27.ps.gz
-
- Now we just need to go off and implement that.
- */
-
- *y_ret = y_intersect;
-
- return 1;
-}
-#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */
-
-/* The algorithm here is pretty simple:
-
- inactive = [edges]
- y = min_p1_y (inactive)
-
- while (num_active || num_inactive) {
- active = all edges containing y
-
- next_y = min ( min_p2_y (active), min_p1_y (inactive), min_intersection (active) )
-
- fill_traps (active, y, next_y, fill_rule)
-
- y = next_y
- }
-
- The invariants that hold during fill_traps are:
-
- All edges in active contain both y and next_y
- No edges in active intersect within y and next_y
-
- These invariants mean that fill_traps is as simple as sorting the
- active edges, forming a trapezoid between each adjacent pair. Then,
- either the even-odd or winding rule is used to determine whether to
- emit each of these trapezoids.
-
- Warning: This function obliterates the edges of the polygon provided.
-*/
-cairo_status_t
-_cairo_traps_tessellate_polygon (cairo_traps_t *traps,
- cairo_polygon_t *poly,
- cairo_fill_rule_t fill_rule)
-{
- cairo_status_t status;
- int i, active, inactive;
- cairo_fixed_t y, y_next, intersect;
- int in_out, num_edges = poly->num_edges;
- cairo_edge_t *edges = poly->edges;
-
- if (num_edges == 0)
- return CAIRO_STATUS_SUCCESS;
-
- qsort (edges, num_edges, sizeof (cairo_edge_t), _compare_cairo_edge_by_top);
-
- y = edges[0].edge.p1.y;
- active = 0;
- inactive = 0;
- while (active < num_edges) {
- while (inactive < num_edges && edges[inactive].edge.p1.y <= y)
- inactive++;
-
- for (i = active; i < inactive; i++)
- edges[i].current_x = _compute_x (&edges[i].edge, y);
-
- qsort (&edges[active], inactive - active,
- sizeof (cairo_edge_t), _compare_cairo_edge_by_current_x_slope);
-
- /* find next inflection point */
- y_next = edges[active].edge.p2.y;
-
- for (i = active; i < inactive; i++) {
- if (edges[i].edge.p2.y < y_next)
- y_next = edges[i].edge.p2.y;
- /* check intersect */
- if (i != inactive - 1 && edges[i].current_x != edges[i+1].current_x)
- if (_line_segs_intersect_ceil (&edges[i].edge, &edges[i+1].edge,
- &intersect))
- if (intersect > y && intersect < y_next)
- y_next = intersect;
- }
- /* check next inactive point */
- if (inactive < num_edges && edges[inactive].edge.p1.y < y_next)
- y_next = edges[inactive].edge.p1.y;
-
- /* walk the active edges generating trapezoids */
- in_out = 0;
- for (i = active; i < inactive - 1; i++) {
- if (fill_rule == CAIRO_FILL_RULE_WINDING) {
- if (edges[i].clockWise)
- in_out++;
- else
- in_out--;
- if (in_out == 0)
- continue;
- } else {
- in_out++;
- if ((in_out & 1) == 0)
- continue;
- }
- status = _cairo_traps_add_trap (traps, y, y_next, &edges[i].edge, &edges[i+1].edge);
- if (status)
- return status;
- }
-
- /* delete inactive edges */
- for (i = active; i < inactive; i++) {
- if (edges[i].edge.p2.y <= y_next) {
- memmove (&edges[active+1], &edges[active], (i - active) * sizeof (cairo_edge_t));
- active++;
- }
- }
-
- y = y_next;
- }
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_bool_t
-_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
-{
- cairo_slope_t slope_left, slope_pt, slope_right;
-
- if (t->top > pt->y)
- return FALSE;
- if (t->bottom < pt->y)
- return FALSE;
-
- _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);
- _cairo_slope_init (&slope_pt, &t->left.p1, pt);
-
- if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)
- return FALSE;
-
- _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);
- _cairo_slope_init (&slope_pt, &t->right.p1, pt);
-
- if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)
- return FALSE;
-
- return TRUE;
-}
-
-cairo_bool_t
-_cairo_traps_contain (cairo_traps_t *traps, double x, double y)
-{
- int i;
- cairo_point_t point;
-
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
-
- for (i = 0; i < traps->num_traps; i++) {
- if (_cairo_trap_contains (&traps->traps[i], &point))
- return TRUE;
- }
-
- return FALSE;
-}
-
-void
-_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
-{
- *extents = traps->extents;
-}
diff --git a/src/cairo_unicode.c b/src/cairo_unicode.c
deleted file mode 100644
index 92201391a..000000000
--- a/src/cairo_unicode.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/* cairo_unicode.c: Unicode conversion routines
- *
- * The code in this file is derived from GLib's gutf8.c and
- * ultimately from libunicode. It is relicensed under the
- * dual LGPL/MPL with permission of the original authors.
- *
- * Copyright © 1999 Tom Tromey
- * Copyright © 2005 Red Hat, Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is cairo_unicode.c as distributed with the
- * cairo graphics library.
- *
- * The Initial Developer of the Original Code is Tom Tromey.
- * and Red Hat, Inc.
- *
- * Contributor(s):
- * Owen Taylor <otaylor@redhat.com>
- */
-
-#include <limits.h>
-
-#include <cairoint.h>
-
-#define UTF8_COMPUTE(Char, Mask, Len) \
- if (Char < 128) \
- { \
- Len = 1; \
- Mask = 0x7f; \
- } \
- else if ((Char & 0xe0) == 0xc0) \
- { \
- Len = 2; \
- Mask = 0x1f; \
- } \
- else if ((Char & 0xf0) == 0xe0) \
- { \
- Len = 3; \
- Mask = 0x0f; \
- } \
- else if ((Char & 0xf8) == 0xf0) \
- { \
- Len = 4; \
- Mask = 0x07; \
- } \
- else if ((Char & 0xfc) == 0xf8) \
- { \
- Len = 5; \
- Mask = 0x03; \
- } \
- else if ((Char & 0xfe) == 0xfc) \
- { \
- Len = 6; \
- Mask = 0x01; \
- } \
- else \
- Len = -1;
-
-#define UTF8_LENGTH(Char) \
- ((Char) < 0x80 ? 1 : \
- ((Char) < 0x800 ? 2 : \
- ((Char) < 0x10000 ? 3 : \
- ((Char) < 0x200000 ? 4 : \
- ((Char) < 0x4000000 ? 5 : 6)))))
-
-
-#define UTF8_GET(Result, Chars, Count, Mask, Len) \
- (Result) = (Chars)[0] & (Mask); \
- for ((Count) = 1; (Count) < (Len); ++(Count)) \
- { \
- if (((Chars)[(Count)] & 0xc0) != 0x80) \
- { \
- (Result) = -1; \
- break; \
- } \
- (Result) <<= 6; \
- (Result) |= ((Chars)[(Count)] & 0x3f); \
- }
-
-#define UNICODE_VALID(Char) \
- ((Char) < 0x110000 && \
- (((Char) & 0xFFFFF800) != 0xD800) && \
- ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
- ((Char) & 0xFFFE) != 0xFFFE)
-
-
-static const char utf8_skip_data[256] = {
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
-};
-
-#define UTF8_NEXT_CHAR(p) (char *)((p) + utf8_skip_data[*(unsigned char *)(p)])
-
-/* Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
- * If @p does not point to a valid UTF-8 encoded character, results are
- * undefined.
- **/
-static uint32_t
-_utf8_get_char (const char *p)
-{
- int i, mask = 0, len;
- uint32_t result;
- unsigned char c = (unsigned char) *p;
-
- UTF8_COMPUTE (c, mask, len);
- if (len == -1)
- return (uint32_t)-1;
- UTF8_GET (result, p, i, mask, len);
-
- return result;
-}
-
-/* Like _utf8_get_char, but take a maximum length
- * and return (uint32_t)-2 on incomplete trailing character
- */
-static uint32_t
-_utf8_get_char_extended (const char *p,
- long max_len)
-{
- int i, len;
- uint32_t wc = (unsigned char) *p;
-
- if (wc < 0x80) {
- return wc;
- } else if (wc < 0xc0) {
- return (uint32_t)-1;
- } else if (wc < 0xe0) {
- len = 2;
- wc &= 0x1f;
- } else if (wc < 0xf0) {
- len = 3;
- wc &= 0x0f;
- } else if (wc < 0xf8) {
- len = 4;
- wc &= 0x07;
- } else if (wc < 0xfc) {
- len = 5;
- wc &= 0x03;
- } else if (wc < 0xfe) {
- len = 6;
- wc &= 0x01;
- } else {
- return (uint32_t)-1;
- }
-
- if (max_len >= 0 && len > max_len) {
- for (i = 1; i < max_len; i++) {
- if ((((unsigned char *)p)[i] & 0xc0) != 0x80)
- return (uint32_t)-1;
- }
- return (uint32_t)-2;
- }
-
- for (i = 1; i < len; ++i) {
- uint32_t ch = ((unsigned char *)p)[i];
-
- if ((ch & 0xc0) != 0x80) {
- if (ch)
- return (uint32_t)-1;
- else
- return (uint32_t)-2;
- }
-
- wc <<= 6;
- wc |= (ch & 0x3f);
- }
-
- if (UTF8_LENGTH(wc) != len)
- return (uint32_t)-1;
-
- return wc;
-}
-
-/**
- * _cairo_utf8_to_utf32:
- * @str: an UTF-8 string
- * @len: length of @str in bytes, or -1 if it is nul-terminated.
- * If @len is supplied and the string has an embedded nul
- * byte, only the portion before the nul byte is converted.
- * @result: location to store a pointer to a newly allocated UTF-32
- * string (always native endian). Free with free(). A 0
- * word will be written after the last character.
- * @items_written: location to store number of 32-bit words
- * written. (Not including the trailing 0)
- *
- * Converts a UTF-8 string to UCS-4. UCS-4 is an encoding of Unicode
- * with 1 32-bit word per character. The string is validated to
- * consist entirely of valid Unicode characters.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if the entire string was
- * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an
- * an invalid sequence was found.
- **/
-cairo_status_t
-_cairo_utf8_to_ucs4 (const char *str,
- int len,
- uint32_t **result,
- int *items_written)
-{
- uint32_t *str32 = NULL;
- int n_chars, i;
- const char *in;
-
- in = str;
- n_chars = 0;
- while ((len < 0 || str + len - in > 0) && *in)
- {
- uint32_t wc = _utf8_get_char_extended (in, str + len - in);
- if (wc & 0x80000000 || !UNICODE_VALID (wc))
- return CAIRO_STATUS_INVALID_STRING;
-
- n_chars++;
- if (n_chars == INT_MAX)
- return CAIRO_STATUS_INVALID_STRING;
-
- in = UTF8_NEXT_CHAR (in);
- }
-
- str32 = malloc (sizeof (uint32_t) * (n_chars + 1));
- if (!str32)
- return CAIRO_STATUS_NO_MEMORY;
-
- in = str;
- for (i=0; i < n_chars; i++) {
- str32[i] = _utf8_get_char (in);
- in = UTF8_NEXT_CHAR (in);
- }
- str32[i] = 0;
-
- *result = str32;
- if (items_written)
- *items_written = n_chars;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * _cairo_utf8_to_utf16:
- * @str: an UTF-8 string
- * @len: length of @str in bytes, or -1 if it is nul-terminated.
- * If @len is supplied and the string has an embedded nul
- * byte, only the portion before the nul byte is converted.
- * @result: location to store a pointer to a newly allocated UTF-16
- * string (always native endian). Free with free(). A 0
- * word will be written after the last character.
- * @items_written: location to store number of 16-bit words
- * written. (Not including the trailing 0)
- *
- * Converts a UTF-8 string to UTF-16. UTF-16 is an encoding of Unicode
- * where characters are represented either as a single 16-bit word, or
- * as a pair of 16-bit "surrogates". The string is validated to
- * consist entirely of valid Unicode characters.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if the entire string was
- * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an
- * an invalid sequence was found.
- **/
-cairo_status_t
-_cairo_utf8_to_utf16 (const char *str,
- int len,
- uint16_t **result,
- int *items_written)
-{
- uint16_t *str16 = NULL;
- int n16, i;
- const char *in;
-
- in = str;
- n16 = 0;
- while ((len < 0 || str + len - in > 0) && *in) {
- uint32_t wc = _utf8_get_char_extended (in, str + len - in);
- if (wc & 0x80000000 || !UNICODE_VALID (wc))
- return CAIRO_STATUS_INVALID_STRING;
-
- if (wc < 0x10000)
- n16 += 1;
- else
- n16 += 2;
-
- if (n16 == INT_MAX - 1 || n16 == INT_MAX)
- return CAIRO_STATUS_INVALID_STRING;
-
- in = UTF8_NEXT_CHAR (in);
- }
-
-
- str16 = malloc (sizeof (uint16_t) * (n16 + 1));
- if (!str16)
- return CAIRO_STATUS_NO_MEMORY;
-
- in = str;
- for (i = 0; i < n16;) {
- uint32_t wc = _utf8_get_char (in);
-
- if (wc < 0x10000) {
- str16[i++] = wc;
- } else {
- str16[i++] = (wc - 0x10000) / 0x400 + 0xd800;
- str16[i++] = (wc - 0x10000) % 0x400 + 0xdc00;
- }
-
- in = UTF8_NEXT_CHAR (in);
- }
-
- str16[i] = 0;
-
- *result = str16;
- if (items_written)
- *items_written = n16;
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo_wideint.c b/src/cairo_wideint.c
deleted file mode 100644
index b636dface..000000000
--- a/src/cairo_wideint.c
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- * $Id: cairo_wideint.c,v 1.4 2005-01-19 15:07:00 cworth Exp $
- *
- * Copyright © 2004 Keith Packard
- *
- * 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>
- */
-
-#include "cairoint.h"
-
-#if !HAVE_UINT64_T || !HAVE_UINT128_T
-
-static const unsigned char top_bit[256] =
-{
- 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
-};
-
-#endif
-
-#if HAVE_UINT64_T
-
-#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l))
-
-cairo_uquorem64_t
-_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
-{
- cairo_uquorem64_t qr;
-
- qr.quo = num / den;
- qr.rem = num % den;
- return qr;
-}
-
-#else
-
-cairo_uint64_t
-_cairo_uint32_to_uint64 (uint32_t i)
-{
- cairo_uint64_t q;
-
- q.lo = i;
- q.hi = 0;
- return q;
-}
-
-cairo_int64_t
-_cairo_int32_to_int64 (int32_t i)
-{
- cairo_uint64_t q;
-
- q.lo = i;
- q.hi = i < 0 ? -1 : 0;
- return q;
-}
-
-static const cairo_uint64_t
-_cairo_uint32s_to_uint64 (uint32_t h, uint32_t l)
-{
- cairo_uint64_t q;
-
- q.lo = l;
- q.hi = h;
- return q;
-}
-
-cairo_uint64_t
-_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b)
-{
- cairo_uint64_t s;
-
- s.hi = a.hi + b.hi;
- s.lo = a.lo + b.lo;
- if (s.lo < a.lo)
- s.hi++;
- return s;
-}
-
-cairo_uint64_t
-_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b)
-{
- cairo_uint64_t s;
-
- s.hi = a.hi - b.hi;
- s.lo = a.lo - b.lo;
- if (s.lo > a.lo)
- s.hi--;
- return s;
-}
-
-#define uint32_lo(i) ((i) & 0xffff)
-#define uint32_hi(i) ((i) >> 16)
-#define uint32_carry16 ((1) << 16)
-
-cairo_uint64_t
-_cairo_uint32x32_64_mul (uint32_t a, uint32_t b)
-{
- cairo_uint64_t s;
-
- uint16_t ah, al, bh, bl;
- uint32_t r0, r1, r2, r3;
-
- al = uint32_lo (a);
- ah = uint32_hi (a);
- bl = uint32_lo (b);
- bh = uint32_hi (b);
-
- r0 = (uint32_t) al * bl;
- r1 = (uint32_t) al * bh;
- r2 = (uint32_t) ah * bl;
- r3 = (uint32_t) ah * bh;
-
- r1 += uint32_hi(r0); /* no carry possible */
- r1 += r2; /* but this can carry */
- if (r1 < r2) /* check */
- r3 += uint32_carry16;
-
- s.hi = r3 + uint32_hi(r1);
- s.lo = (uint32_lo (r1) << 16) + uint32_lo (r0);
- return s;
-}
-
-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;
-
- s = _cairo_uint32x32_64_mul (a.lo, b.lo);
- s.hi += a.lo * b.hi + a.hi * b.lo;
- return s;
-}
-
-cairo_uint64_t
-_cairo_uint64_lsl (cairo_uint64_t a, int shift)
-{
- if (shift >= 32)
- {
- a.hi = a.lo;
- a.lo = 0;
- shift -= 32;
- }
- if (shift)
- {
- a.hi = a.hi << shift | a.lo >> (32 - shift);
- a.lo = a.lo << shift;
- }
- return a;
-}
-
-cairo_uint64_t
-_cairo_uint64_rsl (cairo_uint64_t a, int shift)
-{
- if (shift >= 32)
- {
- a.lo = a.hi;
- a.hi = 0;
- shift -= 32;
- }
- if (shift)
- {
- a.lo = a.lo >> shift | a.hi << (32 - shift);
- a.hi = a.hi >> shift;
- }
- return a;
-}
-
-#define _cairo_uint32_rsa(a,n) ((uint32_t) (((int32_t) (a)) >> (n)))
-
-cairo_int64_t
-_cairo_uint64_rsa (cairo_int64_t a, int shift)
-{
- if (shift >= 32)
- {
- a.lo = a.hi;
- a.hi = _cairo_uint32_rsa (a.hi, 31);
- shift -= 32;
- }
- if (shift)
- {
- a.lo = a.lo >> shift | a.hi << (32 - shift);
- a.hi = _cairo_uint32_rsa (a.hi, shift);
- }
- return a;
-}
-
-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));
-}
-
-int
-_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b)
-{
- return a.hi == b.hi && a.lo == b.lo;
-}
-
-int
-_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b)
-{
- if (_cairo_int64_negative (a) && !_cairo_int64_negative (b))
- return 1;
- if (!_cairo_int64_negative (a) && _cairo_int64_negative (b))
- return 0;
- return _cairo_uint64_lt (a, b);
-}
-
-cairo_uint64_t
-_cairo_uint64_not (cairo_uint64_t a)
-{
- a.lo = ~a.lo;
- a.hi = ~a.hi;
- return a;
-}
-
-cairo_uint64_t
-_cairo_uint64_negate (cairo_uint64_t a)
-{
- a.lo = ~a.lo;
- a.hi = ~a.hi;
- if (++a.lo == 0)
- ++a.hi;
- return a;
-}
-
-/*
- * The design of this algorithm comes from GCC,
- * but the actual implementation is new
- */
-
-static const int
-_cairo_leading_zeros32 (uint32_t i)
-{
- int top;
-
- if (i < 0x100)
- top = 0;
- else if (i < 0x10000)
- top = 8;
- else if (i < 0x1000000)
- top = 16;
- else
- top = 24;
- top = top + top_bit [i >> top];
- return 32 - top;
-}
-
-typedef struct _cairo_uquorem32_t {
- uint32_t quo;
- uint32_t rem;
-} cairo_uquorem32_t;
-
-/*
- * den >= num.hi
- */
-static const cairo_uquorem32_t
-_cairo_uint64x32_normalized_divrem (cairo_uint64_t num, uint32_t den)
-{
- cairo_uquorem32_t qr;
- uint32_t q0, q1, r0, r1;
- uint16_t d0, d1;
- uint32_t t;
-
- d0 = den & 0xffff;
- d1 = den >> 16;
-
- q1 = num.hi / d1;
- r1 = num.hi % d1;
-
- t = q1 * d0;
- r1 = (r1 << 16) | (num.lo >> 16);
- if (r1 < t)
- {
- q1--;
- r1 += den;
- if (r1 >= den && r1 < t)
- {
- q1--;
- r1 += den;
- }
- }
-
- r1 -= t;
-
- q0 = r1 / d1;
- r0 = r1 % d1;
- t = q0 * d0;
- r0 = (r0 << 16) | (num.lo & 0xffff);
- if (r0 < t)
- {
- q0--;
- r0 += den;
- if (r0 >= den && r0 < t)
- {
- q0--;
- r0 += den;
- }
- }
- r0 -= t;
- qr.quo = (q1 << 16) | q0;
- qr.rem = r0;
- return qr;
-}
-
-cairo_uquorem64_t
-_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den)
-{
- cairo_uquorem32_t qr32;
- cairo_uquorem64_t qr;
- int norm;
- uint32_t q1, q0, r1, r0;
-
- if (den.hi == 0)
- {
- if (den.lo > num.hi)
- {
- /* 0q = nn / 0d */
-
- norm = _cairo_leading_zeros32 (den.lo);
- if (norm)
- {
- den.lo <<= norm;
- num = _cairo_uint64_lsl (num, norm);
- }
- q1 = 0;
- }
- else
- {
- /* qq = NN / 0d */
-
- if (den.lo == 0)
- den.lo = 1 / den.lo;
-
- norm = _cairo_leading_zeros32 (den.lo);
- if (norm)
- {
- cairo_uint64_t num1;
- den.lo <<= norm;
- num1 = _cairo_uint64_rsl (num, 32 - norm);
- qr32 = _cairo_uint64x32_normalized_divrem (num1, den.lo);
- q1 = qr32.quo;
- num.hi = qr32.rem;
- num.lo <<= norm;
- }
- else
- {
- num.hi -= den.lo;
- q1 = 1;
- }
- }
- qr32 = _cairo_uint64x32_normalized_divrem (num, den.lo);
- q0 = qr32.quo;
- r1 = 0;
- r0 = qr32.rem >> norm;
- }
- else
- {
- if (den.hi > num.hi)
- {
- /* 00 = nn / DD */
- q0 = q1 = 0;
- r0 = num.lo;
- r1 = num.hi;
- }
- else
- {
- /* 0q = NN / dd */
-
- norm = _cairo_leading_zeros32 (den.hi);
- if (norm == 0)
- {
- if (num.hi > den.hi || num.lo >= den.lo)
- {
- q0 = 1;
- num = _cairo_uint64_sub (num, den);
- }
- else
- q0 = 0;
-
- q1 = 0;
- r0 = num.lo;
- r1 = num.hi;
- }
- else
- {
- cairo_uint64_t num1;
- cairo_uint64_t part;
-
- num1 = _cairo_uint64_rsl (num, 32 - norm);
- den = _cairo_uint64_lsl (den, norm);
-
- qr32 = _cairo_uint64x32_normalized_divrem (num1, den.hi);
- part = _cairo_uint32x32_64_mul (qr32.quo, den.lo);
-
- q0 = qr32.quo;
-
- num.lo <<= norm;
- num.hi = qr32.rem;
-
- if (_cairo_uint64_gt (part, num))
- {
- q0--;
- part = _cairo_uint64_sub (part, den);
- }
-
- q1 = 0;
-
- num = _cairo_uint64_sub (num, part);
- num = _cairo_uint64_rsl (num, norm);
- r0 = num.lo;
- r1 = num.hi;
- }
- }
- }
- qr.quo.lo = q0;
- qr.quo.hi = q1;
- qr.rem.lo = r0;
- qr.rem.hi = r1;
- return qr;
-}
-
-#endif /* !HAVE_UINT64_T */
-
-cairo_quorem64_t
-_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den)
-{
- int num_neg = _cairo_int64_negative (num);
- int den_neg = _cairo_int64_negative (den);
- cairo_uquorem64_t uqr;
- cairo_quorem64_t qr;
-
- if (num_neg)
- num = _cairo_int64_negate (num);
- if (den_neg)
- den = _cairo_int64_negate (den);
- uqr = _cairo_uint64_divrem (num, den);
- if (num_neg)
- qr.rem = _cairo_int64_negate (uqr.rem);
- else
- qr.rem = uqr.rem;
- if (num_neg != den_neg)
- qr.quo = (cairo_int64_t) _cairo_int64_negate (uqr.quo);
- else
- qr.quo = (cairo_int64_t) uqr.quo;
- return qr;
-}
-
-#if HAVE_UINT128_T
-
-cairo_uquorem128_t
-_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
-{
- cairo_uquorem128_t qr;
-
- qr.quo = num / den;
- qr.rem = num % den;
- return qr;
-}
-
-#else
-
-cairo_uint128_t
-_cairo_uint32_to_uint128 (uint32_t i)
-{
- cairo_uint128_t q;
-
- q.lo = _cairo_uint32_to_uint64 (i);
- q.hi = _cairo_uint32_to_uint64 (0);
- return q;
-}
-
-cairo_int128_t
-_cairo_int32_to_int128 (int32_t i)
-{
- cairo_int128_t q;
-
- q.lo = _cairo_int32_to_int64 (i);
- q.hi = _cairo_int32_to_int64 (i < 0 ? -1 : 0);
- return q;
-}
-
-cairo_uint128_t
-_cairo_uint64_to_uint128 (cairo_uint64_t i)
-{
- cairo_uint128_t q;
-
- q.lo = i;
- q.hi = _cairo_uint32_to_uint64 (0);
- return q;
-}
-
-cairo_int128_t
-_cairo_int64_to_int128 (cairo_int64_t i)
-{
- cairo_int128_t q;
-
- q.lo = i;
- q.hi = _cairo_int32_to_int64 (_cairo_int64_negative(i) ? -1 : 0);
- return q;
-}
-
-cairo_uint128_t
-_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b)
-{
- cairo_uint128_t s;
-
- s.hi = _cairo_uint64_add (a.hi, b.hi);
- s.lo = _cairo_uint64_add (a.lo, b.lo);
- if (_cairo_uint64_lt (s.lo, a.lo))
- s.hi = _cairo_uint64_add (s.hi, _cairo_uint32_to_uint64 (1));
- return s;
-}
-
-cairo_uint128_t
-_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b)
-{
- cairo_uint128_t s;
-
- s.hi = _cairo_uint64_sub (a.hi, b.hi);
- s.lo = _cairo_uint64_sub (a.lo, b.lo);
- if (_cairo_uint64_gt (s.lo, a.lo))
- s.hi = _cairo_uint64_sub (s.hi, _cairo_uint32_to_uint64(1));
- return s;
-}
-
-#if HAVE_UINT64_T
-
-#define uint64_lo32(i) ((i) & 0xffffffff)
-#define uint64_hi32(i) ((i) >> 32)
-#define uint64_lo(i) ((i) & 0xffffffff)
-#define uint64_hi(i) ((i) >> 32)
-#define uint64_shift32(i) ((i) << 32)
-#define uint64_carry32 (((uint64_t) 1) << 32)
-
-#else
-
-#define uint64_lo32(i) ((i).lo)
-#define uint64_hi32(i) ((i).hi)
-
-static const cairo_uint64_t
-uint64_lo (cairo_uint64_t i)
-{
- cairo_uint64_t s;
-
- s.lo = i.lo;
- s.hi = 0;
- return s;
-}
-
-static const cairo_uint64_t
-uint64_hi (cairo_uint64_t i)
-{
- cairo_uint64_t s;
-
- s.lo = i.hi;
- s.hi = 0;
- return s;
-}
-
-static const cairo_uint64_t
-uint64_shift32 (cairo_uint64_t i)
-{
- cairo_uint64_t s;
-
- s.lo = 0;
- s.hi = i.lo;
- return s;
-}
-
-static const cairo_uint64_t uint64_carry32 = { 0, 1 };
-
-#endif
-
-cairo_uint128_t
-_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b)
-{
- cairo_uint128_t s;
- uint32_t ah, al, bh, bl;
- cairo_uint64_t r0, r1, r2, r3;
-
- al = uint64_lo32 (a);
- ah = uint64_hi32 (a);
- bl = uint64_lo32 (b);
- bh = uint64_hi32 (b);
-
- r0 = _cairo_uint32x32_64_mul (al, bl);
- r1 = _cairo_uint32x32_64_mul (al, bh);
- r2 = _cairo_uint32x32_64_mul (ah, bl);
- r3 = _cairo_uint32x32_64_mul (ah, bh);
-
- r1 = _cairo_uint64_add (r1, uint64_hi (r0)); /* no carry possible */
- r1 = _cairo_uint64_add (r1, r2); /* but this can carry */
- if (_cairo_uint64_lt (r1, r2)) /* check */
- r3 = _cairo_uint64_add (r3, uint64_carry32);
-
- s.hi = _cairo_uint64_add (r3, uint64_hi(r1));
- s.lo = _cairo_uint64_add (uint64_shift32 (r1),
- uint64_lo (r0));
- return s;
-}
-
-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;
-
- s = _cairo_uint64x64_128_mul (a.lo, b.lo);
- s.hi = _cairo_uint64_add (s.hi,
- _cairo_uint64_mul (a.lo, b.hi));
- s.hi = _cairo_uint64_add (s.hi,
- _cairo_uint64_mul (a.hi, b.lo));
- return s;
-}
-
-cairo_uint128_t
-_cairo_uint128_lsl (cairo_uint128_t a, int shift)
-{
- if (shift >= 64)
- {
- a.hi = a.lo;
- a.lo = _cairo_uint32_to_uint64 (0);
- shift -= 64;
- }
- if (shift)
- {
- a.hi = _cairo_uint64_add (_cairo_uint64_lsl (a.hi, shift),
- _cairo_uint64_rsl (a.lo, (64 - shift)));
- a.lo = _cairo_uint64_lsl (a.lo, shift);
- }
- return a;
-}
-
-cairo_uint128_t
-_cairo_uint128_rsl (cairo_uint128_t a, int shift)
-{
- if (shift >= 64)
- {
- a.lo = a.hi;
- a.hi = _cairo_uint32_to_uint64 (0);
- shift -= 64;
- }
- if (shift)
- {
- a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
- _cairo_uint64_lsl (a.hi, (64 - shift)));
- a.hi = _cairo_uint64_rsl (a.hi, shift);
- }
- return a;
-}
-
-cairo_uint128_t
-_cairo_uint128_rsa (cairo_int128_t a, int shift)
-{
- if (shift >= 64)
- {
- a.lo = a.hi;
- a.hi = _cairo_uint64_rsa (a.hi, 64-1);
- shift -= 64;
- }
- if (shift)
- {
- a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift),
- _cairo_uint64_lsl (a.hi, (64 - shift)));
- a.hi = _cairo_uint64_rsa (a.hi, shift);
- }
- return a;
-}
-
-int
-_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b)
-{
- return (_cairo_uint64_lt (a.hi, b.hi) ||
- (_cairo_uint64_eq (a.hi, b.hi) &&
- _cairo_uint64_lt (a.lo, b.lo)));
-}
-
-int
-_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b)
-{
- if (_cairo_int128_negative (a) && !_cairo_int128_negative (b))
- return 1;
- if (!_cairo_int128_negative (a) && _cairo_int128_negative (b))
- return 0;
- return _cairo_uint128_lt (a, b);
-}
-
-int
-_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b)
-{
- return (_cairo_uint64_eq (a.hi, b.hi) &&
- _cairo_uint64_eq (a.lo, b.lo));
-}
-
-/*
- * The design of this algorithm comes from GCC,
- * but the actual implementation is new
- */
-
-/*
- * den >= num.hi
- */
-static cairo_uquorem64_t
-_cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den)
-{
- cairo_uquorem64_t qr64;
- cairo_uquorem64_t qr;
- uint32_t q0, q1;
- cairo_uint64_t r0, r1;
- uint32_t d0, d1;
- cairo_uint64_t t;
-
- d0 = uint64_lo32 (den);
- d1 = uint64_hi32 (den);
-
- qr64 = _cairo_uint64_divrem (num.hi, _cairo_uint32_to_uint64 (d1));
- q1 = _cairo_uint64_to_uint32 (qr64.quo);
- r1 = qr64.rem;
-
- t = _cairo_uint32x32_64_mul (q1, d0);
-
- r1 = _cairo_uint64_add (_cairo_uint64_lsl (r1, 32),
- _cairo_uint64_rsl (num.lo, 32));
-
- if (_cairo_uint64_lt (r1, t))
- {
- q1--;
- r1 = _cairo_uint64_add (r1, den);
- if (_cairo_uint64_ge (r1, den) && _cairo_uint64_lt (r1, t))
- {
- q1--;
- r1 = _cairo_uint64_add (r1, den);
- }
- }
-
- r1 = _cairo_uint64_sub (r1, t);
-
- qr64 = _cairo_uint64_divrem (r1, _cairo_uint32_to_uint64 (d1));
-
- q0 = _cairo_uint64_to_uint32 (qr64.quo);
- r0 = qr64.rem;
-
- t = _cairo_uint32x32_64_mul (q0, d0);
-
- r0 = _cairo_uint64_add (_cairo_uint64_lsl (r0, 32),
- _cairo_uint32_to_uint64 (_cairo_uint64_to_uint32 (num.lo)));
- if (_cairo_uint64_lt (r0, t))
- {
- q0--;
- r0 = _cairo_uint64_add (r0, den);
- if (_cairo_uint64_ge (r0, den) && _cairo_uint64_lt (r0, t))
- {
- q0--;
- r0 = _cairo_uint64_add (r0, den);
- }
- }
-
- r0 = _cairo_uint64_sub (r0, t);
-
- qr.quo = _cairo_uint32s_to_uint64 (q1, q0);
- qr.rem = r0;
- return qr;
-}
-
-#if HAVE_UINT64_T
-
-static int
-_cairo_leading_zeros64 (cairo_uint64_t q)
-{
- int top = 0;
-
- if (q >= (uint64_t) 0x10000 << 16)
- {
- top += 32;
- q >>= 32;
- }
- if (q >= (uint64_t) 0x10000)
- {
- top += 16;
- q >>= 16;
- }
- if (q >= (uint64_t) 0x100)
- {
- top += 8;
- q >>= 8;
- }
- top += top_bit [q];
- return 64 - top;
-}
-
-#else
-
-static const int
-_cairo_leading_zeros64 (cairo_uint64_t d)
-{
- if (d.hi)
- return _cairo_leading_zeros32 (d.hi);
- else
- return 32 + _cairo_leading_zeros32 (d.lo);
-}
-
-#endif
-
-cairo_uquorem128_t
-_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den)
-{
- cairo_uquorem64_t qr64;
- cairo_uquorem128_t qr;
- int norm;
- cairo_uint64_t q1, q0, r1, r0;
-
- if (_cairo_uint64_eq (den.hi, _cairo_uint32_to_uint64 (0)))
- {
- if (_cairo_uint64_gt (den.lo, num.hi))
- {
- /* 0q = nn / 0d */
-
- norm = _cairo_leading_zeros64 (den.lo);
- if (norm)
- {
- den.lo = _cairo_uint64_lsl (den.lo, norm);
- num = _cairo_uint128_lsl (num, norm);
- }
- q1 = _cairo_uint32_to_uint64 (0);
- }
- else
- {
- /* qq = NN / 0d */
-
- if (_cairo_uint64_eq (den.lo, _cairo_uint32_to_uint64 (0)))
- den.lo = _cairo_uint64_divrem (_cairo_uint32_to_uint64 (1),
- den.lo).quo;
-
- norm = _cairo_leading_zeros64 (den.lo);
- if (norm)
- {
- cairo_uint128_t num1;
-
- den.lo = _cairo_uint64_lsl (den.lo, norm);
- num1 = _cairo_uint128_rsl (num, 64 - norm);
- qr64 = _cairo_uint128x64_normalized_divrem (num1, den.lo);
- q1 = qr64.quo;
- num.hi = qr64.rem;
- num.lo = _cairo_uint64_lsl (num.lo, norm);
- }
- else
- {
- num.hi = _cairo_uint64_sub (num.hi, den.lo);
- q1 = _cairo_uint32_to_uint64 (1);
- }
- }
- qr64 = _cairo_uint128x64_normalized_divrem (num, den.lo);
- q0 = qr64.quo;
- r1 = _cairo_uint32_to_uint64 (0);
- r0 = _cairo_uint64_rsl (qr64.rem, norm);
- }
- else
- {
- if (_cairo_uint64_gt (den.hi, num.hi))
- {
- /* 00 = nn / DD */
- q0 = q1 = _cairo_uint32_to_uint64 (0);
- r0 = num.lo;
- r1 = num.hi;
- }
- else
- {
- /* 0q = NN / dd */
-
- norm = _cairo_leading_zeros64 (den.hi);
- if (norm == 0)
- {
- if (_cairo_uint64_gt (num.hi, den.hi) ||
- _cairo_uint64_ge (num.lo, den.lo))
- {
- q0 = _cairo_uint32_to_uint64 (1);
- num = _cairo_uint128_sub (num, den);
- }
- else
- q0 = _cairo_uint32_to_uint64 (0);
-
- q1 = _cairo_uint32_to_uint64 (0);
- r0 = num.lo;
- r1 = num.hi;
- }
- else
- {
- cairo_uint128_t num1;
- cairo_uint128_t part;
-
- num1 = _cairo_uint128_rsl (num, 64 - norm);
- den = _cairo_uint128_lsl (den, norm);
-
- qr64 = _cairo_uint128x64_normalized_divrem (num1, den.hi);
- part = _cairo_uint64x64_128_mul (qr64.quo, den.lo);
-
- q0 = qr64.quo;
-
- num.lo = _cairo_uint64_lsl (num.lo, norm);
- num.hi = qr64.rem;
-
- if (_cairo_uint128_gt (part, num))
- {
- q0 = _cairo_uint64_sub (q0, _cairo_uint32_to_uint64 (1));
- part = _cairo_uint128_sub (part, den);
- }
-
- q1 = _cairo_uint32_to_uint64 (0);
-
- num = _cairo_uint128_sub (num, part);
- num = _cairo_uint128_rsl (num, norm);
- r0 = num.lo;
- r1 = num.hi;
- }
- }
- }
- qr.quo.lo = q0;
- qr.quo.hi = q1;
- qr.rem.lo = r0;
- qr.rem.hi = r1;
- return qr;
-}
-
-cairo_int128_t
-_cairo_int128_negate (cairo_int128_t a)
-{
- a.lo = _cairo_uint64_not (a.lo);
- a.hi = _cairo_uint64_not (a.hi);
- return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1));
-}
-
-cairo_int128_t
-_cairo_int128_not (cairo_int128_t a)
-{
- a.lo = _cairo_uint64_not (a.lo);
- a.hi = _cairo_uint64_not (a.hi);
- return a;
-}
-
-#endif /* !HAVE_UINT128_T */
-
-cairo_quorem128_t
-_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den)
-{
- int num_neg = _cairo_int128_negative (num);
- int den_neg = _cairo_int128_negative (den);
- cairo_uquorem128_t uqr;
- cairo_quorem128_t qr;
-
- if (num_neg)
- num = _cairo_int128_negate (num);
- if (den_neg)
- den = _cairo_int128_negate (den);
- uqr = _cairo_uint128_divrem (num, den);
- if (num_neg)
- qr.rem = _cairo_int128_negate (uqr.rem);
- else
- qr.rem = uqr.rem;
- if (num_neg != den_neg)
- qr.quo = _cairo_int128_negate (uqr.quo);
- else
- qr.quo = uqr.quo;
- return qr;
-}
diff --git a/src/cairo_win32_font.c b/src/cairo_win32_font.c
deleted file mode 100644
index 02f0cffd6..000000000
--- a/src/cairo_win32_font.c
+++ /dev/null
@@ -1,1252 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2005 Red Hat, Inc
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Red Hat, Inc.
- *
- * Contributor(s):
- */
-
-#include <string.h>
-#include <stdio.h>
-
-#include "cairo-win32-private.h"
-
-#ifndef SPI_GETFONTSMOOTHINGTYPE
-#define SPI_GETFONTSMOOTHINGTYPE 0x200a
-#endif
-#ifndef FE_FONTSMOOTHINGCLEARTYPE
-#define FE_FONTSMOOTHINGCLEARTYPE 2
-#endif
-#ifndef CLEARTYPE_QUALITY
-#define CLEARTYPE_QUALITY 5
-#endif
-
-const cairo_font_backend_t cairo_win32_font_backend;
-
-#define LOGICAL_SCALE 32
-
-typedef struct {
- cairo_font_t base;
-
- LOGFONTW logfont;
-
- BYTE quality;
-
- /* We do drawing and metrics computation in a "logical space" which
- * is similar to font space, except that it is scaled by a factor
- * of the (desired font size) * (LOGICAL_SCALE). The multiplication
- * by LOGICAL_SCALE allows for sub-pixel precision.
- */
- double logical_scale;
-
- /* The size we should actually request the font at from Windows; differs
- * from the logical_scale because it is quantized for orthogonal
- * transformations
- */
- double logical_size;
-
- /* Transformations from device <=> logical space
- */
- cairo_matrix_t logical_to_device;
- cairo_matrix_t device_to_logical;
-
- /* We special case combinations of 90-degree-rotations, scales and
- * flips ... that is transformations that take the axes to the
- * axes. If preserve_axes is true, then swap_axes/swap_x/swap_y
- * encode the 8 possibilities for orientation (4 rotation angles with
- * and without a flip), and scale_x, scale_y the scale components.
- */
- cairo_bool_t preserve_axes;
- cairo_bool_t swap_axes;
- cairo_bool_t swap_x;
- cairo_bool_t swap_y;
- double x_scale;
- double y_scale;
-
- /* The size of the design unit of the font
- */
- int em_square;
-
- HFONT scaled_font;
- HFONT unscaled_font;
-
-} cairo_win32_font_t;
-
-#define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.))
-
-static void
-_compute_transform (cairo_win32_font_t *font,
- cairo_font_scale_t *sc)
-{
- if (NEARLY_ZERO (sc->matrix[0][1]) && NEARLY_ZERO (sc->matrix[1][0])) {
- font->preserve_axes = TRUE;
- font->x_scale = sc->matrix[0][0];
- font->swap_x = (sc->matrix[0][0] < 0);
- font->y_scale = sc->matrix[1][1];
- font->swap_y = (sc->matrix[1][1] < 0);
- font->swap_axes = FALSE;
-
- } else if (NEARLY_ZERO (sc->matrix[0][0]) && NEARLY_ZERO (sc->matrix[1][1])) {
- font->preserve_axes = TRUE;
- font->x_scale = sc->matrix[0][1];
- font->swap_x = (sc->matrix[0][1] < 0);
- font->y_scale = sc->matrix[1][0];
- font->swap_y = (sc->matrix[1][0] < 0);
- font->swap_axes = TRUE;
-
- } else {
- font->preserve_axes = FALSE;
- font->swap_x = font->swap_y = font->swap_axes = FALSE;
- }
-
- if (font->preserve_axes) {
- if (font->swap_x)
- font->x_scale = - font->x_scale;
- if (font->swap_y)
- font->y_scale = - font->y_scale;
-
- font->logical_scale = LOGICAL_SCALE * font->y_scale;
- font->logical_size = LOGICAL_SCALE * floor (font->y_scale + 0.5);
- }
-
- /* The font matrix has x and y "scale" components which we extract and
- * use as character scale values.
- */
- cairo_matrix_set_affine (&font->logical_to_device,
- sc->matrix[0][0],
- sc->matrix[0][1],
- sc->matrix[1][0],
- sc->matrix[1][1],
- 0, 0);
-
- if (!font->preserve_axes) {
- _cairo_matrix_compute_scale_factors (&font->logical_to_device,
- &font->x_scale, &font->y_scale,
- TRUE); /* XXX: Handle vertical text */
-
- font->logical_size = floor (LOGICAL_SCALE * font->y_scale + 0.5);
- font->logical_scale = LOGICAL_SCALE * font->y_scale;
- }
-
- cairo_matrix_scale (&font->logical_to_device,
- 1.0 / font->logical_scale, 1.0 / font->logical_scale);
-
- font->device_to_logical = font->logical_to_device;
- if (!CAIRO_OK (cairo_matrix_invert (&font->device_to_logical)))
- cairo_matrix_set_identity (&font->device_to_logical);
-}
-
-static BYTE
-_get_system_quality (void)
-{
- BOOL font_smoothing;
-
- if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
- _cairo_win32_print_gdi_error ("_get_system_quality");
- return FALSE;
- }
-
- if (font_smoothing) {
- OSVERSIONINFO version_info;
-
- version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
-
- if (!GetVersionEx (&version_info)) {
- _cairo_win32_print_gdi_error ("_get_system_quality");
- return FALSE;
- }
-
- if (version_info.dwMajorVersion > 5 ||
- (version_info.dwMajorVersion == 5 &&
- version_info.dwMinorVersion >= 1)) { /* XP or newer */
- UINT smoothing_type;
-
- if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE,
- 0, &smoothing_type, 0)) {
- _cairo_win32_print_gdi_error ("_get_system_quality");
- return FALSE;
- }
-
- if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE)
- return CLEARTYPE_QUALITY;
- }
-
- return ANTIALIASED_QUALITY;
- } else
- return DEFAULT_QUALITY;
-}
-
-static cairo_font_t *
-_win32_font_create (LOGFONTW *logfont,
- cairo_font_scale_t *scale)
-{
- cairo_win32_font_t *f;
-
- f = malloc (sizeof(cairo_win32_font_t));
- if (f == NULL)
- return NULL;
-
- f->logfont = *logfont;
- f->quality = _get_system_quality ();
- f->em_square = 0;
- f->scaled_font = NULL;
- f->unscaled_font = NULL;
-
- _compute_transform (f, scale);
-
- _cairo_font_init ((cairo_font_t *)f, scale, &cairo_win32_font_backend);
-
- return (cairo_font_t *)f;
-}
-
-static cairo_status_t
-_win32_font_set_world_transform (cairo_win32_font_t *font,
- HDC hdc)
-{
- XFORM xform;
-
- xform.eM11 = font->logical_to_device.m[0][0];
- xform.eM21 = font->logical_to_device.m[1][0];
- xform.eM12 = font->logical_to_device.m[0][1];
- xform.eM22 = font->logical_to_device.m[1][1];
- xform.eDx = font->logical_to_device.m[2][0];
- xform.eDy = font->logical_to_device.m[2][1];
-
- if (!SetWorldTransform (hdc, &xform))
- return _cairo_win32_print_gdi_error ("_win32_font_set_world_transform");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_win32_font_set_identity_transform (HDC hdc)
-{
- if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY))
- return _cairo_win32_print_gdi_error ("_win32_font_set_identity_transform");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static HDC
-_get_global_font_dc (void)
-{
- static HDC hdc;
-
- if (!hdc) {
- hdc = CreateCompatibleDC (NULL);
- if (!hdc) {
- _cairo_win32_print_gdi_error ("_get_global_font_dc");
- return NULL;
- }
-
- if (!SetGraphicsMode (hdc, GM_ADVANCED)) {
- _cairo_win32_print_gdi_error ("_get_global_font_dc");
- DeleteDC (hdc);
- return NULL;
- }
- }
-
- return hdc;
-}
-
-static HFONT
-_win32_font_get_scaled_font (cairo_win32_font_t *font)
-{
- if (!font->scaled_font) {
- LOGFONTW logfont = font->logfont;
- logfont.lfHeight = font->logical_size;
- logfont.lfWidth = 0;
- logfont.lfEscapement = 0;
- logfont.lfOrientation = 0;
- logfont.lfQuality = font->quality;
-
- font->scaled_font = CreateFontIndirectW (&logfont);
- if (!font->scaled_font) {
- _cairo_win32_print_gdi_error ("_win32_font_get_scaled_font");
- return NULL;
- }
- }
-
- return font->scaled_font;
-}
-
-static HFONT
-_win32_font_get_unscaled_font (cairo_win32_font_t *font,
- HDC hdc)
-{
- if (!font->unscaled_font) {
- OUTLINETEXTMETRIC *otm;
- unsigned int otm_size;
- HFONT scaled_font;
- LOGFONTW logfont;
-
- scaled_font = _win32_font_get_scaled_font (font);
- if (!scaled_font)
- return NULL;
-
- if (!SelectObject (hdc, scaled_font)) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:SelectObject");
- return NULL;
- }
-
- otm_size = GetOutlineTextMetrics (hdc, 0, NULL);
- if (!otm_size) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
- return NULL;
- }
-
- otm = malloc (otm_size);
- if (!otm)
- return NULL;
-
- if (!GetOutlineTextMetrics (hdc, otm_size, otm)) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics");
- free (otm);
- return NULL;
- }
-
- font->em_square = otm->otmEMSquare;
- free (otm);
-
- logfont = font->logfont;
- logfont.lfHeight = font->em_square;
- logfont.lfWidth = 0;
- logfont.lfEscapement = 0;
- logfont.lfOrientation = 0;
- logfont.lfQuality = font->quality;
-
- font->unscaled_font = CreateFontIndirectW (&logfont);
- if (!font->unscaled_font) {
- _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:CreateIndirect");
- return NULL;
- }
- }
-
- return font->unscaled_font;
-}
-
-static cairo_status_t
-_cairo_win32_font_select_unscaled_font (cairo_font_t *font,
- HDC hdc)
-{
- cairo_status_t status;
- HFONT hfont;
- HFONT old_hfont = NULL;
-
- hfont = _win32_font_get_unscaled_font ((cairo_win32_font_t *)font, hdc);
- if (!hfont)
- return CAIRO_STATUS_NO_MEMORY;
-
- old_hfont = SelectObject (hdc, hfont);
- if (!old_hfont)
- return _cairo_win32_print_gdi_error ("_cairo_win32_font_select_unscaled_font");
-
- status = _win32_font_set_identity_transform (hdc);
- if (!CAIRO_OK (status)) {
- SelectObject (hdc, old_hfont);
- return status;
- }
-
- SetMapMode (hdc, MM_TEXT);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_win32_font_done_unscaled_font (cairo_font_t *font)
-{
-}
-
-/* implement the font backend interface */
-
-static cairo_status_t
-_cairo_win32_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *scale,
- cairo_font_t **font_out)
-{
- LOGFONTW logfont;
- cairo_font_t *font;
- uint16_t *face_name;
- int face_name_len;
- cairo_status_t status;
-
- status = _cairo_utf8_to_utf16 (family, -1, &face_name, &face_name_len);
- if (!CAIRO_OK (status))
- return status;
-
- if (face_name_len > LF_FACESIZE - 1) {
- free (face_name);
- return CAIRO_STATUS_INVALID_STRING;
- }
-
- memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * (face_name_len + 1));
- free (face_name);
-
- logfont.lfHeight = 0; /* filled in later */
- logfont.lfWidth = 0; /* filled in later */
- logfont.lfEscapement = 0; /* filled in later */
- logfont.lfOrientation = 0; /* filled in later */
-
- switch (weight) {
- case CAIRO_FONT_WEIGHT_NORMAL:
- default:
- logfont.lfWeight = FW_NORMAL;
- break;
- case CAIRO_FONT_WEIGHT_BOLD:
- logfont.lfWeight = FW_BOLD;
- break;
- }
-
- switch (slant) {
- case CAIRO_FONT_SLANT_NORMAL:
- default:
- logfont.lfItalic = FALSE;
- break;
- case CAIRO_FONT_SLANT_ITALIC:
- case CAIRO_FONT_SLANT_OBLIQUE:
- logfont.lfItalic = TRUE;
- break;
- }
-
- logfont.lfUnderline = FALSE;
- logfont.lfStrikeOut = FALSE;
- /* The docs for LOGFONT discourage using this, since the
- * interpretation is locale-specific, but it's not clear what
- * would be a better alternative.
- */
- logfont.lfCharSet = DEFAULT_CHARSET;
- logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
- logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- logfont.lfQuality = DEFAULT_QUALITY; /* filled in later */
- logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
-
- if (!logfont.lfFaceName)
- return CAIRO_STATUS_NO_MEMORY;
-
- font = _win32_font_create (&logfont, scale);
- if (!font)
- return CAIRO_STATUS_NO_MEMORY;
-
- *font_out = font;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_win32_font_destroy_font (void *abstract_font)
-{
- cairo_win32_font_t *font = abstract_font;
-
- if (font->scaled_font)
- DeleteObject (font->scaled_font);
-
- if (font->unscaled_font)
- DeleteObject (font->unscaled_font);
-
- free (font);
-}
-
-static void
-_cairo_win32_font_destroy_unscaled_font (void *abstract_font)
-{
-}
-
-static void
-_cairo_win32_font_get_glyph_cache_key (void *abstract_font,
- cairo_glyph_cache_key_t *key)
-{
-}
-
-static cairo_status_t
-_cairo_win32_font_text_to_glyphs (void *abstract_font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs)
-{
- cairo_win32_font_t *font = abstract_font;
- uint16_t *utf16;
- int n16;
- GCP_RESULTSW gcp_results;
- unsigned int buffer_size, i;
- WCHAR *glyph_indices = NULL;
- int *dx = NULL;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- double x_pos;
- HDC hdc = NULL;
-
- status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16);
- if (!CAIRO_OK (status))
- return status;
-
- gcp_results.lStructSize = sizeof (GCP_RESULTS);
- gcp_results.lpOutString = NULL;
- gcp_results.lpOrder = NULL;
- gcp_results.lpCaretPos = NULL;
- gcp_results.lpClass = NULL;
-
- buffer_size = MAX (n16 * 1.2, 16); /* Initially guess number of chars plus a few */
- if (buffer_size > INT_MAX) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL1;
- }
-
- hdc = _get_global_font_dc ();
- if (!hdc) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL1;
- }
-
- status = cairo_win32_font_select_font (&font->base, hdc);
- if (!CAIRO_OK (status))
- goto FAIL1;
-
- while (TRUE) {
- if (glyph_indices) {
- free (glyph_indices);
- glyph_indices = NULL;
- }
- if (dx) {
- free (dx);
- dx = NULL;
- }
-
- glyph_indices = malloc (sizeof (WCHAR) * buffer_size);
- dx = malloc (sizeof (int) * buffer_size);
- if (!glyph_indices || !dx) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL2;
- }
-
- gcp_results.nGlyphs = buffer_size;
- gcp_results.lpDx = dx;
- gcp_results.lpGlyphs = glyph_indices;
-
- if (!GetCharacterPlacementW (hdc, utf16, n16,
- 0,
- &gcp_results,
- GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER)) {
- status = _cairo_win32_print_gdi_error ("_cairo_win32_font_text_to_glyphs");
- goto FAIL2;
- }
-
- if (gcp_results.lpDx && gcp_results.lpGlyphs)
- break;
-
- /* Too small a buffer, try again */
-
- buffer_size *= 1.5;
- if (buffer_size > INT_MAX) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL2;
- }
- }
-
- *num_glyphs = gcp_results.nGlyphs;
- *glyphs = malloc (sizeof (cairo_glyph_t) * gcp_results.nGlyphs);
- if (!*glyphs) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto FAIL2;
- }
-
- x_pos = 0;
- for (i = 0; i < gcp_results.nGlyphs; i++) {
- (*glyphs)[i].index = glyph_indices[i];
- (*glyphs)[i].x = x_pos ;
- (*glyphs)[i].y = 0;
-
- x_pos += dx[i] / font->logical_scale;
- }
-
- FAIL2:
- if (glyph_indices)
- free (glyph_indices);
- if (dx)
- free (dx);
-
- cairo_win32_font_done_font (&font->base);
-
- FAIL1:
- free (utf16);
-
- return status;
-}
-
-static cairo_status_t
-_cairo_win32_font_font_extents (void *abstract_font,
- cairo_font_extents_t *extents)
-{
- cairo_win32_font_t *font = abstract_font;
- cairo_status_t status;
- TEXTMETRIC metrics;
- HDC hdc;
-
- hdc = _get_global_font_dc ();
- if (!hdc)
- return CAIRO_STATUS_NO_MEMORY;
-
- if (font->preserve_axes) {
- /* For 90-degree rotations (including 0), we get the metrics
- * from the GDI in logical space, then convert back to font space
- */
- status = cairo_win32_font_select_font (&font->base, hdc);
- if (!CAIRO_OK (status))
- return status;
- GetTextMetrics (hdc, &metrics);
- cairo_win32_font_done_font (&font->base);
-
- extents->ascent = metrics.tmAscent / font->logical_scale;
- extents->descent = metrics.tmDescent / font->logical_scale;
-
- extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / font->logical_scale;
- extents->max_x_advance = metrics.tmMaxCharWidth / font->logical_scale;
- extents->max_y_advance = 0;
-
- } else {
- /* For all other transformations, we use the design metrics
- * of the font. The GDI results from GetTextMetrics() on a
- * transformed font are inexplicably large and we want to
- * avoid them.
- */
- status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
- if (!CAIRO_OK (status))
- return status;
- GetTextMetrics (hdc, &metrics);
- _cairo_win32_font_done_unscaled_font (&font->base);
-
- extents->ascent = (double)metrics.tmAscent / font->em_square;
- extents->descent = metrics.tmDescent * font->em_square;
- extents->height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / font->em_square;
- extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / font->em_square;
- extents->max_y_advance = 0;
-
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_win32_font_glyph_extents (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
-{
- cairo_win32_font_t *font = abstract_font;
- static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
- GLYPHMETRICS metrics;
- cairo_status_t status;
- HDC hdc;
-
- hdc = _get_global_font_dc ();
- if (!hdc)
- return CAIRO_STATUS_NO_MEMORY;
-
- /* We handle only the case num_glyphs == 1, glyphs[i].x == glyphs[0].y == 0.
- * This is all that the calling code triggers, and the backend interface
- * will eventually be changed to match
- */
- assert (num_glyphs == 1);
-
- if (font->preserve_axes) {
- /* If we aren't rotating / skewing the axes, then we get the metrics
- * from the GDI in device space and convert to font space.
- */
- status = cairo_win32_font_select_font (&font->base, hdc);
- if (!CAIRO_OK (status))
- return status;
- GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
- &metrics, 0, NULL, &matrix);
- cairo_win32_font_done_font (&font->base);
-
- if (font->swap_axes) {
- extents->x_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
- extents->y_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
- extents->width = metrics.gmBlackBoxY / font->y_scale;
- extents->height = metrics.gmBlackBoxX / font->x_scale;
- extents->x_advance = metrics.gmCellIncY / font->x_scale;
- extents->y_advance = metrics.gmCellIncX / font->y_scale;
- } else {
- extents->x_bearing = metrics.gmptGlyphOrigin.x / font->x_scale;
- extents->y_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale;
- extents->width = metrics.gmBlackBoxX / font->x_scale;
- extents->height = metrics.gmBlackBoxY / font->y_scale;
- extents->x_advance = metrics.gmCellIncX / font->x_scale;
- extents->y_advance = metrics.gmCellIncY / font->y_scale;
- }
-
- if (font->swap_x) {
- extents->x_bearing = (- extents->x_bearing - extents->width);
- extents->x_advance = - extents->x_advance;
- }
-
- if (font->swap_y) {
- extents->y_bearing = (- extents->y_bearing - extents->height);
- extents->y_advance = - extents->y_advance;
- }
-
- } else {
- /* For all other transformations, we use the design metrics
- * of the font.
- */
- status = _cairo_win32_font_select_unscaled_font (&font->base, hdc);
- GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX,
- &metrics, 0, NULL, &matrix);
- _cairo_win32_font_done_unscaled_font (&font->base);
-
- extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / font->em_square;
- extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / font->em_square;
- extents->width = (double)metrics.gmBlackBoxX / font->em_square;
- extents->height = (double)metrics.gmBlackBoxY / font->em_square;
- extents->x_advance = (double)metrics.gmCellIncX / font->em_square;
- extents->y_advance = (double)metrics.gmCellIncY / font->em_square;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static cairo_status_t
-_cairo_win32_font_glyph_bbox (void *abstract_font,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox)
-{
- static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } };
- cairo_win32_font_t *font = abstract_font;
- int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
-
- if (num_glyphs > 0) {
- HDC hdc = _get_global_font_dc ();
- GLYPHMETRICS metrics;
- cairo_status_t status;
- int i;
-
- if (!hdc)
- return CAIRO_STATUS_NO_MEMORY;
-
- status = cairo_win32_font_select_font (&font->base, hdc);
- if (!CAIRO_OK (status))
- return status;
-
- for (i = 0; i < num_glyphs; i++) {
- int x = floor (0.5 + glyphs[i].x);
- int y = floor (0.5 + glyphs[i].y);
-
- GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | GGO_GLYPH_INDEX,
- &metrics, 0, NULL, &matrix);
-
- if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x)
- x1 = x + metrics.gmptGlyphOrigin.x;
- if (i == 0 || y1 > y - metrics.gmptGlyphOrigin.y)
- y1 = y - metrics.gmptGlyphOrigin.y;
- if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX)
- x2 = x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX;
- if (i == 0 || y2 < y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY)
- y2 = y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY;
- }
-
- cairo_win32_font_done_font (&font->base);
- }
-
- bbox->p1.x = _cairo_fixed_from_int (x1);
- bbox->p1.y = _cairo_fixed_from_int (y1);
- bbox->p2.x = _cairo_fixed_from_int (x2);
- bbox->p2.y = _cairo_fixed_from_int (y2);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-typedef struct {
- cairo_win32_font_t *font;
- HDC hdc;
-
- cairo_array_t glyphs;
- cairo_array_t dx;
-
- int start_x;
- int last_x;
- int last_y;
-} cairo_glyph_state_t;
-
-static void
-_start_glyphs (cairo_glyph_state_t *state,
- cairo_win32_font_t *font,
- HDC hdc)
-{
- state->hdc = hdc;
- state->font = font;
-
- _cairo_array_init (&state->glyphs, sizeof (WCHAR));
- _cairo_array_init (&state->dx, sizeof (int));
-}
-
-static cairo_status_t
-_flush_glyphs (cairo_glyph_state_t *state)
-{
- int dx = 0;
- if (!_cairo_array_append (&state->dx, &dx, 1))
- return CAIRO_STATUS_NO_MEMORY;
-
- if (!ExtTextOutW (state->hdc,
- state->start_x, state->last_y,
- ETO_GLYPH_INDEX,
- NULL,
- (WCHAR *)state->glyphs.elements,
- state->glyphs.num_elements,
- (int *)state->dx.elements)) {
- return _cairo_win32_print_gdi_error ("_flush_glyphs");
- }
-
- _cairo_array_truncate (&state->glyphs, 0);
- _cairo_array_truncate (&state->dx, 0);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_add_glyph (cairo_glyph_state_t *state,
- unsigned long index,
- double device_x,
- double device_y)
-{
- double user_x = device_x;
- double user_y = device_y;
- WCHAR glyph_index = index;
- int logical_x, logical_y;
-
- cairo_matrix_transform_point (&state->font->device_to_logical, &user_x, &user_y);
-
- logical_x = floor (user_x + 0.5);
- logical_y = floor (user_y + 0.5);
-
- if (state->glyphs.num_elements > 0) {
- int dx;
-
- if (logical_y != state->last_y) {
- cairo_status_t status = _flush_glyphs (state);
- if (!CAIRO_OK (status))
- return status;
- state->start_x = logical_x;
- }
-
- dx = logical_x - state->last_x;
- if (!_cairo_array_append (&state->dx, &dx, 1))
- return CAIRO_STATUS_NO_MEMORY;
- } else {
- state->start_x = logical_x;
- }
-
- state->last_x = logical_x;
- state->last_y = logical_y;
-
- _cairo_array_append (&state->glyphs, &glyph_index, 1);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_finish_glyphs (cairo_glyph_state_t *state)
-{
- _flush_glyphs (state);
-
- _cairo_array_fini (&state->glyphs);
- _cairo_array_fini (&state->dx);
-}
-
-static cairo_status_t
-_draw_glyphs_on_surface (cairo_win32_surface_t *surface,
- cairo_win32_font_t *font,
- COLORREF color,
- int x_offset,
- int y_offset,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_glyph_state_t state;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- int i;
-
- if (!SaveDC (surface->dc))
- return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC");
-
- status = cairo_win32_font_select_font (&font->base, surface->dc);
- if (!CAIRO_OK (status))
- goto FAIL1;
-
- SetTextColor (surface->dc, color);
- SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT);
- SetBkMode (surface->dc, TRANSPARENT);
-
- _start_glyphs (&state, font, surface->dc);
-
- for (i = 0; i < num_glyphs; i++) {
- status = _add_glyph (&state, glyphs[i].index,
- glyphs[i].x - x_offset, glyphs[i].y - y_offset);
- if (!CAIRO_OK (status))
- goto FAIL2;
- }
-
- FAIL2:
- _finish_glyphs (&state);
- cairo_win32_font_done_font (&font->base);
- FAIL1:
- RestoreDC (surface->dc, 1);
-
- return status;
-}
-
-/* Duplicate the green channel of a 4-channel mask in the alpha channel, then
- * invert the whole mask.
- */
-static void
-_compute_argb32_mask_alpha (cairo_win32_surface_t *mask_surface)
-{
- cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image;
- int i, j;
-
- for (i = 0; i < image->height; i++) {
- uint32_t *p = (uint32_t *) (image->data + i * image->stride);
- for (j = 0; j < image->width; j++) {
- *p = 0xffffffff ^ (*p | ((*p & 0x0000ff00) << 16));
- p++;
- }
- }
-}
-
-/* Invert a mask
- */
-static void
-_invert_argb32_mask (cairo_win32_surface_t *mask_surface)
-{
- cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image;
- int i, j;
-
- for (i = 0; i < image->height; i++) {
- uint32_t *p = (uint32_t *) (image->data + i * image->stride);
- for (j = 0; j < image->width; j++) {
- *p = 0xffffffff ^ *p;
- p++;
- }
- }
-}
-
-/* Compute an alpha-mask from a monochrome RGB24 image
- */
-static cairo_surface_t *
-_compute_a8_mask (cairo_win32_surface_t *mask_surface)
-{
- cairo_image_surface_t *image24 = (cairo_image_surface_t *)mask_surface->image;
- cairo_image_surface_t *image8;
- int i, j;
-
- image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8,
- image24->width, image24->height);
- if (!image8)
- return NULL;
-
- for (i = 0; i < image24->height; i++) {
- uint32_t *p = (uint32_t *) (image24->data + i * image24->stride);
- unsigned char *q = (unsigned char *) (image8->data + i * image8->stride);
-
- for (j = 0; j < image24->width; j++) {
- *q = 255 - ((*p & 0x0000ff00) >> 8);
- p++;
- q++;
- }
- }
-
- return &image8->base;
-}
-
-static cairo_status_t
-_cairo_win32_font_show_glyphs (void *abstract_font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *generic_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_win32_font_t *font = abstract_font;
- cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface;
- cairo_status_t status;
-
- if (width == 0 || height == 0)
- return CAIRO_STATUS_SUCCESS;
-
- if (_cairo_surface_is_win32 (generic_surface) &&
- surface->format == CAIRO_FORMAT_RGB24 &&
- operator == CAIRO_OPERATOR_OVER &&
- pattern->type == CAIRO_PATTERN_SOLID &&
- _cairo_pattern_is_opaque (pattern)) {
-
- cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)pattern;
-
- /* When compositing OVER on a GDI-understood surface, with a
- * solid opaque color, we can just call ExtTextOut directly.
- */
- COLORREF new_color;
-
- new_color = RGB (((int)(0xffff * solid_pattern->red)) >> 8,
- ((int)(0xffff * solid_pattern->green)) >> 8,
- ((int)(0xffff * solid_pattern->blue)) >> 8);
-
- status = _draw_glyphs_on_surface (surface, font, new_color,
- 0, 0,
- glyphs, num_glyphs);
-
- return status;
- } else {
- /* Otherwise, we need to draw using software fallbacks. We create a mask
- * surface by drawing the the glyphs onto a DIB, black-on-white then
- * inverting. GDI outputs gamma-corrected images so inverted black-on-white
- * is very different from white-on-black. We favor the more common
- * case where the final output is dark-on-light.
- */
- cairo_win32_surface_t *tmp_surface;
- cairo_surface_t *mask_surface;
- cairo_surface_pattern_t mask;
- RECT r;
-
- tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height);
- if (!tmp_surface)
- return CAIRO_STATUS_NO_MEMORY;
-
- r.left = 0;
- r.top = 0;
- r.right = width;
- r.bottom = height;
- FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH));
-
- _draw_glyphs_on_surface (tmp_surface, font, RGB (0, 0, 0),
- dest_x, dest_y,
- glyphs, num_glyphs);
-
- if (font->quality == CLEARTYPE_QUALITY) {
- /* For ClearType, we need a 4-channel mask. If we are compositing on
- * a surface with alpha, we need to compute the alpha channel of
- * the mask (we just copy the green channel). But for a destination
- * surface without alpha the alpha channel of the mask is ignored
- */
-
- if (surface->format != CAIRO_FORMAT_RGB24)
- _compute_argb32_mask_alpha (tmp_surface);
- else
- _invert_argb32_mask (tmp_surface);
-
- mask_surface = &tmp_surface->base;
-
- /* XXX: Hacky, should expose this in cairo_image_surface */
- pixman_image_set_component_alpha (((cairo_image_surface_t *)tmp_surface->image)->pixman_image, TRUE);
-
- } else {
- mask_surface = _compute_a8_mask (tmp_surface);
- cairo_surface_destroy (&tmp_surface->base);
- if (!mask_surface)
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- /* For operator == OVER, no-cleartype, a possible optimization here is to
- * draw onto an intermediate ARGB32 surface and alpha-blend that with the
- * destination
- */
- _cairo_pattern_init_for_surface (&mask, mask_surface);
-
- status = _cairo_surface_composite (operator, pattern,
- &mask.base,
- &surface->base,
- source_x, source_y,
- 0, 0,
- dest_x, dest_y,
- width, height);
-
- _cairo_pattern_fini (&mask.base);
-
- cairo_surface_destroy (mask_surface);
-
- return status;
- }
-}
-
-static cairo_status_t
-_cairo_win32_font_glyph_path (void *abstract_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path)
-{
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_win32_font_create_glyph (cairo_image_glyph_cache_entry_t *val)
-{
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-const cairo_font_backend_t cairo_win32_font_backend = {
- _cairo_win32_font_create,
- _cairo_win32_font_destroy_font,
- _cairo_win32_font_destroy_unscaled_font,
- _cairo_win32_font_font_extents,
- _cairo_win32_font_text_to_glyphs,
- _cairo_win32_font_glyph_extents,
- _cairo_win32_font_glyph_bbox,
- _cairo_win32_font_show_glyphs,
- _cairo_win32_font_glyph_path,
- _cairo_win32_font_get_glyph_cache_key,
- _cairo_win32_font_create_glyph
-};
-
-/* implement the platform-specific interface */
-
-/**
- * cairo_win32_font_create_for_logfontw:
- * @logfont: A #LOGFONTW structure specifying the font to use.
- * The lfHeight, lfWidth, lfOrientation and lfEscapement
- * fields of this structure are ignored; information from
- * @scale will be used instead.
- * @scale: The scale at which this font will be used. The
- * scale is given by multiplying the font matrix (see
- * cairo_transform_font()) by the current transformation matrix.
- * The translation elements of the resulting matrix are ignored.
- *
- * Creates a new font for the Win32 font backend based on a
- * #LOGFONT. This font can then be used with
- * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend
- * specific functions like cairo_win32_font_select_font().
- *
- * Return value: a newly created #cairo_font_t. Free with
- * cairo_font_destroy() when you are done using it.
- **/
-cairo_font_t *
-cairo_win32_font_create_for_logfontw (LOGFONTW *logfont,
- cairo_matrix_t *scale)
-{
- cairo_font_scale_t sc;
-
- cairo_matrix_get_affine (scale,
- &sc.matrix[0][0], &sc.matrix[0][1],
- &sc.matrix[1][0], &sc.matrix[1][1],
- NULL, NULL);
-
- return _win32_font_create (logfont, &sc);
-}
-
-/**
- * cairo_win32_font_select_font:
- * @font: A #cairo_font_t from the Win32 font backend. Such an
- * object can be created with cairo_win32_font_create_for_logfontw().
- * @hdc: a device context
- *
- * Selects the font into the given device context and changes the
- * map mode and world transformation of the device context to match
- * that of the font. This function is intended for use when using
- * layout APIs such as Uniscribe to do text layout with the
- * Cairo font. After finishing using the device context, you must call
- * cairo_win32_font_done_font() to release any resources allocated
- * by this function.
- *
- * See cairo_win32_font_get_scale_factor() for converting logical
- * coordinates from the device context to font space.
- *
- * Normally, calls to SaveDC() and RestoreDC() would be made around
- * the use of this function to preserve the original graphics state.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if the operation succeeded.
- * otherwise an error such as %CAIRO_STATUS_NO_MEMORY and
- * the device context is unchanged.
- **/
-cairo_status_t
-cairo_win32_font_select_font (cairo_font_t *font,
- HDC hdc)
-{
- cairo_status_t status;
- HFONT hfont;
- HFONT old_hfont = NULL;
- int old_mode;
-
- hfont = _win32_font_get_scaled_font ((cairo_win32_font_t *)font);
- if (!hfont)
- return CAIRO_STATUS_NO_MEMORY;
-
- old_hfont = SelectObject (hdc, hfont);
- if (!old_hfont)
- return _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
-
- old_mode = SetGraphicsMode (hdc, GM_ADVANCED);
- if (!old_mode) {
- status = _cairo_win32_print_gdi_error ("cairo_win32_font_select_font");
- SelectObject (hdc, old_hfont);
- return status;
- }
-
- status = _win32_font_set_world_transform ((cairo_win32_font_t *)font, hdc);
- if (!CAIRO_OK (status)) {
- SetGraphicsMode (hdc, old_mode);
- SelectObject (hdc, old_hfont);
- return status;
- }
-
- SetMapMode (hdc, MM_TEXT);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * cairo_win32_font_done_font:
- * @font: A #cairo_font_t from the Win32 font backend.
- *
- * Releases any resources allocated by cairo_win32_font_select_font()
- **/
-void
-cairo_win32_font_done_font (cairo_font_t *font)
-{
-}
-
-/**
- * cairo_win32_font_get_scale_factor:
- * @font: a #cairo_font_t from the Win32 font backend
- *
- * Gets a scale factor between logical coordinates in the coordinate
- * space used by cairo_win32_font_select_font() and font space coordinates.
- *
- * Return value: factor to multiply logical units by to get font space
- * coordinates.
- **/
-double
-cairo_win32_font_get_scale_factor (cairo_font_t *font)
-{
- return 1. / ((cairo_win32_font_t *)font)->logical_scale;
-}
diff --git a/src/cairo_win32_surface.c b/src/cairo_win32_surface.c
deleted file mode 100644
index dcfe6d044..000000000
--- a/src/cairo_win32_surface.c
+++ /dev/null
@@ -1,931 +0,0 @@
-/* Cairo - a vector graphics library with display and print output
- *
- * Copyright © 2005 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is Red Hat, Inc.
- *
- * Contributor(s):
- * Owen Taylor <otaylor@redhat.com>
- */
-
-#include <stdio.h>
-
-#include "cairo-win32-private.h"
-
-static const cairo_surface_backend_t cairo_win32_surface_backend;
-
-/**
- * _cairo_win32_print_gdi_error:
- * @context: context string to display along with the error
- *
- * Helper function to dump out a human readable form of the
- * current error code.
- *
- * Return value: A Cairo status code for the error code
- **/
-cairo_status_t
-_cairo_win32_print_gdi_error (const char *context)
-{
- void *lpMsgBuf;
- DWORD last_error = GetLastError ();
-
- if (!FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- last_error,
- MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &lpMsgBuf,
- 0, NULL)) {
- fprintf (stderr, "%s: Unknown GDI error", context);
- } else {
- fprintf (stderr, "%s: %s", context, (char *)lpMsgBuf);
-
- LocalFree (lpMsgBuf);
- }
-
- /* We should switch off of last_status, but we'd either return
- * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
- * is no CAIRO_STATUS_UNKNOWN_ERROR.
- */
-
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-void
-cairo_set_target_win32 (cairo_t *cr,
- HDC hdc)
-{
- cairo_surface_t *surface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_win32_surface_create (hdc);
- if (surface == NULL) {
- cr->status = CAIRO_STATUS_NO_MEMORY;
- return;
- }
-
- cairo_set_target_surface (cr, surface);
-
- /* cairo_set_target_surface takes a reference, so we must destroy ours */
- cairo_surface_destroy (surface);
-}
-
-static cairo_status_t
-_create_dc_and_bitmap (cairo_win32_surface_t *surface,
- HDC original_dc,
- cairo_format_t format,
- int width,
- int height,
- char **bits_out,
- int *rowstride_out)
-{
- cairo_status_t status;
-
- BITMAPINFO *bitmap_info = NULL;
- struct {
- BITMAPINFOHEADER bmiHeader;
- RGBQUAD bmiColors[2];
- } bmi_stack;
- void *bits;
-
- int num_palette = 0; /* Quiet GCC */
- int i;
-
- surface->dc = NULL;
- surface->bitmap = NULL;
-
- switch (format) {
- case CAIRO_FORMAT_ARGB32:
- case CAIRO_FORMAT_RGB24:
- num_palette = 0;
- break;
-
- case CAIRO_FORMAT_A8:
- num_palette = 256;
- break;
-
- case CAIRO_FORMAT_A1:
- num_palette = 2;
- break;
- }
-
- if (num_palette > 2) {
- bitmap_info = malloc (sizeof (BITMAPINFOHEADER) + num_palette * sizeof (RGBQUAD));
- if (!bitmap_info)
- return CAIRO_STATUS_NO_MEMORY;
- } else {
- bitmap_info = (BITMAPINFO *)&bmi_stack;
- }
-
- bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
- bitmap_info->bmiHeader.biWidth = width;
- bitmap_info->bmiHeader.biHeight = - height; /* top-down */
- bitmap_info->bmiHeader.biSizeImage = 0;
- bitmap_info->bmiHeader.biXPelsPerMeter = 72. / 0.0254; /* unused here */
- bitmap_info->bmiHeader.biYPelsPerMeter = 72. / 0.0254; /* unused here */
- bitmap_info->bmiHeader.biPlanes = 1;
-
- switch (format) {
- case CAIRO_FORMAT_ARGB32:
- case CAIRO_FORMAT_RGB24:
- bitmap_info->bmiHeader.biBitCount = 32;
- bitmap_info->bmiHeader.biCompression = BI_RGB;
- bitmap_info->bmiHeader.biClrUsed = 0; /* unused */
- bitmap_info->bmiHeader.biClrImportant = 0;
- break;
-
- case CAIRO_FORMAT_A8:
- bitmap_info->bmiHeader.biBitCount = 8;
- bitmap_info->bmiHeader.biCompression = BI_RGB;
- bitmap_info->bmiHeader.biClrUsed = 256;
- bitmap_info->bmiHeader.biClrImportant = 0;
-
- for (i = 0; i < 256; i++) {
- bitmap_info->bmiColors[i].rgbBlue = i;
- bitmap_info->bmiColors[i].rgbGreen = i;
- bitmap_info->bmiColors[i].rgbRed = i;
- bitmap_info->bmiColors[i].rgbReserved = 0;
- }
-
- break;
-
- case CAIRO_FORMAT_A1:
- bitmap_info->bmiHeader.biBitCount = 1;
- bitmap_info->bmiHeader.biCompression = BI_RGB;
- bitmap_info->bmiHeader.biClrUsed = 2;
- bitmap_info->bmiHeader.biClrImportant = 0;
-
- for (i = 0; i < 2; i++) {
- bitmap_info->bmiColors[i].rgbBlue = i * 255;
- bitmap_info->bmiColors[i].rgbGreen = i * 255;
- bitmap_info->bmiColors[i].rgbRed = i * 255;
- bitmap_info->bmiColors[i].rgbReserved = 0;
- break;
- }
- }
-
- surface->dc = CreateCompatibleDC (original_dc);
- if (!surface->dc)
- goto FAIL;
-
- surface->bitmap = CreateDIBSection (surface->dc,
- bitmap_info,
- DIB_RGB_COLORS,
- &bits,
- NULL, 0);
- if (!surface->bitmap)
- goto FAIL;
-
- surface->saved_dc_bitmap = SelectObject (surface->dc,
- surface->bitmap);
- if (!surface->saved_dc_bitmap)
- goto FAIL;
-
- if (bitmap_info && num_palette > 2)
- free (bitmap_info);
-
- if (bits_out)
- *bits_out = bits;
-
- if (rowstride_out) {
- /* Windows bitmaps are padded to 16-bit (word) boundaries */
- switch (format) {
- case CAIRO_FORMAT_ARGB32:
- case CAIRO_FORMAT_RGB24:
- *rowstride_out = 4 * width;
- break;
-
- case CAIRO_FORMAT_A8:
- *rowstride_out = (width + 1) & -2;
- break;
-
- case CAIRO_FORMAT_A1:
- *rowstride_out = ((width + 15) & -16) / 8;
- break;
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-
- FAIL:
- status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap");
-
- if (bitmap_info && num_palette > 2)
- free (bitmap_info);
-
- if (surface->saved_dc_bitmap) {
- SelectObject (surface->dc, surface->saved_dc_bitmap);
- surface->saved_dc_bitmap = NULL;
- }
-
- if (surface->bitmap) {
- DeleteObject (surface->bitmap);
- surface->bitmap = NULL;
- }
-
- if (surface->dc) {
- DeleteDC (surface->dc);
- surface->dc = NULL;
- }
-
- return status;
-}
-
-static cairo_surface_t *
-_cairo_win32_surface_create_for_dc (HDC original_dc,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- cairo_win32_surface_t *surface;
- char *bits;
- int rowstride;
-
- surface = malloc (sizeof (cairo_win32_surface_t));
- if (!surface)
- return NULL;
-
- if (_create_dc_and_bitmap (surface, original_dc, format,
- width, height,
- &bits, &rowstride) != CAIRO_STATUS_SUCCESS)
- goto FAIL;
-
- surface->image = cairo_image_surface_create_for_data (bits, format,
- width, height, rowstride);
- if (!surface->image)
- goto FAIL;
-
- surface->format = format;
-
- surface->clip_rect.x = 0;
- surface->clip_rect.y = 0;
- surface->clip_rect.width = width;
- surface->clip_rect.height = height;
-
- surface->set_clip = 0;
- surface->saved_clip = NULL;
-
- _cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
-
- return (cairo_surface_t *)surface;
-
- FAIL:
- if (surface->bitmap) {
- SelectObject (surface->dc, surface->saved_dc_bitmap);
- DeleteObject (surface->bitmap);
- DeleteDC (surface->dc);
- }
- if (surface)
- free (surface);
-
- return NULL;
-
-}
-
-static cairo_surface_t *
-_cairo_win32_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- cairo_win32_surface_t *src = abstract_src;
-
- return _cairo_win32_surface_create_for_dc (src->dc, format, drawable,
- width, height);
-}
-
-/**
- * _cairo_win32_surface_create_dib:
- * @format: format of pixels in the surface to create
- * @width: width of the surface, in pixels
- * @height: height of the surface, in pixels
- *
- * Creates a device-independent-bitmap surface not associated with
- * any particular existing surface or device context. The created
- * bitmap will be unititialized.
- *
- * Return value: the newly created surface, or %NULL if it couldn't
- * be created (probably because of lack of memory)
- **/
-cairo_surface_t *
-_cairo_win32_surface_create_dib (cairo_format_t format,
- int width,
- int height)
-{
- return _cairo_win32_surface_create_for_dc (NULL, format, TRUE,
- width, height);
-}
-
-static void
-_cairo_win32_surface_destroy (void *abstract_surface)
-{
- cairo_win32_surface_t *surface = abstract_surface;
-
- if (surface->image)
- cairo_surface_destroy (surface->image);
-
- if (surface->saved_clip)
- DeleteObject (surface->saved_clip);
-
- /* If we created the Bitmap and DC, destroy them */
- if (surface->bitmap) {
- SelectObject (surface->dc, surface->saved_dc_bitmap);
- DeleteObject (surface->bitmap);
- DeleteDC (surface->dc);
- }
-
- free (surface);
-}
-
-static double
-_cairo_win32_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We should really get this value from somewhere */
- return 96.0;
-}
-
-static cairo_status_t
-_cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
- int x,
- int y,
- int width,
- int height,
- cairo_win32_surface_t **local_out)
-{
- cairo_win32_surface_t *local;
- cairo_status_t status;
-
- local =
- (cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface,
- surface->format,
- 0,
- width, height);
- if (!local)
- return CAIRO_STATUS_NO_MEMORY;
-
- if (!BitBlt (local->dc,
- 0, 0,
- width, height,
- surface->dc,
- x, y,
- SRCCOPY))
- goto FAIL;
-
- *local_out = local;
-
- return CAIRO_STATUS_SUCCESS;
-
- FAIL:
- status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_get_subimage");
-
- if (local)
- cairo_surface_destroy (&local->base);
-
- return status;
-}
-
-static cairo_status_t
-_cairo_win32_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_win32_surface_t *local = NULL;
- cairo_status_t status;
-
- if (surface->image) {
- *image_out = (cairo_image_surface_t *)surface->image;
- *image_extra = NULL;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0,
- surface->clip_rect.width,
- surface->clip_rect.height, &local);
- if (CAIRO_OK (status)) {
- cairo_surface_set_filter (&local->base, surface->base.filter);
- cairo_surface_set_matrix (&local->base, &surface->base.matrix);
- cairo_surface_set_repeat (&local->base, surface->base.repeat);
-
- *image_out = (cairo_image_surface_t *)local->image;
- *image_extra = local;
- }
-
- return status;
-}
-
-static void
-_cairo_win32_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- cairo_win32_surface_t *local = image_extra;
-
- if (local)
- cairo_surface_destroy ((cairo_surface_t *)local);
-}
-
-static cairo_status_t
-_cairo_win32_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect,
- void **image_extra)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_win32_surface_t *local = NULL;
- cairo_status_t status;
- RECT clip_box;
- int x1, y1, x2, y2;
-
- if (surface->image) {
- image_rect->x = 0;
- image_rect->y = 0;
- image_rect->width = surface->clip_rect.width;
- image_rect->height = surface->clip_rect.height;
-
- *image_out = (cairo_image_surface_t *)surface->image;
- *image_extra = NULL;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (GetClipBox (surface->dc, &clip_box) == ERROR)
- return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
-
- x1 = clip_box.left;
- x2 = clip_box.right;
- y1 = clip_box.top;
- y2 = clip_box.bottom;
-
- if (interest_rect->x > x1)
- x1 = interest_rect->x;
- if (interest_rect->y > y1)
- y1 = interest_rect->y;
- if (interest_rect->x + interest_rect->width < x2)
- x2 = interest_rect->x + interest_rect->width;
- if (interest_rect->y + interest_rect->height < y2)
- y2 = interest_rect->y + interest_rect->height;
-
- if (x1 >= x2 || y1 >= y2) {
- *image_out = NULL;
- *image_extra = NULL;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- status = _cairo_win32_surface_get_subimage (abstract_surface,
- x1, y1, x2 - x1, y2 - y1,
- &local);
- if (CAIRO_OK (status)) {
- *image_out = (cairo_image_surface_t *)local->image;
- *image_extra = local;
-
- image_rect->x = x1;
- image_rect->y = y1;
- image_rect->width = x2 - x1;
- image_rect->height = y2 - y1;
- }
-
- return status;
-}
-
-static void
-_cairo_win32_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_win32_surface_t *local = image_extra;
-
- if (!local)
- return;
-
- if (!BitBlt (surface->dc,
- image_rect->x, image_rect->y,
- image_rect->width, image_rect->height,
- local->dc,
- 0, 0,
- SRCCOPY))
- _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
-
- cairo_surface_destroy ((cairo_surface_t *)local);
-}
-
-static cairo_status_t
-_cairo_win32_surface_clone_similar (void *surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_win32_surface_t *dst = abstract_dst;
- cairo_win32_surface_t *src;
- cairo_surface_pattern_t *src_surface_pattern;
- int alpha;
- int integer_transform;
- int itx, ity;
-
- if (pattern->type != CAIRO_PATTERN_SURFACE ||
- pattern->extend != CAIRO_EXTEND_NONE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (mask_pattern) {
- /* FIXME: When we fully support RENDER style 4-channel
- * masks we need to check r/g/b != 1.0.
- */
- if (mask_pattern->type != CAIRO_PATTERN_SOLID)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- alpha = (int)(0xffff * pattern->alpha * mask_pattern->alpha) >> 8;
- } else {
- alpha = (int)(0xffff * pattern->alpha) >> 8;
- }
-
- src_surface_pattern = (cairo_surface_pattern_t *)pattern;
- src = (cairo_win32_surface_t *)src_surface_pattern->surface;
-
- if (src->base.backend != dst->base.backend)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- integer_transform = _cairo_matrix_is_integer_translation (&pattern->matrix, &itx, &ity);
- if (!integer_transform)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (alpha == 255 &&
- src->format == dst->format &&
- (operator == CAIRO_OPERATOR_SRC ||
- (src->format == CAIRO_FORMAT_RGB24 && operator == CAIRO_OPERATOR_OVER))) {
-
- if (!BitBlt (dst->dc,
- dst_x, dst_y,
- width, height,
- src->dc,
- src_x + itx, src_y + ity,
- SRCCOPY))
- return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
-
- return CAIRO_STATUS_SUCCESS;
-
- } else if (integer_transform &&
- (src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) &&
- dst->format == CAIRO_FORMAT_RGB24 &&
- !src->base.repeat &&
- operator == CAIRO_OPERATOR_OVER) {
-
- BLENDFUNCTION blend_function;
-
- blend_function.BlendOp = AC_SRC_OVER;
- blend_function.BlendFlags = 0;
- blend_function.SourceConstantAlpha = alpha;
- blend_function.AlphaFormat = src->format == CAIRO_FORMAT_ARGB32 ? AC_SRC_ALPHA : 0;
-
- if (!AlphaBlend (dst->dc,
- dst_x, dst_y,
- width, height,
- src->dc,
- src_x + itx, src_y + ity,
- width, height,
- blend_function))
- return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_status_t status;
- COLORREF new_color;
- HBRUSH new_brush;
- int i;
-
- /* If we have a local image, use the fallback code; it will be as fast
- * as calling out to GDI.
- */
- if (surface->image)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* We could support possibly support more operators for color->alpha = 0xffff.
- * for CAIRO_OPERATOR_SRC, alpha doesn't matter since we know the destination
- * image doesn't have alpha. (surface->pixman_image is non-NULL for all
- * surfaces with alpha.)
- */
- if (operator != CAIRO_OPERATOR_SRC)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
-
- new_brush = CreateSolidBrush (new_color);
- if (!new_brush)
- return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
-
- for (i = 0; i < num_rects; i++) {
- RECT rect;
-
- rect.left = rects[i].x;
- rect.top = rects[i].y;
- rect.right = rects[i].x + rects[i].width;
- rect.bottom = rects[i].y + rects[i].height;
-
- if (!FillRect (surface->dc, &rect, new_brush))
- goto FAIL;
- }
-
- DeleteObject (new_brush);
-
- return CAIRO_STATUS_SUCCESS;
-
- FAIL:
- status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
-
- DeleteObject (new_brush);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_win32_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_win32_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
- /* If we are in-memory, then we set the clip on the image surface
- * as well as on the underlying GDI surface.
- */
- if (surface->image)
- _cairo_surface_set_clip_region (surface->image, region);
-
- /* The semantics we want is that any clip set by Cairo combines
- * is intersected with the clip on device context that the
- * surface was created for. To implement this, we need to
- * save the original clip when first setting a clip on surface.
- */
-
- if (region == NULL) {
- /* Clear any clip set by Cairo, return to the original */
-
- if (surface->set_clip) {
- if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
- return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
-
- if (surface->saved_clip) {
- DeleteObject (surface->saved_clip);
- surface->saved_clip = NULL;
- }
-
- surface->set_clip = 0;
- }
-
-
- return CAIRO_STATUS_SUCCESS;
-
- } else {
- pixman_box16_t *boxes = pixman_region_rects (region);
- int num_boxes = pixman_region_num_rects (region);
- pixman_box16_t *extents = pixman_region_extents (region);
- RGNDATA *data;
- size_t data_size;
- RECT *rects;
- int i;
- HRGN gdi_region;
-
- /* Create a GDI region for the cairo region */
-
- data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT);
- data = malloc (data_size);
- if (!data)
- return CAIRO_STATUS_NO_MEMORY;
- rects = (RECT *)data->Buffer;
-
- data->rdh.dwSize = sizeof (RGNDATAHEADER);
- data->rdh.iType = RDH_RECTANGLES;
- data->rdh.nCount = num_boxes;
- data->rdh.nRgnSize = num_boxes * sizeof (RECT);
- data->rdh.rcBound.left = extents->x1;
- data->rdh.rcBound.top = extents->y1;
- data->rdh.rcBound.right = extents->x2;
- data->rdh.rcBound.bottom = extents->y2;
-
- for (i = 0; i < num_boxes; i++) {
- rects[i].left = boxes[i].x1;
- rects[i].top = boxes[i].y1;
- rects[i].right = boxes[i].x2;
- rects[i].bottom = boxes[i].y2;
- }
-
- gdi_region = ExtCreateRegion (NULL, data_size, data);
- free (data);
-
- if (!gdi_region)
- return CAIRO_STATUS_NO_MEMORY;
-
- if (surface->set_clip) {
- /* Combine the new region with the original clip */
-
- if (surface->saved_clip) {
- if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR)
- goto FAIL;
- }
-
- if (SelectClipRgn (surface->dc, gdi_region) == ERROR)
- goto FAIL;
-
- } else {
- /* Save the the current region */
-
- surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
- if (!surface->saved_clip) {
- goto FAIL; }
-
- /* This function has no error return! */
- if (GetClipRgn (surface->dc, surface->saved_clip) == 0) { /* No clip */
- DeleteObject (surface->saved_clip);
- surface->saved_clip = NULL;
- }
-
- if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
- goto FAIL;
-
- surface->set_clip = 1;
- }
-
- DeleteObject (gdi_region);
- return CAIRO_STATUS_SUCCESS;
-
- FAIL:
- status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
- DeleteObject (gdi_region);
- return status;
- }
-}
-
-static cairo_status_t
-_cairo_win32_surface_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_surface_t *
-cairo_win32_surface_create (HDC hdc)
-{
- cairo_win32_surface_t *surface;
- RECT rect;
-
- /* Try to figure out the drawing bounds for the Device context
- */
- if (GetClipBox (hdc, &rect) == ERROR) {
- _cairo_win32_print_gdi_error ("cairo_win32_surface_create");
- return NULL;
- }
-
- surface = malloc (sizeof (cairo_win32_surface_t));
- if (!surface)
- return NULL;
-
- surface->image = NULL;
- surface->format = CAIRO_FORMAT_RGB24;
-
- surface->dc = hdc;
- surface->bitmap = NULL;
-
- surface->clip_rect.x = rect.left;
- surface->clip_rect.y = rect.top;
- surface->clip_rect.width = rect.right - rect.left;
- surface->clip_rect.height = rect.bottom - rect.top;
-
- surface->set_clip = 0;
- surface->saved_clip = NULL;
-
- _cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
-
- return (cairo_surface_t *)surface;
-}
-
-/**
- * _cairo_surface_is_win32:
- * @surface: a #cairo_surface_t
- *
- * Checks if a surface is an #cairo_win32_surface_t
- *
- * Return value: True if the surface is an win32 surface
- **/
-int
-_cairo_surface_is_win32 (cairo_surface_t *surface)
-{
- return surface->backend == &cairo_win32_surface_backend;
-}
-
-static const cairo_surface_backend_t cairo_win32_surface_backend = {
- _cairo_win32_surface_create_similar,
- _cairo_win32_surface_destroy,
- _cairo_win32_surface_pixels_per_inch,
- _cairo_win32_surface_acquire_source_image,
- _cairo_win32_surface_release_source_image,
- _cairo_win32_surface_acquire_dest_image,
- _cairo_win32_surface_release_dest_image,
- _cairo_win32_surface_clone_similar,
- _cairo_win32_surface_composite,
- _cairo_win32_surface_fill_rectangles,
- _cairo_win32_surface_composite_trapezoids,
- _cairo_win32_surface_copy_page,
- _cairo_win32_surface_show_page,
- _cairo_win32_surface_set_clip_region,
- _cairo_win32_surface_show_glyphs
-};
diff --git a/src/cairo_xcb_surface.c b/src/cairo_xcb_surface.c
deleted file mode 100644
index 0694b77a2..000000000
--- a/src/cairo_xcb_surface.c
+++ /dev/null
@@ -1,978 +0,0 @@
-/* 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@cworth.org>
- */
-
-#include "cairoint.h"
-#include "cairo-xcb.h"
-
-cairo_surface_t *
-cairo_xcb_surface_create (XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format);
-
-#define AllPlanes ((unsigned long)~0L)
-
-static XCBRenderPICTFORMAT
-format_from_visual(XCBConnection *c, XCBVISUALID visual)
-{
- static const XCBRenderPICTFORMAT nil = { 0 };
- XCBRenderQueryPictFormatsRep *r;
- XCBRenderPICTSCREENIter si;
- XCBRenderPICTDEPTHIter di;
- XCBRenderPICTVISUALIter vi;
-
- r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
- if(!r)
- return nil;
-
- for(si = XCBRenderQueryPictFormatsScreensIter(r); si.rem; XCBRenderPICTSCREENNext(&si))
- for(di = XCBRenderPICTSCREENDepthsIter(si.data); di.rem; XCBRenderPICTDEPTHNext(&di))
- for(vi = XCBRenderPICTDEPTHVisualsIter(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi))
- if(vi.data->visual.id == visual.id)
- {
- XCBRenderPICTFORMAT ret = vi.data->format;
- free(r);
- return ret;
- }
-
- return nil;
-}
-
-static XCBRenderPICTFORMAT
-format_from_cairo(XCBConnection *c, cairo_format_t fmt)
-{
- XCBRenderPICTFORMAT ret = { 0 };
- struct tmpl_t {
- XCBRenderDIRECTFORMAT direct;
- CARD8 depth;
- };
- static const struct tmpl_t templates[] = {
- /* CAIRO_FORMAT_ARGB32 */
- {
- {
- 16, 0xff,
- 8, 0xff,
- 0, 0xff,
- 24, 0xff
- },
- 32
- },
- /* CAIRO_FORMAT_RGB24 */
- {
- {
- 16, 0xff,
- 8, 0xff,
- 0, 0xff,
- 0, 0x00
- },
- 24
- },
- /* CAIRO_FORMAT_A8 */
- {
- {
- 0, 0x00,
- 0, 0x00,
- 0, 0x00,
- 0, 0xff
- },
- 8
- },
- /* CAIRO_FORMAT_A1 */
- {
- {
- 0, 0x00,
- 0, 0x00,
- 0, 0x00,
- 0, 0x01
- },
- 1
- },
- };
- const struct tmpl_t *tmpl;
- XCBRenderQueryPictFormatsRep *r;
- XCBRenderPICTFORMINFOIter fi;
-
- if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates)))
- return ret;
- tmpl = templates + fmt;
-
- r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
- if(!r)
- return ret;
-
- for(fi = XCBRenderQueryPictFormatsFormatsIter(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
- {
- const XCBRenderDIRECTFORMAT *t, *f;
- if(fi.data->type != XCBRenderPictTypeDirect)
- continue;
- if(fi.data->depth != tmpl->depth)
- continue;
- t = &tmpl->direct;
- f = &fi.data->direct;
- if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift))
- continue;
- if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift))
- continue;
- if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift))
- continue;
- if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift))
- continue;
-
- ret = fi.data->id;
- }
-
- free(r);
- return ret;
-}
-
-void
-cairo_set_target_xcb (cairo_t *cr,
- XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format)
-{
- cairo_surface_t *surface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_xcb_surface_create (dpy, drawable, visual, format);
- 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_xcb_surface {
- cairo_surface_t base;
-
- XCBConnection *dpy;
- XCBGCONTEXT gc;
- XCBDRAWABLE drawable;
- int owns_pixmap;
- XCBVISUALTYPE *visual;
- cairo_format_t format;
-
- int render_major;
- int render_minor;
-
- int width;
- int height;
-
- XCBRenderPICTURE picture;
-} cairo_xcb_surface_t;
-
-#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
- (((surface)->render_major > major) || \
- (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
-
-#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-
-#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-
-#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-
-#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-
-static int
-_CAIRO_FORMAT_DEPTH (cairo_format_t format)
-{
- switch (format) {
- case CAIRO_FORMAT_A1:
- return 1;
- case CAIRO_FORMAT_A8:
- return 8;
- case CAIRO_FORMAT_RGB24:
- return 24;
- case CAIRO_FORMAT_ARGB32:
- default:
- return 32;
- }
-}
-
-static cairo_surface_t *
-_cairo_xcb_surface_create_similar (void *abstract_src,
- cairo_format_t format,
- int drawable,
- int width,
- int height)
-{
- cairo_xcb_surface_t *src = abstract_src;
- XCBConnection *dpy = src->dpy;
- XCBDRAWABLE d;
- cairo_xcb_surface_t *surface;
-
- /* XXX: There's a pretty lame heuristic here. This assumes that
- * all non-Render X servers do not support depth-32 pixmaps, (and
- * that they do support depths 1, 8, and 24). Obviously, it would
- * be much better to check the depths that are actually
- * supported. */
- if (!dpy
- || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)
- && format == CAIRO_FORMAT_ARGB32))
- {
- return NULL;
- }
-
- d.pixmap = XCBPIXMAPNew (dpy);
- XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
- d.pixmap, src->drawable,
- width, height);
-
- surface = (cairo_xcb_surface_t *)
- cairo_xcb_surface_create (dpy, d, NULL, format);
- surface->owns_pixmap = 1;
-
- surface->width = width;
- surface->height = height;
-
- return &surface->base;
-}
-
-static void
-_cairo_xcb_surface_destroy (void *abstract_surface)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- if (surface->picture.xid)
- XCBRenderFreePicture (surface->dpy, surface->picture);
-
- if (surface->owns_pixmap)
- XCBFreePixmap (surface->dpy, surface->drawable.pixmap);
-
- if (surface->gc.xid)
- XCBFreeGC (surface->dpy, surface->gc);
-
- surface->dpy = 0;
-
- free (surface);
-}
-
-static double
-_cairo_xcb_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We should really get this value from somewhere like Xft.dpy */
- return 96.0;
-}
-
-static int
-bits_per_pixel(XCBConnection *c, int depth)
-{
- XCBFORMAT *fmt = XCBConnSetupSuccessRepPixmapFormats(XCBGetSetup(c));
- XCBFORMAT *fmtend = fmt + XCBConnSetupSuccessRepPixmapFormatsLength(XCBGetSetup(c));
-
- for(; fmt != fmtend; ++fmt)
- if(fmt->depth == depth)
- return fmt->bits_per_pixel;
-
- if(depth <= 4)
- return 4;
- if(depth <= 8)
- return 8;
- if(depth <= 16)
- return 16;
- return 32;
-}
-
-static int
-bytes_per_line(XCBConnection *c, int width, int bpp)
-{
- int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
- return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
-}
-
-static cairo_status_t
-_get_image_surface (cairo_xcb_surface_t *surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect)
-{
- cairo_image_surface_t *image;
- XCBGetGeometryRep *geomrep;
- XCBGetImageRep *imagerep;
- int bpp;
- int x1, y1, x2, y2;
-
- geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0);
- if(!geomrep)
- return 0;
-
- surface->width = geomrep->width;
- surface->height = geomrep->height;
- free(geomrep);
-
- x1 = 0;
- y1 = 0;
- x2 = surface->width;
- y2 = surface->height;
-
- if (interest_rect) {
- if (interest_rect->x > x1)
- x1 = interest_rect->x;
- if (interest_rect->y > y1)
- y1 = interest_rect->y;
- if (interest_rect->x + interest_rect->width < x2)
- x2 = interest_rect->x + interest_rect->width;
- if (interest_rect->y + interest_rect->height < y2)
- y2 = interest_rect->y + interest_rect->height;
-
- if (x1 >= x2 || y1 >= y2) {
- *image_out = NULL;
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
- if (image_rect) {
- image_rect->x = x1;
- image_rect->y = y1;
- image_rect->width = x2 - x1;
- image_rect->height = y2 - y1;
- }
-
- imagerep = XCBGetImageReply(surface->dpy,
- XCBGetImage(surface->dpy, ZPixmap,
- surface->drawable,
- x1, y1,
- x2 - x1, y2 - y1,
- AllPlanes), 0);
- if(!imagerep)
- return 0;
-
- bpp = bits_per_pixel(surface->dpy, imagerep->depth);
-
- if (surface->visual) {
- cairo_format_masks_t masks;
-
- /* XXX: Add support here for pictures with external alpha? */
-
- masks.bpp = bpp;
- masks.alpha_mask = 0;
- masks.red_mask = surface->visual->red_mask;
- masks.green_mask = surface->visual->green_mask;
- masks.blue_mask = surface->visual->blue_mask;
-
- image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep),
- &masks,
- x2 - x1,
- y2 - y1,
- bytes_per_line(surface->dpy, surface->width, bpp));
- } else {
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (XCBGetImageData(imagerep),
- surface->format,
- x2 - x1,
- y2 - y1,
- bytes_per_line(surface->dpy, surface->width, bpp));
- }
-
- /* Let the surface take ownership of the data */
- /* XXX: Can probably come up with a cleaner API here. */
- _cairo_image_surface_assume_ownership_of_data (image);
- /* FIXME: imagerep can't be freed correctly, I think. must copy. :-( */
-
- _cairo_image_surface_set_repeat (image, surface->base.repeat);
- _cairo_image_surface_set_matrix (image, &(surface->base.matrix));
-
- *image_out = image;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
-{
- if (surface->gc.xid)
- return;
-
- surface->gc = XCBGCONTEXTNew(surface->dpy);
- XCBCreateGC (surface->dpy, surface->gc, surface->drawable, 0, 0);
-}
-
-static cairo_status_t
-_draw_image_surface (cairo_xcb_surface_t *surface,
- cairo_image_surface_t *image,
- int dst_x,
- int dst_y)
-{
- int bpp, data_len;
-
- _cairo_xcb_surface_ensure_gc (surface);
- bpp = bits_per_pixel(surface->dpy, image->depth);
- data_len = bytes_per_line(surface->dpy, image->width, bpp) * image->height;
- XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
- image->width,
- image->height,
- dst_x, dst_y,
- /* left_pad */ 0, image->depth,
- data_len, image->data);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
-
- status = _get_image_surface (surface, NULL, &image, NULL);
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_set_filter (&image->base, surface->base.filter);
- cairo_surface_set_matrix (&image->base, &surface->base.matrix);
- cairo_surface_set_repeat (&image->base, surface->base.repeat);
-
- *image_out = image;
- }
-
- return status;
-}
-
-static void
-_cairo_xcb_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_xcb_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect_out,
- void **image_extra)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
-
- status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
- if (status == CAIRO_STATUS_SUCCESS)
- *image_out = image;
-
- return status;
-}
-
-static void
-_cairo_xcb_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
-
- /* ignore errors */
- _draw_image_surface (surface, image, image_rect->x, image_rect->y);
-
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_xcb_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- cairo_xcb_surface_t *clone;
-
- if (src->backend == surface->base.backend ) {
- cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
-
- if (xcb_src->dpy == surface->dpy) {
- *clone_out = src;
- cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
- } else if (_cairo_surface_is_image (src)) {
- cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
-
- clone = (cairo_xcb_surface_t *)
- _cairo_xcb_surface_create_similar (surface, image_src->format, 0,
- image_src->width, image_src->height);
- if (clone == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- _draw_image_surface (clone, image_src, 0, 0);
-
- *clone_out = &clone->base;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
- cairo_matrix_t *matrix)
-{
- XCBRenderTRANSFORM xtransform;
-
- if (!surface->picture.xid)
- return CAIRO_STATUS_SUCCESS;
-
- xtransform.matrix11 = _cairo_fixed_from_double (matrix->m[0][0]);
- xtransform.matrix12 = _cairo_fixed_from_double (matrix->m[1][0]);
- xtransform.matrix13 = _cairo_fixed_from_double (matrix->m[2][0]);
-
- xtransform.matrix21 = _cairo_fixed_from_double (matrix->m[0][1]);
- xtransform.matrix22 = _cairo_fixed_from_double (matrix->m[1][1]);
- xtransform.matrix23 = _cairo_fixed_from_double (matrix->m[2][1]);
-
- xtransform.matrix31 = 0;
- xtransform.matrix32 = 0;
- xtransform.matrix33 = _cairo_fixed_from_double (1);
-
- if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
- {
- static const XCBRenderTRANSFORM identity = {
- 1 << 16, 0x00000, 0x00000,
- 0x00000, 1 << 16, 0x00000,
- 0x00000, 0x00000, 1 << 16
- };
-
- if (memcmp (&xtransform, &identity, sizeof (XCBRenderTRANSFORM)) == 0)
- return CAIRO_STATUS_SUCCESS;
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
- cairo_filter_t filter)
-{
- char *render_filter;
-
- if (!surface->picture.xid)
- return CAIRO_STATUS_SUCCESS;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
- {
- if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
- return CAIRO_STATUS_SUCCESS;
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- render_filter = "fast";
- break;
- case CAIRO_FILTER_GOOD:
- render_filter = "good";
- break;
- case CAIRO_FILTER_BEST:
- render_filter = "best";
- break;
- case CAIRO_FILTER_NEAREST:
- render_filter = "nearest";
- break;
- case CAIRO_FILTER_BILINEAR:
- render_filter = "bilinear";
- break;
- default:
- render_filter = "best";
- break;
- }
-
- XCBRenderSetPictureFilter(surface->dpy, surface->picture,
- strlen(render_filter), render_filter, 0, NULL);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat)
-{
- CARD32 mask = XCBRenderCPRepeat;
- CARD32 pa[] = { repeat };
-
- if (!surface->picture.xid)
- return CAIRO_STATUS_SUCCESS;
-
- XCBRenderChangePicture (surface->dpy, surface->picture, mask, pa);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface,
- cairo_surface_attributes_t *attributes)
-{
- cairo_int_status_t status;
-
- status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix);
- if (status)
- return status;
-
- switch (attributes->extend) {
- case CAIRO_EXTEND_NONE:
- _cairo_xcb_surface_set_repeat (surface, 0);
- break;
- case CAIRO_EXTEND_REPEAT:
- _cairo_xcb_surface_set_repeat (surface, 1);
- break;
- case CAIRO_EXTEND_REFLECT:
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static int
-_render_operator (cairo_operator_t operator)
-{
- switch (operator) {
- case CAIRO_OPERATOR_CLEAR:
- return XCBRenderPictOpClear;
- case CAIRO_OPERATOR_SRC:
- return XCBRenderPictOpSrc;
- case CAIRO_OPERATOR_DST:
- return XCBRenderPictOpDst;
- case CAIRO_OPERATOR_OVER:
- return XCBRenderPictOpOver;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return XCBRenderPictOpOverReverse;
- case CAIRO_OPERATOR_IN:
- return XCBRenderPictOpIn;
- case CAIRO_OPERATOR_IN_REVERSE:
- return XCBRenderPictOpInReverse;
- case CAIRO_OPERATOR_OUT:
- return XCBRenderPictOpOut;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return XCBRenderPictOpOutReverse;
- case CAIRO_OPERATOR_ATOP:
- return XCBRenderPictOpAtop;
- case CAIRO_OPERATOR_ATOP_REVERSE:
- return XCBRenderPictOpAtopReverse;
- case CAIRO_OPERATOR_XOR:
- return XCBRenderPictOpXor;
- case CAIRO_OPERATOR_ADD:
- return XCBRenderPictOpAdd;
- case CAIRO_OPERATOR_SATURATE:
- return XCBRenderPictOpSaturate;
- default:
- return XCBRenderPictOpOver;
- }
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src_pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_surface_attributes_t src_attr, mask_attr;
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src;
- cairo_xcb_surface_t *mask;
- cairo_int_status_t status;
-
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
- &dst->base,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- (cairo_surface_t **) &src,
- (cairo_surface_t **) &mask,
- &src_attr, &mask_attr);
- if (status)
- return status;
-
- status = _cairo_xcb_surface_set_attributes (src, &src_attr);
- if (CAIRO_OK (status))
- {
- if (mask)
- {
- status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
- if (CAIRO_OK (status))
- XCBRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- mask->picture,
- dst->picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- mask_x + mask_attr.x_offset,
- mask_y + mask_attr.y_offset,
- dst_x, dst_y,
- width, height);
- }
- else
- {
- static XCBRenderPICTURE maskpict = { 0 };
-
- XCBRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- maskpict,
- dst->picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- }
- }
-
- if (mask)
- _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- XCBRenderCOLOR render_color;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- render_color.red = color->red_short;
- render_color.green = color->green_short;
- render_color.blue = color->blue_short;
- render_color.alpha = color->alpha_short;
-
- /* XXX: This XCBRECTANGLE cast is evil... it needs to go away somehow. */
- XCBRenderFillRectangles (surface->dpy,
- _render_operator (operator),
- surface->picture,
- render_color, num_rects, (XCBRECTANGLE *) rects);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_surface_attributes_t attributes;
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src;
- cairo_int_status_t status;
- int render_reference_x, render_reference_y;
- int render_src_x, render_src_y;
-
- if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- src_x, src_y, width, height,
- (cairo_surface_t **) &src,
- &attributes);
- if (status)
- return status;
-
- if (traps[0].left.p1.y < traps[0].left.p2.y) {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
- } else {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
- }
-
- render_src_x = src_x + render_reference_x - dst_x;
- render_src_y = src_y + render_reference_y - dst_y;
-
- /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
- /* XXX: format_from_cairo is slow. should cache something. */
- status = _cairo_xcb_surface_set_attributes (src, &attributes);
- if (CAIRO_OK (status))
- XCBRenderTrapezoids (dst->dpy,
- _render_operator (operator),
- src->picture, dst->picture,
- format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
- render_src_x + attributes.x_offset,
- render_src_y + attributes.y_offset,
- num_traps, (XCBRenderTRAP *) traps);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- /* FIXME */
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static const cairo_surface_backend_t cairo_xcb_surface_backend = {
- _cairo_xcb_surface_create_similar,
- _cairo_xcb_surface_destroy,
- _cairo_xcb_surface_pixels_per_inch,
- _cairo_xcb_surface_acquire_source_image,
- _cairo_xcb_surface_release_source_image,
- _cairo_xcb_surface_acquire_dest_image,
- _cairo_xcb_surface_release_dest_image,
- _cairo_xcb_surface_clone_similar,
- _cairo_xcb_surface_composite,
- _cairo_xcb_surface_fill_rectangles,
- _cairo_xcb_surface_composite_trapezoids,
- _cairo_xcb_surface_copy_page,
- _cairo_xcb_surface_show_page,
- _cairo_xcb_surface_set_clip_region,
- NULL /* show_glyphs */
-};
-
-static void
-query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface)
-{
- XCBRenderQueryVersionRep *r;
-
- surface->render_major = -1;
- surface->render_minor = -1;
-
- if (!XCBRenderInit(c))
- return;
-
- r = XCBRenderQueryVersionReply(c, XCBRenderQueryVersion(c, 0, 6), 0);
- if (!r)
- return;
-
- surface->render_major = r->major_version;
- surface->render_minor = r->minor_version;
- free(r);
-}
-
-cairo_surface_t *
-cairo_xcb_surface_create (XCBConnection *dpy,
- XCBDRAWABLE drawable,
- XCBVISUALTYPE *visual,
- cairo_format_t format)
-{
- cairo_xcb_surface_t *surface;
-
- surface = malloc (sizeof (cairo_xcb_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend);
-
- surface->dpy = dpy;
- surface->gc.xid = 0;
- surface->drawable = drawable;
- surface->owns_pixmap = 0;
- surface->visual = visual;
- surface->format = format;
-
- query_render_version(dpy, surface);
-
- if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
- {
- XCBRenderPICTFORMAT fmt;
- if(visual)
- fmt = format_from_visual (dpy, visual->visual_id);
- else
- fmt = format_from_cairo (dpy, format);
- surface->picture = XCBRenderPICTURENew(dpy);
- XCBRenderCreatePicture (dpy, surface->picture, drawable,
- fmt, 0, NULL);
- }
- else
- surface->picture.xid = 0;
-
- return (cairo_surface_t *) surface;
-}
diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c
deleted file mode 100644
index 3eaef57e5..000000000
--- a/src/cairo_xlib_surface.c
+++ /dev/null
@@ -1,1530 +0,0 @@
-/* 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@cworth.org>
- */
-
-#include "cairoint.h"
-#include "cairo-xlib.h"
-
-/**
- * cairo_set_target_drawable:
- * @cr: a #cairo_t
- * @dpy: an X display
- * @drawable: a window or pixmap on the default screen of @dpy
- *
- * Directs output for a #cairo_t to an Xlib drawable. @drawable must
- * be a Window or Pixmap on the default screen of @dpy using the
- * default colormap and visual. Using this function is slow because
- * the function must retrieve information about @drawable from the X
- * server.
-
- * The combination of cairo_xlib_surface_create() and
- * cairo_set_target_surface() is somewhat more flexible, although
- * it still is slow.
- **/
-void
-cairo_set_target_drawable (cairo_t *cr,
- Display *dpy,
- Drawable drawable)
-{
- cairo_surface_t *surface;
-
- if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
- return;
-
- surface = cairo_xlib_surface_create (dpy, drawable,
- DefaultVisual (dpy, DefaultScreen (dpy)),
- 0,
- DefaultColormap (dpy, DefaultScreen (dpy)));
- 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_xlib_surface {
- cairo_surface_t base;
-
- Display *dpy;
- GC gc;
- Drawable drawable;
- int owns_pixmap;
- Visual *visual;
- cairo_format_t format;
-
- int render_major;
- int render_minor;
-
- int width;
- int height;
-
- Picture picture;
-} cairo_xlib_surface_t;
-
-#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
- (((surface)->render_major > major) || \
- (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
-
-#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-
-
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-
-#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-
-#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-
-#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-
-static int
-_CAIRO_FORMAT_DEPTH (cairo_format_t format)
-{
- switch (format) {
- case CAIRO_FORMAT_A1:
- return 1;
- case CAIRO_FORMAT_A8:
- return 8;
- case CAIRO_FORMAT_RGB24:
- return 24;
- case CAIRO_FORMAT_ARGB32:
- default:
- return 32;
- }
-}
-
-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,
- int width,
- int height)
-{
- cairo_xlib_surface_t *src = abstract_src;
- Display *dpy = src->dpy;
- int scr;
- Pixmap pix;
- cairo_xlib_surface_t *surface;
-
- /* As a good first approximation, if the display doesn't have COMPOSITE,
- * we're better off using image surfaces for all temporary operations
- */
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE(src)) {
- return cairo_image_surface_create (format, width, height);
- }
-
- scr = DefaultScreen (dpy);
-
- pix = XCreatePixmap (dpy, DefaultRootWindow (dpy),
- width <= 0 ? 1 : width, height <= 0 ? 1 : height,
- _CAIRO_FORMAT_DEPTH (format));
-
- surface = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_with_size (dpy, pix, NULL, format,
- DefaultColormap (dpy, scr),
- width, height);
- surface->owns_pixmap = 1;
-
- surface->width = width;
- surface->height = height;
-
- return &surface->base;
-}
-
-static void
-_cairo_xlib_surface_destroy (void *abstract_surface)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- if (surface->picture)
- XRenderFreePicture (surface->dpy, surface->picture);
-
- if (surface->owns_pixmap)
- XFreePixmap (surface->dpy, surface->drawable);
-
- if (surface->gc)
- XFreeGC (surface->dpy, surface->gc);
-
- surface->dpy = 0;
-
- free (surface);
-}
-
-static double
-_cairo_xlib_surface_pixels_per_inch (void *abstract_surface)
-{
- /* XXX: We should really get this value from somewhere like Xft.dpy */
- return 96.0;
-}
-
-static cairo_status_t
-_get_image_surface (cairo_xlib_surface_t *surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect)
-{
- cairo_image_surface_t *image;
- XImage *ximage;
- Window root_ignore;
- int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
- int x1, y1, x2, y2;
-
- XGetGeometry (surface->dpy,
- surface->drawable,
- &root_ignore, &x_ignore, &y_ignore,
- &surface->width, &surface->height,
- &bwidth_ignore, &depth_ignore);
-
- x1 = 0;
- y1 = 0;
- x2 = surface->width;
- y2 = surface->height;
-
- if (interest_rect) {
- if (interest_rect->x > x1)
- x1 = interest_rect->x;
- if (interest_rect->y > y1)
- y1 = interest_rect->y;
- if (interest_rect->x + interest_rect->width < x2)
- x2 = interest_rect->x + interest_rect->width;
- if (interest_rect->y + interest_rect->height < y2)
- y2 = interest_rect->y + interest_rect->height;
-
- if (x1 >= x2 || y1 >= y2) {
- *image_out = NULL;
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
- if (image_rect) {
- image_rect->x = x1;
- image_rect->y = y1;
- image_rect->width = x2 - x1;
- image_rect->height = y2 - y1;
- }
-
- /* XXX: This should try to use the XShm extension if availible */
- ximage = XGetImage (surface->dpy,
- surface->drawable,
- x1, y1,
- x2 - x1, y2 - y1,
- AllPlanes, ZPixmap);
-
- if (surface->visual) {
- cairo_format_masks_t masks;
-
- /* XXX: Add support here for pictures with external alpha? */
-
- masks.bpp = ximage->bits_per_pixel;
- masks.alpha_mask = 0;
- masks.red_mask = surface->visual->red_mask;
- masks.green_mask = surface->visual->green_mask;
- masks.blue_mask = surface->visual->blue_mask;
-
- image = _cairo_image_surface_create_with_masks (ximage->data,
- &masks,
- ximage->width,
- ximage->height,
- ximage->bytes_per_line);
- } else {
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (ximage->data,
- surface->format,
- ximage->width,
- ximage->height,
- ximage->bytes_per_line);
- }
-
- /* Let the surface take ownership of the data */
- /* XXX: Can probably come up with a cleaner API here. */
- _cairo_image_surface_assume_ownership_of_data (image);
- ximage->data = NULL;
- XDestroyImage (ximage);
-
- _cairo_image_surface_set_repeat (image, surface->base.repeat);
- _cairo_image_surface_set_matrix (image, &(surface->base.matrix));
-
- *image_out = image;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
-{
- if (surface->gc)
- return;
-
- surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
-}
-
-static cairo_status_t
-_draw_image_surface (cairo_xlib_surface_t *surface,
- cairo_image_surface_t *image,
- int dst_x,
- int dst_y)
-{
- XImage *ximage;
- unsigned bitmap_pad;
-
- if (image->depth > 16)
- bitmap_pad = 32;
- else if (image->depth > 8)
- bitmap_pad = 16;
- else
- bitmap_pad = 8;
-
- ximage = XCreateImage (surface->dpy,
- DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)),
- image->depth,
- ZPixmap,
- 0,
- image->data,
- image->width,
- image->height,
- bitmap_pad,
- image->stride);
- if (ximage == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_xlib_surface_ensure_gc (surface);
- XPutImage(surface->dpy, surface->drawable, surface->gc,
- ximage, 0, 0, dst_x, dst_y,
- image->width, image->height);
-
- /* Foolish XDestroyImage thinks it can free my data, but I won't
- stand for it. */
- ximage->data = NULL;
- XDestroyImage (ximage);
-
- return CAIRO_STATUS_SUCCESS;
-
-}
-
-static cairo_status_t
-_cairo_xlib_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
-
- status = _get_image_surface (surface, NULL, &image, NULL);
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_set_filter (&image->base, surface->base.filter);
- cairo_surface_set_matrix (&image->base, &surface->base.matrix);
- cairo_surface_set_repeat (&image->base, surface->base.repeat);
-
- *image_out = image;
- }
-
- return status;
-}
-
-static void
-_cairo_xlib_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_xlib_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_t *image_rect_out,
- void **image_extra)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
-
- status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
- if (status == CAIRO_STATUS_SUCCESS)
- *image_out = image;
-
- return status;
-}
-
-static void
-_cairo_xlib_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_t *image_rect,
- void *image_extra)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
-
- /* ignore errors */
- _draw_image_surface (surface, image, image_rect->x, image_rect->y);
-
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_status_t
-_cairo_xlib_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_surface_t **clone_out)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_xlib_surface_t *clone;
-
- if (src->backend == surface->base.backend ) {
- cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src;
-
- if (xlib_src->dpy == surface->dpy) {
- *clone_out = src;
- cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
- } else if (_cairo_surface_is_image (src)) {
- cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
-
- clone = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_similar (surface, image_src->format, 0,
- image_src->width, image_src->height);
- if (clone == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- _draw_image_surface (clone, image_src, 0, 0);
-
- *clone_out = &clone->base;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
- cairo_matrix_t *matrix)
-{
- XTransform xtransform;
-
- if (!surface->picture)
- return CAIRO_STATUS_SUCCESS;
-
- xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
-
- xtransform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- xtransform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- xtransform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
-
- xtransform.matrix[2][0] = 0;
- xtransform.matrix[2][1] = 0;
- xtransform.matrix[2][2] = _cairo_fixed_from_double (1);
-
- if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
- {
- static const XTransform identity = { {
- { 1 << 16, 0x00000, 0x00000 },
- { 0x00000, 1 << 16, 0x00000 },
- { 0x00000, 0x00000, 1 << 16 },
- } };
-
- if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0)
- return CAIRO_STATUS_SUCCESS;
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
- cairo_filter_t filter)
-{
- char *render_filter;
-
- if (!surface->picture)
- return CAIRO_STATUS_SUCCESS;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
- {
- if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
- return CAIRO_STATUS_SUCCESS;
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- render_filter = FilterFast;
- break;
- case CAIRO_FILTER_GOOD:
- render_filter = FilterGood;
- break;
- case CAIRO_FILTER_BEST:
- render_filter = FilterBest;
- break;
- case CAIRO_FILTER_NEAREST:
- render_filter = FilterNearest;
- break;
- case CAIRO_FILTER_BILINEAR:
- render_filter = FilterBilinear;
- break;
- default:
- render_filter = FilterBest;
- break;
- }
-
- XRenderSetPictureFilter (surface->dpy, surface->picture,
- render_filter, NULL, 0);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat)
-{
- XRenderPictureAttributes pa;
- unsigned long mask;
-
- if (!surface->picture)
- return CAIRO_STATUS_SUCCESS;
-
- mask = CPRepeat;
- pa.repeat = repeat;
-
- XRenderChangePicture (surface->dpy, surface->picture, mask, &pa);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
- cairo_surface_attributes_t *attributes)
-{
- cairo_int_status_t status;
-
- status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix);
- if (status)
- return status;
-
- switch (attributes->extend) {
- case CAIRO_EXTEND_NONE:
- _cairo_xlib_surface_set_repeat (surface, 0);
- break;
- case CAIRO_EXTEND_REPEAT:
- _cairo_xlib_surface_set_repeat (surface, 1);
- break;
- case CAIRO_EXTEND_REFLECT:
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static int
-_render_operator (cairo_operator_t operator)
-{
- switch (operator) {
- case CAIRO_OPERATOR_CLEAR:
- return PictOpClear;
- case CAIRO_OPERATOR_SRC:
- return PictOpSrc;
- case CAIRO_OPERATOR_DST:
- return PictOpDst;
- case CAIRO_OPERATOR_OVER:
- return PictOpOver;
- case CAIRO_OPERATOR_OVER_REVERSE:
- return PictOpOverReverse;
- case CAIRO_OPERATOR_IN:
- return PictOpIn;
- case CAIRO_OPERATOR_IN_REVERSE:
- return PictOpInReverse;
- case CAIRO_OPERATOR_OUT:
- return PictOpOut;
- case CAIRO_OPERATOR_OUT_REVERSE:
- return PictOpOutReverse;
- case CAIRO_OPERATOR_ATOP:
- return PictOpAtop;
- case CAIRO_OPERATOR_ATOP_REVERSE:
- return PictOpAtopReverse;
- case CAIRO_OPERATOR_XOR:
- return PictOpXor;
- case CAIRO_OPERATOR_ADD:
- return PictOpAdd;
- case CAIRO_OPERATOR_SATURATE:
- return PictOpSaturate;
- default:
- return PictOpOver;
- }
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_composite (cairo_operator_t operator,
- cairo_pattern_t *src_pattern,
- cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_surface_attributes_t src_attr, mask_attr;
- cairo_xlib_surface_t *dst = abstract_dst;
- cairo_xlib_surface_t *src;
- cairo_xlib_surface_t *mask;
- cairo_int_status_t status;
-
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
- &dst->base,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- (cairo_surface_t **) &src,
- (cairo_surface_t **) &mask,
- &src_attr, &mask_attr);
- if (status)
- return status;
-
- status = _cairo_xlib_surface_set_attributes (src, &src_attr);
- if (CAIRO_OK (status))
- {
- if (mask)
- {
- status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
- if (CAIRO_OK (status))
- XRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- mask->picture,
- dst->picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- mask_x + mask_attr.x_offset,
- mask_y + mask_attr.y_offset,
- dst_x, dst_y,
- width, height);
- }
- else
- {
- XRenderComposite (dst->dpy,
- _render_operator (operator),
- src->picture,
- 0,
- dst->picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- }
- }
-
- if (mask)
- _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t operator,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- XRenderColor render_color;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- render_color.red = color->red_short;
- render_color.green = color->green_short;
- render_color.blue = color->blue_short;
- render_color.alpha = color->alpha_short;
-
- /* XXX: This XRectangle cast is evil... it needs to go away somehow. */
- XRenderFillRectangles (surface->dpy,
- _render_operator (operator),
- surface->picture,
- &render_color, (XRectangle *) rects, num_rects);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_surface_attributes_t attributes;
- cairo_xlib_surface_t *dst = abstract_dst;
- cairo_xlib_surface_t *src;
- cairo_int_status_t status;
- int render_reference_x, render_reference_y;
- int render_src_x, render_src_y;
-
- if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- src_x, src_y, width, height,
- (cairo_surface_t **) &src,
- &attributes);
- if (status)
- return status;
-
- if (traps[0].left.p1.y < traps[0].left.p2.y) {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
- } else {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
- }
-
- render_src_x = src_x + render_reference_x - dst_x;
- render_src_y = src_y + render_reference_y - dst_y;
-
- /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
- status = _cairo_xlib_surface_set_attributes (src, &attributes);
- if (CAIRO_OK (status))
- XRenderCompositeTrapezoids (dst->dpy,
- _render_operator (operator),
- src->picture, dst->picture,
- XRenderFindStandardFormat (dst->dpy, PictStandardA8),
- render_src_x + attributes.x_offset,
- render_src_y + attributes.y_offset,
- (XTrapezoid *) traps, num_traps);
-
- _cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_copy_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_show_page (void *abstract_surface)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
-
- Region xregion;
- XRectangle xr;
- XRectangle *rects = NULL;
- XGCValues gc_values;
- pixman_box16_t *box;
- cairo_xlib_surface_t *surf;
- int n, m;
-
- surf = (cairo_xlib_surface_t *) abstract_surface;
-
- if (region == NULL) {
- /* NULL region == reset the clip */
- xregion = XCreateRegion();
- xr.x = 0;
- xr.y = 0;
- xr.width = surf->width;
- xr.height = surf->height;
- XUnionRectWithRegion (&xr, xregion, xregion);
- rects = malloc(sizeof(XRectangle));
- if (rects == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- rects[0] = xr;
- m = 1;
-
- } else {
- n = pixman_region_num_rects (region);
- /* XXX: Are we sure these are the semantics we want for an
- * empty, (not null) region? */
- if (n == 0)
- return CAIRO_STATUS_SUCCESS;
- rects = malloc(sizeof(XRectangle) * n);
- if (rects == NULL)
- return CAIRO_STATUS_NO_MEMORY;
- box = pixman_region_rects (region);
- xregion = XCreateRegion();
-
- m = n;
- for (; n > 0; --n, ++box) {
- xr.x = (short) box->x1;
- xr.y = (short) box->y1;
- xr.width = (unsigned short) (box->x2 - box->x1);
- xr.height = (unsigned short) (box->y2 - box->y1);
- rects[n-1] = xr;
- XUnionRectWithRegion (&xr, xregion, xregion);
- }
- }
-
- _cairo_xlib_surface_ensure_gc (surf);
- XGetGCValues(surf->dpy, surf->gc, GCGraphicsExposures, &gc_values);
- XSetGraphicsExposures(surf->dpy, surf->gc, False);
- XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
- free(rects);
- if (surf->picture)
- XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
- XDestroyRegion(xregion);
- XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs);
-
-static const cairo_surface_backend_t cairo_xlib_surface_backend = {
- _cairo_xlib_surface_create_similar,
- _cairo_xlib_surface_destroy,
- _cairo_xlib_surface_pixels_per_inch,
- _cairo_xlib_surface_acquire_source_image,
- _cairo_xlib_surface_release_source_image,
- _cairo_xlib_surface_acquire_dest_image,
- _cairo_xlib_surface_release_dest_image,
- _cairo_xlib_surface_clone_similar,
- _cairo_xlib_surface_composite,
- _cairo_xlib_surface_fill_rectangles,
- _cairo_xlib_surface_composite_trapezoids,
- _cairo_xlib_surface_copy_page,
- _cairo_xlib_surface_show_page,
- _cairo_xlib_surface_set_clip_region,
- _cairo_xlib_surface_show_glyphs
-};
-
-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;
-
- surface = malloc (sizeof (cairo_xlib_surface_t));
- if (surface == NULL)
- return NULL;
-
- _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend);
-
- surface->visual = visual;
- surface->format = format;
-
- surface->dpy = dpy;
-
- surface->gc = 0;
- 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;
- }
-
- switch (format) {
- case CAIRO_FORMAT_A1:
- render_standard = PictStandardA1;
- break;
- case CAIRO_FORMAT_A8:
- render_standard = PictStandardA8;
- break;
- case CAIRO_FORMAT_RGB24:
- render_standard = PictStandardRGB24;
- break;
- case CAIRO_FORMAT_ARGB32:
- default:
- render_standard = PictStandardARGB32;
- break;
- }
-
- /* XXX: I'm currently ignoring the colormap. Is that bad? */
- if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
- surface->picture = XRenderCreatePicture (dpy, drawable,
- visual ?
- XRenderFindVisualFormat (dpy, visual) :
- XRenderFindStandardFormat (dpy, render_standard),
- 0, NULL);
- else
- surface->picture = 0;
-
- return (cairo_surface_t *) surface;
-}
-
-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 */
-
-typedef struct glyphset_cache {
- cairo_cache_t base;
- struct glyphset_cache *next;
- Display *display;
- XRenderPictFormat *a8_pict_format;
- GlyphSet glyphset;
- Glyph counter;
-} glyphset_cache_t;
-
-typedef struct {
- cairo_glyph_cache_key_t key;
- Glyph glyph;
- XGlyphInfo info;
- int refcount;
-} glyphset_cache_entry_t;
-
-static Glyph
-_next_xlib_glyph (glyphset_cache_t *cache)
-{
- return ++(cache->counter);
-}
-
-
-static cairo_status_t
-_xlib_glyphset_cache_create_entry (void *cache,
- void *key,
- void **return_entry)
-{
- glyphset_cache_t *g = (glyphset_cache_t *) cache;
- cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *)key;
- glyphset_cache_entry_t *v;
-
- cairo_status_t status;
-
- cairo_cache_t *im_cache;
- cairo_image_glyph_cache_entry_t *im;
-
- v = malloc (sizeof (glyphset_cache_entry_t));
- _cairo_lock_global_image_glyph_cache ();
- im_cache = _cairo_get_global_image_glyph_cache ();
-
- if (g == NULL || v == NULL || im_cache == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- status = _cairo_cache_lookup (im_cache, key, (void **) (&im), NULL);
- if (status != CAIRO_STATUS_SUCCESS || im == NULL) {
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- v->refcount = 1;
- v->key = *k;
- _cairo_unscaled_font_reference (v->key.unscaled);
-
- v->glyph = _next_xlib_glyph (g);
-
- v->info.width = im->image ? im->image->stride : im->size.width;
- v->info.height = im->size.height;
-
- /*
- * 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;
-
- XRenderAddGlyphs (g->display, g->glyphset,
- &(v->glyph), &(v->info), 1,
- im->image ? im->image->data : NULL,
- im->image ? v->info.height * v->info.width : 0);
-
- v->key.base.memory = im->image ? im->image->width * im->image->stride : 0;
- *return_entry = v;
- _cairo_unlock_global_image_glyph_cache ();
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_glyphset_cache_entry_reference (glyphset_cache_entry_t *e)
-{
- e->refcount++;
-}
-
-static void
-_xlib_glyphset_cache_destroy_cache (void *cache)
-{
- /* FIXME: will we ever release glyphset caches? */
-}
-
-static void
-_xlib_glyphset_cache_destroy_entry (void *cache, void *entry)
-{
- glyphset_cache_t *g;
- glyphset_cache_entry_t *v;
-
- g = (glyphset_cache_t *) cache;
- v = (glyphset_cache_entry_t *) entry;
-
- if (--v->refcount > 0)
- return;
-
- _cairo_unscaled_font_destroy (v->key.unscaled);
- XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1);
- free (v);
-}
-
-static const cairo_cache_backend_t _xlib_glyphset_cache_backend = {
- _cairo_glyph_cache_hash,
- _cairo_glyph_cache_keys_equal,
- _xlib_glyphset_cache_create_entry,
- _xlib_glyphset_cache_destroy_entry,
- _xlib_glyphset_cache_destroy_cache
-};
-
-
-static glyphset_cache_t *
-_xlib_glyphset_caches = NULL;
-
-static void
-_lock_xlib_glyphset_caches (void)
-{
- /* FIXME: implement locking */
-}
-
-static void
-_unlock_xlib_glyphset_caches (void)
-{
- /* FIXME: implement locking */
-}
-
-static glyphset_cache_t *
-_get_glyphset_cache (Display *d)
-{
- /*
- * There should usually only be one, or a very small number, of
- * displays. So we just do a linear scan.
- */
-
- glyphset_cache_t *g;
-
- for (g = _xlib_glyphset_caches; g != NULL; g = g->next) {
- if (g->display == d)
- return g;
- }
-
- g = malloc (sizeof (glyphset_cache_t));
- if (g == NULL)
- goto ERR;
-
- g->counter = 0;
- g->display = d;
- g->a8_pict_format = XRenderFindStandardFormat (d, PictStandardA8);
- if (g->a8_pict_format == NULL)
- goto ERR;
-
- if (_cairo_cache_init (&g->base,
- &_xlib_glyphset_cache_backend,
- CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT))
- goto FREE_GLYPHSET_CACHE;
-
- g->glyphset = XRenderCreateGlyphSet (d, g->a8_pict_format);
- g->next = _xlib_glyphset_caches;
- _xlib_glyphset_caches = g;
- return g;
-
- FREE_GLYPHSET_CACHE:
- free (g);
-
- ERR:
- return NULL;
-}
-
-#define N_STACK_BUF 1024
-
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs32 (cairo_font_t *font,
- cairo_operator_t operator,
- glyphset_cache_t *g,
- cairo_glyph_cache_key_t *key,
- cairo_xlib_surface_t *src,
- cairo_xlib_surface_t *self,
- int source_x,
- int source_y,
- const cairo_glyph_t *glyphs,
- glyphset_cache_entry_t **entries,
- int num_glyphs)
-{
- XGlyphElt32 *elts = NULL;
- XGlyphElt32 stack_elts [N_STACK_BUF];
-
- unsigned int *chars = NULL;
- unsigned int stack_chars [N_STACK_BUF];
-
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
-
- /* Acquire arrays of suitable sizes. */
- if (num_glyphs < N_STACK_BUF) {
- elts = stack_elts;
- chars = stack_chars;
-
- } else {
- elts = malloc (num_glyphs * sizeof (XGlyphElt32));
- if (elts == NULL)
- goto FAIL;
-
- chars = malloc (num_glyphs * sizeof (unsigned int));
- if (chars == NULL)
- goto FREE_ELTS;
-
- }
-
- for (i = 0; i < num_glyphs; ++i) {
- chars[i] = entries[i]->glyph;
- elts[i].chars = &(chars[i]);
- elts[i].nchars = 1;
- elts[i].glyphset = g->glyphset;
- 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,
- _render_operator (operator),
- src->picture,
- self->picture,
- g->a8_pict_format,
- source_x, source_y,
- 0, 0,
- elts, num_glyphs);
-
- if (num_glyphs >= N_STACK_BUF) {
- free (chars);
- free (elts);
- }
-
- return CAIRO_STATUS_SUCCESS;
-
- FREE_ELTS:
- if (num_glyphs >= N_STACK_BUF)
- free (elts);
-
- FAIL:
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs16 (cairo_font_t *font,
- cairo_operator_t operator,
- glyphset_cache_t *g,
- cairo_glyph_cache_key_t *key,
- cairo_xlib_surface_t *src,
- cairo_xlib_surface_t *self,
- int source_x,
- int source_y,
- const cairo_glyph_t *glyphs,
- glyphset_cache_entry_t **entries,
- int num_glyphs)
-{
- XGlyphElt16 *elts = NULL;
- XGlyphElt16 stack_elts [N_STACK_BUF];
-
- unsigned short *chars = NULL;
- unsigned short stack_chars [N_STACK_BUF];
-
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
-
- /* Acquire arrays of suitable sizes. */
- if (num_glyphs < N_STACK_BUF) {
- elts = stack_elts;
- chars = stack_chars;
-
- } else {
- elts = malloc (num_glyphs * sizeof (XGlyphElt16));
- if (elts == NULL)
- goto FAIL;
-
- chars = malloc (num_glyphs * sizeof (unsigned short));
- if (chars == NULL)
- goto FREE_ELTS;
-
- }
-
- for (i = 0; i < num_glyphs; ++i) {
- chars[i] = entries[i]->glyph;
- elts[i].chars = &(chars[i]);
- elts[i].nchars = 1;
- elts[i].glyphset = g->glyphset;
- 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,
- _render_operator (operator),
- src->picture,
- self->picture,
- g->a8_pict_format,
- source_x, source_y,
- 0, 0,
- elts, num_glyphs);
-
- if (num_glyphs >= N_STACK_BUF) {
- free (chars);
- free (elts);
- }
-
- return CAIRO_STATUS_SUCCESS;
-
- FREE_ELTS:
- if (num_glyphs >= N_STACK_BUF)
- free (elts);
-
- FAIL:
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs8 (cairo_font_t *font,
- cairo_operator_t operator,
- glyphset_cache_t *g,
- cairo_glyph_cache_key_t *key,
- cairo_xlib_surface_t *src,
- cairo_xlib_surface_t *self,
- int source_x,
- int source_y,
- const cairo_glyph_t *glyphs,
- glyphset_cache_entry_t **entries,
- int num_glyphs)
-{
- XGlyphElt8 *elts = NULL;
- XGlyphElt8 stack_elts [N_STACK_BUF];
-
- char *chars = NULL;
- char stack_chars [N_STACK_BUF];
-
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
-
- /* Acquire arrays of suitable sizes. */
- if (num_glyphs < N_STACK_BUF) {
- elts = stack_elts;
- chars = stack_chars;
-
- } else {
- elts = malloc (num_glyphs * sizeof (XGlyphElt8));
- if (elts == NULL)
- goto FAIL;
-
- chars = malloc (num_glyphs * sizeof (char));
- if (chars == NULL)
- goto FREE_ELTS;
-
- }
-
- for (i = 0; i < num_glyphs; ++i) {
- chars[i] = entries[i]->glyph;
- elts[i].chars = &(chars[i]);
- elts[i].nchars = 1;
- elts[i].glyphset = g->glyphset;
- 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,
- _render_operator (operator),
- src->picture,
- self->picture,
- g->a8_pict_format,
- source_x, source_y,
- 0, 0,
- elts, num_glyphs);
-
- if (num_glyphs >= N_STACK_BUF) {
- free (chars);
- free (elts);
- }
-
- return CAIRO_STATUS_SUCCESS;
-
- FREE_ELTS:
- if (num_glyphs >= N_STACK_BUF)
- free (elts);
-
- FAIL:
- return CAIRO_STATUS_NO_MEMORY;
-}
-
-
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_surface_attributes_t attributes;
- cairo_int_status_t status;
- unsigned int elt_size;
- cairo_xlib_surface_t *self = abstract_surface;
- cairo_xlib_surface_t *src;
- glyphset_cache_t *g;
- cairo_glyph_cache_key_t key;
- glyphset_cache_entry_t **entries;
- glyphset_cache_entry_t *stack_entries [N_STACK_BUF];
- int i;
-
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surface (pattern, &self->base,
- source_x, source_y, width, height,
- (cairo_surface_t **) &src,
- &attributes);
- if (status)
- return status;
-
- status = _cairo_xlib_surface_set_attributes (src, &attributes);
- if (status)
- goto FAIL;
-
- /* Acquire an entry array of suitable size. */
- if (num_glyphs < N_STACK_BUF) {
- entries = stack_entries;
-
- } else {
- entries = malloc (num_glyphs * sizeof (glyphset_cache_entry_t *));
- if (entries == NULL)
- goto FAIL;
- }
-
- _lock_xlib_glyphset_caches ();
- g = _get_glyphset_cache (self->dpy);
- if (g == NULL)
- goto UNLOCK;
-
- /* Work out the index size to use. */
- elt_size = 8;
- _cairo_font_get_glyph_cache_key (font, &key);
-
- for (i = 0; i < num_glyphs; ++i) {
- key.index = glyphs[i].index;
- status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]), NULL);
- if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL)
- goto UNLOCK;
-
- /* Referencing the glyph entries we use prevents them from
- * being freed if lookup of later entries causes them to
- * be ejected from the cache. It would be more efficient
- * (though more complex) to prevent them from being ejected
- * from the cache at all, so they could get reused later
- * in the same string.
- */
- _glyphset_cache_entry_reference (entries[i]);
-
- if (elt_size == 8 && entries[i]->glyph > 0xff)
- elt_size = 16;
- if (elt_size == 16 && entries[i]->glyph > 0xffff) {
- elt_size = 32;
- break;
- }
- }
-
- /* Call the appropriate sub-function. */
-
- if (elt_size == 8)
- status = _cairo_xlib_surface_show_glyphs8 (font, operator, g, &key, src, self,
- source_x + attributes.x_offset,
- source_y + attributes.y_offset,
- glyphs, entries, num_glyphs);
- else if (elt_size == 16)
- status = _cairo_xlib_surface_show_glyphs16 (font, operator, g, &key, src, self,
- source_x + attributes.x_offset,
- source_y + attributes.y_offset,
- glyphs, entries, num_glyphs);
- else
- status = _cairo_xlib_surface_show_glyphs32 (font, operator, g, &key, src, self,
- source_x + attributes.x_offset,
- source_y + attributes.y_offset,
- glyphs, entries, num_glyphs);
-
- for (i = 0; i < num_glyphs; ++i)
- _xlib_glyphset_cache_destroy_entry (g, entries[i]);
-
- UNLOCK:
- _unlock_xlib_glyphset_caches ();
-
- if (num_glyphs >= N_STACK_BUF)
- free (entries);
-
- FAIL:
- _cairo_pattern_release_surface (&self->base, &src->base, &attributes);
-
- return status;
-}
diff --git a/src/cairoint.h b/src/cairoint.h
index 50899eca8..90d59b2cb 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -52,11 +53,17 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
+
+#ifdef _MSC_VER
+#define _USE_MATH_DEFINES
+#endif
#include <math.h>
#include <limits.h>
-#include <stdint.h>
+#include <stdio.h>
#include "cairo.h"
+#include <pixman.h>
#if __GNUC__ >= 3 && defined(__ELF__)
# define slim_hidden_proto(name) slim_hidden_proto1(name, INT_##name)
@@ -85,7 +92,7 @@
#define cairo_private
#endif
-/* These macros allow us to deprecate a function by providing an alias
+/* This macro 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
some platforms --- tough.
@@ -94,14 +101,15 @@
source code so that it will no longer link against the old
symbols. Instead it will give a descriptive error message
indicating that the old function has been deprecated by the new
- function. */
+ function.
+*/
#if __GNUC__ >= 2 && defined(__ELF__)
-# define DEPRECATE(old, new) \
+# define CAIRO_FUNCTION_ALIAS(old, new) \
extern __typeof (new) old \
__asm__ ("" #old) \
__attribute__((__alias__("" #new)))
#else
-# define DEPRECATE(old, new)
+# define CAIRO_FUNCTION_ALIAS(old, new)
#endif
#ifndef __GNUC__
@@ -119,6 +127,12 @@
#define TRUE 1
#endif
+#define ASSERT_NOT_REACHED \
+do { \
+ static const int NOT_REACHED = 0; \
+ assert (NOT_REACHED); \
+} while (0)
+
#include "cairo-wideint.h"
typedef int32_t cairo_fixed_16_16_t;
@@ -164,7 +178,7 @@ typedef struct _cairo_trapezoid {
cairo_line_t left, right;
} cairo_trapezoid_t;
-typedef struct _cairo_rectangle_int {
+typedef struct _cairo_rectangle {
short x, y;
unsigned short width, height;
} cairo_rectangle_t, cairo_glyph_size_t;
@@ -179,45 +193,12 @@ typedef enum cairo_int_status {
#define CAIRO_OK(status) ((status) == CAIRO_STATUS_SUCCESS)
-typedef enum cairo_path_op {
- CAIRO_PATH_OP_MOVE_TO = 0,
- CAIRO_PATH_OP_LINE_TO = 1,
- CAIRO_PATH_OP_CURVE_TO = 2,
- CAIRO_PATH_OP_CLOSE_PATH = 3
-} __attribute__ ((packed)) cairo_path_op_t; /* Don't want 32 bits if we can avoid it. */
-
typedef enum cairo_direction {
CAIRO_DIRECTION_FORWARD,
CAIRO_DIRECTION_REVERSE
} cairo_direction_t;
-#define CAIRO_PATH_BUF_SZ 64
-
-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;
-} cairo_path_op_buf_t;
-
-typedef struct _cairo_path_arg_buf {
- int num_points;
- cairo_point_t points[CAIRO_PATH_BUF_SZ];
-
- struct _cairo_path_arg_buf *next, *prev;
-} cairo_path_arg_buf_t;
-
-typedef struct _cairo_path {
- cairo_path_op_buf_t *op_head;
- cairo_path_op_buf_t *op_tail;
-
- cairo_path_arg_buf_t *arg_head;
- cairo_path_arg_buf_t *arg_tail;
-
- cairo_point_t last_move_point;
- cairo_point_t current_point;
- int has_current_point;
-} cairo_path_t;
+typedef struct _cairo_path_fixed cairo_path_fixed_t;
typedef struct _cairo_edge {
cairo_line_t edge;
@@ -302,6 +283,24 @@ _cairo_array_copy_element (cairo_array_t *array, int index, void *dst);
cairo_private int
_cairo_array_num_elements (cairo_array_t *array);
+typedef cairo_array_t cairo_user_data_array_t;
+
+cairo_private void
+_cairo_user_data_array_init (cairo_user_data_array_t *array);
+
+cairo_private void
+_cairo_user_data_array_destroy (cairo_user_data_array_t *array);
+
+cairo_private void *
+_cairo_user_data_array_get_data (cairo_user_data_array_t *array,
+ const cairo_user_data_key_t *key);
+
+cairo_private cairo_status_t
+_cairo_user_data_array_set_data (cairo_user_data_array_t *array,
+ const cairo_user_data_key_t *key,
+ void *user_data,
+ cairo_destroy_func_t destroy);
+
/* cairo_cache.c structures and functions */
typedef struct _cairo_cache_backend {
@@ -404,25 +403,34 @@ _cairo_hash_string (const char *c);
#define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
#define CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
-typedef struct {
- double matrix[2][2];
-} cairo_font_scale_t;
+typedef struct _cairo_unscaled_font cairo_unscaled_font_t;
-struct _cairo_font_backend;
+typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t;
+typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t;
+typedef struct _cairo_font_face_backend cairo_font_face_backend_t;
/*
* A cairo_unscaled_font_t is just an opaque handle we use in the
* glyph cache.
*/
-typedef struct {
+struct _cairo_unscaled_font {
+ int refcount;
+ const cairo_unscaled_font_backend_t *backend;
+};
+
+struct _cairo_scaled_font {
int refcount;
- const struct _cairo_font_backend *backend;
-} cairo_unscaled_font_t;
+ cairo_matrix_t font_matrix; /* font space => user space */
+ cairo_matrix_t ctm; /* user space => device space */
+ cairo_matrix_t scale; /* font space => device space */
+ cairo_font_face_t *font_face; /* may be NULL */
+ const cairo_scaled_font_backend_t *backend;
+};
-struct _cairo_font {
+struct _cairo_font_face {
int refcount;
- cairo_font_scale_t scale; /* font space => device space */
- const struct _cairo_font_backend *backend;
+ cairo_user_data_array_t user_data;
+ const cairo_font_face_backend_t *backend;
};
/* cairo_font.c is responsible for a global glyph cache:
@@ -438,7 +446,7 @@ struct _cairo_font {
typedef struct {
cairo_cache_entry_base_t base;
cairo_unscaled_font_t *unscaled;
- cairo_font_scale_t scale;
+ cairo_matrix_t scale; /* translation is ignored */
int flags;
unsigned long index;
} cairo_glyph_cache_key_t;
@@ -471,98 +479,109 @@ _cairo_glyph_cache_keys_equal (void *cache,
/* the font backend interface */
-typedef struct _cairo_font_backend {
- cairo_status_t (*create) (const char *family,
+struct _cairo_unscaled_font_backend {
+ void (*destroy) (void *unscaled_font);
+ cairo_status_t (*create_glyph) (void *unscaled_font,
+ cairo_image_glyph_cache_entry_t *entry);
+};
+
+struct _cairo_scaled_font_backend {
+ cairo_status_t (*create) (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight,
- cairo_font_scale_t *scale,
- cairo_font_t **font);
-
- void (*destroy_font) (void *font);
- void (*destroy_unscaled_font) (void *font);
-
- cairo_status_t (*font_extents) (void *font,
- cairo_font_extents_t *extents);
-
- cairo_status_t (*text_to_glyphs) (void *font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs);
-
- cairo_status_t (*glyph_extents) (void *font,
- cairo_glyph_t *glyphs,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **font);
+
+ void (*destroy) (void *font);
+
+ cairo_status_t (*font_extents) (void *font,
+ cairo_font_extents_t *extents);
+
+ cairo_status_t (*text_to_glyphs) (void *font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs);
+
+ cairo_status_t (*glyph_extents) (void *font,
+ cairo_glyph_t *glyphs,
int num_glyphs,
- cairo_text_extents_t *extents);
+ cairo_text_extents_t *extents);
- cairo_status_t (*glyph_bbox) (void *font,
- const cairo_glyph_t *glyphs,
+ cairo_status_t (*glyph_bbox) (void *font,
+ const cairo_glyph_t *glyphs,
int num_glyphs,
- cairo_box_t *bbox);
+ cairo_box_t *bbox);
- cairo_status_t (*show_glyphs) (void *font,
+ cairo_status_t (*show_glyphs) (void *font,
cairo_operator_t operator,
- cairo_pattern_t *pattern,
- cairo_surface_t *surface,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *surface,
int source_x,
int source_y,
int dest_x,
int dest_y,
unsigned int width,
unsigned int height,
- const cairo_glyph_t *glyphs,
+ const cairo_glyph_t *glyphs,
int num_glyphs);
- cairo_status_t (*glyph_path) (void *font,
- cairo_glyph_t *glyphs,
+ cairo_status_t (*glyph_path) (void *font,
+ cairo_glyph_t *glyphs,
int num_glyphs,
- cairo_path_t *path);
- void (*get_glyph_cache_key) (void *font,
- cairo_glyph_cache_key_t *key);
-
- cairo_status_t (*create_glyph) (cairo_image_glyph_cache_entry_t *entry);
+ cairo_path_fixed_t *path);
+ void (*get_glyph_cache_key) (void *font,
+ cairo_glyph_cache_key_t *key);
+};
-} cairo_font_backend_t;
+struct _cairo_font_face_backend {
+ /* The destroy() function is allowed to resurrect the font face
+ * by re-referencing. This is needed for the FreeType backend.
+ */
+ void (*destroy) (void *font_face);
+ cairo_status_t (*create_font) (void *font_face,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ cairo_scaled_font_t **scaled_font);
+};
/* concrete font backends */
-#ifdef CAIRO_HAS_FT_FONT
+#if CAIRO_HAS_FT_FONT
-extern const cairo_private struct _cairo_font_backend cairo_ft_font_backend;
+extern const cairo_private struct _cairo_scaled_font_backend cairo_ft_scaled_font_backend;
#endif
-#ifdef CAIRO_HAS_WIN32_FONT
+#if CAIRO_HAS_WIN32_FONT
-extern const cairo_private struct _cairo_font_backend cairo_win32_font_backend;
+extern const cairo_private struct _cairo_scaled_font_backend cairo_win32_scaled_font_backend;
#endif
-#ifdef CAIRO_HAS_ATSUI_FONT
+#if CAIRO_HAS_ATSUI_FONT
-extern const cairo_private struct _cairo_font_backend cairo_atsui_font_backend;
+extern const cairo_private struct _cairo_scaled_font_backend cairo_atsui_scaled_font_backend;
#endif
typedef struct _cairo_surface_backend {
cairo_surface_t *
(*create_similar) (void *surface,
- cairo_format_t format,
- int drawable,
- int width,
- int height);
+ cairo_format_t format,
+ int drawable,
+ int width,
+ int height);
- void
- (*destroy) (void *surface);
-
- double
- (*pixels_per_inch) (void *surface);
+ cairo_status_t
+ (*finish) (void *surface);
cairo_status_t
- (* acquire_source_image) (void *abstract_surface,
+ (*acquire_source_image) (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra);
void
- (* release_source_image) (void *abstract_surface,
+ (*release_source_image) (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra);
@@ -587,39 +606,39 @@ typedef struct _cairo_surface_backend {
/* XXX: dst should be the first argument for consistency */
cairo_int_status_t
- (*composite) (cairo_operator_t operator,
+ (*composite) (cairo_operator_t operator,
cairo_pattern_t *src,
cairo_pattern_t *mask,
void *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);
+ 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_int_status_t
(*fill_rectangles) (void *surface,
- cairo_operator_t operator,
+ cairo_operator_t operator,
const cairo_color_t *color,
cairo_rectangle_t *rects,
- int num_rects);
+ int num_rects);
/* XXX: dst should be the first argument for consistency */
cairo_int_status_t
- (*composite_trapezoids) (cairo_operator_t operator,
+ (*composite_trapezoids) (cairo_operator_t operator,
cairo_pattern_t *pattern,
void *dst,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps);
+ int num_traps);
cairo_int_status_t
(*copy_page) (void *surface);
@@ -630,29 +649,47 @@ typedef struct _cairo_surface_backend {
cairo_int_status_t
(*set_clip_region) (void *surface,
pixman_region16_t *region);
+
+ /* Get the extents of the current surface. For many surface types
+ * this will be as simple as { x=0, y=0, width=surface->width,
+ * height=surface->height}.
+ *
+ * This function need not take account of any clipping from
+ * set_clip_region since the generic version of set_clip_region
+ * saves those, and the generic get_clip_extents will only call
+ * into the specific surface->get_extents if there is no current
+ * clip.
+ */
+ cairo_int_status_t
+ (*get_extents) (void *surface,
+ cairo_rectangle_t *rectangle);
+
/*
* This is an optional entry to let the surface manage its own glyph
* resources. If null, the font will be asked to render against this
* surface, using image surfaces as glyphs.
*/
- cairo_status_t
- (*show_glyphs) (cairo_font_t *font,
- cairo_operator_t operator,
+ cairo_int_status_t
+ (*show_glyphs) (cairo_scaled_font_t *font,
+ cairo_operator_t operator,
cairo_pattern_t *pattern,
void *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
const cairo_glyph_t *glyphs,
- int num_glyphs);
-} cairo_surface_backend_t;
+ int num_glyphs);
-struct _cairo_matrix {
- double m[3][2];
-};
+ cairo_int_status_t
+ (*fill_path) (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ void *dst,
+ cairo_path_fixed_t *path);
+
+} cairo_surface_backend_t;
typedef struct _cairo_format_masks {
int bpp;
@@ -662,14 +699,26 @@ typedef struct _cairo_format_masks {
unsigned long blue_mask;
} cairo_format_masks_t;
+typedef struct _cairo_surface_save cairo_surface_save_t;
+
struct _cairo_surface {
const cairo_surface_backend_t *backend;
unsigned int ref_count;
+ cairo_bool_t finished;
+ cairo_user_data_array_t user_data;
cairo_matrix_t matrix;
cairo_filter_t filter;
int repeat;
+
+ double device_x_offset;
+ double device_y_offset;
+
+ cairo_surface_save_t *saves; /* Stack of saved states from cairo_surface_begin/end() */
+ int level; /* Number saved states */
+
+ pixman_region16_t *clip_region;
};
struct _cairo_image_surface {
@@ -677,7 +726,7 @@ struct _cairo_image_surface {
/* libic-specific fields */
cairo_format_t format;
- char *data;
+ unsigned char *data;
int owns_data;
int width;
@@ -706,6 +755,12 @@ struct _cairo_color {
unsigned short alpha_short;
};
+typedef enum {
+ CAIRO_STOCK_WHITE,
+ CAIRO_STOCK_BLACK,
+ CAIRO_STOCK_TRANSPARENT
+} cairo_stock_t;
+
#define CAIRO_EXTEND_DEFAULT CAIRO_EXTEND_NONE
#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_BEST
@@ -727,13 +782,11 @@ struct _cairo_pattern {
cairo_matrix_t matrix;
cairo_filter_t filter;
cairo_extend_t extend;
- double alpha;
};
typedef struct _cairo_solid_pattern {
cairo_pattern_t base;
-
- double red, green, blue;
+ cairo_color_t color;
} cairo_solid_pattern_t;
typedef struct _cairo_surface_pattern {
@@ -787,6 +840,7 @@ typedef struct _cairo_surface_attributes {
int x_offset;
int y_offset;
cairo_bool_t acquired;
+ cairo_bool_t clip_saved;
void *extra;
} cairo_surface_attributes_t;
@@ -800,20 +854,20 @@ typedef struct _cairo_traps {
#define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL
#define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL
-#if defined (CAIRO_HAS_WIN32_FONT)
+#if CAIRO_HAS_WIN32_FONT
#define CAIRO_FONT_FAMILY_DEFAULT "Arial"
-#define CAIRO_FONT_BACKEND_DEFAULT &cairo_win32_font_backend
+#define CAIRO_FONT_BACKEND_DEFAULT &cairo_win32_scaled_font_backend
-#elif defined (CAIRO_HAS_ATSUI_FONT)
+#elif CAIRO_HAS_ATSUI_FONT
#define CAIRO_FONT_FAMILY_DEFAULT "Monaco"
-#define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_font_backend
+#define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_scaled_font_backend
-#elif defined (CAIRO_HAS_FT_FONT)
+#elif CAIRO_HAS_FT_FONT
#define CAIRO_FONT_FAMILY_DEFAULT "serif"
-#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend
+#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_scaled_font_backend
#endif
@@ -824,7 +878,7 @@ typedef struct _cairo_traps {
#define CAIRO_GSTATE_LINE_CAP_DEFAULT CAIRO_LINE_CAP_BUTT
#define CAIRO_GSTATE_LINE_JOIN_DEFAULT CAIRO_LINE_JOIN_MITER
#define CAIRO_GSTATE_MITER_LIMIT_DEFAULT 10.0
-#define CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT 96.0
+#define CAIRO_GSTATE_DEFAULT_FONT_SIZE 10.0
/* Need a name distinct from the cairo_clip function */
typedef struct _cairo_clip_rec {
@@ -833,55 +887,7 @@ typedef struct _cairo_clip_rec {
cairo_surface_t *surface;
} cairo_clip_rec_t;
-typedef struct _cairo_gstate {
- cairo_operator_t operator;
-
- double tolerance;
-
- /* stroke style */
- double line_width;
- cairo_line_cap_t line_cap;
- cairo_line_join_t line_join;
- double miter_limit;
-
- cairo_fill_rule_t fill_rule;
-
- double *dash;
- int num_dashes;
- double dash_offset;
-
- char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */
- cairo_font_slant_t font_slant;
- cairo_font_weight_t font_weight;
-
- cairo_font_t *font; /* Specific to the current CTM */
-
- cairo_surface_t *surface;
-
- cairo_pattern_t *pattern;
- double alpha;
-
- cairo_clip_rec_t clip;
-
- double pixels_per_inch;
-
- cairo_matrix_t font_matrix;
-
- cairo_matrix_t ctm;
- cairo_matrix_t ctm_inverse;
-
- cairo_path_t path;
-
- cairo_pen_t pen_regular;
-
- struct _cairo_gstate *next;
-} cairo_gstate_t;
-
-struct _cairo {
- unsigned int ref_count;
- cairo_gstate_t *gstate;
- cairo_status_t status;
-};
+typedef struct _cairo_gstate cairo_gstate_t;
typedef struct _cairo_stroke_face {
cairo_point_t ccw;
@@ -920,13 +926,13 @@ _cairo_fixed_integer_floor (cairo_fixed_t f);
cairo_private int
_cairo_fixed_integer_ceil (cairo_fixed_t f);
-
/* cairo_gstate.c */
cairo_private cairo_gstate_t *
-_cairo_gstate_create (void);
+_cairo_gstate_create (cairo_surface_t *target);
cairo_private cairo_status_t
-_cairo_gstate_init (cairo_gstate_t *gstate);
+_cairo_gstate_init (cairo_gstate_t *gstate,
+ cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
@@ -949,68 +955,54 @@ _cairo_gstate_begin_group (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_end_group (cairo_gstate_t *gstate);
-cairo_private cairo_status_t
-_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface);
-
cairo_private cairo_surface_t *
-_cairo_gstate_current_target_surface (cairo_gstate_t *gstate);
+_cairo_gstate_get_target (cairo_gstate_t *gstate);
cairo_private cairo_status_t
-_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern);
+_cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_t *source);
+
+cairo_status_t
+_cairo_gstate_set_source_solid (cairo_gstate_t *gstate,
+ const cairo_color_t *color);
cairo_private cairo_pattern_t *
-_cairo_gstate_current_pattern (cairo_gstate_t *gstate);
+_cairo_gstate_get_source (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator);
cairo_private cairo_operator_t
-_cairo_gstate_current_operator (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue);
-
-cairo_private cairo_status_t
-_cairo_gstate_current_rgb_color (cairo_gstate_t *gstate,
- double *red,
- double *green,
- double *blue);
+_cairo_gstate_get_operator (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance);
cairo_private double
-_cairo_gstate_current_tolerance (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha);
-
-cairo_private double
-_cairo_gstate_current_alpha (cairo_gstate_t *gstate);
+_cairo_gstate_get_tolerance (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule);
cairo_private cairo_fill_rule_t
-_cairo_gstate_current_fill_rule (cairo_gstate_t *gstate);
+_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width);
cairo_private double
-_cairo_gstate_current_line_width (cairo_gstate_t *gstate);
+_cairo_gstate_get_line_width (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap);
cairo_private cairo_line_cap_t
-_cairo_gstate_current_line_cap (cairo_gstate_t *gstate);
+_cairo_gstate_get_line_cap (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join);
cairo_private cairo_line_join_t
-_cairo_gstate_current_line_join (cairo_gstate_t *gstate);
+_cairo_gstate_get_line_join (cairo_gstate_t *gstate);
cairo_private cairo_status_t
_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset);
@@ -1019,10 +1011,10 @@ cairo_private cairo_status_t
_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit);
cairo_private double
-_cairo_gstate_current_miter_limit (cairo_gstate_t *gstate);
+_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate);
cairo_private void
-_cairo_gstate_current_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix);
+_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix);
cairo_private cairo_status_t
_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty);
@@ -1034,94 +1026,46 @@ cairo_private cairo_status_t
_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle);
cairo_private cairo_status_t
-_cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix);
+_cairo_gstate_transform (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix);
cairo_private cairo_status_t
-_cairo_gstate_default_matrix (cairo_gstate_t *gstate);
+_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix);
cairo_private cairo_status_t
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate);
cairo_private cairo_status_t
-_cairo_gstate_transform_point (cairo_gstate_t *gstate, double *x, double *y);
-
-cairo_private cairo_status_t
-_cairo_gstate_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
+_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y);
cairo_private cairo_status_t
-_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y);
+_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, double *dx, double *dy);
cairo_private cairo_status_t
-_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy);
+_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y);
cairo_private cairo_status_t
-_cairo_gstate_new_path (cairo_gstate_t *gstate);
+_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, double *dx, double *dy);
-cairo_private cairo_status_t
-_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y);
-
-cairo_private cairo_status_t
-_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y);
-
-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);
-
-cairo_private cairo_status_t
-_cairo_gstate_arc (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2);
-
-cairo_private cairo_status_t
-_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
- double xc, double yc,
- double radius,
- double angle1, double angle2);
-
-cairo_private cairo_status_t
-_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy);
-
-cairo_private cairo_status_t
-_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy);
-
-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
-cairo_private cairo_status_t
-_cairo_gstate_stroke_path (cairo_gstate_t *gstate);
-*/
+cairo_private void
+_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y);
-cairo_private cairo_status_t
-_cairo_gstate_close_path (cairo_gstate_t *gstate);
+cairo_private void
+_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y);
cairo_private cairo_status_t
-_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x, double *y);
+_cairo_gstate_paint (cairo_gstate_t *gstate);
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,
- cairo_curve_to_func_t *curve_to,
- cairo_close_path_func_t *close_path,
- void *closure);
+_cairo_gstate_mask (cairo_gstate_t *gstate,
+ cairo_pattern_t *mask);
cairo_private cairo_status_t
-_cairo_gstate_stroke (cairo_gstate_t *gstate);
+_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
-_cairo_gstate_fill (cairo_gstate_t *gstate);
+_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_gstate_copy_page (cairo_gstate_t *gstate);
@@ -1130,85 +1074,82 @@ cairo_private cairo_status_t
_cairo_gstate_show_page (cairo_gstate_t *gstate);
cairo_private cairo_status_t
-_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
+_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
cairo_private cairo_status_t
-_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
+_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
cairo_private cairo_status_t
-_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret);
+_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
+ double x,
+ double y,
+ cairo_bool_t *inside_ret);
cairo_private cairo_status_t
-_cairo_gstate_in_fill (cairo_gstate_t *gstate,
- double x,
- double y,
- cairo_bool_t *inside_ret);
+_cairo_gstate_in_fill (cairo_gstate_t *gstate,
+ cairo_path_fixed_t *path,
+ double x,
+ double y,
+ cairo_bool_t *inside_ret);
cairo_private cairo_status_t
-_cairo_gstate_init_clip (cairo_gstate_t *gstate);
+_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
-_cairo_gstate_clip (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_restore_external_state (cairo_gstate_t *gstate);
+_cairo_gstate_reset_clip (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);
+ double x,
+ double y,
+ double width,
+ double height);
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);
+_cairo_gstate_select_font_face (cairo_gstate_t *gstate,
+ const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight);
cairo_private cairo_status_t
-_cairo_gstate_scale_font (cairo_gstate_t *gstate,
- double scale);
+_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
+ double size);
-cairo_private void
-_cairo_gstate_current_font_scale (cairo_gstate_t *gstate,
- cairo_font_scale_t *sc);
-
+void
+_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
+ cairo_matrix_t *matrix);
+
cairo_private cairo_status_t
-_cairo_gstate_transform_font (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix);
+_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate,
+ const cairo_matrix_t *matrix);
cairo_private cairo_status_t
-_cairo_gstate_current_font (cairo_gstate_t *gstate,
- cairo_font_t **font);
-
-cairo_private void
-_cairo_gstate_set_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix);
-
-cairo_private void
-_cairo_gstate_current_font_transform (cairo_gstate_t *gstate,
- cairo_matrix_t *matrix);
+_cairo_gstate_get_font_face (cairo_gstate_t *gstate,
+ cairo_font_face_t **font_face);
cairo_private cairo_status_t
-_cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
- cairo_font_extents_t *extents);
+_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
+ cairo_font_extents_t *extents);
cairo_private cairo_status_t
-_cairo_gstate_set_font (cairo_gstate_t *gstate,
- cairo_font_t *font);
+_cairo_gstate_set_font_face (cairo_gstate_t *gstate,
+ cairo_font_face_t *font_face);
cairo_private cairo_status_t
_cairo_gstate_text_to_glyphs (cairo_gstate_t *font,
- const unsigned char *utf8,
+ const char *utf8,
+ double x,
+ double y,
cairo_glyph_t **glyphs,
- int *num_glyphs);
+ int *num_glyphs);
cairo_private cairo_status_t
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
@@ -1222,45 +1163,70 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
int num_glyphs);
cairo_private cairo_status_t
-_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
- cairo_glyph_t *glyphs,
- int num_glyphs);
+_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path);
/* cairo_color.c */
+cairo_private const cairo_color_t *
+_cairo_stock_color (cairo_stock_t stock);
+
+#define CAIRO_COLOR_WHITE _cairo_stock_color (CAIRO_STOCK_WHITE)
+#define CAIRO_COLOR_BLACK _cairo_stock_color (CAIRO_STOCK_BLACK)
+#define CAIRO_COLOR_TRANSPARENT _cairo_stock_color (CAIRO_STOCK_TRANSPARENT)
+
cairo_private void
_cairo_color_init (cairo_color_t *color);
cairo_private void
-_cairo_color_fini (cairo_color_t *color);
+_cairo_color_init_rgb (cairo_color_t *color,
+ double red, double green, double blue);
cairo_private void
-_cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue);
+_cairo_color_init_rgba (cairo_color_t *color,
+ double red, double green, double blue,
+ double alpha);
cairo_private void
-_cairo_color_get_rgb (const cairo_color_t *color,
- double *red, double *green, double *blue);
+_cairo_color_multiply_alpha (cairo_color_t *color,
+ double alpha);
cairo_private void
-_cairo_color_set_alpha (cairo_color_t *color, double alpha);
+_cairo_color_get_rgba (cairo_color_t *color,
+ double *red,
+ double *green,
+ double *blue,
+ double *alpha);
-/* cairo_font.c */
+cairo_private void
+_cairo_color_get_rgba_premultiplied (cairo_color_t *color,
+ double *red,
+ double *green,
+ double *blue,
+ double *alpha);
-cairo_private cairo_status_t
-_cairo_font_create (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight,
- cairo_font_scale_t *sc,
- cairo_font_t **font);
+/* cairo-font.c */
+
+cairo_private void
+_cairo_font_face_init (cairo_font_face_t *font_face,
+ const cairo_font_face_backend_t *backend);
+
+cairo_private cairo_font_face_t *
+_cairo_simple_font_face_create (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight);
cairo_private void
-_cairo_font_init (cairo_font_t *font,
- cairo_font_scale_t *scale,
- const cairo_font_backend_t *backend);
+_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
+ const cairo_matrix_t *font_matrix,
+ const cairo_matrix_t *ctm,
+ const cairo_scaled_font_backend_t *backend);
cairo_private void
-_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_unscaled_font_backend_t *backend);
cairo_private void
_cairo_unscaled_font_reference (cairo_unscaled_font_t *font);
@@ -1269,56 +1235,50 @@ cairo_private void
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font);
cairo_private cairo_status_t
-_cairo_font_font_extents (cairo_font_t *font,
- cairo_font_extents_t *extents);
+_cairo_scaled_font_font_extents (cairo_scaled_font_t *scaled_font,
+ cairo_font_extents_t *extents);
cairo_private cairo_status_t
-_cairo_font_text_to_glyphs (cairo_font_t *font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- int *num_glyphs);
+_cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
+ const char *utf8,
+ cairo_glyph_t **glyphs,
+ int *num_glyphs);
cairo_private cairo_status_t
-_cairo_font_glyph_extents (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents);
+_cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents);
cairo_private cairo_status_t
-_cairo_font_glyph_bbox (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_box_t *bbox);
+_cairo_scaled_font_glyph_bbox (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_box_t *bbox);
cairo_private cairo_status_t
-_cairo_font_show_glyphs (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_pattern_t *source,
- cairo_surface_t *surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int widht,
- unsigned int height,
- cairo_glyph_t *glyphs,
- int num_glyphs);
+_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *source,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_glyph_t *glyphs,
+ int num_glyphs);
cairo_private cairo_status_t
-_cairo_font_glyph_path (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path);
-
-cairo_private cairo_status_t
-_cairo_font_glyph_path (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_path_t *path);
+_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_fixed_t *path);
cairo_private void
-_cairo_font_get_glyph_cache_key (cairo_font_t *font,
- cairo_glyph_cache_key_t *key);
+_cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t *scaled_font,
+ cairo_glyph_cache_key_t *key);
/* cairo_hull.c */
cairo_private cairo_status_t
@@ -1326,76 +1286,97 @@ _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices);
/* cairo_path.c */
cairo_private void
-_cairo_path_init (cairo_path_t *path);
+_cairo_path_fixed_init (cairo_path_fixed_t *path);
cairo_private cairo_status_t
-_cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other);
+_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
+ cairo_path_fixed_t *other);
cairo_private void
-_cairo_path_fini (cairo_path_t *path);
+_cairo_path_fixed_fini (cairo_path_fixed_t *path);
-cairo_private cairo_status_t
-_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point);
+cairo_status_t
+_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x,
+ cairo_fixed_t y);
-cairo_private cairo_status_t
-_cairo_path_rel_move_to (cairo_path_t *path, cairo_slope_t *slope);
+cairo_status_t
+_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx,
+ cairo_fixed_t dy);
-cairo_private cairo_status_t
-_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point);
+cairo_status_t
+_cairo_path_fixed_line_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x,
+ cairo_fixed_t y);
-cairo_private cairo_status_t
-_cairo_path_rel_line_to (cairo_path_t *path, cairo_slope_t *slope);
+cairo_status_t
+_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx,
+ cairo_fixed_t dy);
-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);
+cairo_status_t
+_cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
+ cairo_fixed_t x0, cairo_fixed_t y0,
+ cairo_fixed_t x1, cairo_fixed_t y1,
+ cairo_fixed_t x2, cairo_fixed_t y2);
-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);
+cairo_status_t
+_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
+ cairo_fixed_t dx0, cairo_fixed_t dy0,
+ cairo_fixed_t dx1, cairo_fixed_t dy1,
+ cairo_fixed_t dx2, cairo_fixed_t dy2);
cairo_private cairo_status_t
-_cairo_path_close_path (cairo_path_t *path);
+_cairo_path_fixed_close_path (cairo_path_fixed_t *path);
-cairo_private cairo_status_t
-_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point);
+cairo_status_t
+_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
+ cairo_fixed_t *x,
+ cairo_fixed_t *y);
-typedef cairo_status_t (cairo_path_move_to_func_t) (void *closure,
- cairo_point_t *point);
+typedef cairo_status_t
+(cairo_path_fixed_move_to_func_t) (void *closure,
+ cairo_point_t *point);
-typedef cairo_status_t (cairo_path_line_to_func_t) (void *closure,
- cairo_point_t *point);
+typedef cairo_status_t
+(cairo_path_fixed_line_to_func_t) (void *closure,
+ cairo_point_t *point);
-typedef cairo_status_t (cairo_path_curve_to_func_t) (void *closure,
- cairo_point_t *p0,
- cairo_point_t *p1,
- cairo_point_t *p2);
+typedef cairo_status_t
+(cairo_path_fixed_curve_to_func_t) (void *closure,
+ cairo_point_t *p0,
+ cairo_point_t *p1,
+ cairo_point_t *p2);
-typedef cairo_status_t (cairo_path_close_path_func_t) (void *closure);
+typedef cairo_status_t
+(cairo_path_fixed_close_path_func_t) (void *closure);
cairo_private cairo_status_t
-_cairo_path_interpret (cairo_path_t *path,
- cairo_direction_t dir,
- cairo_path_move_to_func_t *move_to,
- cairo_path_line_to_func_t *line_to,
- cairo_path_curve_to_func_t *curve_to,
- cairo_path_close_path_func_t *close_path,
- void *closure);
+_cairo_path_fixed_interpret (cairo_path_fixed_t *path,
+ cairo_direction_t dir,
+ cairo_path_fixed_move_to_func_t *move_to,
+ cairo_path_fixed_line_to_func_t *line_to,
+ cairo_path_fixed_curve_to_func_t *curve_to,
+ cairo_path_fixed_close_path_func_t *close_path,
+ void *closure);
cairo_private cairo_status_t
-_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2);
+_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
+ double *x1, double *y1,
+ double *x2, double *y2);
/* cairo_path_fill.c */
cairo_private cairo_status_t
-_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
+_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate,
+ cairo_traps_t *traps);
/* cairo_path_stroke.c */
cairo_private cairo_status_t
-_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
+_cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
+ cairo_gstate_t *gstate,
+ cairo_traps_t *traps);
/* cairo_surface.c */
cairo_private cairo_surface_t *
@@ -1406,24 +1387,33 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other,
int height);
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);
+_cairo_surface_create_similar_solid (cairo_surface_t *other,
+ cairo_format_t format,
+ int width,
+ int height,
+ const cairo_color_t *color);
cairo_private void
_cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend);
cairo_private cairo_status_t
-_cairo_surface_fill_rectangle (cairo_surface_t *surface,
- cairo_operator_t operator,
- cairo_color_t *color,
- int x,
- int y,
- int width,
- int height);
+_cairo_surface_begin (cairo_surface_t *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_begin_reset_clip (cairo_surface_t *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_end (cairo_surface_t *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_fill_rectangle (cairo_surface_t *surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ int x,
+ int y,
+ int width,
+ int height);
cairo_private cairo_status_t
_cairo_surface_composite (cairo_operator_t operator,
@@ -1446,6 +1436,12 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_rectangle_t *rects,
int num_rects);
+cairo_private cairo_int_status_t
+_cairo_surface_fill_path (cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *dst,
+ cairo_path_fixed_t *path);
+
cairo_private cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t operator,
cairo_pattern_t *pattern,
@@ -1465,9 +1461,6 @@ _cairo_surface_copy_page (cairo_surface_t *surface);
cairo_private cairo_status_t
_cairo_surface_show_page (cairo_surface_t *surface);
-cairo_private double
-_cairo_surface_pixels_per_inch (cairo_surface_t *surface);
-
cairo_private cairo_status_t
_cairo_surface_acquire_source_image (cairo_surface_t *surface,
cairo_image_surface_t **image_out,
@@ -1498,13 +1491,32 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_t **clone_out);
cairo_private cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region);
+_cairo_surface_set_clip_region (cairo_surface_t *surface,
+ pixman_region16_t *region);
+
+cairo_private cairo_status_t
+_cairo_surface_get_clip_extents (cairo_surface_t *surface,
+ cairo_rectangle_t *rectangle);
+
+cairo_private cairo_status_t
+_cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
+ cairo_operator_t operator,
+ cairo_pattern_t *pattern,
+ cairo_surface_t *surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs);
/* cairo_image_surface.c */
cairo_private cairo_image_surface_t *
-_cairo_image_surface_create_with_masks (char *data,
- cairo_format_masks_t *format,
+_cairo_image_surface_create_with_masks (unsigned char *data,
+ cairo_format_masks_t *format,
int width,
int height,
int stride);
@@ -1514,7 +1526,7 @@ _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface);
cairo_private cairo_status_t
_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
- cairo_matrix_t *matrix);
+ const cairo_matrix_t *matrix);
cairo_private cairo_status_t
_cairo_image_surface_set_filter (cairo_image_surface_t *surface,
@@ -1605,44 +1617,39 @@ _cairo_spline_fini (cairo_spline_t *spline);
/* cairo_matrix.c */
cairo_private void
-_cairo_matrix_init (cairo_matrix_t *matrix);
+_cairo_matrix_get_affine (const cairo_matrix_t *matrix,
+ double *xx, double *yx,
+ double *xy, double *yy,
+ double *x0, double *y0);
cairo_private void
-_cairo_matrix_fini (cairo_matrix_t *matrix);
-
-cairo_private cairo_status_t
-_cairo_matrix_set_translate (cairo_matrix_t *matrix,
- double tx, double ty);
-
-cairo_private cairo_status_t
-_cairo_matrix_set_scale (cairo_matrix_t *matrix,
- double sx, double sy);
-
-cairo_private cairo_status_t
-_cairo_matrix_set_rotate (cairo_matrix_t *matrix,
- double angle);
-
-cairo_private cairo_status_t
-_cairo_matrix_transform_bounding_box (cairo_matrix_t *matrix,
+_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x, double *y,
double *width, double *height);
-cairo_private cairo_status_t
-_cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det);
+cairo_private void
+_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix, double *det);
-cairo_private cairo_status_t
-_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2);
+cairo_private void
+_cairo_matrix_compute_eigen_values (const cairo_matrix_t *matrix,
+ double *lambda1, double *lambda2);
cairo_private cairo_status_t
-_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major);
+_cairo_matrix_compute_scale_factors (const cairo_matrix_t *matrix,
+ double *sx, double *sy, int x_major);
cairo_private cairo_bool_t
-_cairo_matrix_is_integer_translation(cairo_matrix_t *matrix, int *itx, int *ity);
+_cairo_matrix_is_integer_translation(const cairo_matrix_t *matrix,
+ int *itx, int *ity);
/* cairo_traps.c */
cairo_private void
_cairo_traps_init (cairo_traps_t *traps);
+cairo_private cairo_status_t
+_cairo_traps_init_box (cairo_traps_t *traps,
+ cairo_box_t *box);
+
cairo_private void
_cairo_traps_fini (cairo_traps_t *traps);
@@ -1663,6 +1670,10 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y);
cairo_private void
_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents);
+cairo_private cairo_status_t
+_cairo_traps_extract_region (cairo_traps_t *tr,
+ pixman_region16_t **region);
+
/* cairo_slope.c */
cairo_private void
_cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b);
@@ -1683,7 +1694,7 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other);
cairo_private void
_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
- double red, double green, double blue);
+ const cairo_color_t *color);
cairo_private void
_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
@@ -1702,21 +1713,14 @@ cairo_private void
_cairo_pattern_fini (cairo_pattern_t *pattern);
cairo_private cairo_pattern_t *
-_cairo_pattern_create_solid (double red, double green, double blue);
-
-cairo_private cairo_status_t
-_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
- double *red, double *green, double *blue);
+_cairo_pattern_create_solid (const cairo_color_t *color);
cairo_private void
-_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha);
-
-cairo_private void
-_cairo_pattern_transform (cairo_pattern_t *pattern,
- cairo_matrix_t *ctm_inverse);
+_cairo_pattern_transform (cairo_pattern_t *pattern,
+ const cairo_matrix_t *ctm_inverse);
cairo_private cairo_bool_t
-_cairo_pattern_is_opaque (cairo_pattern_t *pattern);
+_cairo_pattern_is_opaque_solid (cairo_pattern_t *pattern);
cairo_private cairo_int_status_t
_cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
@@ -1752,37 +1756,71 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
/* cairo_unicode.c */
cairo_private cairo_status_t
-_cairo_utf8_to_ucs4 (const char *str,
- int len,
- uint32_t **result,
- int *items_written);
+_cairo_utf8_to_ucs4 (const unsigned char *str,
+ int len,
+ uint32_t **result,
+ int *items_written);
cairo_private cairo_status_t
-_cairo_utf8_to_utf16 (const char *str,
- int len,
- uint16_t **result,
- int *items_written);
+_cairo_utf8_to_utf16 (const unsigned char *str,
+ int len,
+ uint16_t **result,
+ int *items_written);
+
+/* cairo_output_stream.c */
+
+typedef struct _cairo_output_stream cairo_output_stream_t;
+
+cairo_private cairo_output_stream_t *
+_cairo_output_stream_create (cairo_write_func_t write_func,
+ void *closure);
+
+cairo_private void
+_cairo_output_stream_destroy (cairo_output_stream_t *stream);
+
+cairo_private cairo_status_t
+_cairo_output_stream_write (cairo_output_stream_t *stream,
+ const void *data, size_t length);
+
+cairo_private cairo_status_t
+_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
+ const char *fmt, va_list ap);
+
+cairo_private cairo_status_t
+_cairo_output_stream_printf (cairo_output_stream_t *stream,
+ const char *fmt, ...);
+
+cairo_private long
+_cairo_output_stream_get_position (cairo_output_stream_t *status);
+
+cairo_private cairo_status_t
+_cairo_output_stream_get_status (cairo_output_stream_t *stream);
+
+cairo_output_stream_t *
+_cairo_output_stream_create_for_file (const char *filename);
/* Avoid unnecessary PLT entries. */
+slim_hidden_proto(cairo_get_current_point)
+slim_hidden_proto(cairo_fill_preserve)
+slim_hidden_proto(cairo_clip_preserve)
slim_hidden_proto(cairo_close_path)
-slim_hidden_proto(cairo_matrix_copy)
slim_hidden_proto(cairo_matrix_invert)
slim_hidden_proto(cairo_matrix_multiply)
slim_hidden_proto(cairo_matrix_scale)
-slim_hidden_proto(cairo_matrix_set_affine)
-slim_hidden_proto(cairo_matrix_set_identity)
+slim_hidden_proto(cairo_matrix_init)
+slim_hidden_proto(cairo_matrix_init_identity)
+slim_hidden_proto(cairo_matrix_init_translate)
+slim_hidden_proto(cairo_matrix_init_scale)
+slim_hidden_proto(cairo_matrix_init_rotate)
slim_hidden_proto(cairo_matrix_transform_distance)
slim_hidden_proto(cairo_matrix_transform_point)
slim_hidden_proto(cairo_move_to)
+slim_hidden_proto(cairo_new_path)
slim_hidden_proto(cairo_rel_line_to)
slim_hidden_proto(cairo_restore)
slim_hidden_proto(cairo_save)
-slim_hidden_proto(cairo_set_target_surface)
-slim_hidden_proto(cairo_surface_create_for_image)
+slim_hidden_proto(cairo_stroke_preserve)
slim_hidden_proto(cairo_surface_destroy)
-slim_hidden_proto(cairo_surface_get_matrix)
-slim_hidden_proto(cairo_surface_set_matrix)
-slim_hidden_proto(cairo_surface_set_repeat)
#endif
diff --git a/test/.cvsignore b/test/.cvsignore
index 6194e2678..beaae22b7 100644
--- a/test/.cvsignore
+++ b/test/.cvsignore
@@ -2,17 +2,49 @@
.libs
Makefile
Makefile.in
+clip-nesting
+clip-twice
coverage
-fill_rule
+create-for-png
+fill-and-stroke
+fill-rule
+filter-nearest-offset
+get-and-set
+gradient-alpha
imagediff
-leaky_polygon
-line_width
-move_to_show_surface
-pixman_rotate
-text_cache_crash
-text_rotate
-clip_twice
-*-out.png
+leaky-polygon
+line-width
+linear-gradient
+mask
+move-to-show-surface
+paint
+paint-with-alpha
+path-data
+pdf-surface
+pdf-surface.pdf
+ps-surface
+ps-surface.ps
+pixman-rotate
+rel-path
+scale-source-surface-paint
+select-font-no-show-text
+self-copy
+set-source
+source-clip
+source-surface-scale-paint
+surface-finish-twice
+surface-pattern
+text-cache-crash
+text-rotate
+transforms
+translate-show-surface
+trap-clip
+user-data
+xlib-surface
+*-image-out.png
+*-xcb-out.png
+*-xlib-out.png
*-diff.png
-
-
+*.la
+*.lo
+*.log
diff --git a/test/Makefile.am b/test/Makefile.am
index 04d42e2d6..0ab593678 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,45 +1,101 @@
-# All new test cases go here
-TESTS = \
-fill_rule \
-leaky_polygon \
-line_width \
-linear_gradient \
-move_to_show_surface \
-text_cache_crash \
-text_rotate \
-coverage \
-clip_twice \
-pixman_rotate
+# All test cases go here
+TESTS = \
+clip-nesting \
+clip-twice \
+create-for-png \
+fill-and-stroke \
+fill-rule \
+filter-nearest-offset \
+get-and-set \
+gradient-alpha \
+leaky-polygon \
+line-width \
+linear-gradient \
+mask \
+move-to-show-surface \
+paint \
+paint-with-alpha \
+path-data \
+pixman-rotate \
+scale-source-surface-paint \
+select-font-no-show-text \
+self-copy \
+set-source \
+source-clip \
+source-surface-scale-paint \
+surface-finish-twice \
+surface-pattern \
+text-cache-crash \
+text-rotate \
+transforms \
+translate-show-surface \
+trap-clip \
+user-data \
+rel-path
-# And all new tests 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 \
-linear_gradient-ref.png \
-move_to_show_surface-ref.png \
-coverage-ref.png \
-clip_twice-ref.png \
-pixman_rotate-ref.png \
-romedalen.png
+if CAIRO_HAS_PDF_SURFACE
+TESTS += pdf-surface
+endif
-# 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.
+if CAIRO_HAS_PS_SURFACE
+TESTS += ps-surface
+endif
-# 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.
+if CAIRO_HAS_XLIB_SURFACE
+TESTS += xlib-surface
+endif
+
+# All tests which have a reference image go here.
+# 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 = \
+clip-nesting-ref.png \
+clip-twice-ref.png \
+create-for-png-ref.png \
+fill-and-stroke-ref.png \
+fill-rule-ref.png \
+filter-nearest-offset-ref.png \
+gradient-alpha-ref.png \
+leaky-polygon-ref.png \
+line-width-ref.png \
+linear-gradient-ref.png \
+mask-ref.png \
+move-to-show-surface-ref.png \
+paint-ref.png \
+paint-with-alpha-ref.png \
+path-data-ref.png \
+pixman-rotate-ref.png \
+romedalen.png \
+self-copy-ref.png \
+scale-source-surface-paint-ref.png \
+set-source-ref.png \
+source-clip-ref.png \
+source-surface-scale-paint-ref.png \
+surface-pattern-ref.png \
+transforms-ref.png \
+translate-show-surface-ref.png \
+trap-clip-ref.png \
+rel-path-ref.png
+
+# Any test for which the code committed to CVS is expected to fail
+# should be listed here.
+#
+# This way, we can avoid being bothered by reports of bugs we are
+# aware of, but users can still report when tests start behaving in
+# unexpected ways on their system.
#
-# When new bugs are found in committed code they can be listed
-# 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 \
-pixman_rotate \
-text_rotate
+# Of course, before any "release" of cairo we should eliminate
+# everything from this list by fixing the bugs. (We don't necessarily
+# have to be that strict for "snapshots" though.)
+#
+# Also, any test listed here should call cairo_test_expect_failure and
+# provide an explanation for the expected failure.
+XFAIL_TESTS = \
+filter-nearest-offset \
+pixman-rotate \
+self-copy \
+source-surface-scale-paint \
+text-rotate
check_PROGRAMS = $(TESTS)
@@ -47,37 +103,64 @@ check_PROGRAMS = $(TESTS)
# not be the most portable approach, but it is pragmatic and I'm
# willing to do something cleaner as soon as it causes someone a
# problem.
-INCLUDES = -D_GNU_SOURCE -I$(srcdir) $(CAIRO_CFLAGS) -I$(srcdir)/../src
+INCLUDES = -D_GNU_SOURCE -I$(srcdir) $(CAIRO_CFLAGS) -I$(top_srcdir)/src
-AM_LDFLAGS = $(CAIRO_LIBS) ../src/libcairo.la
+noinst_LTLIBRARIES = libcairotest.la
-cairo_test_lib =\
-buffer_diff.c \
-buffer_diff.h \
-cairo_test.c \
-cairo_test.h \
-read_png.c \
-read_png.h \
-write_png.c \
-write_png.h \
+libcairotest_la_SOURCES =\
+buffer-diff.c \
+buffer-diff.h \
+cairo-test.c \
+cairo-test.h \
+read-png.c \
+read-png.h \
+write-png.c \
+write-png.h \
xmalloc.c \
xmalloc.h
+LDADDS = libcairotest.la $(top_builddir)/src/libcairo.la
+
# ARGH! I have to repeat the list of tests a third time. Maybe it's
# 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)
-linear_gradient_SOURCES = linear_gradient.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)
-coverage_SOURCES = coverage.c $(cairo_test_lib)
-clip_twice_SOURCES = clip_twice.c $(cairo_test_lib)
-pixman_rotate_SOURCES = pixman_rotate.c $(cairo_test_lib)
+clip_nesting_LDADD = $(LDADDS)
+clip_twice_LDADD = $(LDADDS)
+create_for_png_LDADD = $(LDADDS)
+fill_and_stroke_LDADD = $(LDADDS)
+fill_rule_LDADD = $(LDADDS)
+filter_nearest_offset_LDADD = $(LDADDS)
+get_and_set_LDADD = $(LDADDS)
+gradient_alpha_LDADD = $(LDADDS)
+leaky_polygon_LDADD = $(LDADDS)
+line_width_LDADD = $(LDADDS)
+linear_gradient_LDADD = $(LDADDS)
+mask_LDADD = $(LDADDS)
+move_to_show_surface_LDADD = $(LDADDS)
+paint_LDADD = $(LDADDS)
+paint_with_alpha_LDADD = $(LDADDS)
+path_data_LDADD = $(LDADDS)
+pdf_surface_LDADD = $(LDADDS)
+ps_surface_LDADD = $(LDADDS)
+pixman_rotate_LDADD = $(LDADDS)
+scale_source_surface_paint_LDADD = $(LDADDS)
+select_font_no_show_text_LDADD = $(LDADDS)
+self_copy_LDADD = $(LDADDS)
+set_source_LDADD = $(LDADDS)
+source_clip_LDADD = $(LDADDS)
+source_surface_scale_paint_LDADD = $(LDADDS)
+surface_finish_twice_LDADD = $(LDADDS)
+surface_pattern_LDADD = $(LDADDS)
+text_cache_crash_LDADD = $(LDADDS)
+text_rotate_LDADD = $(LDADDS)
+transforms_LDADD = $(LDADDS)
+translate_show_surface_LDADD = $(LDADDS)
+trap_clip_LDADD = $(LDADDS)
+user_data_LDADD = $(LDADDS)
+rel_path_LDADD = $(LDADDS)
+xlib_surface_LDADD = $(LDADDS)
noinst_PROGRAMS = imagediff
-imagediff_SOURCES = imagediff.c $(cairo_test_lib)
+imagediff_LDADD = $(LDADDS)
-CLEANFILES = *-out.png *-diff.png *.log
+CLEANFILES = *-out.png *-diff.png *.log ps-surface.ps pdf-surface.pdf
diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index 07abd62a3..e540d2f9b 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -23,20 +23,39 @@
*
* Author: Richard D. Worth <richard@theworths.org> */
-#include "buffer_diff.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "cairo-test.h"
+
+#include "buffer-diff.h"
+#include "read-png.h"
+#include "write-png.h"
+#include "xmalloc.h"
+
+static void
+xunlink (const char *pathname)
+{
+ if (unlink (pathname) < 0 && errno != ENOENT) {
+ cairo_test_log (" Error: Cannot remove %s: %s\n",
+ pathname, strerror (errno));
+ exit (1);
+ }
+}
-/* Image comparison code courttesy of Richard Worth.
- * Returns number of pixels changed.
- * Also fills out a "diff" image intended to visually show where the
- * images differ.
- */
int
-buffer_diff (char *buf_a, char *buf_b, char *buf_diff,
- int width, int height, int stride)
+buffer_diff (unsigned char *buf_a,
+ unsigned char *buf_b,
+ unsigned char *buf_diff,
+ int width,
+ int height,
+ int stride)
{
int x, y;
- int total_pixels_changed = 0;
unsigned char *row_a, *row_b, *row;
+ int pixels_changed = 0;
for (y = 0; y < height; y++)
{
@@ -47,19 +66,19 @@ buffer_diff (char *buf_a, char *buf_b, char *buf_diff,
{
int channel;
unsigned char value_a, value_b;
- int pixel_changed = 0;
+ int pixel_differs = 0;
for (channel = 0; channel < 4; channel++)
{
double diff;
value_a = row_a[x * 4 + channel];
value_b = row_b[x * 4 + channel];
if (value_a != value_b)
- pixel_changed = 1;
+ pixel_differs = 1;
diff = value_a - value_b;
row[x * 4 + channel] = 128 + diff / 3.0;
}
- if (pixel_changed) {
- total_pixels_changed++;
+ if (pixel_differs) {
+ pixels_changed++;
} else {
row[x*4+0] = 0;
row[x*4+1] = 0;
@@ -69,5 +88,63 @@ buffer_diff (char *buf_a, char *buf_b, char *buf_diff,
}
}
- return total_pixels_changed;
+ return pixels_changed;
+}
+
+/* Image comparison code courtesy of Richard Worth <richard@theworths.org>
+ * Returns number of pixels changed, (or -1 on error).
+ * Also saves a "diff" image intended to visually show where the
+ * images differ.
+ */
+int
+image_diff (const char *filename_a,
+ const char *filename_b,
+ const char *filename_diff)
+{
+ int pixels_changed;
+ unsigned int width_a, height_a, stride_a;
+ unsigned int width_b, height_b, stride_b;
+ unsigned char *buf_a, *buf_b, *buf_diff;
+ read_png_status_t status;
+
+ status = read_png_argb32 (filename_a, &buf_a, &width_a, &height_a, &stride_a);
+ if (status)
+ return -1;
+
+ status = read_png_argb32 (filename_b, &buf_b, &width_b, &height_b, &stride_b);
+ if (status)
+ return -1;
+
+ if (width_a != width_b ||
+ height_a != height_b ||
+ stride_a != stride_b)
+ {
+ cairo_test_log ("Error: Image size mismatch: (%dx%d@%d) vs. (%dx%d@%d)\n"
+ " for %s vs. %s\n",
+ width_a, height_a, stride_a,
+ width_b, height_b, stride_b,
+ filename_a, filename_b);
+ free (buf_a);
+ free (buf_b);
+ return -1;
+ }
+
+ buf_diff = xcalloc (stride_a * height_a, 1);
+
+ pixels_changed = buffer_diff (buf_a, buf_b, buf_diff,
+ width_a, height_a, stride_a);
+
+ if (pixels_changed) {
+ FILE *png_file = fopen (filename_diff, "wb");
+ write_png_argb32 (buf_diff, png_file, width_a, height_a, stride_a);
+ fclose (png_file);
+ } else {
+ xunlink (filename_diff);
+ }
+
+ free (buf_a);
+ free (buf_b);
+ free (buf_diff);
+
+ return pixels_changed;
}
diff --git a/test/buffer-diff.h b/test/buffer-diff.h
index 9ee51c3cf..a02834f3d 100644
--- a/test/buffer-diff.h
+++ b/test/buffer-diff.h
@@ -26,13 +26,25 @@
#ifndef BUFFER_DIFF_H
#define BUFFER_DIFF_H
-/* Image comparison code courttesy of Richard Worth.
- * Returns number of pixels changed.
- * Also fills out a "diff" image intended to visually show where the
+/* Returns number of pixels changed, (or -1 on error).
+ * Also fills in a "diff" buffer intended to visually show where the
* images differ.
*/
int
-buffer_diff (char *buf_a, char *buf_b, char *buf_diff,
- int width, int height, int stride);
+buffer_diff (unsigned char *buf_a,
+ unsigned char *buf_b,
+ unsigned char *buf_diff,
+ int width,
+ int height,
+ int stride);
+
+/* Returns number of pixels changed, (or -1 on error).
+ * Also saves a "diff" image intended to visually show where the
+ * images differ.
+ */
+int
+image_diff (const char *filename_a,
+ const char *filename_b,
+ const char *filename_diff);
#endif
diff --git a/test/buffer_diff.c b/test/buffer_diff.c
deleted file mode 100644
index 07abd62a3..000000000
--- a/test/buffer_diff.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* imagediff - Compare two images
- *
- * Copyright © 2004 Richard D. Worth
- *
- * 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 Richard Worth
- * not be used in advertising or publicity pertaining to distribution
- * of the software without specific, written prior permission.
- * Richard Worth makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
- * NO EVENT SHALL RICHARD WORTH 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: Richard D. Worth <richard@theworths.org> */
-
-#include "buffer_diff.h"
-
-/* Image comparison code courttesy of Richard Worth.
- * Returns number of pixels changed.
- * Also fills out a "diff" image intended to visually show where the
- * images differ.
- */
-int
-buffer_diff (char *buf_a, char *buf_b, char *buf_diff,
- int width, int height, int stride)
-{
- int x, y;
- int total_pixels_changed = 0;
- unsigned char *row_a, *row_b, *row;
-
- for (y = 0; y < height; y++)
- {
- row_a = buf_a + y * stride;
- row_b = buf_b + y * stride;
- row = buf_diff + y * stride;
- for (x = 0; x < width; x++)
- {
- int channel;
- unsigned char value_a, value_b;
- int pixel_changed = 0;
- for (channel = 0; channel < 4; channel++)
- {
- double diff;
- value_a = row_a[x * 4 + channel];
- value_b = row_b[x * 4 + channel];
- if (value_a != value_b)
- pixel_changed = 1;
- diff = value_a - value_b;
- row[x * 4 + channel] = 128 + diff / 3.0;
- }
- if (pixel_changed) {
- total_pixels_changed++;
- } else {
- row[x*4+0] = 0;
- row[x*4+1] = 0;
- row[x*4+2] = 0;
- }
- row[x * 4 + 3] = 0xff; /* Set ALPHA to 100% (opaque) */
- }
- }
-
- return total_pixels_changed;
-}
diff --git a/test/buffer_diff.h b/test/buffer_diff.h
deleted file mode 100644
index 9ee51c3cf..000000000
--- a/test/buffer_diff.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* imagediff - Compare two images
- *
- * Copyright © 2004 Richard D. Worth
- *
- * 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 Richard Worth
- * not be used in advertising or publicity pertaining to distribution
- * of the software without specific, written prior permission.
- * Richard Worth makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
- * NO EVENT SHALL RICHARD WORTH 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: Richard D. Worth <richard@theworths.org> */
-
-#ifndef BUFFER_DIFF_H
-#define BUFFER_DIFF_H
-
-/* Image comparison code courttesy of Richard Worth.
- * Returns number of pixels changed.
- * Also fills out a "diff" image intended to visually show where the
- * images differ.
- */
-int
-buffer_diff (char *buf_a, char *buf_b, char *buf_diff,
- int width, int height, int stride);
-
-#endif
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 06f7672fd..d8ce6800f 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2004 Red Hat, Inc.
+ * 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
@@ -30,11 +30,11 @@
#include <errno.h>
#include <string.h>
-#include "cairo_test.h"
+#include "cairo-test.h"
-#include "buffer_diff.h"
-#include "read_png.h"
-#include "write_png.h"
+#include "buffer-diff.h"
+#include "read-png.h"
+#include "write-png.h"
#include "xmalloc.h"
#define CAIRO_TEST_LOG_SUFFIX ".log"
@@ -42,7 +42,22 @@
#define CAIRO_TEST_REF_SUFFIX "-ref.png"
#define CAIRO_TEST_DIFF_SUFFIX "-diff.png"
-static void
+/* Static data is messy, but we're coding for tests here, not a
+ * general-purpose library, and it keeps the tests cleaner to avoid a
+ * context object there, (though not a whole lot). */
+FILE *cairo_test_log_file;
+
+void
+cairo_test_log (const char *fmt, ...)
+{
+ va_list va;
+
+ va_start (va, fmt);
+ vfprintf (cairo_test_log_file, fmt, va);
+ va_end (va);
+}
+
+void
xasprintf (char **strp, const char *fmt, ...)
{
#ifdef HAVE_VASPRINTF
@@ -54,7 +69,7 @@ xasprintf (char **strp, const char *fmt, ...)
va_end (va);
if (ret < 0) {
- fprintf (stderr, "Out of memory\n");
+ cairo_test_log ("Out of memory\n");
exit (1);
}
#else /* !HAVE_VASNPRINTF */
@@ -68,18 +83,18 @@ xasprintf (char **strp, const char *fmt, ...)
va_end (va);
if (ret < 0) {
- fprintf (stderr, "Failure in vsnprintf\n");
+ cairo_test_log ("Failure in vsnprintf\n");
exit (1);
}
if (strlen (buffer) == sizeof(buffer) - 1) {
- fprintf (stderr, "Overflowed fixed buffer\n");
+ cairo_test_log ("Overflowed fixed buffer\n");
exit (1);
}
*strp = strdup (buffer);
if (!*strp) {
- fprintf (stderr, "Out of memory\n");
+ cairo_test_log ("Out of memory\n");
exit (1);
}
#endif /* !HAVE_VASNPRINTF */
@@ -89,138 +104,455 @@ static void
xunlink (const char *pathname)
{
if (unlink (pathname) < 0 && errno != ENOENT) {
- fprintf (stderr, " Error: Cannot remove %s: %s\n",
- pathname, strerror (errno));
+ cairo_test_log (" Error: Cannot remove %s: %s\n",
+ pathname, strerror (errno));
exit (1);
}
}
-cairo_test_status_t
-cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
+typedef cairo_surface_t *
+(*cairo_test_create_target_surface_t) (int width, int height, void **closure);
+
+typedef void
+(*cairo_test_cleanup_target_t) (void *closure);
+
+typedef struct _cairo_test_target
+{
+ const char *name;
+ cairo_test_create_target_surface_t create_target_surface;
+ cairo_test_cleanup_target_t cleanup_target;
+ void *closure;
+} cairo_test_target_t;
+
+static cairo_surface_t *
+create_image_surface (int width, int height, void **closure)
+{
+ int stride = 4 * width;
+ unsigned char *buf;
+
+ *closure = buf = xcalloc (stride * height, 1);
+
+ return cairo_image_surface_create_for_data (buf,
+ CAIRO_FORMAT_ARGB32,
+ width, height, stride);
+}
+
+static void
+cleanup_image (void *closure)
+{
+ unsigned char *buf = closure;
+
+ free (buf);
+}
+
+/* XXX: Someone who knows glitz better than I do should fix this up to
+ * work. */
+#if 0 /* #ifdef CAIRO_HAS_GLITZ_SURFACE */
+static cairo_surface_t *
+create_glitz_surface (int width, int height, void **closure)
+{
+#error Not yet implemented
+}
+
+static void
+cleanup_glitz (cairo_t *cr)
+{
+#error Not yet implemented
+}
+#endif
+
+#if CAIRO_HAS_QUARTZ_SURFACE
+static cairo_surface_t *
+create_quartz_surface (int width, int height, void **closure)
+{
+#error Not yet implemented
+}
+
+static void
+cleanup_quartz (void *closure)
{
+#error Not yet implemented
+}
+#endif
+
+/* Testing the win32 surface isn't interesting, since for
+ * ARGB images it just chains to the image backend
+ */
+#if 0 && CAIRO_HAS_WIN32_SURFACE
+static cairo_surface_t *
+create_win32_surface (int width, int height, void **closure)
+{
+#error Not yet implemented
+}
+
+static void
+cleanup_win32 (void *closure)
+{
+#error Not yet implemented
+}
+#endif
+
+#if CAIRO_HAS_XCB_SURFACE
+#include "cairo-xcb-xrender.h"
+typedef struct _xcb_target_closure
+{
+ XCBConnection *c;
+ XCBDRAWABLE drawable;
+} xcb_target_closure_t;
+
+/* XXX: This is a nasty hack. Something like this should be in XCB's
+ * bindings for Render, not here in this test. */
+static XCBRenderPICTFORMINFO
+_format_from_cairo(XCBConnection *c, cairo_format_t fmt)
+{
+ XCBRenderPICTFORMINFO ret = {{ 0 }};
+ struct tmpl_t {
+ XCBRenderDIRECTFORMAT direct;
+ CARD8 depth;
+ };
+ static const struct tmpl_t templates[] = {
+ /* CAIRO_FORMAT_ARGB32 */
+ {
+ {
+ 16, 0xff,
+ 8, 0xff,
+ 0, 0xff,
+ 24, 0xff
+ },
+ 32
+ },
+ /* CAIRO_FORMAT_RGB24 */
+ {
+ {
+ 16, 0xff,
+ 8, 0xff,
+ 0, 0xff,
+ 0, 0x00
+ },
+ 24
+ },
+ /* CAIRO_FORMAT_A8 */
+ {
+ {
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0xff
+ },
+ 8
+ },
+ /* CAIRO_FORMAT_A1 */
+ {
+ {
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0x01
+ },
+ 1
+ },
+ };
+ const struct tmpl_t *tmpl;
+ XCBRenderQueryPictFormatsRep *r;
+ XCBRenderPICTFORMINFOIter fi;
+
+ if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates)))
+ return ret;
+ tmpl = templates + fmt;
+
+ r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
+ if(!r)
+ return ret;
+
+ for(fi = XCBRenderQueryPictFormatsFormatsIter(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
+ {
+ const XCBRenderDIRECTFORMAT *t, *f;
+ if(fi.data->type != XCBRenderPictTypeDirect)
+ continue;
+ if(fi.data->depth != tmpl->depth)
+ continue;
+ t = &tmpl->direct;
+ f = &fi.data->direct;
+ if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift))
+ continue;
+ if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift))
+ continue;
+ if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift))
+ continue;
+ if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift))
+ continue;
+
+ ret = *fi.data;
+ }
+
+ free(r);
+ return ret;
+}
+
+static cairo_surface_t *
+create_xcb_surface (int width, int height, void **closure)
+{
+ XCBSCREEN *root;
+ xcb_target_closure_t *xtc;
+ cairo_surface_t *surface;
+ XCBConnection *c;
+ XCBRenderPICTFORMINFO render_format;
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = XCBConnectBasic();
+ if (c == NULL) {
+ cairo_test_log ("Failed to connect to X server through XCB\n");
+ return NULL;
+ }
+
+ root = XCBConnSetupSuccessRepRootsIter(XCBGetSetup(c)).data;
+
+ xtc->drawable.pixmap = XCBPIXMAPNew (c);
+ {
+ XCBDRAWABLE root_drawable;
+ root_drawable.window = root->root;
+ XCBCreatePixmap (c, 32, xtc->drawable.pixmap, root_drawable,
+ width, height);
+ }
+
+ render_format = _format_from_cairo (c, CAIRO_FORMAT_ARGB32);
+ if (render_format.id.xid == 0)
+ return NULL;
+ surface = cairo_xcb_surface_create_with_xrender_format (c, xtc->drawable,
+ &render_format,
+ width, height);
+
+ return surface;
+}
+
+static void
+cleanup_xcb (void *closure)
+{
+ xcb_target_closure_t *xtc = closure;
+
+ XCBFreePixmap (xtc->c, xtc->drawable.pixmap);
+ XCBDisconnect (xtc->c);
+}
+#endif
+
+#if CAIRO_HAS_XLIB_SURFACE
+#include "cairo-xlib-xrender.h"
+typedef struct _xlib_target_closure
+{
+ Display *dpy;
+ Pixmap pixmap;
+} xlib_target_closure_t;
+
+static cairo_surface_t *
+create_xlib_surface (int width, int height, void **closure)
+{
+ xlib_target_closure_t *xtc;
+ cairo_surface_t *surface;
+ Display *dpy;
+ XRenderPictFormat *xrender_format;
+
+ *closure = xtc = xmalloc (sizeof (xlib_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->dpy = dpy = XOpenDisplay (0);
+ if (xtc->dpy == NULL) {
+ cairo_test_log ("Failed to open display: %s\n", XDisplayName(0));
+ return NULL;
+ }
+
+ xrender_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
+
+ xtc->pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy),
+ width, height, xrender_format->depth);
+
+ surface = cairo_xlib_surface_create_with_xrender_format (dpy, xtc->pixmap,
+ xrender_format,
+ width, height);
+ return surface;
+}
+
+static void
+cleanup_xlib (void *closure)
+{
+ xlib_target_closure_t *xtc = closure;
+
+ XFreePixmap (xtc->dpy, xtc->pixmap);
+ XCloseDisplay (xtc->dpy);
+}
+#endif
+
+static cairo_test_status_t
+cairo_test_for_target (cairo_test_t *test,
+ cairo_test_draw_function_t draw,
+ cairo_test_target_t *target)
+{
+ cairo_test_status_t status;
+ cairo_surface_t *surface;
cairo_t *cr;
- int stride;
- unsigned char *png_buf, *ref_buf, *diff_buf;
- char *log_name, *png_name, *ref_name, *diff_name;
+ char *png_name, *ref_name, *diff_name;
char *srcdir;
int pixels_changed;
- int ref_width, ref_height, ref_stride;
- read_png_status_t png_status;
cairo_test_status_t ret;
- FILE *png_file;
- FILE *log_file;
- /* The cairo part of the test is the easiest part */
- cr = cairo_create ();
+ /* Get the strings ready that we'll need. */
+ srcdir = getenv ("srcdir");
+ if (!srcdir)
+ srcdir = ".";
+ xasprintf (&png_name, "%s-%s%s", test->name,
+ target->name, CAIRO_TEST_PNG_SUFFIX);
+ xasprintf (&ref_name, "%s/%s%s", srcdir, test->name,
+ CAIRO_TEST_REF_SUFFIX);
+ xasprintf (&diff_name, "%s-%s%s", test->name,
+ target->name, CAIRO_TEST_DIFF_SUFFIX);
+
+ /* Run the actual drawing code. */
+ surface = (target->create_target_surface) (test->width, test->height,
+ &target->closure);
+ if (surface == NULL) {
+ cairo_test_log ("Error: Failed to set %s target\n", target->name);
+ return CAIRO_TEST_FAILURE;
+ }
- stride = 4 * test->width;
+ cr = cairo_create (surface);
- png_buf = xcalloc (stride * test->height, 1);
- diff_buf = xcalloc (stride * test->height, 1);
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, 0, 0, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+ cairo_restore (cr);
- cairo_set_target_image (cr, png_buf, CAIRO_FORMAT_ARGB32,
- test->width, test->height, stride);
+ status = (draw) (cr, test->width, test->height);
- (draw) (cr, test->width, test->height);
+ /* Then, check all the different ways it could fail. */
+ if (status) {
+ cairo_test_log ("Error: Function under test failed\n");
+ return status;
+ }
- cairo_destroy (cr);
+ if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
+ cairo_test_log ("Error: Function under test left cairo status in an error state: %s\n", cairo_status_string (cr));
+ return CAIRO_TEST_FAILURE;
+ }
/* 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);
+ cairo_destroy (cr);
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 = ".";
- xasprintf (&log_name, "%s%s", test->name, CAIRO_TEST_LOG_SUFFIX);
- 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);
+ cairo_surface_write_to_png (surface, png_name);
- png_file = fopen (png_name, "w");
- write_png_argb32 (png_buf, png_file, test->width, test->height, stride);
- fclose (png_file);
+ cairo_destroy (cr);
- xunlink (log_name);
+ cairo_surface_destroy (surface);
- ref_buf = NULL;
- png_status = (read_png_argb32 (ref_name, &ref_buf, &ref_width, &ref_height, &ref_stride));
- if (png_status) {
- log_file = fopen (log_name, "a");
- switch (png_status)
- {
- case READ_PNG_FILE_NOT_FOUND:
- fprintf (log_file, "Error: No reference image found: %s\n", ref_name);
- break;
- case READ_PNG_FILE_NOT_PNG:
- fprintf (log_file, "Error: %s is not a png image\n", ref_name);
- break;
- default:
- fprintf (log_file, "Error: Failed to read %s\n", ref_name);
- }
- fclose (log_file);
-
+ target->cleanup_target (target->closure);
+
+ pixels_changed = image_diff (png_name, ref_name, diff_name);
+
+ if (pixels_changed) {
ret = CAIRO_TEST_FAILURE;
- goto BAIL;
+ if (pixels_changed > 0)
+ cairo_test_log ("Error: %d pixels differ from reference image %s\n",
+ pixels_changed, ref_name);
} else {
+ ret = CAIRO_TEST_SUCCESS;
}
- if (test->width != ref_width || test->height != ref_height) {
- log_file = fopen (log_name, "a");
- fprintf (log_file,
- "Error: Image size mismatch: (%dx%d) vs. (%dx%d)\n"
- " for %s vs %s\n",
- test->width, test->height,
- ref_width, ref_height,
- png_name, ref_name);
- fclose (log_file);
+ free (png_name);
+ free (ref_name);
+ free (diff_name);
- ret = CAIRO_TEST_FAILURE;
- goto BAIL;
- }
+ return ret;
+}
- pixels_changed = buffer_diff (png_buf, ref_buf, diff_buf,
- test->width, test->height, stride);
- if (pixels_changed) {
- log_file = fopen (log_name, "a");
- fprintf (log_file, "Error: %d pixels differ from reference image %s\n",
- pixels_changed, ref_name);
- png_file = fopen (diff_name, "w");
- write_png_argb32 (diff_buf, png_file, test->width, test->height, stride);
- fclose (png_file);
- fclose (log_file);
+static cairo_test_status_t
+cairo_test_real (cairo_test_t *test, cairo_test_draw_function_t draw)
+{
+ int i;
+ cairo_test_status_t status, ret;
+ cairo_test_target_t targets[] =
+ {
+ { "image", create_image_surface, cleanup_image},
+#if 0 /* #ifdef CAIRO_HAS_GLITZ_SURFACE */
+ { "glitz", create_glitz_surface, cleanup_glitz},
+#endif
+#if CAIRO_HAS_QUARTZ_SURFACE
+ { "quartz", create_quartz_surface, cleanup_quartz},
+#endif
+#if 0 && CAIRO_HAS_WIN32_SURFACE
+ { "win32", create_win32_surface, cleanup_win32},
+#endif
+#if CAIRO_HAS_XCB_SURFACE
+ { "xcb", create_xcb_surface, cleanup_xcb},
+#endif
+#if CAIRO_HAS_XLIB_SURFACE
+ { "xlib", create_xlib_surface, cleanup_xlib},
+#endif
+ };
+ char *log_name;
- ret = CAIRO_TEST_FAILURE;
- goto BAIL;
- } else {
- xunlink (diff_name);
+ xasprintf (&log_name, "%s%s", test->name, CAIRO_TEST_LOG_SUFFIX);
+ xunlink (log_name);
+
+ cairo_test_log_file = fopen (log_name, "a");
+ if (cairo_test_log_file == NULL) {
+ fprintf (stderr, "Error opening log file: %s\n", log_name);
+ cairo_test_log_file = stderr;
}
ret = CAIRO_TEST_SUCCESS;
+ for (i=0; i < sizeof(targets)/sizeof(targets[0]); i++) {
+ cairo_test_target_t *target = &targets[i];
+ cairo_test_log ("Testing %s with %s target\n", test->name, target->name);
+ printf ("%s-%s:\t", test->name, target->name);
+ status = cairo_test_for_target (test, draw, target);
+ if (status) {
+ printf ("FAIL\n");
+ ret = status;
+ } else {
+ printf ("PASS\n");
+ }
+ }
-BAIL:
- free (png_buf);
- free (ref_buf);
- free (diff_buf);
- free (log_name);
- free (png_name);
- free (ref_name);
- free (diff_name);
+ fclose (cairo_test_log_file);
return ret;
}
+cairo_test_status_t
+cairo_test_expect_failure (cairo_test_t *test,
+ cairo_test_draw_function_t draw,
+ const char *because)
+{
+ printf ("\n%s is expected to fail:\n\t%s\n", test->name, because);
+ return cairo_test_real (test, draw);
+}
+
+cairo_test_status_t
+cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
+{
+ printf ("\n");
+ return cairo_test_real (test, draw);
+}
+
cairo_pattern_t *
cairo_test_create_png_pattern (cairo_t *cr, const char *filename)
{
cairo_surface_t *image;
cairo_pattern_t *pattern;
unsigned char *buffer;
- int w, h, stride;
+ unsigned int w, h, stride;
read_png_status_t status;
char *srcdir = getenv ("srcdir");
@@ -236,12 +568,11 @@ cairo_test_create_png_pattern (cairo_t *cr, const char *filename)
if (status != READ_PNG_SUCCESS)
return NULL;
- image = cairo_surface_create_for_image (buffer, CAIRO_FORMAT_ARGB32,
- w, h, stride);
-
- cairo_surface_set_repeat (image, 1);
+ image = cairo_image_surface_create_for_data (buffer, CAIRO_FORMAT_ARGB32,
+ w, h, stride);
pattern = cairo_pattern_create_for_surface (image);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
return pattern;
}
diff --git a/test/cairo-test.h b/test/cairo-test.h
index 912ce8917..6260daed1 100644
--- a/test/cairo-test.h
+++ b/test/cairo-test.h
@@ -41,15 +41,25 @@ typedef struct cairo_test {
int height;
} cairo_test_t;
-typedef void (*cairo_test_draw_function_t) (cairo_t *cr, int width, int height);
+typedef cairo_test_status_t (*cairo_test_draw_function_t) (cairo_t *cr, int width, int height);
/* cairo_test.c */
cairo_test_status_t
cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw);
+cairo_test_status_t
+cairo_test_expect_failure (cairo_test_t *test,
+ cairo_test_draw_function_t draw,
+ const char *reason);
+
cairo_pattern_t *
cairo_test_create_png_pattern (cairo_t *cr, const char *filename);
+void
+cairo_test_log (const char *fmt, ...);
+
+void
+xasprintf (char **strp, const char *fmt, ...);
#endif
diff --git a/test/cairo_test.c b/test/cairo_test.c
deleted file mode 100644
index 06f7672fd..000000000
--- a/test/cairo_test.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * 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>
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-
-#include "cairo_test.h"
-
-#include "buffer_diff.h"
-#include "read_png.h"
-#include "write_png.h"
-#include "xmalloc.h"
-
-#define CAIRO_TEST_LOG_SUFFIX ".log"
-#define CAIRO_TEST_PNG_SUFFIX "-out.png"
-#define CAIRO_TEST_REF_SUFFIX "-ref.png"
-#define CAIRO_TEST_DIFF_SUFFIX "-diff.png"
-
-static void
-xasprintf (char **strp, const char *fmt, ...)
-{
-#ifdef HAVE_VASPRINTF
- va_list va;
- int ret;
-
- va_start (va, fmt);
- ret = vasprintf (strp, fmt, va);
- va_end (va);
-
- if (ret < 0) {
- fprintf (stderr, "Out of memory\n");
- exit (1);
- }
-#else /* !HAVE_VASNPRINTF */
-#define BUF_SIZE 1024
- va_list va;
- char buffer[BUF_SIZE];
- int ret;
-
- va_start (va, fmt);
- ret = vsnprintf (buffer, sizeof(buffer), fmt, va);
- va_end (va);
-
- if (ret < 0) {
- fprintf (stderr, "Failure in vsnprintf\n");
- exit (1);
- }
-
- if (strlen (buffer) == sizeof(buffer) - 1) {
- fprintf (stderr, "Overflowed fixed buffer\n");
- exit (1);
- }
-
- *strp = strdup (buffer);
- if (!*strp) {
- fprintf (stderr, "Out of memory\n");
- exit (1);
- }
-#endif /* !HAVE_VASNPRINTF */
-}
-
-static void
-xunlink (const char *pathname)
-{
- if (unlink (pathname) < 0 && errno != ENOENT) {
- fprintf (stderr, " Error: Cannot remove %s: %s\n",
- pathname, strerror (errno));
- exit (1);
- }
-}
-
-cairo_test_status_t
-cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
-{
- cairo_t *cr;
- int stride;
- unsigned char *png_buf, *ref_buf, *diff_buf;
- char *log_name, *png_name, *ref_name, *diff_name;
- char *srcdir;
- int pixels_changed;
- int ref_width, ref_height, ref_stride;
- read_png_status_t png_status;
- cairo_test_status_t ret;
- FILE *png_file;
- FILE *log_file;
-
- /* The cairo part of the test is the easiest part */
- cr = cairo_create ();
-
- stride = 4 * test->width;
-
- png_buf = xcalloc (stride * test->height, 1);
- diff_buf = xcalloc (stride * test->height, 1);
-
- cairo_set_target_image (cr, png_buf, CAIRO_FORMAT_ARGB32,
- test->width, test->height, stride);
-
- (draw) (cr, test->width, test->height);
-
- 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 = ".";
- xasprintf (&log_name, "%s%s", test->name, CAIRO_TEST_LOG_SUFFIX);
- 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);
-
- png_file = fopen (png_name, "w");
- write_png_argb32 (png_buf, png_file, test->width, test->height, stride);
- fclose (png_file);
-
- xunlink (log_name);
-
- ref_buf = NULL;
- png_status = (read_png_argb32 (ref_name, &ref_buf, &ref_width, &ref_height, &ref_stride));
- if (png_status) {
- log_file = fopen (log_name, "a");
- switch (png_status)
- {
- case READ_PNG_FILE_NOT_FOUND:
- fprintf (log_file, "Error: No reference image found: %s\n", ref_name);
- break;
- case READ_PNG_FILE_NOT_PNG:
- fprintf (log_file, "Error: %s is not a png image\n", ref_name);
- break;
- default:
- fprintf (log_file, "Error: Failed to read %s\n", ref_name);
- }
- fclose (log_file);
-
- ret = CAIRO_TEST_FAILURE;
- goto BAIL;
- } else {
- }
-
- if (test->width != ref_width || test->height != ref_height) {
- log_file = fopen (log_name, "a");
- fprintf (log_file,
- "Error: Image size mismatch: (%dx%d) vs. (%dx%d)\n"
- " for %s vs %s\n",
- test->width, test->height,
- ref_width, ref_height,
- png_name, ref_name);
- fclose (log_file);
-
- ret = CAIRO_TEST_FAILURE;
- goto BAIL;
- }
-
- pixels_changed = buffer_diff (png_buf, ref_buf, diff_buf,
- test->width, test->height, stride);
- if (pixels_changed) {
- log_file = fopen (log_name, "a");
- fprintf (log_file, "Error: %d pixels differ from reference image %s\n",
- pixels_changed, ref_name);
- png_file = fopen (diff_name, "w");
- write_png_argb32 (diff_buf, png_file, test->width, test->height, stride);
- fclose (png_file);
- fclose (log_file);
-
- ret = CAIRO_TEST_FAILURE;
- goto BAIL;
- } else {
- xunlink (diff_name);
- }
-
- ret = CAIRO_TEST_SUCCESS;
-
-BAIL:
- free (png_buf);
- free (ref_buf);
- free (diff_buf);
- free (log_name);
- free (png_name);
- free (ref_name);
- free (diff_name);
-
- return ret;
-}
-
-cairo_pattern_t *
-cairo_test_create_png_pattern (cairo_t *cr, const char *filename)
-{
- cairo_surface_t *image;
- cairo_pattern_t *pattern;
- unsigned char *buffer;
- int w, h, stride;
- read_png_status_t status;
- char *srcdir = getenv ("srcdir");
-
- status = read_png_argb32 (filename, &buffer, &w,&h, &stride);
- if (status != READ_PNG_SUCCESS) {
- if (srcdir) {
- char *srcdir_filename;
- xasprintf (&srcdir_filename, "%s/%s", srcdir, filename);
- status = read_png_argb32 (srcdir_filename, &buffer, &w,&h, &stride);
- free (srcdir_filename);
- }
- }
- if (status != READ_PNG_SUCCESS)
- return NULL;
-
- image = cairo_surface_create_for_image (buffer, CAIRO_FORMAT_ARGB32,
- w, h, stride);
-
- cairo_surface_set_repeat (image, 1);
-
- pattern = cairo_pattern_create_for_surface (image);
-
- return pattern;
-}
diff --git a/test/clip-nesting-ref.png b/test/clip-nesting-ref.png
new file mode 100644
index 000000000..6b7e1cd50
--- /dev/null
+++ b/test/clip-nesting-ref.png
Binary files differ
diff --git a/test/clip-nesting.c b/test/clip-nesting.c
new file mode 100644
index 000000000..801978037
--- /dev/null
+++ b/test/clip-nesting.c
@@ -0,0 +1,98 @@
+/*
+ * 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: Owen Taylor <otaylor@redhat.com>
+ */
+
+#include <math.h>
+#include "cairo-test.h"
+#include <stdio.h>
+
+#define SIZE 100
+#define BORDER 10
+#define LINE_WIDTH 20
+
+cairo_test_t test = {
+ "clip-nesting",
+ "Test clipping with multiple contexts for the same surface",
+ SIZE, SIZE
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *target_surface;
+ cairo_t *cr2, *cr3;
+
+ target_surface = cairo_get_target (cr);
+
+ cr2 = cairo_create (target_surface);
+
+ /* Draw a diagonal line and clip to it */
+
+ cairo_move_to (cr2, BORDER, BORDER);
+ cairo_line_to (cr2, BORDER + LINE_WIDTH, BORDER);
+ cairo_line_to (cr2, SIZE - BORDER, SIZE - BORDER);
+ cairo_line_to (cr2, SIZE - BORDER - LINE_WIDTH, SIZE - BORDER);
+
+ cairo_clip (cr2);
+ cairo_set_source_rgb (cr2, 0, 0, 1); /* Blue */
+ cairo_paint (cr2);
+
+ /* Clipping affects this cairo_t */
+
+ cairo_set_source_rgb (cr2, 1, 1, 1); /* White */
+ cairo_rectangle (cr2,
+ SIZE / 2 - LINE_WIDTH / 2, BORDER,
+ LINE_WIDTH, SIZE - 2 * BORDER);
+ cairo_fill (cr2);
+
+ /* But doesn't affect another cairo_t that we create temporarily for
+ * the same surface
+ */
+ cr3 = cairo_create (target_surface);
+ cairo_set_source_rgb (cr3, 1, 1, 1); /* White */
+ cairo_rectangle (cr3,
+ SIZE - BORDER - LINE_WIDTH, BORDER,
+ LINE_WIDTH, SIZE - 2 * BORDER);
+ cairo_fill (cr3);
+
+ cairo_destroy (cr3);
+ cairo_destroy (cr2);
+
+ /* And doesn't affect anything after this cairo_t is destroyed */
+
+ cairo_set_source_rgb (cr, 1, 1, 1); /* White */
+ cairo_rectangle (cr,
+ BORDER, BORDER,
+ LINE_WIDTH, SIZE - 2 * BORDER);
+ cairo_fill (cr);
+
+ return CAIRO_TEST_SUCCESS;
+
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/clip-twice.c b/test/clip-twice.c
index 00215e62c..eebfec944 100644
--- a/test/clip-twice.c
+++ b/test/clip-twice.c
@@ -23,21 +23,20 @@
* Author: Kristian Høgsberg <krh@redhat.com>
*/
-#include "cairo_test.h"
+#include "cairo-test.h"
#define WIDTH 64
#define HEIGHT 64
cairo_test_t test = {
- "clip_twice",
+ "clip-twice",
"Verifies that the clip mask is updated correctly when it constructed by setting the clip path twice.",
WIDTH, HEIGHT
};
-static void
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
- cairo_set_alpha (cr, 1.0);
cairo_new_path (cr);
cairo_arc (cr, WIDTH / 2, HEIGHT / 2, WIDTH / 3, 0, 2 * M_PI);
cairo_clip (cr);
@@ -52,7 +51,7 @@ draw (cairo_t *cr, int width, int height)
cairo_close_path (cr);
cairo_clip (cr);
- cairo_set_rgb_color (cr, 0, 0, 0.6);
+ cairo_set_source_rgb (cr, 0, 0, 0.6);
cairo_new_path (cr);
cairo_move_to (cr, 0, 0);
@@ -63,6 +62,8 @@ draw (cairo_t *cr, int width, int height)
cairo_line_to (cr, WIDTH / 2, HEIGHT / 4);
cairo_close_path (cr);
cairo_fill (cr);
+
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/clip_twice-ref.png b/test/clip_twice-ref.png
deleted file mode 100644
index ab0ae1aeb..000000000
--- a/test/clip_twice-ref.png
+++ /dev/null
Binary files differ
diff --git a/test/coverage-ref.png b/test/coverage-ref.png
deleted file mode 100644
index 9b7104057..000000000
--- a/test/coverage-ref.png
+++ /dev/null
Binary files differ
diff --git a/test/move_to_show_surface-ref.png b/test/create-for-png-ref.png
index 765adc4a4..765adc4a4 100644
--- a/test/move_to_show_surface-ref.png
+++ b/test/create-for-png-ref.png
Binary files differ
diff --git a/test/create-for-png.c b/test/create-for-png.c
new file mode 100644
index 000000000..ef3b6f62e
--- /dev/null
+++ b/test/create-for-png.c
@@ -0,0 +1,69 @@
+/*
+ * 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 Worth <cworth@cworth.org>
+ */
+
+#include "cairo-test.h"
+
+#include <stdlib.h>
+
+#define WIDTH 2
+#define HEIGHT 2
+
+cairo_test_t test = {
+ "create-for-png",
+ "Tests the creation of an image surface from a PNG file",
+ WIDTH, HEIGHT
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ char *srcdir = getenv ("srcdir");
+ char *filename;
+ cairo_surface_t *surface;
+
+ xasprintf (&filename, "%s/%s", srcdir ? srcdir : ".",
+ "create-for-png-ref.png");
+
+ surface = cairo_image_surface_create_from_png (filename);
+ free (filename);
+
+ if (surface == NULL) {
+ cairo_test_log ("Error: failed to open file %s\n", filename);
+ return CAIRO_TEST_FAILURE;
+ }
+
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+
+ cairo_surface_destroy (surface);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/create-from-png-ref.png b/test/create-from-png-ref.png
new file mode 100644
index 000000000..765adc4a4
--- /dev/null
+++ b/test/create-from-png-ref.png
Binary files differ
diff --git a/test/create-from-png.c b/test/create-from-png.c
new file mode 100644
index 000000000..ef3b6f62e
--- /dev/null
+++ b/test/create-from-png.c
@@ -0,0 +1,69 @@
+/*
+ * 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 Worth <cworth@cworth.org>
+ */
+
+#include "cairo-test.h"
+
+#include <stdlib.h>
+
+#define WIDTH 2
+#define HEIGHT 2
+
+cairo_test_t test = {
+ "create-for-png",
+ "Tests the creation of an image surface from a PNG file",
+ WIDTH, HEIGHT
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ char *srcdir = getenv ("srcdir");
+ char *filename;
+ cairo_surface_t *surface;
+
+ xasprintf (&filename, "%s/%s", srcdir ? srcdir : ".",
+ "create-for-png-ref.png");
+
+ surface = cairo_image_surface_create_from_png (filename);
+ free (filename);
+
+ if (surface == NULL) {
+ cairo_test_log ("Error: failed to open file %s\n", filename);
+ return CAIRO_TEST_FAILURE;
+ }
+
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+
+ cairo_surface_destroy (surface);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/fill-and-stroke-ref.png b/test/fill-and-stroke-ref.png
new file mode 100644
index 000000000..298f6945f
--- /dev/null
+++ b/test/fill-and-stroke-ref.png
Binary files differ
diff --git a/test/fill-and-stroke.c b/test/fill-and-stroke.c
new file mode 100644
index 000000000..989317112
--- /dev/null
+++ b/test/fill-and-stroke.c
@@ -0,0 +1,63 @@
+/*
+ * 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>
+ */
+
+#include "cairo-test.h"
+
+#define PAD 2
+#define SIZE 10
+
+cairo_test_t test = {
+ "fill-and-stroke",
+ "Tests calls to various set_source functions",
+ 2 * SIZE + 4 * PAD, SIZE + 2 * PAD
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_rectangle (cr, PAD, PAD, SIZE, SIZE);
+ cairo_set_source_rgb (cr, 0, 0, 1);
+ cairo_fill_preserve (cr);
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ cairo_stroke (cr);
+
+ cairo_translate (cr, SIZE + 2 * PAD, 0);
+
+ cairo_arc (cr,
+ PAD + SIZE / 2, PAD + SIZE / 2,
+ SIZE / 2,
+ 0, 2 * M_PI);
+ cairo_fill_preserve (cr);
+ cairo_set_source_rgb (cr, 0, 0, 1);
+ cairo_stroke (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/fill-rule.c b/test/fill-rule.c
index 037a044ab..103208cab 100644
--- a/test/fill-rule.c
+++ b/test/fill-rule.c
@@ -61,13 +61,13 @@
*
*/
-#include "cairo_test.h"
+#include "cairo-test.h"
#define LITTLE_STAR_SIZE 20
#define BIG_STAR_SIZE 80
cairo_test_t test = {
- "fill_rule",
+ "fill-rule",
"Tests cairo_set_full_rule with some star shapes",
BIG_STAR_SIZE * 2 + 3, BIG_STAR_SIZE + LITTLE_STAR_SIZE + 3
};
@@ -97,10 +97,10 @@ big_star_path (cairo_t *cr)
}
/* Fill the same path twice, once with each fill rule */
-static void
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
- cairo_set_rgb_color (cr, 1, 0, 0);
+ cairo_set_source_rgb (cr, 1, 0, 0);
cairo_translate (cr, 1, 1);
little_star_path (cr);
@@ -121,6 +121,8 @@ draw (cairo_t *cr, int width, int height)
big_star_path (cr);
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
cairo_fill (cr);
+
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/fill_rule-ref.png b/test/fill_rule-ref.png
deleted file mode 100644
index e2e10d4a8..000000000
--- a/test/fill_rule-ref.png
+++ /dev/null
Binary files differ
diff --git a/test/fill_rule.c b/test/fill_rule.c
deleted file mode 100644
index 037a044ab..000000000
--- a/test/fill_rule.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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-10-27 Carl Worth <cworth@cworth.org>
- *
- * There's currently a regression bug in the tessellation code. This
- * causes each of these simple star shapes to be filled incorrectly.
- *
- * It looks like right now we can get this test to pass by doing:
- *
- * cvs update -r 1.16 src/cairo_traps.c
- *
- * But we don't want to revert that change permanently since it
- * really does correct some bugs. It must be that the old version of
- * the code is masking some other bugs in the tessellation code. My
- * current plan is to back this revision up for the next snapshot,
- * but not to list the test as an expected failure since I'm
- * 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 LITTLE_STAR_SIZE 20
-#define BIG_STAR_SIZE 80
-
-cairo_test_t test = {
- "fill_rule",
- "Tests cairo_set_full_rule with some star shapes",
- BIG_STAR_SIZE * 2 + 3, BIG_STAR_SIZE + LITTLE_STAR_SIZE + 3
-};
-
-/* The SVG start trimmed down, but still showing the bug (originally) */
-static void
-little_star_path (cairo_t *cr)
-{
- cairo_move_to (cr, 10, 0);
- cairo_rel_line_to (cr, 6, 20);
- cairo_rel_line_to (cr, -16, -12);
- cairo_rel_line_to (cr, 20, 0);
- 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)
-{
- cairo_set_rgb_color (cr, 1, 0, 0);
-
- cairo_translate (cr, 1, 1);
- 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, BIG_STAR_SIZE + 1, 0);
- big_star_path (cr);
- cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
- cairo_fill (cr);
-}
-
-int
-main (void)
-{
- return cairo_test (&test, draw);
-}
diff --git a/test/filter-nearest-offset-ref.png b/test/filter-nearest-offset-ref.png
new file mode 100644
index 000000000..46092e3c7
--- /dev/null
+++ b/test/filter-nearest-offset-ref.png
Binary files differ
diff --git a/test/filter-nearest-offset.c b/test/filter-nearest-offset.c
new file mode 100644
index 000000000..74ad47611
--- /dev/null
+++ b/test/filter-nearest-offset.c
@@ -0,0 +1,107 @@
+/*
+ * 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>
+ */
+
+#include "cairo-test.h"
+
+#define STAMP_WIDTH 4
+#define STAMP_HEIGHT 4
+#define PAD 1
+
+#define STEPS 10
+
+#define IMAGE_WIDTH (PAD + STEPS * (STAMP_WIDTH + PAD) + PAD)
+#define IMAGE_HEIGHT (PAD + STEPS * (STAMP_HEIGHT + PAD) + PAD)
+
+cairo_test_t test = {
+ "filter-nearest-offset",
+ "Test sampling offset of CAIRO_FILTER_NEAREST",
+ IMAGE_WIDTH, IMAGE_HEIGHT
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *surface;
+ unsigned long data[STAMP_WIDTH * STAMP_HEIGHT] = {
+ 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000,
+ 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000,
+
+ 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff,
+ 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff
+ };
+ int i, j;
+
+ /* Draw reference lines where the jump should be. */
+ cairo_move_to (cr, PAD + STEPS / 2 * (STAMP_WIDTH + PAD), 0);
+ cairo_rel_line_to (cr, 0, IMAGE_HEIGHT);
+ cairo_move_to (cr, 0, PAD + STEPS / 2 * (STAMP_HEIGHT + PAD));
+ cairo_rel_line_to (cr, IMAGE_WIDTH, 0);
+ cairo_set_line_width (cr, 2.0);
+ cairo_stroke (cr);
+
+ surface = cairo_image_surface_create_for_data ((unsigned char *) data,
+ CAIRO_FORMAT_ARGB32,
+ STAMP_WIDTH,
+ STAMP_HEIGHT,
+ STAMP_WIDTH * 4);
+
+ for (j=0; j < STEPS; j++) {
+ double j_step;
+
+ for (i=0; i < STEPS; i++) {
+ double i_step;
+
+#define GENERATE_REFERENCE_IMAGE 0
+#if GENERATE_REFERENCE_IMAGE
+ i_step = i >= STEPS / 2 ? 1 : 0;
+ j_step = j >= STEPS / 2 ? 1 : 0;
+#else
+ i_step = i * 1.0 / STEPS;
+ j_step = j * 1.0 / STEPS;
+#endif
+
+ cairo_save (cr);
+
+ cairo_set_source_surface (cr, surface,
+ PAD + i * (STAMP_WIDTH + PAD) + i_step,
+ PAD + j * (STAMP_HEIGHT + PAD) + j_step);
+ cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_BEST);
+ cairo_paint (cr);
+
+ cairo_restore (cr);
+ }
+ }
+
+ cairo_surface_destroy (surface);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test_expect_failure (&test, draw,
+ "wrong sampling location for nearest-neighbor filter in libpixman and Render");
+}
diff --git a/test/get-and-set.c b/test/get-and-set.c
new file mode 100644
index 000000000..72d661047
--- /dev/null
+++ b/test/get-and-set.c
@@ -0,0 +1,142 @@
+/*
+ * 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>
+ */
+
+#include "cairo-test.h"
+
+cairo_test_t test = {
+ "get-and-set",
+ "Tests calls to the most trivial cairo_get and cairo_set functions",
+ 0, 0
+};
+
+typedef struct {
+ cairo_operator_t operator;
+ double tolerance;
+ cairo_fill_rule_t fill_rule;
+ double line_width;
+ cairo_line_cap_t line_cap;
+ cairo_line_join_t line_join;
+ double miter_limit;
+ cairo_matrix_t matrix;
+} settings_t;
+
+/* Two sets of settings, no defaults */
+settings_t settings[] = {
+ {
+ CAIRO_OPERATOR_IN,
+ 2.0,
+ CAIRO_FILL_RULE_EVEN_ODD,
+ 7.7,
+ CAIRO_LINE_CAP_SQUARE,
+ CAIRO_LINE_JOIN_ROUND,
+ 3.14,
+ {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}
+ },
+ {
+ CAIRO_OPERATOR_ATOP,
+ 5.25,
+ CAIRO_FILL_RULE_WINDING,
+ 2.17,
+ CAIRO_LINE_CAP_ROUND,
+ CAIRO_LINE_JOIN_BEVEL,
+ 1000.0,
+ {.1, .01, .001, .0001, .00001, .000001}
+ }
+};
+
+static void
+settings_set (cairo_t *cr, settings_t *settings)
+{
+ cairo_set_operator (cr, settings->operator);
+ cairo_set_tolerance (cr, settings->tolerance);
+ cairo_set_fill_rule (cr, settings->fill_rule);
+ cairo_set_line_width (cr, settings->line_width);
+ cairo_set_line_cap (cr, settings->line_cap);
+ cairo_set_line_join (cr, settings->line_join);
+ cairo_set_miter_limit (cr, settings->miter_limit);
+ cairo_set_matrix (cr, &settings->matrix);
+}
+
+static void
+settings_get (cairo_t *cr, settings_t *settings)
+{
+ settings->operator = cairo_get_operator (cr);
+ settings->tolerance = cairo_get_tolerance (cr);
+ settings->fill_rule = cairo_get_fill_rule (cr);
+ settings->line_width = cairo_get_line_width (cr);
+ settings->line_cap = cairo_get_line_cap (cr);
+ settings->line_join = cairo_get_line_join (cr);
+ settings->miter_limit = cairo_get_miter_limit (cr);
+ cairo_get_matrix (cr, &settings->matrix);
+}
+
+static int
+settings_equal (settings_t *a, settings_t *b)
+{
+ return (a->operator == b->operator &&
+ a->tolerance == b->tolerance &&
+ a->fill_rule == b->fill_rule &&
+ a->line_width == b->line_width &&
+ a->line_cap == b->line_cap &&
+ a->line_join == b->line_join &&
+ a->miter_limit == b->miter_limit &&
+ a->matrix.xx == b->matrix.xx &&
+ a->matrix.xy == b->matrix.xy &&
+ a->matrix.x0 == b->matrix.x0 &&
+ a->matrix.yx == b->matrix.yx &&
+ a->matrix.yy == b->matrix.yy &&
+ a->matrix.y0 == b->matrix.y0);
+}
+
+static cairo_test_status_t
+get_and_set (cairo_t *cr, int width, int height)
+{
+ settings_t check;
+
+ settings_set (cr, &settings[0]);
+
+ cairo_save (cr);
+ {
+ settings_set (cr, &settings[1]);
+ settings_get (cr, &check);
+
+ if (!settings_equal (&settings[1], &check))
+ return CAIRO_TEST_FAILURE;
+ }
+ cairo_restore (cr);
+
+ settings_get (cr, &check);
+
+ if (!settings_equal (&settings[0], &check))
+ return CAIRO_TEST_FAILURE;
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, get_and_set);
+}
diff --git a/test/gradient-alpha-ref.png b/test/gradient-alpha-ref.png
new file mode 100644
index 000000000..e75f91105
--- /dev/null
+++ b/test/gradient-alpha-ref.png
Binary files differ
diff --git a/test/cairo_test.h b/test/gradient-alpha.c
index 912ce8917..3015728b0 100644
--- a/test/cairo_test.h
+++ b/test/gradient-alpha.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2004 Red Hat, Inc.
+ * 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
@@ -23,33 +23,39 @@
* Author: Carl D. Worth <cworth@cworth.org>
*/
-#ifndef _CAIRO_TEST_H_
-#define _CAIRO_TEST_H_
-
-#include <math.h>
-#include <cairo.h>
-
-typedef enum cairo_test_status {
- CAIRO_TEST_SUCCESS = 0,
- CAIRO_TEST_FAILURE
-} cairo_test_status_t;
-
-typedef struct cairo_test {
- char *name;
- char *description;
- int width;
- int height;
-} cairo_test_t;
-
-typedef void (*cairo_test_draw_function_t) (cairo_t *cr, int width, int height);
-
-/* cairo_test.c */
-cairo_test_status_t
-cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw);
-
-cairo_pattern_t *
-cairo_test_create_png_pattern (cairo_t *cr, const char *filename);
-
-
-#endif
-
+#include "cairo-test.h"
+
+cairo_test_t test = {
+ "gradient-alpha",
+ "Tests drawing of a gradient with various alpha values in the color stops",
+ 10, 10
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_pattern_t *gradient;
+
+ gradient = cairo_pattern_create_linear (0, -height,
+ 0, height);
+ cairo_pattern_add_color_stop_rgba (gradient, 0.0,
+ 1.0, 0.0, 0.0,
+ 1.0);
+ cairo_pattern_add_color_stop_rgba (gradient, 1.0,
+ 0.0, 0.0, 1.0,
+ 0.5);
+
+ cairo_set_source (cr, gradient);
+
+ cairo_paint (cr);
+
+ cairo_pattern_destroy (gradient);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/imagediff.c b/test/imagediff.c
index 36962f11f..8e13a1fe5 100644
--- a/test/imagediff.c
+++ b/test/imagediff.c
@@ -26,9 +26,9 @@
#include <stdio.h>
#include <stdlib.h>
-#include "buffer_diff.h"
-#include "read_png.h"
-#include "write_png.h"
+#include "buffer-diff.h"
+#include "read-png.h"
+#include "write-png.h"
#include "xmalloc.h"
int
@@ -77,7 +77,7 @@ main (int argc, char *argv[])
free (buffer);
- return 0;
+ return total_pixels_changed;
}
diff --git a/test/leaky-polygon.c b/test/leaky-polygon.c
index 39daf4ca3..575311ee9 100644
--- a/test/leaky-polygon.c
+++ b/test/leaky-polygon.c
@@ -51,18 +51,18 @@
*
*/
-#include "cairo_test.h"
+#include "cairo-test.h"
#define WIDTH 21
#define HEIGHT 21
cairo_test_t test = {
- "leaky_polygon",
+ "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
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
cairo_scale (cr, 1.0/(1<<16), 1.0/(1<<16));
@@ -73,6 +73,8 @@ draw (cairo_t *cr, int width, int height)
cairo_close_path (cr);
cairo_fill (cr);
+
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/leaky_polygon-ref.png b/test/leaky_polygon-ref.png
deleted file mode 100644
index 0daabe15a..000000000
--- a/test/leaky_polygon-ref.png
+++ /dev/null
Binary files differ
diff --git a/test/line-width.c b/test/line-width.c
index 9c3ed89b9..ca2d2760b 100644
--- a/test/line-width.c
+++ b/test/line-width.c
@@ -23,7 +23,7 @@
* Author: Carl D. Worth <cworth@cworth.org>
*/
-#include "cairo_test.h"
+#include "cairo-test.h"
#define LINES 5
#define LINE_LENGTH 10
@@ -31,17 +31,17 @@
#define IMAGE_HEIGHT ((LINES+4)*LINES)/2 + 2
cairo_test_t test = {
- "line_width",
+ "line-width",
"Tests cairo_set_line_width",
IMAGE_WIDTH, IMAGE_HEIGHT
};
-static void
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
int i;
- cairo_set_rgb_color (cr, 0, 0, 0);
+ cairo_set_source_rgb (cr, 0, 0, 0);
cairo_translate (cr, 2, 2);
for (i=0; i < LINES; i++) {
@@ -54,6 +54,8 @@ draw (cairo_t *cr, int width, int height)
cairo_stroke (cr);
cairo_translate (cr, 0, i+3);
}
+
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/line_width-ref.png b/test/line_width-ref.png
deleted file mode 100644
index ddcd929d8..000000000
--- a/test/line_width-ref.png
+++ /dev/null
Binary files differ
diff --git a/test/linear-gradient.c b/test/linear-gradient.c
index 189b50065..38ba559d0 100644
--- a/test/linear-gradient.c
+++ b/test/linear-gradient.c
@@ -23,7 +23,7 @@
* Author: Owen Taylor <otaylor@redhat.com>
*/
-#include "cairo_test.h"
+#include "cairo-test.h"
#include "stdio.h"
/* The test matrix is
@@ -55,7 +55,7 @@ static const int n_stops[] = { 2, 3 };
#define HEIGHT N_N_STOPS * N_ROTATE_ANGLES * UNIT_SIZE + (N_N_STOPS * N_ROTATE_ANGLES + 1) * PAD
cairo_test_t test = {
- "linear_gradient",
+ "linear-gradient",
"Tests the drawing of linear gradients",
WIDTH, HEIGHT
};
@@ -72,7 +72,7 @@ draw_unit (cairo_t *cr,
cairo_clip (cr);
cairo_new_path(cr);
- cairo_set_rgb_color (cr, 0.0, 0.0, 0.0);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_rectangle (cr, 0, 0, 1, 1);
cairo_fill (cr);
@@ -84,38 +84,32 @@ draw_unit (cairo_t *cr,
0.5 * cos (gradient_angle), 0.5 * sin (gradient_angle));
if (n_stops == 2) {
- cairo_pattern_add_color_stop (pattern, 0.,
- 0.3, 0.3, 0.3,
- 1.0);
- cairo_pattern_add_color_stop (pattern, 1.,
- 1.0, 1.0, 1.0,
- 1.0);
+ cairo_pattern_add_color_stop_rgb (pattern, 0.,
+ 0.3, 0.3, 0.3);
+ cairo_pattern_add_color_stop_rgb (pattern, 1.,
+ 1.0, 1.0, 1.0);
} else {
- cairo_pattern_add_color_stop (pattern, 0.,
- 1.0, 0.0, 0.0,
- 1.0);
- cairo_pattern_add_color_stop (pattern, 0.5,
- 1.0, 1.0, 1.0,
- 1.0);
- cairo_pattern_add_color_stop (pattern, 1.,
- 0.0, 0.0, 1.0,
- 1.0);
+ cairo_pattern_add_color_stop_rgb (pattern, 0.,
+ 1.0, 0.0, 0.0);
+ cairo_pattern_add_color_stop_rgb (pattern, 0.5,
+ 1.0, 1.0, 1.0);
+ cairo_pattern_add_color_stop_rgb (pattern, 1.,
+ 0.0, 0.0, 1.0);
}
- cairo_set_pattern (cr, pattern);
+ cairo_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
cairo_rectangle (cr, -0.5, -0.5, 1, 1);
cairo_fill (cr);
}
-static void
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
int i, j, k;
- cairo_set_rgb_color (cr, 0.5, 0.5, 0.5);
- cairo_rectangle (cr, 0, 0, width, height);
- cairo_fill (cr);
+ cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
+ cairo_paint (cr);
for (i = 0; i < N_GRADIENT_ANGLES; i++)
for (j = 0; j < N_ROTATE_ANGLES; j++)
@@ -132,6 +126,8 @@ draw (cairo_t *cr, int width, int height)
n_stops[k]);
cairo_restore (cr);
}
+
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/linear_gradient-ref.png b/test/linear_gradient-ref.png
deleted file mode 100644
index 77904144d..000000000
--- a/test/linear_gradient-ref.png
+++ /dev/null
Binary files differ
diff --git a/test/linear_gradient.c b/test/linear_gradient.c
deleted file mode 100644
index 189b50065..000000000
--- a/test/linear_gradient.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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: Owen Taylor <otaylor@redhat.com>
- */
-
-#include "cairo_test.h"
-#include "stdio.h"
-
-/* The test matrix is
- *
- * A) Horizontal B) 5° C) 45° D) Vertical
- * 1) Rotated 0° 2) Rotated 45° C) Rotated 90°
- * a) 2 stop b) 3 stop
- *
- * A1a B1a C1a D1a
- * A2a B2a C2a D2a
- * A3a B3a C3a D3a
- * A1b B1b C1b D1b
- * A2b B2b C2b D2b
- * A3b B3b C3b D3b
- */
-
-static const double gradient_angles[] = { 0, 45, 90 };
-#define N_GRADIENT_ANGLES 3
-static const double rotate_angles[] = { 0, 45, 90 };
-#define N_ROTATE_ANGLES 3
-static const int n_stops[] = { 2, 3 };
-#define N_N_STOPS 2
-
-#define UNIT_SIZE 75
-#define UNIT_SIZE 75
-#define PAD 5
-
-#define WIDTH N_GRADIENT_ANGLES * UNIT_SIZE + (N_GRADIENT_ANGLES + 1) * PAD
-#define HEIGHT N_N_STOPS * N_ROTATE_ANGLES * UNIT_SIZE + (N_N_STOPS * N_ROTATE_ANGLES + 1) * PAD
-
-cairo_test_t test = {
- "linear_gradient",
- "Tests the drawing of linear gradients",
- WIDTH, HEIGHT
-};
-
-static void
-draw_unit (cairo_t *cr,
- double gradient_angle,
- double rotate_angle,
- int n_stops)
-{
- cairo_pattern_t *pattern;
-
- cairo_rectangle (cr, 0, 0, 1, 1);
- cairo_clip (cr);
- cairo_new_path(cr);
-
- cairo_set_rgb_color (cr, 0.0, 0.0, 0.0);
- cairo_rectangle (cr, 0, 0, 1, 1);
- cairo_fill (cr);
-
- cairo_translate (cr, 0.5, 0.5);
- cairo_scale (cr, 1 / 1.5, 1 / 1.5);
- cairo_rotate (cr, rotate_angle);
-
- pattern = cairo_pattern_create_linear (-0.5 * cos (gradient_angle), -0.5 * sin (gradient_angle),
- 0.5 * cos (gradient_angle), 0.5 * sin (gradient_angle));
-
- if (n_stops == 2) {
- cairo_pattern_add_color_stop (pattern, 0.,
- 0.3, 0.3, 0.3,
- 1.0);
- cairo_pattern_add_color_stop (pattern, 1.,
- 1.0, 1.0, 1.0,
- 1.0);
- } else {
- cairo_pattern_add_color_stop (pattern, 0.,
- 1.0, 0.0, 0.0,
- 1.0);
- cairo_pattern_add_color_stop (pattern, 0.5,
- 1.0, 1.0, 1.0,
- 1.0);
- cairo_pattern_add_color_stop (pattern, 1.,
- 0.0, 0.0, 1.0,
- 1.0);
- }
-
- cairo_set_pattern (cr, pattern);
- cairo_pattern_destroy (pattern);
- cairo_rectangle (cr, -0.5, -0.5, 1, 1);
- cairo_fill (cr);
-}
-
-static void
-draw (cairo_t *cr, int width, int height)
-{
- int i, j, k;
-
- cairo_set_rgb_color (cr, 0.5, 0.5, 0.5);
- cairo_rectangle (cr, 0, 0, width, height);
- cairo_fill (cr);
-
- for (i = 0; i < N_GRADIENT_ANGLES; i++)
- for (j = 0; j < N_ROTATE_ANGLES; j++)
- for (k = 0; k < N_N_STOPS; k++) {
- cairo_save (cr);
- cairo_translate (cr,
- PAD + (PAD + UNIT_SIZE) * i,
- PAD + (PAD + UNIT_SIZE) * (N_ROTATE_ANGLES * k + j));
- cairo_scale (cr, UNIT_SIZE, UNIT_SIZE);
-
- draw_unit (cr,
- gradient_angles[i] * M_PI / 180.,
- rotate_angles[j] * M_PI / 180.,
- n_stops[k]);
- cairo_restore (cr);
- }
-}
-
-int
-main (void)
-{
- return cairo_test (&test, draw);
-}
diff --git a/test/mask-ref.png b/test/mask-ref.png
new file mode 100644
index 000000000..4b357c0a0
--- /dev/null
+++ b/test/mask-ref.png
Binary files differ
diff --git a/test/mask.c b/test/mask.c
new file mode 100644
index 000000000..ec0322da0
--- /dev/null
+++ b/test/mask.c
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ *
+ * Authors: Owen Taylor <otaylor@redhat.com>
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include <math.h>
+#include "cairo-test.h"
+#include <stdio.h>
+
+#define WIDTH 64
+#define HEIGHT 64
+#define PAD 10
+
+const char png_filename[] = "romedalen.png";
+
+static void
+set_solid_pattern (cairo_t *cr, int x, int y)
+{
+ cairo_set_source_rgb (cr, 0, 0, 0.6);
+}
+
+static void
+set_translucent_pattern (cairo_t *cr, int x, int y)
+{
+ cairo_set_source_rgba (cr, 0, 0, 0.6, 0.5);
+}
+
+static void
+set_gradient_pattern (cairo_t *cr, int x, int y)
+{
+ cairo_pattern_t *pattern;
+
+ pattern =
+ cairo_pattern_create_linear (x, y, x + WIDTH, y + HEIGHT);
+ cairo_pattern_add_color_stop_rgba (pattern, 0, 1, 1, 1, 1);
+ cairo_pattern_add_color_stop_rgba (pattern, 1, 0, 0, 0.4, 1);
+ cairo_set_source (cr, pattern);
+}
+
+static void
+set_image_pattern (cairo_t *cr, int x, int y)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = cairo_test_create_png_pattern (cr, png_filename);
+ cairo_set_source (cr, pattern);
+}
+
+static void
+mask_polygon (cairo_t *cr, int x, int y)
+{
+ cairo_surface_t *mask_surface;
+ cairo_t *cr2;
+
+ mask_surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_FORMAT_A8,
+ WIDTH, HEIGHT);
+ cr2 = cairo_create (mask_surface);
+
+ cairo_save (cr2);
+ cairo_set_source_rgba (cr2, 0, 0, 0, 0); /* transparent */
+ cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr2);
+ cairo_restore (cr2);
+
+ cairo_set_source_rgb (cr2, 1, 1, 1); /* white */
+
+ cairo_new_path (cr2);
+ cairo_move_to (cr2, 0, 0);
+ cairo_line_to (cr2, 0, HEIGHT);
+ cairo_line_to (cr2, WIDTH / 2, 3 * HEIGHT / 4);
+ cairo_line_to (cr2, WIDTH, HEIGHT);
+ cairo_line_to (cr2, WIDTH, 0);
+ cairo_line_to (cr2, WIDTH / 2, HEIGHT / 4);
+ cairo_close_path (cr2);
+ cairo_fill (cr2);
+
+ cairo_destroy (cr2);
+
+ cairo_mask_surface (cr, mask_surface, x, y);
+
+ cairo_surface_destroy (mask_surface);
+}
+
+static void
+mask_alpha (cairo_t *cr, int x, int y)
+{
+ cairo_paint_with_alpha (cr, 0.75);
+}
+
+static void
+mask_gradient (cairo_t *cr, int x, int y)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = cairo_pattern_create_linear (x, y,
+ x + WIDTH, y + HEIGHT);
+
+ cairo_pattern_add_color_stop_rgba (pattern,
+ 0,
+ 1, 1, 1, 1);
+ cairo_pattern_add_color_stop_rgba (pattern,
+ 1,
+ 1, 1, 1, 0);
+
+ cairo_mask (cr, pattern);
+
+ cairo_pattern_destroy (pattern);
+}
+
+static void
+clip_none (cairo_t *cr, int x, int y)
+{
+}
+
+static void
+clip_rects (cairo_t *cr, int x, int y)
+{
+ int height = HEIGHT / 3;
+
+ cairo_new_path (cr);
+ cairo_rectangle (cr, x, y, WIDTH, height);
+ cairo_rectangle (cr, x, y + 2 * height, WIDTH, height);
+ cairo_clip (cr);
+}
+
+static void
+clip_circle (cairo_t *cr, int x, int y)
+{
+ cairo_new_path (cr);
+ cairo_arc (cr, x + WIDTH / 2, y + HEIGHT / 2,
+ WIDTH / 2, 0, 2 * M_PI);
+ cairo_clip (cr);
+ cairo_new_path (cr);
+}
+
+static void (*pattern_funcs[])(cairo_t *cr, int x, int y) = {
+ set_solid_pattern,
+ set_translucent_pattern,
+ set_gradient_pattern,
+ set_image_pattern,
+};
+
+static void (*mask_funcs[])(cairo_t *cr, int x, int y) = {
+ mask_alpha,
+ mask_gradient,
+ mask_polygon,
+};
+
+static void (*clip_funcs[])(cairo_t *cr, int x, int y) = {
+ clip_none,
+ clip_rects,
+ clip_circle,
+};
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+#define IMAGE_WIDTH (ARRAY_SIZE (pattern_funcs) * (WIDTH + PAD) + PAD)
+#define IMAGE_HEIGHT (ARRAY_SIZE (mask_funcs) * ARRAY_SIZE (clip_funcs) * (HEIGHT + PAD) + PAD)
+
+static cairo_test_t test = {
+ "mask",
+ "Tests of cairo_mask",
+ IMAGE_WIDTH, IMAGE_HEIGHT
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *tmp_surface;
+ cairo_pattern_t *tmp_pattern;
+ int i, j, k;
+ cairo_t *cr2;
+
+ /* Some of our drawing is unbounded, so we draw each test to
+ * a temporary surface and copy over.
+ */
+ tmp_surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_FORMAT_ARGB32,
+ IMAGE_WIDTH, IMAGE_HEIGHT);
+ cr2 = cairo_create (tmp_surface);
+
+ tmp_pattern = cairo_pattern_create_for_surface (tmp_surface);
+ cairo_set_source (cr, tmp_pattern);
+
+ for (k = 0; k < ARRAY_SIZE (clip_funcs); k++) {
+ for (j = 0; j < ARRAY_SIZE (mask_funcs); j++) {
+ for (i = 0; i < ARRAY_SIZE (pattern_funcs); i++) {
+ int x = i * (WIDTH + PAD) + PAD;
+ int y = (ARRAY_SIZE (mask_funcs) * k + j) * (HEIGHT + PAD) + PAD;
+
+ /* Clear area we are going to be drawing onto */
+ cairo_save (cr2);
+ cairo_set_source_rgba (cr2, 0, 0, 0, 0); /* transparent */
+ cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE);
+ cairo_rectangle (cr2, x, y, WIDTH, HEIGHT);
+ cairo_fill (cr2);
+ cairo_restore (cr2);
+
+ /* draw */
+ cairo_save (cr2);
+
+ clip_funcs[k] (cr2, x, y);
+ pattern_funcs[i] (cr2, x, y);
+ mask_funcs[j] (cr2, x, y);
+
+ cairo_restore (cr2);
+
+ /* Copy back to the main pixmap */
+ cairo_rectangle (cr, x, y, WIDTH, HEIGHT);
+ cairo_fill (cr);
+ }
+ }
+ }
+
+ cairo_destroy (cr2);
+ cairo_surface_destroy (tmp_surface);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/move-to-show-surface.c b/test/move-to-show-surface.c
index 6dcda2103..c5cc1ae59 100644
--- a/test/move-to-show-surface.c
+++ b/test/move-to-show-surface.c
@@ -32,34 +32,46 @@
* bit of poking around suggests this isn't a regression, (at least
* not since the last pixman snapshot).
*
+ * 2005-04-02 Carl Worth <cworth@cworth.org>
+ *
+ * Status: RESOLVED
+ *
+ * Inside cairo_show_surface the current point was being used as
+ * both source and destination offsets. After fixing that to use 0,0
+ * as the source offset and the current point as the destination
+ * offset, the bug seems to be gone.
+ *
*/
-
-#include "cairo_test.h"
+#include "cairo-test.h"
cairo_test_t test = {
- "move_to_show_surface",
+ "move-to-show-surface",
"Tests calls to cairo_show_surface after cairo_move_to",
2, 2
};
-static void
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
cairo_surface_t *surface;
- uint32_t colors[4] = {
+ unsigned long colors[4] = {
0xffffffff, 0xffff0000,
0xff00ff00, 0xff0000ff
};
int i;
for (i=0; i < 4; i++) {
- surface = cairo_surface_create_for_image ((char *) &colors[i],
- CAIRO_FORMAT_ARGB32, 1, 1, 4);
- cairo_move_to (cr, i % 2, i / 2);
- cairo_show_surface (cr, surface, 1, 1);
+ surface = cairo_image_surface_create_for_data ((unsigned char *) &colors[i],
+ CAIRO_FORMAT_ARGB32,
+ 1, 1, 4);
+ cairo_set_source_surface (cr, surface,
+ i % 2, i / 2);
+ cairo_paint (cr);
cairo_surface_destroy (surface);
}
+
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/paint-ref.png b/test/paint-ref.png
new file mode 100644
index 000000000..fff03b363
--- /dev/null
+++ b/test/paint-ref.png
Binary files differ
diff --git a/test/paint-with-alpha-ref.png b/test/paint-with-alpha-ref.png
new file mode 100644
index 000000000..d821b5ebc
--- /dev/null
+++ b/test/paint-with-alpha-ref.png
Binary files differ
diff --git a/test/move_to_show_surface.c b/test/paint-with-alpha.c
index 6dcda2103..f4734afdb 100644
--- a/test/move_to_show_surface.c
+++ b/test/paint-with-alpha.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2004 Red Hat, Inc.
+ * 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
@@ -23,43 +23,38 @@
* Author: Carl D. Worth <cworth@cworth.org>
*/
-/* Bug history
- *
- * 2004-10-25 Carl Worth <cworth@cworth.org>
- *
- * It looks like cairo_show_surface has no effect if it follows a
- * 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).
- *
- */
-
-
-#include "cairo_test.h"
+#include "cairo-test.h"
cairo_test_t test = {
- "move_to_show_surface",
- "Tests calls to cairo_show_surface after cairo_move_to",
- 2, 2
+ "paint-with-alpha",
+ "Simple test of cairo_paint_with_alpha",
+ 12, 12
};
-static void
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
cairo_surface_t *surface;
- uint32_t colors[4] = {
- 0xffffffff, 0xffff0000,
- 0xff00ff00, 0xff0000ff
+ unsigned long data[16] = {
+ 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000,
+ 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000,
+
+ 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff,
+ 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff
};
- int i;
- for (i=0; i < 4; i++) {
- surface = cairo_surface_create_for_image ((char *) &colors[i],
- CAIRO_FORMAT_ARGB32, 1, 1, 4);
- cairo_move_to (cr, i % 2, i / 2);
- cairo_show_surface (cr, surface, 1, 1);
- cairo_surface_destroy (surface);
- }
+ surface = cairo_image_surface_create_for_data ((unsigned char *) data,
+ CAIRO_FORMAT_ARGB32, 4, 4, 16);
+
+ cairo_scale (cr, 2, 2);
+
+ cairo_set_source_surface (cr, surface, 1 , 1);
+ cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
+ cairo_paint_with_alpha (cr, 0.5);
+
+ cairo_surface_destroy (surface);
+
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/line_width.c b/test/paint.c
index 9c3ed89b9..126becc9c 100644
--- a/test/line_width.c
+++ b/test/paint.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2004 Red Hat, Inc.
+ * 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
@@ -23,37 +23,27 @@
* Author: Carl D. Worth <cworth@cworth.org>
*/
-#include "cairo_test.h"
-
-#define LINES 5
-#define LINE_LENGTH 10
-#define IMAGE_WIDTH 2 * LINE_LENGTH + 6
-#define IMAGE_HEIGHT ((LINES+4)*LINES)/2 + 2
+#include "cairo-test.h"
cairo_test_t test = {
- "line_width",
- "Tests cairo_set_line_width",
- IMAGE_WIDTH, IMAGE_HEIGHT
+ "paint",
+ "Test calls to cairo_paint",
+ 8, 8
};
-static void
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
- int i;
+ cairo_set_source_rgb (cr, 0, 0, 1);
+ cairo_paint (cr);
- cairo_set_rgb_color (cr, 0, 0, 0);
cairo_translate (cr, 2, 2);
+ cairo_scale (cr, 0.5, 0.5);
+
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ cairo_paint (cr);
- for (i=0; i < LINES; i++) {
- cairo_set_line_width (cr, i+1);
- cairo_move_to (cr, 0, 0);
- cairo_rel_line_to (cr, LINE_LENGTH, 0);
- cairo_stroke (cr);
- cairo_move_to (cr, LINE_LENGTH + 2, 0.5);
- cairo_rel_line_to (cr, LINE_LENGTH, 0);
- cairo_stroke (cr);
- cairo_translate (cr, 0, i+3);
- }
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/path-data-ref.png b/test/path-data-ref.png
new file mode 100644
index 000000000..f8bc64758
--- /dev/null
+++ b/test/path-data-ref.png
Binary files differ
diff --git a/test/path-data.c b/test/path-data.c
new file mode 100644
index 000000000..b2d7edbf5
--- /dev/null
+++ b/test/path-data.c
@@ -0,0 +1,184 @@
+/*
+ * 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>
+ */
+
+#include <stdlib.h>
+#include "cairo-test.h"
+
+cairo_test_t test = {
+ "path-data",
+ "Tests calls to path_data functions: cairo_copy_path_data, cairo_copy_path_data_flat, and cairo_append_path_data",
+ 45, 53
+};
+
+static void
+scale_by_two (double *x, double *y)
+{
+ *x = *x * 2.0;
+ *y = *y * 2.0;
+}
+
+typedef void (*munge_func_t) (double *x, double *y);
+
+static void
+munge_and_set_path (cairo_t *cr,
+ cairo_path_t *path,
+ munge_func_t munge)
+{
+ int i;
+ cairo_path_data_t *p;
+ double x1, y1, x2, y2, x3, y3;
+
+ for (i=0; i < path->num_data; i += path->data[i].header.length) {
+ p = &path->data[i];
+ switch (p->header.type) {
+ case CAIRO_PATH_MOVE_TO:
+ x1 = p[1].point.x; y1 = p[1].point.y;
+ (munge) (&x1, &y1);
+ cairo_move_to (cr, x1, y1);
+ break;
+ case CAIRO_PATH_LINE_TO:
+ x1 = p[1].point.x; y1 = p[1].point.y;
+ (munge) (&x1, &y1);
+ cairo_line_to (cr, x1, y1);
+ break;
+ case CAIRO_PATH_CURVE_TO:
+ x1 = p[1].point.x; y1 = p[1].point.y;
+ x2 = p[2].point.x; y2 = p[2].point.y;
+ x3 = p[3].point.x; y3 = p[3].point.y;
+ (munge) (&x1, &y1);
+ (munge) (&x2, &y2);
+ (munge) (&x3, &y3);
+ cairo_curve_to (cr,
+ x1, y1,
+ x2, y2,
+ x3, y3);
+ break;
+ case CAIRO_PATH_CLOSE_PATH:
+ cairo_close_path (cr);
+ break;
+ }
+ }
+}
+
+static void
+make_path (cairo_t *cr)
+{
+ cairo_rectangle (cr, 0, 0, 5, 5);
+ cairo_move_to (cr, 15, 2.5);
+ cairo_arc (cr, 12.5, 2.5, 2.5, 0, 2 * M_PI);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_path_t *path;
+
+ /* copy path, munge, and fill */
+ cairo_translate (cr, 5, 5);
+ make_path (cr);
+ path = cairo_copy_path (cr);
+
+ cairo_new_path (cr);
+ munge_and_set_path (cr, path, scale_by_two);
+ cairo_path_destroy (path);
+ cairo_fill (cr);
+
+ /* copy flattened path, munge, and fill */
+ cairo_translate (cr, 0, 15);
+ make_path (cr);
+ path = cairo_copy_path_flat (cr);
+
+ cairo_new_path (cr);
+ munge_and_set_path (cr, path, scale_by_two);
+ cairo_path_destroy (path);
+ cairo_fill (cr);
+
+ /* append two copies of path, and fill */
+ cairo_translate (cr, 0, 15);
+ cairo_scale (cr, 2.0, 2.0);
+ make_path (cr);
+ path = cairo_copy_path (cr);
+
+ cairo_new_path (cr);
+ cairo_append_path (cr, path);
+ cairo_translate (cr, 2.5, 2.5);
+ cairo_append_path (cr, path);
+
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_fill (cr);
+
+ cairo_path_destroy (path);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ cairo_t *cr;
+ cairo_path_data_t data;
+ cairo_path_t path;
+ cairo_surface_t *surface;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+
+ /* Test a few error cases for cairo_append_path_data */
+ cr = cairo_create (surface);
+ cairo_append_path (cr, NULL);
+ if (cairo_status (cr) != CAIRO_STATUS_NULL_POINTER)
+ return 1;
+ cairo_destroy (cr);
+
+ cr = cairo_create (surface);
+ path.data = NULL;
+ path.num_data = 0;
+ cairo_append_path (cr, &path);
+ if (cairo_status (cr) != CAIRO_STATUS_NULL_POINTER)
+ return 1;
+ cairo_destroy (cr);
+
+ cr = cairo_create (surface);
+ /* Intentionally insert bogus header.length value (otherwise would be 2) */
+ data.header.type = CAIRO_PATH_MOVE_TO;
+ data.header.length = 1;
+ path.data = &data;
+ path.num_data = 1;
+ cairo_append_path (cr, &path);
+ if (cairo_status (cr) != CAIRO_STATUS_INVALID_PATH_DATA)
+ return 1;
+ cairo_destroy (cr);
+
+ /* And test the degnerate case */
+ cr = cairo_create (surface);
+ path.num_data = 0;
+ cairo_append_path (cr, &path);
+ if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
+ return 1;
+ cairo_destroy (cr);
+
+ cairo_surface_destroy (surface);
+
+ return cairo_test (&test, draw);
+}
diff --git a/test/pdf-surface.c b/test/pdf-surface.c
new file mode 100644
index 000000000..863da539b
--- /dev/null
+++ b/test/pdf-surface.c
@@ -0,0 +1,115 @@
+/*
+ * 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>
+ */
+
+#include <stdio.h>
+
+#include <cairo-pdf.h>
+#include "cairo-test.h"
+
+/* Pretty boring test just to make sure things aren't crashing ---
+ * no verification that we're getting good results yet.
+ * But you can manually view the image to make sure it looks happy.
+ */
+
+#define WIDTH_IN_INCHES 3
+#define HEIGHT_IN_INCHES 3
+#define WIDTH_IN_POINTS (WIDTH_IN_INCHES * 72.0)
+#define HEIGHT_IN_POINTS (HEIGHT_IN_INCHES * 72.0)
+
+static void
+draw (cairo_t *cr, double width, double height)
+{
+#define STROKE_WIDTH .04
+
+ double size;
+
+ if (width > height)
+ size = height;
+ else
+ size = width;
+
+ cairo_translate (cr, (width - size) / 2.0, (height - size) / 2.0);
+ cairo_scale (cr, size, size);
+
+ /* Fill face */
+ cairo_arc (cr, 0.5, 0.5, 0.5 - STROKE_WIDTH, 0, 2 * M_PI);
+ cairo_set_source_rgb (cr, 1, 1, 0);
+ cairo_save (cr);
+ {
+ cairo_fill (cr);
+ }
+ cairo_restore (cr);
+
+ cairo_set_source_rgb (cr, 0, 0, 0);
+
+ /* Stroke face */
+ cairo_set_line_width (cr, STROKE_WIDTH / 2.0);
+ cairo_stroke (cr);
+
+ /* Eyes */
+ cairo_set_line_width (cr, STROKE_WIDTH);
+ cairo_arc (cr, 0.3, 0.4, STROKE_WIDTH, 0, 2 * M_PI);
+ cairo_fill (cr);
+ cairo_arc (cr, 0.7, 0.4, STROKE_WIDTH, 0, 2 * M_PI);
+ cairo_fill (cr);
+
+ /* Mouth */
+ cairo_move_to (cr, 0.3, 0.7);
+ cairo_curve_to (cr,
+ 0.4, 0.8,
+ 0.6, 0.8,
+ 0.7, 0.7);
+ cairo_stroke (cr);
+}
+
+int
+main (void)
+{
+ cairo_t *cr;
+ const char *filename = "pdf-surface.pdf";
+ cairo_surface_t *surface;
+
+ printf("\n");
+
+ surface = cairo_pdf_surface_create (filename,
+ WIDTH_IN_POINTS, HEIGHT_IN_POINTS);
+ if (surface == NULL) {
+ fprintf (stderr, "Failed to create pdf surface for file %s\n", filename);
+ return CAIRO_TEST_FAILURE;
+ }
+
+ cr = cairo_create (surface);
+
+ draw (cr, WIDTH_IN_POINTS, HEIGHT_IN_POINTS);
+
+ cairo_show_page (cr);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ printf ("pdf-surface: Please check pdf-surface.pdf to make sure it looks happy.\n");
+
+ return 0;
+}
diff --git a/test/pixman-rotate.c b/test/pixman-rotate.c
index 6a64a9a77..5c6fe4140 100644
--- a/test/pixman-rotate.c
+++ b/test/pixman-rotate.c
@@ -4,10 +4,9 @@
#include <math.h>
#include <cairo.h>
-#include <cairo-png.h>
#include <cairo-pdf.h>
-#include "cairo_test.h"
+#include "cairo-test.h"
#define WIDTH 32
#define HEIGHT WIDTH
@@ -16,43 +15,40 @@
#define IMAGE_HEIGHT IMAGE_WIDTH
cairo_test_t test = {
- "pixman_rotate",
+ "pixman-rotate",
"Exposes pixman off-by-one error when rotating",
IMAGE_WIDTH, IMAGE_HEIGHT
};
/* Draw the word cairo at NUM_TEXT different angles */
-static void
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
- cairo_surface_t *target, *stamp;
+ cairo_surface_t *stamp;
+ cairo_t *cr2;
- target = cairo_current_target_surface (cr);
- cairo_surface_reference (target);
-
- stamp = cairo_surface_create_similar (target, CAIRO_FORMAT_ARGB32,
+ stamp = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_FORMAT_ARGB32,
WIDTH, HEIGHT);
- cairo_set_target_surface (cr, stamp);
- cairo_new_path (cr);
- cairo_rectangle (cr, WIDTH / 4, HEIGHT / 4, WIDTH / 2, HEIGHT / 2);
- cairo_set_rgb_color (cr, 1, 0, 0);
- cairo_set_alpha (cr, 0.8);
- cairo_fill (cr);
-
- cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
- cairo_set_line_width (cr, 2);
- cairo_set_rgb_color (cr, 0, 0, 0);
- cairo_set_alpha (cr, 1);
- cairo_stroke (cr);
-
- cairo_set_target_surface (cr, target);
+ cr2 = cairo_create (stamp);
+ {
+ cairo_new_path (cr2);
+ cairo_rectangle (cr2, WIDTH / 4, HEIGHT / 4, WIDTH / 2, HEIGHT / 2);
+ cairo_set_source_rgba (cr2, 1, 0, 0, 0.8);
+ cairo_fill (cr2);
+
+ cairo_rectangle (cr2, 0, 0, WIDTH, HEIGHT);
+ cairo_set_line_width (cr2, 2);
+ cairo_set_source_rgb (cr2, 0, 0, 0);
+ cairo_stroke (cr2);
+ }
+ cairo_destroy (cr2);
/* Draw a translucent rectangle for reference where the rotated
* image should be. */
cairo_new_path (cr);
cairo_rectangle (cr, WIDTH, HEIGHT, WIDTH, HEIGHT);
- cairo_set_rgb_color (cr, 1, 1, 0);
- cairo_set_alpha (cr, 0.3);
+ cairo_set_source_rgba (cr, 1, 1, 0, 0.3);
cairo_fill (cr);
#if 1 /* Set to 0 to generate reference image */
@@ -62,17 +58,19 @@ draw (cairo_t *cr, int width, int height)
cairo_translate (cr, WIDTH, HEIGHT);
#endif
- cairo_set_alpha (cr, 1);
- cairo_show_surface (cr, stamp, WIDTH + 2, HEIGHT + 2);
+ cairo_set_source_surface (cr, stamp, 0, 0);
+ cairo_paint (cr);
cairo_show_page (cr);
cairo_surface_destroy (stamp);
- cairo_surface_destroy (target);
+
+ return CAIRO_TEST_SUCCESS;
}
int
main (void)
{
- return cairo_test (&test, draw);
+ return cairo_test_expect_failure (&test, draw,
+ "known off-by-one bug when rotating a pixman image");
}
diff --git a/test/pixman_rotate-ref.png b/test/pixman_rotate-ref.png
deleted file mode 100644
index 7e47a4d8f..000000000
--- a/test/pixman_rotate-ref.png
+++ /dev/null
Binary files differ
diff --git a/test/pixman_rotate.c b/test/pixman_rotate.c
deleted file mode 100644
index 6a64a9a77..000000000
--- a/test/pixman_rotate.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include <cairo.h>
-#include <cairo-png.h>
-#include <cairo-pdf.h>
-
-#include "cairo_test.h"
-
-#define WIDTH 32
-#define HEIGHT WIDTH
-
-#define IMAGE_WIDTH (3 * WIDTH)
-#define IMAGE_HEIGHT IMAGE_WIDTH
-
-cairo_test_t test = {
- "pixman_rotate",
- "Exposes pixman off-by-one error when rotating",
- IMAGE_WIDTH, IMAGE_HEIGHT
-};
-
-/* Draw the word cairo at NUM_TEXT different angles */
-static void
-draw (cairo_t *cr, int width, int height)
-{
- cairo_surface_t *target, *stamp;
-
- target = cairo_current_target_surface (cr);
- cairo_surface_reference (target);
-
- stamp = cairo_surface_create_similar (target, CAIRO_FORMAT_ARGB32,
- WIDTH, HEIGHT);
- cairo_set_target_surface (cr, stamp);
- cairo_new_path (cr);
- cairo_rectangle (cr, WIDTH / 4, HEIGHT / 4, WIDTH / 2, HEIGHT / 2);
- cairo_set_rgb_color (cr, 1, 0, 0);
- cairo_set_alpha (cr, 0.8);
- cairo_fill (cr);
-
- cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
- cairo_set_line_width (cr, 2);
- cairo_set_rgb_color (cr, 0, 0, 0);
- cairo_set_alpha (cr, 1);
- cairo_stroke (cr);
-
- cairo_set_target_surface (cr, target);
-
- /* Draw a translucent rectangle for reference where the rotated
- * image should be. */
- cairo_new_path (cr);
- cairo_rectangle (cr, WIDTH, HEIGHT, WIDTH, HEIGHT);
- cairo_set_rgb_color (cr, 1, 1, 0);
- cairo_set_alpha (cr, 0.3);
- cairo_fill (cr);
-
-#if 1 /* Set to 0 to generate reference image */
- cairo_translate (cr, 2 * WIDTH, 2 * HEIGHT);
- cairo_rotate (cr, M_PI);
-#else
- cairo_translate (cr, WIDTH, HEIGHT);
-#endif
-
- cairo_set_alpha (cr, 1);
- cairo_show_surface (cr, stamp, WIDTH + 2, HEIGHT + 2);
-
- cairo_show_page (cr);
-
- cairo_surface_destroy (stamp);
- cairo_surface_destroy (target);
-}
-
-int
-main (void)
-{
- return cairo_test (&test, draw);
-}
diff --git a/test/ps-surface.c b/test/ps-surface.c
new file mode 100644
index 000000000..5d5bf4ee3
--- /dev/null
+++ b/test/ps-surface.c
@@ -0,0 +1,115 @@
+/*
+ * 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>
+ */
+
+#include <stdio.h>
+
+#include <cairo-ps.h>
+#include "cairo-test.h"
+
+/* Pretty boring test just to make sure things aren't crashing ---
+ * no verification that we're getting good results yet.
+ * But you can manually view the image to make sure it looks happy.
+ */
+
+#define WIDTH_IN_INCHES 3
+#define HEIGHT_IN_INCHES 3
+#define WIDTH_IN_POINTS (WIDTH_IN_INCHES * 72.0)
+#define HEIGHT_IN_POINTS (HEIGHT_IN_INCHES * 72.0)
+
+static void
+draw (cairo_t *cr, double width, double height)
+{
+#define STROKE_WIDTH .04
+
+ double size;
+
+ if (width > height)
+ size = height;
+ else
+ size = width;
+
+ cairo_translate (cr, (width - size) / 2.0, (height - size) / 2.0);
+ cairo_scale (cr, size, size);
+
+ /* Fill face */
+ cairo_arc (cr, 0.5, 0.5, 0.5 - STROKE_WIDTH, 0, 2 * M_PI);
+ cairo_set_source_rgb (cr, 1, 1, 0);
+ cairo_save (cr);
+ {
+ cairo_fill (cr);
+ }
+ cairo_restore (cr);
+
+ cairo_set_source_rgb (cr, 0, 0, 0);
+
+ /* Stroke face */
+ cairo_set_line_width (cr, STROKE_WIDTH / 2.0);
+ cairo_stroke (cr);
+
+ /* Eyes */
+ cairo_set_line_width (cr, STROKE_WIDTH);
+ cairo_arc (cr, 0.3, 0.4, STROKE_WIDTH, 0, 2 * M_PI);
+ cairo_fill (cr);
+ cairo_arc (cr, 0.7, 0.4, STROKE_WIDTH, 0, 2 * M_PI);
+ cairo_fill (cr);
+
+ /* Mouth */
+ cairo_move_to (cr, 0.3, 0.7);
+ cairo_curve_to (cr,
+ 0.4, 0.8,
+ 0.6, 0.8,
+ 0.7, 0.7);
+ cairo_stroke (cr);
+}
+
+int
+main (void)
+{
+ cairo_t *cr;
+ const char *filename = "ps-surface.ps";
+ cairo_surface_t *surface;
+
+ printf("\n");
+
+ surface = cairo_ps_surface_create (filename,
+ WIDTH_IN_POINTS, HEIGHT_IN_POINTS);
+ if (surface == NULL) {
+ cairo_test_log ("Failed to create pdf surface for file %s\n", filename);
+ return CAIRO_TEST_FAILURE;
+ }
+
+ cr = cairo_create (surface);
+
+ draw (cr, WIDTH_IN_POINTS, HEIGHT_IN_POINTS);
+
+ cairo_show_page (cr);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ printf ("ps-surface: Please check ps-surface.ps to make sure it looks happy.\n");
+
+ return 0;
+}
diff --git a/test/read-png.c b/test/read-png.c
index e7e2a92ca..96259dfe8 100644
--- a/test/read-png.c
+++ b/test/read-png.c
@@ -25,11 +25,26 @@
* Author: Carl D. Worth <cworth@isi.edu>
*/
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_STDINT_H
+# include <stdint.h>
+#elif HAVE_INTTYPES_H
+# include <inttypes.h>
+#elif HAVE_SYS_INT_TYPES_H
+# include <sys/int_types.h>
+#else
+#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
+#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <png.h>
-#include "read_png.h"
+#include "cairo-test.h"
+#include "read-png.h"
#include "xmalloc.h"
static void
@@ -40,18 +55,18 @@ premultiply_data (png_structp png,
int i;
for (i = 0; i < row_info->rowbytes; i += 4) {
- unsigned char *base = &data[i];
- unsigned char blue = base[0];
- unsigned char green = base[1];
- unsigned char red = base[2];
- unsigned char alpha = base[3];
- unsigned long p;
+ uint8_t *base = &data[i];
+ uint8_t blue = base[0];
+ uint8_t green = base[1];
+ uint8_t red = base[2];
+ uint8_t alpha = base[3];
+ uint32_t p;
red = ((unsigned) red * (unsigned) alpha + 127) / 255;
green = ((unsigned) green * (unsigned) alpha + 127) / 255;
blue = ((unsigned) blue * (unsigned) alpha + 127) / 255;
p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
- memcpy (base, &p, sizeof (unsigned long));
+ memcpy (base, &p, sizeof (uint32_t));
}
}
@@ -76,12 +91,14 @@ read_png_argb32 (const char *filename,
file = fopen (filename, "rb");
if (file == NULL) {
+ cairo_test_log ("Error: File not found: %s\n", filename);
return READ_PNG_FILE_NOT_FOUND;
}
sig_bytes = fread (png_sig, 1, PNG_SIG_SIZE, file);
if (png_check_sig (png_sig, sig_bytes) == 0) {
fclose (file);
+ cairo_test_log ("Error: File is not a PNG image: %s\n", filename);
return READ_PNG_FILE_NOT_PNG;
}
@@ -92,6 +109,7 @@ read_png_argb32 (const char *filename,
NULL);
if (png == NULL) {
fclose (file);
+ cairo_test_log ("Error: Out of memory while reading %s\n", filename);
return READ_PNG_NO_MEMORY;
}
@@ -99,6 +117,7 @@ read_png_argb32 (const char *filename,
if (info == NULL) {
fclose (file);
png_destroy_read_struct (&png, NULL, NULL);
+ cairo_test_log ("Error: Out of memory while reading %s\n", filename);
return READ_PNG_NO_MEMORY;
}
diff --git a/test/read_png.c b/test/read_png.c
deleted file mode 100644
index e7e2a92ca..000000000
--- a/test/read_png.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright © 2003 USC, Information Sciences Institute
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of the
- * University of Southern California not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. The University of Southern
- * California makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Carl D. Worth <cworth@isi.edu>
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <png.h>
-
-#include "read_png.h"
-#include "xmalloc.h"
-
-static void
-premultiply_data (png_structp png,
- png_row_infop row_info,
- png_bytep data)
-{
- int i;
-
- for (i = 0; i < row_info->rowbytes; i += 4) {
- unsigned char *base = &data[i];
- unsigned char blue = base[0];
- unsigned char green = base[1];
- unsigned char red = base[2];
- unsigned char alpha = base[3];
- unsigned long p;
-
- red = ((unsigned) red * (unsigned) alpha + 127) / 255;
- green = ((unsigned) green * (unsigned) alpha + 127) / 255;
- blue = ((unsigned) blue * (unsigned) alpha + 127) / 255;
- p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
- memcpy (base, &p, sizeof (unsigned long));
- }
-}
-
-read_png_status_t
-read_png_argb32 (const char *filename,
- unsigned char **data,
- unsigned int *width,
- unsigned int *height,
- unsigned int *stride)
-{
- int i;
- FILE *file;
- static const int PNG_SIG_SIZE = 8;
- unsigned char png_sig[PNG_SIG_SIZE];
- int sig_bytes;
- png_struct *png;
- png_info *info;
- png_uint_32 png_width, png_height;
- int depth, color_type, interlace;
- unsigned int pixel_size;
- png_byte **row_pointers;
-
- file = fopen (filename, "rb");
- if (file == NULL) {
- return READ_PNG_FILE_NOT_FOUND;
- }
-
- sig_bytes = fread (png_sig, 1, PNG_SIG_SIZE, file);
- if (png_check_sig (png_sig, sig_bytes) == 0) {
- fclose (file);
- return READ_PNG_FILE_NOT_PNG;
- }
-
- /* XXX: Perhaps we'll want some other error handlers? */
- png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
- NULL,
- NULL,
- NULL);
- if (png == NULL) {
- fclose (file);
- return READ_PNG_NO_MEMORY;
- }
-
- info = png_create_info_struct (png);
- if (info == NULL) {
- fclose (file);
- png_destroy_read_struct (&png, NULL, NULL);
- return READ_PNG_NO_MEMORY;
- }
-
- png_init_io (png, file);
- png_set_sig_bytes (png, sig_bytes);
-
- png_read_info (png, info);
-
- png_get_IHDR (png, info,
- &png_width, &png_height, &depth,
- &color_type, &interlace, NULL, NULL);
- *width = png_width;
- *height = png_height;
- *stride = 4 * png_width;
-
-
- /* convert palette/gray image to rgb */
- if (color_type == PNG_COLOR_TYPE_PALETTE)
- png_set_palette_to_rgb (png);
-
- /* expand gray bit depth if needed */
- if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8)
- png_set_gray_1_2_4_to_8 (png);
- /* transform transparency to alpha */
- if (png_get_valid(png, info, PNG_INFO_tRNS))
- png_set_tRNS_to_alpha (png);
-
- if (depth == 16)
- png_set_strip_16 (png);
-
- if (depth < 8)
- png_set_packing (png);
-
- /* convert grayscale to RGB */
- if (color_type == PNG_COLOR_TYPE_GRAY
- || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
- png_set_gray_to_rgb (png);
-
- if (interlace != PNG_INTERLACE_NONE)
- png_set_interlace_handling (png);
-
- png_set_bgr (png);
- png_set_filler (png, 0xff, PNG_FILLER_AFTER);
-
- png_set_read_user_transform_fn (png, premultiply_data);
-
- png_read_update_info (png, info);
-
- pixel_size = 4;
- *data = xmalloc (png_width * png_height * pixel_size);
-
- row_pointers = malloc (png_height * sizeof(char *));
- for (i=0; i < png_height; i++)
- row_pointers[i] = (png_byte *) (*data + i * png_width * pixel_size);
-
- png_read_image (png, row_pointers);
- png_read_end (png, info);
-
- free (row_pointers);
- fclose (file);
-
- png_destroy_read_struct (&png, &info, NULL);
-
- return READ_PNG_SUCCESS;
-}
diff --git a/test/read_png.h b/test/read_png.h
deleted file mode 100644
index 9c9ba433d..000000000
--- a/test/read_png.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright © 2003 USC, Information Sciences Institute
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of the
- * University of Southern California not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. The University of Southern
- * California makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Carl D. Worth <cworth@isi.edu>
- */
-
-#ifndef READ_PNG_H
-#define READ_PNG_H
-
-typedef enum {
- READ_PNG_SUCCESS = 0,
- READ_PNG_FILE_NOT_FOUND,
- READ_PNG_FILE_NOT_PNG,
- READ_PNG_NO_MEMORY
-} read_png_status_t;
-
-read_png_status_t
-read_png_argb32 (const char *filename,
- unsigned char **data,
- unsigned int *width,
- unsigned int *height,
- unsigned int *stride);
-
-#endif
diff --git a/test/rel-path-ref.png b/test/rel-path-ref.png
new file mode 100644
index 000000000..7b7007f31
--- /dev/null
+++ b/test/rel-path-ref.png
Binary files differ
diff --git a/test/rel-path.c b/test/rel-path.c
new file mode 100644
index 000000000..72a7076cf
--- /dev/null
+++ b/test/rel-path.c
@@ -0,0 +1,56 @@
+/*
+ * $Id: rel-path.c,v 1.1 2005-05-02 19:36:20 keithp Exp $
+ *
+ * Copyright © 2005 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "cairo-test.h"
+
+#define SIZE 10
+
+cairo_test_t test = {
+ "rel-path",
+ "Tests calls to various relative path functions",
+ SIZE, SIZE
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_move_to (cr, 0, 0);
+ cairo_rel_move_to (cr, SIZE, SIZE/2);
+ cairo_rel_line_to (cr, -SIZE, SIZE/2);
+ cairo_rel_curve_to (cr,
+ SIZE/2, -SIZE/2,
+ SIZE*2/3, -SIZE/3,
+ SIZE/2, -SIZE);
+
+ cairo_stroke (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/scale-source-surface-paint-ref.png b/test/scale-source-surface-paint-ref.png
new file mode 100644
index 000000000..ec3c059fd
--- /dev/null
+++ b/test/scale-source-surface-paint-ref.png
Binary files differ
diff --git a/test/scale-source-surface-paint.c b/test/scale-source-surface-paint.c
new file mode 100644
index 000000000..7b1cc3824
--- /dev/null
+++ b/test/scale-source-surface-paint.c
@@ -0,0 +1,64 @@
+/*
+ * 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>
+ */
+
+#include "cairo-test.h"
+
+cairo_test_t test = {
+ "scale-source-surface-paint",
+ "Test call sequence: cairo_scale; cairo_set_source_surface; cairo_paint",
+ 12, 12
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *surface;
+ unsigned long data[16] = {
+ 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000,
+ 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000,
+
+ 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff,
+ 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff
+ };
+
+ surface = cairo_image_surface_create_for_data ((unsigned char *) data,
+ CAIRO_FORMAT_ARGB32, 4, 4, 16);
+
+ cairo_scale (cr, 2, 2);
+
+ cairo_set_source_surface (cr, surface, 1 , 1);
+ cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
+ cairo_paint (cr);
+
+ cairo_surface_destroy (surface);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/select-font-no-show-text.c b/test/select-font-no-show-text.c
new file mode 100644
index 000000000..b99dfeaef
--- /dev/null
+++ b/test/select-font-no-show-text.c
@@ -0,0 +1,64 @@
+/*
+ * 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 Worth <cworth@redhat.com>
+ */
+
+/* Bug history
+ *
+ * 2005-04-12 Carl Worth <cworth@cworth.org>
+ *
+ * I noticed that if we call cairo_select_font_face, but then do a
+ * cairo_destroy before ever drawing any text, then we get:
+ *
+ * *** glibc detected *** double free or corruption (fasttop): 0x083274d0 ***
+ * Aborted
+ *
+ * 2005-04-14 Owen Taylor <otaylor@redhat.com>
+ *
+ * Fixed... just a stray free().
+ */
+
+#include <math.h>
+#include "cairo-test.h"
+
+static cairo_test_t test = {
+ "select-font-no-show-text",
+ "Test calling cairo_select_font_face but never drawing text.",
+ 0, 0
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_select_font_face (cr, "Bitstream Vera Sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_BOLD);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/self-copy-ref.png b/test/self-copy-ref.png
new file mode 100644
index 000000000..92a20db64
--- /dev/null
+++ b/test/self-copy-ref.png
Binary files differ
diff --git a/test/self-copy.c b/test/self-copy.c
new file mode 100644
index 000000000..3ad406ecc
--- /dev/null
+++ b/test/self-copy.c
@@ -0,0 +1,90 @@
+/*
+ * 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: Owen Taylor <otaylor@redhat.com>
+ */
+
+#include <math.h>
+#include "cairo-test.h"
+#include <stdio.h>
+
+#define SIZE 40
+
+cairo_test_t test = {
+ "self-copy",
+ "Test copying from a surface to itself with a clip",
+ SIZE, SIZE
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+
+ /* Paint a diagonal division as a test image */
+ cairo_set_source_rgb (cr, 1, 1, 1); /* White */
+ cairo_paint (cr);
+
+ cairo_move_to (cr, SIZE, 0);
+ cairo_line_to (cr, SIZE, SIZE);
+ cairo_line_to (cr, 0, SIZE);
+
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_fill (cr);
+
+ /* Create a pattern with the target surface as the source,
+ * offset by SIZE/2
+ */
+ pattern = cairo_pattern_create_for_surface (cairo_get_target (cr));
+
+ cairo_matrix_init_translate (&matrix, - SIZE / 2, - SIZE / 2);
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+
+ /* Copy two rectangles from the upper-left quarter of the image to
+ * the lower right. It will work if we use cairo_fill(), but the
+ * cairo_clip() cairo_paint() combination fails because the clip
+ * on the surface as a destination affects it as the source as
+ * well.
+ */
+ cairo_rectangle (cr,
+ 2 * SIZE / 4, 2 * SIZE / 4,
+ SIZE / 4, SIZE / 4);
+ cairo_rectangle (cr,
+ 3 * SIZE / 4, 3 * SIZE / 4,
+ SIZE / 4, SIZE / 4);
+ cairo_clip (cr);
+ cairo_paint (cr);
+
+ return CAIRO_TEST_SUCCESS;
+
+}
+
+int
+main (void)
+{
+ return cairo_test_expect_failure (&test, draw,
+ "copying from a surface to itself doesn't handle clipping properly");
+}
diff --git a/test/set-source-ref.png b/test/set-source-ref.png
new file mode 100644
index 000000000..c5d5e9205
--- /dev/null
+++ b/test/set-source-ref.png
Binary files differ
diff --git a/test/set-source.c b/test/set-source.c
new file mode 100644
index 000000000..568935df6
--- /dev/null
+++ b/test/set-source.c
@@ -0,0 +1,87 @@
+/*
+ * 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>
+ */
+
+#include "cairo-test.h"
+
+cairo_test_t test = {
+ "set-source",
+ "Tests calls to various set_source functions",
+ 5, 5
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ int i;
+ /* This color value might need to change in the future when we fix
+ * the rounding in cairo-color.c */
+ unsigned long color = 0x7f19334C;
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+
+ surface = cairo_image_surface_create_for_data ((unsigned char *) &color,
+ CAIRO_FORMAT_ARGB32, 1, 1, 4);
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+
+ /* Several different means of making mostly the same color (though
+ * we can't get anything but alpha==1.0 out of
+ * cairo_set_source_rgb. */
+ for (i=0; i < width; i++) {
+ switch (i) {
+ case 0:
+ cairo_set_source_rgb (cr, .6, .7, .8);
+ break;
+ case 1:
+ cairo_set_source_rgba (cr, .2, .4, .6, 0.5);
+ break;
+ case 2:
+#if WE_HAD_SUPPORT_FOR_PREMULTIPLIED
+ cairo_set_source_rgba_premultiplied (cr, .1, .2, .3, 0.5);
+#else
+ cairo_set_source_rgba (cr, .2, .4, .6, 0.5);
+#endif
+ break;
+ case 3:
+ default:
+ cairo_set_source (cr, pattern);
+ break;
+ }
+
+ cairo_rectangle (cr, i, 0, 1, height);
+ cairo_fill (cr);
+ }
+
+ cairo_pattern_destroy (pattern);
+ cairo_surface_destroy (surface);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/source-clip-ref.png b/test/source-clip-ref.png
new file mode 100644
index 000000000..8df2bff97
--- /dev/null
+++ b/test/source-clip-ref.png
Binary files differ
diff --git a/test/source-clip.c b/test/source-clip.c
new file mode 100644
index 000000000..73be6b432
--- /dev/null
+++ b/test/source-clip.c
@@ -0,0 +1,84 @@
+/*
+ * 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: Owen Taylor <otaylor@redhat.com>
+ */
+
+#include <math.h>
+#include "cairo-test.h"
+#include <stdio.h>
+
+#define SIZE 50
+
+cairo_test_t test = {
+ "source-clip",
+ "Test using a surface with an active clip as a source",
+ SIZE, SIZE
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_pattern_t *pattern;
+ cairo_surface_t *source_surface;
+ cairo_t *cr2;
+
+ source_surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_FORMAT_ARGB32,
+ SIZE, SIZE);
+
+ cr2 = cairo_create (source_surface);
+
+ /* Fill the source surface with solid black */
+ cairo_set_source_rgb (cr2, 0, 0, 0);
+ cairo_paint (cr2);
+
+ /* Now leave a clip in place */
+ cairo_rectangle (cr2,
+ SIZE / 4, SIZE / 4,
+ SIZE / 2, SIZE / 2);
+ cairo_clip (cr2);
+
+ /* Fill the destination surface with solid white */
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+
+ /* Now draw the source surface onto the destination surface */
+ pattern = cairo_pattern_create_for_surface (source_surface);
+ cairo_set_source (cr, pattern);
+ cairo_paint (cr);
+
+ /* As the clip shouldn't matter, the result should be solid black */
+
+ cairo_destroy (cr2);
+ cairo_pattern_destroy (pattern);
+ cairo_surface_destroy (source_surface);
+
+ return CAIRO_TEST_SUCCESS;
+
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/source-surface-scale-paint-ref.png b/test/source-surface-scale-paint-ref.png
new file mode 100644
index 000000000..ec3c059fd
--- /dev/null
+++ b/test/source-surface-scale-paint-ref.png
Binary files differ
diff --git a/test/source-surface-scale-paint.c b/test/source-surface-scale-paint.c
new file mode 100644
index 000000000..9862ba594
--- /dev/null
+++ b/test/source-surface-scale-paint.c
@@ -0,0 +1,64 @@
+/*
+ * 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>
+ */
+
+#include "cairo-test.h"
+
+cairo_test_t test = {
+ "source-surface-scale-paint",
+ "Test call sequence: cairo_set_source_surface; cairo_scale; cairo_paint",
+ 12, 12
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *surface;
+ unsigned long data[16] = {
+ 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000,
+ 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000,
+
+ 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff,
+ 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff
+ };
+
+ surface = cairo_image_surface_create_for_data ((unsigned char *) data,
+ CAIRO_FORMAT_ARGB32, 4, 4, 16);
+
+ cairo_set_source_surface (cr, surface, 2, 2);
+ cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
+ cairo_scale (cr, 2, 2);
+ cairo_paint (cr);
+
+ cairo_surface_destroy (surface);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test_expect_failure (&test, draw,
+ "cairo_set_source needs user space locking semantics");
+}
diff --git a/test/surface-finish-twice.c b/test/surface-finish-twice.c
new file mode 100644
index 000000000..3f24e391c
--- /dev/null
+++ b/test/surface-finish-twice.c
@@ -0,0 +1,74 @@
+/*
+ * 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 Worth <cworth@cworth.org>
+ */
+
+/* Bug history
+ *
+ * 2005-04-10 stevech1097@yahoo.com.au
+ *
+ * Subject: [Bug 2950] New: *** glibc detected *** double free or corruption
+ * URL: https://bugs.freedesktop.org/show_bug.cgi?id=2950
+ *
+ * The following short program gives the error message:
+ *
+ * *** glibc detected *** double free or corruption: 0x082a7268 ***
+ * Aborted
+ *
+ * 2005-04-13 Carl Worth <cworth@cworth.org>
+ *
+ * Looks like surface->finished was never being set. Now fixed.
+ */
+
+#include "cairo-test.h"
+
+cairo_test_t test = {
+ "surface-finish-twice",
+ "Test to exercise a crash when calling cairo_surface_finish twice on the same surface.",
+ 0, 0
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *surface;
+ cairo_status_t status;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ status = cairo_surface_finish (surface);
+ if (status != CAIRO_STATUS_SUCCESS)
+ return CAIRO_TEST_FAILURE;
+
+ status = cairo_surface_finish (surface);
+ if (status != CAIRO_STATUS_SURFACE_FINISHED)
+ return CAIRO_TEST_FAILURE;
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
+
diff --git a/test/surface-pattern-ref.png b/test/surface-pattern-ref.png
new file mode 100644
index 000000000..1a641065b
--- /dev/null
+++ b/test/surface-pattern-ref.png
Binary files differ
diff --git a/test/clip_twice.c b/test/surface-pattern.c
index 00215e62c..4f91d4336 100644
--- a/test/clip_twice.c
+++ b/test/surface-pattern.c
@@ -20,49 +20,51 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * Author: Kristian Høgsberg <krh@redhat.com>
+ * Author: Carl D. Worth <cworth@cworth.org>
*/
-#include "cairo_test.h"
-
-#define WIDTH 64
-#define HEIGHT 64
+#include "cairo-test.h"
cairo_test_t test = {
- "clip_twice",
- "Verifies that the clip mask is updated correctly when it constructed by setting the clip path twice.",
- WIDTH, HEIGHT
+ "surface-pattern",
+ "Tests use of a surface pattern",
+ 36, 36
};
-static void
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
- cairo_set_alpha (cr, 1.0);
- cairo_new_path (cr);
- cairo_arc (cr, WIDTH / 2, HEIGHT / 2, WIDTH / 3, 0, 2 * M_PI);
- cairo_clip (cr);
+ cairo_surface_t *surface;
+ cairo_t *cr2;
+ cairo_pattern_t *pattern;
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ 6, 6);
- cairo_new_path (cr);
- cairo_move_to (cr, 0, 0);
- cairo_line_to (cr, WIDTH / 4, HEIGHT / 2);
- cairo_line_to (cr, 0, HEIGHT);
- cairo_line_to (cr, WIDTH, HEIGHT);
- cairo_line_to (cr, 3 * WIDTH / 4, HEIGHT / 2);
- cairo_line_to (cr, WIDTH, 0);
- cairo_close_path (cr);
- cairo_clip (cr);
+ cr2 = cairo_create (surface);
+ {
+ cairo_rectangle (cr2, 0, 0, 3, 3);
+ cairo_rectangle (cr2, 3, 3, 3, 3);
+ cairo_set_source_rgb (cr2, 1, 1, 0);
+ cairo_fill (cr2);
+
+ cairo_rectangle (cr2, 3, 0, 3, 3);
+ cairo_rectangle (cr2, 0, 3, 3, 3);
+ cairo_set_source_rgb (cr2, 0, 0, 1);
+ cairo_fill (cr2);
+ }
+ cairo_destroy (cr2);
- cairo_set_rgb_color (cr, 0, 0, 0.6);
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+ cairo_set_source (cr, pattern);
- cairo_new_path (cr);
- cairo_move_to (cr, 0, 0);
- cairo_line_to (cr, 0, HEIGHT);
- cairo_line_to (cr, WIDTH / 2, 3 * HEIGHT / 4);
- cairo_line_to (cr, WIDTH, HEIGHT);
- cairo_line_to (cr, WIDTH, 0);
- cairo_line_to (cr, WIDTH / 2, HEIGHT / 4);
- cairo_close_path (cr);
+ cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
+
+ cairo_pattern_destroy (pattern);
+ cairo_surface_destroy (surface);
+
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/testsvg b/test/testsvg
index 520442948..9b18df586 100755
--- a/test/testsvg
+++ b/test/testsvg
@@ -27,11 +27,11 @@ for svg in $@; do
# if xsvg $svg -p $outpng ; then
if svg2png $svg $outpng ; then
if [ -e $refpng ]; then
- if diff $refpng $outpng > /dev/null; then
+ if $IMAGEDIFF $refpng $outpng > $diffpng; then
echo "Rendering of $svg matches." >&2
+ rm -f $diffpng
else
echo "ERROR: Rendering of $svg differs from reference image." >&2
- $IMAGEDIFF $refpng $outpng > $diffpng
echo $refpng $outpng $diffpng >> $IMAGELIST
err=$(($err+1))
fi
diff --git a/test/text-cache-crash.c b/test/text-cache-crash.c
index 6ac3245a6..547e2a34c 100644
--- a/test/text-cache-crash.c
+++ b/test/text-cache-crash.c
@@ -60,26 +60,28 @@
* fixed the orginal test case.
*/
-#include "cairo_test.h"
+#include "cairo-test.h"
cairo_test_t test = {
- "text_cache_crash",
+ "text-cache-crash",
"Test case for bug causing an assertion failure in _cairo_cache_lookup",
0, 0,
};
#include <cairo.h>
-static void
+static cairo_test_status_t
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");
+ cairo_select_font_face (cr, "sans",
+ CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_set_font_size (cr, 40.0);
+
+ cairo_select_font_face (cr, "sans",
+ CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_set_font_size (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. */
@@ -102,9 +104,11 @@ Aborted
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_set_font_size (cr, 500);
cairo_show_text (cr, "hello");
*/
+
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/text-rotate.c b/test/text-rotate.c
index c08c402cf..6301ad9fa 100644
--- a/test/text-rotate.c
+++ b/test/text-rotate.c
@@ -57,7 +57,7 @@
* builtin font to cairo for pixel-perfect tests with text.
*/
-#include "cairo_test.h"
+#include "cairo-test.h"
#define WIDTH 150
#define HEIGHT 150
@@ -65,25 +65,25 @@
#define TEXT_SIZE 12
cairo_test_t test = {
- "text_rotate",
+ "text-rotate",
"Tests show_text under various rotations",
WIDTH, HEIGHT
};
/* Draw the word cairo at NUM_TEXT different angles */
-static void
+static cairo_test_status_t
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_select_font_face (cr, "Bitstream Vera Sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (cr, TEXT_SIZE);
- cairo_set_rgb_color (cr, 0,0,0);
+ cairo_set_source_rgb (cr, 0, 0, 0);
cairo_translate (cr, WIDTH/2.0, HEIGHT/2.0);
@@ -101,17 +101,20 @@ draw (cairo_t *cr, int width, int height)
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_set_source_rgb (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_set_source_rgb (cr, 0, 0, 0);
cairo_show_text (cr, "cairo");
cairo_restore (cr);
}
+
+ return CAIRO_TEST_SUCCESS;
}
int
main (void)
{
- return cairo_test (&test, draw);
+ return cairo_test_expect_failure (&test, draw,
+ "known bugs in positioning rotated glyphs");
}
diff --git a/test/text_cache_crash.c b/test/text_cache_crash.c
deleted file mode 100644
index 6ac3245a6..000000000
--- a/test/text_cache_crash.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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
deleted file mode 100644
index c08c402cf..000000000
--- a/test/text_rotate.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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/transforms-ref.png b/test/transforms-ref.png
new file mode 100644
index 000000000..ee5bc7c7b
--- /dev/null
+++ b/test/transforms-ref.png
Binary files differ
diff --git a/test/transforms.c b/test/transforms.c
new file mode 100644
index 000000000..2c7556a9d
--- /dev/null
+++ b/test/transforms.c
@@ -0,0 +1,111 @@
+/*
+ * 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 Worth <cworth@cworth.org>
+ */
+
+#include "cairo-test.h"
+
+#define WIDTH 45
+#define HEIGHT 30
+
+cairo_test_t test = {
+ "transforms",
+ "Test various transformations.",
+ WIDTH, HEIGHT
+};
+
+static void
+draw_L_shape (cairo_t *cr)
+{
+ cairo_move_to (cr, 0, 0);
+ cairo_rel_line_to (cr, 0, 10);
+ cairo_rel_line_to (cr, 5, 0);
+
+ cairo_save (cr);
+ cairo_identity_matrix (cr);
+ cairo_set_line_width (cr, 2.0);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_translate (cr, 5, 5);
+
+ draw_L_shape (cr);
+
+ cairo_translate (cr, 10, 0);
+
+ cairo_save (cr);
+ {
+ cairo_scale (cr, 2, 2);
+ draw_L_shape (cr);
+ }
+ cairo_restore (cr);
+
+ cairo_translate (cr, 15, 0);
+
+ cairo_save (cr);
+ {
+ cairo_rotate (cr, M_PI / 2.0);
+ draw_L_shape (cr);
+ }
+ cairo_restore (cr);
+
+ cairo_translate (cr, 5, 0);
+
+ cairo_save (cr);
+ {
+ cairo_matrix_t skew_y = {
+ 1, -1,
+ 0, 1,
+ 0, 0
+ };
+ cairo_transform (cr, &skew_y);
+ draw_L_shape (cr);
+ }
+ cairo_restore (cr);
+
+ cairo_translate (cr, 5, 10);
+
+ cairo_save (cr);
+ {
+ cairo_matrix_t skew_x = {
+ 1.0, 0.0,
+ -0.5, 1.0,
+ 0.0, 0.0
+ };
+ cairo_transform (cr, &skew_x);
+ draw_L_shape (cr);
+ }
+ cairo_restore (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/translate-show-surface-ref.png b/test/translate-show-surface-ref.png
new file mode 100644
index 000000000..765adc4a4
--- /dev/null
+++ b/test/translate-show-surface-ref.png
Binary files differ
diff --git a/test/leaky_polygon.c b/test/translate-show-surface.c
index 39daf4ca3..5a566bcb1 100644
--- a/test/leaky_polygon.c
+++ b/test/translate-show-surface.c
@@ -25,54 +25,55 @@
/* Bug history
*
- * 2005-01-07 Carl Worth <cworth@cworth.org>
+ * 2005-04-11 Carl Worth <cworth@cworth.org>
*
- * Bug reported:
+ * It appears that calling cairo_show_surface after cairo_translate
+ * somehow applies the translation twice to the surface being
+ * shown. This is pretty easy to demonstrate by bringing up xsvg on
+ * an SVG file with an <image> and panning around a bit with the
+ * arrow keys.
*
- * 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
+ * This is almost certainly a regression, and I suspect there may be
+ * some interaction with the fix for move-to-show-surface.
*
- * 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.
+ * 2005-04-12 Carl Worth <cworth@cworth.org>
*
+ * I committed a fix for this bug today.
*/
-#include "cairo_test.h"
-
-#define WIDTH 21
-#define HEIGHT 21
+#include "cairo-test.h"
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
+ "translate-show-surface",
+ "Tests calls to cairo_show_surface after cairo_translate",
+ 2, 2
};
-static void
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
- cairo_scale (cr, 1.0/(1<<16), 1.0/(1<<16));
+ cairo_surface_t *surface;
+ unsigned long colors[4] = {
+ 0xffffffff, 0xffff0000,
+ 0xff00ff00, 0xff0000ff
+ };
+ int i;
- cairo_move_to (cr, 131072,39321);
- cairo_line_to (cr, 1103072,1288088);
- cairo_line_to (cr, 1179648,1294990);
- cairo_close_path (cr);
+ for (i=0; i < 4; i++) {
+ surface = cairo_image_surface_create_for_data ((unsigned char *) &colors[i],
+ CAIRO_FORMAT_ARGB32,
+ 1, 1, 4);
+ cairo_save (cr);
+ {
+ cairo_translate (cr, i % 2, i / 2);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+ }
+ cairo_restore (cr);
+ cairo_surface_destroy (surface);
+ }
- cairo_fill (cr);
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/trap-clip-ref.png b/test/trap-clip-ref.png
new file mode 100644
index 000000000..9b5b317aa
--- /dev/null
+++ b/test/trap-clip-ref.png
Binary files differ
diff --git a/test/coverage.c b/test/trap-clip.c
index 00c86a1d5..2ad43ea5f 100644
--- a/test/coverage.c
+++ b/test/trap-clip.c
@@ -24,31 +24,25 @@
*/
#include <math.h>
-#include "cairo_test.h"
+#include "cairo-test.h"
+#include <stdio.h>
#define WIDTH 64
#define HEIGHT 64
#define PAD 10
-/* XXX The test image uses Bitstream Vera Sans as the font - how do we
- * ensure that it's available? Can we ship it with this test? */
-
-const char fontname[] = "Bitstream Vera Sans";
-const int fontsize = 40;
const char png_filename[] = "romedalen.png";
static void
set_solid_pattern (cairo_t *cr, int x, int y)
{
- cairo_set_rgb_color (cr, 0, 0, 0.6);
- cairo_set_alpha (cr, 1.0);
+ cairo_set_source_rgb (cr, 0, 0, 0.6);
}
static void
set_translucent_pattern (cairo_t *cr, int x, int y)
{
- cairo_set_rgb_color (cr, 0, 0, 0.6);
- cairo_set_alpha (cr, 0.5);
+ cairo_set_source_rgba (cr, 0, 0, 0.6, 0.5);
}
static void
@@ -58,10 +52,9 @@ set_gradient_pattern (cairo_t *cr, int x, int y)
pattern =
cairo_pattern_create_linear (x, y, x + WIDTH, y + HEIGHT);
- cairo_pattern_add_color_stop (pattern, 0, 1, 1, 1, 1);
- cairo_pattern_add_color_stop (pattern, 1, 0, 0, 0.4, 1);
- cairo_set_pattern (cr, pattern);
- cairo_set_alpha (cr, 1);
+ cairo_pattern_add_color_stop_rgba (pattern, 0, 1, 1, 1, 1);
+ cairo_pattern_add_color_stop_rgba (pattern, 1, 0, 0, 0.4, 1);
+ cairo_set_source (cr, pattern);
}
static void
@@ -70,25 +63,28 @@ set_image_pattern (cairo_t *cr, int x, int y)
cairo_pattern_t *pattern;
pattern = cairo_test_create_png_pattern (cr, png_filename);
- cairo_set_pattern (cr, pattern);
- cairo_set_alpha (cr, 1);
+ cairo_set_source (cr, pattern);
}
static void
-set_translucent_image_pattern (cairo_t *cr, int x, int y)
+draw_rect (cairo_t *cr, int x, int y)
{
- cairo_pattern_t *pattern;
-
- pattern = cairo_test_create_png_pattern (cr, png_filename);
- cairo_set_pattern (cr, pattern);
- cairo_set_alpha (cr, 0.5);
+ cairo_new_path (cr);
+ cairo_rectangle (cr, x, y, WIDTH, HEIGHT);
+ cairo_fill (cr);
}
static void
-draw_text (cairo_t *cr, int x, int y)
+draw_rects (cairo_t *cr, int x, int y)
{
- cairo_rel_move_to (cr, 0, fontsize);
- cairo_show_text (cr, "Aa");
+ int width = WIDTH / 3;
+ int height = HEIGHT / 2;
+
+ cairo_new_path (cr);
+ cairo_rectangle (cr, x, y, width, height);
+ cairo_rectangle (cr, x + width, y + height, width, height);
+ cairo_rectangle (cr, x + 2 * width, y, width, height);
+ cairo_fill (cr);
}
static void
@@ -105,74 +101,102 @@ draw_polygon (cairo_t *cr, int x, int y)
cairo_fill (cr);
}
+static void
+clip_none (cairo_t *cr, int x, int y)
+{
+}
+
+static void
+clip_rect (cairo_t *cr, int x, int y)
+{
+ cairo_new_path (cr);
+ cairo_rectangle (cr, x + (int)WIDTH / 6, y + (int)HEIGHT / 6,
+ 4 * ((int)WIDTH / 6), 4 * ((int)WIDTH / 6));
+ cairo_clip (cr);
+ cairo_new_path (cr);
+}
+
+static void
+clip_rects (cairo_t *cr, int x, int y)
+{
+ int height = HEIGHT / 3;
+
+ cairo_new_path (cr);
+ cairo_rectangle (cr, x, y, WIDTH, height);
+ cairo_rectangle (cr, x, y + 2 * height, WIDTH, height);
+ cairo_clip (cr);
+ cairo_new_path (cr);
+}
+
+static void
+clip_circle (cairo_t *cr, int x, int y)
+{
+ cairo_new_path (cr);
+ cairo_arc (cr, x + WIDTH / 2, y + HEIGHT / 2,
+ WIDTH / 3, 0, 2 * M_PI);
+ cairo_clip (cr);
+ cairo_new_path (cr);
+}
+
static void (*pattern_funcs[])(cairo_t *cr, int x, int y) = {
set_solid_pattern,
set_translucent_pattern,
set_gradient_pattern,
set_image_pattern,
- set_translucent_image_pattern
};
static void (*draw_funcs[])(cairo_t *cr, int x, int y) = {
- draw_text,
+ draw_rect,
+ draw_rects,
draw_polygon,
};
+static void (*clip_funcs[])(cairo_t *cr, int x, int y) = {
+ clip_none,
+ clip_rect,
+ clip_rects,
+ clip_circle,
+};
+
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
#define IMAGE_WIDTH (ARRAY_SIZE (pattern_funcs) * (WIDTH + PAD) + PAD)
-#define IMAGE_HEIGHT (ARRAY_SIZE (draw_funcs) * (HEIGHT + PAD) * 2 + PAD)
+#define IMAGE_HEIGHT (ARRAY_SIZE (draw_funcs) * ARRAY_SIZE (clip_funcs) * (HEIGHT + PAD) + PAD)
static cairo_test_t test = {
- "coverage",
- "Various coverage test of cairo",
+ "trap-clip",
+ "Trapezoid clipping",
IMAGE_WIDTH, IMAGE_HEIGHT
};
-
-static void
+static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
- /* TODO: pattern fill, gradient fill, clipping, gradient clipping,
- path+solid alpha mask clipping */
-
- int i, j, x, y;
-
- cairo_select_font (cr, fontname,
- CAIRO_FONT_SLANT_NORMAL,
- CAIRO_FONT_WEIGHT_BOLD);
- cairo_scale_font (cr, fontsize);
-
- for (j = 0; j < ARRAY_SIZE (draw_funcs); j++) {
- for (i = 0; i < ARRAY_SIZE (pattern_funcs); i++) {
- x = i * (WIDTH + PAD) + PAD;
- y = j * (HEIGHT + PAD) + PAD;
- cairo_move_to (cr, x, y);
- pattern_funcs[i] (cr, x, y);
- draw_funcs[j] (cr, x, y);
- }
- }
-
- for (j = 0; j < ARRAY_SIZE (draw_funcs); j++) {
- for (i = 0; i < ARRAY_SIZE (pattern_funcs); i++) {
- x = i * (WIDTH + PAD) + PAD;
- y = (ARRAY_SIZE (draw_funcs) + j) * (HEIGHT + PAD) + PAD;
-
- cairo_save (cr);
+ int i, j, k, x, y;
- cairo_set_alpha (cr, 1.0);
- cairo_new_path (cr);
- cairo_arc (cr, x + WIDTH / 2, y + HEIGHT / 2,
- WIDTH / 3, 0, 2 * M_PI);
- cairo_clip (cr);
+ for (k = 0; k < ARRAY_SIZE (clip_funcs); k++) {
+ for (j = 0; j < ARRAY_SIZE (draw_funcs); j++) {
+ for (i = 0; i < ARRAY_SIZE (pattern_funcs); i++) {
+ x = i * (WIDTH + PAD) + PAD;
+ y = (ARRAY_SIZE (draw_funcs) * k + j) * (HEIGHT + PAD) + PAD;
- cairo_move_to (cr, x, y);
- pattern_funcs[i] (cr, x, y);
- draw_funcs[j] (cr, x, y);
+ cairo_save (cr);
- cairo_restore (cr);
+ cairo_move_to (cr, x, y);
+ clip_funcs[k] (cr, x, y);
+ pattern_funcs[i] (cr, x, y);
+ draw_funcs[j] (cr, x, y);
+ if (cairo_status (cr))
+ cairo_test_log ("%d %d HERE!\n", i, j);
+ cairo_restore (cr);
+ }
}
}
+
+ if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
+ cairo_test_log ("%d %d .HERE!\n", i, j);
+
+ return CAIRO_TEST_SUCCESS;
}
int
diff --git a/test/user-data.c b/test/user-data.c
new file mode 100644
index 000000000..d17b933bb
--- /dev/null
+++ b/test/user-data.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: Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include <cairo.h>
+#include <assert.h>
+#include <stdlib.h>
+
+static void
+destroy_data1 (void *p)
+{
+ *(int *) p = 1;
+}
+
+static void
+destroy_data2 (void *p)
+{
+ *(int *) p = 2;
+}
+
+int
+main (void)
+{
+ cairo_surface_t *surface;
+ static const cairo_user_data_key_t key1, key2;
+ int data1, data2;
+
+ data1 = 0;
+ data2 = 0;
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ assert (cairo_surface_set_user_data (surface, &key1, &data1, destroy_data1)
+ == CAIRO_STATUS_SUCCESS);
+ assert (cairo_surface_set_user_data (surface, &key2, &data2, destroy_data2)
+ == CAIRO_STATUS_SUCCESS);
+ assert (cairo_surface_get_user_data (surface, &key1) == &data1);
+ assert (cairo_surface_set_user_data (surface, &key1, NULL, NULL)
+ == CAIRO_STATUS_SUCCESS);
+ assert (cairo_surface_get_user_data (surface, &key1) == NULL);
+ assert (data1 == 1);
+ assert (data2 == 0);
+
+ assert (cairo_surface_set_user_data (surface, &key2, NULL, NULL)
+ == CAIRO_STATUS_SUCCESS);
+ assert (data2 == 2);
+
+ data1 = 0;
+ assert (cairo_surface_set_user_data (surface, &key1, &data1, NULL)
+ == CAIRO_STATUS_SUCCESS);
+ assert (cairo_surface_set_user_data (surface, &key1, NULL, NULL)
+ == CAIRO_STATUS_SUCCESS);
+ assert (data1 == 0);
+ assert (cairo_surface_get_user_data (surface, &key1) == NULL);
+
+ assert (cairo_surface_set_user_data (surface, &key1, &data1, destroy_data1)
+ == CAIRO_STATUS_SUCCESS);
+ cairo_surface_destroy (surface);
+ assert (data1 == 1);
+ assert (data2 == 2);
+
+ return 0;
+}
diff --git a/test/write-png.c b/test/write-png.c
index 0ff5bcd3a..f5a274738 100644
--- a/test/write-png.c
+++ b/test/write-png.c
@@ -29,7 +29,7 @@
#include <stdlib.h>
#include <png.h>
-#include "write_png.h"
+#include "write-png.h"
static void
unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
@@ -55,7 +55,7 @@ unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
}
void
-write_png_argb32 (char *buffer, FILE *file,
+write_png_argb32 (unsigned char *buffer, FILE *file,
int width, int height, int stride)
{
int i;
diff --git a/test/write-png.h b/test/write-png.h
index fe0e92b20..8074666a3 100644
--- a/test/write-png.h
+++ b/test/write-png.h
@@ -29,7 +29,7 @@
#define WRITE_PNG_H
void
-write_png_argb32 (char *buffer, FILE * file,
+write_png_argb32 (unsigned char *buffer, FILE * file,
int width, int height, int stride);
#endif
diff --git a/test/write_png.c b/test/write_png.c
deleted file mode 100644
index 0ff5bcd3a..000000000
--- a/test/write_png.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright © 2003 USC, Information Sciences Institute
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of the
- * University of Southern California not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. The University of Southern
- * California makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Carl D. Worth <cworth@cworth.org>
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <png.h>
-
-#include "write_png.h"
-
-static void
-unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
-{
- int i;
-
- for (i = 0; i < row_info->rowbytes; i += 4) {
- unsigned char *b = &data[i];
- unsigned int pixel;
- unsigned char alpha;
-
- memcpy (&pixel, b, sizeof (unsigned int));
- alpha = (pixel & 0xff000000) >> 24;
- if (alpha == 0) {
- b[0] = b[1] = b[2] = b[3] = 0;
- } else {
- b[0] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
- b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
- b[2] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
- b[3] = alpha;
- }
- }
-}
-
-void
-write_png_argb32 (char *buffer, FILE *file,
- int width, int height, int stride)
-{
- int i;
- png_struct *png;
- png_info *info;
- png_byte **rows;
- png_color_16 white;
-
- rows = malloc (height * sizeof(png_byte*));
-
- for (i = 0; i < height; i++) {
- rows[i] = buffer + i * stride;
- }
-
- png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- info = png_create_info_struct (png);
-
- png_init_io (png, file);
- png_set_IHDR (png, info,
- width, height, 8,
- PNG_COLOR_TYPE_RGB_ALPHA,
- PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT);
-
- white.red = 0xff;
- white.blue = 0xff;
- white.green = 0xff;
- png_set_bKGD (png, info, &white);
-
- png_set_write_user_transform_fn (png, unpremultiply_data);
- png_set_bgr (png);
-
- png_write_info (png, info);
- png_write_image (png, rows);
- png_write_end (png, info);
-
- png_destroy_write_struct (&png, &info);
-
- free (rows);
-}
diff --git a/test/write_png.h b/test/write_png.h
deleted file mode 100644
index fe0e92b20..000000000
--- a/test/write_png.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright © 2003 USC, Information Sciences Institute
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of the
- * University of Southern California not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. The University of Southern
- * California makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
- * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Carl D. Worth <cworth@isi.edu>
- */
-
-#ifndef WRITE_PNG_H
-#define WRITE_PNG_H
-
-void
-write_png_argb32 (char *buffer, FILE * file,
- int width, int height, int stride);
-
-#endif
diff --git a/test/xlib-surface.c b/test/xlib-surface.c
new file mode 100644
index 000000000..d8c241c8e
--- /dev/null
+++ b/test/xlib-surface.c
@@ -0,0 +1,269 @@
+/*
+ * 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>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cairo.h"
+#include "cairo-xlib.h"
+#include "cairo-xlib-xrender.h"
+#include "cairo-test.h"
+#include "cairo-xlib-test.h"
+
+#include "buffer-diff.h"
+
+#define SIZE 100
+#define OFFSCREEN_OFFSET 50
+
+cairo_bool_t result = 0;
+FILE *log_file = NULL;
+
+static void
+draw_pattern (cairo_surface_t *surface)
+{
+ cairo_t *cr = cairo_create (surface);
+ int i;
+
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+ cairo_paint (cr);
+
+ cairo_set_source_rgba (cr, 0, 0.0, 0.0, 0.50); /* half-alpha-black */
+
+ for (i = 1; i <= 3; i++) {
+ int inset = SIZE / 8 * i;
+
+ cairo_rectangle (cr,
+ inset, inset,
+ SIZE - 2 * inset, SIZE - 2 * inset);
+ cairo_fill (cr);
+ }
+
+ cairo_destroy (cr);
+}
+
+static void
+erase_pattern (cairo_surface_t *surface)
+{
+ cairo_t *cr = cairo_create (surface);
+
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+}
+
+static cairo_bool_t
+do_test (Display *dpy,
+ unsigned char *reference_data,
+ unsigned char *test_data,
+ unsigned char *diff_data,
+ cairo_bool_t use_render,
+ cairo_bool_t use_pixmap,
+ cairo_bool_t set_size,
+ cairo_bool_t offscreen)
+{
+ cairo_surface_t *surface;
+ cairo_surface_t *test_surface;
+ cairo_t *test_cr;
+ cairo_bool_t result;
+ Drawable drawable;
+ int screen = DefaultScreen (dpy);
+
+ if (use_pixmap && offscreen)
+ return 1;
+
+ if (use_pixmap) {
+ drawable = XCreatePixmap (dpy, DefaultRootWindow (dpy),
+ SIZE, SIZE, DefaultDepth (dpy, screen));
+ } else {
+ XSetWindowAttributes xwa;
+ int x, y;
+
+ xwa.override_redirect = True;
+
+ if (offscreen) {
+ x = - OFFSCREEN_OFFSET;
+ y = - OFFSCREEN_OFFSET;
+ } else {
+ x = 0;
+ y = 0;
+ }
+
+ drawable = XCreateWindow (dpy, DefaultRootWindow (dpy),
+ x, y, SIZE, SIZE, 0,
+ DefaultDepth (dpy, screen), InputOutput,
+ DefaultVisual (dpy, screen),
+ CWOverrideRedirect, &xwa);
+ XMapWindow (dpy, drawable);
+ }
+
+ surface = cairo_xlib_surface_create (dpy,
+ drawable,
+ DefaultVisual (dpy, screen),
+ SIZE, SIZE);
+
+ if (set_size)
+ cairo_xlib_surface_set_size (surface, SIZE, SIZE);
+
+ draw_pattern (surface);
+
+ test_surface = cairo_image_surface_create_for_data (test_data,
+ CAIRO_FORMAT_RGB24,
+ SIZE, SIZE,
+ SIZE * 4);
+
+ test_cr = cairo_create (test_surface);
+ cairo_set_source_surface (test_cr, surface, 0, 0);
+ cairo_paint (test_cr);
+
+ cairo_destroy (test_cr);
+ cairo_surface_destroy (test_surface);
+
+ /* We erase the surface to black in case we get the same
+ * memory back again for the pixmap case.
+ */
+ erase_pattern (surface);
+ cairo_surface_destroy (surface);
+
+ if (use_pixmap)
+ XFreePixmap (dpy, drawable);
+ else
+ XDestroyWindow (dpy, drawable);
+
+ if (offscreen) {
+ size_t offset = 4 * (SIZE * OFFSCREEN_OFFSET + OFFSCREEN_OFFSET);
+
+ result = !buffer_diff (reference_data + offset,
+ test_data + offset,
+ diff_data + offset,
+ SIZE - OFFSCREEN_OFFSET,
+ SIZE - OFFSCREEN_OFFSET,
+ 4 * SIZE);
+ } else {
+ result = !buffer_diff (reference_data,
+ test_data,
+ diff_data,
+ SIZE,
+ SIZE,
+ 4 * SIZE);
+ }
+
+ fprintf (log_file, "xlib-surface: %s, %s, %s%s: %s\n",
+ use_render ? " render" : "no-render",
+ set_size ? " size" : "no-size",
+ use_pixmap ? "pixmap" : "window",
+ use_pixmap ?
+ " " :
+ (offscreen ? ", offscreen" : ", onscreen"),
+ result ? "PASS" : "FAIL");
+
+ return result;
+}
+
+static cairo_bool_t
+check_visual (Display *dpy)
+{
+ Visual *visual = DefaultVisual (dpy, DefaultScreen (dpy));
+
+ if ((visual->red_mask == 0xff0000 &&
+ visual->green_mask == 0x00ff00 &&
+ visual->blue_mask == 0x0000ff) ||
+ (visual->red_mask == 0x0000ff &&
+ visual->green_mask == 0x00ff00 &&
+ visual->blue_mask == 0xff0000))
+ return 1;
+ else
+ return 0;
+}
+
+int
+main (void)
+{
+ Display *dpy;
+ unsigned char *reference_data;
+ unsigned char *test_data;
+ unsigned char *diff_data;
+ cairo_surface_t *reference_surface;
+ cairo_bool_t use_pixmap;
+ cairo_bool_t set_size;
+ cairo_bool_t offscreen;
+ result = 0;
+
+ printf("\n");
+ log_file = fopen ("xlib-surface.log", "w");
+ if (log_file == NULL) {
+ fprintf (stderr, "Error opening log file: %s\n", "xlib-surface.log");
+ log_file = stderr;
+ }
+
+ dpy = XOpenDisplay (NULL);
+ if (!dpy) {
+ fprintf (log_file, "xlib-surface: Cannot open display, skipping\n");
+ return 0;
+ }
+
+ if (!check_visual (dpy)) {
+ fprintf (log_file, "xlib-surface: default visual is not RGB24 or BGR24, skipping\n");
+ return 0;
+ }
+
+ reference_data = malloc (SIZE * SIZE * 4);
+ test_data = malloc (SIZE * SIZE * 4);
+ diff_data = malloc (SIZE * SIZE * 4);
+
+ reference_surface = cairo_image_surface_create_for_data (reference_data,
+ CAIRO_FORMAT_RGB24,
+ SIZE, SIZE,
+ SIZE * 4);
+
+ draw_pattern (reference_surface);
+ cairo_surface_destroy (reference_surface);
+
+ for (set_size = 0; set_size <= 1; set_size++)
+ for (use_pixmap = 0; use_pixmap <= 1; use_pixmap++)
+ for (offscreen = 0; offscreen <= 1; offscreen++)
+ if (!do_test (dpy,
+ reference_data, test_data, diff_data,
+ 1, use_pixmap, set_size, offscreen))
+ result = 1;
+
+ cairo_test_xlib_disable_render ();
+
+ for (set_size = 0; set_size <= 1; set_size++)
+ for (use_pixmap = 0; use_pixmap <= 1; use_pixmap++)
+ for (offscreen = 0; offscreen <= 1; offscreen++)
+ if (!do_test (dpy,
+ reference_data, test_data, diff_data,
+ 0, use_pixmap, set_size, offscreen))
+ result = 1;
+
+ free (reference_data);
+ free (test_data);
+ free (diff_data);
+
+ XCloseDisplay (dpy);
+
+ return result;
+}
diff --git a/test/xmalloc.c b/test/xmalloc.c
index 04ed38afa..f5721c5de 100644
--- a/test/xmalloc.c
+++ b/test/xmalloc.c
@@ -26,6 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include "cairo-test.h"
#include "xmalloc.h"
void *
@@ -35,7 +36,7 @@ xmalloc (size_t size)
buf = malloc (size);
if (!buf) {
- fprintf (stderr, "Error: Out of memory. Exiting.\n");
+ cairo_test_log ("Error: Out of memory. Exiting.\n");
exit (1);
}
@@ -49,7 +50,7 @@ xcalloc (size_t nmemb, size_t size)
buf = calloc (nmemb, size);
if (!buf) {
- fprintf (stderr, "Error: Out of memory. Exiting\n");
+ cairo_test_log ("Error: Out of memory. Exiting\n");
exit (1);
}
diff --git a/test/xmalloc.h b/test/xmalloc.h
index a4ba24b67..bc1ab69eb 100644
--- a/test/xmalloc.h
+++ b/test/xmalloc.h
@@ -26,6 +26,8 @@
#ifndef _XMALLOC_H_
#define _XMALLOC_H_
+#include <stdlib.h>
+
void *
xmalloc (size_t size);
diff --git a/util/cairo-api-update b/util/cairo-api-update
index d2dfc0fa0..e16df43fd 100755
--- a/util/cairo-api-update
+++ b/util/cairo-api-update
@@ -14,22 +14,54 @@ cairo_api_update() {
backup=$file.bak
cp $file $backup
- sed -e '
- s/cairo_get_operator/cairo_current_operator/g
- s/cairo_get_rgb_color/cairo_current_rgb_color/g
- s/cairo_get_alpha/cairo_current_alpha/g
- s/cairo_get_tolerance/cairo_current_tolerance/g
- s/cairo_get_current_point/cairo_current_point/g
- s/cairo_get_fill_rule/cairo_current_fill_rule/g
- s/cairo_get_line_width/cairo_current_line_width/g
- s/cairo_get_line_cap/cairo_current_line_cap/g
- s/cairo_get_line_join/cairo_current_line_join/g
- s/cairo_get_miter_limit/cairo_current_miter_limit/g
- s/cairo_get_matrix/cairo_current_matrix/g
- s/cairo_get_target_surface/cairo_current_target_surface/g
- s/cairo_get_status_string/cairo_status_string/g
+ sed -e '/\(DEPRECATED\|REPLACED\)_BY/! {
+ s/cairo_current_font_extents/cairo_font_extents/g
+ s/cairo_get_font_extents/cairo_font_extents/g
+ s/cairo_current_operator/cairo_get_operator/g
+ s/cairo_current_tolerance/cairo_get_tolerance/g
+ s/cairo_current_point/cairo_get_current_point/g
+ s/cairo_current_fill_rule/cairo_get_fill_rule/g
+ s/cairo_current_line_width/cairo_get_line_width/g
+ s/cairo_current_line_cap/cairo_get_line_cap/g
+ s/cairo_current_line_join/cairo_get_line_join/g
+ s/cairo_current_miter_limit/cairo_get_miter_limit/g
+ s/cairo_current_matrix/cairo_get_matrix/g
+ s/cairo_current_pattern/cairo_get_source/g
+ s/cairo_current_target_surface/cairo_get_target/g
s/cairo_get_status/cairo_status/g
+ s/cairo_get_status_string/cairo_status_string/g
+ s/cairo_concat_matrix/cairo_transform/g
+ s/cairo_scale_font/cairo_set_font_size/g
+ s/cairo_select_font\([^_]\)/cairo_select_font_face\1/g
+ s/cairo_transform_font/cairo_set_font_matrix/g
+ s/cairo_transform_point/cairo_user_to_device/g
+ s/cairo_transform_distance/cairo_user_to_device_distance/g
+ s/cairo_inverse_transform_point/cairo_device_to_user/g
+ s/cairo_inverse_transform_distance/cairo_device_to_user_distance/g
+ s/cairo_init_clip/cairo_reset_clip/g
+ s/cairo_surface_create_for_image/cairo_image_surface_create_for_data/g
+ s/cairo_default_matrix/cairo_identity_matrix/g
+ s/cairo_matrix_set_affine/cairo_matrix_init/g
+ s/cairo_matrix_set_identity/cairo_matrix_init_identity/g
+ s/\([^_]\)cairo_pattern_add_color_stop\([^_]\)/\1cairo_pattern_add_color_stop_rgba\2/g
+ s/cairo_set_rgb_color/cairo_set_source_rgb/g
+ s/cairo_set_pattern/cairo_set_source/g
+ s/CAIRO_OPERATOR_SRC/CAIRO_OPERATOR_SOURCE/g
+ s/CAIRO_OPERATOR_DST/CAIRO_OPERATOR_DEST/g
+ s/CAIRO_OPERATOR_OVER_REVERSE/CAIRO_OPERATOR_DEST_OVER/g
+ s/CAIRO_OPERATOR_IN_REVERSE/CAIRO_OPERATOR_DEST_IN/g
+ s/CAIRO_OPERATOR_OUT_REVERSE/CAIRO_OPERATOR_DEST_OUT/g
+ s/CAIRO_OPERATOR_ATOP_REVERSE/CAIRO_OPERATOR_DEST_ATOP/g
+ }
' $backup > $file
+
+ grep -n 'cairo_create[ ]*([ ]*)' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*/\1 cairo_create must now accept a target surface/'
+ grep -n 'cairo_set_target_image' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*/\1 cairo_set_target_image should be reworked to use cairo_image_surface_create_for_data, likely before cairo_create/'
+ grep -n 'cairo_set_target_surface' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*/\1 cairo_set_target_surface for temporarily changing the target should now be rworked to create a temporary context with cairo_create/'
+ grep -n 'cairo_set_target_png' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*/\1 cairo_set_target_png should be reworked to use cairo_image_surface_create followed by cairo_surface_write_to_png/'
+ grep -n 'cairo_set_target_drawable' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*/\1 cairo_set_target_drawable should be reworked to use cairo_xlib_surface_create, likely before cairo_create/'
+ grep -n 'cairo_set_target_[^dis][^n]' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*cairo_set_target_\([a-z]*\).*/\1 cairo_set_target_\2 should be reworked to use cairo_\2_surface_create, likely before cairo_create/'
+ grep -n 'cairo_set_alpha' $file /dev/null | sed 's/\(.*:[0-9]\+:\).*/\1 cairo_set_alpha should be replaced by turning a nearby cairo_set_source_rgb into cairo_set_source_rgba or turning a nearby cairo_paint into cairo_paint_with_alpha/'
}
while [ $# -gt 0 ]; do