diff options
author | Carl Worth <cworth@cworth.org> | 2006-02-13 16:47:01 -0800 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2006-02-13 16:47:01 -0800 |
commit | 6c38e238e5daab5df4c11027d28e48e62bbd4bc8 (patch) | |
tree | 150fc4b07ca1b92e8439bb722fde8bf63db7d009 | |
parent | 0b5ac24b1522b3287903c04fb894bfae4fc67403 (diff) | |
parent | 980eff38e494223de00e7ded706f6beaca27fce1 (diff) |
Remove pixman from SNAPSHOT_0_4_0SNAPSHOT_0_4_0
256 files changed, 21968 insertions, 13085 deletions
@@ -1,6 +1,7 @@ +Shawn T. Amundson <amundson@gtk.org> Build fix Olivier Andrieu <oliv__a@users.sourceforge.net> PNG backend Peter Dennis Bartok <peter@novonyx.com> Bug fix for clipping -Dave Beckett <dave.beckett@bristol.ac.uk> Track rename of libpixman, build fixes +Dave Beckett <dajobe@debian.org> Build fixes, Debian packaging Andrew Chant <andrew.chant@utoronto.ca> Adding const where needed John Ellson <ellson@research.att.com> First font/glyph extents functions Richard Henderson <rth@twiddle.net> "slim" macros for better shared libraries @@ -10,11 +11,13 @@ Thomas Hunger <info@teh-web.de> Initial version of cairo_in_stroke/fill Kristian Høgsberg <krh@redhat.com> PDF backend Alexander Larsson <alexl@redhat.com> Profiling and performance fixes. Jordi Mas <jordi@ximian.com> Bug fix for cairo_show_text -Keith Packard <keithp@keithp.com> Original concept, polygon tessellation, dashing +Keith Packard <keithp@keithp.com> Original concept, polygon tessellation, dashing, font metrics rewrite Christof Petig <christof@petig-baender.de> Build fixes related to freetype -David Reveman <davidr@freedesktop.org> New pattern API, OpenGL backend +David Reveman <davidr@novell.com> New pattern API, glitz backend +Calum Robinson <calumr@mac.com> Quartz backend Jamey Sharp <jamey@minilop.net> Surface/font backend virtualization, XCB backend Bill Spitzak <spitzak@d2.com> Build fix to find Xrender.h without xrender.pc +Owen Taylor <otaylor@redhat.com> Font support rewrite Sasha Vasko <sasha@aftercode.net> Build fix to compile without xlib backend Vladimir Vukicevic <vladimir@pobox.com> Bug fix for clipping Carl Worth <cworth@isi.edu> Original library, support for paths, images @@ -1,3 +1,19 @@ +cairo_show_surface fails when given a non-default CTM, see the +show_surface.cairo snippet in: + + From: Per Bjornsson <perbj@stanford.edu> + To: Cairo mailing list <cairo@cairographics.org> + Date: Wed, 09 Feb 2005 20:05:35 -0800 + Message-Id: <1108008335.5349.46.camel@localhost.localdomain> + Subject: [cairo] How is cairo_show_surface supposed to work? + +-- + +cairo_image_surface_create should return a blank image +(eg. transparent black) instead of an image with random data in it. + +-- + cairo_surface_create_for_image is claiming ownership of the user's data. -- @@ -1,3 +1,972 @@ +2005-03-08 Carl Worth <cworth@cworth.org> + + * gtk-doc.make (dist-check-gtkdoc): Commit workaround to prevent + make distcheck from making bogus complaints that gtk-doc is not + enabled. + + * test/cairo_test.c (cairo_test_create_png_pattern): Look for png + images in ${srcdir}/filename as well, so that make distcheck can + still find them. + + * test/Makefile.am (EXTRA_DIST): Add romedalen.png to EXTRA_DIST + so the tests can pass from the tar file. + + * doc/public/cairo-sections.txt: Fix typo: cairo-win3 -> + cairo-win32. + + * doc/public/cairo-docs.xml: Add cairo-win32.xml to the list, so + it gets generated as well. + + * NEWS (http): Add pointer to new win32 documentation. + + * configure.in: Increment CAIRO_VERSION to 0.4.0 + + * NEWS: Added notes for snapshot 0.4.0 + +2005-03-08 Carl Worth <cworth@cworth.org> + + * test/cairo_test.c (xunlink): Shared function for checking unlink + errrors. + (cairo_test): Move all error messages to test-specific log files + for quieter test output. + + * test/Makefile.am (XFAIL_TESTS): Make pixman_rotate an expected + failure. + + * configure.in: Require libpixman >= 0.1.4. + +2005-03-08 Kristian Høgsberg <krh@redhat.com> + + * src/cairo_pdf_surface.c (_cairo_pdf_surface_composite): Return + CAIRO_STATUS_SUCCESS even if we don't implement masks yet, so we + don't set cr->status to CAIRO_INT_STATUS_UNSUPPORTED. + +2005-03-07 Carl Worth <cworth@cworth.org> + + * src/cairo_traps.c: Disable the "new" intersection code so that + the incorrect fill problems (test/fill_rule) go away. + + * configure.in: Make configure fail if no font backend is + available. Point the user at freetype and fontconfig. + +2005-03-06 Owen Taylor <otaylor@redhat.com> + + * src/cairo_pattern.c (_cairo_image_data_set_linear): Comment + and clean up the gradient computation. + (_cairo_linear_pattern_classify): Determine if a linear + gradient is horizontal or vertical. + (_cairo_pattern_acquire_surface_for_gradient): Optimize + horizontal/vertical gradients with a repeating surface. + + * test/linear_gradient.c: Test case for linear gradients + at angles and with a rotated pattern matrix. + +2005-03-06 David Reveman <davidr@novell.com> + + * src/cairo_glitz_surface.c (_cairo_glitz_pattern_acquire_surface): + Do not allow acceleration of gradients when color stops have different + alpha. Add note about the current state of glitz's gradient + acceleration. CAIRO_FILTER_GOOD and CAIRO_FILTER_BEST is ok. + (_cairo_glitz_surface_composite_trapezoids): Use unsigned short for + alpha. + +2005-03-04 Owen Taylor <otaylor@redhat.com> + + * src/cairo_win32_font.c src/cairo_win32_surface.c: Update + for recent backend interface changes. + + * configure.in: Reenable win32 backend by default. + +2005-03-04 Carl Worth <cworth@cworth.org> + + * src/cairo_glitz_surface.c + (_cairo_glitz_pattern_acquire_surface): Fix accidental reversal of + condition in previous patch. + +2005-03-04 Owen Taylor <otaylor@redhat.com> + + * src/cairoint.h src/cairo_pattern.c src/cairo_glitz_surface.c: + Add _cairo_pattern_is_opaque, use it rather than + pattern->alpha == 1.0. + +2005-03-04 David Reveman <davidr@novell.com> + + * configure.in: Enable xcb backend. + + * src/cairo_xcb_surface.c: Update xcb backend. + + * configure.in: Fixed variable assignments. + + * src/cairo_glitz_surface.c: Add overall alpha acceleration + to a few cases not covered by _cairo_pattern_acquire_surfaces but + possible to accelerate by glitz. + + * src/cairo_pattern.c: + (_cairo_pattern_acquire_surfaces): Add overall alpha acceleration + using mask surface. + + * src/cairoint.h: + Add convenience function _cairo_pattern_acquire_surfaces. + + * src/cairo_xlib_surface.c: + * src/cairo_surface.c: + * src/cairo_ps_surface.c: + * src/cairo_png_surface.c: + * src/cairo_pdf_surface.c: + * src/cairo_pattern.c: + * src/cairo_image_surface.c: + * src/cairo_gstate.c: + * src/cairo_glitz_surface.c: + * src/cairo_ft_font.c (_cairo_ft_font_show_glyphs): Mask to composite + operation is now passed as a pattern. + + * src/cairoint.h: + * src/cairo_xlib_surface.c: + (_cairo_xlib_surface_set_matrix): Setting identity transform should + always be successful. + + * src/cairo_surface.c: + * src/cairo_ps_surface.c: + * src/cairo_png_surface.c: + * src/cairo_pdf_surface.c: + * src/cairo_image_surface.c: + * src/cairo_glitz_surface.c: Removed surface backend functions + set_matrix, set_filter, set_repeat. + + * configure.in: Enabled glitz backend. + + * src/cairo_glitz_surface.c: Major update to glitz backend. The output + quality should now be just as good as the image and xlib backends. + + * configure.in: Disabled win32 and quartz backends as they are now + temporarily out of sync. + + * src/cairoint.h: Replaced old cairo_pattern_t struct with new + cairo_surface_t like structure of cairo_pattern_t. + Added new function prototypes for acquiring a source surface from + a pattern. + + * src/cairo_xlib_surface.c: + (_cairo_xlib_surface_composite): Removed fast path that used XCopyArea. + + * src/cairo_ps_surface.c: + * src/cairo_pdf_surface.c: + * src/cairo_image_surface.c: + * src/cairo_gstate.c: Switched to cairo_surface_t like structure + of cairo_pattern_t and new interface for acquiring a source + surface from a pattern. + + * src/cairo_pattern.c: New implementations of many functions. This was + necessary because of switch to cairo_surface_t like structure of + cairo_pattern_t. Includes new interface for acquiring a source + surface for a pattern. Things that didn't belong in cairoint.h have + been moved here. + + * src/cairo_gstate.c (_cairo_gstate_show_surface): Inherit surface + attributes while surface attribute functions still exist. + +2005-03-01 Carl Worth <cworth@cworth.org> + + * TODO: Note that cairo_output_stream_t patch has been reviewed. + +2005-03-01 Carl Worth <cworth@cworth.org> + + * src/cairo_gstate.c (_cairo_gstate_show_surface): Fix + uninitialized value for status, (reported by Manish Singh). + +2005-02-27 Kristian Høgsberg <krh@redhat.com> + + * src/cairo_gstate.c (_cairo_rectangle_intersect): Fix this + function again. Problem with signed/unsigned types reported by + Jeff Muizelaar <jrmuizel@nit.ca>. + +2005-02-27 Kristian Høgsberg <krh@redhat.com> + + * src/cairo.h (cairo_fill_rule_t): Remove newline in comment which + was confusing gtk-doc. + + * src/cairo_image_surface.c (cairo_image_surface_create_for_data) + (cairo_image_surface_create): Document these functions. + +2005-02-25 Carl Worth <cworth@cworth.org> + + * TODO: Note that "user data" and "setters and getters" patches + have been reviewed. Remove a few more TODO notes: + cleanup cairo_snippets: DONE + cairo_surface_finish: Now in API Shakeup + snapping code: Decided against this + +2005-02-25 Carl Worth <cworth@cworth.org> + + From David Reveman: + + * src/cairo_matrix.c (_cairo_matrix_is_integer_translation): + Rewrite to use cairo_bool_t for legibility. + +2005-02-25 Carl Worth <cworth@cworth.org> + + From David Reveman: + + * src/cairo_gstate.c (_cairo_gstate_show_surface): Simplify code + to eliminate a goto. + +2005-02-25 Carl Worth <cworth@cworth.org> + + From David Reveman: + + * src/cairo_gstate.c (_cairo_gstate_pattern_init_copy): + (_cairo_gstate_clip_and_composite_trapezoids) + (_cairo_gstate_clip_and_composite_trapezoids) + (_cairo_gstate_show_surface, _cairo_gstate_show_glyphs) + (_cairo_gstate_show_glyphs): Clean up the mess that was + the misnamed _cairo_gstate_create_pattern. + +2005-02-25 Carl Worth <cworth@cworth.org> + + * src/cairo_pattern.c (_cairo_pattern_shader_init): Don't put an + off-by-one n_stops into cairo_shader_op_t. + (_cairo_shader_op_find_color_stops): Put search for two color + stops containing a given offset into its own function. Handle the + case of before first and after last stop by returning the nearest + stop twice. + (_cairo_pattern_calc_color_at_pixel): Handle case of no color + stops by returning a transparent pixel. + +2005-02-24 Owen Taylor <otaylor@redhat.com> + + * src/cairo_win32_surface.c: Remove a left-over debug printf. + +2005-02-24 Carl Worth <cworth@cworth.org> + + * src/cairo_pattern.c (cairo_pattern_add_color_stop): Fix memory + leak when realloc fails due to out-of-memory. + +2005-02-24 Owen Taylor <otaylor@redhat.com> + + * src/cairo_win32_surface.[ch]: Instead of counting + on ordering deletion to work (apparently it didn't on + older Windows), save the initial bitmap created + with the DC and reselect that into the DC. (Based + on a patch by Hans Breuer) + +2005-02-24 Carl Worth <cworth@cworth.org> + + * test/.cvsignore: Add pixman_rotate to ignore list. + +2005-02-24 Carl Worth <cworth@cworth.org> + + Fixes from David Reveman with minor cleanups by Carl Worth: + + * src/cairo_gstate.c (_cairo_gstate_create): Handle new failure + possibility of _cairo_gstate_init. + (_cairo_gstate_init): Handle possible failure of + _cairo_pattern_create_solid. + (_cairo_gstate_set_pattern): Reference new pattern before + destroying existing pattern to handle the case where they are the + same. + (_cairo_gstate_set_rgb_color): Handle possible failure of + _cairo_pattern_create_solid. + +2005-02-24 Carl Worth <cworth@cworth.org> + + * src/cairo.h: Fix typo (pointed out by Kristian Høgsberg). + +2005-02-24 Owen Taylor <otaylor@redhat.com> + + * src/cairo_win32_surface.c (_cairo_win32_surface_destroy): + When we created a DC/bitmap pair, delete the DC before + the Bitmap so that the Bitmap will be released from the + DC and can be destroyed. (Reported by Hans Breuer) + + * configure.in cairo.pc.in: Only require fontconfig + if building FreeType font backend. + + * configure.in: Fix output when reporting Win32 font backend. + +2005-02-24 Carl Worth c<worth@cworth.org> + + * TODO: Remove many TODO items that have now been absorbed by the + API shakeup. Remove comparison with PostScript as there's nothing + interesting there left unimplemented, (and cairo is already + establishing its own conventions in naming and behavior that + deviate from PostScript). + + * src/cairoint.h: Fix typo (pointed out by Mike Emmel) + +2005-02-23 Carl Worth <cworth@cworth.org> + + * TODO: Add entries from API Shakeup. + +2005-02-22 Carl Worth <cworth@cworth.org> + + * README: + * src/cairo-features.h.in: + * src/cairo-glitz.h: + * src/cairo-pdf.h: + * src/cairo-png.h: + * src/cairo-ps.h: + * src/cairo-quartz.h: + * src/cairo-xcb.h: + * src/cairo-xlib.h: + * src/cairo.c: + * src/cairo.h: + * src/cairo_color.c: + * src/cairo_fixed.c: + * src/cairo_font.c: + * src/cairo_gstate.c: + * src/cairo_hull.c: + * src/cairo_image_surface.c: + * src/cairo_matrix.c: + * src/cairo_path.c: + * src/cairo_path_bounds.c: + * src/cairo_path_fill.c: + * src/cairo_path_stroke.c: + * src/cairo_pen.c: + * src/cairo_png_surface.c: + * src/cairo_polygon.c: + * src/cairo_ps_surface.c: + * src/cairo_slope.c: + * src/cairo_spline.c: + * src/cairo_surface.c: + * src/cairo_traps.c: + * src/cairo_xcb_surface.c: + * src/cairo_xlib_surface.c: + * src/cairoint.h: Switch from broken cworth@isi.edu address to + canonical cworth@cworth.org address. + +2005-02-22 Carl Worth <cworth@cworth.org> + + * test/write_png.c: + * src/cairo-atsui.h: + * src/cairo_atsui_font.c: Convert to utf-8 encoding. + +2005-02-22 Carl Worth <cworth@cworth.org> + + * configure.in: Temporarily disable XCB backend by default. + +2005-02-21 Carl Worth <cworth@cworth.org> + + * src/cairo_pattern.c (cairo_pattern_reference): + * src/cairo.h: Revert accidental commit. + +2005-02-21 Carl Worth <cworth@cworth.org> + + * src/cairo_surface.c (_fallback_composite_trapezoids): Fix y + offset to use dst_y instead of dst_x, (caught by David Reveman). + +2005-02-20 Owen Taylor <otaylor@redhat.com> + + * src/cairo-win32.h: Fix line endings (reported by + Hans Breuer) + +2005-02-16 Kristian Høgsberg <krh@redhat.com> + + Patches from Mike Owens <etc@filespanker.com>: + + * src/cairo_png_surface.c (_cairo_png_surface_copy_page): Free + rows if we fail early in this function. + + * src/cairo_path.c (_cairo_path_init_copy): Clean up path if we + run out of memory. + +2005-02-13 Kristian Høgsberg <krh@redhat.com> + + * src/cairo_pdf_surface.c + (_cairo_pdf_surface_create_for_document): Initialize array element + size correctly. + +2005-02-10 Kristian Høgsberg <krh@redhat.com> + + Patches from Owen Taylor: + + * src/cairo_pdf_surface.c + (_cairo_pdf_surface_show_glyphs): Emit text as octal escapes, + to avoid problems with \, \r, ), etc. + (_cairo_pdf_document_write_fonts): Change /Flags to be 4 (symbolic), + not 32 (non-symbolic), otherwise acroread gets confuse. + (cairo_pdf_ft_font_write_cmap_table): Use a 1,0 cmap subtable, + not a 0,0, to conform to the PDF spec. + +2005-02-13 Carl Worth <cworth@cworth.org> + + * autogen.sh (LC_NUMERIC): Use LC_NUMERIC=C so that decimal + separator works in version checks. + +2005-02-12 Owen Taylor <otaylor@redhat.com> + + * src/cairo_gstate.c (_cairo_gstate_clip_and_composite_trapezoids): Fix + x2/x1 typo. + +2005-02-12 Carl Worth <cworth@cworth.org> + + * src/cairo.c (cairo_text_extents): Return all-zero extents if + string is NULL. + +2005-02-12 Kristian Høgsberg <krh@redhat.com> + + * src/cairo_gstate.c + (_cairo_gstate_clip_and_composite_trapezoids): Make clipping fast + path fast. When we have a clipping region set, intersect it + against the drawing extents to determine the bounding box for the + visible drawing. + +2005-02-10 Carl Worth <cworth@cworth.org> + + * BUGS: Add bug for cairo_show_surface under non-default CTM. + +2005-02-07 Kristian Høgsberg <krh@redhat.com> + + * test/pixman_rotate.c, test/pixman_rotate-ref.png: New test case + which exposes off-by-one rotation error in pixman. + +2005-02-06 Owen Taylor <otaylor@redhat.com> + + * src/cairo_gstate.c src/cairo.c: Allow cairo_set_font (cr, NULL) + to unset the current font and return the cairo_t to the the + "use the font from cairo_select_font() state". + +2005-02-06 Owen Taylor <otaylor@redhat.com> + + * src/cairo_win32_font.c (_cairo_win32_font_text_to_glyphs): + Return the right status. (Reported by Hans Breuer.) + +2005-02-06 Owen Taylor <otaylor@redhat.com> + + * src/cairo_win32_font.c (_cairo_win32_font_text_to_glyphs): Free + glyph_indices, not glyphs. (Reported by Hans Breuer.) + +2005-02-05 Carl Worth <cworth@cworth.org> + + * configure.in: Add message stating why glitz backend is disabled. + +2005-02-05 Owen Taylor <otaylor@redhat.com> + + * src/cairo_ft_font.c (_cairo_ft_font_text_to_glyphs): + Don't free *glyphs when succeeding! (Reported by Øyvind Kolås) + + * configure.in: Temporarily disable glitz by default. + +2005-02-04 Carl Worth <cworth@cworth.org> + + * src/Makefile.am: Generate an error during make install if old + cairo headers are found in includedir, (rather than + includedir/cairo where the new ones are going). + +2005-02-03 Owen Taylor <otaylor@redhat.com> + + * src/cairo_ft_font.c (_cairo_ft_font_text_to_glyphs, + _cairo_ft_font_create_glyph): Fix missing cairo_ft_font_unlock_face(). + + * src/cairo_cache.c (_cairo_cache_random_entry): Fix problem + when no entry could be found. + +2005-02-03 Owen Taylor <otaylor@redhat.com> + + * src/cairo_font.c src/cairo.h doc/public/cairo-sections.txt: + Add cairo_font_extents(). + + * src/cairo_win32_font.c src/cairo-win32.h doc/public/cairo-sections.txt: + Rename cairo_font_create_for_logfont() into + cairo_font_create_for_logfontw() to make clear what it takes. + Don't add cairo_font_create_for_logfonta() for now. + +2005-02-02 Owen Taylor <otaylor@redhat.com> + + * src/cairo_win32_font.c doc/public/cairo-sections.txt + doc/public/Makefile.am: Add windows functions to the docs. + +2005-02-02 Owen Taylor <otaylor@redhat.com> + + * src/cairo_win32_font.c (cairo_win32_font_select_font, + cairo_win32_release_font, cairo_win32_font_get_scale_factor): + Add some functions to select the font into a device context + with the intention to enable callers to use, e.g, Uniscribe. + + * src/cairo_win32_font.c: Use 'hdc' not 'dc' for param/variable + name. + +2005-02-02 Owen Taylor <otaylor@redhat.com> + + * src/cairo_win32_font.c (cairo_win32_font_select_font, + cairo_win32_release_font, cairo_win32_font_get_scale_factor): + Add some functions to select the font into a device context + with the intention to enable callers to use, e.g, Uniscribe. + + * src/cairo_win32_font.c: Use 'hdc' not 'dc' for param/variable + name. + + * src/cairo_win32_font.c (_cairo_win32_font_show_glyphs): Return + immediately if height or width is 0. + +2005-02-02 Owen Taylor <otaylor@redhat.com> + + * src/cairo_win32_font.c: Mostly-functioning Win32 font backend; + no glyph paths yet. + + * configure.in: Turn on building of the Win32 font backend. + + * src/cairo-win32-private.h src/Makefile.am: Private header for + the Win32 backend. + + * src/cairo-win32-private.h src/cairo_win32_surface.c: + Internally export _cairo_win32_print_gdi_error() for use + in the font code. + + * src/cairo-win32-private.h src/cairo_win32_surface.c: + Add _cairo_win32_surface_create_dib to create a DIB surface. + + src/cairo-win32-private.h src/cairo_win32_surface.c: + Add _cairo_surface_is_win32() + + * configure.in: Check for vasnprintf. + + * test/cairo_test.c (xasprintf): Add a simple fixed-buffer size + snprintf fallback in the absence of vasnprintf. + +2005-02-01 Kristian Høgsberg <krh@redhat.com> + + * src/cairo_pdf_surface.c (_cairo_pdf_surface_composite): Pretend + we support compositing of solid color or gradient patterns to + prevent image fallback. + (emit_pattern): New function, code factored out from + _cairo_pdf_surface_composite_trapezoids. + (_cairo_pdf_surface_show_glyphs): Use emit_pattern here so we get + pattern support for text. + + * src/cairo_ft_font.c (_cairo_ft_font_get_unscaled_font): Fix typo. + +2005-02-01 Owen Taylor <otaylor@redhat.com> + + * src/cairo_unicode.c src/cairoint.h src/Makefile.am: Add + _cairo_utf8_to_utf16(), _cairo_utf8_to_ucs4() based on code from GLib. + + * src/cairo.[ch]: Add CAIRO_STATUS_INVALID_STRING + + * src/cairo_ft_font.c: Use _cairo_utf8_to_ucs4(). + + * src/cairo.h: Add cairo_bool_t + + * src/cairoint.h: Add TRUE/FALSE definitions. + + * src/cairo.[ch] src/cairoint.h src/cairo_gstate.c: switch + cairo_in_stroke/cairo_in_fill and all the functions used to + implement them over to cairo_bool_t. + +2005-01-31 Owen Taylor <otaylor@redhat.com> + + * configure.in src/cairo-features.h.in: Add a check for the + Windows platform and --enable-win32. Also add some (currently + always off) stubs for native Win32 fonts. + + * configure.in: Make building the PDF backend conditional + on having FreeType. + + * src/Makefile.am src/cairo_win32_surface.c src/cairo_win32_font.c + src/cairo-win32.h: Add a Win32 backend using GDI and software + fallbacks Font code is not yet there yet, but it works with the + fontconfig backend. + + * src/cairo_gdip_font.cpp src/cairo_gdip_surface.cpp: Remove + remnants of a GDI+ based backend. + + * src/cairoint.h: Prefer platform-specific font backends + to the fontconfig backend. + +2005-01-31 Owen Taylor <otaylor@redhat.com> + + * src/cairoint.h src/cairo_image_surface.c + src/cairo_pdf_surface.c src/cairo_png_surface.c + src/cairo_surface.c src/cairo_xlib_surface.c: Replace + the get_image()/set_image() backend operations with + a more specific {acquire,release}_{source,dest}_image() + and clone_similar(). + + * src/cairoint.h src/cairo_pattern.c: Replace + _cairo_pattern_get_surface() with a + _cairo_pattern_begin_draw()/_cairo_pattern_end_draw() pair. + + * src/cairo_image_surface.c: Save the format for which + an image is created so we can access it later. (Needed + for the _cairo_xlib_surface_clone_similar()) + + * src/cairoint.h src/cairo_image_surface.c: + Add _cairo_surface_is_image(). + + * src/cairoint.h: Add CAIRO_OK(status) to check + for CAIRO_STATUS_SUCCESS. + + * src/cairo_xlib_surface.c: In the absence of of + RENDER, make cairo_xlib_surface_create_similar() + return an image surface. + + * src/cairo_xlib_surface.c: Don't try to use RENDER + to composite glyphs in the absence of the RENDER + extension. + +2005-01-30 Owen Taylor <otaylor@redhat.com> + + * src/cairo_ps_surface.c (_cairo_ps_surface_copy_page): Update + composite-over-white code to use a pattern, not a surface. + (to match _cairo_surface_composite API change.) + +2005-01-30 Owen Taylor <otaylor@redhat.com> + + Fixes from David Reveman: + + * src/cairo_pattern.c (_cairo_pattern_save/restore_surface): Don't + save to surface part of the union when the pattern isn't a surface + pattern. + (_cairo_pattern_get_surface): Create the new surface at the width + and height of the source. + + * src/Makefile.am (libcairo_ft_sources): Add cairo-ft-private.h + +2005-01-28 Kristian Høgsberg <krh@redhat.com> + + * src/cairo_png_surface.c (_cairo_png_surface_composite): Update + prototype to eliminate warning. + + * src/cairo_pattern.c (_cairo_pattern_init_copy): Remember to + reference surfaces when copying patterns. + + * src/cairo_gstate.c: (_cairo_rectangle_intersect), + (_cairo_gstate_clip_and_composite_trapezoids), + (_cairo_gstate_clip), (_cairo_gstate_show_glyphs): Don't call + _gstate_create_pattern for internally created patterns. + (_cairo_gstate_show_surface): Don't change the surface matrix + here, it's done later when we set it up as a pattern. + + * test/Makefile.am: Correct clip_twice-ref.png filename. + + * src/cairoint.h (MIN, MAX): Add these. + + * src/cairo_gstate.c (_cairo_rectangle_intersect): Fix broken + intersection code. + +2005-01-27 Kristian Høgsberg <krh@redhat.com> + + * src/cairo_pattern.c (_cairo_pattern_get_surface): Make sure we + always return a surface similar to dst in the gradient case. + + * src/cairo_pattern.c (_cairo_pattern_get_surface): Fold + _cairo_pattern_get_image into _cairo_pattern_get_surface and make + sure we always return a surface of the same type as dest. + + * src/cairo_glitz_surface.c (_cairo_glitz_composite), + (_cairo_glitz_surface_composite_trapezoids): Use + _cairo_pattern_get_surface instead of _cairo_pattern_get_image. + + * src/cairo_xlib_surface.c (_cairo_xlib_surface_show_glyphs), + (_cairo_xlib_surface_composite) + (_cairo_xlib_surface_composite_trapezoids): Remove use of + _cairo_xlib_surface_clone_similar since _cairo_pattern_get_surface + always gives us an xlib surface for the pattern. Clean up error + handling code in _cairo_xlib_surface_show_glyphs. + + * src/cairo_image_surface.c (_cairo_image_surface_composite): + (_cairo_image_surface_composite_trapezoids): Add missing + cairo_surface_destroy and tidy up offset calculations as suggested + by Owen. + + * src/cairoint.h (cairo_clip_rect_t): + * src/cairo_gstate.c (_cairo_gstate_clip_and_composite_trapezoids) + (_cairo_gstate_clip, _cairo_gstate_show_glyphs): Simplify code for + computing the extents of clipping area, by introducing a couple of + cairo_rectangle_t functions. + +2005-01-27 Owen Taylor <otaylor@redhat.com> + + * src/cairo.[ch] src/cairo_font.c src/cairo_ft_font.c + src/cairo_ps_surface.c src/cairo_xlib_surface.c: Move + docs from docs/reference, with a fair bit of addition + and rewriting. + + * doc/reference/: Remove old-format docs. + + * configure.in: Add a AC_PREREQ(2.54) (Jason Dorje Short) + +2005-01-27 Kristian Høgsberg <krh@redhat.com> + + * test/coverage-ref.png: + * test/clip_twice-ref.png: + Update these two once again, this time generated using + libpixman-0.1.3 without leaky circles. + +2005-01-27 Owen Taylor <otaylor@redhat.com> + + * configure.in Makefile.am docs/Makefile.am docs/public/*: + Add framework for doing docs via gtk-doc. + + * src/cairo.[ch] src/cairo-matrix.c: Add some inline docs + for arcs and matrices. + + * gtk-doc.m4 acinclude.m4: Check in files from gtk-doc + to make the dependency on gtk-doc optional. + + * autogen.sh (LANG): Add --enable-gtk-doc to the default + args. + +2005-01-27 Kristian Høgsberg <krh@redhat.com> + + * test/write_png.c (unpremultiply_data): + * test/read_png.c (premultiply_data): + Fix missing rounding in these two functions. + + * test/coverage-ref.png: + * test/clip_twice-ref.png: + Update these to versions with properly rounded alpha values. + + * test/Makefile.am: Move clip_twice out of XFAIL now that rounding + works. + + * test/.cvsignore: Add new test cases. + +2005-01-27 Kristian Høgsberg <krh@redhat.com> + + The overall idea of this rewrite is that we want to pass the + source pattern all the way down into the backends. The motivation + for this is that not all backends want a surface for the source + operand, and by passing the pattern down, backends can choose to + convert it to a surface if they need that. + + The patch removes the create_surface function pointer from the + surface vtable and moves much of that code into a couple of helper + functions. The composite, compsite_trapezoids, and show_glyphs + backend functions are updated to take a cairo_pattern_t instead of + a surface as the source. + + * src/cairo_font.c: (_cairo_font_show_glyphs): + * src/cairo_gstate.c: (_cairo_gstate_create_pattern), + (_cairo_gstate_clip_and_composite_trapezoids), + (_cairo_gstate_clip), (_cairo_gstate_show_surface), + (_cairo_gstate_show_glyphs): + Change these functions to not create a surface for the pattern and + just pass the pattern down to the backend functions. + + * src/cairo_gstate.c: (translate_traps): + New function to translate a set of trapezoids. + + * src/cairo_pattern.c: + (_cairo_pattern_init), + (_cairo_pattern_init_copy), + (_cairo_pattern_prepare_surface), + (_cairo_pattern_restore_surface): + Break out the code to adjust and restore surface transformation + and repeat settings into _cairo_pattern_prepare_surface and + _cairo_pattern_restore_surface. + + * src/cairo_pattern.c: (_cairo_pattern_fini), + (_cairo_pattern_init_for_surface), + (cairo_pattern_create_for_surface): + Split cairo_pattern_create_for_surface into an init function and a + create function. + + * src/cairo_pattern.c: (_cairo_pattern_get_image), + (_cairo_pattern_get_surface): + Utility functions to create a surface from a pattern. + + * src/cairo_ft_font.c: + * src/cairo_image_surface.c: + * src/cairo_pdf_surface.c: + * src/cairo_png_surface.c: + * src/cairo_ps_surface.c: + * src/cairo_xlib_surface.c: + * src/cairo_glitz_surface.c: + Update these backends to work with the new pattern API. Glitz + work by David Reveman. + + * src/cairo_surface.c: (_cairo_surface_composite), + (_cairo_surface_composite_trapezoids), + (_cairo_surface_set_clip_region): + Update these to pass through the new set of args. + + * test/coverage-ref.png: + Update this reference image as we now render it correctly. + +2005-01-26 Kristian Høgsberg <krh@redhat.com> + + * test/clip_twice.c, test/clip_twice-ref.png: New test case to + verify that the clip surface is correctly updated when extending + an existing clip path. + + * test/coverage.c (draw): Set alpha to 1 before setting clip mask. + + * test/coverage-ref.png: Added the right reference PNG. Running + test against stock 0.3.0 gives the expected results. + + * test/Makefile.am, test/coverage.c, test/coverage-ref.png: New + test case, covering various combinations of pattern types, drawing + operations and clipping. Currently fails, for some combinations, + coverage-ref.png is just a placeholder. + + * test/romedalen.png: Added this PNG from cairo-snippets to use + for pattern fills. + + * test/cairo_test.c, test/cairo_test.h: expose PNG loading to test + cases. + +2005-01-26 Alexander Larsson <alexl@redhat.com> + + * src/cairo_ft_font.c: (_ft_unscaled_font_set_scale): + Fix access to uninitialized data + + * src/cairo_xlib_surface.c: + key must be first element in cache entry + +2005-01-25 David Reveman <davidr@novell.com> + + * AUTHORS: Update mail address. + + * src/cairo_glitz_surface.c: Update mail address. + + * configure.in: Require version 0.4.0 of glitz. + + * src/cairo_glitz_surface.c: Track changes to glitz. + + * src/cairo_xcb_surface.c: Add missing include directive so xcb + backend compile again. + +2005-01-25 Carl Worth <cworth@cworth.org> + + * test/imagediff.c + * test/testsvg: Add new testsvg script and accompanying imagediff + program, (for interim SVG-based test suites while we wait for the + standard cairo test suite to mature). + + * test/buffer_diff.c: + * test/cairo_test.c: Split buffer_diff out into its own file for + the purpose of imagediff. + + * src/cairo_ft_font.c (_cairo_ft_font_show_glyphs): Fixed rounding + of glyph positioning. + +2005-01-25 Owen Taylor <otaylor@redhat.com> + + * src/cairo_pdf_surface.c (_cairo_pdf_document_get_font): Chec + pdf_font for NULL, not font. + +2005-01-25 Alexander Larsson <alexl@redhat.com> + + * src/Makefile.am: + Fix typo that made cairo-ft.h not get installed + +2005-01-24 Carl Worth <cworth@cworth.org> + + * AUTHORS: Add Shawn T. Amundson, Calum Robinson, and Owen Taylor. + + * src/Makefile.am: Conditionally install header files only for + backends that are compiled. Thanks to Shawn T. Amundson + <amundson@gtk.org>. + + * src/cairoint.h: + * src/cairo_color.c (_cairo_color_get_rgb): Qualify color argument + as const. Closes bug #2336. + +2005-01-23 Dave Beckett <Dave.Beckett@bristol.ac.uk> + + * src/cairo_ft_font.c (_get_load_flags): Protect switch on + hintstyle with #ifdef FC_HINT_STYLE. + +2005-01-23 Carl Worth <cworth@cworth.org> + + * RELEASING: Add instructions for handling the new "-head" suffix + of CAIRO_VERSION at release-time. + + * configure.in: Append "-head" to CAIRO_VERSION to indicate state + between snapshots. + + * src/cairo_gstate.c: Add missing prototype for _cairo_gstate_ensure_font. + (_cairo_gstate_current_font): Add missing declaration so things + compile again. + +2005-01-21 Owen Taylor <otaylor@redhat.com> + + * Call _cairo_gstate_ensure_font(). Don't reference + the returned font. + +2005-01-21 Owen Taylor <otaylor@redhat.com> + + * src/cairo_ft_font.c (_get_load_flags): Make dependence + on FC_HINT_STYLE conditional. (reported by Abraham Egnor) + + * src/cairo_ft_font.c: Use FT_LOAD_MONOCHROME if + FT_LOAD_TARGET_MONO isn't defined for compatibility + with older FreeType. + +2005-01-16 Owen Taylor <otaylor@redhat.com> + + Change cairo_font_t to refer to a font scaled to a particular + output device resolution. + + * src/cairoint.h src/cairo_font.c src/cairo_ft_font.c + src/cairo_xlib_surface.c src/cairo_pdf_surface.c src/cairo_gstate.c + src/cairo.c: Switch many internal methods from handling + cairo_unscaled_font_t and cairo_font_scale_t pairs to handling + cairo_font_t. + + * src/cairo-ft-private.h src/cairo_ft_fontc: Add some internal + interfaces for use by the FreeType backend. + + * src/cairo_gstate.c: Clear the gstate's current font when + the transform or target surface changes. + + * src/cairo.h src/cairo_ft_font.c: Rename cairo_ft_font_pattern + to cairo_ft_font_get_pattern(). + + * src/cairo.h src/cairo_ft_font.c: Make cairo_ft_font_create() + and cairo_ft_font_create_for_ft_face() take a font scale; + make the latter take load_flags for FT_Load_Glyph() as well. + Change cairo_ft_font_face() to Xft-style cairo_ft_font_lock_face, + cairo_ft_font_unlock_face. + + * src/cairo_font.c: Remove the name/slant/weight=>unscaled font + cache, it didn't work with the new cairo_font_t setup. If it turns + out to be needed, it can be added back in some other form. + + * src/cairoint.h src/cairo_font.c: Add a 'flags' field + to cairo_glyph_cache_key_t, we use it for load flags with + freetype backend. + + * src/cairo_ft_font.c: Switch the caching to be from + resolved fontconfig pattern => file; keep only a fixed number + of FT_Face objects open at once, similar to FreeType. + + * src/cairo_font.c (cairo_font_glyph_extents) src/cairo_gstate.c + src/cairoint.h: Add public cairo_font_glyph_extents, use it + to implement _cairo_gstate_glyph_extents(). + + * src/cairo_xlib_surface.c (_glyphset_cache_entry_reference): + Add refcounting for glyph cache elements; there was an + bug where elements got ejected from the cache and freed before + they could be used. + + * src/cairoint.h src/cairo_cache.c (_cairo_cache_random_entry()) + New function to return a random entry in the cache matching a predicate; + reuse the internals for the previous _random_live_entry(). + + * src/cairoint.h src/cairo_cache.c (_cairo_cache_lookup()): Add an + optional created_entry return value. + + * src/cairo_ft_font.c src/cairo_xlib_surface.c: Adapt to + _cairo_cache_lookup() change. + + * src/cairo_cache.c (_cairo_cache_lookup()): Support max_memory == 0 + to indicate an unbounded cache. + + * src/cairoint.h src/cairo_cache.c (_cairo_cache_remove()): Add a + function to manually remove entries from the cache. + + * doc/reference: Update for changes, document cairo_matrix_t, + cairo_glyph_t, etc. + + * src/cairo.h src/cairo-atsui.h src/cairo-ft.h src/cairo-glitz.h + src/cairo-pdf.h src/cairo-png.h src/cairo-ps.h src/cairo-quartz.h + src/cairo-xcb.h src/cairo-xlib.h: Add CAIRO_BEGIN/END_DECLS for + extern "C", use it on all public headers. Move header guards + outermost. + + * src/cairo_quartz_surface.c: Fix encoding. + 2005-01-21 Carl Worth <cworth@cworth.org> * configure.in: Increment CAIRO_VERSION to 0.3.0 diff --git a/Makefile.am b/Makefile.am index 3a33e9a7c..60ae80514 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = src test +SUBDIRS = src test doc EXTRA_DIST = \ COPYING \ @@ -1,3 +1,129 @@ +Snapshot 0.4.0 (2005-03-08 Carl Worth <cworth@cworth.org>) +========================================================== +New documentation +----------------- +Owen Taylor has converted cairo's documentation system to gtk-doc and +has begun some long-needed work on the documentation, which can now be +viewed online here: + + http://cairographics.org/manual/ + +New backend: win32 +------------------ +This is the first snapshot to include a functional win32 backend, +(thanks to Owen Taylor). The interface is as follows: + + #include <cairo-win32.h> + + void + cairo_set_target_win32 (cairo_t *cr, + HDC hdc); + + cairo_surface_t * + cairo_win32_surface_create (HDC hdc); + + cairo_font_t * + cairo_win32_font_create_for_logfontw (LOGFONTW *logfont, + cairo_matrix_t *scale); + + cairo_status_t + cairo_win32_font_select_font (cairo_font_t *font, + HDC hdc); + + void + cairo_win32_font_done_font (cairo_font_t *font); + + double + cairo_win32_font_get_scale_factor (cairo_font_t *font); + +And see also the documentation at: + +http://cairographics.org/manual/cairo-Microsoft-Windows-Backend.html + +Disabled backend: quartz +------------------------ +Unfortunately, the quartz backend code is currently out of date with +respect to some recent backend interface changes. So, the quartz +backend is disabled in this snapshot. + +If the quartz backend is brought up-to-date before the next snapshot, +we would be glad to make a 0.4.1 snapshot that re-enables it, (we do +not expect many more big backend interface changes). + +API Changes +----------- +The font system has been revamped, (as Owen Taylor's work with +integrating pango and cairo gave us the first serious usage of the +non-toy font API). + +One fundamental, user-visible change is that the cairo_font_t object +now represents a font that is scaled to a particular device +resolution. Further changes are described below. + + cairo.h + ------- + Removed cairo_font_set_transform and cairo_font_current_transform. + + Added cairo_font_extents and cairo_font_glyph_extents. See + documentation for details: + + http://cairographics.org/manual/cairo-cairo-t.html#cairo-font-extents + + cairo-ft.h + ---------- + The cairo_ft_font API changed considerably. Please see the + documentation for details: + + http://cairographics.org/manual/cairo-FreeType-Fonts.html + +Performance +----------- +Make the fast-path clipping (pixel-aligned rectangles) faster. + +Add optimization for applying a constant alpha to a pattern. + +Optimize gradients that are horizontal or vertical in device space. + +Xlib: When RENDER is not available, use image surfaces for +intermediate surfaces rather than xlib surfaces. + +Backend-specific changes +------------------------ + Glitz + ----- + Major update to glitz backend. The output quality should now be just + as good as the image and xlib backends. + + Track changes to glitz 0.4.0. + + PDF + --- + Various improvements to produce more conformant output. + +Internals +--------- +David Reveman contributed a large re-work of the cairo_pattern_t +implementation, providing cleaner code and more optimization +opportunities. + + Backend interface changes + ------------------------- + Rework backend interface to accept patterns, not surfaces for source + and mask. + + Remove set_matrix, set_filter, and set_repeat functions. + + More sophisticated backend interface for image fallbacks, + ({acquire,release}_{source,dest}_image() and clone_similar). + +Bug fixes +--------- +Only install header files for backends that have been compiled. + +Fixed some rounding errors leading to incorrectly placed glyphs. + +Many other minor fixes. + Snapshot 0.3.0 (2005-01-21 Carl Worth <cworth@cworth.org>) ========================================================== Major API changes @@ -43,7 +43,7 @@ model will help in understanding cairo. History ------- -Cairo was originally developed by Carl Worth <cworth@isi.edu> and +Cairo was originally developed by Carl Worth <cworth@cworth.org> and Keith Packard <keithp@keithp.com>. Many thanks are due to Lyle Ramshaw without whose patient help our ignorance would be much more apparent. @@ -39,15 +39,19 @@ fixes are committed. Here are the steps to follow: 4) Increment CAIRO_VERSION in configure.in - Right now, in its pre-release form, we are incrementing - CAIRO_VERSION for each snapshot but we are not changing - the libtool shared library version information. Increment the - subminor version for bug fixes and backwards-compatible - additions to the API. Increment the minor number (and reset - the subminor) for backward-incompatible changes to the API - (including removals). Leave the major number at 0 until we are - ready for the first 1.0 release, (at which point these rules - will change). + First, remove the "-head" suffix, then increment the version + as follows: + + If there are backward-incompatible changes in the API, + (function removals, or semantic changes), increment the minor + number and reset the sub-minor number to 0. + + Otherwise, (that is, if there are only bug fixes and perhaps + API additions), then increment only the sub-minor number. + + Prior to the initial "1.0" release of cairo, leave the major + number at 0. Also, do not modify the "libtool shared library + version" variables, (LT_CURRENT, LT_VERSION, LT_AGE). 5) Commit the changes to NEWS and configure.in @@ -71,6 +75,8 @@ fixes are committed. Here are the steps to follow: cvs tag SNAPSHOT_X_Y_Z +8) Add a "-head" to CAIRO_VERSION in configure, and commit. + 9) Send a message to cairo-announce@cairographics.org to announce the new snapshot using the text provided from "make release-publish". @@ -1,51 +1,47 @@ -* Add support for non-antialiased rendering. API ? - -* Cleanup cairo_snippets so they operate in a more default cairo - environment, (particularly with a default CTM). - -* Add one of cairo_surface_finish/_finalize/_close to resolve the - "reference counting vs garbage collection" thread. +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 -* Shove experimental snapping code from libsvg-cairo down int cairo - proper. +* Add support for non-antialiased rendering. API ? * Clean up the cache code a bit, (there is at least one redundant level of cacheing, and there are some minor style issues). -* Implement the parallel install stuff, (most importantly, push - cairo.h down into into one directory below $(includedir)). - * Add CAIRO_FILL_RULE_INVERSE_WINDING and CAIRO_FILL_RULE_INVERSE_EVEN_ODD -* Simplifying the operator set? - * Fix clipping to work for all operators. The equation we have come up with is: ((src Op dest) In clip) Add (dest Out clip) -* Resolve the rest of the rendering equation. We need a fundamental - equation upon which more convenient operations are based, (at least - formally). Some of the common operations that should be convenient: - - * display surface - * display surface multiplied by constant alpha - * display pattern masked by surface - - So this involves deciding whether to expose a new mask object in the - graphics state, and deciding exactly what set_alpha means. It almost - certainly means adding cairo_show_surface_mask. - -* Implement a hidden transform, (as per the result of the hidden - offset thread on the mailing list). - * Replace PNG backend with an image_surface function to save a PNG image. * Clean up the API in preparation for freezing and release. -* Implement a PDF backend. - * Make a more interesting PS backend, (other than the current "giant-image for every page" approach). @@ -54,9 +50,6 @@ * Change stroke code to go through one giant polygon. This will fix problems with stroking self-intersecting paths. -* Implement cairo_stroke_path, (very easy to do after the above change -is done). - * Re-work the backend clipping interface to use geometry rather than images. @@ -90,17 +83,6 @@ do gradients the Right Way). * Implement cairo_arc_to. -* Fix support for old X servers so that it is not swamped with image -transport. The key idea is to assume that nothing external to cairo -will be drawing to the same drawable after it is handed to -cairo. Beyond that, we might actually provide support for cooperating -with external entities by adding one or more of the following -functions: - - cairo_flush - cairo_erase - cairo_mark_dirty - * Re-implement the trapezoid rasterization algorithm according to the new "specification". @@ -146,134 +128,3 @@ functions: * Verification, profiling, optimization. centi_unfinished.svg may provide a good test case. - -A comparison with PostScript -============================ - -Here's a list of several classes of PostScript operators indicating -which operators have rough equivalents in cairo and which do not. In -general, the name of a cairo function corresponding to a PostScript -operator can be obtained by inserting a '_' between each word and -prefixing it with "cairo_". For example, "cairo_move_to" corresponds -to the PostScript "moveto". - -In cases where the name of the cairo function deviates from this -convention, or when the behavior of the cairo function is -significantly different, the change is noted in parentheses below. - -This list is not exhaustive, (there are definitely some minor (major?) -semantic deviations that are not noted below). Also, this list is -almost certainly out of date with respect to the current cairo -implementation. Caveat lector. - -Operators that are not yet in cairo, but probably should be: arcto, -strokepath, rectclip?, clipsave/restore?, setstrokeadjust?, -currentdash, grestoreall?, initgraphics?, currentgstate?, setgstate?, -erasepage?, setsmoothness? - -Painting operators ------------------- -in cairo: stroke, fill, eofill (set_fill_rule/fill), image -(show_surface) - -not in cairo: erasepage, rectstroke, rectfill, shfill, colorimage, -imagemask - -Path construction operators ---------------------------- -in cairo: arc, arcn (arc_negative), newpath, moveto, rmoveto -(rel_move_to), lineto, rlineto (rel_line_to), curveto, rcurveto -(rel_curve_to), closepath, currentpoint, charpath (text_path), -pathforall (current_path), flattenpath (current_path_flat) - -not in cairo: arct, arcto, reversepath, strokepath, clippath, pathbbox - -Clipping --------- -in cairo: clip, eoclip (set_fill_rule/clip) - -not in cairo: initclip, rectclip, clipsave, cliprestore - -Graphics state operators ------------------------- -in cairo: setlinewidth, currentlinewidth, setlinecap, currentlinecap, -setlinejoin, currentlinejoin, setmiterlimit, currentmiterlimit, -setdash - -not in cairo: setstrokeadjust, currentstrokeadjust, currentdash - -Color specification operators ------------------------------ -in cairo: setrgbcolor, currentcolor - -not in cairo: setcolor, setgray, currentgray, currentrgbcolor, -sethsbcolor, currenthsbcolor, setcmykcolor, currentcmykcolor, -setcolorspace, currentcolorspace - -Form and pattern operators --------------------------- -in cairo: setpattern, makepattern (lock_pattern) - -not in cairo: execform - -Whole-state manipulation ------------------------- -in cairo: gsave (save), grestore (restore) - -not in cairo: grestoreall, initgraphics, gstate, currentgstate, -setgstate - -Coordinate system and matrix operators --------------------------------------- -in cairo: identmatrix (identity_matrix), initmatrix (default_matrix), -setmatrix, translate, scale, rotate, concatmatrix, currentmatrix, -transform (transform_point), dtransform (transform_distance) - -not in cairo: matrix, defaultmatrix, concat, itransform, idtransform, -invertmatrix - -Insideness testing ------------------- -in cairo: infill, instroke, ineofill (set_fill_rule/in_fill) - -not in cairo: inufill, inustroke, inueofill - -Device setup ------------- -in cairo: showpage, copypage - -not in cairo: setpagedevice, currentpagedevice, nulldevice - -Glyph and font operators ------------------------- -in cairo: currentfont, definefont (font_create_for_ft_face), -undefine_font (font_destroy), findfont (font_create), makefont -(transform_font), setfont, scalefont, selectfont, show (show_text), -stringwidth (x/y in text_extents), xyshow (glyph_show -- but ignoring -current_point and using absolute positions) - -not in cairo, (and likely not needed): composefont, rootfont, ashow, -widthshow, awidthshow, xshow, xyshow, yshow, glyphshow, cshow, kshow, -FontDirectory, GlobalFontDirectory, StandardEncoding, -ISOLatin1Encoding, findencoding, setcachedevice, setcachedevice2, -setcharwidth - -Graphics state operators (device-dependent) -------------------------------------------- -in cairo: setflat (set_tolerance), currentflat (current_tolerance) - -not in cairo: sethalftone, currenthalftone, setscreen, currentscreen, -setcolorscreen, currentcolorscreen, settransfer, currenttransfer, -setcolortransfer, currentcolortransfer, setblackgeneration, -currentblackgeneration, setundercolorremoval, -currentundercolorremoval, setcolorrendering, currentcolorrendering, -setoverprint, currentoverprint, setsmoothness, currentsmoothness - -PostScript operators never to be in cairo ------------------------------------------ -Operator Stack Manipulation Operators, Arithmetic and Math Operators, -Array Operators, Packed Array Operators, Dictionary Operators, String -Operators, Rational,Boolean,and Bitwise Operators, Control Operators, -Type,Attribute,and Conversion Operators, File Operators, Resource -Operators, Virtual Memory Operators, Miscellaneous Operators, -Interpreter Parameter Operators, Errors, User Path Operators diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 000000000..af73800bf --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,53 @@ +dnl -*- mode: autoconf -*- + +# serial 1 + +dnl Usage: +dnl GTK_DOC_CHECK([minimum-gtk-doc-version]) +AC_DEFUN([GTK_DOC_CHECK], +[ + AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + dnl for overriding the documentation installation directory + AC_ARG_WITH(html-dir, + AC_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),, + [with_html_dir='${datadir}/gtk-doc/html']) + HTML_DIR="$with_html_dir" + AC_SUBST(HTML_DIR) + + dnl enable/disable documentation building + AC_ARG_ENABLE(gtk-doc, + AC_HELP_STRING([--enable-gtk-doc], + [use gtk-doc to build documentation [default=no]]),, + enable_gtk_doc=no) + + have_gtk_doc=no + if test x$enable_gtk_doc = xyes; then + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + if test "$PKG_CONFIG" != "no" && $PKG_CONFIG --exists gtk-doc; then + have_gtk_doc=yes + fi + + dnl do we want to do a version check? +ifelse([$1],[],, + [gtk_doc_min_version=$1 + if test "$have_gtk_doc" = yes; then + AC_MSG_CHECKING([gtk-doc version >= $gtk_doc_min_version]) + if $PKG_CONFIG --atleast-version $gtk_doc_min_version gtk-doc; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + have_gtk_doc=no + fi + fi +]) + if test "$have_gtk_doc" != yes; then + enable_gtk_doc=no + fi + fi + + AM_CONDITIONAL(ENABLE_GTK_DOC, test x$enable_gtk_doc = xyes) + AM_CONDITIONAL(GTK_DOC_USE_LIBTOOL, test -n "$LIBTOOL") +]) diff --git a/autogen.sh b/autogen.sh index 46ca3422b..f834cfed1 100755 --- a/autogen.sh +++ b/autogen.sh @@ -22,6 +22,7 @@ libtoolize_min_vers=1.4 # The awk-based string->number conversion we use needs a C locale to work as expected. LANG=C +LC_NUMERIC=C ARGV0=$0 @@ -133,4 +134,4 @@ do_cmd $AUTOMAKE $AUTOMAKE_FLAGS do_cmd $AUTOCONF -do_cmd ./configure --enable-maintainer-mode ${1+"$@"} && echo "Now type \`make' to compile" || exit 1 +do_cmd ./configure --enable-maintainer-mode --enable-gtk-doc ${1+"$@"} && echo "Now type \`make' to compile" || exit 1 diff --git a/cairo.pc.in b/cairo.pc.in index 4e420b202..2cd0ff182 100644 --- a/cairo.pc.in +++ b/cairo.pc.in @@ -7,6 +7,6 @@ Name: cairo Description: Multi-platform 2D graphics library Version: @VERSION@ -Requires: fontconfig libpixman @XRENDER_REQUIRES@ @PNG_REQUIRES@ @GLITZ_REQUIRES@ +Requires: @FREETYPE_REQUIRES@ libpixman @XRENDER_REQUIRES@ @PNG_REQUIRES@ @GLITZ_REQUIRES@ Libs: @FREETYPE_LIBS@ -L${libdir} -lcairo Cflags: @FREETYPE_CFLAGS@ -I${includedir}/cairo diff --git a/configure.in b/configure.in index 61d9adbae..5ee585e73 100644 --- a/configure.in +++ b/configure.in @@ -1,9 +1,11 @@ +AC_PREREQ(2.54) + AC_INIT(src/cairo.h) dnl =========================================================================== # Package version number, (as distinct from shared library version) -CAIRO_VERSION=0.3.0 +CAIRO_VERSION=0.4.0 # libtool shared library version @@ -35,6 +37,8 @@ AM_PROG_LIBTOOL AC_STDC_HEADERS AC_C_BIGENDIAN +AC_CHECK_FUNCS(vasnprintf) + AC_CHECK_LIBM LIBS="$LIBS $LIBM" @@ -75,7 +79,7 @@ CAIRO_LIBS="$CAIRO_LIBS $XRENDER_LIBS" AC_ARG_ENABLE(quartz, [ --disable-quartz Disable cairo's quartz backend], - [use_quartz=$enableval], [use_quartz=yes]) + [use_quartz=$enableval], [use_quartz="no (temporarily disabled while code is out of sync)"]) if test "x$use_quartz" = "xyes"; then dnl There is no pkgconfig for quartz; lets do a header check @@ -120,6 +124,50 @@ AC_SUBST(XCB_SURFACE_FEATURE) dnl =========================================================================== +AC_MSG_CHECKING([for some Win32 platform]) +case "$host" in + *-*-mingw*|*-*-cygwin*) + cairo_platform_win32=yes + ;; + *) + cairo_platform_win32=no + ;; +esac +AC_MSG_RESULT([$cairo_platform_win32]) + +AC_ARG_ENABLE(win32, + [ --disable-win32 Disable cairo's Microsoft Windows backend], + [use_win32=$enableval], [use_win32="yes"]) + +if test "x$cairo_platform_win32" != "xyes" ; then + use_win32=no +fi + +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) +fi + +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) +fi + +AC_SUBST(WIN32_SURFACE_FEATURE) +AC_SUBST(WIN32_FONT_FEATURE) + +dnl =========================================================================== + AC_ARG_ENABLE(ps, [ --disable-ps Disable cairo's PostScript backend], [use_ps=$enableval], [use_ps=yes]) @@ -140,37 +188,27 @@ AC_SUBST(PS_LIBS) dnl =========================================================================== -AC_ARG_ENABLE(pdf, - [ --disable-pdf Disable cairo's PDF backend], - [use_pdf=$enableval], [use_pdf=yes]) - -if test "x$use_pdf" != "xyes"; then - PDF_SURFACE_FEATURE=CAIRO_HAS_NO_PDF_SURFACE - AM_CONDITIONAL(CAIRO_HAS_PDF_SURFACE, false) -else - PDF_SURFACE_FEATURE=CAIRO_HAS_PDF_SURFACE - PDF_LIBS=-lz - AM_CONDITIONAL(CAIRO_HAS_PDF_SURFACE, true) -fi - -CAIRO_LIBS="$CAIRO_LIBS $PDF_LIBS" - -AC_SUBST(PDF_SURFACE_FEATURE) -AC_SUBST(PDF_LIBS) - -dnl =========================================================================== - AC_ARG_ENABLE(png, [ --disable-png Disable cairo's PNG backend], [use_png=$enableval], [use_png=yes]) if test "x$use_png" = "xyes"; then - PKG_CHECK_MODULES(PNG, libpng12, [ - PNG_REQUIRES=libpng12 - use_png=yes], [ - PKG_CHECK_MODULES(PNG, libpng10, [ - PNG_REQUIRES=libpng10 - use_png=yes], [use_png="no (requires libpng http://www.libpng.org)"])]) + use_png=no + # libpng13 is GnuWin32's libpng-1.2.8 :-( + for l in libpng12 libpng13 libpng10 ; do + if $PKG_CONFIG --exists $l ; then + PNG_REQUIRES=$l + use_png=yes + break + fi + done + + if test "x$use_png" = "xyes" ; then + # Sets PNG_CFLAGS, PNG_LIBS + PKG_CHECK_MODULES(PNG, $PNG_REQUIRES) + else + AC_MSG_WARN([Could not find libpng in the pkg-config search path]) + fi fi if test "x$use_png" != "xyes"; then @@ -194,7 +232,7 @@ AC_ARG_ENABLE(glitz, [use_glitz=$enableval], [use_glitz=yes]) if test "x$use_glitz" = "xyes"; then - PKG_CHECK_MODULES(GLITZ, glitz >= 0.3.0, [ + PKG_CHECK_MODULES(GLITZ, glitz >= 0.4.0, [ GLITZ_REQUIRES=glitz use_glitz=yes], [use_glitz="no (requires glitz http://freedesktop.org/software/glitz)"]) fi @@ -229,7 +267,7 @@ AC_SUBST(SANITY_CHECKING_FEATURE) dnl =========================================================================== -PKG_CHECK_MODULES(PIXMAN, libpixman >= 0.1.2) +PKG_CHECK_MODULES(PIXMAN, libpixman >= 0.1.4) CAIRO_CFLAGS="$CAIRO_CFLAGS $PIXMAN_CFLAGS" CAIRO_LIBS="$CAIRO_LIBS $PIXMAN_LIBS" @@ -285,9 +323,11 @@ if test "x$use_freetype" = "xyes"; then AC_MSG_RESULT($FREETYPE_VERSION - OK) FREETYPE_CFLAGS=`$FREETYPE_CONFIG --cflags` - FREETYPE_LIBS=`$FREETYPE_CONFIG --libs` + FREETYPE_LIBS=`$FREETYPE_CONFIG --libs` + FREETYPE_REQUIRES=fontconfig AC_SUBST(FREETYPE_CFLAGS) AC_SUBST(FREETYPE_LIBS) + AC_SUBST(FREETYPE_REQUIRES) fi CAIRO_CFLAGS="$CAIRO_CFLAGS $FREETYPE_CFLAGS" @@ -304,6 +344,31 @@ AC_SUBST(FT_FONT_FEATURE) dnl =========================================================================== +AC_ARG_ENABLE(pdf, + [ --disable-pdf Disable cairo's PDF backend], + [use_pdf=$enableval], [use_pdf=yes]) + +if test x"$use_freetype" != "xyes" ; then + AC_MSG_WARN([PDF backend requires FreeType, disabling]) + 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 + PDF_LIBS=-lz + AM_CONDITIONAL(CAIRO_HAS_PDF_SURFACE, true) +fi + +CAIRO_LIBS="$CAIRO_LIBS $PDF_LIBS" + +AC_SUBST(PDF_SURFACE_FEATURE) +AC_SUBST(PDF_LIBS) + +dnl =========================================================================== + dnl This check should default to 'yes' once we have code to actually dnl check for the atsui font backend. @@ -346,6 +411,9 @@ AC_SUBST(CAIRO_CFLAGS) AC_SUBST(CAIRO_LIBS) dnl =========================================================================== +dnl Check for gtk-doc and docbook + +GTK_DOC_CHECK([1.3]) AC_OUTPUT([ cairo.pc @@ -353,6 +421,8 @@ Makefile src/Makefile src/cairo-features.h test/Makefile +doc/Makefile +doc/public/Makefile ]) dnl =========================================================================== @@ -362,13 +432,25 @@ echo "cairo will be compiled with the following surface backends:" echo " Xlib: $use_xlib" echo " Quartz: $use_quartz" 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 " freetype: $use_freetype" -echo " atsui: $use_atsui" +echo " FreeType: $use_freetype" +echo " Win32: $use_win32" +echo " ATSUI: $use_atsui" echo "" +if test x"$use_freetype" != "xyes" && \ + test x"$use_win32" != "xyes" && \ + test x"$use_atsui" != "xyes" ; then + + AC_MSG_ERROR([Cairo requires at least one font backend. + Please install freetype and fontconfig, then try again: + http://freetype.org/ http://fontconfig.org/ + ]) +fi + diff --git a/doc/.cvsignore b/doc/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/doc/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 000000000..411ad5c93 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS=public + diff --git a/doc/public/.cvsignore b/doc/public/.cvsignore new file mode 100644 index 000000000..35479d5e3 --- /dev/null +++ b/doc/public/.cvsignore @@ -0,0 +1,15 @@ +*.stamp +Makefile +Makefile.in +cairo-decl-list.txt +cairo-decl.txt +cairo-undocumented.txt +cairo-unused.txt +cairo.hierarchy +cairo.interfaces +cairo.prerequisites +cairo.args +cairo.signals +html +xml + diff --git a/doc/public/Makefile.am b/doc/public/Makefile.am new file mode 100644 index 000000000..b993bb978 --- /dev/null +++ b/doc/public/Makefile.am @@ -0,0 +1,46 @@ +## Process this file with automake to create Makefile.in. + +AUTOMAKE_OPTIONS = 1.7 + +# The name of the module. +DOC_MODULE=cairo + +# The top-level SGML file. +DOC_MAIN_SGML_FILE=cairo-docs.xml + +# Extra options to supply to gtkdoc-scan +SCAN_OPTIONS=--deprecated-guards="CAIRO_DISABLE_DEPRECATED" + +# The directory containing the source code. Relative to $(srcdir) +DOC_SOURCE_DIR=../../src + +# Used for dependencies +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 \ + cairo-wideint.h + +# CFLAGS and LDFLAGS for compiling scan program. Only needed +# if $(DOC_MODULE).types is non-empty. +INCLUDES = +GTKDOC_LIBS = + +# Extra options to supply to gtkdoc-mkdb +MKDB_OPTIONS=--sgml-mode --output-format=xml + +# Non-autogenerated SGML files to be included in $(DOC_MAIN_SGML_FILE) +content_files = + +# Images to copy into HTML directory +HTML_IMAGES = + +# Extra options to supply to gtkdoc-fixref +FIXXREF_OPTIONS= + +include $(top_srcdir)/gtk-doc.make diff --git a/doc/public/cairo-docs.xml b/doc/public/cairo-docs.xml new file mode 100644 index 000000000..2a4cdae8a --- /dev/null +++ b/doc/public/cairo-docs.xml @@ -0,0 +1,31 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" + "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> +<book lang="en" id="libglade" xmlns:xi="http://www.w3.org/2003/XInclude"> +<title>Cairo: A Vector Graphics Library</title> + <part> + <title>Tutorial</title> + </part> + <part> + <title>Reference</title> + <xi:include href="xml/cairo.xml"/> + <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-atsui.xml"/> + <xi:include href="xml/cairo-ft.xml"/> + <xi:include href="xml/cairo-glitz.xml"/> + <xi:include href="xml/cairo-pdf.xml"/> + <xi:include href="xml/cairo-png.xml"/> + <xi:include href="xml/cairo-ps.xml"/> + <xi:include href="xml/cairo-quartz.xml"/> + <xi:include href="xml/cairo-win32.xml"/> + <xi:include href="xml/cairo-xcb.xml"/> + <xi:include href="xml/cairo-xlib.xml"/> + </part> +</book> + + + + + diff --git a/doc/public/cairo-overrides.txt b/doc/public/cairo-overrides.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/doc/public/cairo-overrides.txt diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt new file mode 100644 index 000000000..3da0fa801 --- /dev/null +++ b/doc/public/cairo-sections.txt @@ -0,0 +1,251 @@ +<SECTION> +<FILE>cairo-atsui</FILE> +<TITLE>ATSUI Fonts</TITLE> +cairo_atsui_font_create +</SECTION> + +<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 +</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 +</SECTION> + +<SECTION> +<FILE>cairo-png</FILE> +<TITLE>PNG Backend</TITLE> +cairo_set_target_png +cairo_png_surface_create +</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 +</SECTION> + +<SECTION> +<FILE>cairo-xcb</FILE> +<TITLE>XCB Backend</TITLE> +cairo_set_target_xcb +</SECTION> + +<SECTION> +<FILE>cairo-xlib</FILE> +<TITLE>XLib Backend</TITLE> +cairo_set_target_drawable +cairo_xlib_surface_create +</SECTION> + +<SECTION> +<FILE>cairo-surface</FILE> +<TITLE>cairo_surface_t</TITLE> +cairo_surface_t +cairo_surface_create_for_image +cairo_surface_create_similar +cairo_surface_reference +cairo_surface_destroy +cairo_surface_set_repeat +cairo_surface_set_matrix +cairo_surface_get_matrix +cairo_surface_set_filter +cairo_surface_get_filter +</SECTION> + +<SECTION> +<FILE>cairo-pattern</FILE> +<TITLE>cairo_pattern_t</TITLE> +cairo_pattern_t +cairo_pattern_create_for_surface +cairo_pattern_create_linear +cairo_pattern_create_radial +cairo_pattern_reference +cairo_pattern_destroy +cairo_pattern_add_color_stop +cairo_pattern_set_matrix +cairo_pattern_get_matrix +cairo_extend_t +cairo_pattern_set_extend +cairo_pattern_get_extend +cairo_pattern_set_filter +cairo_pattern_get_filter +</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_translate +cairo_matrix_scale +cairo_matrix_rotate +cairo_matrix_invert +cairo_matrix_multiply +cairo_matrix_transform_distance +cairo_matrix_transform_point +</SECTION> + +<SECTION> +<FILE>cairo</FILE> +<TITLE>cairo_t</TITLE> +cairo_t +cairo_create +cairo_reference +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_alpha +cairo_set_tolerance +cairo_fill_rule_t +cairo_set_fill_rule +cairo_set_line_width +cairo_line_cap_t +cairo_set_line_cap +cairo_line_join_t +cairo_set_line_join +cairo_set_dash +cairo_set_miter_limit +cairo_translate +cairo_scale +cairo_rotate +cairo_concat_matrix +cairo_set_matrix +cairo_default_matrix +cairo_identity_matrix +cairo_transform_point +cairo_transform_distance +cairo_inverse_transform_point +cairo_inverse_transform_distance +cairo_new_path +cairo_move_to +cairo_line_to +cairo_curve_to +cairo_arc +cairo_arc_negative +cairo_rel_move_to +cairo_rel_line_to +cairo_rel_curve_to +cairo_rectangle +cairo_close_path +cairo_stroke +cairo_fill +cairo_copy_page +cairo_show_page +cairo_in_stroke +cairo_in_fill +cairo_bool_t +cairo_stroke_extents +cairo_fill_extents +cairo_init_clip +cairo_clip +cairo_font_t +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_show_text +cairo_show_glyphs +cairo_current_font +cairo_current_font_extents +cairo_set_font +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_current_operator +cairo_current_rgb_color +cairo_current_pattern +cairo_current_alpha +cairo_current_tolerance +cairo_current_point +cairo_current_fill_rule +cairo_current_line_width +cairo_current_line_cap +cairo_current_line_join +cairo_current_miter_limit +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_get_status +cairo_get_status_string +</SECTION> diff --git a/doc/public/cairo.types b/doc/public/cairo.types new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/doc/public/cairo.types diff --git a/doc/public/tmpl/.cvsignore b/doc/public/tmpl/.cvsignore new file mode 100644 index 000000000..844dc52df --- /dev/null +++ b/doc/public/tmpl/.cvsignore @@ -0,0 +1 @@ +cairo-unused.sgml diff --git a/doc/public/tmpl/cairo-atsui.sgml b/doc/public/tmpl/cairo-atsui.sgml new file mode 100644 index 000000000..0d957ecdf --- /dev/null +++ b/doc/public/tmpl/cairo-atsui.sgml @@ -0,0 +1,25 @@ +<!-- ##### SECTION Title ##### --> +ATSUI Fonts + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### FUNCTION cairo_atsui_font_create ##### --> +<para> + +</para> + +@style: +@Returns: + + diff --git a/doc/public/tmpl/cairo-ft.sgml b/doc/public/tmpl/cairo-ft.sgml new file mode 100644 index 000000000..bcf52ac34 --- /dev/null +++ b/doc/public/tmpl/cairo-ft.sgml @@ -0,0 +1,63 @@ +<!-- ##### SECTION Title ##### --> +FreeType Fonts + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### FUNCTION cairo_ft_font_create ##### --> +<para> + +</para> + +@pattern: +@scale: +@Returns: + + +<!-- ##### FUNCTION cairo_ft_font_create_for_ft_face ##### --> +<para> + +</para> + +@face: +@load_flags: +@scale: +@Returns: + + +<!-- ##### FUNCTION cairo_ft_font_lock_face ##### --> +<para> + +</para> + +@ft_font: +@Returns: + + +<!-- ##### FUNCTION cairo_ft_font_unlock_face ##### --> +<para> + +</para> + +@ft_font: + + +<!-- ##### FUNCTION cairo_ft_font_get_pattern ##### --> +<para> + +</para> + +@ft_font: +@Returns: + + diff --git a/doc/public/tmpl/cairo-glitz.sgml b/doc/public/tmpl/cairo-glitz.sgml new file mode 100644 index 000000000..101eb9e3e --- /dev/null +++ b/doc/public/tmpl/cairo-glitz.sgml @@ -0,0 +1,34 @@ +<!-- ##### SECTION Title ##### --> +Glitz backend + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### FUNCTION cairo_set_target_glitz ##### --> +<para> + +</para> + +@cr: +@surface: + + +<!-- ##### FUNCTION cairo_glitz_surface_create ##### --> +<para> + +</para> + +@surface: +@Returns: + + diff --git a/doc/public/tmpl/cairo-matrix.sgml b/doc/public/tmpl/cairo-matrix.sgml new file mode 100644 index 000000000..dc24c5754 --- /dev/null +++ b/doc/public/tmpl/cairo-matrix.sgml @@ -0,0 +1,193 @@ +<!-- ##### SECTION Title ##### --> +cairo_matrix_t + +<!-- ##### SECTION Short_Description ##### --> + + Transformation matrices + +<!-- ##### SECTION Long_Description ##### --> + + <para><indexterm><primary>types</primary><secondary>cairo_matrix</secondary></indexterm><indexterm><primary/></indexterm> + <structname>cairo_matrix_t</structname> is used throughout + Cairo to represents between different coordinates spaces. + A <structname>cairo_matrix</structname> holds an affine + transformation, such as a scale, rotation, or shear, or a + combination of those. Mathematically, the effect of an affine + transformation on a point (<literal>x</literal>,<literal>y</literal>) is given by: + </para> + <programlisting> + x_new = x * a + y * c + tx; + y_new = x * b + y * d + ty; + </programlisting> + <para> + The parameters <literal>a</literal>, <literal>b</literal>, + <literal>c</literal>, <literal>d</literal>, <literal>tx</literal>, + <literal>ty</literal> can be retrieved with + cairo_matrix_get_affine() and set with cairo_matrix_get_affine(). + </para> + <para> + The primary use of transformation matrices in Cairo is as the + current transformation matrix in a #cairo_t. The current + transformation matrix gives the transformation from user space + coordinates to device coordinates. See cairo_set_matrix(), + cairo_current_matrix(). + </para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### TYPEDEF cairo_matrix_t ##### --> +<para> + +</para> + + +<!-- ##### FUNCTION cairo_matrix_create ##### --> +<para> + +</para> + +@Returns: + + +<!-- ##### FUNCTION cairo_matrix_destroy ##### --> +<para> + +</para> + +@matrix: + + +<!-- ##### FUNCTION cairo_matrix_copy ##### --> +<para> + +</para> + +@matrix: +@other: +@Returns: + + +<!-- ##### FUNCTION cairo_matrix_set_identity ##### --> +<para> + +</para> + +@matrix: +@Returns: + + +<!-- ##### FUNCTION cairo_matrix_set_affine ##### --> +<para> + +</para> + +@matrix: +@a: +@b: +@c: +@d: +@tx: +@ty: +@Returns: +<!-- # Unused Parameters # --> +@cr: + + +<!-- ##### FUNCTION cairo_matrix_get_affine ##### --> +<para> + +</para> + +@matrix: +@a: +@b: +@c: +@d: +@tx: +@ty: +@Returns: + + +<!-- ##### FUNCTION cairo_matrix_translate ##### --> +<para> + +</para> + +@matrix: +@tx: +@ty: +@Returns: + + +<!-- ##### FUNCTION cairo_matrix_scale ##### --> +<para> + +</para> + +@matrix: +@sx: +@sy: +@Returns: + + +<!-- ##### FUNCTION cairo_matrix_rotate ##### --> +<para> + +</para> + +@matrix: +@radians: +@Returns: + + +<!-- ##### FUNCTION cairo_matrix_invert ##### --> +<para> + +</para> + +@matrix: +@Returns: + + +<!-- ##### FUNCTION cairo_matrix_multiply ##### --> +<para> + +</para> + +@result: +@a: +@b: +@Returns: + + +<!-- ##### FUNCTION cairo_matrix_transform_distance ##### --> +<para> + +</para> + +@matrix: +@dx: +@dy: +@Returns: + + +<!-- ##### FUNCTION cairo_matrix_transform_point ##### --> +<para> +</para> + +@matrix: +@x: +@y: +@Returns: + +<!-- +Local variables: +mode: sgml +sgml-parent-document: ("../cairo-docs.xml" "book" "refsect2" "") +End: +--> + + diff --git a/doc/public/tmpl/cairo-pattern.sgml b/doc/public/tmpl/cairo-pattern.sgml new file mode 100644 index 000000000..84728212b --- /dev/null +++ b/doc/public/tmpl/cairo-pattern.sgml @@ -0,0 +1,154 @@ +<!-- ##### SECTION Title ##### --> +cairo_pattern_t + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### TYPEDEF cairo_pattern_t ##### --> +<para> + +</para> + + +<!-- ##### FUNCTION cairo_pattern_create_for_surface ##### --> +<para> + +</para> + +@surface: +@Returns: + + +<!-- ##### FUNCTION cairo_pattern_create_linear ##### --> +<para> + +</para> + +@x0: +@y0: +@x1: +@y1: +@Returns: + + +<!-- ##### FUNCTION cairo_pattern_create_radial ##### --> +<para> + +</para> + +@cx0: +@cy0: +@radius0: +@cx1: +@cy1: +@radius1: +@Returns: + + +<!-- ##### FUNCTION cairo_pattern_reference ##### --> +<para> + +</para> + +@pattern: + + +<!-- ##### FUNCTION cairo_pattern_destroy ##### --> +<para> + +</para> + +@pattern: + + +<!-- ##### FUNCTION cairo_pattern_add_color_stop ##### --> +<para> + +</para> + +@pattern: +@offset: +@red: +@green: +@blue: +@alpha: +@Returns: + + +<!-- ##### FUNCTION cairo_pattern_set_matrix ##### --> +<para> + +</para> + +@pattern: +@matrix: +@Returns: + + +<!-- ##### FUNCTION cairo_pattern_get_matrix ##### --> +<para> + +</para> + +@pattern: +@matrix: +@Returns: + + +<!-- ##### ENUM cairo_extend_t ##### --> +<para> + +</para> + +@CAIRO_EXTEND_NONE: +@CAIRO_EXTEND_REPEAT: +@CAIRO_EXTEND_REFLECT: + +<!-- ##### FUNCTION cairo_pattern_set_extend ##### --> +<para> + +</para> + +@pattern: +@extend: +@Returns: + + +<!-- ##### FUNCTION cairo_pattern_get_extend ##### --> +<para> + +</para> + +@pattern: +@Returns: + + +<!-- ##### FUNCTION cairo_pattern_set_filter ##### --> +<para> + +</para> + +@pattern: +@filter: +@Returns: + + +<!-- ##### FUNCTION cairo_pattern_get_filter ##### --> +<para> + +</para> + +@pattern: +@Returns: + + diff --git a/doc/public/tmpl/cairo-pdf.sgml b/doc/public/tmpl/cairo-pdf.sgml new file mode 100644 index 000000000..e627c236e --- /dev/null +++ b/doc/public/tmpl/cairo-pdf.sgml @@ -0,0 +1,42 @@ +<!-- ##### SECTION Title ##### --> +PDF Backend + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### FUNCTION cairo_set_target_pdf ##### --> +<para> + +</para> + +@cr: +@file: +@width_inches: +@height_inches: +@x_pixels_per_inch: +@y_pixels_per_inch: + + +<!-- ##### FUNCTION cairo_pdf_surface_create ##### --> +<para> + +</para> + +@file: +@width_inches: +@height_inches: +@x_pixels_per_inch: +@y_pixels_per_inch: +@Returns: + + diff --git a/doc/public/tmpl/cairo-png.sgml b/doc/public/tmpl/cairo-png.sgml new file mode 100644 index 000000000..d4d5a66b5 --- /dev/null +++ b/doc/public/tmpl/cairo-png.sgml @@ -0,0 +1,40 @@ +<!-- ##### SECTION Title ##### --> +PNG Backend + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### FUNCTION cairo_set_target_png ##### --> +<para> + +</para> + +@cr: +@file: +@format: +@width: +@height: + + +<!-- ##### FUNCTION cairo_png_surface_create ##### --> +<para> + +</para> + +@file: +@format: +@width: +@height: +@Returns: + + diff --git a/doc/public/tmpl/cairo-ps.sgml b/doc/public/tmpl/cairo-ps.sgml new file mode 100644 index 000000000..70b2e7e8f --- /dev/null +++ b/doc/public/tmpl/cairo-ps.sgml @@ -0,0 +1,42 @@ +<!-- ##### SECTION Title ##### --> +PS Backend + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### FUNCTION cairo_set_target_ps ##### --> +<para> + +</para> + +@cr: +@file: +@width_inches: +@height_inches: +@x_pixels_per_inch: +@y_pixels_per_inch: + + +<!-- ##### FUNCTION cairo_ps_surface_create ##### --> +<para> + +</para> + +@file: +@width_inches: +@height_inches: +@x_pixels_per_inch: +@y_pixels_per_inch: +@Returns: + + diff --git a/doc/public/tmpl/cairo-quartz.sgml b/doc/public/tmpl/cairo-quartz.sgml new file mode 100644 index 000000000..04c9bc61f --- /dev/null +++ b/doc/public/tmpl/cairo-quartz.sgml @@ -0,0 +1,38 @@ +<!-- ##### SECTION Title ##### --> +Quartz Backend + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### FUNCTION cairo_set_target_quartz_context ##### --> +<para> + +</para> + +@cr: +@context: +@width: +@height: + + +<!-- ##### FUNCTION cairo_quartz_surface_create ##### --> +<para> + +</para> + +@context: +@width: +@height: +@Returns: + + diff --git a/doc/public/tmpl/cairo-surface.sgml b/doc/public/tmpl/cairo-surface.sgml new file mode 100644 index 000000000..2f8ad470c --- /dev/null +++ b/doc/public/tmpl/cairo-surface.sgml @@ -0,0 +1,112 @@ +<!-- ##### SECTION Title ##### --> +cairo_surface_t + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### TYPEDEF cairo_surface_t ##### --> +<para> + +</para> + + +<!-- ##### FUNCTION cairo_surface_create_for_image ##### --> +<para> + +</para> + +@data: +@format: +@width: +@height: +@stride: +@Returns: + + +<!-- ##### FUNCTION cairo_surface_create_similar ##### --> +<para> + +</para> + +@other: +@format: +@width: +@height: +@Returns: + + +<!-- ##### FUNCTION cairo_surface_reference ##### --> +<para> + +</para> + +@surface: + + +<!-- ##### FUNCTION cairo_surface_destroy ##### --> +<para> + +</para> + +@surface: + + +<!-- ##### FUNCTION cairo_surface_set_repeat ##### --> +<para> + +</para> + +@surface: +@repeat: +@Returns: + + +<!-- ##### FUNCTION cairo_surface_set_matrix ##### --> +<para> + +</para> + +@surface: +@matrix: +@Returns: + + +<!-- ##### FUNCTION cairo_surface_get_matrix ##### --> +<para> + +</para> + +@surface: +@matrix: +@Returns: + + +<!-- ##### FUNCTION cairo_surface_set_filter ##### --> +<para> + +</para> + +@surface: +@filter: +@Returns: + + +<!-- ##### FUNCTION cairo_surface_get_filter ##### --> +<para> + +</para> + +@surface: +@Returns: + + diff --git a/doc/public/tmpl/cairo-xcb.sgml b/doc/public/tmpl/cairo-xcb.sgml new file mode 100644 index 000000000..e5e1ee912 --- /dev/null +++ b/doc/public/tmpl/cairo-xcb.sgml @@ -0,0 +1,28 @@ +<!-- ##### SECTION Title ##### --> +XCB Backend + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### FUNCTION cairo_set_target_xcb ##### --> +<para> + +</para> + +@cr: +@dpy: +@drawable: +@visual: +@format: + + diff --git a/doc/public/tmpl/cairo-xlib.sgml b/doc/public/tmpl/cairo-xlib.sgml new file mode 100644 index 000000000..b18e76aae --- /dev/null +++ b/doc/public/tmpl/cairo-xlib.sgml @@ -0,0 +1,39 @@ +<!-- ##### SECTION Title ##### --> +XLib Backend + +<!-- ##### SECTION Short_Description ##### --> + + +<!-- ##### SECTION Long_Description ##### --> +<para> + +</para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### FUNCTION cairo_set_target_drawable ##### --> +<para> + +</para> + +@cr: +@dpy: +@drawable: + + +<!-- ##### FUNCTION cairo_xlib_surface_create ##### --> +<para> + +</para> + +@dpy: +@drawable: +@visual: +@format: +@colormap: +@Returns: + + diff --git a/doc/public/tmpl/cairo.sgml b/doc/public/tmpl/cairo.sgml new file mode 100644 index 000000000..a9e195c73 --- /dev/null +++ b/doc/public/tmpl/cairo.sgml @@ -0,0 +1,1019 @@ +<!-- ##### SECTION Title ##### --> +cairo_t + +<!-- ##### SECTION Short_Description ##### --> +Drawing contexts. + +<!-- ##### SECTION Long_Description ##### --> + + <para> + #cairo_t is the main object used when drawing with Cairo. To + draw with Cairo, you create a #cairo_t, set the target surface, + and drawing options for the #cairo_t, create shapes with + functions like cairo_move_to() and cairo_line_to(), and then + draw ships with cairo_stroke() or cairo_fill(). + </para> + <para> + #cairo_t<!-- -->'s can be pushed to a stack via cairo_save(). + They may then safely be changed, without loosing the current state. + Use cairo_restore() to restore to the saved state. + </para> + +<!-- ##### SECTION See_Also ##### --> +<para> + +</para> + +<!-- ##### TYPEDEF cairo_t ##### --> +<para> + +</para> + + +<!-- ##### FUNCTION cairo_create ##### --> +<para> + +</para> + +@Returns: + + +<!-- ##### FUNCTION cairo_reference ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_destroy ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_save ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_restore ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_copy ##### --> +<para> + +</para> + +@dest: +@src: + + +<!-- ##### FUNCTION cairo_set_target_surface ##### --> +<para> + +</para> + +@cr: +@surface: + + +<!-- ##### ENUM cairo_format_t ##### --> +<para> + +</para> + +@CAIRO_FORMAT_ARGB32: +@CAIRO_FORMAT_RGB24: +@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_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_XOR: +@CAIRO_OPERATOR_ADD: +@CAIRO_OPERATOR_SATURATE: + +<!-- ##### FUNCTION cairo_set_operator ##### --> +<para> + +</para> + +@cr: +@op: + + +<!-- ##### FUNCTION cairo_set_rgb_color ##### --> +<para> + +</para> + +@cr: +@red: +@green: +@blue: + + +<!-- ##### FUNCTION cairo_set_pattern ##### --> +<para> + +</para> + +@cr: +@pattern: + + +<!-- ##### FUNCTION cairo_set_alpha ##### --> +<para> + +</para> + +@cr: +@alpha: + + +<!-- ##### FUNCTION cairo_set_tolerance ##### --> +<para> + +</para> + +@cr: +@tolerance: + + +<!-- ##### ENUM cairo_fill_rule_t ##### --> +<para> + +</para> + +@CAIRO_FILL_RULE_WINDING: +@CAIRO_FILL_RULE_EVEN_ODD: + +<!-- ##### FUNCTION cairo_set_fill_rule ##### --> +<para> + +</para> + +@cr: +@fill_rule: + + +<!-- ##### FUNCTION cairo_set_line_width ##### --> +<para> + +</para> + +@cr: +@width: + + +<!-- ##### ENUM cairo_line_cap_t ##### --> +<para> + +</para> + +@CAIRO_LINE_CAP_BUTT: +@CAIRO_LINE_CAP_ROUND: +@CAIRO_LINE_CAP_SQUARE: + +<!-- ##### FUNCTION cairo_set_line_cap ##### --> +<para> + +</para> + +@cr: +@line_cap: + + +<!-- ##### ENUM cairo_line_join_t ##### --> +<para> + +</para> + +@CAIRO_LINE_JOIN_MITER: +@CAIRO_LINE_JOIN_ROUND: +@CAIRO_LINE_JOIN_BEVEL: + +<!-- ##### FUNCTION cairo_set_line_join ##### --> +<para> + +</para> + +@cr: +@line_join: + + +<!-- ##### FUNCTION cairo_set_dash ##### --> +<para> + +</para> + +@cr: +@dashes: +@ndash: +@offset: + + +<!-- ##### FUNCTION cairo_set_miter_limit ##### --> +<para> + +</para> + +@cr: +@limit: + + +<!-- ##### FUNCTION cairo_translate ##### --> +<para> + +</para> + +@cr: +@tx: +@ty: + + +<!-- ##### FUNCTION cairo_scale ##### --> +<para> + +</para> + +@cr: +@sx: +@sy: + + +<!-- ##### FUNCTION cairo_rotate ##### --> +<para> + +</para> + +@cr: +@angle: + + +<!-- ##### FUNCTION cairo_concat_matrix ##### --> +<para> + +</para> + +@cr: +@matrix: + + +<!-- ##### FUNCTION cairo_set_matrix ##### --> +<para> + +</para> + +@cr: +@matrix: + + +<!-- ##### FUNCTION cairo_default_matrix ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_identity_matrix ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_transform_point ##### --> +<para> + +</para> + +@cr: +@x: +@y: + + +<!-- ##### FUNCTION cairo_transform_distance ##### --> +<para> + +</para> + +@cr: +@dx: +@dy: + + +<!-- ##### FUNCTION cairo_inverse_transform_point ##### --> +<para> + +</para> + +@cr: +@x: +@y: + + +<!-- ##### FUNCTION cairo_inverse_transform_distance ##### --> +<para> + +</para> + +@cr: +@dx: +@dy: + + +<!-- ##### FUNCTION cairo_new_path ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_move_to ##### --> +<para> + +</para> + +@cr: +@x: +@y: + + +<!-- ##### FUNCTION cairo_line_to ##### --> +<para> + +</para> + +@cr: +@x: +@y: + + +<!-- ##### FUNCTION cairo_curve_to ##### --> +<para> + +</para> + +@cr: +@x1: +@y1: +@x2: +@y2: +@x3: +@y3: + + +<!-- ##### FUNCTION cairo_arc ##### --> +<para> + +</para> + +@cr: +@xc: +@yc: +@radius: +@angle1: +@angle2: + + +<!-- ##### FUNCTION cairo_arc_negative ##### --> +<para> + +</para> + +@cr: +@xc: +@yc: +@radius: +@angle1: +@angle2: + + +<!-- ##### FUNCTION cairo_rel_move_to ##### --> +<para> + +</para> + +@cr: +@dx: +@dy: + + +<!-- ##### FUNCTION cairo_rel_line_to ##### --> +<para> + +</para> + +@cr: +@dx: +@dy: + + +<!-- ##### FUNCTION cairo_rel_curve_to ##### --> +<para> + +</para> + +@cr: +@dx1: +@dy1: +@dx2: +@dy2: +@dx3: +@dy3: + + +<!-- ##### FUNCTION cairo_rectangle ##### --> +<para> + +</para> + +@cr: +@x: +@y: +@width: +@height: + + +<!-- ##### FUNCTION cairo_close_path ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_stroke ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_fill ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_copy_page ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_show_page ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_in_stroke ##### --> +<para> + +</para> + +@cr: +@x: +@y: +@Returns: + + +<!-- ##### FUNCTION cairo_in_fill ##### --> +<para> + +</para> + +@cr: +@x: +@y: +@Returns: + + +<!-- ##### TYPEDEF cairo_bool_t ##### --> +<para> + +</para> + + +<!-- ##### FUNCTION cairo_stroke_extents ##### --> +<para> + +</para> + +@cr: +@x1: +@y1: +@x2: +@y2: + + +<!-- ##### FUNCTION cairo_fill_extents ##### --> +<para> + +</para> + +@cr: +@x1: +@y1: +@x2: +@y2: + + +<!-- ##### FUNCTION cairo_init_clip ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### FUNCTION cairo_clip ##### --> +<para> + +</para> + +@cr: + + +<!-- ##### TYPEDEF cairo_font_t ##### --> +<para> + +</para> + + +<!-- ##### STRUCT cairo_glyph_t ##### --> +<para> + +</para> + +@index: +@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> + +</para> + +@CAIRO_FONT_SLANT_NORMAL: +@CAIRO_FONT_SLANT_ITALIC: +@CAIRO_FONT_SLANT_OBLIQUE: + +<!-- ##### ENUM cairo_font_weight_t ##### --> +<para> + +</para> + +@CAIRO_FONT_WEIGHT_NORMAL: +@CAIRO_FONT_WEIGHT_BOLD: + +<!-- ##### FUNCTION cairo_select_font ##### --> +<para> + +</para> + +@cr: +@family: +@slant: +@weight: + + +<!-- ##### FUNCTION cairo_scale_font ##### --> +<para> + +</para> + +@cr: +@scale: + + +<!-- ##### FUNCTION cairo_transform_font ##### --> +<para> + +</para> + +@cr: +@matrix: + + +<!-- ##### FUNCTION cairo_show_text ##### --> +<para> + +</para> + +@cr: +@utf8: + + +<!-- ##### FUNCTION cairo_show_glyphs ##### --> +<para> + +</para> + +@cr: +@glyphs: +@num_glyphs: + + +<!-- ##### FUNCTION cairo_current_font ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_current_font_extents ##### --> +<para> + +</para> + +@cr: +@extents: + + +<!-- ##### FUNCTION cairo_set_font ##### --> +<para> + +</para> + +@cr: +@font: + + +<!-- ##### FUNCTION cairo_text_extents ##### --> +<para> + +</para> + +@cr: +@utf8: +@extents: + + +<!-- ##### FUNCTION cairo_glyph_extents ##### --> +<para> + +</para> + +@cr: +@glyphs: +@num_glyphs: +@extents: + + +<!-- ##### FUNCTION cairo_text_path ##### --> +<para> + +</para> + +@cr: +@utf8: + + +<!-- ##### FUNCTION cairo_glyph_path ##### --> +<para> + +</para> + +@cr: +@glyphs: +@num_glyphs: + + +<!-- ##### FUNCTION cairo_font_reference ##### --> +<para> + +</para> + +@font: + + +<!-- ##### FUNCTION cairo_font_destroy ##### --> +<para> + +</para> + +@font: + + +<!-- ##### FUNCTION cairo_font_glyph_extents ##### --> +<para> + +</para> + +@font: +@font_matrix: +@glyphs: +@num_glyphs: +@extents: + + +<!-- ##### FUNCTION cairo_show_surface ##### --> +<para> + +</para> + +@cr: +@surface: +@width: +@height: + + +<!-- ##### FUNCTION cairo_current_operator ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_current_rgb_color ##### --> +<para> + +</para> + +@cr: +@red: +@green: +@blue: + + +<!-- ##### FUNCTION cairo_current_pattern ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_current_alpha ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_current_tolerance ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_current_point ##### --> +<para> + +</para> + +@cr: +@x: +@y: + + +<!-- ##### FUNCTION cairo_current_fill_rule ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_current_line_width ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_current_line_cap ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_current_line_join ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_current_miter_limit ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_current_matrix ##### --> +<para> + +</para> + +@cr: +@matrix: + + +<!-- ##### FUNCTION cairo_current_target_surface ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_current_path ##### --> +<para> + +</para> + +@cr: +@move_to: +@line_to: +@curve_to: +@close_path: +@closure: + + +<!-- ##### FUNCTION cairo_current_path_flat ##### --> +<para> + +</para> + +@cr: +@move_to: +@line_to: +@close_path: +@closure: + + +<!-- ##### ENUM cairo_status_t ##### --> +<para> + +</para> + +@CAIRO_STATUS_SUCCESS: +@CAIRO_STATUS_NO_MEMORY: +@CAIRO_STATUS_INVALID_RESTORE: +@CAIRO_STATUS_INVALID_POP_GROUP: +@CAIRO_STATUS_NO_CURRENT_POINT: +@CAIRO_STATUS_INVALID_MATRIX: +@CAIRO_STATUS_NO_TARGET_SURFACE: +@CAIRO_STATUS_NULL_POINTER: +@CAIRO_STATUS_INVALID_STRING: + +<!-- ##### FUNCTION cairo_status ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### FUNCTION cairo_status_string ##### --> +<para> + +</para> + +@cr: +@Returns: + + +<!-- ##### ENUM cairo_filter_t ##### --> +<para> + +</para> + +@CAIRO_FILTER_FAST: +@CAIRO_FILTER_GOOD: +@CAIRO_FILTER_BEST: +@CAIRO_FILTER_NEAREST: +@CAIRO_FILTER_BILINEAR: +@CAIRO_FILTER_GAUSSIAN: + +<!-- ##### FUNCTION cairo_image_surface_create ##### --> +<para> + +</para> + +@format: +@width: +@height: +@Returns: + + +<!-- ##### FUNCTION cairo_image_surface_create_for_data ##### --> +<para> + +</para> + +@data: +@format: +@width: +@height: +@stride: +@Returns: + + + +<!-- +Local variables: +mode: sgml +sgml-parent-document: ("../cairo-docs.xml" "book" "refsect2" "") +End: +--> + + diff --git a/doc/reference/.cvsignore b/doc/reference/.cvsignore deleted file mode 100644 index a25ff09ee..000000000 --- a/doc/reference/.cvsignore +++ /dev/null @@ -1,20 +0,0 @@ -Makefile -Makefile.in -aclocal.m4 -autom4te.cache -cairo.pc -config.cache -config.guess -config.h -config.h.in -config.log -config.status -config.sub -configure -libtool -ltmain.sh -stamp-h -stamp-h1 -stamp-h.in -*~ - diff --git a/doc/reference/ChangeLog b/doc/reference/ChangeLog deleted file mode 100644 index 708499b71..000000000 --- a/doc/reference/ChangeLog +++ /dev/null @@ -1,16 +0,0 @@ -2003-10-16 Thomas Hunger <info@teh-web.de> - - * xml/some started to document stuff from top to bottom - -2003-10-16 Thomas Hunger <info@teh-web.de> - - * xml/* changed all files in the xml directory to - look more like gtk. now <link> elements may be - embedded almost everywhere - * added ruby script crossreferences which puts - <link> tags around all known refentries - -2003-10-15 Thomas Hunger <info@teh-web.de> - - * doc.xml: some documentation skeleton - * files for each entry can be found in xml/ diff --git a/doc/reference/README b/doc/reference/README deleted file mode 100644 index 656a76fb4..000000000 --- a/doc/reference/README +++ /dev/null @@ -1,11 +0,0 @@ -How to transform the docs to html: -call -$ xmlto html doc.xml -from within the reference directory - -cross-referecing ----------------- -there is a small ruby script which collects all id="" thingies from the xml files in xml and creates links around the symbols found in files. -exceptions: -- there is already a link around a symbol. -- its part of a function: cairo_translate !=> <link>cairo_t</link>ranslate
\ No newline at end of file diff --git a/doc/reference/crossreference.rb b/doc/reference/crossreference.rb deleted file mode 100644 index 9f7c30350..000000000 --- a/doc/reference/crossreference.rb +++ /dev/null @@ -1,30 +0,0 @@ -d = Dir.glob("xml/*.xml") - -ids = [] - -# collect symbols -d.each do |file| - f = File.new(file) - buf = f.read - ids << buf.scan(/.*id="(.*)".*/) -end -ids = ids.flatten - -#resolve symbols -d.each do |file| - f = File.new(file,"r+") - buf = f.read - p file - ids.each do |id| - if "xml/"+id+".xml" == file - next - end - re = Regexp.compile('([^"\w\d])('+id+')([^"\w\d])') - buf.gsub!(re, '\1<link linkend="\2">\2</link>\3') - buf.gsub!(/(<\/link>)+/, '\1') - buf.gsub!(/(<link[^>]*>)+/, '\1') - end - f.rewind - f.write buf - f.rewind -end diff --git a/doc/reference/doc.xml b/doc/reference/doc.xml deleted file mode 100644 index 1530ec957..000000000 --- a/doc/reference/doc.xml +++ /dev/null @@ -1,204 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" - "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [ -<!ENTITY cairo_create SYSTEM "xml/cairo_create.xml"> -<!ENTITY cairo_reference SYSTEM "xml/cairo_reference.xml"> -<!ENTITY cairo_destroy SYSTEM "xml/cairo_destroy.xml"> -<!ENTITY cairo_save SYSTEM "xml/cairo_save.xml"> -<!ENTITY cairo_restore SYSTEM "xml/cairo_restore.xml"> -<!ENTITY cairo_copy SYSTEM "xml/cairo_copy.xml"> -<!ENTITY cairo_push_group SYSTEM "xml/cairo_push_group.xml"> -<!ENTITY cairo_pop_group SYSTEM "xml/cairo_pop_group.xml"> -<!ENTITY cairo_set_target_surface SYSTEM "xml/cairo_set_target_surface.xml"> -<!ENTITY cairo_set_target_image SYSTEM "xml/cairo_set_target_image.xml"> -<!ENTITY cairo_set_target_ps SYSTEM "xml/cairo_set_target_ps.xml"> -<!ENTITY cairo_set_target_drawable SYSTEM "xml/cairo_set_target_drawable.xml"> -<!ENTITY cairo_set_target_xcb SYSTEM "xml/cairo_set_target_xcb.xml"> -<!ENTITY cairo_set_target_png SYSTEM "xml/cairo_set_target_png.xml"> -<!ENTITY cairo_set_operator SYSTEM "xml/cairo_set_operator.xml"> -<!ENTITY cairo_set_rgb_color SYSTEM "xml/cairo_set_rgb_color.xml"> -<!ENTITY cairo_set_alpha SYSTEM "xml/cairo_set_alpha.xml"> -<!ENTITY cairo_set_pattern SYSTEM "xml/cairo_set_pattern.xml"> -<!ENTITY cairo_set_tolerance SYSTEM "xml/cairo_set_tolerance.xml"> -<!ENTITY cairo_set_fill_rule SYSTEM "xml/cairo_set_fill_rule.xml"> -<!ENTITY cairo_set_line_width SYSTEM "xml/cairo_set_line_width.xml"> -<!ENTITY cairo_set_line_cap SYSTEM "xml/cairo_set_line_cap.xml"> -<!ENTITY cairo_set_line_join SYSTEM "xml/cairo_set_line_join.xml"> -<!ENTITY cairo_set_dash SYSTEM "xml/cairo_set_dash.xml"> -<!ENTITY cairo_set_miter_limit SYSTEM "xml/cairo_set_miter_limit.xml"> -<!ENTITY cairo_translate SYSTEM "xml/cairo_translate.xml"> -<!ENTITY cairo_scale SYSTEM "xml/cairo_scale.xml"> -<!ENTITY cairo_rotate SYSTEM "xml/cairo_rotate.xml"> -<!ENTITY cairo_default_matrix SYSTEM "xml/cairo_default_matrix.xml"> -<!ENTITY cairo_identity_matrix SYSTEM "xml/cairo_identity_matrix.xml"> -<!ENTITY cairo_transform_point SYSTEM "xml/cairo_transform_point.xml"> -<!ENTITY cairo_transform_distance SYSTEM "xml/cairo_transform_distance.xml"> -<!ENTITY cairo_inverse_transform_point SYSTEM "xml/cairo_inverse_transform_point.xml"> -<!ENTITY cairo_inverse_transform_distance SYSTEM "xml/cairo_inverse_transform_distance.xml"> -<!ENTITY cairo_new_path SYSTEM "xml/cairo_new_path.xml"> -<!ENTITY cairo_move_to SYSTEM "xml/cairo_move_to.xml"> -<!ENTITY cairo_line_to SYSTEM "xml/cairo_line_to.xml"> -<!ENTITY cairo_arc SYSTEM "xml/cairo_arc.xml"> -<!ENTITY cairo_arc_negative SYSTEM "xml/cairo_arc_negative.xml"> -<!ENTITY cairo_rel_move_to SYSTEM "xml/cairo_rel_move_to.xml"> -<!ENTITY cairo_rel_line_to SYSTEM "xml/cairo_rel_line_to.xml"> -<!ENTITY cairo_rectangle SYSTEM "xml/cairo_rectangle.xml"> -<!ENTITY cairo_curve_to SYSTEM "xml/cairo_curve_to.xml"> -<!ENTITY cairo_stroke_path SYSTEM "xml/cairo_stroke_path.xml"> -<!ENTITY cairo_close_path SYSTEM "xml/cairo_close_path.xml"> -<!ENTITY cairo_stroke SYSTEM "xml/cairo_stroke.xml"> -<!ENTITY cairo_fill SYSTEM "xml/cairo_fill.xml"> -<!ENTITY cairo_clip SYSTEM "xml/cairo_clip.xml"> -<!ENTITY cairo_select_font SYSTEM "xml/cairo_select_font.xml"> -<!ENTITY cairo_scale_font SYSTEM "xml/cairo_scale_font.xml"> -<!ENTITY cairo_show_text SYSTEM "xml/cairo_show_text.xml"> -<!ENTITY cairo_text_extents SYSTEM "xml/cairo_text_extents.xml"> -<!ENTITY cairo_current_operator SYSTEM "xml/cairo_current_operator.xml"> -<!ENTITY cairo_current_rgb_color SYSTEM "xml/cairo_current_rgb_color.xml"> -<!ENTITY cairo_current_alpha SYSTEM "xml/cairo_current_alpha.xml"> -<!ENTITY cairo_current_tolerance SYSTEM "xml/cairo_current_tolerance.xml"> -<!ENTITY cairo_current_point SYSTEM "xml/cairo_current_point.xml"> -<!ENTITY cairo_current_fill_rule SYSTEM "xml/cairo_current_fill_rule.xml"> -<!ENTITY cairo_current_line_width SYSTEM "xml/cairo_current_line_width.xml"> -<!ENTITY cairo_current_line_cap SYSTEM "xml/cairo_current_line_cap.xml"> -<!ENTITY cairo_current_line_join SYSTEM "xml/cairo_current_line_join.xml"> -<!ENTITY cairo_current_miter_limit SYSTEM "xml/cairo_current_miter_limit.xml"> -<!ENTITY cairo_current_matrix SYSTEM "xml/cairo_current_matrix.xml"> -<!ENTITY cairo_current_target_surface SYSTEM "xml/cairo_current_target_surface.xml"> -<!ENTITY cairo_status SYSTEM "xml/cairo_status.xml"> -<!ENTITY cairo_status_string SYSTEM "xml/cairo_status_string.xml"> -<!ENTITY cairo_surface_reference SYSTEM "xml/cairo_surface_reference.xml"> -<!ENTITY cairo_surface_destroy SYSTEM "xml/cairo_surface_destroy.xml"> -<!ENTITY cairo_surface_clip_restore SYSTEM "xml/cairo_surface_clip_restore.xml"> -<!ENTITY cairo_surface_set_repeat SYSTEM "xml/cairo_surface_set_repeat.xml"> -<!ENTITY cairo_surface_set_matrix SYSTEM "xml/cairo_surface_set_matrix.xml"> -<!ENTITY cairo_surface_get_matrix SYSTEM "xml/cairo_surface_get_matrix.xml"> -<!ENTITY cairo_surface_set_filter SYSTEM "xml/cairo_surface_set_filter.xml"> -<!ENTITY cairo_matrix_create SYSTEM "xml/cairo_matrix_create.xml"> -<!ENTITY cairo_matrix_destroy SYSTEM "xml/cairo_matrix_destroy.xml"> -<!ENTITY cairo_matrix_copy SYSTEM "xml/cairo_matrix_copy.xml"> -<!ENTITY cairo_matrix_set_identity SYSTEM "xml/cairo_matrix_set_identity.xml"> -<!ENTITY cairo_matrix_translate SYSTEM "xml/cairo_matrix_translate.xml"> -<!ENTITY cairo_matrix_scale SYSTEM "xml/cairo_matrix_scale.xml"> -<!ENTITY cairo_matrix_rotate SYSTEM "xml/cairo_matrix_rotate.xml"> -<!ENTITY cairo_matrix_invert SYSTEM "xml/cairo_matrix_invert.xml"> -<!ENTITY cairo_matrix_multiply SYSTEM "xml/cairo_matrix_multiply.xml"> -<!ENTITY cairo_matrix_transform_distance SYSTEM "xml/cairo_matrix_transform_distance.xml"> -<!ENTITY cairo_matrix_transform_point SYSTEM "xml/cairo_matrix_transform_point.xml"> -<!ENTITY cairo_t SYSTEM "xml/cairo_t.xml"> -<!ENTITY cairo_matrix_t SYSTEM "xml/cairo_matrix_t.xml"> -<!ENTITY cairo_surface_t SYSTEM "xml/cairo_surface_t.xml"> -<!ENTITY cairo_format_t SYSTEM "xml/cairo_format_t.xml"> -<!ENTITY cairo_operator_t SYSTEM "xml/cairo_operator_t.xml"> -<!ENTITY cairo_fill_rule_t SYSTEM "xml/cairo_fill_rule_t.xml"> -<!ENTITY cairo_line_cap_t SYSTEM "xml/cairo_line_cap_t.xml"> -<!ENTITY cairo_text_extents_t SYSTEM "xml/cairo_text_extents_t.xml"> -]> -<book lang="en"> -<title>Cairo: A Vector Graphics Library</title> - - -<reference> -<title>functions</title> -&cairo_create; -&cairo_reference; -&cairo_destroy; -&cairo_save; -&cairo_restore; -&cairo_copy; -&cairo_push_group; -&cairo_pop_group; -&cairo_set_target_surface; -&cairo_set_target_image; -&cairo_set_target_ps; -&cairo_set_target_png; -&cairo_set_target_drawable; -&cairo_set_target_xcb; -&cairo_set_operator; -&cairo_set_rgb_color; -&cairo_set_alpha; -&cairo_set_pattern; -&cairo_set_tolerance; -&cairo_set_fill_rule; -&cairo_set_line_width; -&cairo_set_line_cap; -&cairo_set_line_join; -&cairo_set_dash; -&cairo_set_miter_limit; -&cairo_translate; -&cairo_scale; -&cairo_rotate; -&cairo_default_matrix; -&cairo_identity_matrix; -&cairo_transform_point; -&cairo_transform_distance; -&cairo_inverse_transform_point; -&cairo_inverse_transform_distance; -&cairo_new_path; -&cairo_move_to; -&cairo_line_to; -&cairo_arc; -&cairo_arc_negative; -&cairo_rel_move_to; -&cairo_rel_line_to; -&cairo_rectangle; -&cairo_curve_to; -&cairo_stroke_path; -&cairo_close_path; -&cairo_stroke; -&cairo_fill; -&cairo_clip; -&cairo_select_font; -&cairo_scale_font; -&cairo_show_text; -&cairo_text_extents; -&cairo_current_operator; -&cairo_current_rgb_color; -&cairo_current_alpha; -&cairo_current_tolerance; -&cairo_current_point; -&cairo_current_fill_rule; -&cairo_current_line_width; -&cairo_current_line_cap; -&cairo_current_line_join; -&cairo_current_miter_limit; -&cairo_current_matrix; -&cairo_current_target_surface; -&cairo_status; -&cairo_status_string; -&cairo_surface_reference; -&cairo_surface_destroy; -&cairo_surface_clip_restore; -&cairo_surface_set_repeat; -&cairo_surface_set_matrix; -&cairo_surface_get_matrix; -&cairo_surface_set_filter; -&cairo_matrix_create; -&cairo_matrix_destroy; -&cairo_matrix_copy; -&cairo_matrix_set_identity; -&cairo_matrix_translate; -&cairo_matrix_scale; -&cairo_matrix_rotate; -&cairo_matrix_invert; -&cairo_matrix_multiply; -&cairo_matrix_transform_distance; -&cairo_matrix_transform_point; -</reference> -<reference> -<title>types and enums</title> -&cairo_t; -&cairo_matrix_t; -&cairo_surface_t; -&cairo_format_t; -&cairo_operator_t; -&cairo_fill_rule_t; -&cairo_line_cap_t; -&cairo_text_extents_t; -</reference> -</book> - - - - - diff --git a/doc/reference/xml/cairo_arc.xml b/doc/reference/xml/cairo_arc.xml deleted file mode 100644 index b8a391f9d..000000000 --- a/doc/reference/xml/cairo_arc.xml +++ /dev/null @@ -1,40 +0,0 @@ -<refentry id="cairo_arc"> - <refmeta> - <refentrytitle>cairo_arc</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_arc</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> - void cairo_arc (<link linkend="cairo_t">cairo_t</link> *cr, double xc, double yc, double radius, double angle1, double angle2);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>xc, yc</parameter> :</term> - <listitem> - <simpara>center of arc (a full arc makes a circle)</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_arc</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_arc_negative.xml b/doc/reference/xml/cairo_arc_negative.xml deleted file mode 100644 index ece1af7f5..000000000 --- a/doc/reference/xml/cairo_arc_negative.xml +++ /dev/null @@ -1,40 +0,0 @@ -<refentry id="cairo_arc_negative"> - <refmeta> - <refentrytitle>cairo_arc_negative</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_arc_negative</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> - void cairo_arc_negative (<link linkend="cairo_t">cairo_t</link> *cr, double xc, double yc, double radius, double angle1, double angle2);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>xc, yc</parameter> :</term> - <listitem> - <simpara>center of the arc</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_arc_negative</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_clip.xml b/doc/reference/xml/cairo_clip.xml deleted file mode 100644 index c1f165306..000000000 --- a/doc/reference/xml/cairo_clip.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_clip"> - <refmeta> - <refentrytitle>cairo_clip</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_clip</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_clip (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_clip</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_close_path.xml b/doc/reference/xml/cairo_close_path.xml deleted file mode 100644 index d610c0eee..000000000 --- a/doc/reference/xml/cairo_close_path.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_close_path"> - <refmeta> - <refentrytitle>cairo_close_path</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_close_path</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_close_path (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_close_path</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_copy.xml b/doc/reference/xml/cairo_copy.xml deleted file mode 100644 index f9d6537da..000000000 --- a/doc/reference/xml/cairo_copy.xml +++ /dev/null @@ -1,54 +0,0 @@ -<refentry id="cairo_copy"> - <refmeta> - <refentrytitle>cairo_copy</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_copy</refname> - <refpurpose>copy contents from one <link linkend="cairo_t">cairo_t</link> to another</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_copy (<link linkend="cairo_t">cairo_t</link> *dest, <link linkend="cairo_t">cairo_t</link> *src)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>dest</parameter> :</term> - <listitem> - <simpara>an allocated <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>src</parameter> :</term> - <listitem> - <simpara><link linkend="cairo_t">cairo_t</link> to copy</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_copy</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - This function copies all state information from src to dest. That includes not yet drawn paths and font information. - </para> - <para> -The new <link linkend="cairo_t">cairo_t</link> will become owner of the target and clip surfaces by incrementing their refcount. But the surfaces will not be copied, that means operations on either src or dest will be painted onto the same surface. - </para> - <para> - Note that saved states on the stack can only be restored once. So if you have unclosed calls to <link linkend="cairo_save">cairo_save</link> before copying, calling <link linkend="cairo_restore">cairo_restore</link> on both, src and dest is invalid. - </para> - </refsect1> - <refsect1> - <title>See also</title> - <para> - cairo_clone - </para> - </refsect1> - -</refentry> diff --git a/doc/reference/xml/cairo_create.xml b/doc/reference/xml/cairo_create.xml deleted file mode 100644 index eb1c530aa..000000000 --- a/doc/reference/xml/cairo_create.xml +++ /dev/null @@ -1,34 +0,0 @@ -<refentry id="cairo_create"> - <refmeta> - <refentrytitle>cairo_create</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_create</refname> - <refpurpose>create a new <link linkend="cairo_t">cairo_t</link> object</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting><link linkend="cairo_t">cairo_t</link> * cairo_create (void)</programlisting> - <variablelist role="params"> - <varlistentry> - <term/> - <listitem> - <simpara>this takes no arguments</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_create</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - This function creates a new <link linkend="cairo_t">cairo_t</link> with a reference count of one. Call <link linkend="cairo_destroy">cairo_destroy</link> to free the allocated resources. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_alpha.xml b/doc/reference/xml/cairo_current_alpha.xml deleted file mode 100644 index 9aae8e166..000000000 --- a/doc/reference/xml/cairo_current_alpha.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_current_alpha"> - <refmeta> - <refentrytitle>cairo_current_alpha</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_alpha</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -double cairo_current_alpha (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_alpha</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_fill_rule.xml b/doc/reference/xml/cairo_current_fill_rule.xml deleted file mode 100644 index 3902c7acb..000000000 --- a/doc/reference/xml/cairo_current_fill_rule.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_current_fill_rule"> - <refmeta> - <refentrytitle>cairo_current_fill_rule</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_fill_rule</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -<link linkend="cairo_fill_rule_t">cairo_fill_rule_t</link> cairo_current_fill_rule (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_fill_rule</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_font.xml b/doc/reference/xml/cairo_current_font.xml deleted file mode 100644 index 3503b6db7..000000000 --- a/doc/reference/xml/cairo_current_font.xml +++ /dev/null @@ -1,37 +0,0 @@ - -<refentry id="cairo_current_font"> - <refmeta> - <refentrytitle>cairo_current_font</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_font</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> - cairo_font_t * - cairo_current_font (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_font</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - returns pointer to the current cairo_font_t object in the <link linkend="cairo_t">cairo_t</link> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_font_extents.xml b/doc/reference/xml/cairo_current_font_extents.xml deleted file mode 100644 index 822cd4049..000000000 --- a/doc/reference/xml/cairo_current_font_extents.xml +++ /dev/null @@ -1,40 +0,0 @@ -<refentry id="cairo_current_font_extents"> - <refmeta> - <refentrytitle>cairo_current_font_extents</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_font_extents</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_current_font_extents (<link linkend="cairo_t">cairo_t</link> *cr, cairo_font_extents_t *extents)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>extents</parameter> :</term> - <listitem> - <simpara>fills in a provided cairo_font_extents_t object</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_font_extents</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_line_cap.xml b/doc/reference/xml/cairo_current_line_cap.xml deleted file mode 100644 index 4b01c4db7..000000000 --- a/doc/reference/xml/cairo_current_line_cap.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_current_line_cap"> - <refmeta> - <refentrytitle>cairo_current_line_cap</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_line_cap</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -<link linkend="cairo_line_cap_t">cairo_line_cap_t</link> cairo_current_line_cap (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_line_cap</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_line_join.xml b/doc/reference/xml/cairo_current_line_join.xml deleted file mode 100644 index 58571aba8..000000000 --- a/doc/reference/xml/cairo_current_line_join.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_current_line_join"> - <refmeta> - <refentrytitle>cairo_current_line_join</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_line_join</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_line_join_t cairo_current_line_join (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_line_join</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_line_width.xml b/doc/reference/xml/cairo_current_line_width.xml deleted file mode 100644 index f2af35f8f..000000000 --- a/doc/reference/xml/cairo_current_line_width.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_current_line_width"> - <refmeta> - <refentrytitle>cairo_current_line_width</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_line_width</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -double cairo_current_line_width (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_line_width</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_matrix.xml b/doc/reference/xml/cairo_current_matrix.xml deleted file mode 100644 index 03f435227..000000000 --- a/doc/reference/xml/cairo_current_matrix.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_current_matrix"> - <refmeta> - <refentrytitle>cairo_current_matrix</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_matrix</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_current_matrix (<link linkend="cairo_t">cairo_t</link> *cr, <link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_matrix</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_miter_limit.xml b/doc/reference/xml/cairo_current_miter_limit.xml deleted file mode 100644 index fa0403ddb..000000000 --- a/doc/reference/xml/cairo_current_miter_limit.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_current_miter_limit"> - <refmeta> - <refentrytitle>cairo_current_miter_limit</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_miter_limit</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -double cairo_current_miter_limit (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_miter_limit</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_operator.xml b/doc/reference/xml/cairo_current_operator.xml deleted file mode 100644 index 166717300..000000000 --- a/doc/reference/xml/cairo_current_operator.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_current_operator"> - <refmeta> - <refentrytitle>cairo_current_operator</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_operator</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -<link linkend="cairo_operator_t">cairo_operator_t</link> cairo_current_operator (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_operator</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_point.xml b/doc/reference/xml/cairo_current_point.xml deleted file mode 100644 index a865bf1e5..000000000 --- a/doc/reference/xml/cairo_current_point.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_current_point"> - <refmeta> - <refentrytitle>cairo_current_point</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_point</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_current_point (<link linkend="cairo_t">cairo_t</link> *cr, double *x, double *y)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>x</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>y</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_point</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_rgb_color.xml b/doc/reference/xml/cairo_current_rgb_color.xml deleted file mode 100644 index a1a8bbcac..000000000 --- a/doc/reference/xml/cairo_current_rgb_color.xml +++ /dev/null @@ -1,53 +0,0 @@ - -<refentry id="cairo_current_rgb_color"> - <refmeta> - <refentrytitle>cairo_current_rgb_color</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_rgb_color</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_current_rgb_color (<link linkend="cairo_t">cairo_t</link> *cr, double *red, double *green, double *blue)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>red</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>green</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>blue</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_rgb_color</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_target_surface.xml b/doc/reference/xml/cairo_current_target_surface.xml deleted file mode 100644 index 60d0263b6..000000000 --- a/doc/reference/xml/cairo_current_target_surface.xml +++ /dev/null @@ -1,34 +0,0 @@ - -<refentry id="cairo_current_target_surface"> - <refmeta> - <refentrytitle>cairo_current_target_surface</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_target_surface</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting><link linkend="cairo_surface_t">cairo_surface_t</link> * cairo_current_target_surface (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_target_surface</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_current_tolerance.xml b/doc/reference/xml/cairo_current_tolerance.xml deleted file mode 100644 index bfc24151c..000000000 --- a/doc/reference/xml/cairo_current_tolerance.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_current_tolerance"> - <refmeta> - <refentrytitle>cairo_current_tolerance</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_current_tolerance</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -double cairo_current_tolerance (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_current_tolerance</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_curve_to.xml b/doc/reference/xml/cairo_curve_to.xml deleted file mode 100644 index 330ed3629..000000000 --- a/doc/reference/xml/cairo_curve_to.xml +++ /dev/null @@ -1,70 +0,0 @@ -<refentry id="cairo_curve_to"> - <refmeta> - <refentrytitle>cairo_curve_to</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_curve_to</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> - void cairo_curve_to (<link linkend="cairo_t">cairo_t</link> *cr, double x1, double y1, double x2, double y2, double x3, double y3);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>x1</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>y1</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>x2</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>y2</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>x3</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>y3</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_curve_to</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_default_matrix.xml b/doc/reference/xml/cairo_default_matrix.xml deleted file mode 100644 index 182ca01a3..000000000 --- a/doc/reference/xml/cairo_default_matrix.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_default_matrix"> - <refmeta> - <refentrytitle>cairo_default_matrix</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_default_matrix</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_default_matrix (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_default_matrix</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_destroy.xml b/doc/reference/xml/cairo_destroy.xml deleted file mode 100644 index 0f55239fa..000000000 --- a/doc/reference/xml/cairo_destroy.xml +++ /dev/null @@ -1,38 +0,0 @@ -<refentry id="cairo_destroy"> - <refmeta> - <refentrytitle>cairo_destroy</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_destroy</refname> - <refpurpose>free a <link linkend="cairo_t">cairo_t</link></refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_destroy (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_destroy</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - Decreases the reference of a a <link linkend="cairo_t">cairo_t</link>. If the refcount drops to zero, all associated resources will be freed. - </para> - <para> - Saved states on the stack which were not restored with <link linkend="cairo_restore">cairo_restore</link> will be destroyed, too. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_fill.xml b/doc/reference/xml/cairo_fill.xml deleted file mode 100644 index e890ab1b1..000000000 --- a/doc/reference/xml/cairo_fill.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_fill"> - <refmeta> - <refentrytitle>cairo_fill</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_fill</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_fill (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_fill</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_fill_rule_t.xml b/doc/reference/xml/cairo_fill_rule_t.xml deleted file mode 100644 index 9f1fbe3ee..000000000 --- a/doc/reference/xml/cairo_fill_rule_t.xml +++ /dev/null @@ -1,40 +0,0 @@ -<refentry id="cairo_fill_rule_t"> - <refmeta> - <refentrytitle>cairo_fill_rule_t</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - - <refnamediv> - <refname>cairo_fill_rule_t</refname> - <refpurpose>enumeration for fill rules</refpurpose> - </refnamediv> - - <refsect1> - <title>Description</title> - <indexterm><primary>enums</primary> - <secondary>cairo_fill_rule_t</secondary></indexterm> -<programlisting>typedef enum cairo_fill_rule { - CAIRO_FILL_RULE_WINDING, - CAIRO_FILL_RULE_EVEN_ODD -} cairo_fill_rule_t; -</programlisting> -<para> -Select ways to fill paths. -</para> -<variablelist role="enum"> -<varlistentry> -<term><literal>CAIRO_FILL_RULE_WINDING</literal></term> -<listitem><simpara>counts all intersections with a clockwise line positive and intersections with a counter-clockwise line negative. All areas with a non-zero counts are filled. -</simpara></listitem> -</varlistentry> -<varlistentry> -<term><literal>CAIRO_FILL_RULE_EVEN_ODD</literal></term> -<listitem><simpara>Only the area from one intersection to the next will be filled, no matter what orientation the intersected line has. -</simpara></listitem> -</varlistentry> -</variablelist> - </refsect1> -</refentry> - - - diff --git a/doc/reference/xml/cairo_format_t.xml b/doc/reference/xml/cairo_format_t.xml deleted file mode 100644 index e80c18a94..000000000 --- a/doc/reference/xml/cairo_format_t.xml +++ /dev/null @@ -1,52 +0,0 @@ -<refentry id="cairo_format_t"> - <refmeta> - <refentrytitle>cairo_format_t</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - - <refnamediv> - <refname>cairo_format_t</refname> - <refpurpose>enumeration for image formats</refpurpose> - </refnamediv> - - <refsect1> - <title>Description</title> - <indexterm><primary>enums</primary> - <secondary>cairo_format_t</secondary></indexterm> -<programlisting>typedef enum cairo_format { - CAIRO_FORMAT_ARGB32 = PictStandardARGB32, - CAIRO_FORMAT_RGB24 = PictStandardRGB24, - CAIRO_FORMAT_A8 = PictStandardA8, - CAIRO_FORMAT_A1 = PictStandardA1 -} cairo_format_t; -</programlisting> -<para> -Possible formats for in-memory images. -</para> -<variablelist role="enum"> -<varlistentry> -<term><literal>CAIRO_FORMAT_ARGB32</literal></term> -<listitem><simpara>one byte for red, green, blue and alpha. (rowstride = width * 4) -</simpara></listitem> -</varlistentry> -<varlistentry> -<term><literal>CAIRO_FORMAT_RGB24</literal></term> -<listitem><simpara>one byte for red, green and blue (rowstride = width * 4) -</simpara></listitem> -</varlistentry> -<varlistentry> -<term><literal>CAIRO_FORMAT_A8</literal></term> -<listitem><simpara>indexed color image -</simpara></listitem> -</varlistentry> -<varlistentry> -<term><literal>CAIRO_FORMAT_A1</literal></term> -<listitem><simpara>a bitmap -</simpara></listitem> -</varlistentry> -</variablelist> - </refsect1> -</refentry> - - - diff --git a/doc/reference/xml/cairo_hit.xml b/doc/reference/xml/cairo_hit.xml deleted file mode 100644 index 3d834586a..000000000 --- a/doc/reference/xml/cairo_hit.xml +++ /dev/null @@ -1,36 +0,0 @@ - -<refentry id="cairo_hit"> - <refmeta> - <refentrytitle>cairo_hit</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_hit</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <funcsynopsis> - <funcsynopsisinfo> -</funcsynopsisinfo> - <funcprototype> - <funcdef>int <function>cairo_hit</function></funcdef> - <paramdef> - <link linkend="cairo_t">cairo_t</link> - <parameter>*cr</parameter> - </paramdef> - </funcprototype> - </funcsynopsis> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_hit</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_identity_matrix.xml b/doc/reference/xml/cairo_identity_matrix.xml deleted file mode 100644 index 23dafad9e..000000000 --- a/doc/reference/xml/cairo_identity_matrix.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_identity_matrix"> - <refmeta> - <refentrytitle>cairo_identity_matrix</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_identity_matrix</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_identity_matrix (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_identity_matrix</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_in_fill.xml b/doc/reference/xml/cairo_in_fill.xml deleted file mode 100644 index df78c484a..000000000 --- a/doc/reference/xml/cairo_in_fill.xml +++ /dev/null @@ -1,34 +0,0 @@ -<refentry id="cairo_in_fill"> -<refmeta> -<refentrytitle>cairo_in_fill</refentrytitle> -<manvolnum>3</manvolnum> -</refmeta> - -<refnamediv> -<refname>cairo_in_fill</refname> -<refpurpose>some description</refpurpose> -</refnamediv> - - -<refsynopsisdiv> -<funcsynopsis> -<funcsynopsisinfo> -</funcsynopsisinfo> -<funcprototype> - <funcdef>void <function>cairo_in_fill</function></funcdef><paramdef><link linkend="cairo_t">cairo_t</link> <parameter>*cr</parameter></paramdef> -<paramdef>double <parameter>x</parameter></paramdef> -<paramdef>double <parameter>y</parameter></paramdef> -</funcprototype> -</funcsynopsis> -</refsynopsisdiv> - -<refsect1> - <title>Description</title> - <para> - <indexterm><primary>functions</primary> - <secondary>cairo_in_fill</secondary></indexterm> - <indexterm><primary></primary></indexterm> - </para> - </refsect1> -</refentry> - diff --git a/doc/reference/xml/cairo_in_stroke.xml b/doc/reference/xml/cairo_in_stroke.xml deleted file mode 100644 index 77c9d6c34..000000000 --- a/doc/reference/xml/cairo_in_stroke.xml +++ /dev/null @@ -1,34 +0,0 @@ -<refentry id="cairo_in_stroke"> -<refmeta> -<refentrytitle>cairo_in_stroke</refentrytitle> -<manvolnum>3</manvolnum> -</refmeta> - -<refnamediv> -<refname>cairo_in_stroke</refname> -<refpurpose>some description</refpurpose> -</refnamediv> - - -<refsynopsisdiv> -<funcsynopsis> -<funcsynopsisinfo> -</funcsynopsisinfo> -<funcprototype> - <funcdef>void <function>cairo_in_stroke</function></funcdef><paramdef><link linkend="cairo_t">cairo_t</link> <parameter>*cr</parameter></paramdef> -<paramdef>double <parameter>x</parameter></paramdef> -<paramdef>double <parameter>y</parameter></paramdef> -</funcprototype> -</funcsynopsis> -</refsynopsisdiv> - -<refsect1> - <title>Description</title> - <para> - <indexterm><primary>functions</primary> - <secondary>cairo_in_stroke</secondary></indexterm> - <indexterm><primary></primary></indexterm> - </para> - </refsect1> -</refentry> - diff --git a/doc/reference/xml/cairo_inverse_transform_distance.xml b/doc/reference/xml/cairo_inverse_transform_distance.xml deleted file mode 100644 index a525fdc0e..000000000 --- a/doc/reference/xml/cairo_inverse_transform_distance.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_inverse_transform_distance"> - <refmeta> - <refentrytitle>cairo_inverse_transform_distance</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_inverse_transform_distance</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_inverse_transform_distance (<link linkend="cairo_t">cairo_t</link> *cr, double *dx, double *dy)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dx</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dy</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_inverse_transform_distance</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_inverse_transform_point.xml b/doc/reference/xml/cairo_inverse_transform_point.xml deleted file mode 100644 index 7100a92bd..000000000 --- a/doc/reference/xml/cairo_inverse_transform_point.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_inverse_transform_point"> - <refmeta> - <refentrytitle>cairo_inverse_transform_point</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_inverse_transform_point</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_inverse_transform_point (<link linkend="cairo_t">cairo_t</link> *cr, double *x, double *y)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>x</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>y</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_inverse_transform_point</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_line_cap_t.xml b/doc/reference/xml/cairo_line_cap_t.xml deleted file mode 100644 index 9f1ee028a..000000000 --- a/doc/reference/xml/cairo_line_cap_t.xml +++ /dev/null @@ -1,43 +0,0 @@ -<refentry id="cairo_line_cap_t"> - <refmeta> - <refentrytitle>cairo_line_cap_t</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - - <refnamediv> - <refname>cairo_line_cap_t</refname> - <refpurpose>enumeration for style of line-endings</refpurpose> - </refnamediv> - - <refsect1> - <title>Description</title> - <indexterm><primary>enums</primary> - <secondary>cairo_line_cap_t</secondary></indexterm> -<programlisting>typedef enum cairo_line_cap { - CAIRO_LINE_CAP_BUTT, - CAIRO_LINE_CAP_ROUND, - CAIRO_LINE_CAP_SQUARE -} cairo_line_cap_t; -</programlisting> -<variablelist role="enum"> -<varlistentry> -<term><literal>CAIRO_LINE_CAP_BUTT</literal></term> -<listitem><simpara>start(stop) the line exactly at the start(end) point -</simpara></listitem> -</varlistentry> -<varlistentry> -<term><literal>CAIRO_LINE_CAP_ROUND</literal></term> -<listitem><simpara>use a round ending, the center of the circle is the end point. -</simpara></listitem> -</varlistentry> -<varlistentry> -<term><literal>CAIRO_LINE_CAP_SQUARE</literal></term> -<listitem><simpara>use squared ending, the center of the square is the end point. -</simpara></listitem> -</varlistentry> -</variablelist> - </refsect1> -</refentry> - - - diff --git a/doc/reference/xml/cairo_line_to.xml b/doc/reference/xml/cairo_line_to.xml deleted file mode 100644 index 7cc226dad..000000000 --- a/doc/reference/xml/cairo_line_to.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_line_to"> - <refmeta> - <refentrytitle>cairo_line_to</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_line_to</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_line_to (<link linkend="cairo_t">cairo_t</link> *cr, double x, double y)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>x</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>y</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_line_to</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_copy.xml b/doc/reference/xml/cairo_matrix_copy.xml deleted file mode 100644 index a7da42078..000000000 --- a/doc/reference/xml/cairo_matrix_copy.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_matrix_copy"> - <refmeta> - <refentrytitle>cairo_matrix_copy</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix_copy</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_matrix_copy (<link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix, const <link linkend="cairo_matrix_t">cairo_matrix_t</link> *other)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>other</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_matrix_copy</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_create.xml b/doc/reference/xml/cairo_matrix_create.xml deleted file mode 100644 index b3351c8a9..000000000 --- a/doc/reference/xml/cairo_matrix_create.xml +++ /dev/null @@ -1,34 +0,0 @@ - -<refentry id="cairo_matrix_create"> - <refmeta> - <refentrytitle>cairo_matrix_create</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix_create</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting><link linkend="cairo_matrix_t">cairo_matrix_t</link> * cairo_matrix_create (void)</programlisting> - <variablelist role="params"> - <varlistentry> - <term/> - <listitem> - <simpara>this takes no arguments</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_matrix_create</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_destroy.xml b/doc/reference/xml/cairo_matrix_destroy.xml deleted file mode 100644 index 24cb7d385..000000000 --- a/doc/reference/xml/cairo_matrix_destroy.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_matrix_destroy"> - <refmeta> - <refentrytitle>cairo_matrix_destroy</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix_destroy</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_matrix_destroy (<link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_matrix_destroy</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_invert.xml b/doc/reference/xml/cairo_matrix_invert.xml deleted file mode 100644 index 3786b24a7..000000000 --- a/doc/reference/xml/cairo_matrix_invert.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_matrix_invert"> - <refmeta> - <refentrytitle>cairo_matrix_invert</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix_invert</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_matrix_invert (<link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_matrix_invert</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_multiply.xml b/doc/reference/xml/cairo_matrix_multiply.xml deleted file mode 100644 index 55d2a71ad..000000000 --- a/doc/reference/xml/cairo_matrix_multiply.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_matrix_multiply"> - <refmeta> - <refentrytitle>cairo_matrix_multiply</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix_multiply</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_matrix_multiply (<link linkend="cairo_matrix_t">cairo_matrix_t</link> *result, const <link linkend="cairo_matrix_t">cairo_matrix_t</link> *a, const <link linkend="cairo_matrix_t">cairo_matrix_t</link> *b)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>result</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>a</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>b</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_matrix_multiply</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_rotate.xml b/doc/reference/xml/cairo_matrix_rotate.xml deleted file mode 100644 index 1f9005125..000000000 --- a/doc/reference/xml/cairo_matrix_rotate.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_matrix_rotate"> - <refmeta> - <refentrytitle>cairo_matrix_rotate</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix_rotate</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_matrix_rotate (<link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix, double radians)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>radians</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_matrix_rotate</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_scale.xml b/doc/reference/xml/cairo_matrix_scale.xml deleted file mode 100644 index 183ef6d55..000000000 --- a/doc/reference/xml/cairo_matrix_scale.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_matrix_scale"> - <refmeta> - <refentrytitle>cairo_matrix_scale</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix_scale</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_matrix_scale (<link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix, double sx, double sy)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>sx</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>sy</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_matrix_scale</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_set_identity.xml b/doc/reference/xml/cairo_matrix_set_identity.xml deleted file mode 100644 index 449de6d4f..000000000 --- a/doc/reference/xml/cairo_matrix_set_identity.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_matrix_set_identity"> - <refmeta> - <refentrytitle>cairo_matrix_set_identity</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix_set_identity</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_matrix_set_identity (<link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_matrix_set_identity</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_t.xml b/doc/reference/xml/cairo_matrix_t.xml deleted file mode 100644 index 67632ac18..000000000 --- a/doc/reference/xml/cairo_matrix_t.xml +++ /dev/null @@ -1,23 +0,0 @@ - -<refentry id="cairo_matrix_t"> - <refmeta> - <refentrytitle>cairo_matrix</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix</refname> - <refpurpose>a matrix</refpurpose> - </refnamediv> - <refsect1> - <title>Description</title> - <para><indexterm><primary>types</primary><secondary>cairo_matrix</secondary></indexterm><indexterm><primary/></indexterm> - A <varname>cairo_matrix</varname> contains the current state of the rendering device, - including coordinates of yet to be drawn shapes. - <varname>cairo_matrix</varname>'s can be pushed to a stack via - <link linkend="cairo_save">cairo_save</link>. - They may then savely be changed, without loosing the current state. - Use <link linkend="cairo_restore">cairo_restore</link> to - restore to the saved state. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_transform_distance.xml b/doc/reference/xml/cairo_matrix_transform_distance.xml deleted file mode 100644 index a1a558078..000000000 --- a/doc/reference/xml/cairo_matrix_transform_distance.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_matrix_transform_distance"> - <refmeta> - <refentrytitle>cairo_matrix_transform_distance</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix_transform_distance</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_matrix_transform_distance (<link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix, double *dx, double *dy)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dx</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dy</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_matrix_transform_distance</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_transform_point.xml b/doc/reference/xml/cairo_matrix_transform_point.xml deleted file mode 100644 index 2b0e12b59..000000000 --- a/doc/reference/xml/cairo_matrix_transform_point.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_matrix_transform_point"> - <refmeta> - <refentrytitle>cairo_matrix_transform_point</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix_transform_point</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_matrix_transform_point (<link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix, double *x, double *y)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>x</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>y</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_matrix_transform_point</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_matrix_translate.xml b/doc/reference/xml/cairo_matrix_translate.xml deleted file mode 100644 index 9800569ca..000000000 --- a/doc/reference/xml/cairo_matrix_translate.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_matrix_translate"> - <refmeta> - <refentrytitle>cairo_matrix_translate</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_matrix_translate</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_matrix_translate (<link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix, double tx, double ty)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>tx</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>ty</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_matrix_translate</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_move_to.xml b/doc/reference/xml/cairo_move_to.xml deleted file mode 100644 index dc8118f87..000000000 --- a/doc/reference/xml/cairo_move_to.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_move_to"> - <refmeta> - <refentrytitle>cairo_move_to</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_move_to</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_move_to (<link linkend="cairo_t">cairo_t</link> *cr, double x, double y)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>x</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>y</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_move_to</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_new_path.xml b/doc/reference/xml/cairo_new_path.xml deleted file mode 100644 index 680d7f937..000000000 --- a/doc/reference/xml/cairo_new_path.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_new_path"> - <refmeta> - <refentrytitle>cairo_new_path</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_new_path</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_new_path (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_new_path</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_operator_t.xml b/doc/reference/xml/cairo_operator_t.xml deleted file mode 100644 index b659bb9b2..000000000 --- a/doc/reference/xml/cairo_operator_t.xml +++ /dev/null @@ -1,47 +0,0 @@ -<refentry id="cairo_operator_t"> - <refmeta> - <refentrytitle>cairo_operator_t</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - - <refnamediv> - <refname>cairo_operator_t</refname> - <refpurpose>enumeration for image operators</refpurpose> - </refnamediv> - - <refsect1> - <title>Description</title> - <indexterm><primary>enums</primary> - <secondary>cairo_operator_t</secondary></indexterm> -<programlisting>typedef enum cairo_operator { - CAIRO_OPERATOR_CLEAR, - CAIRO_OPERATOR_SRC, - CAIRO_OPERATOR_DST, - 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_XOR, - CAIRO_OPERATOR_ADD, - CAIRO_OPERATOR_SATURATE -} cairo_operator_t; -</programlisting> -<para> -Operators for surface-compositing. XXX -</para> -<variablelist role="enum"> -<varlistentry> -<term><literal></literal></term> -<listitem><simpara> -</simpara></listitem> -</varlistentry> -</variablelist> - </refsect1> -</refentry> - - - diff --git a/doc/reference/xml/cairo_pop_group.xml b/doc/reference/xml/cairo_pop_group.xml deleted file mode 100644 index 9adc0ad62..000000000 --- a/doc/reference/xml/cairo_pop_group.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_pop_group"> - <refmeta> - <refentrytitle>cairo_pop_group</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_pop_group</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_pop_group (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_pop_group</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_push_group.xml b/doc/reference/xml/cairo_push_group.xml deleted file mode 100644 index 9d252cc72..000000000 --- a/doc/reference/xml/cairo_push_group.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_push_group"> - <refmeta> - <refentrytitle>cairo_push_group</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_push_group</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_push_group (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_push_group</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_rectangle.xml b/doc/reference/xml/cairo_rectangle.xml deleted file mode 100644 index bab307f32..000000000 --- a/doc/reference/xml/cairo_rectangle.xml +++ /dev/null @@ -1,47 +0,0 @@ -<refentry id="cairo_rectangle"> - <refmeta> - <refentrytitle>cairo_rectangle</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_rectangle</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> - void cairo_rectangle (<link linkend="cairo_t">cairo_t</link> *cr, double x, double y, double width, double height);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>x, y</parameter> :</term> - <listitem> - <simpara>coordinates of the left top corner</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>width, height</parameter> :</term> - <listitem> - <simpara>width and height of the rectangle</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_rectangle</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - The current line style applies to the lines of the rectangle. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_reference.xml b/doc/reference/xml/cairo_reference.xml deleted file mode 100644 index 21725adbd..000000000 --- a/doc/reference/xml/cairo_reference.xml +++ /dev/null @@ -1,35 +0,0 @@ -<refentry id="cairo_reference"> - <refmeta> - <refentrytitle>cairo_reference</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_reference</refname> - <refpurpose>increase reference count of <link linkend="cairo_t">cairo_t</link></refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_reference (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_reference</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - When calling <function>cairo_reference</function> the reference count will be increased by one and the caller becomes owner of the <link linkend="cairo_t">cairo_t</link>. When the creator of the <link linkend="cairo_t">cairo_t</link> destroys the the object via <link linkend="cairo_destroy">cairo_destroy</link> the refcount will be decreased but the object will stay valid, since you are still owner of the object. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_rel_curve_to.xml b/doc/reference/xml/cairo_rel_curve_to.xml deleted file mode 100644 index c16f85ff2..000000000 --- a/doc/reference/xml/cairo_rel_curve_to.xml +++ /dev/null @@ -1,70 +0,0 @@ -<refentry id="cairo_curve_to"> - <refmeta> - <refentrytitle><link linkend="cairo_curve_to">cairo_curve_to</link></refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname><link linkend="cairo_curve_to">cairo_curve_to</link></refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> - void <link linkend="cairo_curve_to">cairo_curve_to</link> (<link linkend="cairo_t">cairo_t</link> *cr, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dx1</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dy1</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dx2</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dy2</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dx3</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dy3</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary><link linkend="cairo_curve_to">cairo_curve_to</link></secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_rel_line_to.xml b/doc/reference/xml/cairo_rel_line_to.xml deleted file mode 100644 index 208cb4d33..000000000 --- a/doc/reference/xml/cairo_rel_line_to.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_rel_line_to"> - <refmeta> - <refentrytitle>cairo_rel_line_to</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_rel_line_to</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_rel_line_to (<link linkend="cairo_t">cairo_t</link> *cr, double dx, double dy)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dx</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dy</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_rel_line_to</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_rel_move_to.xml b/doc/reference/xml/cairo_rel_move_to.xml deleted file mode 100644 index 2468536b9..000000000 --- a/doc/reference/xml/cairo_rel_move_to.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_rel_move_to"> - <refmeta> - <refentrytitle>cairo_rel_move_to</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_rel_move_to</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_rel_move_to (<link linkend="cairo_t">cairo_t</link> *cr, double dx, double dy)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dx</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dy</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_rel_move_to</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_restore.xml b/doc/reference/xml/cairo_restore.xml deleted file mode 100644 index ed2411a52..000000000 --- a/doc/reference/xml/cairo_restore.xml +++ /dev/null @@ -1,36 +0,0 @@ - -<refentry id="cairo_restore"> - <refmeta> - <refentrytitle>cairo_restore</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_restore</refname> - <refpurpose>restore a saved state</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_restore (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_restore</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - This fucntion is the counterpart to <link linkend="cairo_save">cairo_save</link>. A saved state can be restored with cairo_restore. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_rotate.xml b/doc/reference/xml/cairo_rotate.xml deleted file mode 100644 index 6effd5648..000000000 --- a/doc/reference/xml/cairo_rotate.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_rotate"> - <refmeta> - <refentrytitle>cairo_rotate</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_rotate</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_rotate (<link linkend="cairo_t">cairo_t</link> *cr, double angle)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>angle</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_rotate</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_save.xml b/doc/reference/xml/cairo_save.xml deleted file mode 100644 index fc2a4e04e..000000000 --- a/doc/reference/xml/cairo_save.xml +++ /dev/null @@ -1,36 +0,0 @@ - -<refentry id="cairo_save"> - <refmeta> - <refentrytitle>cairo_save</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_save</refname> - <refpurpose>save current state</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_save (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_save</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - This function stores the complete state of a <link linkend="cairo_t">cairo_t</link>. It may then be changed in any way. The saved state can then be restored with <link linkend="cairo_restore">cairo_restore</link>. Calls to cairo_save may be nested to an arbitraty depth. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_scale.xml b/doc/reference/xml/cairo_scale.xml deleted file mode 100644 index eccd8af80..000000000 --- a/doc/reference/xml/cairo_scale.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_scale"> - <refmeta> - <refentrytitle>cairo_scale</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_scale</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_scale (<link linkend="cairo_t">cairo_t</link> *cr, double sx, double sy)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>sx</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>sy</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_scale</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_scale_font.xml b/doc/reference/xml/cairo_scale_font.xml deleted file mode 100644 index 170df09b0..000000000 --- a/doc/reference/xml/cairo_scale_font.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_scale_font"> - <refmeta> - <refentrytitle>cairo_scale_font</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_scale_font</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_scale_font (<link linkend="cairo_t">cairo_t</link> *cr, double scale)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>scale</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_scale_font</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_select_font.xml b/doc/reference/xml/cairo_select_font.xml deleted file mode 100644 index 36bd782f8..000000000 --- a/doc/reference/xml/cairo_select_font.xml +++ /dev/null @@ -1,53 +0,0 @@ - -<refentry id="cairo_select_font"> - <refmeta> - <refentrytitle>cairo_select_font</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_select_font</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_select_font (<link linkend="cairo_t">cairo_t</link> *cr, const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>family</parameter> :</term> - <listitem> - <simpara>name for the font family (e.g. XXX)</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>slant</parameter> :</term> - <listitem> - <simpara>see cairo_font_slant_t for valid values</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>weight</parameter> :</term> - <listitem> - <simpara>see cairo_font_weight_t for valid values</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_select_font</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_alpha.xml b/doc/reference/xml/cairo_set_alpha.xml deleted file mode 100644 index e996c33bf..000000000 --- a/doc/reference/xml/cairo_set_alpha.xml +++ /dev/null @@ -1,42 +0,0 @@ - -<refentry id="cairo_set_alpha"> - <refmeta> - <refentrytitle>cairo_set_alpha</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_alpha</refname> - <refpurpose>set opaqueness for painting</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_alpha (<link linkend="cairo_t">cairo_t</link> *cr, double alpha)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a cairo_r</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>alpha</parameter> :</term> - <listitem> - <simpara>an alpha value between 0.0 and 1.0</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_alpha</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - If alpha is not between 0.0 and 1.0 it will be restricted to fit. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_dash.xml b/doc/reference/xml/cairo_set_dash.xml deleted file mode 100644 index 50d1b37ff..000000000 --- a/doc/reference/xml/cairo_set_dash.xml +++ /dev/null @@ -1,53 +0,0 @@ - -<refentry id="cairo_set_dash"> - <refmeta> - <refentrytitle>cairo_set_dash</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_dash</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_dash (<link linkend="cairo_t">cairo_t</link> *cr, double *dashes, int ndash, double offset)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dashes</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>ndash</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>offset</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_dash</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_fill_rule.xml b/doc/reference/xml/cairo_set_fill_rule.xml deleted file mode 100644 index 64bd9b51c..000000000 --- a/doc/reference/xml/cairo_set_fill_rule.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_set_fill_rule"> - <refmeta> - <refentrytitle>cairo_set_fill_rule</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_fill_rule</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_fill_rule (<link linkend="cairo_t">cairo_t</link> *cr, <link linkend="cairo_fill_rule_t">cairo_fill_rule_t</link> fill_rule)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>fill_rule</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_fill_rule</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_font.xml b/doc/reference/xml/cairo_set_font.xml deleted file mode 100644 index 31661494e..000000000 --- a/doc/reference/xml/cairo_set_font.xml +++ /dev/null @@ -1,40 +0,0 @@ -<refentry id="cairo_set_font"> - <refmeta> - <refentrytitle>cairo_set_font</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_font</refname> - <refpurpose>replace the font in the current state</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_font (<link linkend="cairo_t">cairo_t</link> *cr, cairo_font_t *font)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>font</parameter> :</term> - <listitem> - <simpara>replaces the current cairo_font_t object in the <link linkend="cairo_t">cairo_t</link> with font. The replaced font in the <link linkend="cairo_t">cairo_t</link> will be destroyed if there are no other references to it.</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_font</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_line_cap.xml b/doc/reference/xml/cairo_set_line_cap.xml deleted file mode 100644 index 9b346b782..000000000 --- a/doc/reference/xml/cairo_set_line_cap.xml +++ /dev/null @@ -1,41 +0,0 @@ -<refentry id="cairo_set_line_cap"> - <refmeta> - <refentrytitle>cairo_set_line_cap</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_line_cap</refname> - <refpurpose>determine shape of line endings</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_line_cap (<link linkend="cairo_t">cairo_t</link> *cr, <link linkend="cairo_line_cap_t">cairo_line_cap_t</link> line_cap)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>line_cap</parameter> :</term> - <listitem> - <simpara>see <link linkend="cairo_line_cap_t">cairo_line_cap_t</link> for styles</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_line_cap</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - When the line width is larger than one device unit, it matters which way the ending of a line is drawn. Use this function to set the line-ending-style. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_line_join.xml b/doc/reference/xml/cairo_set_line_join.xml deleted file mode 100644 index 28e5b6956..000000000 --- a/doc/reference/xml/cairo_set_line_join.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_set_line_join"> - <refmeta> - <refentrytitle>cairo_set_line_join</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_line_join</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_line_join (<link linkend="cairo_t">cairo_t</link> *cr, cairo_line_join_t line_join)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>line_join</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_line_join</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_line_width.xml b/doc/reference/xml/cairo_set_line_width.xml deleted file mode 100644 index 033a426c1..000000000 --- a/doc/reference/xml/cairo_set_line_width.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_set_line_width"> - <refmeta> - <refentrytitle>cairo_set_line_width</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_line_width</refname> - <refpurpose>set line width in device units</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_line_width (<link linkend="cairo_t">cairo_t</link> *cr, double width)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>width</parameter> :</term> - <listitem> - <simpara>width in device units</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_line_width</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_miter_limit.xml b/doc/reference/xml/cairo_set_miter_limit.xml deleted file mode 100644 index e86c14227..000000000 --- a/doc/reference/xml/cairo_set_miter_limit.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_set_miter_limit"> - <refmeta> - <refentrytitle>cairo_set_miter_limit</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_miter_limit</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_miter_limit (<link linkend="cairo_t">cairo_t</link> *cr, double limit)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>limit</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_miter_limit</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_operator.xml b/doc/reference/xml/cairo_set_operator.xml deleted file mode 100644 index 0bde0b1b5..000000000 --- a/doc/reference/xml/cairo_set_operator.xml +++ /dev/null @@ -1,42 +0,0 @@ - -<refentry id="cairo_set_operator"> - <refmeta> - <refentrytitle>cairo_set_operator</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_operator</refname> - <refpurpose>select operator for surface compositing</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_operator (<link linkend="cairo_t">cairo_t</link> *cr, <link linkend="cairo_operator_t">cairo_operator_t</link> op)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>op</parameter> :</term> - <listitem> - <simpara>the operator for subsequent compositing operations</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_operator</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_pattern.xml b/doc/reference/xml/cairo_set_pattern.xml deleted file mode 100644 index 14d0678df..000000000 --- a/doc/reference/xml/cairo_set_pattern.xml +++ /dev/null @@ -1,41 +0,0 @@ -<refentry id="cairo_set_pattern"> - <refmeta> - <refentrytitle>cairo_set_pattern</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_pattern</refname> - <refpurpose>select a surface as fill pattern</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_pattern (<link linkend="cairo_t">cairo_t</link> *cr, <link linkend="cairo_surface_t">cairo_surface_t</link> *pattern)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>pattern</parameter> :</term> - <listitem> - <simpara>a surface</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_pattern</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - This function selects <varname>pattern</varname> as pattern for fill operations. If the repeat flag is set via <link linkend="cairo_surface_set_repeat">cairo_surface_set_repeat</link>, the pattern will be tiled, otherwise just drawn once. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_rgb_color.xml b/doc/reference/xml/cairo_set_rgb_color.xml deleted file mode 100644 index 24db26a63..000000000 --- a/doc/reference/xml/cairo_set_rgb_color.xml +++ /dev/null @@ -1,54 +0,0 @@ - -<refentry id="cairo_set_rgb_color"> - <refmeta> - <refentrytitle>cairo_set_rgb_color</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_rgb_color</refname> - <refpurpose>select color for painting operations</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_rgb_color (<link linkend="cairo_t">cairo_t</link> *cr, double red, double green, double blue)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>red</parameter> :</term> - <listitem> - <simpara>red component</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>green</parameter> :</term> - <listitem> - <simpara>green component</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>blue</parameter> :</term> - <listitem> - <simpara>blue component</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_rgb_color</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - Set the color for subsequent drawing operations. Values which are not between 0.0 and 1.0 will be changed (e.g. red=2.0 => red=1.0). - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_target_drawable.xml b/doc/reference/xml/cairo_set_target_drawable.xml deleted file mode 100644 index febabb554..000000000 --- a/doc/reference/xml/cairo_set_target_drawable.xml +++ /dev/null @@ -1,45 +0,0 @@ -<refentry id="cairo_set_target_drawable"> - <refmeta> - <refentrytitle>cairo_set_target_drawable</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_target_drawable</refname> - <refpurpose>set surface for painting operations </refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting>void cairo_set_target_drawable (<link linkend="cairo_t">cairo_t</link> *cr, Display *dpy, Drawable drawable);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dpy</parameter> :</term> - <listitem> - <simpara>X Display</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>drawable</parameter> :</term> - <listitem> - <simpara>an X onscreen or offscreen drawable</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_target_drawable</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_target_image.xml b/doc/reference/xml/cairo_set_target_image.xml deleted file mode 100644 index b96a5fbdc..000000000 --- a/doc/reference/xml/cairo_set_target_image.xml +++ /dev/null @@ -1,58 +0,0 @@ -<refentry id="cairo_set_target_image"> - <refmeta> - <refentrytitle>cairo_set_target_image</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_target_image</refname> - <refpurpose>set image for painting operations </refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_target_image (<link linkend="cairo_t">cairo_t</link> *cr,char *data, <link linkend="cairo_format_t">cairo_format_t</link> format, int width, int height, int stride)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>data</parameter> :</term> - <listitem> - <simpara>pointer to an user-allocated buffer of appropriate size</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>format</parameter> :</term> - <listitem> - <simpara>select color-format of image</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>width, height</parameter></term> - <listitem> - <simpara>width and height describe the visibles image size.</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>stride</parameter></term> - <listitem> - <simpara>stride is the actual with of the image and can be larger than with. It is requiered even if stride is equal to with.</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_target_image</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_target_png.xml b/doc/reference/xml/cairo_set_target_png.xml deleted file mode 100644 index 8577fa160..000000000 --- a/doc/reference/xml/cairo_set_target_png.xml +++ /dev/null @@ -1,51 +0,0 @@ -<refentry id="cairo_set_target_png"> - <refmeta> - <refentrytitle>cairo_set_target_png</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_target_png</refname> - <refpurpose>set surface for painting operations </refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting>void cairo_set_target_png (<link linkend="cairo_t">cairo_t</link> *cr, FILE *file, <link linkend="cairo_format_t">cairo_format_t</link> format, int width, int height);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>FILE</parameter> :</term> - <listitem> - <simpara>an open, writeable file</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter><link linkend="cairo_format_t">cairo_format_t</link></parameter> :</term> - <listitem> - <simpara>determines the color-depth of the resulting png image</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>width, height</parameter> :</term> - <listitem> - <simpara>sets width and height of resulting png image </simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_target_png</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_target_ps.xml b/doc/reference/xml/cairo_set_target_ps.xml deleted file mode 100644 index b1211a9d8..000000000 --- a/doc/reference/xml/cairo_set_target_ps.xml +++ /dev/null @@ -1,52 +0,0 @@ -<refentry id="cairo_set_target_ps"> - <refmeta> - <refentrytitle>cairo_set_target_ps</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_target_ps</refname> - <refpurpose>set surface for painting operations </refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_target_ps (<link linkend="cairo_t">cairo_t</link> *cr,FILE *file, double width_inches, double height_inches, double x_pixels_per_inch, double y_pixels_per_inch);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>FILE</parameter> :</term> - <listitem> - <simpara>an open, writeable file</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>width_inches, height_inches</parameter> :</term> - <listitem> - <simpara>width and height of an output page in inches</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>x_pixels_per_inch, y_pixels_per_inch</parameter> :</term> - <listitem> - <simpara>Resolution of the postscript file. Right now cairo dumps an entire image on every page, so this parameters define the resolution of the resulting image.</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_target_ps</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_target_surface.xml b/doc/reference/xml/cairo_set_target_surface.xml deleted file mode 100644 index 473df3fe9..000000000 --- a/doc/reference/xml/cairo_set_target_surface.xml +++ /dev/null @@ -1,41 +0,0 @@ -<refentry id="cairo_set_target_surface"> - <refmeta> - <refentrytitle>cairo_set_target_surface</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_target_surface</refname> - <refpurpose>set surface for painting operations </refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_target_surface (<link linkend="cairo_t">cairo_t</link> *cr, <link linkend="cairo_surface_t">cairo_surface_t</link> *surface)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>surface</parameter> :</term> - <listitem> - <simpara>an allocated <link linkend="cairo_surface_t">cairo_surface_t</link></simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_target_surface</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> -Selects <varname>surface</varname> as the surface to draw on. If there already is a surface set, it will be substituted by <varname>surface</varname>. It references <varname>surface</varname>e to ensure that it will be valid at least until another surface was selected or the <link linkend="cairo_t">cairo_t</link> is destroyed. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_target_xcb.xml b/doc/reference/xml/cairo_set_target_xcb.xml deleted file mode 100644 index d7bd2b05f..000000000 --- a/doc/reference/xml/cairo_set_target_xcb.xml +++ /dev/null @@ -1,58 +0,0 @@ -<refentry id="cairo_set_target_xcb"> - <refmeta> - <refentrytitle>cairo_set_target_xcb</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_target_xcb</refname> - <refpurpose>set surface for painting operations </refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting>void -cairo_set_target_xcb (<link linkend="cairo_t">cairo_t</link> *cr, XCBConnection *dpy, DRAWABLE drawable, VISUALTYPE *visual, <link linkend="cairo_format_t">cairo_format_t</link> format);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dpy</parameter> :</term> - <listitem> - <simpara>...</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>drawable</parameter> :</term> - <listitem> - <simpara>an X onscreen or offscreen drawable</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>visual</parameter> :</term> - <listitem> - <simpara>...</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>format</parameter> :</term> - <listitem> - <simpara>...</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_target_xcb</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_set_tolerance.xml b/doc/reference/xml/cairo_set_tolerance.xml deleted file mode 100644 index 2ab257c0a..000000000 --- a/doc/reference/xml/cairo_set_tolerance.xml +++ /dev/null @@ -1,41 +0,0 @@ -<refentry id="cairo_set_tolerance"> - <refmeta> - <refentrytitle>cairo_set_tolerance</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_set_tolerance</refname> - <refpurpose>set accuracy of painting operations</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_set_tolerance (<link linkend="cairo_t">cairo_t</link> *cr, double tolerance)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>tolerance</parameter> :</term> - <listitem> - <simpara>the accuracy in device pixels</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_set_tolerance</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - This function adjusts the error tolerance for tesselating curved objects. The default value is 0.1 (device pixels). This function can be used to trade speed against accuracy. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_show_glyphs.xml b/doc/reference/xml/cairo_show_glyphs.xml deleted file mode 100644 index aab0de1de..000000000 --- a/doc/reference/xml/cairo_show_glyphs.xml +++ /dev/null @@ -1,46 +0,0 @@ -<refentry id="cairo_show_glyphs"> - <refmeta> - <refentrytitle>cairo_show_glyphs</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_show_glyphs</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_show_glyphs (<link linkend="cairo_t">cairo_t</link> *cr, cairo_glyph_t *glyphs, int num_glyphs);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>glyphs</parameter> :</term> - <listitem> - <simpara></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>num_glyphs</parameter> :</term> - <listitem> - <simpara></simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_show_glyphs</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_show_text.xml b/doc/reference/xml/cairo_show_text.xml deleted file mode 100644 index db16c9704..000000000 --- a/doc/reference/xml/cairo_show_text.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_show_text"> - <refmeta> - <refentrytitle>cairo_show_text</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_show_text</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_show_text (<link linkend="cairo_t">cairo_t</link> *cr, const unsigned char *utf8)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>utf8</parameter> :</term> - <listitem> - <simpara>text to show</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_show_text</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_status.xml b/doc/reference/xml/cairo_status.xml deleted file mode 100644 index bb5b890e5..000000000 --- a/doc/reference/xml/cairo_status.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_status"> - <refmeta> - <refentrytitle>cairo_status</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_status</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_status (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_status</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_status_string.xml b/doc/reference/xml/cairo_status_string.xml deleted file mode 100644 index 17e6efeef..000000000 --- a/doc/reference/xml/cairo_status_string.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_status_string"> - <refmeta> - <refentrytitle>cairo_status_string</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_status_string</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -const char * cairo_status_string (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_status_string</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_stroke.xml b/doc/reference/xml/cairo_stroke.xml deleted file mode 100644 index 0d9e270c0..000000000 --- a/doc/reference/xml/cairo_stroke.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_stroke"> - <refmeta> - <refentrytitle>cairo_stroke</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_stroke</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_stroke (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_stroke</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_stroke_path.xml b/doc/reference/xml/cairo_stroke_path.xml deleted file mode 100644 index 1003b1d0c..000000000 --- a/doc/reference/xml/cairo_stroke_path.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_stroke_path"> - <refmeta> - <refentrytitle>cairo_stroke_path</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_stroke_path</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_stroke_path (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_stroke_path</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_surface_clip_restore.xml b/doc/reference/xml/cairo_surface_clip_restore.xml deleted file mode 100644 index eb5b4d8e1..000000000 --- a/doc/reference/xml/cairo_surface_clip_restore.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_surface_clip_restore"> - <refmeta> - <refentrytitle>cairo_surface_clip_restore</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_surface_clip_restore</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_surface_clip_restore (<link linkend="cairo_surface_t">cairo_surface_t</link> *surface)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>surface</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_surface_clip_restore</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_surface_destroy.xml b/doc/reference/xml/cairo_surface_destroy.xml deleted file mode 100644 index 4d788f2fd..000000000 --- a/doc/reference/xml/cairo_surface_destroy.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_surface_destroy"> - <refmeta> - <refentrytitle>cairo_surface_destroy</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_surface_destroy</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_surface_destroy (<link linkend="cairo_surface_t">cairo_surface_t</link> *surface)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>surface</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_surface_destroy</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_surface_get_matrix.xml b/doc/reference/xml/cairo_surface_get_matrix.xml deleted file mode 100644 index 6a8dd4cc0..000000000 --- a/doc/reference/xml/cairo_surface_get_matrix.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_surface_get_matrix"> - <refmeta> - <refentrytitle>cairo_surface_get_matrix</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_surface_get_matrix</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_surface_get_matrix (<link linkend="cairo_surface_t">cairo_surface_t</link> *surface, <link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>surface</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_surface_get_matrix</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_surface_reference.xml b/doc/reference/xml/cairo_surface_reference.xml deleted file mode 100644 index 1767830d9..000000000 --- a/doc/reference/xml/cairo_surface_reference.xml +++ /dev/null @@ -1,35 +0,0 @@ - -<refentry id="cairo_surface_reference"> - <refmeta> - <refentrytitle>cairo_surface_reference</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_surface_reference</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_surface_reference (<link linkend="cairo_surface_t">cairo_surface_t</link> *surface)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>surface</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_surface_reference</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_surface_set_filter.xml b/doc/reference/xml/cairo_surface_set_filter.xml deleted file mode 100644 index 399cca19b..000000000 --- a/doc/reference/xml/cairo_surface_set_filter.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_surface_set_filter"> - <refmeta> - <refentrytitle>cairo_surface_set_filter</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_surface_set_filter</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_surface_set_filter (<link linkend="cairo_surface_t">cairo_surface_t</link> *surface, cairo_filter_t filter)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>surface</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>filter</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_surface_set_filter</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_surface_set_matrix.xml b/doc/reference/xml/cairo_surface_set_matrix.xml deleted file mode 100644 index 83e466a4b..000000000 --- a/doc/reference/xml/cairo_surface_set_matrix.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_surface_set_matrix"> - <refmeta> - <refentrytitle>cairo_surface_set_matrix</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_surface_set_matrix</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_surface_set_matrix (<link linkend="cairo_surface_t">cairo_surface_t</link> *surface, <link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>surface</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_surface_set_matrix</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_surface_set_repeat.xml b/doc/reference/xml/cairo_surface_set_repeat.xml deleted file mode 100644 index d64be4795..000000000 --- a/doc/reference/xml/cairo_surface_set_repeat.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_surface_set_repeat"> - <refmeta> - <refentrytitle>cairo_surface_set_repeat</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_surface_set_repeat</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -cairo_status_t cairo_surface_set_repeat (<link linkend="cairo_surface_t">cairo_surface_t</link> *surface, int repeat)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>surface</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>repeat</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_surface_set_repeat</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_surface_t.xml b/doc/reference/xml/cairo_surface_t.xml deleted file mode 100644 index aa5b9d80e..000000000 --- a/doc/reference/xml/cairo_surface_t.xml +++ /dev/null @@ -1,17 +0,0 @@ - -<refentry id="cairo_surface_t"> - <refmeta> - <refentrytitle>cairo_surface_t</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_surface_t</refname> - <refpurpose>surface to draw on</refpurpose> - </refnamediv> - <refsect1> - <title>Description</title> - <para><indexterm><primary>types</primary><secondary>cairo_surface_t</secondary></indexterm><indexterm><primary/></indexterm> - A <varname>cairo_surface_t</varname> is a high level wrapper for varoius surface. So far the surface can be a bitmap or a memory image. It also contains information about the width and height, repeating information (in case it is used as a pattern: <link linkend="cairo_surface_set_repeat">cairo_surface_set_repeat</link>), the quality for rescaling (<link linkend="cairo_surface_set_filter">cairo_surface_set_filter</link>), and transformations. Surfaces support reference counting via <link linkend="cairo_surface_reference">cairo_surface_reference</link> and <link linkend="cairo_surface_destroy">cairo_surface_destroy</link>. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_t.xml b/doc/reference/xml/cairo_t.xml deleted file mode 100644 index 5adb628a5..000000000 --- a/doc/reference/xml/cairo_t.xml +++ /dev/null @@ -1,23 +0,0 @@ - -<refentry id="cairo_t"> - <refmeta> - <refentrytitle>cairo_t</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_t</refname> - <refpurpose>holds the current state</refpurpose> - </refnamediv> - <refsect1> - <title>Description</title> - <para><indexterm><primary>types</primary><secondary>cairo_t</secondary></indexterm><indexterm><primary/></indexterm> - A <varname>cairo_t</varname> contains the current state of the rendering device, - including coordinates of yet to be drawn shapes. - <varname>cairo_t</varname>'s can be pushed to a stack via - <link linkend="cairo_save">cairo_save</link>. - They may then savely be changed, without loosing the current state. - Use <link linkend="cairo_restore">cairo_restore</link> to - restore to the saved state. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_text_extents.xml b/doc/reference/xml/cairo_text_extents.xml deleted file mode 100644 index fcb359304..000000000 --- a/doc/reference/xml/cairo_text_extents.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_text_extents"> - <refmeta> - <refentrytitle>cairo_text_extents</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_text_extents</refname> - <refpurpose>determine extents of a utf8 string</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting>void cairo_text_extents (<link linkend="cairo_t">cairo_t</link> *ct, const unsigned char *utf8, <link linkend="cairo_text_extents_t">cairo_text_extents_t</link> *extents);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>utf8</parameter> :</term> - <listitem> - <simpara>utf8 encoded string</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>extents</parameter> :</term> - <listitem> - <simpara>a <link linkend="cairo_text_extents_t">cairo_text_extents_t</link> structure</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_text_extents</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_text_extents_t.xml b/doc/reference/xml/cairo_text_extents_t.xml deleted file mode 100644 index 80e8534d5..000000000 --- a/doc/reference/xml/cairo_text_extents_t.xml +++ /dev/null @@ -1,29 +0,0 @@ - -<refentry id="cairo_text_extents_t"> - <refmeta> - <refentrytitle>cairo_text_extents_t</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_text_extents_t</refname> - <refpurpose>struct to store extents of a string</refpurpose> - </refnamediv> - <refsect1> - <title>Description</title> - <para><indexterm><primary>types</primary><secondary>cairo_text_extents_t</secondary></indexterm><indexterm><primary/></indexterm> - <programlisting> - typedef struct { - double x_bearing; - double y_bearing; - double width; - double height; - double x_advance; - double y_advance; - } cairo_text_extents_t; - </programlisting> - </para> - <para> - XXX. not sure what the status is right know. - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_transform_distance.xml b/doc/reference/xml/cairo_transform_distance.xml deleted file mode 100644 index 5f348f5fb..000000000 --- a/doc/reference/xml/cairo_transform_distance.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_transform_distance"> - <refmeta> - <refentrytitle>cairo_transform_distance</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_transform_distance</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_transform_distance (<link linkend="cairo_t">cairo_t</link> *cr, double *dx, double *dy)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dx</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>dy</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_transform_distance</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_transform_font.xml b/doc/reference/xml/cairo_transform_font.xml deleted file mode 100644 index d348d9b54..000000000 --- a/doc/reference/xml/cairo_transform_font.xml +++ /dev/null @@ -1,41 +0,0 @@ - -<refentry id="cairo_transform_font"> - <refmeta> - <refentrytitle>cairo_transform_font</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_transform_font</refname> - <refpurpose>set transformation matrix for individual glyphs</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> - void cairo_transform_font (<link linkend="cairo_t">cairo_t</link> *cr, <link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix);</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>matrix</parameter> :</term> - <listitem> - <simpara>an affine transformation matrix</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_transform_font</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_transform_point.xml b/doc/reference/xml/cairo_transform_point.xml deleted file mode 100644 index 3c369696f..000000000 --- a/doc/reference/xml/cairo_transform_point.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_transform_point"> - <refmeta> - <refentrytitle>cairo_transform_point</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_transform_point</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_transform_point (<link linkend="cairo_t">cairo_t</link> *cr, double *x, double *y)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>x</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>y</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_transform_point</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/cairo_translate.xml b/doc/reference/xml/cairo_translate.xml deleted file mode 100644 index cb8c54c43..000000000 --- a/doc/reference/xml/cairo_translate.xml +++ /dev/null @@ -1,47 +0,0 @@ - -<refentry id="cairo_translate"> - <refmeta> - <refentrytitle>cairo_translate</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - <refnamediv> - <refname>cairo_translate</refname> - <refpurpose>some description</refpurpose> - </refnamediv> - <refsynopsisdiv> - <programlisting> -void cairo_translate (<link linkend="cairo_t">cairo_t</link> *cr, double tx, double ty)</programlisting> - <variablelist role="params"> - <varlistentry> - <term><parameter>cr</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>tx</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - <varlistentry> - <term><parameter>ty</parameter> :</term> - <listitem> - <simpara>description</simpara> - </listitem> - </varlistentry> - </variablelist> - </refsynopsisdiv> - <refsect1> - <title>Description</title> - <para> - <indexterm> - <primary>functions</primary> - <secondary>cairo_translate</secondary> - </indexterm> - <indexterm> - <primary/> - </indexterm> - </para> - </refsect1> -</refentry> diff --git a/doc/reference/xml/skeleton.xml b/doc/reference/xml/skeleton.xml deleted file mode 100644 index 66a1923b7..000000000 --- a/doc/reference/xml/skeleton.xml +++ /dev/null @@ -1,30 +0,0 @@ -<refentry id="##function##"> - -<refnamediv> -<refname><link linkend="##function##">##function##</link></refname> -<refpurpose></refpurpose> -</refnamediv> - -<refsynopsisdiv> -<funcsynopsis> -<funcsynopsisinfo> -#include <cairo.h> -</funcsynopsisinfo> -<funcprototype> - <funcdef><link linkend="cairo_t">cairo_t</link> *<function><link linkend="##function##">##function##</link></function></funcdef> - <paramdef> - </paramdef> -</funcprototype> -</funcsynopsis> -</refsynopsisdiv> - -<refsect1><title>Description</title> -<para> -<indexterm><primary>functions</primary> - <secondary></secondary></indexterm> -<indexterm><primary></primary></indexterm> - -<function><link linkend="##function##">##function##</link></function> -</para> -</refsect1> -</refentry> diff --git a/gtk-doc.make b/gtk-doc.make new file mode 100644 index 000000000..18c60c2d7 --- /dev/null +++ b/gtk-doc.make @@ -0,0 +1,163 @@ +# +# *** NOTE *** this file is checked into CVS for convenience only. +# DO NOT EDIT. Rather get changes into upstream gtk-doc and then +# update this version from the gtk-doc version. +# + +# -*- mode: makefile -*- + +#################################### +# Everything below here is generic # +#################################### + +if GTK_DOC_USE_LIBTOOL +GTKDOC_CC = $(LIBTOOL) --mode=compile $(CC) $(INCLUDES) $(AM_CFLAGS) $(CFLAGS) +GTKDOC_LD = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) +else +GTKDOC_CC = $(CC) $(INCLUDES) $(AM_CFLAGS) $(CFLAGS) +GTKDOC_LD = $(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) +endif + +# We set GPATH here; this gives us semantics for GNU make +# which are more like other make's VPATH, when it comes to +# whether a source that is a target of one rule is then +# searched for in VPATH/GPATH. +# +GPATH = $(srcdir) + +TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE) + +EXTRA_DIST = \ + $(content_files) \ + $(HTML_IMAGES) \ + $(DOC_MAIN_SGML_FILE) \ + $(DOC_MODULE).types \ + $(DOC_MODULE)-sections.txt \ + $(DOC_MODULE)-overrides.txt + +DOC_STAMPS=scan-build.stamp tmpl-build.stamp sgml-build.stamp html-build.stamp \ + $(srcdir)/tmpl.stamp $(srcdir)/sgml.stamp $(srcdir)/html.stamp + +SCANOBJ_FILES = \ + $(DOC_MODULE).args \ + $(DOC_MODULE).hierarchy \ + $(DOC_MODULE).interfaces \ + $(DOC_MODULE).prerequisites \ + $(DOC_MODULE).signals + +CLEANFILES = $(SCANOBJ_FILES) $(DOC_MODULE)-unused.txt $(DOC_STAMPS) + +if ENABLE_GTK_DOC +all-local: html-build.stamp + +#### scan #### + +scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB) + @echo '*** Scanning header files ***' + @-chmod -R u+w $(srcdir) + if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null ; then \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" gtkdoc-scangobj $(SCANGOBJ_OPTIONS) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \ + else \ + cd $(srcdir) ; \ + for i in $(SCANOBJ_FILES) ; do \ + test -f $$i || touch $$i ; \ + done \ + fi + cd $(srcdir) && \ + gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES) + touch scan-build.stamp + +$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp + @true + +#### templates #### + +tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt + @echo '*** Rebuilding template files ***' + @-chmod -R u+w $(srcdir) + cd $(srcdir) && gtkdoc-mktmpl --module=$(DOC_MODULE) + touch tmpl-build.stamp + +tmpl.stamp: tmpl-build.stamp + @true + +#### xml #### + +sgml-build.stamp: tmpl.stamp $(CFILE_GLOB) $(srcdir)/tmpl/*.sgml + @echo '*** Building XML ***' + @-chmod -R u+w $(srcdir) + cd $(srcdir) && \ + gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --output-format=xml $(MKDB_OPTIONS) + touch sgml-build.stamp + +sgml.stamp: sgml-build.stamp + @true + +#### html #### + +html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) + @echo '*** Building HTML ***' + @-chmod -R u+w $(srcdir) + rm -rf $(srcdir)/html + mkdir $(srcdir)/html + cd $(srcdir)/html && gtkdoc-mkhtml $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE) + test "x$(HTML_IMAGES)" = "x" || ( cd $(srcdir) && cp $(HTML_IMAGES) html ) + @echo '-- Fixing Crossreferences' + cd $(srcdir) && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + touch html-build.stamp +else +all-local: +endif + +############## + +clean-local: + rm -f *~ *.bak + rm -rf .libs + +maintainer-clean-local: clean + cd $(srcdir) && rm -rf xml html $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt + +install-data-local: + installfiles=`echo $(srcdir)/html/*`; \ + if test "$$installfiles" = '$(srcdir)/html/*'; \ + then echo '-- Nothing to install' ; \ + else \ + $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR); \ + for i in $$installfiles; do \ + echo '-- Installing '$$i ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ + done; \ + echo '-- Installing $(srcdir)/html/index.sgml' ; \ + $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR) || :; \ + fi + +uninstall-local: + rm -f $(DESTDIR)$(TARGET_DIR)/* + +# +# Require gtk-doc when making dist +# +if ENABLE_GTK_DOC +dist-check-gtkdoc: +else +dist-check-gtkdoc: + @echo "*** gtk-doc must be installed and enabled in order to make dist" + @false +endif + +# XXX: Before this was: +# dist-hook: dist-check-gtkdoc dist-hook-local +# which seems reasonable, but for some reason the dist-check-gtkdoc +# was always failing on me, even though I do have gtk-doc installed +# and it is successfully building the documentation. + +dist-hook: dist-hook-local + mkdir $(distdir)/tmpl + mkdir $(distdir)/xml + mkdir $(distdir)/html + -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl + -cp $(srcdir)/xml/*.xml $(distdir)/xml + -cp $(srcdir)/html/* $(distdir)/html + +.PHONY : dist-hook-local diff --git a/src/Makefile.am b/src/Makefile.am index d4155e817..3f76d2726 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,53 +1,56 @@ -cairoincludedir = $(includedir)/cairo -cairoinclude_HEADERS = \ - cairo.h \ - cairo-atsui.h \ - cairo-features.h\ - cairo-ft.h \ - cairo-glitz.h \ - cairo-pdf.h \ - cairo-png.h \ - cairo-ps.h \ - cairo-quartz.h \ - cairo-xcb.h \ - cairo-xlib.h - -lib_LTLIBRARIES = libcairo.la if CAIRO_HAS_PS_SURFACE -libcairo_ps_sources = cairo_ps_surface.c cairo-ps.h +libcairo_ps_headers = cairo-ps.h +libcairo_ps_sources = cairo_ps_surface.c endif if CAIRO_HAS_PDF_SURFACE -libcairo_pdf_sources = cairo_pdf_surface.c cairo-pdf.h +libcairo_pdf_headers = cairo-pdf.h +libcairo_pdf_sources = cairo_pdf_surface.c endif if CAIRO_HAS_PNG_SURFACE -libcairo_png_sources = cairo_png_surface.c cairo-png.h +libcairo_png_headers = cairo-png.h +libcairo_png_sources = cairo_png_surface.c endif if CAIRO_HAS_XLIB_SURFACE -libcairo_xlib_sources = cairo_xlib_surface.c cairo-xlib.h +libcairo_xlib_headers = cairo-xlib.h +libcairo_xlib_sources = cairo_xlib_surface.c endif if CAIRO_HAS_QUARTZ_SURFACE -libcairo_quartz_sources = cairo_quartz_surface.c cairo-quartz.h +libcairo_quartz_headers = cairo-quartz.h +libcairo_quartz_sources = cairo_quartz_surface.c endif if CAIRO_HAS_XCB_SURFACE -libcairo_xcb_sources = cairo_xcb_surface.c cairo-xcb.h +libcairo_xcb_headers = cairo-xcb.h +libcairo_xcb_sources = cairo_xcb_surface.c +endif + +libcairo_win32_sources = +if CAIRO_HAS_WIN32_SURFACE +libcairo_win32_headers = cairo-win32.h +libcairo_win32_sources += cairo_win32_surface.c cairo-win32-private.h +endif +if CAIRO_HAS_WIN32_FONT +libcairo_win32_sources += cairo_win32_font.c endif if CAIRO_HAS_GLITZ_SURFACE -libcairo_glitz_sources = cairo_glitz_surface.c cairo-glitz.h +libcairo_glitz_headers = cairo-glitz.h +libcairo_glitz_sources = cairo_glitz_surface.c endif if CAIRO_HAS_ATSUI_FONT -libcairo_atsui_sources = cairo_atsui_font.c cairo-atsui.h +libcairo_atsui_headers = cairo-atsui.h +libcairo_atsui_sources = cairo_atsui_font.c endif if CAIRO_HAS_FT_FONT -libcairo_ft_sources = cairo_ft_font.c cairo-ft.h +libcairo_ft_headers = cairo-ft.h +libcairo_ft_sources = cairo_ft_font.c cairo-ft-private.h endif # These names match automake style variable definition conventions so @@ -57,6 +60,23 @@ endif FONTCONFIG_LIBS=@FONTCONFIG_LIBS@ XRENDER_LIBS=@XRENDER_LIBS@ +cairoincludedir = $(includedir)/cairo +cairoinclude_HEADERS = \ + cairo.h \ + cairo-features.h \ + $(libcairo_atsui_headers) \ + $(libcairo_ft_headers) \ + $(libcairo_glitz_headers) \ + $(libcairo_pdf_headers) \ + $(libcairo_png_headers) \ + $(libcairo_ps_headers) \ + $(libcairo_quartz_headers) \ + $(libcairo_win32_headers) \ + $(libcairo_xcb_headers) \ + $(libcairo_xlib_headers) + +lib_LTLIBRARIES = libcairo.la + libcairo_la_SOURCES = \ cairo.c \ cairo.h \ @@ -80,6 +100,7 @@ libcairo_la_SOURCES = \ cairo_surface.c \ cairo_traps.c \ cairo_pattern.c \ + cairo_unicode.c \ cairo_wideint.c \ cairo-wideint.h \ $(libcairo_atsui_sources)\ @@ -91,6 +112,8 @@ libcairo_la_SOURCES = \ $(libcairo_quartz_sources)\ $(libcairo_xcb_sources) \ $(libcairo_glitz_sources)\ + $(libcairo_win32_sources)\ + $(libcairo_freetype_sources) \ cairoint.h libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined @@ -98,3 +121,13 @@ libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS) libcairo_la_LIBADD = $(CAIRO_LIBS) + +install-data-local: + @if test -f $(includedir)/cairo.h || test -f $(includedir)/cairo-features.h ; then \ + echo "****************************************************************" ; \ + echo "*** Error: Old headers found. You should remove the following" ; \ + echo "*** files and then type 'make install' again." ; \ + ls $(includedir)/cairo*.h ; \ + echo "****************************************************************" ; \ + false ; \ + fi diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c index 52cfc6bd8..cb4b1c5d7 100644 --- a/src/cairo-atsui-font.c +++ b/src/cairo-atsui-font.c @@ -1,6 +1,6 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2004 Calum Robinson + * Copyright © 2004 Calum Robinson * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public diff --git a/src/cairo-atsui.h b/src/cairo-atsui.h index 94b30432a..a5b7308f8 100644 --- a/src/cairo-atsui.h +++ b/src/cairo-atsui.h @@ -1,6 +1,6 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2004 Calum Robinson + * Copyright © 2004 Calum Robinson * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -33,18 +33,23 @@ * Calum Robinson <calumr@mac.com> */ -#include <cairo.h> - #ifndef CAIRO_ATSUI_H #define CAIRO_ATSUI_H + +#include <cairo.h> + #ifdef CAIRO_HAS_ATSUI_FONT /* ATSUI platform-specific font interface */ #include <Carbon/Carbon.h> +CAIRO_BEGIN_DECLS + cairo_font_t * cairo_atsui_font_create(ATSUStyle style); +CAIRO_END_DECLS + #endif /* CAIRO_HAS_ATSUI_FONT */ #endif /* CAIRO_ATSUI_H */ diff --git a/src/cairo-cache.c b/src/cairo-cache.c index b097b609b..d1ad5a4e2 100644 --- a/src/cairo-cache.c +++ b/src/cairo-cache.c @@ -94,9 +94,9 @@ static const cairo_cache_arrangement_t cache_arrangements [] = { * a mostly-dead table. * * Generally you do not need to worry about freeing cache entries; the - * cache will expire entries randomly as it experiences memory pressure. - * There is currently no explicit entry-removing call, though one can be - * added easily. + * cache will expire entries randomly as it experiences memory pressure. + * If max_memory is set, entries are not expired, and must be explicitely + * removed. * * This table is open-addressed with double hashing. Each table size is a * prime chosen to be a little more than double the high water mark for a @@ -282,17 +282,51 @@ _load_factor (cairo_cache_t *cache) } #endif -static unsigned long -_random_live_entry (cairo_cache_t *cache) -{ - unsigned long idx; - assert(cache != NULL); - do { - idx = rand () % cache->arrangement->size; - } while (! LIVE_ENTRY_P(cache, idx)); - return idx; -} +/* Find a random in the cache matching the given predicate. We use the + * same algorithm as the probing algorithm to walk over the entries in + * the hash table in a pseudo-random order. Walking linearly would + * favor entries following gaps in the hash table. We could also + * call rand() repeatedly, which works well for almost-full tables, + * but degrades when the table is almost empty, or predicate + * returns false for most entries. + */ +static cairo_cache_entry_base_t ** +_random_entry (cairo_cache_t *cache, + int (*predicate)(void*)) +{ + cairo_cache_entry_base_t **probe; + unsigned long hash; + unsigned long table_size, i, idx, step; + + _cache_sane_state (cache); + + table_size = cache->arrangement->size; + hash = rand (); + idx = hash % table_size; + step = 0; + + for (i = 0; i < table_size; ++i) + { + assert(idx < table_size); + probe = cache->entries + idx; + if (LIVE_ENTRY_P(cache, idx) + && (!predicate || predicate (*probe))) + return probe; + + if (step == 0) { + step = hash % cache->arrangement->rehash; + if (step == 0) + step = 1; + } + + idx += step; + if (idx >= table_size) + idx -= table_size; + } + + return NULL; +} /* public API follows */ @@ -356,8 +390,9 @@ _cairo_cache_destroy (cairo_cache_t *cache) cairo_status_t _cairo_cache_lookup (cairo_cache_t *cache, - void *key, - void **entry_return) + void *key, + void **entry_return, + int *created_entry) { unsigned long idx; @@ -392,6 +427,8 @@ _cairo_cache_lookup (cairo_cache_t *cache, cache->hits++; #endif *entry_return = *slot; + if (created_entry) + *created_entry = 0; return status; } @@ -401,19 +438,18 @@ _cairo_cache_lookup (cairo_cache_t *cache, /* Build the new entry. */ status = cache->backend->create_entry (cache, key, - entry_return); + (void **)&new_entry); if (status != CAIRO_STATUS_SUCCESS) return status; - new_entry = (cairo_cache_entry_base_t *) (*entry_return); - /* Store the hash value in case the backend forgot. */ new_entry->hashcode = cache->backend->hash (cache, key); /* Make some entries die if we're under memory pressure. */ while (cache->live_entries > 0 && + cache->max_memory > 0 && ((cache->max_memory - cache->used_memory) < new_entry->memory)) { - idx = _random_live_entry (cache); + idx = _random_entry (cache, NULL) - cache->entries; assert (idx < cache->arrangement->size); _entry_destroy (cache, idx); } @@ -425,7 +461,6 @@ _cairo_cache_lookup (cairo_cache_t *cache, status = _resize_cache (cache, cache->live_entries + 1); if (status != CAIRO_STATUS_SUCCESS) { cache->backend->destroy_entry (cache, new_entry); - *entry_return = NULL; return status; } @@ -439,9 +474,38 @@ _cairo_cache_lookup (cairo_cache_t *cache, _cache_sane_state (cache); + *entry_return = new_entry; + if (created_entry) + *created_entry = 1; + return status; } +cairo_status_t +_cairo_cache_remove (cairo_cache_t *cache, + void *key) +{ + cairo_cache_entry_base_t **slot; + + _cache_sane_state (cache); + + /* See if we have an entry in the table already. */ + slot = _find_exact_live_entry_for (cache, key); + if (slot != NULL) + _entry_destroy (cache, slot - cache->entries); + + return CAIRO_STATUS_SUCCESS; +} + +void * +_cairo_cache_random_entry (cairo_cache_t *cache, + int (*predicate)(void*)) +{ + cairo_cache_entry_base_t **slot = _random_entry (cache, predicate); + + return slot ? *slot : NULL; +} + unsigned long _cairo_hash_string (const char *c) { diff --git a/src/cairo-color.c b/src/cairo-color.c index 899b1e3d5..f203d96cc 100644 --- a/src/cairo-color.c +++ b/src/cairo-color.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" @@ -67,7 +67,8 @@ _cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blu } void -_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue) +_cairo_color_get_rgb (const cairo_color_t *color, + double *red, double *green, double *blue) { if (red) *red = color->red; diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in index e2a62ba66..a13250d97 100644 --- a/src/cairo-features.h.in +++ b/src/cairo-features.h.in @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl Worth <cworth@east.isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #ifndef CAIRO_FEATURES_H @@ -49,10 +49,14 @@ #define @XCB_SURFACE_FEATURE@ +#define @WIN32_SURFACE_FEATURE@ + #define @GLITZ_SURFACE_FEATURE@ #define @FT_FONT_FEATURE@ +#define @WIN32_FONT_FEATURE@ + #define @ATSUI_FONT_FEATURE@ #define @SANITY_CHECKING_FEATURE@ diff --git a/src/cairo-fixed.c b/src/cairo-fixed.c index ee31718ef..a4faa1708 100644 --- a/src/cairo-fixed.c +++ b/src/cairo-fixed.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo-font.c b/src/cairo-font.c index f5fc0e981..529c1c7c3 100644 --- a/src/cairo-font.c +++ b/src/cairo-font.c @@ -1,6 +1,7 @@ /* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -31,293 +32,129 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> + * Graydon Hoare <graydon@redhat.com> + * Owen Taylor <otaylor@redhat.com> */ #include "cairoint.h" -/* First we implement a global font cache for named fonts. */ - -typedef struct { - cairo_cache_entry_base_t base; - const char *family; - cairo_font_slant_t slant; - cairo_font_weight_t weight; -} cairo_font_cache_key_t; - -typedef struct { - cairo_font_cache_key_t key; - cairo_unscaled_font_t *unscaled; -} cairo_font_cache_entry_t; - -static unsigned long -_font_cache_hash (void *cache, void *key) -{ - unsigned long hash; - cairo_font_cache_key_t *in; - in = (cairo_font_cache_key_t *) key; - - /* 1607 and 1451 are just a couple random primes. */ - hash = _cairo_hash_string (in->family); - hash += ((unsigned long) in->slant) * 1607; - hash += ((unsigned long) in->weight) * 1451; - return hash; -} - - -static int -_font_cache_keys_equal (void *cache, - void *k1, - void *k2) -{ - cairo_font_cache_key_t *a, *b; - a = (cairo_font_cache_key_t *) k1; - b = (cairo_font_cache_key_t *) k2; - - return (strcmp (a->family, b->family) == 0) - && (a->weight == b->weight) - && (a->slant == b->slant); -} - - -static cairo_status_t -_font_cache_create_entry (void *cache, - void *key, - void **return_value) -{ - const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT; - cairo_font_cache_key_t *k; - cairo_font_cache_entry_t *entry; - k = (cairo_font_cache_key_t *) key; - - /* XXX: The current freetype backend may return NULL, (for example - * if no fonts are installed), but I would like to guarantee that - * the toy API always returns at least *some* font, so I would - * like to build in some sort fo font here, (even a really lame, - * ugly one if necessary). */ - - entry = malloc (sizeof (cairo_font_cache_entry_t)); - if (entry == NULL) - goto FAIL; - - entry->key.slant = k->slant; - entry->key.weight = k->weight; - entry->key.family = strdup(k->family); - if (entry->key.family == NULL) - goto FREE_ENTRY; - - entry->unscaled = backend->create (k->family, k->slant, k->weight); - if (entry->unscaled == NULL) - goto FREE_FAMILY; - - /* Not sure how to measure backend font mem; use a simple count for now.*/ - entry->key.base.memory = 1; - *return_value = entry; - return CAIRO_STATUS_SUCCESS; - - FREE_FAMILY: - free ((void *) entry->key.family); - - FREE_ENTRY: - free (entry); - - FAIL: - return CAIRO_STATUS_NO_MEMORY; -} - -static void -_font_cache_destroy_entry (void *cache, - void *entry) -{ - cairo_font_cache_entry_t *e; - - e = (cairo_font_cache_entry_t *) entry; - _cairo_unscaled_font_destroy (e->unscaled); - free ((void *) e->key.family); - free (e); -} - -static void -_font_cache_destroy_cache (void *cache) -{ - free (cache); -} - -static const cairo_cache_backend_t cairo_font_cache_backend = { - _font_cache_hash, - _font_cache_keys_equal, - _font_cache_create_entry, - _font_cache_destroy_entry, - _font_cache_destroy_cache -}; - -static void -_lock_global_font_cache (void) -{ - /* FIXME: implement locking. */ -} - -static void -_unlock_global_font_cache (void) -{ - /* FIXME: implement locking. */ -} - -static cairo_cache_t * -_global_font_cache = NULL; - -static cairo_cache_t * -_get_global_font_cache (void) -{ - if (_global_font_cache == NULL) { - _global_font_cache = malloc (sizeof (cairo_cache_t)); - - if (_global_font_cache == NULL) - goto FAIL; - - if (_cairo_cache_init (_global_font_cache, - &cairo_font_cache_backend, - CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT)) - goto FAIL; - } - - return _global_font_cache; - - FAIL: - if (_global_font_cache) - free (_global_font_cache); - _global_font_cache = NULL; - return NULL; -} - - /* Now the internal "unscaled + scale" font API */ -cairo_unscaled_font_t * -_cairo_unscaled_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight) +cairo_private cairo_status_t +_cairo_font_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight, + cairo_font_scale_t *sc, + cairo_font_t **font) { - cairo_cache_t * cache; - cairo_font_cache_key_t key; - cairo_font_cache_entry_t *font; - cairo_status_t status; - - _lock_global_font_cache (); - cache = _get_global_font_cache (); - if (cache == NULL) { - _unlock_global_font_cache (); - return NULL; - } - - key.family = family; - key.slant = slant; - key.weight = weight; - - status = _cairo_cache_lookup (cache, &key, (void **) &font); - if (status) { - _unlock_global_font_cache (); - return NULL; - } + const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT; - _cairo_unscaled_font_reference (font->unscaled); - _unlock_global_font_cache (); - return font->unscaled; + return backend->create (family, slant, weight, sc, font); } void -_cairo_font_init (cairo_font_t *scaled, - cairo_font_scale_t *scale, - cairo_unscaled_font_t *unscaled) +_cairo_font_init (cairo_font_t *font, + cairo_font_scale_t *scale, + const cairo_font_backend_t *backend) { - scaled->scale = *scale; - scaled->unscaled = unscaled; - scaled->refcount = 1; + font->scale = *scale; + font->refcount = 1; + font->backend = backend; } -cairo_status_t -_cairo_unscaled_font_init (cairo_unscaled_font_t *font, - const cairo_font_backend_t *backend) +void +_cairo_unscaled_font_init (cairo_unscaled_font_t *font, + const cairo_font_backend_t *backend) { font->refcount = 1; font->backend = backend; - return CAIRO_STATUS_SUCCESS; } - cairo_status_t -_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - const unsigned char *utf8, - cairo_glyph_t **glyphs, - int *num_glyphs) +_cairo_font_text_to_glyphs (cairo_font_t *font, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs) { - return font->backend->text_to_glyphs (font, scale, utf8, glyphs, num_glyphs); + return font->backend->text_to_glyphs (font, utf8, glyphs, num_glyphs); } cairo_status_t -_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents) +_cairo_font_glyph_extents (cairo_font_t *font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) { - return font->backend->glyph_extents(font, scale, glyphs, num_glyphs, extents); + return font->backend->glyph_extents(font, glyphs, num_glyphs, extents); } cairo_status_t -_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox) +_cairo_font_glyph_bbox (cairo_font_t *font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox) { - return font->backend->glyph_bbox (font, scale, glyphs, num_glyphs, bbox); + return font->backend->glyph_bbox (font, glyphs, num_glyphs, bbox); } cairo_status_t -_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_font_show_glyphs (cairo_font_t *font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + cairo_glyph_t *glyphs, + int num_glyphs) { cairo_status_t status; if (surface->backend->show_glyphs != NULL) { - status = surface->backend->show_glyphs (font, scale, operator, source, - surface, source_x, source_y, + status = surface->backend->show_glyphs (font, operator, pattern, + surface, + source_x, source_y, + dest_x, dest_y, + width, height, glyphs, num_glyphs); if (status == CAIRO_STATUS_SUCCESS) return status; } /* Surface display routine either does not exist or failed. */ - return font->backend->show_glyphs (font, scale, operator, source, - surface, source_x, source_y, + return font->backend->show_glyphs (font, operator, pattern, + surface, + source_x, source_y, + dest_x, dest_y, + width, height, glyphs, num_glyphs); } cairo_status_t -_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_t *path) +_cairo_font_glyph_path (cairo_font_t *font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path) +{ + return font->backend->glyph_path (font, glyphs, num_glyphs, path); +} + +void +_cairo_font_get_glyph_cache_key (cairo_font_t *font, + cairo_glyph_cache_key_t *key) { - return font->backend->glyph_path (font, scale, glyphs, num_glyphs, path); + font->backend->get_glyph_cache_key (font, key); } cairo_status_t -_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_font_extents_t *extents) +_cairo_font_font_extents (cairo_font_t *font, + cairo_font_extents_t *extents) { - return font->backend->font_extents(font, scale, extents); + return font->backend->font_extents (font, extents); } void @@ -332,8 +169,7 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font) if (--(font->refcount) > 0) return; - if (font->backend) - font->backend->destroy (font); + font->backend->destroy_unscaled_font (font); } @@ -352,37 +188,154 @@ cairo_font_destroy (cairo_font_t *font) if (--(font->refcount) > 0) return; - if (font->unscaled) - _cairo_unscaled_font_destroy (font->unscaled); - - free (font); + font->backend->destroy_font (font); } -void -cairo_font_set_transform (cairo_font_t *font, - cairo_matrix_t *matrix) +/** + * cairo_font_extents: + * @font: a #cairo_font_t + * @font_matrix: the font transformation for which this font was + * created. (See cairo_transform_font()). This is needed + * properly convert the metrics from the font into user space. + * @extents: a #cairo_font_extents_t which to store the retrieved extents. + * + * Gets the metrics for a #cairo_font_t. + * + * Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an + * error such as %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_status_t +cairo_font_extents (cairo_font_t *font, + cairo_matrix_t *font_matrix, + cairo_font_extents_t *extents) { - double dummy; - cairo_matrix_get_affine (matrix, - &font->scale.matrix[0][0], - &font->scale.matrix[0][1], - &font->scale.matrix[1][0], - &font->scale.matrix[1][1], - &dummy, &dummy); + cairo_int_status_t status; + double font_scale_x, font_scale_y; + + status = _cairo_font_font_extents (font, extents); + + if (!CAIRO_OK (status)) + return status; + + _cairo_matrix_compute_scale_factors (font_matrix, + &font_scale_x, &font_scale_y, + /* XXX */ 1); + + /* + * The font responded in unscaled units, scale by the font + * matrix scale factors to get to user space + */ + + extents->ascent *= font_scale_y; + extents->descent *= font_scale_y; + extents->height *= font_scale_y; + extents->max_x_advance *= font_scale_x; + extents->max_y_advance *= font_scale_y; + + return status; } +/** + * cairo_font_glyph_extents: + * @font: a #cairo_font_t + * @font_matrix: the font transformation for which this font was + * created. (See cairo_transform_font()). This is needed + * properly convert the metrics from the font into user space. + * @glyphs: an array of glyph IDs with X and Y offsets. + * @num_glyphs: the number of glyphs in the @glyphs array + * @extents: a #cairo_text_extents_t which to store the retrieved extents. + * + * cairo_font_glyph_extents() gets the overall metrics for a string of + * glyphs. The X and Y offsets in @glyphs are taken from an origin of 0,0. + **/ void -cairo_font_current_transform (cairo_font_t *font, - cairo_matrix_t *matrix) +cairo_font_glyph_extents (cairo_font_t *font, + cairo_matrix_t *font_matrix, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) { - cairo_matrix_set_affine (matrix, - font->scale.matrix[0][0], - font->scale.matrix[0][1], - font->scale.matrix[1][0], - font->scale.matrix[1][1], - 0, 0); -} + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_glyph_t origin_glyph; + cairo_text_extents_t origin_extents; + int i; + double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0; + double x_pos = 0.0, y_pos = 0.0; + int set = 0; + + if (!num_glyphs) + { + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + extents->x_advance = 0.0; + extents->y_advance = 0.0; + + return; + } + for (i = 0; i < num_glyphs; i++) + { + double x, y; + double wm, hm; + + origin_glyph = glyphs[i]; + origin_glyph.x = 0.0; + origin_glyph.y = 0.0; + status = _cairo_font_glyph_extents (font, + &origin_glyph, 1, + &origin_extents); + + /* + * Transform font space metrics into user space metrics + * by running the corners through the font matrix and + * expanding the bounding box as necessary + */ + x = origin_extents.x_bearing; + y = origin_extents.y_bearing; + cairo_matrix_transform_point (font_matrix, + &x, &y); + + for (hm = 0.0; hm <= 1.0; hm += 1.0) + for (wm = 0.0; wm <= 1.0; wm += 1.0) + { + x = origin_extents.x_bearing + origin_extents.width * wm; + y = origin_extents.y_bearing + origin_extents.height * hm; + cairo_matrix_transform_point (font_matrix, + &x, &y); + x += glyphs[i].x; + y += glyphs[i].y; + if (!set) + { + min_x = max_x = x; + min_y = max_y = y; + set = 1; + } + else + { + if (x < min_x) min_x = x; + if (x > max_x) max_x = x; + if (y < min_y) min_y = y; + if (y > max_y) max_y = y; + } + } + + x = origin_extents.x_advance; + y = origin_extents.y_advance; + cairo_matrix_transform_point (font_matrix, + &x, &y); + x_pos = glyphs[i].x + x; + y_pos = glyphs[i].y + y; + } + + extents->x_bearing = min_x - glyphs[0].x; + extents->y_bearing = min_y - glyphs[0].y; + extents->width = max_x - min_x; + extents->height = max_y - min_y; + extents->x_advance = x_pos - glyphs[0].x; + extents->y_advance = y_pos - glyphs[0].y; +} /* Now we implement functions to access a default global image & metrics * cache. @@ -398,7 +351,8 @@ _cairo_glyph_cache_hash (void *cache, void *key) ^ ((unsigned long) in->scale.matrix[0][0]) ^ ((unsigned long) in->scale.matrix[0][1]) ^ ((unsigned long) in->scale.matrix[1][0]) - ^ ((unsigned long) in->scale.matrix[1][1]) + ^ ((unsigned long) in->scale.matrix[1][1]) + ^ (in->flags * 1451) /* 1451 is just an abitrary prime */ ^ in->index; } @@ -412,6 +366,7 @@ _cairo_glyph_cache_keys_equal (void *cache, b = (cairo_glyph_cache_key_t *) k2; return (a->index == b->index) && (a->unscaled == b->unscaled) + && (a->flags == b->flags) && (a->scale.matrix[0][0] == b->scale.matrix[0][0]) && (a->scale.matrix[0][1] == b->scale.matrix[0][1]) && (a->scale.matrix[1][0] == b->scale.matrix[1][0]) diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index b928b04fc..44e1b0e84 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -1,29 +1,40 @@ -/* - * Copyright © 2003 Red Hat Inc. +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and that - * both that copyright notice and this permission notice appear in - * supporting documentation, and that the name of Red Hat Inc. not be used - * in advertising or publicity pertaining to distribution of the software - * without specific, written prior permission. Red Hat Inc. makes no - * representations about the suitability of this software for any purpose. - * It is provided "as is" without express or implied warranty. + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * RED HAT INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL RED HAT INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. * - * Author: Graydon Hoare <graydon@redhat.com> + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Graydon Hoare <graydon@redhat.com> + * Owen Taylor <otaylor@redhat.com> */ -#include "cairoint.h" -#include "cairo-ft.h" +#include "cairo-ft-private.h" #include <fontconfig/fontconfig.h> #include <fontconfig/fcfreetype.h> @@ -38,19 +49,9 @@ #define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) #define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) -/* - * First we make a private, sharable implementation object which can be - * stored both in a private cache and in public font objects (including - * those connected to fonts we don't own) +/* This is the max number of FT_face objects we keep open at once */ - -typedef struct { - int refcount; - - FT_Face face; - int owns_face; - -} ft_font_val_t; +#define MAX_OPEN_FACES 10 /* * The simple 2x2 matrix is converted into separate scale and shape @@ -62,141 +63,126 @@ typedef struct { double shape[2][2]; } ft_font_transform_t; -static ft_font_val_t * -_create_from_face (FT_Face face, int owns_face) -{ - ft_font_val_t *tmp = malloc (sizeof(ft_font_val_t)); - if (tmp) { - tmp->refcount = 1; - tmp->face = face; - tmp->owns_face = owns_face; - FT_Set_Char_Size (face, - DOUBLE_TO_26_6 (1.0), - DOUBLE_TO_26_6 (1.0), - 0, 0); - } - return tmp; -} +/* + * We create an object that corresponds to a single font on the disk; + * (identified by a filename/id pair) these are shared between all + * fonts using that file. For cairo_ft_font_create_for_ft_face(), we + * just create a one-off version with a permanent face value. + */ -static void -_reference_font_val (ft_font_val_t *f) -{ - f->refcount++; -} +typedef struct { + cairo_unscaled_font_t base; -static void -_destroy_font_val (ft_font_val_t *f) -{ - if (--(f->refcount) > 0) - return; + int from_face; /* from cairo_ft_font_create_for_ft_face()? */ + FT_Face face; /* provided or cached face */ - if (f->owns_face) - FT_Done_Face (f->face); + /* only set if from_face is false */ + FT_Library library; + char *filename; + int id; - free (f); -} + /* We temporarily scale the unscaled font as neede */ + int have_scale; + cairo_font_scale_t current_scale; + double x_scale; /* Extracted X scale factor */ + double y_scale; /* Extracted Y scale factor */ + + int lock; /* count of how many times this font has been locked */ +} ft_unscaled_font_t; -static ft_font_val_t * -_create_from_library_and_pattern (FT_Library ft_library, FcPattern *pattern) -{ - ft_font_val_t *f = NULL; - char *filename = NULL; - int owns_face = 0; - FT_Face face = NULL; - FcPattern *resolved = NULL; - FcResult result = FcResultMatch; +const cairo_font_backend_t cairo_ft_font_backend; - if (pattern == NULL) - goto FAIL; +static ft_unscaled_font_t * +_ft_unscaled_font_create_from_face (FT_Face face) +{ + ft_unscaled_font_t *unscaled = malloc (sizeof(ft_unscaled_font_t)); + if (!unscaled) + return NULL; + + unscaled->from_face = 1; + unscaled->face = face; - FcConfigSubstitute (0, pattern, FcMatchPattern); - FcDefaultSubstitute (pattern); + unscaled->library = NULL; + unscaled->filename = NULL; + unscaled->id = 0; - resolved = FcFontMatch (0, pattern, &result); - if (!resolved) - goto FAIL; + unscaled->have_scale = 0; + unscaled->lock = 0; - if (result != FcResultMatch) - goto FREE_RESOLVED; + _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled, + &cairo_ft_font_backend); + return unscaled; +} + +static ft_unscaled_font_t * +_ft_unscaled_font_create_from_filename (FT_Library library, + const char *filename, + int id) +{ + ft_unscaled_font_t *unscaled; + char *new_filename; - /* If the pattern has an FT_Face object, use that. */ - if (FcPatternGetFTFace (resolved, FC_FT_FACE, 0, &face) != FcResultMatch - || face == NULL) - { - /* otherwise it had better have a filename */ - result = FcPatternGetString (resolved, FC_FILE, 0, (FcChar8 **)(&filename)); - - if (result == FcResultMatch) - if (FT_New_Face (ft_library, filename, 0, &face)) - goto FREE_RESOLVED; - - if (face == NULL) - goto FREE_RESOLVED; - - owns_face = 1; + new_filename = strdup (filename); + if (!new_filename) + return NULL; + + unscaled = malloc (sizeof (ft_unscaled_font_t)); + if (!unscaled) { + free (new_filename); + return NULL; } + + unscaled->from_face = 0; + unscaled->face = NULL; - f = _create_from_face (face, owns_face); - - FcPatternDestroy (resolved); - return f; + unscaled->library = library; + unscaled->filename = new_filename; + unscaled->id = id; - FREE_RESOLVED: - if (resolved) - FcPatternDestroy (resolved); - - FAIL: - return NULL; + unscaled->have_scale = 0; + unscaled->lock = 0; + + _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled, + &cairo_ft_font_backend); + return unscaled; } - -/* - * We then make the user-exposed structure out of one of these impls, such - * that it is reasonably cheap to copy and/or destroy. Unfortunately this - * duplicates a certain amount of the caching machinery in the font cache, - * but that's unavoidable as we also provide an FcPattern resolution API, - * which is not part of cairo's generic font finding system. - */ - -typedef struct { - cairo_unscaled_font_t base; - FcPattern *pattern; - ft_font_val_t *val; -} cairo_ft_font_t; - -/* - * We then make a key and entry type which are compatible with the generic - * cache system. This cache serves to share single ft_font_val_t instances - * between fonts (or between font lifecycles). +/* + * We keep a global cache from [file/id] => [ft_unscaled_font_t]. This + * hash isn't limited in size. However, we limit the number of + * FT_Face objects we keep around; when we've exceeeded that + * limit and need to create a new FT_Face, we dump the FT_Face from + * a random ft_unscaled_font_t. */ typedef struct { cairo_cache_entry_base_t base; - FcPattern *pattern; + char *filename; + int id; } cairo_ft_cache_key_t; typedef struct { cairo_ft_cache_key_t key; - ft_font_val_t *val; + ft_unscaled_font_t *unscaled; } cairo_ft_cache_entry_t; -/* - * Then we create a cache which maps FcPattern keys to the refcounted - * ft_font_val_t values. - */ - typedef struct { cairo_cache_t base; FT_Library lib; + int n_faces; /* Number of open FT_Face objects */ } ft_cache_t; - static unsigned long _ft_font_cache_hash (void *cache, void *key) { - cairo_ft_cache_key_t *in; - in = (cairo_ft_cache_key_t *) key; - return FcPatternHash (in->pattern); + cairo_ft_cache_key_t *in = (cairo_ft_cache_key_t *) key; + unsigned long hash; + + /* 1607 is just a random prime. */ + hash = _cairo_hash_string (in->filename); + hash += ((unsigned long) in->id) * 1607; + + return hash; } static int @@ -208,10 +194,10 @@ _ft_font_cache_keys_equal (void *cache, cairo_ft_cache_key_t *b; a = (cairo_ft_cache_key_t *) k1; b = (cairo_ft_cache_key_t *) k2; - - return FcPatternEqual (a->pattern, b->pattern); -} + return strcmp (a->filename, b->filename) == 0 && + a->id == b->id; +} static cairo_status_t _ft_font_cache_create_entry (void *cache, @@ -226,27 +212,33 @@ _ft_font_cache_create_entry (void *cache, if (entry == NULL) return CAIRO_STATUS_NO_MEMORY; - entry->key.pattern = FcPatternDuplicate (k->pattern); - if (!entry->key.pattern) { + entry->unscaled = _ft_unscaled_font_create_from_filename (ftcache->lib, + k->filename, + k->id); + if (!entry->unscaled) { free (entry); return CAIRO_STATUS_NO_MEMORY; } - - entry->val = _create_from_library_and_pattern (ftcache->lib, entry->key.pattern); - entry->key.base.memory = 1; - + + entry->key.base.memory = 0; + entry->key.filename = entry->unscaled->filename; + entry->key.id = entry->unscaled->id; + *return_entry = entry; return CAIRO_STATUS_SUCCESS; } +/* Entries are never spontaneously destroyed; but only when + * we remove them from the cache specifically. We free entry->unscaled + * in the code that removes the entry from the cache + */ static void _ft_font_cache_destroy_entry (void *cache, void *entry) { cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry; - FcPatternDestroy (e->key.pattern); - _destroy_font_val (e->val); + free (e); } @@ -291,11 +283,12 @@ _get_global_ft_cache (void) if (_cairo_cache_init (&_global_ft_cache->base, &_ft_font_cache_backend, - CAIRO_FT_CACHE_NUM_FONTS_DEFAULT)) + 0)) /* No memory limit */ goto FAIL; if (FT_Init_FreeType (&_global_ft_cache->lib)) goto FAIL; + _global_ft_cache->n_faces = 0; } return &_global_ft_cache->base; @@ -306,30 +299,304 @@ _get_global_ft_cache (void) return NULL; } -/* implement the backend interface */ +/* Finds or creates a ft_unscaled_font for the filename/id from pattern. + * Returns a new reference to the unscaled font. + */ +static ft_unscaled_font_t * +_ft_unscaled_font_get_for_pattern (FcPattern *pattern) +{ + cairo_ft_cache_entry_t *entry; + cairo_ft_cache_key_t key; + cairo_cache_t *cache; + cairo_status_t status; + FcChar8 *filename; + int created_entry; + + if (FcPatternGetString (pattern, FC_FILE, 0, &filename) != FcResultMatch) + return NULL; + key.filename = (char *)filename; + + if (FcPatternGetInteger (pattern, FC_INDEX, 0, &key.id) != FcResultMatch) + return NULL; + + _lock_global_ft_cache (); + cache = _get_global_ft_cache (); + if (cache == NULL) { + _unlock_global_ft_cache (); + return NULL; + } + + status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry); + _unlock_global_ft_cache (); + if (status) + return NULL; + + if (!created_entry) + _cairo_unscaled_font_reference ((cairo_unscaled_font_t *)entry->unscaled); + + return entry->unscaled; +} + +static int +_has_unlocked_face (void *entry) +{ + cairo_ft_cache_entry_t *e = entry; -const cairo_font_backend_t cairo_ft_font_backend; + return (e->unscaled->lock == 0 && e->unscaled->face); +} + +/* Ensures that an unscaled font has a face object. If we exceed + * MAX_OPEN_FACES, try to close some. + */ +static FT_Face +_ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled) +{ + ft_cache_t *ftcache; + FT_Face face = NULL; + + if (unscaled->face) { + unscaled->lock++; + return unscaled->face; + } -static cairo_unscaled_font_t * -_cairo_ft_font_create (const char *family, + assert (!unscaled->from_face); + + _lock_global_ft_cache (); + ftcache = (ft_cache_t *) _get_global_ft_cache (); + assert (ftcache != NULL); + + while (ftcache->n_faces >= MAX_OPEN_FACES) { + cairo_ft_cache_entry_t *entry; + + entry = _cairo_cache_random_entry ((cairo_cache_t *)ftcache, _has_unlocked_face); + if (entry) { + FT_Done_Face (entry->unscaled->face); + entry->unscaled->face = NULL; + entry->unscaled->have_scale = 0; + ftcache->n_faces--; + } else { + break; + } + } + + if (FT_New_Face (ftcache->lib, + unscaled->filename, + unscaled->id, + &face) != FT_Err_Ok) + goto FAIL; + + unscaled->face = face; + unscaled->lock++; + ftcache->n_faces++; + + FAIL: + _unlock_global_ft_cache (); + return face; +} + +/* Unlock unscaled font locked with _ft_unscaled_font_lock_face + */ +static void +_ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled) +{ + assert (unscaled->lock > 0); + + unscaled->lock--; +} + +static void +_compute_transform (ft_font_transform_t *sf, + cairo_font_scale_t *sc) +{ + cairo_matrix_t normalized; + double tx, ty; + + /* The font matrix has x and y "scale" components which we extract and + * use as character scale values. These influence the way freetype + * chooses hints, as well as selecting different bitmaps in + * hand-rendered fonts. We also copy the normalized matrix to + * freetype's transformation. + */ + + cairo_matrix_set_affine (&normalized, + sc->matrix[0][0], + sc->matrix[0][1], + sc->matrix[1][0], + sc->matrix[1][1], + 0, 0); + + _cairo_matrix_compute_scale_factors (&normalized, + &sf->x_scale, &sf->y_scale, + /* XXX */ 1); + cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale); + cairo_matrix_get_affine (&normalized, + &sf->shape[0][0], &sf->shape[0][1], + &sf->shape[1][0], &sf->shape[1][1], + &tx, &ty); +} + +/* Temporarily scales an unscaled font to the give scale. We catch + * scaling to the same size, since changing a FT_Face is expensive. + */ +static void +_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled, + cairo_font_scale_t *scale) +{ + ft_font_transform_t sf; + FT_Matrix mat; + + assert (unscaled->face != NULL); + + if (unscaled->have_scale && + scale->matrix[0][0] == unscaled->current_scale.matrix[0][0] && + scale->matrix[0][1] == unscaled->current_scale.matrix[0][1] && + scale->matrix[1][0] == unscaled->current_scale.matrix[1][0] && + scale->matrix[1][1] == unscaled->current_scale.matrix[1][1]) + return; + + unscaled->have_scale = 1; + unscaled->current_scale = *scale; + + _compute_transform (&sf, scale); + + unscaled->x_scale = sf.x_scale; + unscaled->y_scale = sf.y_scale; + + mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]); + mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]); + mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]); + mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]); + + FT_Set_Transform(unscaled->face, &mat, NULL); + + FT_Set_Pixel_Sizes(unscaled->face, + (FT_UInt) sf.x_scale, + (FT_UInt) sf.y_scale); +} + +/* implement the font backend interface */ + +typedef struct { + cairo_font_t base; + FcPattern *pattern; + int load_flags; + ft_unscaled_font_t *unscaled; +} cairo_ft_font_t; + +/* for compatibility with older freetype versions */ +#ifndef FT_LOAD_TARGET_MONO +#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME +#endif + +/* The load flags passed to FT_Load_Glyph control aspects like hinting and + * antialiasing. Here we compute them from the fields of a FcPattern. + */ +static int +_get_load_flags (FcPattern *pattern) +{ + FcBool antialias, hinting, autohint; +#ifdef FC_HINT_STYLE + int hintstyle; +#endif + int load_flags = 0; + + /* disable antialiasing if requested */ + if (FcPatternGetBool (pattern, + FC_ANTIALIAS, 0, &antialias) != FcResultMatch) + antialias = FcTrue; + + if (antialias) + load_flags |= FT_LOAD_NO_BITMAP; + else + load_flags |= FT_LOAD_TARGET_MONO; + + /* disable hinting if requested */ + if (FcPatternGetBool (pattern, + FC_HINTING, 0, &hinting) != FcResultMatch) + hinting = FcTrue; + +#ifdef FC_HINT_STYLE + if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) + hintstyle = FC_HINT_FULL; + + if (!hinting || hintstyle == FC_HINT_NONE) + load_flags |= FT_LOAD_NO_HINTING; + + switch (hintstyle) { + case FC_HINT_SLIGHT: + case FC_HINT_MEDIUM: + load_flags |= FT_LOAD_TARGET_LIGHT; + break; + default: + load_flags |= FT_LOAD_TARGET_NORMAL; + break; + } +#else /* !FC_HINT_STYLE */ + if (!hinting) + load_flags |= FT_LOAD_NO_HINTING; +#endif /* FC_FHINT_STYLE */ + + /* force autohinting if requested */ + if (FcPatternGetBool (pattern, + FC_AUTOHINT, 0, &autohint) != FcResultMatch) + autohint = FcFalse; + + if (autohint) + load_flags |= FT_LOAD_FORCE_AUTOHINT; + + return load_flags; +} + +/* Like the public cairo_ft_font_create, but takes a cairo_font_scale_t, + * rather than a cairo_font_t + */ +static cairo_font_t * +_ft_font_create (FcPattern *pattern, + cairo_font_scale_t *scale) +{ + cairo_ft_font_t *f = NULL; + ft_unscaled_font_t *unscaled = NULL; + + unscaled = _ft_unscaled_font_get_for_pattern (pattern); + if (unscaled == NULL) + return NULL; + + f = malloc (sizeof(cairo_ft_font_t)); + if (f == NULL) + goto FREE_UNSCALED; + + f->unscaled = unscaled; + f->pattern = pattern; + FcPatternReference (pattern); + f->load_flags = _get_load_flags (pattern); + + _cairo_font_init ((cairo_font_t *)f, scale, &cairo_ft_font_backend); + + return (cairo_font_t *)f; + + FREE_UNSCALED: + _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled); + + return NULL; +} + +static cairo_status_t +_cairo_ft_font_create (const char *family, cairo_font_slant_t slant, - cairo_font_weight_t weight) + cairo_font_weight_t weight, + cairo_font_scale_t *scale, + cairo_font_t **font) { - cairo_status_t status; - cairo_ft_font_t *font = NULL; + FcPattern *pattern, *resolved; + cairo_font_t *new_font; + FcResult result; int fcslant; int fcweight; - cairo_cache_t *cache; - cairo_ft_cache_entry_t *entry; - cairo_ft_cache_key_t key; - - key.pattern = FcPatternCreate (); - if (key.pattern == NULL) - goto FAIL; + ft_font_transform_t sf; - font = malloc (sizeof (cairo_ft_font_t)); - if (font == NULL) - goto FREE_PATTERN; + pattern = FcPatternCreate (); + if (!pattern) + return CAIRO_STATUS_NO_MEMORY; switch (weight) { @@ -356,46 +623,44 @@ _cairo_ft_font_create (const char *family, break; } - FcPatternAddString (key.pattern, FC_FAMILY, family); - FcPatternAddInteger (key.pattern, FC_SLANT, fcslant); - FcPatternAddInteger (key.pattern, FC_WEIGHT, fcweight); - - if (_cairo_unscaled_font_init (&font->base, &cairo_ft_font_backend)) + if (!FcPatternAddString (pattern, FC_FAMILY, family)) goto FREE_PATTERN; - - _lock_global_ft_cache (); - cache = _get_global_ft_cache (); - if (cache == NULL) { - _unlock_global_ft_cache (); + if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) + goto FREE_PATTERN; + if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) goto FREE_PATTERN; - } - status = _cairo_cache_lookup (cache, &key, (void **) &entry); - _unlock_global_ft_cache (); + _compute_transform (&sf, scale); - if (status) - goto FREE_PATTERN; + FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale); - font->pattern = FcPatternDuplicate (entry->key.pattern); - if (font->pattern == NULL) + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + FcDefaultSubstitute (pattern); + + resolved = FcFontMatch (NULL, pattern, &result); + if (!resolved) goto FREE_PATTERN; - font->val = entry->val; - _reference_font_val (font->val); - - return &font->base; + new_font = _ft_font_create (resolved, scale); - FREE_PATTERN: - FcPatternDestroy (key.pattern); + FcPatternDestroy (resolved); + FcPatternDestroy (pattern); - FAIL: - return NULL; + if (new_font) { + *font = new_font; + return CAIRO_STATUS_SUCCESS; + } else { + return CAIRO_STATUS_NO_MEMORY; /* A guess */ + } -} + FREE_PATTERN: + FcPatternDestroy (pattern); + return CAIRO_STATUS_NO_MEMORY; +} static void -_cairo_ft_font_destroy (void *abstract_font) +_cairo_ft_font_destroy_font (void *abstract_font) { cairo_ft_font_t * font = abstract_font; @@ -405,179 +670,94 @@ _cairo_ft_font_destroy (void *abstract_font) if (font->pattern != NULL) FcPatternDestroy (font->pattern); - _destroy_font_val (font->val); + _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)font->unscaled); free (font); } static void -_utf8_to_ucs4 (char const *utf8, - FT_ULong **ucs4, - int *nchars) +_cairo_ft_font_destroy_unscaled_font (void *abstract_font) { - int len = 0, step = 0; - int n = 0, alloc = 0; - FcChar32 u = 0; + ft_unscaled_font_t *unscaled = abstract_font; - if (utf8 == NULL || ucs4 == NULL || nchars == NULL) - return; + if (!unscaled->from_face) { + cairo_cache_t *cache; + cairo_ft_cache_key_t key; + + _lock_global_ft_cache (); + cache = _get_global_ft_cache (); + assert (cache); - len = strlen (utf8); - alloc = len; - *ucs4 = malloc (sizeof (FT_ULong) * alloc); - if (*ucs4 == NULL) - return; - - while (len && (step = FcUtf8ToUcs4(utf8, &u, len)) > 0) - { - if (n == alloc) - { - alloc *= 2; - *ucs4 = realloc (*ucs4, sizeof (FT_ULong) * alloc); - if (*ucs4 == NULL) - return; - } - (*ucs4)[n++] = u; - len -= step; - utf8 += step; + key.filename = unscaled->filename; + key.id = unscaled->id; + + _cairo_cache_remove (cache, &key); + + _unlock_global_ft_cache (); } - *nchars = n; -} - -/* - * Split a matrix into the component pieces of scale and shape - */ - -static void -_cairo_ft_font_compute_transform (ft_font_transform_t *sf, cairo_font_scale_t *sc) -{ - cairo_matrix_t normalized; - double tx, ty; - /* The font matrix has x and y "scale" components which we extract and - * use as character scale values. These influence the way freetype - * chooses hints, as well as selecting different bitmaps in - * hand-rendered fonts. We also copy the normalized matrix to - * freetype's transformation. - */ - - cairo_matrix_set_affine (&normalized, - sc->matrix[0][0], - sc->matrix[0][1], - sc->matrix[1][0], - sc->matrix[1][1], - 0, 0); - - _cairo_matrix_compute_scale_factors (&normalized, - &sf->x_scale, &sf->y_scale, - /* XXX */ 1); - cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale); - cairo_matrix_get_affine (&normalized, - &sf->shape[0][0], &sf->shape[0][1], - &sf->shape[1][0], &sf->shape[1][1], - &tx, &ty); -} - -/* - * Set the font transformation - */ - -static void -_cairo_ft_font_install_transform (ft_font_transform_t *sf, FT_Face face) -{ - FT_Matrix mat; - - mat.xx = DOUBLE_TO_16_16(sf->shape[0][0]); - mat.yx = -DOUBLE_TO_16_16(sf->shape[0][1]); - mat.xy = -DOUBLE_TO_16_16(sf->shape[1][0]); - mat.yy = DOUBLE_TO_16_16(sf->shape[1][1]); + if (unscaled == NULL) + return; - FT_Set_Transform(face, &mat, NULL); + if (!unscaled->from_face && unscaled->face) + FT_Done_Face (unscaled->face); - FT_Set_Char_Size(face, - (FT_F26Dot6) (sf->x_scale * 64.0), - (FT_F26Dot6) (sf->y_scale * 64.0), - 0, 0); + if (unscaled->filename) + free (unscaled->filename); + + free (unscaled); } static void -_install_font_scale (cairo_font_scale_t *sc, FT_Face face) +_cairo_ft_font_get_glyph_cache_key (void *abstract_font, + cairo_glyph_cache_key_t *key) { - cairo_matrix_t normalized; - double x_scale, y_scale; - double xx, xy, yx, yy, tx, ty; - FT_Matrix mat; - - /* The font matrix has x and y "scale" components which we extract and - * use as character scale values. These influence the way freetype - * chooses hints, as well as selecting different bitmaps in - * hand-rendered fonts. We also copy the normalized matrix to - * freetype's transformation. - */ - - cairo_matrix_set_affine (&normalized, - sc->matrix[0][0], - sc->matrix[0][1], - sc->matrix[1][0], - sc->matrix[1][1], - 0, 0); - - _cairo_matrix_compute_scale_factors (&normalized, &x_scale, &y_scale, - /* XXX */ 1); - cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale); - cairo_matrix_get_affine (&normalized, - &xx /* 00 */ , &yx /* 01 */, - &xy /* 10 */, &yy /* 11 */, - &tx, &ty); - - mat.xx = DOUBLE_TO_16_16(xx); - mat.xy = -DOUBLE_TO_16_16(xy); - mat.yx = -DOUBLE_TO_16_16(yx); - mat.yy = DOUBLE_TO_16_16(yy); - - FT_Set_Transform(face, &mat, NULL); + cairo_ft_font_t *font = abstract_font; - FT_Set_Pixel_Sizes(face, - (FT_UInt) x_scale, - (FT_UInt) y_scale); + key->unscaled = (cairo_unscaled_font_t *)font->unscaled; + key->scale = font->base.scale; + key->flags = font->load_flags; } static cairo_status_t _cairo_ft_font_text_to_glyphs (void *abstract_font, - cairo_font_scale_t *sc, const unsigned char *utf8, cairo_glyph_t **glyphs, int *nglyphs) { double x = 0., y = 0.; size_t i; - FT_ULong *ucs4 = NULL; + uint32_t *ucs4 = NULL; cairo_ft_font_t *font = abstract_font; - FT_Face face = font->val->face; + FT_Face face; cairo_glyph_cache_key_t key; cairo_image_glyph_cache_entry_t *val; - cairo_cache_t *cache; + cairo_cache_t *cache = NULL; + cairo_status_t status = CAIRO_STATUS_SUCCESS; - key.unscaled = &font->base; - key.scale = *sc; + _cairo_ft_font_get_glyph_cache_key (font, &key); - _utf8_to_ucs4 (utf8, &ucs4, nglyphs); - - if (ucs4 == NULL) - return CAIRO_STATUS_NO_MEMORY; + status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, nglyphs); + if (!CAIRO_OK (status)) + return status; - *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t))); - if (*glyphs == NULL) - { - free (ucs4); - return CAIRO_STATUS_NO_MEMORY; + face = cairo_ft_font_lock_face ((cairo_font_t *)font); + if (!face) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL1; } _cairo_lock_global_image_glyph_cache (); cache = _cairo_get_global_image_glyph_cache (); if (cache == NULL) { - _cairo_unlock_global_image_glyph_cache (); - return CAIRO_STATUS_NO_MEMORY; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; + } + + *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t))); + if (*glyphs == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; } for (i = 0; i < *nglyphs; i++) @@ -589,51 +769,62 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font, val = NULL; key.index = (*glyphs)[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &val) + if (_cairo_cache_lookup (cache, &key, (void **) &val, NULL) != CAIRO_STATUS_SUCCESS || val == NULL) continue; x += val->extents.x_advance; y += val->extents.y_advance; } - _cairo_unlock_global_image_glyph_cache (); + FAIL2: + if (cache) + _cairo_unlock_global_image_glyph_cache (); + + cairo_ft_font_unlock_face ((cairo_font_t *)font); + + FAIL1: free (ucs4); - return CAIRO_STATUS_SUCCESS; + + return status; } static cairo_status_t _cairo_ft_font_font_extents (void *abstract_font, - cairo_font_scale_t *sc, cairo_font_extents_t *extents) { cairo_ft_font_t *font = abstract_font; - FT_Face face = font->val->face; - FT_Size_Metrics *metrics = &face->size->metrics; - ft_font_transform_t sf; + FT_Face face; + FT_Size_Metrics *metrics; + + face = _ft_unscaled_font_lock_face (font->unscaled); + if (!face) + return CAIRO_STATUS_NO_MEMORY; - _cairo_ft_font_compute_transform (&sf, sc); - _cairo_ft_font_install_transform (&sf, face); + metrics = &face->size->metrics; + _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale); + /* * Get to unscaled metrics so that the upper level can get back to * user space */ - extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / sf.y_scale; - extents->descent = DOUBLE_FROM_26_6(metrics->descender) / sf.y_scale; - extents->height = DOUBLE_FROM_26_6(metrics->height) / sf.y_scale; - extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / sf.x_scale; + extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / font->unscaled->y_scale; + extents->descent = DOUBLE_FROM_26_6(metrics->descender) / font->unscaled->y_scale; + extents->height = DOUBLE_FROM_26_6(metrics->height) / font->unscaled->y_scale; + extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / font->unscaled->x_scale; /* FIXME: this doesn't do vertical layout atm. */ extents->max_y_advance = 0.0; + _ft_unscaled_font_unlock_face (font->unscaled); + return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_ft_font_glyph_extents (void *abstract_font, - cairo_font_scale_t *sc, cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents) @@ -670,14 +861,13 @@ _cairo_ft_font_glyph_extents (void *abstract_font, return CAIRO_STATUS_NO_MEMORY; } - key.unscaled = &font->base; - key.scale = *sc; + _cairo_ft_font_get_glyph_cache_key (font, &key); for (i = 0; i < num_glyphs; i++) { img = NULL; key.index = glyphs[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &img) + if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL) != CAIRO_STATUS_SUCCESS || img == NULL) continue; @@ -721,7 +911,6 @@ _cairo_ft_font_glyph_extents (void *abstract_font, static cairo_status_t _cairo_ft_font_glyph_bbox (void *abstract_font, - cairo_font_scale_t *sc, const cairo_glyph_t *glyphs, int num_glyphs, cairo_box_t *bbox) @@ -747,16 +936,15 @@ _cairo_ft_font_glyph_bbox (void *abstract_font, return CAIRO_STATUS_NO_MEMORY; } - key.unscaled = &font->base; - key.scale = *sc; - + _cairo_ft_font_get_glyph_cache_key (font, &key); + for (i = 0; i < num_glyphs; i++) { img = NULL; key.index = glyphs[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &img) + if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL) != CAIRO_STATUS_SUCCESS || img == NULL) continue; @@ -785,12 +973,15 @@ _cairo_ft_font_glyph_bbox (void *abstract_font, static cairo_status_t _cairo_ft_font_show_glyphs (void *abstract_font, - cairo_font_scale_t *sc, cairo_operator_t operator, - cairo_surface_t *source, + cairo_pattern_t *pattern, cairo_surface_t *surface, int source_x, int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs) { @@ -798,9 +989,9 @@ _cairo_ft_font_show_glyphs (void *abstract_font, cairo_cache_t *cache; cairo_glyph_cache_key_t key; cairo_ft_font_t *font = abstract_font; + cairo_surface_pattern_t glyph_pattern; cairo_status_t status; - - double x, y; + int x, y; int i; _cairo_lock_global_image_glyph_cache (); @@ -808,47 +999,54 @@ _cairo_ft_font_show_glyphs (void *abstract_font, if (cache == NULL || font == NULL - || source == NULL + || pattern == NULL || surface == NULL || glyphs == NULL) { _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_NO_MEMORY; } - key.unscaled = &font->base; - key.scale = *sc; + key.unscaled = (cairo_unscaled_font_t *)font->unscaled; + key.scale = font->base.scale; + key.flags = font->load_flags; for (i = 0; i < num_glyphs; i++) { img = NULL; key.index = glyphs[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &img) + if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL) != CAIRO_STATUS_SUCCESS || img == NULL || img->image == NULL) continue; - x = glyphs[i].x; - y = glyphs[i].y; + x = (int) floor (glyphs[i].x + 0.5); + y = (int) floor (glyphs[i].y + 0.5); + + _cairo_pattern_init_for_surface (&glyph_pattern, &(img->image->base)); - status = _cairo_surface_composite (operator, source, - &(img->image->base), + status = _cairo_surface_composite (operator, pattern, + &glyph_pattern.base, surface, - source_x + x + img->size.x, - source_y + y + img->size.y, + x + img->size.x, + y + img->size.y, 0, 0, x + img->size.x, y + img->size.y, (double) img->size.width, (double) img->size.height); + _cairo_pattern_fini (&glyph_pattern.base); + if (status) { - _cairo_unlock_global_image_glyph_cache (); + _cairo_unlock_global_image_glyph_cache (); return status; } } + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_SUCCESS; } @@ -932,7 +1130,6 @@ _cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closur static cairo_status_t _cairo_ft_font_glyph_path (void *abstract_font, - cairo_font_scale_t *sc, cairo_glyph_t *glyphs, int num_glyphs, cairo_path_t *path) @@ -940,6 +1137,7 @@ _cairo_ft_font_glyph_path (void *abstract_font, int i; cairo_ft_font_t *font = abstract_font; FT_GlyphSlot glyph; + FT_Face face; FT_Error error; FT_Outline_Funcs outline_funcs = { _move_to, @@ -949,10 +1147,12 @@ _cairo_ft_font_glyph_path (void *abstract_font, 0, /* shift */ 0, /* delta */ }; + + face = cairo_ft_font_lock_face (abstract_font); + if (!face) + return CAIRO_STATUS_NO_MEMORY; - glyph = font->val->face->glyph; - - _install_font_scale (sc, font->val->face); + glyph = face->glyph; for (i = 0; i < num_glyphs; i++) { @@ -961,7 +1161,7 @@ _cairo_ft_font_glyph_path (void *abstract_font, 0, DOUBLE_TO_16_16 (-1.0), }; - error = FT_Load_Glyph (font->val->face, glyphs[i].index, FT_LOAD_DEFAULT); + error = FT_Load_Glyph (font->unscaled->face, glyphs[i].index, font->load_flags | FT_LOAD_NO_BITMAP); /* XXX: What to do in this error case? */ if (error) continue; @@ -977,32 +1177,39 @@ _cairo_ft_font_glyph_path (void *abstract_font, FT_Outline_Decompose (&glyph->outline, &outline_funcs, path); } _cairo_path_close_path (path); + + cairo_ft_font_unlock_face (abstract_font); return CAIRO_STATUS_SUCCESS; } - static cairo_status_t -_cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) +_cairo_ft_font_create_glyph (cairo_image_glyph_cache_entry_t *val) { - cairo_ft_font_t *font = (cairo_ft_font_t *)val->key.unscaled; + ft_unscaled_font_t *unscaled = (ft_unscaled_font_t *)val->key.unscaled; FT_GlyphSlot glyphslot; unsigned int width, height, stride; + FT_Face face; FT_Outline *outline; FT_BBox cbox; FT_Bitmap bitmap; FT_Glyph_Metrics *metrics; - ft_font_transform_t sf; + cairo_status_t status = CAIRO_STATUS_SUCCESS; - glyphslot = font->val->face->glyph; + glyphslot = unscaled->face->glyph; metrics = &glyphslot->metrics; - _cairo_ft_font_compute_transform (&sf, &val->key.scale); - _cairo_ft_font_install_transform (&sf, font->val->face); - - if (FT_Load_Glyph (font->val->face, val->key.index, FT_LOAD_DEFAULT) != 0) + face = _ft_unscaled_font_lock_face (unscaled); + if (!face) return CAIRO_STATUS_NO_MEMORY; + _ft_unscaled_font_set_scale (unscaled, &val->key.scale); + + if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } + /* * Note: the font's coordinate system is upside down from ours, so the * Y coordinates of the bearing and advance need to be negated. @@ -1011,11 +1218,11 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) * by FreeType */ - val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / sf.x_scale; - val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / sf.y_scale; + val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale; + val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale; - val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / sf.x_scale; - val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / sf.y_scale; + val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale; + val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale; /* * use untransformed advance values @@ -1023,8 +1230,8 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) should provide FT_LOAD_VERTICAL_LAYOUT */ - val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->metrics.horiAdvance) / sf.x_scale; - val->extents.y_advance = 0 / sf.y_scale; + val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale; + val->extents.y_advance = 0 / unscaled->y_scale; outline = &glyphslot->outline; @@ -1052,14 +1259,16 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) bitmap.buffer = calloc (1, stride * height); if (bitmap.buffer == NULL) { - return CAIRO_STATUS_NO_MEMORY; - }; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin); if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) { free (bitmap.buffer); - return CAIRO_STATUS_NO_MEMORY; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; } val->image = (cairo_image_surface_t *) @@ -1068,7 +1277,8 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) width, height, stride); if (val->image == NULL) { free (bitmap.buffer); - return CAIRO_STATUS_NO_MEMORY; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; } _cairo_image_surface_assume_ownership_of_data (val->image); @@ -1084,138 +1294,245 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) val->size.x = (short) (cbox.xMin >> 6); val->size.y = - (short) (cbox.yMax >> 6); - return CAIRO_STATUS_SUCCESS; + FAIL: + _ft_unscaled_font_unlock_face (unscaled); + + return status; } const cairo_font_backend_t cairo_ft_font_backend = { _cairo_ft_font_create, - _cairo_ft_font_destroy, + _cairo_ft_font_destroy_font, + _cairo_ft_font_destroy_unscaled_font, _cairo_ft_font_font_extents, _cairo_ft_font_text_to_glyphs, _cairo_ft_font_glyph_extents, _cairo_ft_font_glyph_bbox, _cairo_ft_font_show_glyphs, _cairo_ft_font_glyph_path, + _cairo_ft_font_get_glyph_cache_key, _cairo_ft_font_create_glyph }; - /* implement the platform-specific interface */ +/** + * cairo_ft_font_create: + * @pattern: A fully resolved fontconfig + * pattern. A pattern can be resolved, by, among other things, calling + * FcConfigSubstitute(), FcDefaultSubstitute(), then + * FcFontMatch(). Cairo will call FcPatternReference() on this + * pattern, so you should not further modify the pattern, but you can + * release your reference to the pattern with FcPatternDestroy() if + * you no longer need to access it. + * @scale: The scale at which this font will be used. The + * scale is given by multiplying the font matrix (see + * cairo_transform_font()) by the current transformation matrix. + * The translation elements of the resulting matrix are ignored. + * + * Creates a new font for the FreeType font backend based on a + * fontconfig pattern. This font can then be used with + * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend + * specific functions like cairo_ft_font_lock_face(). + * + * Return value: a newly created #cairo_font_t. Free with + * cairo_font_destroy() when you are done using it. + **/ cairo_font_t * -cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern) +cairo_ft_font_create (FcPattern *pattern, + cairo_matrix_t *scale) { - cairo_font_scale_t scale; - cairo_font_t *scaled; - cairo_ft_font_t *f = NULL; - ft_font_val_t *v = NULL; - FcPattern *dup; - - scale.matrix[0][0] = 1.; - scale.matrix[0][1] = 0.; - scale.matrix[1][0] = 0.; - scale.matrix[1][1] = 1.; - - scaled = malloc (sizeof (cairo_font_t)); - if (scaled == NULL) - goto FAIL; - - dup = FcPatternDuplicate(pattern); - if (dup == NULL) - goto FREE_SCALED; - - v = _create_from_library_and_pattern (ft_library, pattern); - if (v == NULL) - goto FREE_PATTERN; - - f = malloc (sizeof(cairo_ft_font_t)); - if (f == NULL) - goto FREE_VAL; - - if (_cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend)) - goto FREE_VAL; - - f->pattern = dup; - f->val = v; - - _cairo_font_init (scaled, &scale, &f->base); - - return scaled; - - FREE_VAL: - _destroy_font_val (v); - - FREE_PATTERN: - FcPatternDestroy (dup); + cairo_font_scale_t sc; + double tx, ty; - FREE_SCALED: - free (scaled); + cairo_matrix_get_affine (scale, + &sc.matrix[0][0], &sc.matrix[0][1], + &sc.matrix[1][0], &sc.matrix[1][1], + &tx, &ty); - FAIL: - return NULL; + return _ft_font_create (pattern, &sc); } +/** + * cairo_ft_font_create_for_ft_face: + * @face: A FreeType face object, already opened. This must + * be kept around until the font object's refcount drops to + * zero and it is freed. The font object can be kept alive by + * internal caching, so it's safest to keep the face object + * around forever. + * @load_flags: The flags to pass to FT_Load_Glyph when loading + * glyphs from the font. These flags control aspects of + * rendering such as hinting and antialiasing. See the FreeType + * docs for full information. + * @scale: The scale at which this font will be used. The + * scale is given by multiplying the font matrix (see + * cairo_transform_font()) by the current transformation matrix. + * The translation elements of the resulting matrix are ignored. + * + * Creates a new font forthe FreeType font backend from a pre-opened + * FreeType face. This font can then be used with cairo_set_font(), + * cairo_font_glyph_extents(), or FreeType backend specific + * functions like cairo_ft_font_lock_face() Cairo will determine the + * pixel size and transformation from the @scale parameter and call + * FT_Set_Transform() and FT_Set_Pixel_Sizes(). + * + * Return value: a newly created #cairo_font_t. Free with + * cairo_font_destroy() when you are done using it. + **/ cairo_font_t * -cairo_ft_font_create_for_ft_face (FT_Face face) +cairo_ft_font_create_for_ft_face (FT_Face face, + int load_flags, + cairo_matrix_t *scale) { - cairo_font_scale_t scale; - cairo_font_t *scaled; cairo_ft_font_t *f = NULL; - ft_font_val_t *v = NULL; - - scale.matrix[0][0] = 1.; - scale.matrix[0][1] = 0.; - scale.matrix[1][0] = 0.; - scale.matrix[1][1] = 1.; - - scaled = malloc (sizeof (cairo_font_t)); - if (scaled == NULL) - goto FAIL; + ft_unscaled_font_t *unscaled = NULL; + cairo_font_scale_t sc; + double tx, ty; - v = _create_from_face (face, 0); - if (v == NULL) - goto FREE_SCALED; + unscaled = _ft_unscaled_font_create_from_face (face); + if (unscaled == NULL) + return NULL; f = malloc (sizeof(cairo_ft_font_t)); if (f == NULL) - goto FREE_VAL; + goto FREE_UNSCALED; - _cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend); + f->unscaled = unscaled; f->pattern = NULL; - f->val = v; + f->load_flags = load_flags; - _cairo_font_init (scaled, &scale, &f->base); + cairo_matrix_get_affine (scale, + &sc.matrix[0][0], &sc.matrix[0][1], + &sc.matrix[1][0], &sc.matrix[1][1], + &tx, &ty); - return scaled; + _cairo_font_init ((cairo_font_t *)f, &sc, &cairo_ft_font_backend); - FREE_VAL: - _destroy_font_val (v); + return (cairo_font_t *)f; - FREE_SCALED: - free (scaled); + FREE_UNSCALED: + _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled); - FAIL: return NULL; } + +/** + * cairo_ft_font_lock_face: + * @ft_font: A #cairo_font_t from the FreeType font backend. Such an + * object can be created with cairo_ft_font_create() or + * cairo_ft_font_create_for_ft_face(). On some platforms the font from + * cairo_current_font() will also be a FreeType font, but using this + * functionality with fonts you don't create yourself is not + * recommended. + * + * cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType + * backend font and scales it appropriately for the font. You must + * release the face with cairo_ft_font_unlock_face() + * when you are done using it. Since the #FT_Face object can be + * shared between multiple #cairo_font_t objects, you must not + * lock any other font objects until you unlock this one. A count is + * kept of the number of times cairo_ft_font_lock_face() is + * called. cairo_ft_font_unlock_face() must be called the same number + * of times. + * + * You must be careful when using this function in a library or in a + * threaded application, because other threads may lock faces that + * share the same #FT_Face object. For this reason, you must call + * cairo_ft_lock() before locking any face objects, and + * cairo_ft_unlock() after you are done. (These functions are not yet + * implemented, so this function cannot be currently safely used in a + * threaded application.) + + * Return value: The #FT_Face object for @font, scaled appropriately. + **/ FT_Face -cairo_ft_font_face (cairo_font_t *abstract_font) +cairo_ft_font_lock_face (cairo_font_t *abstract_font) { - cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled; + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + FT_Face face; - if (font == NULL || font->val == NULL) - return NULL; + face = _ft_unscaled_font_lock_face (font->unscaled); + if (!face) + return NULL; + + _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale); + + return face; +} - return font->val->face; +/** + * cairo_ft_font_unlock_face: + * @ft_font: A #cairo_font_t from the FreeType font backend. Such an + * object can be created with cairo_ft_font_create() or + * cairo_ft_font_create_for_ft_face(). On some platforms the font from + * cairo_current_font() will also be a FreeType font, but using this + * functionality with fonts you don't create yourself is not + * recommended. + * + * Releases a face obtained with cairo_ft_font_lock_face(). See the + * documentation for that function for full details. + **/ +void +cairo_ft_font_unlock_face (cairo_font_t *abstract_font) +{ + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + + _ft_unscaled_font_unlock_face (font->unscaled); } +/** + * cairo_ft_font_get_pattern: + * @ft_font: A #cairo_font_t from the FreeType font backend. Such an + * object can be created with cairo_ft_font_create() or + * cairo_ft_font_create_for_ft_face(). On some platforms the font from + * cairo_current_font() will also be a FreeType font, but using this + * functionality with fonts you don't create yourself is not + * recommended. + * + * cairo_ft_font_get_pattern() gets the #FcPattern for a FreeType + * backend font. + + * Return value: The #FcPattenr for @font. The return value is owned + * by the font, so you must not modify it, and must call + * FcPatternReference() to keep a persistant reference to the + * pattern. If the font was created with cairo_ft_font_create_for_ft_face() + * returns %NULL. + **/ FcPattern * -cairo_ft_font_pattern (cairo_font_t *abstract_font) +cairo_ft_font_get_pattern (cairo_font_t *abstract_font) { - cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled; + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; if (font == NULL) return NULL; return font->pattern; } + +/* We expose our unscaled font implementation internally for the the + * PDF backend, which needs to keep track of the the different + * fonts-on-disk used by a document, so it can embed them. + */ +cairo_unscaled_font_t * +_cairo_ft_font_get_unscaled_font (cairo_font_t *abstract_font) +{ + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + + return (cairo_unscaled_font_t *)font->unscaled; +} + +/* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't + * set the scale on the face, but just returns it at the last scale. + */ +FT_Face +_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font) +{ + return _ft_unscaled_font_lock_face ((ft_unscaled_font_t *)unscaled_font); +} + +void +_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font) +{ + _ft_unscaled_font_unlock_face ((ft_unscaled_font_t *)unscaled_font); +} diff --git a/src/cairo-ft-private.h b/src/cairo-ft-private.h new file mode 100644 index 000000000..37a6feecc --- /dev/null +++ b/src/cairo-ft-private.h @@ -0,0 +1,63 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Graydon Hoare <graydon@redhat.com> + * Owen Taylor <otaylor@redhat.com> + */ + +#ifndef CAIRO_FT_PRIVATE_H +#define CAIRO_FT_PRIVATE_H + +#include <cairo-ft.h> +#include <cairoint.h> + +#ifdef CAIRO_HAS_FT_FONT + +CAIRO_BEGIN_DECLS + +/* These functions are needed by the PDF backend, which needs to keep track of the + * the different fonts-on-disk used by a document, so it can embed them + */ +cairo_private cairo_unscaled_font_t * +_cairo_ft_font_get_unscaled_font (cairo_font_t *font); + +cairo_private FT_Face +_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font); + +cairo_private void +_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font); + +CAIRO_END_DECLS + +#endif /* CAIRO_HAS_FT_FONT */ + +#endif /* CAIRO_FT_PRIVATE_H */ diff --git a/src/cairo-ft.h b/src/cairo-ft.h index 57d439ab2..f10c67d80 100644 --- a/src/cairo-ft.h +++ b/src/cairo-ft.h @@ -1,6 +1,6 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -27,17 +27,18 @@ * * The Original Code is the cairo graphics library. * - * The Initial Developer of the Original Code is University of Southern - * California. + * The Initial Developer of the Original Code is Red Hat, Inc. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Graydon Hoare <graydon@redhat.com> + * Owen Taylor <otaylor@redhat.com> */ -#include <cairo.h> - #ifndef CAIRO_FT_H #define CAIRO_FT_H + +#include <cairo.h> + #ifdef CAIRO_HAS_FT_FONT /* Fontconfig/Freetype platform-specific font interface */ @@ -46,17 +47,27 @@ #include <ft2build.h> #include FT_FREETYPE_H +CAIRO_BEGIN_DECLS + cairo_font_t * -cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern); +cairo_ft_font_create (FcPattern *pattern, + cairo_matrix_t *scale); cairo_font_t * -cairo_ft_font_create_for_ft_face (FT_Face face); +cairo_ft_font_create_for_ft_face (FT_Face face, + int load_flags, + cairo_matrix_t *scale); FT_Face -cairo_ft_font_face (cairo_font_t *ft_font); +cairo_ft_font_lock_face (cairo_font_t *ft_font); + +void +cairo_ft_font_unlock_face (cairo_font_t *ft_font); FcPattern * -cairo_ft_font_pattern (cairo_font_t *ft_font); +cairo_ft_font_get_pattern (cairo_font_t *ft_font); + +CAIRO_END_DECLS #endif /* CAIRO_HAS_FT_FONT */ #endif /* CAIRO_FT_H */ diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index 69fc82f2e..ee664e1cc 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -21,30 +21,12 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * Author: David Reveman <c99drn@cs.umu.se> + * Author: David Reveman <davidr@novell.com> */ #include "cairoint.h" #include "cairo-glitz.h" -#define GLITZ_FIXED_TO_FLOAT(f) \ - (((glitz_float_t) (f)) / 65536) - -#define GLITZ_FIXED_LINE_X_TO_FLOAT(line, v) \ - (((glitz_float_t) \ - ((line).p1.x + (cairo_fixed_16_16_t) \ - (((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ - ((line).p2.x - (line).p1.x)) / \ - ((line).p2.y - (line).p1.y)))) / 65536) - -#define GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \ - (((glitz_float_t) \ - ((line).p1.x + (cairo_fixed_16_16_t) \ - (((((line).p2.y - (line).p1.y) - 1) + \ - ((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ - ((line).p2.x - (line).p1.x))) / \ - ((line).p2.y - (line).p1.y)))) / 65536) - void cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface) { @@ -65,13 +47,11 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface) } typedef struct _cairo_glitz_surface { - cairo_surface_t base; - - glitz_surface_t *surface; - glitz_format_t *format; + cairo_surface_t base; - cairo_pattern_t pattern; - cairo_box_t pattern_box; + glitz_surface_t *surface; + glitz_format_t *format; + pixman_region16_t *clip; } cairo_glitz_surface_t; static void @@ -79,11 +59,60 @@ _cairo_glitz_surface_destroy (void *abstract_surface) { cairo_glitz_surface_t *surface = abstract_surface; + if (surface->clip) + { + glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); + pixman_region_destroy (surface->clip); + } + glitz_surface_destroy (surface->surface); + free (surface); +} - _cairo_pattern_fini (&surface->pattern); +static glitz_format_name_t +_glitz_format (cairo_format_t format) +{ + switch (format) { + default: + case CAIRO_FORMAT_ARGB32: + return GLITZ_STANDARD_ARGB32; + case CAIRO_FORMAT_RGB24: + return GLITZ_STANDARD_RGB24; + case CAIRO_FORMAT_A8: + return GLITZ_STANDARD_A8; + case CAIRO_FORMAT_A1: + return GLITZ_STANDARD_A1; + } +} - free (surface); +static cairo_surface_t * +_cairo_glitz_surface_create_similar (void *abstract_src, + cairo_format_t format, + int draw, + int width, + int height) +{ + cairo_glitz_surface_t *src = abstract_src; + cairo_surface_t *crsurface; + glitz_drawable_t *drawable; + glitz_surface_t *surface; + glitz_format_t *gformat; + + drawable = glitz_surface_get_drawable (src->surface); + + gformat = glitz_find_standard_format (drawable, _glitz_format (format)); + if (!gformat) + return NULL; + + surface = glitz_surface_create (drawable, gformat, width, height, 0, NULL); + if (!surface) + return NULL; + + crsurface = cairo_glitz_surface_create (surface); + + glitz_surface_destroy (surface); + + return crsurface; } static double @@ -92,31 +121,54 @@ _cairo_glitz_surface_pixels_per_inch (void *abstract_surface) return 96.0; } -static cairo_image_surface_t * -_cairo_glitz_surface_get_image (void *abstract_surface) +static cairo_status_t +_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, + cairo_rectangle_t *interest, + cairo_image_surface_t **image_out, + cairo_rectangle_t *rect_out) { - cairo_glitz_surface_t *surface = abstract_surface; cairo_image_surface_t *image; - char *pixels; - int width, height; - cairo_format_masks_t format; - glitz_buffer_t *buffer; - glitz_pixel_format_t pf; - - if (surface->pattern.type != CAIRO_PATTERN_SURFACE) { - cairo_box_t box; - - box.p1.x = box.p1.y = 0; - box.p2.x = surface->pattern_box.p2.x; - box.p2.y = surface->pattern_box.p2.y; - - return _cairo_pattern_get_image (&surface->pattern, &box); + int x1, y1, x2, y2; + int width, height; + char *pixels; + cairo_format_masks_t format; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + + x1 = 0; + y1 = 0; + x2 = glitz_surface_get_width (surface->surface); + y2 = glitz_surface_get_height (surface->surface); + + if (interest) + { + if (interest->x > x1) + x1 = interest->x; + if (interest->y > y1) + y1 = interest->y; + if (interest->x + interest->width < x2) + x2 = interest->x + interest->width; + if (interest->y + interest->height < y2) + y2 = interest->y + interest->height; + + if (x1 >= x2 || y1 >= y2) + { + *image_out = NULL; + return CAIRO_STATUS_SUCCESS; + } } + width = x2 - x1; + height = y2 - y1; - width = glitz_surface_get_width (surface->surface); - height = glitz_surface_get_height (surface->surface); - + if (rect_out) + { + rect_out->x = x1; + rect_out->y = y1; + rect_out->width = width; + rect_out->height = height; + } + if (surface->format->type == GLITZ_FORMAT_TYPE_COLOR) { if (surface->format->color.red_size > 0) { format.bpp = 32; @@ -149,21 +201,24 @@ _cairo_glitz_surface_get_image (void *abstract_surface) pf.masks.blue_mask = format.blue_mask; pf.xoffset = 0; pf.skip_lines = 0; + + /* XXX: we should eventually return images with negative stride, + need to verify that libpixman have no problem with this first. */ pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4; pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; pixels = malloc (height * pf.bytes_per_line); if (!pixels) - return NULL; + return CAIRO_STATUS_NO_MEMORY; buffer = glitz_buffer_create_for_data (pixels); if (!buffer) { free (pixels); - return NULL; + return CAIRO_STATUS_NO_MEMORY; } glitz_get_pixels (surface->surface, - 0, 0, + x1, y1, width, height, &pf, buffer); @@ -175,27 +230,38 @@ _cairo_glitz_surface_get_image (void *abstract_surface) &format, width, height, pf.bytes_per_line); - + + if (!image) + { + free (pixels); + return CAIRO_STATUS_NO_MEMORY; + } + _cairo_image_surface_assume_ownership_of_data (image); _cairo_image_surface_set_repeat (image, surface->base.repeat); _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - return image; + *image_out = image; + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_glitz_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +_cairo_glitz_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image, + int x_dst, + int y_dst) { cairo_glitz_surface_t *surface = abstract_surface; - glitz_buffer_t *buffer; - glitz_pixel_format_t pf; - pixman_format_t *format; - int am, rm, gm, bm; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + pixman_format_t *format; + int am, rm, gm, bm; + char *data; format = pixman_image_get_format (image->pixman_image); - if (format == NULL) + if (!format) return CAIRO_STATUS_NO_MEMORY; pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm); @@ -206,15 +272,27 @@ _cairo_glitz_surface_set_image (void *abstract_surface, pf.masks.blue_mask = bm; pf.xoffset = 0; pf.skip_lines = 0; - pf.bytes_per_line = image->stride; - pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; - buffer = glitz_buffer_create_for_data (image->data); + /* check for negative stride */ + if (image->stride < 0) + { + pf.bytes_per_line = -image->stride; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP; + data = (char *) image->data + image->stride * (image->height - 1); + } + else + { + pf.bytes_per_line = image->stride; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + data = (char *) image->data; + } + + buffer = glitz_buffer_create_for_data (data); if (!buffer) return CAIRO_STATUS_NO_MEMORY; glitz_set_pixels (surface->surface, - 0, 0, + x_dst, y_dst, image->width, image->height, &pf, buffer); @@ -225,63 +303,118 @@ _cairo_glitz_surface_set_image (void *abstract_surface, } static cairo_status_t -_cairo_glitz_surface_set_matrix (void *abstract_surface, - cairo_matrix_t *matrix) +_cairo_glitz_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { cairo_glitz_surface_t *surface = abstract_surface; - glitz_transform_t transform; - transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); - transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); - transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); + *image_extra = NULL; + + return _cairo_glitz_surface_get_image (surface, NULL, image_out, NULL); +} - transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); - transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); - transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); +static void +_cairo_glitz_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); +} - transform.matrix[2][0] = 0; - transform.matrix[2][1] = 0; - transform.matrix[2][2] = 1 << 16; +static cairo_status_t +_cairo_glitz_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect_out, + void **image_extra) +{ + cairo_glitz_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; - glitz_surface_set_transform (surface->surface, &transform); + status = _cairo_glitz_surface_get_image (surface, interest_rect, &image, + image_rect_out); + if (status) + return status; - return CAIRO_STATUS_SUCCESS; + *image_out = image; + *image_extra = NULL; + + return status; } +static void +_cairo_glitz_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + _cairo_glitz_surface_set_image (surface, image, + image_rect->x, image_rect->y); + + cairo_surface_destroy (&image->base); +} + + static cairo_status_t -_cairo_glitz_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +_cairo_glitz_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { cairo_glitz_surface_t *surface = abstract_surface; - glitz_filter_t glitz_filter; + cairo_glitz_surface_t *clone; - switch (filter) { - case CAIRO_FILTER_FAST: - case CAIRO_FILTER_NEAREST: - glitz_filter = GLITZ_FILTER_NEAREST; - break; - case CAIRO_FILTER_GOOD: - case CAIRO_FILTER_BEST: - case CAIRO_FILTER_BILINEAR: - default: - glitz_filter = GLITZ_FILTER_BILINEAR; - break; + if (src->backend == surface->base.backend) + { + *clone_out = src; + cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; } + else if (_cairo_surface_is_image (src)) + { + cairo_image_surface_t *image_src = (cairo_image_surface_t *) src; + + clone = (cairo_glitz_surface_t *) + _cairo_glitz_surface_create_similar (surface, image_src->format, 0, + image_src->width, + image_src->height); + if (!clone) + return CAIRO_STATUS_NO_MEMORY; - glitz_surface_set_filter (surface->surface, glitz_filter, NULL, 0); + _cairo_glitz_surface_set_image (clone, image_src, 0, 0); + + *clone_out = &clone->base; - return CAIRO_STATUS_SUCCESS; + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_status_t -_cairo_glitz_surface_set_repeat (void *abstract_surface, int repeat) +static void +_cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface, + cairo_matrix_t *matrix) { - cairo_glitz_surface_t *surface = abstract_surface; + glitz_transform_t transform; + + transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); + transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); + transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); - glitz_surface_set_fill (surface->surface, - (repeat)? GLITZ_FILL_REPEAT: - GLITZ_FILL_TRANSPARENT); + transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); + transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); + transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); - return CAIRO_STATUS_SUCCESS; + transform.matrix[2][0] = 0; + transform.matrix[2][1] = 0; + transform.matrix[2][2] = 1 << 16; + + glitz_surface_set_transform (surface->surface, &transform); } static glitz_operator_t @@ -318,32 +451,6 @@ _glitz_operator (cairo_operator_t op) } } -static glitz_surface_t * -_glitz_surface_create_solid (glitz_surface_t *other, - glitz_format_name_t format_name, - glitz_color_t *color) -{ - glitz_drawable_t *drawable; - glitz_format_t *format; - glitz_surface_t *surface; - - drawable = glitz_surface_get_drawable (other); - - format = glitz_find_standard_format (drawable, format_name); - if (format == NULL) - return NULL; - - surface = glitz_surface_create (drawable, format, 1, 1); - if (surface == NULL) - return NULL; - - glitz_set_rectangle (surface, color, 0, 0, 1, 1); - - glitz_surface_set_fill (surface, GLITZ_FILL_REPEAT); - - return surface; -} - static glitz_status_t _glitz_ensure_target (glitz_surface_t *surface) { @@ -355,7 +462,6 @@ _glitz_ensure_target (glitz_surface_t *surface) glitz_drawable_format_t templ; glitz_format_t *format; glitz_drawable_t *pbuffer; - glitz_pbuffer_attributes_t attributes; unsigned long mask; int i; @@ -397,21 +503,13 @@ _glitz_ensure_target (glitz_surface_t *surface) if (!dformat) return CAIRO_INT_STATUS_UNSUPPORTED; - attributes.width = glitz_surface_get_width (surface); - attributes.height = glitz_surface_get_height (surface); - mask = GLITZ_PBUFFER_WIDTH_MASK | GLITZ_PBUFFER_HEIGHT_MASK; - - pbuffer = glitz_create_pbuffer_drawable (drawable, dformat, - &attributes, mask); + pbuffer = + glitz_create_pbuffer_drawable (drawable, dformat, + glitz_surface_get_width (surface), + glitz_surface_get_height (surface)); if (!pbuffer) return CAIRO_INT_STATUS_UNSUPPORTED; - if (glitz_drawable_get_width (pbuffer) < attributes.width || - glitz_drawable_get_height (pbuffer) < attributes.height) { - glitz_drawable_destroy (pbuffer); - return CAIRO_INT_STATUS_UNSUPPORTED; - } - glitz_surface_attach (surface, pbuffer, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR, 0, 0); @@ -422,388 +520,711 @@ _glitz_ensure_target (glitz_surface_t *surface) return CAIRO_STATUS_SUCCESS; } -static glitz_format_name_t -_glitz_format (cairo_format_t format) +typedef struct _cairo_glitz_surface_attributes { + cairo_surface_attributes_t base; + + glitz_fill_t fill; + glitz_filter_t filter; + glitz_fixed16_16_t *params; + int n_params; + cairo_bool_t acquired; +} cairo_glitz_surface_attributes_t; + +static cairo_int_status_t +_cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, + cairo_glitz_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_glitz_surface_t **surface_out, + cairo_glitz_surface_attributes_t *attr) { - switch (format) { + cairo_glitz_surface_t *src = NULL; + + attr->acquired = FALSE; + + switch (pattern->type) { + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_gradient_pattern_t *gradient = + (cairo_gradient_pattern_t *) pattern; + glitz_drawable_t *drawable; + glitz_fixed16_16_t *params; + int n_params; + int i; + unsigned short alpha; + + /* XXX: the current color gradient acceleration provided by glitz is + * experimental, it's been proven inappropriate in a number of ways, + * most importantly, it's currently implemented as filters and + * gradients are not filters. eventually, it will be replaced with + * something more appropriate. + */ + + if (gradient->n_stops < 2) + break; + + /* glitz doesn't support inner and outer circle with different + center points. */ + if (pattern->type == CAIRO_PATTERN_RADIAL) + { + cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern; + + if (grad->center0.x != grad->center1.x || + grad->center0.y != grad->center1.y) + break; + } + + drawable = glitz_surface_get_drawable (dst->surface); + if (!(glitz_drawable_get_features (drawable) & + GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK)) + break; + + if (pattern->filter != CAIRO_FILTER_BILINEAR && + pattern->filter != CAIRO_FILTER_GOOD && + pattern->filter != CAIRO_FILTER_BEST) + break; + + alpha = (gradient->stops[0].color.alpha * pattern->alpha) * 0xffff; + for (i = 1; i < gradient->n_stops; i++) + { + unsigned short a; + + a = (gradient->stops[i].color.alpha * pattern->alpha) * 0xffff; + if (a != alpha) + break; + } + + /* we can't have color stops with different alpha as gradient color + interpolation should be done to unpremultiplied colors. */ + if (i < gradient->n_stops) + break; + + n_params = gradient->n_stops * 3 + 4; + + params = malloc (sizeof (glitz_fixed16_16_t) * n_params); + if (!params) + return CAIRO_STATUS_NO_MEMORY; + + src = (cairo_glitz_surface_t *) + _cairo_surface_create_similar_scratch (&dst->base, + CAIRO_FORMAT_ARGB32, 0, + gradient->n_stops, 1); + if (!src) + { + free (params); + return CAIRO_STATUS_NO_MEMORY; + } + + for (i = 0; i < gradient->n_stops; i++) { + glitz_color_t color; + + color.red = gradient->stops[i].color.red * alpha; + color.green = gradient->stops[i].color.green * alpha; + color.blue = gradient->stops[i].color.blue * alpha; + color.alpha = alpha; + + glitz_set_rectangle (src->surface, &color, i, 0, 1, 1); + + params[4 + 3 * i] = gradient->stops[i].offset; + params[5 + 3 * i] = i << 16; + params[6 + 3 * i] = 0; + } + + if (pattern->type == CAIRO_PATTERN_LINEAR) + { + cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern; + + params[0] = _cairo_fixed_from_double (grad->point0.x); + params[1] = _cairo_fixed_from_double (grad->point0.y); + params[2] = _cairo_fixed_from_double (grad->point1.x); + params[3] = _cairo_fixed_from_double (grad->point1.y); + attr->filter = GLITZ_FILTER_LINEAR_GRADIENT; + } + else + { + cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern; + + params[0] = _cairo_fixed_from_double (grad->center0.x); + params[1] = _cairo_fixed_from_double (grad->center0.y); + params[2] = _cairo_fixed_from_double (grad->radius0); + params[3] = _cairo_fixed_from_double (grad->radius1); + attr->filter = GLITZ_FILTER_RADIAL_GRADIENT; + } + + switch (pattern->extend) { + case CAIRO_EXTEND_NONE: + attr->fill = GLITZ_FILL_NEAREST; + break; + case CAIRO_EXTEND_REPEAT: + attr->fill = GLITZ_FILL_REPEAT; + break; + case CAIRO_EXTEND_REFLECT: + attr->fill = GLITZ_FILL_REFLECT; + break; + } + + attr->params = params; + attr->n_params = n_params; + attr->base.matrix = pattern->matrix; + attr->base.x_offset = 0; + attr->base.y_offset = 0; + } break; default: - case CAIRO_FORMAT_ARGB32: - return GLITZ_STANDARD_ARGB32; - case CAIRO_FORMAT_RGB24: - return GLITZ_STANDARD_RGB24; - case CAIRO_FORMAT_A8: - return GLITZ_STANDARD_A8; - case CAIRO_FORMAT_A1: - return GLITZ_STANDARD_A1; + break; } -} -static cairo_surface_t * -_cairo_glitz_surface_create_similar (void *abstract_src, - cairo_format_t format, - int draw, - int width, - int height) -{ - cairo_glitz_surface_t *src = abstract_src; - cairo_surface_t *crsurface; - glitz_drawable_t *drawable; - glitz_surface_t *surface; - glitz_format_t *gformat; + if (!src) + { + cairo_int_status_t status; - drawable = glitz_surface_get_drawable (src->surface); - - gformat = glitz_find_standard_format (drawable, _glitz_format (format)); - if (gformat == NULL) - return NULL; - - surface = glitz_surface_create (drawable, gformat, width, height); - if (surface == NULL) - return NULL; + status = _cairo_pattern_acquire_surface (pattern, &dst->base, + x, y, width, height, + (cairo_surface_t **) &src, + &attr->base); + if (status) + return status; + + if (src) + { + switch (attr->base.extend) { + case CAIRO_EXTEND_NONE: + attr->fill = GLITZ_FILL_TRANSPARENT; + break; + case CAIRO_EXTEND_REPEAT: + attr->fill = GLITZ_FILL_REPEAT; + break; + case CAIRO_EXTEND_REFLECT: + attr->fill = GLITZ_FILL_REFLECT; + break; + } - crsurface = cairo_glitz_surface_create (surface); - - glitz_surface_destroy (surface); + switch (attr->base.filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + attr->filter = GLITZ_FILTER_NEAREST; + break; + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + default: + attr->filter = GLITZ_FILTER_BILINEAR; + break; + } + + attr->params = NULL; + attr->n_params = 0; + attr->acquired = TRUE; + } + } - return crsurface; + *surface_out = src; + + return CAIRO_STATUS_SUCCESS; } -static cairo_glitz_surface_t * -_cairo_glitz_surface_clone_similar (cairo_glitz_surface_t *templ, - cairo_surface_t *src, - cairo_format_t format) +static void +_cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst, + cairo_glitz_surface_t *surface, + cairo_glitz_surface_attributes_t *attr) { - cairo_glitz_surface_t *clone; - cairo_image_surface_t *src_image; + if (attr->acquired) + _cairo_pattern_release_surface (&dst->base, &surface->base, + &attr->base); + else + _cairo_glitz_surface_destroy (surface); +} - src_image = _cairo_surface_get_image (src); +static cairo_int_status_t +_cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src, + cairo_pattern_t *mask, + cairo_glitz_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + unsigned int width, + unsigned int height, + cairo_glitz_surface_t **src_out, + cairo_glitz_surface_t **mask_out, + cairo_glitz_surface_attributes_t *sattr, + cairo_glitz_surface_attributes_t *mattr) +{ + cairo_int_status_t status; + cairo_pattern_union_t tmp; + cairo_bool_t src_opaque, mask_opaque; + double src_alpha, mask_alpha; - clone = (cairo_glitz_surface_t *) - _cairo_glitz_surface_create_similar (templ, format, 0, - src_image->width, - src_image->height); - if (clone == NULL) - return NULL; - - _cairo_glitz_surface_set_filter (clone, cairo_surface_get_filter (src)); + src_opaque = _cairo_pattern_is_opaque (src); + mask_opaque = !mask || _cairo_pattern_is_opaque (mask); - _cairo_glitz_surface_set_image (clone, src_image); - - _cairo_glitz_surface_set_matrix (clone, &(src_image->base.matrix)); + /* For surface patterns, we move any translucency from src->alpha + * to mask->alpha so we can use the source unchanged. Otherwise we + * move the translucency from mask->alpha to src->alpha so that + * we can drop the mask if possible. + */ + if (src->type == CAIRO_PATTERN_SURFACE) + { + if (mask) { + mask_opaque = mask_opaque && src_opaque; + mask_alpha = mask->alpha * src->alpha; + } else { + mask_opaque = src_opaque; + mask_alpha = src->alpha; + } + + src_alpha = 1.0; + src_opaque = TRUE; + } + else + { + if (mask) + { + src_opaque = mask_opaque && src_opaque; + src_alpha = mask->alpha * src->alpha; + /* FIXME: This needs changing when we support RENDER + * style 4-channel masks. + */ + if (mask->type == CAIRO_PATTERN_SOLID) + mask = NULL; + } else + src_alpha = src->alpha; + + mask_alpha = 1.0; + mask_opaque = TRUE; + } + + _cairo_pattern_init_copy (&tmp.base, src); + _cairo_pattern_set_alpha (&tmp.base, src_alpha); + + status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, + src_x, src_y, + width, height, + src_out, sattr); - cairo_surface_destroy (&src_image->base); + _cairo_pattern_fini (&tmp.base); - return clone; -} + if (status) + return status; -static cairo_int_status_t -_glitz_composite (glitz_operator_t op, - glitz_surface_t *src, - glitz_surface_t *mask, - glitz_surface_t *dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - int width, - int height, - glitz_buffer_t *geometry, - glitz_geometry_format_t *format) -{ - if (_glitz_ensure_target (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (mask || !mask_opaque) + { + if (mask) + _cairo_pattern_init_copy (&tmp.base, mask); + else + _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0); - if (glitz_surface_get_status (dst)) - return CAIRO_STATUS_NO_TARGET_SURFACE; - - glitz_set_geometry (dst, - 0, 0, - format, geometry); - - glitz_composite (op, - src, - mask, - dst, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); - - glitz_set_geometry (dst, 0, 0, NULL, NULL); + _cairo_pattern_set_alpha (&tmp.base, mask_alpha); + + status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, + mask_x, mask_y, + width, height, + mask_out, mattr); + + _cairo_pattern_fini (&tmp.base); - if (glitz_surface_get_status (dst) == GLITZ_STATUS_NOT_SUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (status) + { + _cairo_glitz_pattern_release_surface (dst, *src_out, sattr); + return status; + } + } + else + { + *mask_out = NULL; + } return CAIRO_STATUS_SUCCESS; } +static void +_cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface, + cairo_glitz_surface_attributes_t *a) +{ + _cairo_glitz_surface_set_matrix (surface, &a->base.matrix); + glitz_surface_set_fill (surface->surface, a->fill); + glitz_surface_set_filter (surface->surface, a->filter, + a->params, a->n_params); +} + static cairo_int_status_t _cairo_glitz_surface_composite (cairo_operator_t op, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, - void *abstract_dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height) + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) { - cairo_glitz_surface_t *dst = abstract_dst; - cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; - cairo_glitz_surface_t *mask = (cairo_glitz_surface_t *) generic_mask; - cairo_glitz_surface_t *src_clone = NULL; - cairo_glitz_surface_t *mask_clone = NULL; - cairo_int_status_t status; + cairo_glitz_surface_attributes_t src_attr, mask_attr; + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src; + cairo_glitz_surface_t *mask; + cairo_int_status_t status; if (op == CAIRO_OPERATOR_SATURATE) return CAIRO_INT_STATUS_UNSUPPORTED; - if (generic_src->backend != dst->base.backend) { - src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src, - CAIRO_FORMAT_ARGB32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (_glitz_ensure_target (dst->surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern, + dst, + src_x, src_y, + mask_x, mask_y, + width, height, + &src, &mask, + &src_attr, &mask_attr); + if (status) + return status; + + _cairo_glitz_surface_set_attributes (src, &src_attr); + if (mask) + { + _cairo_glitz_surface_set_attributes (mask, &mask_attr); + glitz_composite (_glitz_operator (op), + src->surface, + mask->surface, + dst->surface, + src_x + src_attr.base.x_offset, + src_y + src_attr.base.y_offset, + mask_x + mask_attr.base.x_offset, + mask_y + mask_attr.base.y_offset, + dst_x, dst_y, + width, height); - src = src_clone; - } - - if (generic_mask && (generic_mask->backend != dst->base.backend)) { - mask_clone = _cairo_glitz_surface_clone_similar (dst, generic_mask, - CAIRO_FORMAT_A8); - if (!mask_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (mask_attr.n_params) + free (mask_attr.params); - mask = mask_clone; + _cairo_glitz_pattern_release_surface (dst, mask, &mask_attr); + } + else + { + glitz_composite (_glitz_operator (op), + src->surface, + NULL, + dst->surface, + src_x + src_attr.base.x_offset, + src_y + src_attr.base.y_offset, + 0, 0, + dst_x, dst_y, + width, height); } - status = _glitz_composite (_glitz_operator (op), - src->surface, - (mask)? mask->surface: NULL, - dst->surface, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height, - NULL, NULL); - - if (src_clone) - cairo_surface_destroy (&src_clone->base); - - if (mask_clone) - cairo_surface_destroy (&mask_clone->base); + if (src_attr.n_params) + free (src_attr.params); - return status; + _cairo_glitz_pattern_release_surface (dst, src, &src_attr); + + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t -_cairo_glitz_surface_fill_rectangles (void *abstract_dst, - cairo_operator_t op, +_cairo_glitz_surface_fill_rectangles (void *abstract_dst, + cairo_operator_t op, const cairo_color_t *color, - cairo_rectangle_t *rects, - int n_rects) + cairo_rectangle_t *rects, + int n_rects) { cairo_glitz_surface_t *dst = abstract_dst; - glitz_color_t glitz_color; - if (op == CAIRO_OPERATOR_SATURATE) - return CAIRO_INT_STATUS_UNSUPPORTED; - - glitz_color.red = color->red_short; - glitz_color.green = color->green_short; - glitz_color.blue = color->blue_short; - glitz_color.alpha = color->alpha_short; + if (op == CAIRO_OPERATOR_SRC) + { + glitz_color_t glitz_color; + + glitz_color.red = color->red_short; + glitz_color.green = color->green_short; + glitz_color.blue = color->blue_short; + glitz_color.alpha = color->alpha_short; + + if (glitz_surface_get_width (dst->surface) != 1 || + glitz_surface_get_height (dst->surface) != 1) + _glitz_ensure_target (dst->surface); - if (op != CAIRO_OPERATOR_SRC) { - glitz_surface_t *solid; - glitz_float_t *vertices; - glitz_buffer_t *buffer; - glitz_geometry_format_t gf; - cairo_int_status_t status; - int width, height; - void *data; + glitz_set_rectangles (dst->surface, &glitz_color, + (glitz_rectangle_t *) rects, n_rects); + } + else + { + cairo_glitz_surface_t *src; - gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; - gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_SHARP; - gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; - gf.type = GLITZ_DATA_TYPE_FLOAT; - gf.first = 0; - gf.count = n_rects * 4; - - data = malloc (n_rects * 8 * sizeof (glitz_float_t)); - if (!data) - return CAIRO_STATUS_NO_MEMORY; - - buffer = glitz_buffer_create_for_data (data); - if (buffer == NULL) { - free (data); - return CAIRO_STATUS_NO_MEMORY; - } + if (op == CAIRO_OPERATOR_SATURATE) + return CAIRO_INT_STATUS_UNSUPPORTED; - width = height = 0; - vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); - for (; n_rects; rects++, n_rects--) { - *vertices++ = (glitz_float_t) rects->x; - *vertices++ = (glitz_float_t) rects->y; - *vertices++ = (glitz_float_t) (rects->x + rects->width); - *vertices++ = (glitz_float_t) rects->y; - *vertices++ = (glitz_float_t) (rects->x + rects->width); - *vertices++ = (glitz_float_t) (rects->y + rects->height); - *vertices++ = (glitz_float_t) rects->x; - *vertices++ = (glitz_float_t) (rects->y + rects->height); - - if ((rects->x + rects->width) > width) - width = rects->x + rects->width; - - if ((rects->y + rects->height) > height) - height = rects->y + rects->height; - } - glitz_buffer_unmap (buffer); + if (_glitz_ensure_target (dst->surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; - solid = _glitz_surface_create_solid (dst->surface, - GLITZ_STANDARD_ARGB32, - &glitz_color); - if (solid == NULL) + src = (cairo_glitz_surface_t *) + _cairo_surface_create_similar_solid (&dst->base, + CAIRO_FORMAT_ARGB32, 1, 1, + (cairo_color_t *) color); + if (!src) return CAIRO_STATUS_NO_MEMORY; - - status = _glitz_composite (_glitz_operator (op), - solid, - NULL, - dst->surface, - 0, 0, - 0, 0, - 0, 0, - width, height, - buffer, &gf); - - glitz_surface_destroy (solid); - glitz_buffer_destroy (buffer); - free (data); - - return status; - } else { - if (glitz_surface_get_width (dst->surface) != 1 || - glitz_surface_get_height (dst->surface) != 1) { - if (_glitz_ensure_target (dst->surface)) - return CAIRO_INT_STATUS_UNSUPPORTED; + + while (n_rects--) + { + glitz_composite (_glitz_operator (op), + src->surface, + NULL, + dst->surface, + 0, 0, + 0, 0, + rects->x, rects->y, + rects->width, rects->height); + rects++; } - glitz_set_rectangles (dst->surface, &glitz_color, - (glitz_rectangle_t *) rects, n_rects); + cairo_surface_destroy (&src->base); } + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t -_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, - cairo_surface_t *generic_src, - void *abstract_dst, - int x_src, - int y_src, +_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, + cairo_pattern_t *pattern, + void *abstract_dst, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, - int n_traps) + int n_traps) { - cairo_glitz_surface_t *dst = abstract_dst; - cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; - glitz_surface_t *mask = NULL; - glitz_float_t *vertices; - glitz_buffer_t *buffer; - glitz_geometry_format_t gf; - cairo_int_status_t status; - int x_dst, y_dst, x_rel, y_rel, width, height; - void *data; + cairo_glitz_surface_attributes_t attributes; + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src; + cairo_glitz_surface_t *mask = NULL; + glitz_buffer_t *buffer = NULL; + void *data = NULL; + cairo_int_status_t status; + unsigned short alpha; if (op == CAIRO_OPERATOR_SATURATE) return CAIRO_INT_STATUS_UNSUPPORTED; - if (generic_src->backend != dst->base.backend) + if (_glitz_ensure_target (dst->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; - gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; - gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_GOOD_SMOOTH; - gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; - gf.type = GLITZ_DATA_TYPE_FLOAT; - gf.first = 0; - gf.count = n_traps * 4; + if (pattern->type == CAIRO_PATTERN_SURFACE) + { + cairo_pattern_union_t tmp; - data = malloc (n_traps * 8 * sizeof (glitz_float_t)); - if (!data) - return CAIRO_STATUS_NO_MEMORY; - - buffer = glitz_buffer_create_for_data (data); - if (buffer == NULL) { - free (data); - return CAIRO_STATUS_NO_MEMORY; - } - - x_dst = traps[0].left.p1.x >> 16; - y_dst = traps[0].left.p1.y >> 16; + _cairo_pattern_init_copy (&tmp.base, pattern); + _cairo_pattern_set_alpha (&tmp.base, 1.0); - vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); - for (; n_traps; traps++, n_traps--) { - glitz_float_t top, bottom; + status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, + src_x, src_y, + width, height, + &src, &attributes); - top = GLITZ_FIXED_TO_FLOAT (traps->top); - bottom = GLITZ_FIXED_TO_FLOAT (traps->bottom); + _cairo_pattern_fini (&tmp.base); - *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->top); - *vertices++ = top; - *vertices++ = - GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->top); - *vertices++ = top; - *vertices++ = - GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->bottom); - *vertices++ = bottom; - *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->bottom); - *vertices++ = bottom; + alpha = pattern->alpha * 0xffff; } - glitz_buffer_unmap (buffer); + else + { + status = _cairo_glitz_pattern_acquire_surface (pattern, dst, + src_x, src_y, + width, height, + &src, &attributes); + alpha = 0xffff; + } + + if (status) + return status; + + if (op == CAIRO_OPERATOR_ADD || n_traps <= 1) + { + static glitz_color_t clear_black = { 0, 0, 0, 0 }; + glitz_color_t color; + glitz_geometry_format_t format; + int n_trap_added; + int offset = 0; + int data_size = 0; + int size = 30 * n_traps; /* just a guess */ + + format.vertex.primitive = GLITZ_PRIMITIVE_QUADS; + format.vertex.type = GLITZ_DATA_TYPE_FLOAT; + format.vertex.bytes_per_vertex = 3 * sizeof (glitz_float_t); + format.vertex.attributes = GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK; + format.vertex.mask.type = GLITZ_DATA_TYPE_FLOAT; + format.vertex.mask.size = GLITZ_COORDINATE_SIZE_X; + format.vertex.mask.offset = 2 * sizeof (glitz_float_t); + + mask = (cairo_glitz_surface_t *) + _cairo_glitz_surface_create_similar (&dst->base, + CAIRO_FORMAT_A8, 0, + 2, 1); + if (!mask) + { + _cairo_glitz_pattern_release_surface (dst, src, &attributes); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + color.red = color.green = color.blue = color.alpha = alpha; - if ((src->pattern.type == CAIRO_PATTERN_SURFACE) && - (src->pattern.color.alpha != 1.0)) { - glitz_color_t color; + glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1); + glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1); + + glitz_surface_set_fill (mask->surface, GLITZ_FILL_NEAREST); + glitz_surface_set_filter (mask->surface, + GLITZ_FILTER_BILINEAR, + NULL, 0); + + size *= format.vertex.bytes_per_vertex; - color.red = color.green = color.blue = 0; - color.alpha = src->pattern.color.alpha_short; + while (n_traps) + { + if (data_size < size) + { + data_size = size; + data = realloc (data, data_size); + if (!data) + { + _cairo_glitz_pattern_release_surface (dst, src, + &attributes); + return CAIRO_STATUS_NO_MEMORY; + } + + if (buffer) + glitz_buffer_destroy (buffer); + + buffer = glitz_buffer_create_for_data (data); + if (!buffer) { + free (data); + _cairo_glitz_pattern_release_surface (dst, src, + &attributes); + return CAIRO_STATUS_NO_MEMORY; + } + } - mask = _glitz_surface_create_solid (dst->surface, - GLITZ_STANDARD_A8, - &color); + offset += + glitz_add_trapezoids (buffer, + offset, size - offset, + format.vertex.type, mask->surface, + (glitz_trapezoid_t *) traps, n_traps, + &n_trap_added); + + n_traps -= n_trap_added; + traps += n_trap_added; + size *= 2; + } + + glitz_set_geometry (dst->surface, + GLITZ_GEOMETRY_TYPE_VERTEX, + &format, buffer); + glitz_set_array (dst->surface, 0, 3, + offset / format.vertex.bytes_per_vertex, + 0, 0); } + else + { + cairo_image_surface_t *image; + char *ptr; + int stride; + + stride = (width + 3) & -4; + data = malloc (stride * height); + if (!data) + { + _cairo_glitz_pattern_release_surface (dst, src, &attributes); + return CAIRO_STATUS_NO_MEMORY; + } + + memset (data, 0, stride * height); - x_rel = (src->pattern_box.p1.x >> 16) + x_src - x_dst; - y_rel = (src->pattern_box.p1.y >> 16) + y_src - y_dst; + /* using negative stride */ + ptr = (char *) data + stride * (height - 1); + + image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (ptr, + CAIRO_FORMAT_A8, + width, height, + -stride); + if (!image) + { + cairo_surface_destroy (&src->base); + free (data); + return CAIRO_STATUS_NO_MEMORY; + } - x_dst = src->pattern_box.p1.x >> 16; - y_dst = src->pattern_box.p1.y >> 16; + pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y, + (pixman_trapezoid_t *) traps, n_traps); + + if (alpha != 0xffff) + { + pixman_color_t color; + + color.red = color.green = color.blue = color.alpha = alpha; + + pixman_fill_rectangle (PIXMAN_OPERATOR_IN, + image->pixman_image, + &color, + 0, 0, width, height); + } + + mask = (cairo_glitz_surface_t *) + _cairo_surface_create_similar_scratch (&dst->base, + CAIRO_FORMAT_A8, 0, + width, height); + if (!mask) + { + _cairo_glitz_pattern_release_surface (dst, src, &attributes); + free (data); + cairo_surface_destroy (&image->base); + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_glitz_surface_set_image (mask, image, 0, 0); + } + + _cairo_glitz_surface_set_attributes (src, &attributes); - width = ((src->pattern_box.p2.x + 65535) >> 16) - - (src->pattern_box.p1.x >> 16); - height = ((src->pattern_box.p2.y + 65535) >> 16) - - (src->pattern_box.p1.y >> 16); + glitz_composite (_glitz_operator (op), + src->surface, + mask->surface, + dst->surface, + src_x + attributes.base.x_offset, + src_y + attributes.base.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + + if (attributes.n_params) + free (attributes.params); + + glitz_set_geometry (dst->surface, + GLITZ_GEOMETRY_TYPE_NONE, + NULL, NULL); + + if (buffer) + glitz_buffer_destroy (buffer); - status = _glitz_composite (_glitz_operator (op), - src->surface, - mask, - dst->surface, - x_rel, y_rel, - 0, 0, - x_dst, y_dst, - width, height, - buffer, &gf); + free (data); + _cairo_glitz_pattern_release_surface (dst, src, &attributes); if (mask) - glitz_surface_destroy (mask); + cairo_surface_destroy (&mask->base); - glitz_buffer_destroy (buffer); - free (data); + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -819,173 +1240,56 @@ _cairo_glitz_surface_show_page (void *abstract_surface) } static cairo_int_status_t -_cairo_glitz_surface_create_pattern (void *abstract_dst, - cairo_pattern_t *pattern, - cairo_box_t *box) +_cairo_glitz_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) { - cairo_glitz_surface_t *dst = abstract_dst; - cairo_surface_t *generic_src = NULL; - cairo_image_surface_t *image = NULL; - cairo_glitz_surface_t *src; - - switch (pattern->type) { - case CAIRO_PATTERN_SOLID: - generic_src = - _cairo_surface_create_similar_solid (abstract_dst, - CAIRO_FORMAT_ARGB32, - 1, 1, - &pattern->color); - if (generic_src) - cairo_surface_set_repeat (generic_src, 1); - break; - case CAIRO_PATTERN_RADIAL: - /* glitz doesn't support inner and outer circle with different - center points. */ - if (pattern->u.radial.center0.x != pattern->u.radial.center1.x || - pattern->u.radial.center0.y != pattern->u.radial.center1.y) - break; - /* fall-through */ - case CAIRO_PATTERN_LINEAR: { - glitz_drawable_t *drawable; - glitz_fixed16_16_t *params; - int i, n_params; - - drawable = glitz_surface_get_drawable (dst->surface); - if (!(glitz_drawable_get_features (drawable) & - GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK)) - break; - - if (pattern->filter != CAIRO_FILTER_BILINEAR) - break; - - n_params = pattern->n_stops * 3 + 4; - - params = malloc (sizeof (glitz_fixed16_16_t) * n_params); - if (params == NULL) - return CAIRO_STATUS_NO_MEMORY; - - generic_src = - _cairo_glitz_surface_create_similar (abstract_dst, - CAIRO_FORMAT_ARGB32, 0, - pattern->n_stops, 1); - if (generic_src == NULL) { - free (params); - return CAIRO_STATUS_NO_MEMORY; - } - - src = (cairo_glitz_surface_t *) generic_src; - - for (i = 0; i < pattern->n_stops; i++) { - glitz_color_t color; + cairo_glitz_surface_t *surface = abstract_surface; - color.alpha = pattern->stops[i].color_char[3]; - color.red = pattern->stops[i].color_char[0] * color.alpha; - color.green = pattern->stops[i].color_char[1] * color.alpha; - color.blue = pattern->stops[i].color_char[2] * color.alpha; - color.alpha *= 256; + if (region) + { + glitz_box_t *box; + int n; - glitz_set_rectangle (src->surface, &color, i, 0, 1, 1); - - params[4 + 3 * i] = pattern->stops[i].offset; - params[5 + 3 * i] = i << 16; - params[6 + 3 * i] = 0; - } - - if (pattern->type == CAIRO_PATTERN_LINEAR) { - params[0] = _cairo_fixed_from_double (pattern->u.linear.point0.x); - params[1] = _cairo_fixed_from_double (pattern->u.linear.point0.y); - params[2] = _cairo_fixed_from_double (pattern->u.linear.point1.x); - params[3] = _cairo_fixed_from_double (pattern->u.linear.point1.y); - - glitz_surface_set_filter (src->surface, - GLITZ_FILTER_LINEAR_GRADIENT, - params, n_params); - } else { - params[0] = _cairo_fixed_from_double (pattern->u.radial.center0.x); - params[1] = _cairo_fixed_from_double (pattern->u.radial.center0.y); - params[2] = _cairo_fixed_from_double (pattern->u.radial.radius0); - params[3] = _cairo_fixed_from_double (pattern->u.radial.radius1); - - glitz_surface_set_filter (src->surface, - GLITZ_FILTER_RADIAL_GRADIENT, - params, n_params); - } - - switch (pattern->extend) { - case CAIRO_EXTEND_REPEAT: - glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); - break; - case CAIRO_EXTEND_REFLECT: - glitz_surface_set_fill (src->surface, GLITZ_FILL_REFLECT); - break; - case CAIRO_EXTEND_NONE: - default: - glitz_surface_set_fill (src->surface, GLITZ_FILL_NEAREST); - break; + if (!surface->clip) + { + surface->clip = pixman_region_create (); + if (!surface->clip) + return CAIRO_STATUS_NO_MEMORY; } + pixman_region_copy (surface->clip, region); - cairo_surface_set_matrix (&src->base, &pattern->matrix); - - free (params); - } break; - case CAIRO_PATTERN_SURFACE: - generic_src = pattern->u.surface.surface; - cairo_surface_reference (generic_src); - break; - } - - if (generic_src == NULL) { - image = _cairo_pattern_get_image (pattern, box); - if (image == NULL) - return CAIRO_STATUS_NO_MEMORY; - - generic_src = &image->base; + box = (glitz_box_t *) pixman_region_rects (surface->clip); + n = pixman_region_num_rects (surface->clip); + glitz_surface_set_clip_region (surface->surface, 0, 0, box, n); } + else + { + glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); - if (generic_src->backend != dst->base.backend) { - src = _cairo_glitz_surface_clone_similar (dst, generic_src, - CAIRO_FORMAT_ARGB32); - if (src == NULL) - return CAIRO_STATUS_NO_MEMORY; - - cairo_surface_set_repeat (&src->base, generic_src->repeat); - } else - src = (cairo_glitz_surface_t *) generic_src; + if (surface->clip) + pixman_region_destroy (surface->clip); - if (image) - cairo_surface_destroy (&image->base); - - _cairo_pattern_init_copy (&src->pattern, pattern); - src->pattern_box = *box; - - pattern->source = &src->base; + surface->clip = NULL; + } return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_glitz_surface_set_clip_region (void *abstract_surface, - pixman_region16_t *region) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - static const cairo_surface_backend_t cairo_glitz_surface_backend = { _cairo_glitz_surface_create_similar, _cairo_glitz_surface_destroy, _cairo_glitz_surface_pixels_per_inch, - _cairo_glitz_surface_get_image, - _cairo_glitz_surface_set_image, - _cairo_glitz_surface_set_matrix, - _cairo_glitz_surface_set_filter, - _cairo_glitz_surface_set_repeat, + _cairo_glitz_surface_acquire_source_image, + _cairo_glitz_surface_release_source_image, + _cairo_glitz_surface_acquire_dest_image, + _cairo_glitz_surface_release_dest_image, + _cairo_glitz_surface_clone_similar, _cairo_glitz_surface_composite, _cairo_glitz_surface_fill_rectangles, _cairo_glitz_surface_composite_trapezoids, _cairo_glitz_surface_copy_page, _cairo_glitz_surface_show_page, _cairo_glitz_surface_set_clip_region, - _cairo_glitz_surface_create_pattern, NULL /* show_glyphs */ }; @@ -1004,12 +1308,10 @@ cairo_glitz_surface_create (glitz_surface_t *surface) _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend); glitz_surface_reference (surface); - crsurface->surface = surface; - crsurface->format = glitz_surface_get_format (surface); - _cairo_pattern_init (&crsurface->pattern); - crsurface->pattern.type = CAIRO_PATTERN_SURFACE; - crsurface->pattern.u.surface.surface = NULL; + crsurface->surface = surface; + crsurface->format = glitz_surface_get_format (surface); + crsurface->clip = NULL; return (cairo_surface_t *) crsurface; } diff --git a/src/cairo-glitz.h b/src/cairo-glitz.h index 350d10233..f1917eb28 100644 --- a/src/cairo-glitz.h +++ b/src/cairo-glitz.h @@ -31,17 +31,20 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ -#include <cairo.h> - #ifndef CAIRO_GLITZ_H #define CAIRO_GLITZ_H + +#include <cairo.h> + #ifdef CAIRO_HAS_GLITZ_SURFACE #include <glitz.h> +CAIRO_BEGIN_DECLS + void cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface); @@ -49,5 +52,7 @@ cairo_set_target_glitz (cairo_t *cr, cairo_surface_t * cairo_glitz_surface_create (glitz_surface_t *surface); +CAIRO_END_DECLS + #endif /* CAIRO_HAS_GLITZ_SURFACE */ #endif /* CAIRO_GLITZ_H */ diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index e855a7a66..d6db560a3 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include <stdlib.h> @@ -46,20 +46,33 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, cairo_surface_t *dst, cairo_traps_t *traps); +static cairo_status_t +_cairo_gstate_ensure_font (cairo_gstate_t *gstate); + +static void +_cairo_gstate_unset_font (cairo_gstate_t *gstate); + cairo_gstate_t * _cairo_gstate_create () { + cairo_status_t status; cairo_gstate_t *gstate; gstate = malloc (sizeof (cairo_gstate_t)); if (gstate) - _cairo_gstate_init (gstate); + { + status = _cairo_gstate_init (gstate); + if (status) { + free (gstate); + return NULL; + } + } return gstate; } -void +cairo_status_t _cairo_gstate_init (cairo_gstate_t *gstate) { gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT; @@ -77,9 +90,11 @@ _cairo_gstate_init (cairo_gstate_t *gstate) gstate->num_dashes = 0; gstate->dash_offset = 0.0; - gstate->font = _cairo_unscaled_font_create (CAIRO_FONT_FAMILY_DEFAULT, - CAIRO_FONT_SLANT_DEFAULT, - CAIRO_FONT_WEIGHT_DEFAULT); + gstate->font_family = NULL; + gstate->font_slant = CAIRO_FONT_SLANT_DEFAULT; + gstate->font_weight = CAIRO_FONT_WEIGHT_DEFAULT; + + gstate->font = NULL; gstate->surface = NULL; @@ -87,6 +102,9 @@ _cairo_gstate_init (cairo_gstate_t *gstate) gstate->clip.surface = NULL; gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0); + if (!gstate->pattern) + return CAIRO_STATUS_NO_MEMORY; + gstate->alpha = 1.0; gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT; @@ -97,6 +115,8 @@ _cairo_gstate_init (cairo_gstate_t *gstate) _cairo_pen_init_empty (&gstate->pen_regular); gstate->next = NULL; + + return CAIRO_STATUS_SUCCESS; } cairo_status_t @@ -118,9 +138,15 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double)); } + if (other->font_family) { + gstate->font_family = strdup (other->font_family); + if (!gstate->font_family) + goto CLEANUP_DASH; + } + if (other->font) { gstate->font = other->font; - _cairo_unscaled_font_reference (gstate->font); + cairo_font_reference (gstate->font); } if (other->clip.region) @@ -148,18 +174,29 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) _cairo_path_fini (&gstate->path); CLEANUP_FONT: - _cairo_unscaled_font_destroy (gstate->font); + cairo_font_destroy (gstate->font); + gstate->font = NULL; + + if (gstate->font_family) { + free (gstate->font_family); + gstate->font_family = NULL; + } + CLEANUP_DASH: free (gstate->dash); gstate->dash = NULL; - return status; + return CAIRO_STATUS_NO_MEMORY; } void _cairo_gstate_fini (cairo_gstate_t *gstate) { - _cairo_unscaled_font_destroy (gstate->font); + if (gstate->font_family) + free (gstate->font_family); + + if (gstate->font) + cairo_font_destroy (gstate->font); if (gstate->surface) cairo_surface_destroy (gstate->surface); @@ -323,6 +360,8 @@ _cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surfa { double scale; + _cairo_gstate_unset_font (gstate); + if (gstate->surface) cairo_surface_destroy (gstate->surface); @@ -365,11 +404,9 @@ _cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern) if (pattern == NULL) return CAIRO_STATUS_NULL_POINTER; - if (gstate->pattern) - cairo_pattern_destroy (gstate->pattern); - - gstate->pattern = pattern; cairo_pattern_reference (pattern); + cairo_pattern_destroy (gstate->pattern); + gstate->pattern = pattern; return CAIRO_STATUS_SUCCESS; } @@ -407,6 +444,8 @@ _cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, d cairo_pattern_destroy (gstate->pattern); gstate->pattern = _cairo_pattern_create_solid (red, green, blue); + if (!gstate->pattern) + return CAIRO_STATUS_NO_MEMORY; return CAIRO_STATUS_SUCCESS; } @@ -549,6 +588,8 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty) { cairo_matrix_t tmp; + _cairo_gstate_unset_font (gstate); + _cairo_matrix_set_translate (&tmp, tx, ty); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -566,6 +607,8 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy) if (sx == 0 || sy == 0) return CAIRO_STATUS_INVALID_MATRIX; + _cairo_gstate_unset_font (gstate); + _cairo_matrix_set_scale (&tmp, sx, sy); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -580,6 +623,8 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle) { cairo_matrix_t tmp; + _cairo_gstate_unset_font (gstate); + _cairo_matrix_set_rotate (&tmp, angle); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -595,6 +640,8 @@ _cairo_gstate_concat_matrix (cairo_gstate_t *gstate, { cairo_matrix_t tmp; + _cairo_gstate_unset_font (gstate); + cairo_matrix_copy (&tmp, matrix); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -610,6 +657,8 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate, { cairo_status_t status; + _cairo_gstate_unset_font (gstate); + cairo_matrix_copy (&gstate->ctm, matrix); cairo_matrix_copy (&gstate->ctm_inverse, matrix); @@ -627,6 +676,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate) if (scale == 0) scale = 1; + _cairo_gstate_unset_font (gstate); + cairo_matrix_set_identity (&gstate->font_matrix); cairo_matrix_set_identity (&gstate->ctm); @@ -640,6 +691,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_identity_matrix (cairo_gstate_t *gstate) { + _cairo_gstate_unset_font (gstate); + cairo_matrix_set_identity (&gstate->ctm); cairo_matrix_set_identity (&gstate->ctm_inverse); @@ -1256,54 +1309,17 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate, &gpi); } -/* This function modifies the pattern and the state of the pattern surface it - may contain. The pattern surface will be restored to its orignal state - when the pattern is destroyed. The appropriate way is to pass a copy of - the original pattern to this function just before the pattern should be - used and destroy the copy when done. */ -static cairo_status_t -_cairo_gstate_create_pattern (cairo_gstate_t *gstate, - cairo_pattern_t *pattern, - cairo_box_t *extents) +/* XXX: gstate->alpha will be going away before too long, and when it + * does, it may make sense for this function to just disappear. + */ +static void +_cairo_gstate_pattern_init_copy (cairo_gstate_t *gstate, + cairo_pattern_union_t *pattern, + cairo_pattern_t *src) { - cairo_int_status_t status; - - if (gstate->surface == NULL) { - _cairo_pattern_fini (pattern); - return CAIRO_STATUS_NO_TARGET_SURFACE; - } - - if (pattern->type == CAIRO_PATTERN_LINEAR || - pattern->type == CAIRO_PATTERN_RADIAL) { - if (pattern->n_stops < 2) { - pattern->type = CAIRO_PATTERN_SOLID; - - if (pattern->n_stops) { - cairo_color_stop_t *stop = pattern->stops; - - _cairo_color_set_rgb (&pattern->color, - (double) stop->color_char[0] / 0xff, - (double) stop->color_char[1] / 0xff, - (double) stop->color_char[2] / 0xff); - _cairo_color_set_alpha (&pattern->color, - (double) stop->color_char[3] / 0xff); - } - } - } - - _cairo_pattern_set_alpha (pattern, gstate->alpha); - _cairo_pattern_transform (pattern, &gstate->ctm_inverse); - - status = _cairo_surface_create_pattern (gstate->surface, pattern, extents); - if (status) { - _cairo_pattern_fini (pattern); - return status; - } - - if (pattern->type == CAIRO_PATTERN_SURFACE) - _cairo_pattern_prepare_surface (pattern); - - return CAIRO_STATUS_SUCCESS; + _cairo_pattern_init_copy (&pattern->base, src); + _cairo_pattern_transform (&pattern->base, &gstate->ctm_inverse); + _cairo_pattern_set_alpha (&pattern->base, gstate->alpha); } cairo_status_t @@ -1342,7 +1358,7 @@ cairo_status_t _cairo_gstate_in_stroke (cairo_gstate_t *gstate, double x, double y, - int *inside_ret) + cairo_bool_t *inside_ret) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_traps_t traps; @@ -1365,51 +1381,85 @@ BAIL: return status; } -static cairo_status_t -_calculate_region_for_intermediate_clip_surface (pixman_region16_t *out, - cairo_box_t *extents, - cairo_clip_rec_t *clip_rect) +/* XXX We currently have a confusing mix of boxes and rectangles as + * exemplified by this function. A cairo_box_t is a rectangular area + * represented by the coordinates of the upper left and lower right + * corners, expressed in fixed point numbers. A cairo_rectangle_t is + * also a rectangular area, but represented by the upper left corner + * and the width and the height, as integer numbers. + * + * This function converts a cairo_box_t to a cairo_rectangle_t by + * increasing the area to the nearest integer coordinates. We should + * standardize on cairo_rectangle_t and cairo_rectangle_fixed_t, and + * this function could be renamed to the more reasonable + * _cairo_rectangle_fixed_round. + */ + +static void +_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle) { - cairo_status_t status; - pixman_region16_t *extents_region, *clip_region; - pixman_box16_t clip_box, pixman_extents; - - pixman_extents.x1 = _cairo_fixed_integer_floor (extents->p1.x); - pixman_extents.y1 = _cairo_fixed_integer_floor (extents->p1.y); - pixman_extents.x2 = _cairo_fixed_integer_ceil (extents->p2.x); - pixman_extents.y2 = _cairo_fixed_integer_ceil (extents->p2.y); - extents_region = pixman_region_create_simple (&pixman_extents); - if (extents_region == NULL) - { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; - } + rectangle->x = _cairo_fixed_integer_floor (box->p1.x); + rectangle->y = _cairo_fixed_integer_floor (box->p1.y); + rectangle->width = _cairo_fixed_integer_ceil (box->p2.x) - rectangle->x; + rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y; +} - clip_box.x1 = clip_rect->x; - clip_box.y1 = clip_rect->y; - clip_box.x2 = clip_rect->x + clip_rect->width; - clip_box.y2 = clip_rect->y + clip_rect->height; - clip_region = pixman_region_create_simple (&clip_box); - if (clip_region == NULL) - { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL1; - } +static void +_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src) +{ + int x1, y1, x2, y2; - if (pixman_region_intersect (out, - extents_region, - clip_region) - == PIXMAN_REGION_STATUS_FAILURE) - status = CAIRO_STATUS_NO_MEMORY; - else - status = CAIRO_STATUS_SUCCESS; - - pixman_region_destroy (extents_region); - BAIL1: - pixman_region_destroy (clip_region); - - BAIL0: - return status; + x1 = MAX (dest->x, src->x); + y1 = MAX (dest->y, src->y); + x2 = MIN (dest->x + dest->width, src->x + src->width); + y2 = MIN (dest->y + dest->height, src->y + src->height); + + if (x1 >= x2 || y1 >= y2) { + dest->x = 0; + dest->y = 0; + dest->width = 0; + dest->height = 0; + } else { + dest->x = x1; + dest->y = y1; + dest->width = x2 - x1; + dest->height = y2 - y1; + } +} + +static int +_cairo_rectangle_empty (cairo_rectangle_t *rect) +{ + return rect->width == 0 || rect->height == 0; +} + +static void +translate_traps (cairo_traps_t *traps, int x, int y) +{ + cairo_fixed_t xoff, yoff; + cairo_trapezoid_t *t; + int i; + + /* Ugh. The cairo_composite/(Render) interface doesn't allow + an offset for the trapezoids. Need to manually shift all + the coordinates to align with the offset origin of the + intermediate surface. */ + + xoff = _cairo_fixed_from_int (x); + yoff = _cairo_fixed_from_int (y); + + for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) { + t->top += yoff; + t->bottom += yoff; + t->left.p1.x += xoff; + t->left.p1.y += yoff; + t->left.p2.x += xoff; + t->left.p2.y += yoff; + t->right.p1.x += xoff; + t->right.p1.y += yoff; + t->right.p2.x += xoff; + t->right.p2.y += yoff; + } } @@ -1422,173 +1472,148 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, cairo_traps_t *traps) { cairo_status_t status; - cairo_pattern_t pattern; - cairo_box_t extents; - int x_src, y_src; + cairo_pattern_union_t pattern; + cairo_rectangle_t extents; + cairo_box_t trap_extents; if (traps->num_traps == 0) return CAIRO_STATUS_SUCCESS; + if (gstate->surface == NULL) + return CAIRO_STATUS_NO_TARGET_SURFACE; + + _cairo_traps_extents (traps, &trap_extents); + _cairo_box_round_to_rectangle (&trap_extents, &extents); + if (gstate->clip.surface) { - cairo_fixed_t xoff, yoff; - cairo_trapezoid_t *t; - int i; cairo_surface_t *intermediate; + cairo_surface_pattern_t intermediate_pattern; cairo_color_t empty_color; - pixman_box16_t *draw_extents; - pixman_region16_t *draw_region; - draw_region = pixman_region_create (); - if (draw_region == NULL) - { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; - } - - _cairo_traps_extents (traps, &extents); - - status = _calculate_region_for_intermediate_clip_surface (draw_region, - &extents, - &gstate->clip); - if (status) - goto BAIL1; + _cairo_rectangle_intersect (&extents, &gstate->clip.rect); - /* Shortcut if empty */ - if (!pixman_region_not_empty (draw_region)) { + if (_cairo_rectangle_empty (&extents)) { status = CAIRO_STATUS_SUCCESS; goto BAIL1; } - draw_extents = pixman_region_extents (draw_region); - - /* Ugh. The cairo_composite/(Render) interface doesn't allow - an offset for the trapezoids. Need to manually shift all - the coordinates to align with the offset origin of the - intermediate surface. */ - xoff = _cairo_fixed_from_int (draw_extents->x1); - yoff = _cairo_fixed_from_int (draw_extents->y1); - for (i=0, t=traps->traps; i < traps->num_traps; i++, t++) { - t->top -= yoff; - t->bottom -= yoff; - t->left.p1.x -= xoff; - t->left.p1.y -= yoff; - t->left.p2.x -= xoff; - t->left.p2.y -= yoff; - t->right.p1.x -= xoff; - t->right.p1.y -= yoff; - t->right.p2.x -= xoff; - t->right.p2.y -= yoff; - } - - if (traps->traps[0].left.p1.y < traps->traps[0].left.p2.y) { - x_src = _cairo_fixed_to_double (traps->traps[0].left.p1.x); - y_src = _cairo_fixed_to_double (traps->traps[0].left.p1.y); - } else { - x_src = _cairo_fixed_to_double (traps->traps[0].left.p2.x); - y_src = _cairo_fixed_to_double (traps->traps[0].left.p2.y); - } - - _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); - _cairo_pattern_set_alpha (&pattern, 1.0); - - status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); - if (status) - goto BAIL1; + translate_traps (traps, -extents.x, -extents.y); _cairo_color_init (&empty_color); _cairo_color_set_alpha (&empty_color, 0.); intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, CAIRO_FORMAT_A8, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1, + extents.width, + extents.height, &empty_color); if (intermediate == NULL) { status = CAIRO_STATUS_NO_MEMORY; - goto BAIL2; + goto BAIL1; } + _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0); + status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD, - pattern.source, intermediate, - x_src, - y_src, + &pattern.base, + intermediate, + extents.x, extents.y, + 0, 0, + extents.width, + extents.height, traps->traps, traps->num_traps); + _cairo_pattern_fini (&pattern.base); + if (status) - goto BAIL3; + goto BAIL2; + + + _cairo_pattern_init_for_surface (&pattern.surface, + gstate->clip.surface); status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - gstate->clip.surface, + &pattern.base, NULL, intermediate, - draw_extents->x1 - gstate->clip.x, - draw_extents->y1 - gstate->clip.y, + extents.x - gstate->clip.rect.x, + extents.y - gstate->clip.rect.y, 0, 0, 0, 0, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); - if (status) - goto BAIL3; - - _cairo_pattern_fini (&pattern); + extents.width, extents.height); + _cairo_pattern_fini (&pattern.base); - _cairo_pattern_init_copy (&pattern, src); - - extents.p1.x = _cairo_fixed_from_int (draw_extents->x1); - extents.p1.y = _cairo_fixed_from_int (draw_extents->y1); - extents.p2.x = _cairo_fixed_from_int (draw_extents->x2); - extents.p2.y = _cairo_fixed_from_int (draw_extents->y2); - status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); if (status) - goto BAIL3; + goto BAIL2; - if (dst == gstate->clip.surface) - xoff = yoff = 0; + _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); + _cairo_gstate_pattern_init_copy (gstate, &pattern, src); status = _cairo_surface_composite (operator, - pattern.source, intermediate, dst, - 0, 0, + &pattern.base, + &intermediate_pattern.base, + dst, + extents.x, extents.y, 0, 0, - xoff >> 16, - yoff >> 16, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); + extents.x, extents.y, + extents.width, extents.height); + _cairo_pattern_fini (&pattern.base); + _cairo_pattern_fini (&intermediate_pattern.base); - BAIL3: - cairo_surface_destroy (intermediate); BAIL2: - _cairo_pattern_fini (&pattern); + cairo_surface_destroy (intermediate); BAIL1: - pixman_region_destroy (draw_region); - BAIL0: if (status) return status; } else { - if (traps->traps[0].left.p1.y < traps->traps[0].left.p2.y) { - x_src = _cairo_fixed_to_double (traps->traps[0].left.p1.x); - y_src = _cairo_fixed_to_double (traps->traps[0].left.p1.y); - } else { - x_src = _cairo_fixed_to_double (traps->traps[0].left.p2.x); - y_src = _cairo_fixed_to_double (traps->traps[0].left.p2.y); + if (gstate->clip.region) { + pixman_box16_t box; + pixman_box16_t *intersection_extents; + pixman_region16_t *rect, *intersection; + + box.x1 = _cairo_fixed_integer_floor (trap_extents.p1.x); + box.y1 = _cairo_fixed_integer_floor (trap_extents.p1.y); + box.x2 = _cairo_fixed_integer_ceil (trap_extents.p2.x); + box.y2 = _cairo_fixed_integer_ceil (trap_extents.p2.y); + + rect = pixman_region_create_simple (&box); + if (rect == NULL) + goto bail1; + intersection = pixman_region_create(); + if (intersection == NULL) + goto bail2; + + if (pixman_region_intersect (intersection, gstate->clip.region, + rect) != PIXMAN_REGION_STATUS_SUCCESS) + goto bail3; + intersection_extents = pixman_region_extents (intersection); + + extents.x = intersection_extents->x1; + extents.y = intersection_extents->y1; + extents.width = intersection_extents->x2 - intersection_extents->x1; + extents.height = intersection_extents->y2 - intersection_extents->y1; + bail3: + pixman_region_destroy (intersection); + bail2: + pixman_region_destroy (rect); + bail1: + ; } - _cairo_pattern_init_copy (&pattern, src); + _cairo_gstate_pattern_init_copy (gstate, &pattern, src); - _cairo_traps_extents (traps, &extents); - status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); - if (status) - return status; - status = _cairo_surface_composite_trapezoids (gstate->operator, - pattern.source, dst, - x_src - pattern.source_offset.x, - y_src - pattern.source_offset.y, + &pattern.base, dst, + extents.x, extents.y, + extents.x, extents.y, + extents.width, + extents.height, traps->traps, traps->num_traps); - _cairo_pattern_fini (&pattern); + _cairo_pattern_fini (&pattern.base); if (status) return status; @@ -1628,7 +1653,7 @@ cairo_status_t _cairo_gstate_in_fill (cairo_gstate_t *gstate, double x, double y, - int *inside_ret) + cairo_bool_t *inside_ret) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_traps_t traps; @@ -1807,9 +1832,10 @@ cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate) { cairo_status_t status; - cairo_pattern_t pattern; + cairo_pattern_union_t pattern; cairo_traps_t traps; cairo_color_t white_color; + cairo_box_t extents; pixman_box16_t box; /* Fill the clip region as traps. */ @@ -1871,33 +1897,32 @@ _cairo_gstate_clip (cairo_gstate_t *gstate) _cairo_color_init (&white_color); if (gstate->clip.surface == NULL) { - cairo_box_t extents; - _cairo_traps_extents (&traps, &extents); - gstate->clip.x = extents.p1.x >> 16; - gstate->clip.y = extents.p1.y >> 16; - gstate->clip.width = ((extents.p2.x + 65535) >> 16) - gstate->clip.x; - gstate->clip.height = ((extents.p2.y + 65535) >> 16) - gstate->clip.y; + _cairo_box_round_to_rectangle (&extents, &gstate->clip.rect); gstate->clip.surface = _cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, - gstate->clip.width, - gstate->clip.height, + gstate->clip.rect.width, + gstate->clip.rect.height, &white_color); if (gstate->clip.surface == NULL) return CAIRO_STATUS_NO_MEMORY; } - _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); - _cairo_pattern_set_alpha (&pattern, 1.0); - - _cairo_gstate_clip_and_composite_trapezoids (gstate, - &pattern, - CAIRO_OPERATOR_IN, - gstate->clip.surface, - &traps); + translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y); + _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0); - _cairo_pattern_fini (&pattern); + status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN, + &pattern.base, + gstate->clip.surface, + 0, 0, + 0, 0, + gstate->clip.rect.width, + gstate->clip.rect.height, + traps.traps, + traps.num_traps); + + _cairo_pattern_fini (&pattern.base); _cairo_traps_fini (&traps); @@ -1978,19 +2003,15 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, * */ - cairo_status_t status; - cairo_matrix_t user_to_image, image_to_user; - cairo_matrix_t image_to_device, device_to_image; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_matrix_t image_to_user, image_to_device; double device_x, device_y; double device_width, device_height; - cairo_pattern_t pattern; + cairo_surface_pattern_t pattern; cairo_box_t pattern_extents; + cairo_rectangle_t extents; - cairo_surface_get_matrix (surface, &user_to_image); - cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image); - cairo_surface_set_matrix (surface, &device_to_image); - - image_to_user = user_to_image; + cairo_surface_get_matrix (surface, &image_to_user); cairo_matrix_invert (&image_to_user); cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm); @@ -2001,126 +2022,82 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, &device_x, &device_y, &device_width, &device_height); - _cairo_pattern_init (&pattern); + _cairo_pattern_init_for_surface (&pattern, surface); + + /* inherit surface attributes while surface attribute functions still + exist */ + pattern.base.matrix = surface->matrix; + pattern.base.filter = surface->filter; + if (surface->repeat) + pattern.base.extend = CAIRO_EXTEND_REPEAT; + else + pattern.base.extend = CAIRO_EXTEND_NONE; + + _cairo_pattern_transform (&pattern.base, &gstate->ctm_inverse); + _cairo_pattern_set_alpha (&pattern.base, gstate->alpha); pattern_extents.p1.x = _cairo_fixed_from_double (device_x); pattern_extents.p1.y = _cairo_fixed_from_double (device_y); pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width); pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height); - - if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) || - (gstate->alpha != 1.0)) { - /* I'm allowing any type of pattern for the mask right now. - Maybe this is bad. Will allow for some cool effects though. */ - _cairo_pattern_init_copy (&pattern, gstate->pattern); - status = _cairo_gstate_create_pattern (gstate, &pattern, &pattern_extents); - if (status) - return status; - } - + _cairo_box_round_to_rectangle (&pattern_extents, &extents); + if (gstate->clip.surface) { - cairo_surface_t *intermediate; - cairo_color_t empty_color; - pixman_box16_t *draw_extents; - pixman_region16_t *draw_region; - - draw_region = pixman_region_create (); - if (draw_region == NULL) - { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; + _cairo_rectangle_intersect (&extents, &gstate->clip.rect); + + /* We only need to composite if the rectangle is not empty. */ + if (!_cairo_rectangle_empty (&extents)) { + cairo_surface_pattern_t clip_pattern; + + _cairo_pattern_init_for_surface (&clip_pattern, + gstate->clip.surface); + + status = _cairo_surface_composite (gstate->operator, + &pattern.base, + &clip_pattern.base, + gstate->surface, + extents.x, extents.y, + 0, 0, + extents.x, extents.y, + extents.width, extents.height); + + _cairo_pattern_fini (&clip_pattern.base); } - - status = _calculate_region_for_intermediate_clip_surface (draw_region, - &pattern_extents, - &gstate->clip); - if (status) - goto BAIL1; - - /* Shortcut if empty */ - if (!pixman_region_not_empty (draw_region)) { - status = CAIRO_STATUS_SUCCESS; - goto BAIL1; - } - - draw_extents = pixman_region_extents (draw_region); - - _cairo_color_init (&empty_color); - _cairo_color_set_alpha (&empty_color, .0); - intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, - CAIRO_FORMAT_A8, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1, - &empty_color); - - /* it is not completely clear what the "right" way to combine the - pattern and mask surface is. I will use the the clip as a source - and the pattern as a mask in building up my temporary, because - this is not *totally* bogus and accomodates the case where - pattern's source image is NULL reasonably well. feel free to - correct this if you see a reason. */ - - status = _cairo_surface_composite (CAIRO_OPERATOR_SRC, - gstate->clip.surface, - pattern.source, - intermediate, - draw_extents->x1 - gstate->clip.x, - draw_extents->y1 - gstate->clip.y, - 0, 0, - 0, 0, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); - - - if (status) - goto BAIL2; - - status = _cairo_surface_composite (gstate->operator, - surface, - intermediate, - gstate->surface, - draw_extents->x1, draw_extents->y1, - 0, 0, - draw_extents->x1, draw_extents->y1, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); - - BAIL2: - cairo_surface_destroy (intermediate); - BAIL1: - pixman_region_destroy (draw_region); - BAIL0: - ; } else { - - /* XXX: The rendered size is sometimes 1 or 2 pixels short from - what I expect. Need to fix this. */ + /* XXX: The rendered size is sometimes 1 or 2 pixels short + * from what I expect. Need to fix this. + * KRH: I'm guessing this was due to rounding error when + * passing double coordinates for integer arguments. Using + * the extents rectangle should fix this, since it's properly + * rounded. Is this still the case? + */ status = _cairo_surface_composite (gstate->operator, - surface, - pattern.source, + &pattern.base, + NULL, gstate->surface, - device_x, device_y, + extents.x, extents.y, 0, 0, - device_x, device_y, - device_width, - device_height); + extents.x, extents.y, + extents.width, extents.height); } - _cairo_pattern_fini (&pattern); + _cairo_pattern_fini (&pattern.base); - /* restore the matrix originally in the surface */ - cairo_surface_set_matrix (surface, &user_to_image); - - if (status) - return status; - - return CAIRO_STATUS_SUCCESS; + return status; } +static void +_cairo_gstate_unset_font (cairo_gstate_t *gstate) +{ + if (gstate->font) { + cairo_font_destroy (gstate->font); + gstate->font = NULL; + } +} cairo_status_t _cairo_gstate_select_font (cairo_gstate_t *gstate, @@ -2128,12 +2105,17 @@ _cairo_gstate_select_font (cairo_gstate_t *gstate, cairo_font_slant_t slant, cairo_font_weight_t weight) { - if (gstate->font) - _cairo_unscaled_font_destroy (gstate->font); + char *new_family; - gstate->font = _cairo_unscaled_font_create (family, slant, weight); - if (gstate->font == NULL) + new_family = strdup (family); + if (!new_family) return CAIRO_STATUS_NO_MEMORY; + + _cairo_gstate_unset_font (gstate); + + gstate->font_family = new_family; + gstate->font_slant = slant; + gstate->font_weight = weight; cairo_matrix_set_identity (&gstate->font_matrix); @@ -2144,6 +2126,8 @@ cairo_status_t _cairo_gstate_scale_font (cairo_gstate_t *gstate, double scale) { + _cairo_gstate_unset_font (gstate); + return cairo_matrix_scale (&gstate->font_matrix, scale, scale); } @@ -2153,6 +2137,9 @@ _cairo_gstate_transform_font (cairo_gstate_t *gstate, { cairo_matrix_t tmp; double a, b, c, d, tx, ty; + + _cairo_gstate_unset_font (gstate); + cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty); cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0); return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp); @@ -2160,28 +2147,16 @@ _cairo_gstate_transform_font (cairo_gstate_t *gstate, cairo_status_t -_cairo_gstate_current_font (cairo_gstate_t *gstate, - cairo_font_t **font) +_cairo_gstate_current_font (cairo_gstate_t *gstate, + cairo_font_t **font) { - cairo_font_scale_t scale; - cairo_font_t *scaled; - double dummy; - - scaled = malloc (sizeof (cairo_font_t)); - if (scaled == NULL) - return CAIRO_STATUS_NO_MEMORY; - - cairo_matrix_get_affine (&gstate->font_matrix, - &scale.matrix[0][0], - &scale.matrix[0][1], - &scale.matrix[1][0], - &scale.matrix[1][1], - &dummy, &dummy); - - _cairo_font_init (scaled, &scale, gstate->font); - _cairo_unscaled_font_reference (gstate->font); + cairo_status_t status; - *font = scaled; + status = _cairo_gstate_ensure_font (gstate); + if (status) + return status; + + *font = gstate->font; return CAIRO_STATUS_SUCCESS; } @@ -2190,6 +2165,8 @@ void _cairo_gstate_set_font_transform (cairo_gstate_t *gstate, cairo_matrix_t *matrix) { + _cairo_gstate_unset_font (gstate); + cairo_matrix_copy (&gstate->font_matrix, matrix); } @@ -2214,12 +2191,10 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate, * independently scale the user coordinate system *or* the font matrix, in * order to adjust the rendered size of the font. * - * If the user asks for a permanent reference to "a font", they are given a - * handle to a structure holding a scale matrix and an unscaled font. This - * effectively decouples the font from further changes to user space. Even - * if the user then "sets" the current cairo_t font to the handle they were - * passed, further changes to the cairo_t CTM will not affect externally - * held references to the font. + * The only font type exposed to the user is cairo_font_t which is a + * a font specialized to a particular scale matrix, CTM, and target + * surface. The user is responsible for not using a cairo_font_t + * after changing the parameters; doing so will produce garbled metrics. * * * The font's view @@ -2279,9 +2254,9 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate, * */ -static void -_build_font_scale (cairo_gstate_t *gstate, - cairo_font_scale_t *sc) +void +_cairo_gstate_current_font_scale (cairo_gstate_t *gstate, + cairo_font_scale_t *sc) { cairo_matrix_t tmp; double dummy; @@ -2294,34 +2269,46 @@ _build_font_scale (cairo_gstate_t *gstate, &dummy, &dummy); } -cairo_status_t -_cairo_gstate_current_font_extents (cairo_gstate_t *gstate, - cairo_font_extents_t *extents) +static cairo_status_t +_cairo_gstate_ensure_font (cairo_gstate_t *gstate) { - cairo_int_status_t status; cairo_font_scale_t sc; - double font_scale_x, font_scale_y; + cairo_status_t status; + const char *family; + + if (gstate->font) + return CAIRO_STATUS_SUCCESS; + + _cairo_gstate_current_font_scale (gstate, &sc); - _build_font_scale (gstate, &sc); + if (gstate->font_family) + family = gstate->font_family; + else + family = CAIRO_FONT_FAMILY_DEFAULT; + + status = _cairo_font_create (family, + gstate->font_slant, + gstate->font_weight, + &sc, + &gstate->font); - status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents); + if (status) + return status; - _cairo_matrix_compute_scale_factors (&gstate->font_matrix, - &font_scale_x, &font_scale_y, - /* XXX */ 1); - - /* - * The font responded in unscaled units, scale by the font - * matrix scale factors to get to user space - */ - - extents->ascent *= font_scale_y; - extents->descent *= font_scale_y; - extents->height *= font_scale_y; - extents->max_x_advance *= font_scale_x; - extents->max_y_advance *= font_scale_y; - - return status; + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_current_font_extents (cairo_gstate_t *gstate, + cairo_font_extents_t *extents) +{ + cairo_status_t status = _cairo_gstate_ensure_font (gstate); + if (status) + return status; + + return cairo_font_extents (gstate->font, + &gstate->font_matrix, + extents); } cairo_status_t @@ -2331,14 +2318,15 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, int *nglyphs) { cairo_status_t status; - cairo_font_scale_t sc; cairo_point_t point; double origin_x, origin_y; int i; - _build_font_scale (gstate, &sc); - + status = _cairo_gstate_ensure_font (gstate); + if (status) + return status; + status = _cairo_path_current_point (&gstate->path, &point); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { origin_x = 0.0; @@ -2350,8 +2338,8 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, &origin_x, &origin_y); } - status = _cairo_unscaled_font_text_to_glyphs (gstate->font, - &sc, utf8, glyphs, nglyphs); + status = _cairo_font_text_to_glyphs (gstate->font, + utf8, glyphs, nglyphs); if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs)) return status; @@ -2373,18 +2361,16 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, cairo_status_t _cairo_gstate_set_font (cairo_gstate_t *gstate, - cairo_font_t *font) -{ - if (gstate->font != NULL) - _cairo_unscaled_font_destroy (gstate->font); - gstate->font = font->unscaled; - _cairo_unscaled_font_reference (gstate->font); - cairo_matrix_set_affine (&gstate->font_matrix, - font->scale.matrix[0][0], - font->scale.matrix[0][1], - font->scale.matrix[1][0], - font->scale.matrix[1][1], - 0, 0); + cairo_font_t *font) +{ + if (font != gstate->font) { + if (gstate->font) + cairo_font_destroy (gstate->font); + gstate->font = font; + if (gstate->font) + cairo_font_reference (gstate->font); + } + return CAIRO_STATUS_SUCCESS; } @@ -2394,90 +2380,18 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, int num_glyphs, cairo_text_extents_t *extents) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_glyph_t origin_glyph; - cairo_text_extents_t origin_extents; - cairo_font_scale_t sc; - int i; - double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0; - double x_pos = 0.0, y_pos = 0.0; - int set = 0; - - if (!num_glyphs) - { - extents->x_bearing = 0.0; - extents->y_bearing = 0.0; - extents->width = 0.0; - extents->height = 0.0; - extents->x_advance = 0.0; - extents->y_advance = 0.0; - return CAIRO_STATUS_SUCCESS; - } - - _build_font_scale (gstate, &sc); - - for (i = 0; i < num_glyphs; i++) - { - double x, y; - double wm, hm; - - origin_glyph = glyphs[i]; - origin_glyph.x = 0.0; - origin_glyph.y = 0.0; - status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc, - &origin_glyph, 1, - &origin_extents); - - /* - * Transform font space metrics into user space metrics - * by running the corners through the font matrix and - * expanding the bounding box as necessary - */ - x = origin_extents.x_bearing; - y = origin_extents.y_bearing; - cairo_matrix_transform_point (&gstate->font_matrix, - &x, &y); - - for (hm = 0.0; hm <= 1.0; hm += 1.0) - for (wm = 0.0; wm <= 1.0; wm += 1.0) - { - x = origin_extents.x_bearing + origin_extents.width * wm; - y = origin_extents.y_bearing + origin_extents.height * hm; - cairo_matrix_transform_point (&gstate->font_matrix, - &x, &y); - x += glyphs[i].x; - y += glyphs[i].y; - if (!set) - { - min_x = max_x = x; - min_y = max_y = y; - set = 1; - } - else - { - if (x < min_x) min_x = x; - if (x > max_x) max_x = x; - if (y < min_y) min_y = y; - if (y > max_y) max_y = y; - } - } + cairo_status_t status; - x = origin_extents.x_advance; - y = origin_extents.y_advance; - cairo_matrix_transform_point (&gstate->font_matrix, - &x, &y); - x_pos = glyphs[i].x + x; - y_pos = glyphs[i].y + y; - } + status = _cairo_gstate_ensure_font (gstate); + if (status) + return status; - extents->x_bearing = min_x - glyphs[0].x; - extents->y_bearing = min_y - glyphs[0].y; - extents->width = max_x - min_x; - extents->height = max_y - min_y; - extents->x_advance = x_pos - glyphs[0].x; - extents->y_advance = y_pos - glyphs[0].y; + cairo_font_glyph_extents (gstate->font, + &gstate->font_matrix, + glyphs, num_glyphs, + extents); - return status; + return CAIRO_STATUS_SUCCESS; } cairo_status_t @@ -2488,12 +2402,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_status_t status; int i; cairo_glyph_t *transformed_glyphs = NULL; - cairo_font_scale_t sc; - cairo_pattern_t pattern; + cairo_pattern_union_t pattern; cairo_box_t bbox; + cairo_rectangle_t extents; - _build_font_scale (gstate, &sc); - + status = _cairo_gstate_ensure_font (gstate); + if (status) + return status; + transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) return CAIRO_STATUS_NO_MEMORY; @@ -2506,52 +2422,34 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, &transformed_glyphs[i].y); } - _cairo_pattern_init_copy (&pattern, gstate->pattern); - status = _cairo_unscaled_font_glyph_bbox (gstate->font, &sc, - transformed_glyphs, num_glyphs, - &bbox); - if (status) - goto CLEANUP_GLYPHS; + status = _cairo_font_glyph_bbox (gstate->font, + transformed_glyphs, num_glyphs, + &bbox); + _cairo_box_round_to_rectangle (&bbox, &extents); - status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox); if (status) goto CLEANUP_GLYPHS; - + if (gstate->clip.surface) { cairo_surface_t *intermediate; + cairo_surface_pattern_t intermediate_pattern; cairo_color_t empty_color; - pixman_box16_t *draw_extents; - pixman_region16_t *draw_region; - - draw_region = pixman_region_create (); - if (draw_region == NULL) - { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; - } - status = _calculate_region_for_intermediate_clip_surface (draw_region, - &bbox, - &gstate->clip); - if (status) { - goto BAIL1; - } + _cairo_rectangle_intersect (&extents, &gstate->clip.rect); /* Shortcut if empty */ - if (!pixman_region_not_empty (draw_region)) { + if (_cairo_rectangle_empty (&extents)) { status = CAIRO_STATUS_SUCCESS; goto BAIL1; } - draw_extents = pixman_region_extents (draw_region); - _cairo_color_init (&empty_color); _cairo_color_set_alpha (&empty_color, .0); intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, CAIRO_FORMAT_A8, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1, + extents.width, + extents.height, &empty_color); if (intermediate == NULL) { status = CAIRO_STATUS_NO_MEMORY; @@ -2561,66 +2459,77 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, /* move the glyphs again, from dev space to intermediate space */ for (i = 0; i < num_glyphs; ++i) { - transformed_glyphs[i].x -= draw_extents->x1; - transformed_glyphs[i].y -= draw_extents->y1; + transformed_glyphs[i].x -= extents.x; + transformed_glyphs[i].y -= extents.y; } - status = _cairo_unscaled_font_show_glyphs (gstate->font, - &sc, - CAIRO_OPERATOR_ADD, - pattern.source, intermediate, - draw_extents->x1 - pattern.source_offset.x, - draw_extents->y1 - pattern.source_offset.y, - transformed_glyphs, num_glyphs); + _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0); + + status = _cairo_font_show_glyphs (gstate->font, + CAIRO_OPERATOR_ADD, + &pattern.base, intermediate, + extents.x, extents.y, + 0, 0, + extents.width, extents.height, + transformed_glyphs, num_glyphs); + + _cairo_pattern_fini (&pattern.base); if (status) goto BAIL2; + _cairo_pattern_init_for_surface (&pattern.surface, + gstate->clip.surface); + status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - gstate->clip.surface, + &pattern.base, NULL, intermediate, - draw_extents->x1 - gstate->clip.x, - draw_extents->y1 - gstate->clip.y, + extents.x - gstate->clip.rect.x, + extents.y - gstate->clip.rect.y, 0, 0, 0, 0, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); + extents.width, extents.height); + + _cairo_pattern_fini (&pattern.base); if (status) goto BAIL2; + _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); + _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern); + status = _cairo_surface_composite (gstate->operator, - pattern.source, - intermediate, + &pattern.base, + &intermediate_pattern.base, gstate->surface, - 0, 0, + extents.x, extents.y, 0, 0, - draw_extents->x1, - draw_extents->y1, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); + extents.x, extents.y, + extents.width, extents.height); + _cairo_pattern_fini (&pattern.base); + _cairo_pattern_fini (&intermediate_pattern.base); BAIL2: cairo_surface_destroy (intermediate); BAIL1: - pixman_region_destroy (draw_region); - BAIL0: ; } else { - status = _cairo_unscaled_font_show_glyphs (gstate->font, - &sc, - gstate->operator, pattern.source, - gstate->surface, - -pattern.source_offset.x, - -pattern.source_offset.y, - transformed_glyphs, num_glyphs); + _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern); + + status = _cairo_font_show_glyphs (gstate->font, + gstate->operator, &pattern.base, + gstate->surface, + extents.x, extents.y, + extents.x, extents.y, + extents.width, extents.height, + transformed_glyphs, num_glyphs); + + _cairo_pattern_fini (&pattern.base); } - _cairo_pattern_fini (&pattern); - CLEANUP_GLYPHS: free (transformed_glyphs); @@ -2635,9 +2544,6 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_status_t status; int i; cairo_glyph_t *transformed_glyphs = NULL; - cairo_font_scale_t sc; - - _build_font_scale (gstate, &sc); transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) @@ -2651,9 +2557,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, &(transformed_glyphs[i].y)); } - status = _cairo_unscaled_font_glyph_path (gstate->font, &sc, - transformed_glyphs, num_glyphs, - &gstate->path); + status = _cairo_font_glyph_path (gstate->font, + transformed_glyphs, num_glyphs, + &gstate->path); free (transformed_glyphs); return status; diff --git a/src/cairo-hash.c b/src/cairo-hash.c index b097b609b..d1ad5a4e2 100644 --- a/src/cairo-hash.c +++ b/src/cairo-hash.c @@ -94,9 +94,9 @@ static const cairo_cache_arrangement_t cache_arrangements [] = { * a mostly-dead table. * * Generally you do not need to worry about freeing cache entries; the - * cache will expire entries randomly as it experiences memory pressure. - * There is currently no explicit entry-removing call, though one can be - * added easily. + * cache will expire entries randomly as it experiences memory pressure. + * If max_memory is set, entries are not expired, and must be explicitely + * removed. * * This table is open-addressed with double hashing. Each table size is a * prime chosen to be a little more than double the high water mark for a @@ -282,17 +282,51 @@ _load_factor (cairo_cache_t *cache) } #endif -static unsigned long -_random_live_entry (cairo_cache_t *cache) -{ - unsigned long idx; - assert(cache != NULL); - do { - idx = rand () % cache->arrangement->size; - } while (! LIVE_ENTRY_P(cache, idx)); - return idx; -} +/* Find a random in the cache matching the given predicate. We use the + * same algorithm as the probing algorithm to walk over the entries in + * the hash table in a pseudo-random order. Walking linearly would + * favor entries following gaps in the hash table. We could also + * call rand() repeatedly, which works well for almost-full tables, + * but degrades when the table is almost empty, or predicate + * returns false for most entries. + */ +static cairo_cache_entry_base_t ** +_random_entry (cairo_cache_t *cache, + int (*predicate)(void*)) +{ + cairo_cache_entry_base_t **probe; + unsigned long hash; + unsigned long table_size, i, idx, step; + + _cache_sane_state (cache); + + table_size = cache->arrangement->size; + hash = rand (); + idx = hash % table_size; + step = 0; + + for (i = 0; i < table_size; ++i) + { + assert(idx < table_size); + probe = cache->entries + idx; + if (LIVE_ENTRY_P(cache, idx) + && (!predicate || predicate (*probe))) + return probe; + + if (step == 0) { + step = hash % cache->arrangement->rehash; + if (step == 0) + step = 1; + } + + idx += step; + if (idx >= table_size) + idx -= table_size; + } + + return NULL; +} /* public API follows */ @@ -356,8 +390,9 @@ _cairo_cache_destroy (cairo_cache_t *cache) cairo_status_t _cairo_cache_lookup (cairo_cache_t *cache, - void *key, - void **entry_return) + void *key, + void **entry_return, + int *created_entry) { unsigned long idx; @@ -392,6 +427,8 @@ _cairo_cache_lookup (cairo_cache_t *cache, cache->hits++; #endif *entry_return = *slot; + if (created_entry) + *created_entry = 0; return status; } @@ -401,19 +438,18 @@ _cairo_cache_lookup (cairo_cache_t *cache, /* Build the new entry. */ status = cache->backend->create_entry (cache, key, - entry_return); + (void **)&new_entry); if (status != CAIRO_STATUS_SUCCESS) return status; - new_entry = (cairo_cache_entry_base_t *) (*entry_return); - /* Store the hash value in case the backend forgot. */ new_entry->hashcode = cache->backend->hash (cache, key); /* Make some entries die if we're under memory pressure. */ while (cache->live_entries > 0 && + cache->max_memory > 0 && ((cache->max_memory - cache->used_memory) < new_entry->memory)) { - idx = _random_live_entry (cache); + idx = _random_entry (cache, NULL) - cache->entries; assert (idx < cache->arrangement->size); _entry_destroy (cache, idx); } @@ -425,7 +461,6 @@ _cairo_cache_lookup (cairo_cache_t *cache, status = _resize_cache (cache, cache->live_entries + 1); if (status != CAIRO_STATUS_SUCCESS) { cache->backend->destroy_entry (cache, new_entry); - *entry_return = NULL; return status; } @@ -439,9 +474,38 @@ _cairo_cache_lookup (cairo_cache_t *cache, _cache_sane_state (cache); + *entry_return = new_entry; + if (created_entry) + *created_entry = 1; + return status; } +cairo_status_t +_cairo_cache_remove (cairo_cache_t *cache, + void *key) +{ + cairo_cache_entry_base_t **slot; + + _cache_sane_state (cache); + + /* See if we have an entry in the table already. */ + slot = _find_exact_live_entry_for (cache, key); + if (slot != NULL) + _entry_destroy (cache, slot - cache->entries); + + return CAIRO_STATUS_SUCCESS; +} + +void * +_cairo_cache_random_entry (cairo_cache_t *cache, + int (*predicate)(void*)) +{ + cairo_cache_entry_base_t **slot = _random_entry (cache, predicate); + + return slot ? *slot : NULL; +} + unsigned long _cairo_hash_string (const char *c) { diff --git a/src/cairo-hull.c b/src/cairo-hull.c index 99b16d1ae..c93d70625 100644 --- a/src/cairo-hull.c +++ b/src/cairo-hull.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 14e30f695..9745b3150 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" @@ -54,7 +54,8 @@ _cairo_format_bpp (cairo_format_t format) } static cairo_image_surface_t * -_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image) +_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, + cairo_format_t format) { cairo_image_surface_t *surface; @@ -66,6 +67,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image) surface->pixman_image = pixman_image; + surface->format = format; surface->data = (char *) pixman_image_get_data (pixman_image); surface->owns_data = 0; @@ -105,7 +107,8 @@ _cairo_image_surface_create_with_masks (char *data, if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_pixman_image (pixman_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image, + (cairo_format_t)-1); return surface; } @@ -130,6 +133,20 @@ _create_pixman_format (cairo_format_t format) } } +/** + * cairo_image_surface_create: + * @format: format of pixels in the surface to create + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates an image surface of the specified format and + * dimensions. The initial contents of the surface is undefined; you + * must explicitely clear the buffer, using, for example, + * cairo_rectangle() and cairo_fill() if you want it cleared. + * + * Return value: the newly created surface, or %NULL if it couldn't + * be created because of lack of memory + **/ cairo_surface_t * cairo_image_surface_create (cairo_format_t format, int width, @@ -150,11 +167,33 @@ cairo_image_surface_create (cairo_format_t format, if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_pixman_image (pixman_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format); return &surface->base; } +/** + * cairo_image_surface_create_for_data: + * @data: a pointer to a buffer supplied by the application + * in which to write contents. + * @format: the format of pixels in the buffer + * @width: the width of the image to be stored in the buffer + * @height: the height of the image to be stored in the buffer + * @stride: the number of bytes between the start of rows + * in the buffer. Having this be specified separate from @width + * allows for padding at the end of rows, or for writing + * to a subportion of a larger image. + * + * Creates an image surface for the provided pixel data. The output + * buffer must be kept around until the #cairo_surface_t is destroyed + * or cairo_surface_finish() is called on the surface. The initial + * contents of @buffer will be used as the inital image contents; you + * must explicitely clear the buffer, using, for example, + * cairo_rectangle() and cairo_fill() if you want it cleared. + * + * Return value: the newly created surface, or %NULL if it couldn't + * be created because of lack of memory + **/ cairo_surface_t * cairo_image_surface_create_for_data (char *data, cairo_format_t format, @@ -180,7 +219,7 @@ cairo_image_surface_create_for_data (char *data, if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_pixman_image (pixman_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format); return &surface->base; } @@ -224,33 +263,66 @@ _cairo_image_surface_pixels_per_inch (void *abstract_surface) return 96.0; } -static cairo_image_surface_t * -_cairo_image_surface_get_image (void *abstract_surface) +static cairo_status_t +_cairo_image_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { - cairo_image_surface_t *surface = abstract_surface; - - cairo_surface_reference (&surface->base); + *image_out = abstract_surface; + + return CAIRO_STATUS_SUCCESS; +} - return surface; +static void +_cairo_image_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ } static cairo_status_t -_cairo_image_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +_cairo_image_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect_out, + void **image_extra) { - if (image == abstract_surface) - return CAIRO_STATUS_SUCCESS; + cairo_image_surface_t *surface = abstract_surface; + + image_rect_out->x = 0; + image_rect_out->y = 0; + image_rect_out->width = surface->width; + image_rect_out->height = surface->height; + + *image_out = surface; - /* XXX: This case has not yet been implemented. We'll lie for now. */ return CAIRO_STATUS_SUCCESS; } +static void +_cairo_image_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ +} + static cairo_status_t -_cairo_image_abstract_surface_set_matrix (void *abstract_surface, - cairo_matrix_t *matrix) +_cairo_image_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { cairo_image_surface_t *surface = abstract_surface; - return _cairo_image_surface_set_matrix (surface, matrix); + + if (src->backend == surface->base.backend) { + *clone_out = src; + cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; } cairo_status_t @@ -276,14 +348,6 @@ _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_image_abstract_surface_set_filter (void *abstract_surface, cairo_filter_t filter) -{ - cairo_image_surface_t *surface = abstract_surface; - - return _cairo_image_surface_set_filter (surface, filter); -} - cairo_status_t _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter) { @@ -314,13 +378,6 @@ _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_image_abstract_surface_set_repeat (void *abstract_surface, int repeat) -{ - cairo_image_surface_t *surface = abstract_surface; - return _cairo_image_surface_set_repeat (surface, repeat); -} - cairo_status_t _cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat) { @@ -329,6 +386,34 @@ _cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat) return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_image_surface_set_attributes (cairo_image_surface_t *surface, + cairo_surface_attributes_t *attributes) +{ + cairo_int_status_t status; + + status = _cairo_image_surface_set_matrix (surface, &attributes->matrix); + if (status) + return status; + + switch (attributes->extend) { + case CAIRO_EXTEND_NONE: + _cairo_image_surface_set_repeat (surface, 0); + break; + case CAIRO_EXTEND_REPEAT: + _cairo_image_surface_set_repeat (surface, 1); + break; + case CAIRO_EXTEND_REFLECT: + /* XXX: Obviously wrong. */ + _cairo_image_surface_set_repeat (surface, 1); + break; + } + + status = _cairo_image_surface_set_filter (surface, attributes->filter); + + return status; +} + static pixman_operator_t _pixman_operator (cairo_operator_t operator) { @@ -368,8 +453,8 @@ _pixman_operator (cairo_operator_t operator) static cairo_int_status_t _cairo_image_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, void *abstract_dst, int src_x, int src_y, @@ -380,26 +465,61 @@ _cairo_image_surface_composite (cairo_operator_t operator, unsigned int width, unsigned int height) { - cairo_image_surface_t *dst = abstract_dst; - cairo_image_surface_t *src = (cairo_image_surface_t *) generic_src; - cairo_image_surface_t *mask = (cairo_image_surface_t *) generic_mask; - - if (generic_src->backend != dst->base.backend || - (generic_mask && (generic_mask->backend != dst->base.backend))) + cairo_surface_attributes_t src_attr, mask_attr; + cairo_image_surface_t *dst = abstract_dst; + cairo_image_surface_t *src; + cairo_image_surface_t *mask; + cairo_int_status_t status; + + status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern, + &dst->base, + src_x, src_y, + mask_x, mask_y, + width, height, + (cairo_surface_t **) &src, + (cairo_surface_t **) &mask, + &src_attr, &mask_attr); + if (status) + return status; + + status = _cairo_image_surface_set_attributes (src, &src_attr); + if (CAIRO_OK (status)) { - return CAIRO_INT_STATUS_UNSUPPORTED; + if (mask) + { + status = _cairo_image_surface_set_attributes (mask, &mask_attr); + if (CAIRO_OK (status)) + pixman_composite (_pixman_operator (operator), + src->pixman_image, + mask->pixman_image, + dst->pixman_image, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + mask_x + mask_attr.x_offset, + mask_y + mask_attr.y_offset, + dst_x, dst_y, + width, height); + } + else + { + pixman_composite (_pixman_operator (operator), + src->pixman_image, + NULL, + dst->pixman_image, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + } } - pixman_composite (_pixman_operator (operator), - src->pixman_image, - mask ? mask->pixman_image : NULL, - dst->pixman_image, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); - - return CAIRO_STATUS_SUCCESS; + if (mask) + _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr); + + _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr); + + return status; } static cairo_int_status_t @@ -427,24 +547,56 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, static cairo_int_status_t _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, + cairo_pattern_t *pattern, void *abstract_dst, - int x_src, - int y_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps) { - cairo_image_surface_t *dst = abstract_dst; - cairo_image_surface_t *src = (cairo_image_surface_t *) generic_src; + cairo_surface_attributes_t attributes; + cairo_image_surface_t *dst = abstract_dst; + cairo_image_surface_t *src; + cairo_int_status_t status; + int render_reference_x, render_reference_y; + int render_src_x, render_src_y; + + status = _cairo_pattern_acquire_surface (pattern, &dst->base, + src_x, src_y, width, height, + (cairo_surface_t **) &src, + &attributes); + if (status) + return status; + + if (traps[0].left.p1.y < traps[0].left.p2.y) { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y); + } else { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y); + } - if (generic_src->backend != dst->base.backend) - return CAIRO_INT_STATUS_UNSUPPORTED; + render_src_x = src_x + render_reference_x - dst_x; + render_src_y = src_y + render_reference_y - dst_y; - /* XXX: The pixman_trapezoid_t cast is evil and needs to go away somehow. */ - pixman_composite_trapezoids (operator, src->pixman_image, dst->pixman_image, - x_src, y_src, (pixman_trapezoid_t *) traps, num_traps); + /* XXX: The pixman_trapezoid_t cast is evil and needs to go away + * somehow. */ + status = _cairo_image_surface_set_attributes (src, &attributes); + if (CAIRO_OK (status)) + pixman_composite_trapezoids (operator, + src->pixman_image, + dst->pixman_image, + render_src_x + attributes.x_offset, + render_src_y + attributes.y_offset, + (pixman_trapezoid_t *) traps, num_traps); - return CAIRO_STATUS_SUCCESS; + _cairo_pattern_release_surface (&dst->base, &src->base, &attributes); + + return status; } static cairo_int_status_t @@ -490,41 +642,34 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_image_abstract_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *box) +/** + * _cairo_surface_is_image: + * @surface: a #cairo_surface_t + * + * Checks if a surface is an #cairo_image_surface_t + * + * Return value: True if the surface is an image surface + **/ +int +_cairo_surface_is_image (cairo_surface_t *surface) { - cairo_image_surface_t *image; - - /* Fall back to general pattern creation for surface patterns. */ - if (pattern->type == CAIRO_PATTERN_SURFACE) - return CAIRO_INT_STATUS_UNSUPPORTED; - - image = _cairo_pattern_get_image (pattern, box); - if (image) { - pattern->source = &image->base; - - return CAIRO_STATUS_SUCCESS; - } else - return CAIRO_STATUS_NO_MEMORY; + return surface->backend == &cairo_image_surface_backend; } - + static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_create_similar, _cairo_image_abstract_surface_destroy, _cairo_image_surface_pixels_per_inch, - _cairo_image_surface_get_image, - _cairo_image_surface_set_image, - _cairo_image_abstract_surface_set_matrix, - _cairo_image_abstract_surface_set_filter, - _cairo_image_abstract_surface_set_repeat, + _cairo_image_surface_acquire_source_image, + _cairo_image_surface_release_source_image, + _cairo_image_surface_acquire_dest_image, + _cairo_image_surface_release_dest_image, + _cairo_image_surface_clone_similar, _cairo_image_surface_composite, _cairo_image_surface_fill_rectangles, _cairo_image_surface_composite_trapezoids, _cairo_image_surface_copy_page, _cairo_image_surface_show_page, _cairo_image_abstract_surface_set_clip_region, - _cairo_image_abstract_surface_create_pattern, NULL /* show_glyphs */ }; diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index b964b688c..88e536e8a 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #define _GNU_SOURCE @@ -54,6 +54,14 @@ _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar); static void _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix); +/** + * cairo_matrix_create: + * + * Creates a new identity matrix. + * + * Return value: a newly created matrix; free with cairo_matrix_destroy(), + * or %NULL if memory couldn't be allocated. + **/ cairo_matrix_t * cairo_matrix_create (void) { @@ -80,6 +88,12 @@ _cairo_matrix_fini (cairo_matrix_t *matrix) /* nothing to do here */ } +/** + * cairo_matrix_destroy: + * @matrix: a #cairo_matrix_t + * + * Frees a matrix created with cairo_matrix_create. + **/ void cairo_matrix_destroy (cairo_matrix_t *matrix) { @@ -87,6 +101,15 @@ cairo_matrix_destroy (cairo_matrix_t *matrix) free (matrix); } +/** + * cairo_matrix_copy: + * @matrix: a #cairo_matrix_t + * @other: another #cairo_ + * + * Modifies @matrix to be identical to @other. + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other) { @@ -96,6 +119,14 @@ cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other) } slim_hidden_def(cairo_matrix_copy); +/** + * cairo_matrix_set_identity: + * @matrix: a #cairo_matrix_t + * + * Modifies @matrix to be an identity transformation. + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_set_identity (cairo_matrix_t *matrix) { @@ -105,6 +136,26 @@ cairo_matrix_set_identity (cairo_matrix_t *matrix) } slim_hidden_def(cairo_matrix_set_identity); +/** + * cairo_matrix_set_affine: + * @matrix: a cairo_matrix_t + * @a: a component of the affine transformation + * @b: b component of the affine transformation + * @c: c component of the affine transformation + * @d: d component of the affine transformation + * @tx: X translation component of the affine transformation + * @ty: Y translation component of the affine transformation + * + * Sets @matrix to be the affine transformation given by + * @a, b, @c, @d, @tx, @ty. The transformation is given + * by: + * <programlisting> + * x_new = x * a + y * c + tx; + * y_new = x * b + y * d + ty; + * </programlisting> + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_set_affine (cairo_matrix_t *matrix, double a, double b, @@ -119,6 +170,21 @@ cairo_matrix_set_affine (cairo_matrix_t *matrix, } slim_hidden_def(cairo_matrix_set_affine); +/** + * cairo_matrix_get_affine: + * @matrix: a @cairo_matrix_t + * @a: location to store a component of affine transformation, or %NULL + * @b: location to store b component of affine transformation, or %NULL + * @c: location to store c component of affine transformation, or %NULL + * @d: location to store d component of affine transformation, or %NULL + * @tx: location to store X-translation component of affine transformation, or %NULL + * @ty: location to store Y-translation component of affine transformation, or %NULL + * + * Gets the matrix values for the affine tranformation that @matrix represents. + * See cairo_matrix_set_affine(). + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_get_affine (cairo_matrix_t *matrix, double *a, double *b, @@ -153,6 +219,18 @@ _cairo_matrix_set_translate (cairo_matrix_t *matrix, tx, ty); } +/** + * cairo_matrix_translate: + * @matrix: a cairo_matrix_t + * @tx: amount to rotate in the X direction + * @ty: amount to rotate in the Y direction + * + * Applies a translation by @tx, @ty to the transformation in + * @matrix. The new transformation is given by first translating by + * @tx, @ty then applying the original transformation + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty) { @@ -173,6 +251,18 @@ _cairo_matrix_set_scale (cairo_matrix_t *matrix, 0, 0); } +/** + * cairo_matrix_scale: + * @matrix: a #cairo_matrix_t + * @sx: Scale factor in the X direction + * @sy: Scale factor in the Y direction + * + * Applies scaling by @tx, @ty to the transformation in + * @matrix. The new transformation is given by first scaling by @sx + * and @sy then applying the original transformation + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy) { @@ -202,6 +292,21 @@ _cairo_matrix_set_rotate (cairo_matrix_t *matrix, 0, 0); } +/** + * cairo_matrix_rotate: + * @matrix: a @cairo_matrix_t + * @radians: angle of rotation, in radians. Angles are defined + * so that an angle of 90 degrees (%M_PI radians) rotates the + * positive X axis into the positive Y axis. With the default + * Cairo choice of axis orientation, positive rotations are + * clockwise. + * + * Applies rotation by @radians to the transformation in + * @matrix. The new transformation is given by first rotating by + * @radians then applying the original transformation + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_rotate (cairo_matrix_t *matrix, double radians) { @@ -212,6 +317,19 @@ cairo_matrix_rotate (cairo_matrix_t *matrix, double radians) return cairo_matrix_multiply (matrix, &tmp, matrix); } +/** + * cairo_matrix_multiply: + * @result: a @cairo_matrix_t in which to store the result + * @a: a @cairo_matrix_t + * @b: a @cairo_matrix_t + * + * Multiplies the affine transformations in @a and @b together + * and stores the result in @result. The resulting transformation + * is given by first applying the transformation in @b then + * applying the transformation in @a. + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b) { @@ -238,6 +356,27 @@ cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const ca } slim_hidden_def(cairo_matrix_multiply); +/** + * cairo_matrix_transform_distance: + * @matrix: a @cairo_matrix_t + * @dx: a distance in the X direction. An in/out parameter + * @dy: a distance in the Y direction. An in/out parameter + * + * Transforms the vector (@dx,@dy) by @matrix. Translation is + * ignored. In terms of the components of the affine transformation: + * + * <programlisting> + * dx2 = dx1 * a + dy1 * c; + * dy2 = dx1 * b + dy1 * d; + * </programlisting> + * + * Affine transformations are position invariant, so the same vector + * always transforms to the same vector. If (@x1,@y1) transforms + * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to + * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2. + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy) { @@ -255,6 +394,16 @@ cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy) } slim_hidden_def(cairo_matrix_transform_distance); +/** + * cairo_matrix_transform_point: + * @matrix: a @cairo_matrix_t + * @x: X position. An in/out parameter + * @y: Y position. An in/out parameter + * + * Transforms the point (@x, @y) by @matrix. + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y) { @@ -351,6 +500,19 @@ _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix) c*ty - d*tx, b*tx - a*ty); } +/** + * cairo_matrix_invert: + * @matrix: a @cairo_matrix_t + * + * Changes @matrix to be the inverse of it's original value. Not + * all transformation matrices have inverses; if the matrix + * collapses points together (it is <firstterm>degenerate</firstterm>), + * then it has no inverse and this function will fail. + * + * Returns: If @matrix has an inverse, modifies @matrix to + * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise, + * returns %CAIRO_STATUS_INVALID_MATRIX. + **/ cairo_status_t cairo_matrix_invert (cairo_matrix_t *matrix) { @@ -458,7 +620,7 @@ _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double return CAIRO_STATUS_SUCCESS; } -int +cairo_bool_t _cairo_matrix_is_integer_translation(cairo_matrix_t *mat, int *itx, int *ity) { @@ -477,7 +639,7 @@ _cairo_matrix_is_integer_translation(cairo_matrix_t *mat, if (ok) { *itx = _cairo_fixed_integer_part(ttx); *ity = _cairo_fixed_integer_part(tty); - return 1; + return TRUE; } - return 0; + return FALSE; } diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c index cfcdd97ee..7c5772a82 100644 --- a/src/cairo-path-bounds.c +++ b/src/cairo-path-bounds.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index 6c6ebd976..dc79b6b96 100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index ad0220370..08b380902 100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo-path.c b/src/cairo-path.c index 36c25d637..8314f601c 100644 --- a/src/cairo-path.c +++ b/src/cairo-path.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include <stdlib.h> @@ -100,6 +100,7 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other) for (other_op = other->op_head; other_op; other_op = other_op->next) { op = _cairo_path_op_buf_create (); if (op == NULL) { + _cairo_path_fini(path); return CAIRO_STATUS_NO_MEMORY; } *op = *other_op; @@ -109,6 +110,7 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other) for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) { arg = _cairo_path_arg_buf_create (); if (arg == NULL) { + _cairo_path_fini(path); return CAIRO_STATUS_NO_MEMORY; } *arg = *other_arg; diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 6cb981458..283c36dbd 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -21,58 +21,108 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * Author: David Reveman <c99drn@cs.umu.se> + * Author: David Reveman <davidr@novell.com> */ #include "cairoint.h" +typedef void (*cairo_shader_function_t) (unsigned char *color0, + unsigned char *color1, + cairo_fixed_t factor, + uint32_t *pixel); + +typedef struct _cairo_shader_color_stop { + cairo_fixed_t offset; + cairo_fixed_48_16_t scale; + int id; + unsigned char color_char[4]; +} cairo_shader_color_stop_t; + +typedef struct _cairo_shader_op { + cairo_shader_color_stop_t *stops; + int n_stops; + cairo_extend_t extend; + cairo_shader_function_t shader_function; +} cairo_shader_op_t; + #define MULTIPLY_COLORCOMP(c1, c2) \ ((unsigned char) \ ((((unsigned char) (c1)) * (int) ((unsigned char) (c2))) / 0xff)) -void -_cairo_pattern_init (cairo_pattern_t *pattern) +static void +_cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) { + pattern->type = type; pattern->ref_count = 1; - - pattern->extend = CAIRO_EXTEND_DEFAULT; - pattern->filter = CAIRO_FILTER_DEFAULT; - - _cairo_color_init (&pattern->color); + pattern->extend = CAIRO_EXTEND_DEFAULT; + pattern->filter = CAIRO_FILTER_DEFAULT; + pattern->alpha = 1.0; _cairo_matrix_init (&pattern->matrix); +} - pattern->stops = NULL; - pattern->n_stops = 0; +static cairo_status_t +_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, + cairo_gradient_pattern_t *other) +{ + if (other->base.type == CAIRO_PATTERN_LINEAR) + { + cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern; + cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other; + + *dst = *src; + } + else + { + cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern; + cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other; + + *dst = *src; + } - pattern->type = CAIRO_PATTERN_SOLID; + if (other->n_stops) + { + pattern->stops = malloc (other->n_stops * sizeof (cairo_color_stop_t)); + if (!pattern->stops) + return CAIRO_STATUS_NO_MEMORY; + + memcpy (pattern->stops, other->stops, + other->n_stops * sizeof (cairo_color_stop_t)); + } - pattern->source = NULL; - pattern->source_offset.x = 0.0; - pattern->source_offset.y = 0.0; + return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other) { - *pattern = *other; - - pattern->ref_count = 1; + switch (other->type) { + case CAIRO_PATTERN_SOLID: { + cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern; + cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other; - if (pattern->n_stops) { - pattern->stops = - malloc (sizeof (cairo_color_stop_t) * pattern->n_stops); - if (pattern->stops == NULL) - return CAIRO_STATUS_NO_MEMORY; - memcpy (pattern->stops, other->stops, - sizeof (cairo_color_stop_t) * other->n_stops); + *dst = *src; + } break; + case CAIRO_PATTERN_SURFACE: { + cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern; + cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other; + + *dst = *src; + cairo_surface_reference (dst->surface); + } break; + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern; + cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other; + cairo_status_t status; + + status = _cairo_gradient_pattern_init_copy (dst, src); + if (status) + return status; + } break; } - - if (pattern->source) - cairo_surface_reference (other->source); - - if (pattern->type == CAIRO_PATTERN_SURFACE) - cairo_surface_reference (other->u.surface.surface); + + pattern->ref_count = 1; return CAIRO_STATUS_SUCCESS; } @@ -80,110 +130,145 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other) void _cairo_pattern_fini (cairo_pattern_t *pattern) { - if (pattern->n_stops) - free (pattern->stops); - - if (pattern->type == CAIRO_PATTERN_SURFACE) { - /* show_surface require us to restore surface matrix, repeat - attribute, filter type */ - if (pattern->source) { - cairo_surface_set_matrix (pattern->source, - &pattern->u.surface.save_matrix); - cairo_surface_set_repeat (pattern->source, - pattern->u.surface.save_repeat); - cairo_surface_set_filter (pattern->source, - pattern->u.surface.save_filter); - } - cairo_surface_destroy (pattern->u.surface.surface); + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: + break; + case CAIRO_PATTERN_SURFACE: { + cairo_surface_pattern_t *fini = (cairo_surface_pattern_t *) pattern; + + cairo_surface_destroy (fini->surface); + } break; + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_gradient_pattern_t *fini = (cairo_gradient_pattern_t *) pattern; + + if (fini->n_stops) + free (fini->stops); + } break; } +} + +void +_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, + double red, + double green, + double blue) +{ + _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SOLID); - if (pattern->source) - cairo_surface_destroy (pattern->source); + pattern->red = red; + pattern->green = green; + pattern->blue = blue; } void -_cairo_pattern_init_solid (cairo_pattern_t *pattern, - double red, double green, double blue) +_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern, + cairo_surface_t *surface) { - _cairo_pattern_init (pattern); + _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SURFACE); + + pattern->surface = surface; + cairo_surface_reference (surface); +} - pattern->type = CAIRO_PATTERN_SOLID; - _cairo_color_set_rgb (&pattern->color, red, green, blue); +static void +_cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern, + cairo_pattern_type_t type) +{ + _cairo_pattern_init (&pattern->base, type); + + pattern->stops = 0; + pattern->n_stops = 0; +} + +void +_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern, + double x0, double y0, double x1, double y1) +{ + _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_LINEAR); + + pattern->point0.x = x0; + pattern->point0.y = y0; + pattern->point1.x = x1; + pattern->point1.y = y1; +} + +void +_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, + double cx0, double cy0, double radius0, + double cx1, double cy1, double radius1) +{ + _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_RADIAL); + + pattern->center0.x = cx0; + pattern->center0.y = cy0; + pattern->radius0 = fabs (radius0); + pattern->center1.x = cx1; + pattern->center1.y = cy1; + pattern->radius1 = fabs (radius1); } cairo_pattern_t * _cairo_pattern_create_solid (double red, double green, double blue) { - cairo_pattern_t *pattern; + cairo_solid_pattern_t *pattern; - pattern = malloc (sizeof (cairo_pattern_t)); + pattern = malloc (sizeof (cairo_solid_pattern_t)); if (pattern == NULL) return NULL; _cairo_pattern_init_solid (pattern, red, green, blue); - return pattern; + return &pattern->base; } cairo_pattern_t * cairo_pattern_create_for_surface (cairo_surface_t *surface) { - cairo_pattern_t *pattern; + cairo_surface_pattern_t *pattern; - pattern = malloc (sizeof (cairo_pattern_t)); + pattern = malloc (sizeof (cairo_surface_pattern_t)); if (pattern == NULL) return NULL; - _cairo_pattern_init (pattern); - - pattern->type = CAIRO_PATTERN_SURFACE; - pattern->u.surface.surface = surface; - cairo_surface_reference (surface); + _cairo_pattern_init_for_surface (pattern, surface); + + /* this will go away when we completely remove the surface attributes */ + if (surface->repeat) + pattern->base.extend = CAIRO_EXTEND_REPEAT; + else + pattern->base.extend = CAIRO_EXTEND_DEFAULT; - return pattern; + return &pattern->base; } cairo_pattern_t * cairo_pattern_create_linear (double x0, double y0, double x1, double y1) { - cairo_pattern_t *pattern; + cairo_linear_pattern_t *pattern; - pattern = malloc (sizeof (cairo_pattern_t)); + pattern = malloc (sizeof (cairo_linear_pattern_t)); if (pattern == NULL) return NULL; - _cairo_pattern_init (pattern); - - pattern->type = CAIRO_PATTERN_LINEAR; - pattern->u.linear.point0.x = x0; - pattern->u.linear.point0.y = y0; - pattern->u.linear.point1.x = x1; - pattern->u.linear.point1.y = y1; + _cairo_pattern_init_linear (pattern, x0, y0, x1, y1); - return pattern; + return &pattern->base.base; } cairo_pattern_t * cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1) { - cairo_pattern_t *pattern; + cairo_radial_pattern_t *pattern; - pattern = malloc (sizeof (cairo_pattern_t)); + pattern = malloc (sizeof (cairo_radial_pattern_t)); if (pattern == NULL) return NULL; - _cairo_pattern_init (pattern); - - pattern->type = CAIRO_PATTERN_RADIAL; - pattern->u.radial.center0.x = cx0; - pattern->u.radial.center0.y = cy0; - pattern->u.radial.radius0 = fabs (radius0); - pattern->u.radial.center1.x = cx1; - pattern->u.radial.center1.y = cy1; - pattern->u.radial.radius1 = fabs (radius1); + _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1); - return pattern; + return &pattern->base.base; } void @@ -209,37 +294,19 @@ cairo_pattern_destroy (cairo_pattern_t *pattern) free (pattern); } -static int -_cairo_pattern_stop_compare (const void *elem1, const void *elem2) -{ - return - (((cairo_color_stop_t *) elem1)->offset == - ((cairo_color_stop_t *) elem2)->offset) ? - /* equal offsets, sort on id */ - ((((cairo_color_stop_t *) elem1)->id < - ((cairo_color_stop_t *) elem2)->id) ? -1 : 1) : - /* sort on offset */ - ((((cairo_color_stop_t *) elem1)->offset < - ((cairo_color_stop_t *) elem2)->offset) ? -1 : 1); -} - -cairo_status_t -cairo_pattern_add_color_stop (cairo_pattern_t *pattern, - double offset, - double red, double green, double blue, - double alpha) +static cairo_status_t +_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, + double offset, + double red, + double green, + double blue, + double alpha) { cairo_color_stop_t *stop; - int i; - - _cairo_restrict_value (&offset, 0.0, 1.0); - _cairo_restrict_value (&red, 0.0, 1.0); - _cairo_restrict_value (&green, 0.0, 1.0); - _cairo_restrict_value (&blue, 0.0, 1.0); pattern->n_stops++; pattern->stops = realloc (pattern->stops, - sizeof (cairo_color_stop_t) * pattern->n_stops); + pattern->n_stops * sizeof (cairo_color_stop_t)); if (pattern->stops == NULL) { pattern->n_stops = 0; @@ -249,41 +316,51 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern, stop = &pattern->stops[pattern->n_stops - 1]; stop->offset = _cairo_fixed_from_double (offset); - stop->id = pattern->n_stops; - stop->color_char[0] = red * 0xff; - stop->color_char[1] = green * 0xff; - stop->color_char[2] = blue * 0xff; - stop->color_char[3] = alpha * 0xff; + _cairo_color_init (&stop->color); + _cairo_color_set_rgb (&stop->color, red, green, blue); + _cairo_color_set_alpha (&stop->color, alpha); - /* sort stops in ascending order */ - qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t), - _cairo_pattern_stop_compare); - - for (i = 0; i < pattern->n_stops - 1; i++) { - pattern->stops[i + 1].scale = - pattern->stops[i + 1].offset - pattern->stops[i].offset; - if (pattern->stops[i + 1].scale == 65536) - pattern->stops[i + 1].scale = 0; + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_pattern_add_color_stop (cairo_pattern_t *pattern, + double offset, + double red, + double green, + double blue, + double alpha) +{ + if (pattern->type != CAIRO_PATTERN_LINEAR && + pattern->type != CAIRO_PATTERN_RADIAL) + { + /* XXX: CAIRO_STATUS_INVALID_PATTERN? */ + return CAIRO_STATUS_SUCCESS; } - return CAIRO_STATUS_SUCCESS; + _cairo_restrict_value (&offset, 0.0, 1.0); + _cairo_restrict_value (&red, 0.0, 1.0); + _cairo_restrict_value (&green, 0.0, 1.0); + _cairo_restrict_value (&blue, 0.0, 1.0); + _cairo_restrict_value (&alpha, 0.0, 1.0); + + return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, + offset, + red, green, blue, + alpha); } cairo_status_t cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) { - cairo_matrix_copy (&pattern->matrix, matrix); - - return CAIRO_STATUS_SUCCESS; + return cairo_matrix_copy (&pattern->matrix, matrix); } cairo_status_t cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) { - cairo_matrix_copy (matrix, &pattern->matrix); - - return CAIRO_STATUS_SUCCESS; + return cairo_matrix_copy (matrix, &pattern->matrix); } cairo_status_t @@ -316,9 +393,20 @@ cairo_pattern_get_extend (cairo_pattern_t *pattern) cairo_status_t _cairo_pattern_get_rgb (cairo_pattern_t *pattern, - double *red, double *green, double *blue) + double *red, + double *green, + double *blue) { - _cairo_color_get_rgb (&pattern->color, red, green, blue); + + if (pattern->type == CAIRO_PATTERN_SOLID) + { + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; + + *red = solid->red; + *green = solid->green; + *blue = solid->blue; + } else + *red = *green = *blue = 1.0; return CAIRO_STATUS_SUCCESS; } @@ -326,63 +414,16 @@ _cairo_pattern_get_rgb (cairo_pattern_t *pattern, void _cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha) { - int i; - - _cairo_color_set_alpha (&pattern->color, alpha); - - for (i = 0; i < pattern->n_stops; i++) - pattern->stops[i].color_char[3] = - MULTIPLY_COLORCOMP (pattern->stops[i].color_char[3], alpha * 0xff); -} - -void -_cairo_pattern_set_source_offset (cairo_pattern_t *pattern, - double x, double y) -{ - pattern->source_offset.x = x; - pattern->source_offset.y = y; + pattern->alpha = alpha; } void _cairo_pattern_transform (cairo_pattern_t *pattern, - cairo_matrix_t *ctm_inverse) + cairo_matrix_t *ctm_inverse) { cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix); } -void -_cairo_pattern_prepare_surface (cairo_pattern_t *pattern) -{ - cairo_matrix_t device_to_source; - cairo_matrix_t user_to_source; - - /* should the surface matrix interface be remove from the API? - for now we multiple the surface matrix with the pattern matrix */ - cairo_surface_get_matrix (pattern->u.surface.surface, &user_to_source); - cairo_matrix_multiply (&device_to_source, &pattern->matrix, - &user_to_source); - cairo_surface_set_matrix (pattern->source, &device_to_source); - - /* storing original surface matrix in pattern */ - pattern->u.surface.save_matrix = user_to_source; - - /* storing original surface repeat mode in pattern */ - pattern->u.surface.save_repeat = pattern->source->repeat; - - /* what do we do with extend types pad and reflect? */ - if (pattern->extend == CAIRO_EXTEND_REPEAT - || pattern->source->repeat == 1) - cairo_surface_set_repeat (pattern->source, 1); - else - cairo_surface_set_repeat (pattern->source, 0); - - /* storing original surface filter in pattern */ - pattern->u.surface.save_filter = - cairo_surface_get_filter (pattern->source); - - cairo_surface_set_filter (pattern->source, pattern->filter); -} - #define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \ ((factor < 32768)? c1: c2) @@ -390,7 +431,7 @@ static void _cairo_pattern_shader_nearest (unsigned char *color0, unsigned char *color1, cairo_fixed_t factor, - int *pixel) + uint32_t *pixel) { *pixel = ((INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor) << 24) | @@ -408,7 +449,7 @@ static void _cairo_pattern_shader_linear (unsigned char *color0, unsigned char *color1, cairo_fixed_t factor, - int *pixel) + uint32_t *pixel) { *pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) | (INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) | @@ -422,7 +463,7 @@ static void _cairo_pattern_shader_gaussian (unsigned char *color0, unsigned char *color1, cairo_fixed_t factor, - int *pixel) + uint32_t *pixel) { double f = ((double) factor) / 65536.0; @@ -436,17 +477,59 @@ _cairo_pattern_shader_gaussian (unsigned char *color0, #undef INTERPOLATE_COLOR_LINEAR -void -_cairo_pattern_shader_init (cairo_pattern_t *pattern, - cairo_shader_op_t *op) -{ - op->stops = pattern->stops; - op->n_stops = pattern->n_stops - 1; - op->min_offset = pattern->stops[0].offset; - op->max_offset = pattern->stops[op->n_stops].offset; - op->extend = pattern->extend; - - switch (pattern->filter) { +static int +_cairo_shader_color_stop_compare (const void *elem1, const void *elem2) +{ + cairo_shader_color_stop_t *s1 = (cairo_shader_color_stop_t *) elem1; + cairo_shader_color_stop_t *s2 = (cairo_shader_color_stop_t *) elem2; + + return + (s1->offset == s2->offset) ? + /* equal offsets, sort on id */ + ((s1->id < s2->id) ? -1 : 1) : + /* sort on offset */ + ((s1->offset < s2->offset) ? -1 : 1); +} + +static cairo_status_t +_cairo_pattern_shader_init (cairo_gradient_pattern_t *pattern, + cairo_shader_op_t *op) +{ + int i; + + op->stops = malloc (pattern->n_stops * sizeof (cairo_shader_color_stop_t)); + if (!op->stops) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < pattern->n_stops; i++) + { + op->stops[i].color_char[0] = pattern->stops[i].color.red * 0xff; + op->stops[i].color_char[1] = pattern->stops[i].color.green * 0xff; + op->stops[i].color_char[2] = pattern->stops[i].color.blue * 0xff; + op->stops[i].color_char[3] = pattern->stops[i].color.alpha * + pattern->base.alpha * 0xff; + op->stops[i].offset = pattern->stops[i].offset; + op->stops[i].id = i; + } + + /* sort stops in ascending order */ + qsort (op->stops, pattern->n_stops, sizeof (cairo_shader_color_stop_t), + _cairo_shader_color_stop_compare); + + for (i = 0; i < pattern->n_stops - 1; i++) + { + op->stops[i + 1].scale = op->stops[i + 1].offset - op->stops[i].offset; + if (op->stops[i + 1].scale == 65536) + op->stops[i + 1].scale = 0; + } + + op->n_stops = pattern->n_stops; + op->extend = pattern->base.extend; + + /* XXX: this is wrong, the filter should not be used for selecting + color stop interpolation function. function should always be 'linear' + and filter should be used for computing pixels. */ + switch (pattern->base.filter) { case CAIRO_FILTER_FAST: case CAIRO_FILTER_NEAREST: op->shader_function = _cairo_pattern_shader_nearest; @@ -460,15 +543,56 @@ _cairo_pattern_shader_init (cairo_pattern_t *pattern, op->shader_function = _cairo_pattern_shader_linear; break; } + + return CAIRO_STATUS_SUCCESS; } -void -_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op, - cairo_fixed_t factor, - int *pixel) +static void +_cairo_pattern_shader_fini (cairo_shader_op_t *op) +{ + if (op->stops) + free (op->stops); +} + +/* Find two color stops bounding the given offset. If the given offset + * is before the first or after the last stop offset, the nearest + * offset is returned twice. + */ +static void +_cairo_shader_op_find_color_stops (cairo_shader_op_t *op, + cairo_fixed_t offset, + cairo_shader_color_stop_t *stops[2]) { int i; - + + /* Before first stop. */ + if (offset <= op->stops[0].offset) { + stops[0] = &op->stops[0]; + stops[1] = &op->stops[0]; + return; + } + + /* Between two stops. */ + for (i = 0; i < op->n_stops - 1; i++) { + if (offset <= op->stops[i + 1].offset) { + stops[0] = &op->stops[i]; + stops[1] = &op->stops[i + 1]; + return; + } + } + + /* After last stop. */ + stops[0] = &op->stops[op->n_stops - 1]; + stops[1] = &op->stops[op->n_stops - 1]; +} + +static void +_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op, + cairo_fixed_t factor, + uint32_t *pixel) +{ + cairo_shader_color_stop_t *stops[2]; + switch (op->extend) { case CAIRO_EXTEND_REPEAT: factor -= factor & 0xffff0000; @@ -485,96 +609,158 @@ _cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op, break; } - if (factor < op->min_offset) - factor = op->min_offset; - else if (factor > op->max_offset) - factor = op->max_offset; - - for (i = 0; i < op->n_stops; i++) { - if (factor <= op->stops[i + 1].offset) { - - /* take offset as new 0 of coordinate system */ - factor -= op->stops[i].offset; - - /* difference between two offsets == 0, abrubt change */ - if (op->stops[i + 1].scale) - factor = ((cairo_fixed_48_16_t) factor << 16) / - op->stops[i + 1].scale; + _cairo_shader_op_find_color_stops (op, factor, stops); + + /* take offset as new 0 of coordinate system */ + factor -= stops[0]->offset; - op->shader_function (op->stops[i].color_char, - op->stops[i + 1].color_char, - factor, pixel); + /* difference between two offsets == 0, abrubt change */ + if (stops[1]->scale) + factor = ((cairo_fixed_48_16_t) factor << 16) / + stops[1]->scale; + + op->shader_function (stops[0]->color_char, + stops[1]->color_char, + factor, pixel); - /* multiply alpha */ - if (((unsigned char) (*pixel >> 24)) != 0xff) { - *pixel = (*pixel & 0xff000000) | - (MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) | - (MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) | - (MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0); - } - break; - } + /* multiply alpha */ + if (((unsigned char) (*pixel >> 24)) != 0xff) { + *pixel = (*pixel & 0xff000000) | + (MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) | + (MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) | + (MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0); } } -static void -_cairo_image_data_set_linear (cairo_pattern_t *pattern, - double offset_x, - double offset_y, - int *pixels, - int width, - int height) +static cairo_status_t +_cairo_image_data_set_linear (cairo_linear_pattern_t *pattern, + double offset_x, + double offset_y, + uint32_t *pixels, + int width, + int height) { int x, y; cairo_point_double_t point0, point1; - double px, py, ex, ey; double a, b, c, d, tx, ty; - double length, start, angle, fx, fy, factor; + double scale, start, dx, dy, factor; cairo_shader_op_t op; - - _cairo_pattern_shader_init (pattern, &op); - - point0.x = pattern->u.linear.point0.x; - point0.y = pattern->u.linear.point0.y; - point1.x = pattern->u.linear.point1.x; - point1.y = pattern->u.linear.point1.y; - - cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty); - - length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) + - (point1.y - point0.y) * (point1.y - point0.y)); - length = (length) ? 1.0 / length : CAIRO_MAXSHORT; - - angle = -atan2 (point1.y - point0.y, point1.x - point0.x); - fx = cos (angle); - fy = -sin (angle); - - start = fx * point0.x; - start += fy * point0.y; + cairo_status_t status; + + status = _cairo_pattern_shader_init (&pattern->base, &op); + if (status) + return status; + + /* We compute the position in the linear gradient for + * a point q as: + * + * [q . (p1 - p0) - p0 . (p1 - p0)] / (p1 - p0) ^ 2 + * + * The computation is done in pattern space. The + * calculation could be heavily optimized by using the + * fact that 'factor' increases linearly in both + * directions. + */ + point0.x = pattern->point0.x; + point0.y = pattern->point0.y; + point1.x = pattern->point1.x; + point1.y = pattern->point1.y; + + cairo_matrix_get_affine (&pattern->base.base.matrix, + &a, &b, &c, &d, &tx, &ty); + + dx = point1.x - point0.x; + dy = point1.y - point0.y; + scale = dx * dx + dy * dy; + scale = (scale) ? 1.0 / scale : 1.0; + + start = dx * point0.x + dy * point0.y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { - px = x + offset_x; - py = y + offset_y; + double qx_device = x + offset_x; + double qy_device = y + offset_y; - /* transform fragment */ - ex = a * px + c * py + tx; - ey = b * px + d * py + ty; + /* transform fragment into pattern space */ + double qx = a * qx_device + c * qy_device + tx; + double qy = b * qx_device + d * qy_device + ty; - factor = ((fx * ex + fy * ey) - start) * length; + factor = ((dx * qx + dy * qy) - start) * scale; _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++); } } + + _cairo_pattern_shader_fini (&op); + + return CAIRO_STATUS_SUCCESS; } static void -_cairo_image_data_set_radial (cairo_pattern_t *pattern, - double offset_x, - double offset_y, - int *pixels, - int width, - int height) +_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern, + double offset_x, + double offset_y, + int width, + int height, + cairo_bool_t *is_horizontal, + cairo_bool_t *is_vertical) +{ + cairo_point_double_t point0, point1; + double a, b, c, d, tx, ty; + double scale, start, dx, dy; + cairo_fixed_t factors[3]; + int i; + + /* To classidy a pattern as horizontal or vertical, we first + * compute the (fixed point) factors at the corners of the + * pattern. We actually only need 3/4 corners, so we skip the + * fourth. + */ + point0.x = pattern->point0.x; + point0.y = pattern->point0.y; + point1.x = pattern->point1.x; + point1.y = pattern->point1.y; + + cairo_matrix_get_affine (&pattern->base.base.matrix, + &a, &b, &c, &d, &tx, &ty); + + dx = point1.x - point0.x; + dy = point1.y - point0.y; + scale = dx * dx + dy * dy; + scale = (scale) ? 1.0 / scale : 1.0; + + start = dx * point0.x + dy * point0.y; + + for (i = 0; i < 3; i++) { + double qx_device = (i % 2) * (width - 1) + offset_x; + double qy_device = (i / 2) * (height - 1) + offset_y; + + /* transform fragment into pattern space */ + double qx = a * qx_device + c * qy_device + tx; + double qy = b * qx_device + d * qy_device + ty; + + factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale); + } + + /* We consider a pattern to be vertical if the fixed point factor + * at the two upper corners is the same. We could accept a small + * change, but determining what change is acceptable would require + * sorting the stops in the pattern and looking at the differences. + * + * Horizontal works the same way with the two left corners. + */ + + *is_vertical = factors[1] == factors[0]; + *is_horizontal = factors[2] == factors[0]; +} + +static cairo_status_t +_cairo_image_data_set_radial (cairo_radial_pattern_t *pattern, + double offset_x, + double offset_y, + uint32_t *pixels, + int width, + int height) { int x, y, aligned_circles; cairo_point_double_t c0, c1; @@ -584,15 +770,18 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern, c0_c1_x, c0_c1_y, c0_c1, angle_c0, c1_y, y_x, c0_y, c0_x, r1_2, denumerator, fraction, factor; cairo_shader_op_t op; + cairo_status_t status; - _cairo_pattern_shader_init (pattern, &op); + status = _cairo_pattern_shader_init (&pattern->base, &op); + if (status) + return status; - c0.x = pattern->u.radial.center0.x; - c0.y = pattern->u.radial.center0.y; - r0 = pattern->u.radial.radius0; - c1.x = pattern->u.radial.center1.x; - c1.y = pattern->u.radial.center1.y; - r1 = pattern->u.radial.radius1; + c0.x = pattern->center0.x; + c0.y = pattern->center0.y; + r0 = pattern->radius0; + c1.x = pattern->center1.x; + c1.y = pattern->center1.y; + r1 = pattern->radius1; if (c0.x != c1.x || c0.y != c1.y) { aligned_circles = 0; @@ -606,7 +795,8 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern, r1_2 = c0_c1 = 0.0; /* shut up compiler */ } - cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty); + cairo_matrix_get_affine (&pattern->base.base.matrix, + &a, &b, &c, &d, &tx, &ty); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { @@ -682,70 +872,454 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern, _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++); } } + + _cairo_pattern_shader_fini (&op); + + return CAIRO_STATUS_SUCCESS; } -cairo_image_surface_t * -_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box) +static cairo_int_status_t +_cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, + cairo_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_surface_t **out, + cairo_surface_attributes_t *attr) { - cairo_surface_t *surface; + cairo_image_surface_t *image; + cairo_status_t status; + uint32_t *data; + cairo_bool_t repeat = FALSE; + + if (pattern->base.type == CAIRO_PATTERN_LINEAR) { + cairo_bool_t is_horizontal; + cairo_bool_t is_vertical; + + _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern, + x, y, width, height, + &is_horizontal, &is_vertical); + if (is_horizontal) { + height = 1; + repeat = TRUE; + } + if (is_vertical) { + width = 1; + repeat = TRUE; + } + } + + data = malloc (width * height * 4); + if (!data) + return CAIRO_STATUS_NO_MEMORY; + + if (pattern->base.type == CAIRO_PATTERN_LINEAR) + { + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern; + + status = _cairo_image_data_set_linear (linear, x, y, data, + width, height); + } + else + { + cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern; + + status = _cairo_image_data_set_radial (radial, x, y, data, + width, height); + } - switch (pattern->type) { - case CAIRO_PATTERN_LINEAR: - case CAIRO_PATTERN_RADIAL: { - char *data; - double x = box->p1.x >> 16; - double y = box->p1.y >> 16; - int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16); - int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16); + if (status) { + free (data); + return status; + } + + image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data ((char *) data, + CAIRO_FORMAT_ARGB32, + width, height, + width * 4); + + if (image == NULL) { + free (data); + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_image_surface_assume_ownership_of_data (image); + + status = _cairo_surface_clone_similar (dst, &image->base, out); + + cairo_surface_destroy (&image->base); + + attr->x_offset = -x; + attr->y_offset = -y; + cairo_matrix_set_identity (&attr->matrix); + attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE; + attr->filter = CAIRO_FILTER_NEAREST; + attr->acquired = FALSE; + + return status; +} + +static cairo_int_status_t +_cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern, + cairo_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_surface_t **out, + cairo_surface_attributes_t *attribs) +{ + cairo_color_t color; + + _cairo_color_init (&color); + _cairo_color_set_rgb (&color, pattern->red, pattern->green, pattern->blue); + _cairo_color_set_alpha (&color, pattern->base.alpha); + + *out = _cairo_surface_create_similar_solid (dst, + CAIRO_FORMAT_ARGB32, + 1, 1, + &color); + + if (*out == NULL) + return CAIRO_STATUS_NO_MEMORY; + + attribs->x_offset = attribs->y_offset = 0; + cairo_matrix_set_identity (&attribs->matrix); + attribs->extend = CAIRO_EXTEND_REPEAT; + attribs->filter = CAIRO_FILTER_NEAREST; + attribs->acquired = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + + +/** + * _cairo_pattern_is_opaque + * + * Convenience function to determine whether a pattern has an opaque + * alpha value. This is done by testing whether the pattern's alpha + * value when converted to a byte is 255, so if a backend actually + * supported deep alpha channels this function might not do the right + * thing. + * + * Note that for a gradient or surface pattern, the overall resulting + * alpha for the pattern can be non-opaque even this function returns + * %TRUE, since the resulting alpha is the multiplication of the + * alpha of the gradient or surface with the pattern's alpha. In + * the future, alpha will be moved from the base pattern to the + * solid pattern subtype, at which point this function should + * probably be renamed to _cairo_pattern_is_opaque_solid() + * + * Return value: %TRUE if the pattern is opaque + **/ +cairo_bool_t +_cairo_pattern_is_opaque (cairo_pattern_t *pattern) +{ + return (pattern->alpha >= ((double)0xff00 / (double)0xffff)); +} + +static cairo_int_status_t +_cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, + cairo_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_surface_t **out, + cairo_surface_attributes_t *attr) +{ + cairo_int_status_t status; + + attr->acquired = FALSE; + + /* handle pattern opacity */ + if (!_cairo_pattern_is_opaque (&pattern->base)) + { + cairo_surface_pattern_t tmp; + cairo_color_t color; + + _cairo_color_init (&color); + _cairo_color_set_alpha (&color, pattern->base.alpha); + + *out = _cairo_surface_create_similar_solid (dst, + CAIRO_FORMAT_ARGB32, + width, height, + &color); + if (*out == NULL) + return CAIRO_STATUS_NO_MEMORY; + + status = _cairo_pattern_init_copy (&tmp.base, &pattern->base); + if (CAIRO_OK (status)) + { + tmp.base.alpha = 1.0; + status = _cairo_surface_composite (CAIRO_OPERATOR_IN, + &tmp.base, + NULL, + *out, + x, y, 0, 0, 0, 0, + width, height); + + _cairo_pattern_fini (&tmp.base); + } + + if (status) { + cairo_surface_destroy (*out); + return status; + } - data = malloc (width * height * 4); - if (!data) - return NULL; + attr->x_offset = -x; + attr->y_offset = -y; + attr->extend = CAIRO_EXTEND_NONE; + attr->filter = CAIRO_FILTER_NEAREST; + + cairo_matrix_set_identity (&attr->matrix); + } + else + { + int tx, ty; + + if (_cairo_surface_is_image (dst)) + { + cairo_image_surface_t *image; + + status = _cairo_surface_acquire_source_image (pattern->surface, + &image, + &attr->extra); + if (CAIRO_OK (status)) + *out = &image->base; + + attr->acquired = TRUE; + } + else + status = _cairo_surface_clone_similar (dst, pattern->surface, out); - if (pattern->type == CAIRO_PATTERN_RADIAL) - _cairo_image_data_set_radial (pattern, x, y, (int *) data, - width, height); + attr->extend = pattern->base.extend; + attr->filter = pattern->base.filter; + if (_cairo_matrix_is_integer_translation (&pattern->base.matrix, + &tx, &ty)) + { + cairo_matrix_set_identity (&attr->matrix); + attr->x_offset = tx; + attr->y_offset = ty; + } else - _cairo_image_data_set_linear (pattern, x, y, (int *) data, - width, height); + { + attr->matrix = pattern->base.matrix; + attr->x_offset = attr->y_offset = 0; + } + } + + return status; +} - _cairo_pattern_set_source_offset (pattern, x, y); +/** + * _cairo_pattern_acquire_surface: + * @pattern: a #cairo_pattern_t + * @dst: destination surface + * @x: X coordinate in source corresponding to left side of destination area + * @y: Y coordinate in source corresponding to top side of destination area + * @width: width of destination area + * @height: height of destination area + * @surface_out: location to store a pointer to a surface + * @attributes: surface attributes that destination backend should apply to + * the returned surface + * + * A convenience function to obtain a surface to use as the source for + * drawing on @dst. + * + * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out. + **/ +cairo_int_status_t +_cairo_pattern_acquire_surface (cairo_pattern_t *pattern, + cairo_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_surface_t **surface_out, + cairo_surface_attributes_t *attributes) +{ + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: { + cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern; + + return _cairo_pattern_acquire_surface_for_solid (src, dst, + x, y, width, height, + surface_out, + attributes); + } break; + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern; + + /* fast path for gradients with less than 2 color stops */ + if (src->n_stops < 2) + { + cairo_solid_pattern_t solid; + + if (src->n_stops) + { + _cairo_pattern_init_solid (&solid, + src->stops->color.red, + src->stops->color.green, + src->stops->color.blue); + _cairo_pattern_set_alpha (&solid.base, + src->stops->color.alpha); + } + else + { + _cairo_pattern_init_solid (&solid, 0.0, 0.0, 0.0); + _cairo_pattern_set_alpha (&solid.base, 0.0); + } - surface = cairo_image_surface_create_for_data (data, - CAIRO_FORMAT_ARGB32, - width, height, - width * 4); + return _cairo_pattern_acquire_surface_for_solid (&solid, dst, + x, y, + width, height, + surface_out, + attributes); + } + else + return _cairo_pattern_acquire_surface_for_gradient (src, dst, + x, y, + width, height, + surface_out, + attributes); + } break; + case CAIRO_PATTERN_SURFACE: { + cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern; - if (surface) - _cairo_image_surface_assume_ownership_of_data ( - (cairo_image_surface_t *) surface); + return _cairo_pattern_acquire_surface_for_surface (src, dst, + x, y, width, height, + surface_out, + attributes); + } break; } - break; - case CAIRO_PATTERN_SOLID: - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); - if (surface) { - _cairo_surface_fill_rectangle (surface, - CAIRO_OPERATOR_SRC, - &pattern->color, 0, 0, 1, 1); - cairo_surface_set_repeat (surface, 1); + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +/** + * _cairo_pattern_release_surface: + * @pattern: a #cairo_pattern_t + * @info: pointer to #cairo_surface_attributes_t filled in by + * _cairo_pattern_acquire_surface + * + * Releases resources obtained by _cairo_pattern_acquire_surface. + **/ +void +_cairo_pattern_release_surface (cairo_surface_t *dst, + cairo_surface_t *surface, + cairo_surface_attributes_t *attributes) +{ + if (attributes->acquired) + _cairo_surface_release_source_image (dst, + (cairo_image_surface_t *) surface, + attributes->extra); + else + cairo_surface_destroy (surface); +} + +cairo_int_status_t +_cairo_pattern_acquire_surfaces (cairo_pattern_t *src, + cairo_pattern_t *mask, + cairo_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + unsigned int width, + unsigned int height, + cairo_surface_t **src_out, + cairo_surface_t **mask_out, + cairo_surface_attributes_t *src_attributes, + cairo_surface_attributes_t *mask_attributes) +{ + cairo_int_status_t status; + + cairo_pattern_union_t tmp; + cairo_bool_t src_opaque, mask_opaque; + double src_alpha, mask_alpha; + + src_opaque = _cairo_pattern_is_opaque (src); + mask_opaque = !mask || _cairo_pattern_is_opaque (mask); + + /* For surface patterns, we move any translucency from src->alpha + * to mask->alpha so we can use the source unchanged. Otherwise we + * move the translucency from mask->alpha to src->alpha so that + * we can drop the mask if possible. + */ + if (src->type == CAIRO_PATTERN_SURFACE) + { + if (mask) { + mask_opaque = mask_opaque && src_opaque; + mask_alpha = mask->alpha * src->alpha; + } else { + mask_opaque = src_opaque; + mask_alpha = src->alpha; } - break; - case CAIRO_PATTERN_SURFACE: { - cairo_image_surface_t *image; + + src_alpha = 1.0; + src_opaque = TRUE; + } + else + { + if (mask) + { + src_opaque = mask_opaque && src_opaque; + src_alpha = mask->alpha * src->alpha; + /* FIXME: This needs changing when we support RENDER + * style 4-channel masks. + */ + if (mask->type == CAIRO_PATTERN_SOLID) + mask = NULL; + } else + src_alpha = src->alpha; + + mask_alpha = 1.0; + mask_opaque = TRUE; + } - image = _cairo_surface_get_image (pattern->u.surface.surface); - if (image) - surface = &image->base; + _cairo_pattern_init_copy (&tmp.base, src); + _cairo_pattern_set_alpha (&tmp.base, src_alpha); + + status = _cairo_pattern_acquire_surface (&tmp.base, dst, + src_x, src_y, + width, height, + src_out, src_attributes); + + _cairo_pattern_fini (&tmp.base); + + if (status) + return status; + + if (mask || !mask_opaque) + { + if (mask) + _cairo_pattern_init_copy (&tmp.base, mask); else - surface = NULL; + _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0); + + _cairo_pattern_set_alpha (&tmp.base, mask_alpha); + + status = _cairo_pattern_acquire_surface (&tmp.base, dst, + mask_x, mask_y, + width, height, + mask_out, mask_attributes); + _cairo_pattern_fini (&tmp.base); + + if (status) + { + _cairo_pattern_release_surface (dst, *src_out, src_attributes); + return status; + } } - break; - default: - surface = NULL; - break; + else + { + *mask_out = NULL; } - - return (cairo_image_surface_t *) surface; + + return CAIRO_STATUS_SUCCESS; } - diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 23230aa74..fee918355 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -36,9 +36,8 @@ #include "cairoint.h" #include "cairo-pdf.h" -/* XXX: This seems broken to me. What about users without freetype - * that want to use a cairo PDF surface? */ -#include "cairo-ft.h" +/* XXX: Eventually, we need to handle other font backends */ +#include "cairo-ft-private.h" #include <ft2build.h> #include FT_FREETYPE_H @@ -54,10 +53,6 @@ * - Why doesn't pages inherit /alpha%d GS dictionaries from the Pages * object? * - * - Why isn't the pattern passed to composite traps instead of - * pattern->source? If composite traps needs an image or a surface it - * can call create_pattern(). - * * - We embed an image in the stream each time it's composited. We * could add generation counters to surfaces and remember the stream * ID for a particular generation for a particular surface. @@ -183,9 +178,6 @@ struct cairo_pdf_surface { double width_inches; double height_inches; - /* HACK: Non-null if this surface was created for a pattern. */ - cairo_pattern_t *pattern; - cairo_pdf_document_t *document; cairo_pdf_stream_t *current_stream; @@ -240,8 +232,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend; #define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) ) #define SFNT_VERSION 0x00010000 -#define OFFSET_TABLE_SIZE 12 -#define TABLE_DIRECTORY_ENTRY_SIZE 16 #ifdef WORDS_BIGENDIAN @@ -300,19 +290,15 @@ cairo_pdf_font_destroy (cairo_pdf_font_t *font) } static cairo_pdf_font_t * -cairo_pdf_ft_font_create (cairo_pdf_document_t *document, - cairo_unscaled_font_t *unscaled_font, - cairo_font_scale_t *scale) +cairo_pdf_ft_font_create (cairo_pdf_document_t *document, + cairo_unscaled_font_t *unscaled_font) { - cairo_font_t scaled_font; FT_Face face; cairo_pdf_ft_font_t *font; unsigned long size; int i, j; - /* FIXME: Why do I have to pass a scaled font to get the FT_Face? */ - _cairo_font_init (&scaled_font, scale, unscaled_font); - face = cairo_ft_font_face (&scaled_font); + face = _cairo_ft_unscaled_font_lock_face (unscaled_font); /* We currently only support freetype truetype fonts. */ size = 0; @@ -333,7 +319,8 @@ cairo_pdf_ft_font_create (cairo_pdf_document_t *document, if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS) goto fail1; - font->face = face; + font->base.unscaled_font = unscaled_font; + _cairo_unscaled_font_reference (unscaled_font); font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t)); if (font->glyphs == NULL) goto fail2; @@ -364,6 +351,8 @@ cairo_pdf_ft_font_create (cairo_pdf_document_t *document, if (font->base.widths == NULL) goto fail5; + _cairo_ft_unscaled_font_unlock_face (unscaled_font); + font->status = CAIRO_STATUS_SUCCESS; return &font->base; @@ -447,7 +436,7 @@ cairo_pdf_ft_font_write_cmap_table (cairo_pdf_ft_font_t *font, unsigned long tag cairo_pdf_ft_font_write_be16 (font, 0); cairo_pdf_ft_font_write_be16 (font, 1); - cairo_pdf_ft_font_write_be16 (font, 0); + cairo_pdf_ft_font_write_be16 (font, 1); cairo_pdf_ft_font_write_be16 (font, 0); cairo_pdf_ft_font_write_be32 (font, 12); @@ -764,12 +753,15 @@ cairo_pdf_ft_font_generate (void *abstract_font, unsigned long start, end, next, checksum; int i; + font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font); + if (cairo_pdf_ft_font_write_offset_table (font)) - return font->status; + goto fail; start = cairo_pdf_ft_font_align_output (font); end = start; + end = 0; for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) { if (truetype_tables[i].write (font, truetype_tables[i].tag)) goto fail; @@ -789,6 +781,9 @@ cairo_pdf_ft_font_generate (void *abstract_font, *length = _cairo_array_num_elements (&font->output); fail: + _cairo_ft_unscaled_font_unlock_face (font->base.unscaled_font); + font->face = NULL; + return font->status; } @@ -947,14 +942,13 @@ _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document, surface->width_inches = width_inches; surface->height_inches = height_inches; - surface->pattern = NULL; _cairo_pdf_document_reference (document); surface->document = document; _cairo_array_init (&surface->streams, sizeof (cairo_pdf_stream_t *)); _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_resource_t)); _cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t)); _cairo_array_init (&surface->alphas, sizeof (double)); - _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t)); + _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_resource_t)); return &surface->base; } @@ -1102,38 +1096,46 @@ _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface) } } -static cairo_image_surface_t * -_cairo_pdf_surface_get_image (void *abstract_surface) +static cairo_status_t +_cairo_pdf_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { - return NULL; + return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_status_t -_cairo_pdf_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +static void +_cairo_pdf_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) { - return CAIRO_INT_STATUS_UNSUPPORTED; } static cairo_status_t -_cairo_pdf_surface_set_matrix (void *abstract_surface, - cairo_matrix_t *matrix) +_cairo_pdf_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra) { - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_status_t -_cairo_pdf_surface_set_filter (void *abstract_surface, - cairo_filter_t filter) +static void +_cairo_pdf_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) { - return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_pdf_surface_set_repeat (void *abstract_surface, - int repeat) +_cairo_pdf_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_UNSUPPORTED; } static void * @@ -1210,23 +1212,34 @@ emit_image_data (cairo_pdf_document_t *document, } static cairo_int_status_t -_cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, - cairo_image_surface_t *image) +_cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, + cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; FILE *file = document->file; unsigned id; cairo_matrix_t i2u; + cairo_status_t status; + cairo_image_surface_t *image; + cairo_surface_t *src; + void *image_extra; + + src = pattern->surface; + status = _cairo_surface_acquire_source_image (src, &image, &image_extra); + if (!CAIRO_OK (status)) + return status; id = emit_image_data (dst->document, image); - if (id == 0) - return CAIRO_STATUS_NO_MEMORY; + if (id == 0) { + status = CAIRO_STATUS_NO_MEMORY; + goto bail; + } _cairo_pdf_surface_add_xobject (dst, id); _cairo_pdf_surface_ensure_stream (dst); - cairo_matrix_copy (&i2u, &image->base.matrix); + cairo_matrix_copy (&i2u, &pattern->base.matrix); cairo_matrix_invert (&i2u); cairo_matrix_translate (&i2u, 0, image->height); cairo_matrix_scale (&i2u, image->width, -image->height); @@ -1238,7 +1251,10 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, i2u.m[2][0], i2u.m[2][1], id); - return CAIRO_STATUS_SUCCESS; + bail: + _cairo_surface_release_source_image (src, image, image_extra); + + return status; } /* The contents of the surface is already transformed into PDF units, @@ -1253,20 +1269,19 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, static cairo_int_status_t _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst, - cairo_pdf_surface_t *src, - int width, int height) + cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; FILE *file = document->file; cairo_matrix_t i2u; cairo_pdf_stream_t *stream; int num_streams, i; - - if (src->pattern != NULL) - return CAIRO_STATUS_SUCCESS; + cairo_pdf_surface_t *src; _cairo_pdf_surface_ensure_stream (dst); + src = (cairo_pdf_surface_t *) pattern->surface; + cairo_matrix_copy (&i2u, &src->base.matrix); cairo_matrix_invert (&i2u); cairo_matrix_scale (&i2u, @@ -1297,8 +1312,8 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst, static cairo_int_status_t _cairo_pdf_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, void *abstract_dst, int src_x, int src_y, @@ -1310,17 +1325,18 @@ _cairo_pdf_surface_composite (cairo_operator_t operator, unsigned int height) { cairo_pdf_surface_t *dst = abstract_dst; - cairo_pdf_surface_t *src; - cairo_image_surface_t *image; + cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) src_pattern; - if (generic_src->backend == &cairo_pdf_surface_backend) { - src = (cairo_pdf_surface_t *) generic_src; - return _cairo_pdf_surface_composite_pdf (dst, src, width, height); - } - else { - image = _cairo_surface_get_image (generic_src); - return _cairo_pdf_surface_composite_image (dst, image); - } + if (mask_pattern) + return CAIRO_STATUS_SUCCESS; + + if (src_pattern->type != CAIRO_PATTERN_SURFACE) + return CAIRO_STATUS_SUCCESS; + + if (src->surface->backend == &cairo_pdf_surface_backend) + return _cairo_pdf_surface_composite_pdf (dst, src); + else + return _cairo_pdf_surface_composite_image (dst, src); } static cairo_int_status_t @@ -1335,9 +1351,6 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface, FILE *file = document->file; int i; - if (surface->pattern != NULL) - return CAIRO_STATUS_SUCCESS; - _cairo_pdf_surface_ensure_stream (surface); fprintf (file, @@ -1355,23 +1368,44 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface, } static void -emit_tiling_pattern (cairo_operator_t operator, - cairo_pdf_surface_t *dst, - cairo_pattern_t *pattern) +emit_solid_pattern (cairo_pdf_surface_t *surface, + cairo_solid_pattern_t *pattern) +{ + cairo_pdf_document_t *document = surface->document; + FILE *file = document->file; + unsigned int alpha; + + alpha = _cairo_pdf_surface_add_alpha (surface, pattern->base.alpha); + _cairo_pdf_surface_ensure_stream (surface); + fprintf (file, + "%f %f %f rg /a%d gs\r\n", + pattern->red, + pattern->green, + pattern->blue, + alpha); +} + +static void +emit_surface_pattern (cairo_pdf_surface_t *dst, + cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; FILE *file = document->file; cairo_pdf_stream_t *stream; cairo_image_surface_t *image; + void *image_extra; + cairo_status_t status; char entries[250]; unsigned int id, alpha; cairo_matrix_t pm; - if (pattern->u.surface.surface->backend == &cairo_pdf_surface_backend) { + if (pattern->surface->backend == &cairo_pdf_surface_backend) { return; } - - image = _cairo_surface_get_image (pattern->u.surface.surface); + + status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra); + if (!CAIRO_OK (status)) + return; _cairo_pdf_document_close_stream (document); @@ -1382,7 +1416,7 @@ emit_tiling_pattern (cairo_operator_t operator, cairo_matrix_set_identity (&pm); cairo_matrix_scale (&pm, image->width, image->height); - cairo_matrix_copy (&pm, &pattern->matrix); + cairo_matrix_copy (&pm, &pattern->base.matrix); cairo_matrix_invert (&pm); snprintf (entries, sizeof entries, @@ -1401,6 +1435,8 @@ emit_tiling_pattern (cairo_operator_t operator, stream = _cairo_pdf_document_open_stream (document, entries); + /* FIXME: emit code to show surface here. */ + _cairo_pdf_surface_add_pattern (dst, stream->id); _cairo_pdf_surface_ensure_stream (dst); @@ -1408,10 +1444,12 @@ emit_tiling_pattern (cairo_operator_t operator, fprintf (file, "/Pattern cs /res%d scn /a%d gs\r\n", stream->id, alpha); + + _cairo_surface_release_source_image (pattern->surface, image, image_extra); } static unsigned int -emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) +emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; FILE *file = document->file; @@ -1430,12 +1468,12 @@ emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) "stream\r\n", function_id); - fputc (pattern->stops[0].color_char[0], file); - fputc (pattern->stops[0].color_char[1], file); - fputc (pattern->stops[0].color_char[2], file); - fputc (pattern->stops[1].color_char[0], file); - fputc (pattern->stops[1].color_char[1], file); - fputc (pattern->stops[1].color_char[2], file); + fputc (pattern->stops[0].color.red * 0xff, file); + fputc (pattern->stops[0].color.green * 0xff, file); + fputc (pattern->stops[0].color.blue * 0xff, file); + fputc (pattern->stops[1].color.red * 0xff, file); + fputc (pattern->stops[1].color.green * 0xff, file); + fputc (pattern->stops[1].color.blue * 0xff, file); fprintf (file, "\r\n" @@ -1446,7 +1484,7 @@ emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) } static void -emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) +emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; FILE *file = document->file; @@ -1456,16 +1494,16 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) _cairo_pdf_document_close_stream (document); - function_id = emit_pattern_stops (surface, pattern); + function_id = emit_pattern_stops (surface, &pattern->base); - cairo_matrix_copy (&p2u, &pattern->matrix); + cairo_matrix_copy (&p2u, &pattern->base.base.matrix); cairo_matrix_invert (&p2u); - x0 = pattern->u.linear.point0.x; - y0 = pattern->u.linear.point0.y; + x0 = pattern->point0.x; + y0 = pattern->point0.y; cairo_matrix_transform_point (&p2u, &x0, &y0); - x1 = pattern->u.linear.point1.x; - y1 = pattern->u.linear.point1.y; + x1 = pattern->point1.x; + y1 = pattern->point1.y; cairo_matrix_transform_point (&p2u, &x1, &y1); pattern_id = _cairo_pdf_document_new_object (document); @@ -1479,16 +1517,14 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) " /ColorSpace /DeviceRGB\r\n" " /Coords [ %f %f %f %f ]\r\n" " /Function %d 0 R\r\n" - " /Extend [ %s %s ]\r\n" + " /Extend [ true true ]\r\n" " >>\r\n" ">>\r\n" "endobj\r\n", pattern_id, document->height_inches * document->y_ppi, x0, y0, x1, y1, - function_id, - (1 || pattern->extend) ? "true" : "false", - (1 || pattern->extend) ? "true" : "false"); + function_id); _cairo_pdf_surface_add_pattern (surface, pattern_id); @@ -1502,7 +1538,7 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) } static void -emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) +emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; FILE *file = document->file; @@ -1512,24 +1548,31 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) _cairo_pdf_document_close_stream (document); - function_id = emit_pattern_stops (surface, pattern); + function_id = emit_pattern_stops (surface, &pattern->base); - cairo_matrix_copy (&p2u, &pattern->matrix); + cairo_matrix_copy (&p2u, &pattern->base.base.matrix); cairo_matrix_invert (&p2u); - x0 = pattern->u.radial.center0.x; - y0 = pattern->u.radial.center0.y; - r0 = pattern->u.radial.radius0; + x0 = pattern->center0.x; + y0 = pattern->center0.y; + r0 = pattern->radius0; cairo_matrix_transform_point (&p2u, &x0, &y0); - x1 = pattern->u.radial.center1.x; - y1 = pattern->u.radial.center1.y; - r1 = pattern->u.radial.radius1; + x1 = pattern->center1.x; + y1 = pattern->center1.y; + r1 = pattern->radius1; cairo_matrix_transform_point (&p2u, &x1, &y1); /* FIXME: This is surely crack, but how should you scale a radius * in a non-orthogonal coordinate system? */ cairo_matrix_transform_distance (&p2u, &r0, &r1); + /* FIXME: There is a difference between the cairo gradient extend + * semantics and PDF extend semantics. PDFs extend=false means + * that nothing is painted outside the gradient boundaries, + * whereas cairo takes this to mean that the end color is padded + * to infinity. Setting extend=true in PDF gives the cairo default + * behavoir, not yet sure how to implement the cairo mirror and + * repeat behaviour. */ pattern_id = _cairo_pdf_document_new_object (document); fprintf (file, "%d 0 obj\r\n" @@ -1541,16 +1584,14 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) " /ColorSpace /DeviceRGB\r\n" " /Coords [ %f %f %f %f %f %f ]\r\n" " /Function %d 0 R\r\n" - " /Extend [ %s %s ]\r\n" + " /Extend [ true true ]\r\n" " >>\r\n" ">>\r\n" "endobj\r\n", pattern_id, document->height_inches * document->y_ppi, x0, y0, r0, x1, y1, r1, - function_id, - (1 || pattern->extend) ? "true" : "false", - (1 || pattern->extend) ? "true" : "false"); + function_id); _cairo_pdf_surface_add_pattern (surface, pattern_id); @@ -1563,6 +1604,28 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) pattern_id, alpha); } +static void +emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) +{ + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: + emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern); + break; + + case CAIRO_PATTERN_SURFACE: + emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern); + break; + + case CAIRO_PATTERN_LINEAR: + emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern); + break; + + case CAIRO_PATTERN_RADIAL: + emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern); + break; + } +} + static double intersect (cairo_line_t *line, cairo_fixed_t y) { @@ -1574,60 +1637,23 @@ intersect (cairo_line_t *line, cairo_fixed_t y) static cairo_int_status_t _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, + cairo_pattern_t *pattern, void *abstract_dst, int x_src, int y_src, + int x_dst, + int y_dst, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps) { cairo_pdf_surface_t *surface = abstract_dst; - cairo_pdf_surface_t *source = (cairo_pdf_surface_t *) generic_src; cairo_pdf_document_t *document = surface->document; - cairo_pattern_t *pattern; FILE *file = document->file; int i; - unsigned int alpha; - /* FIXME: we really just want the original pattern here, not a - * source surface. */ - pattern = source->pattern; - - if (source->base.backend != &cairo_pdf_surface_backend) { - printf ("_cairo_pdf_surface_composite_trapezoids: not a pdf source\r"); - return CAIRO_STATUS_SUCCESS; - } - - if (pattern == NULL) { - printf ("_cairo_pdf_surface_composite_trapezoids: " - "non-pattern pdf source\r"); - return CAIRO_STATUS_SUCCESS; - } - - switch (pattern->type) { - case CAIRO_PATTERN_SOLID: - alpha = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha); - _cairo_pdf_surface_ensure_stream (surface); - fprintf (file, - "%f %f %f rg /a%d gs\r\n", - pattern->color.red, - pattern->color.green, - pattern->color.blue, - alpha); - break; - - case CAIRO_PATTERN_SURFACE: - emit_tiling_pattern (operator, surface, pattern); - break; - - case CAIRO_PATTERN_LINEAR: - emit_linear_pattern (surface, pattern); - break; - - case CAIRO_PATTERN_RADIAL: - emit_radial_pattern (surface, pattern ); - break; - } + emit_pattern (surface, pattern); /* After the above switch the current stream should belong to this * surface, so no need to _cairo_pdf_surface_ensure_stream() */ @@ -1686,59 +1712,48 @@ _cairo_pdf_surface_set_clip_region (void *abstract_surface, return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_int_status_t -_cairo_pdf_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *extents) -{ - cairo_pdf_surface_t *surface = abstract_surface; - cairo_pdf_surface_t *source; - - source = (cairo_pdf_surface_t *) - _cairo_pdf_surface_create_for_document (surface->document, 0, 0); - source->pattern = pattern; - pattern->source = &source->base; - - return CAIRO_STATUS_SUCCESS; -} - static cairo_pdf_font_t * _cairo_pdf_document_get_font (cairo_pdf_document_t *document, - cairo_unscaled_font_t *unscaled_font, - cairo_font_scale_t *scale) + cairo_font_t *font) { - cairo_pdf_font_t *font; + cairo_unscaled_font_t *unscaled_font; + cairo_pdf_font_t *pdf_font; unsigned int num_fonts, i; + unscaled_font = _cairo_ft_font_get_unscaled_font (font); + num_fonts = _cairo_array_num_elements (&document->fonts); for (i = 0; i < num_fonts; i++) { - _cairo_array_copy_element (&document->fonts, i, &font); - if (font->unscaled_font == unscaled_font) - return font; + _cairo_array_copy_element (&document->fonts, i, &pdf_font); + if (pdf_font->unscaled_font == unscaled_font) + return pdf_font; } /* FIXME: Figure out here which font backend is in use and call * the appropriate constructor. */ - font = cairo_pdf_ft_font_create (document, unscaled_font, scale); - if (font == NULL) + pdf_font = cairo_pdf_ft_font_create (document, unscaled_font); + if (pdf_font == NULL) return NULL; - if (_cairo_array_append (&document->fonts, &font, 1) == NULL) { - cairo_pdf_font_destroy (font); + if (_cairo_array_append (&document->fonts, &pdf_font, 1) == NULL) { + cairo_pdf_font_destroy (pdf_font); return NULL; } - return font; + return pdf_font; } static cairo_status_t -_cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_pdf_surface_show_glyphs (cairo_font_t *font, cairo_operator_t operator, - cairo_surface_t *source, + cairo_pattern_t *pattern, void *abstract_surface, int source_x, int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs) { @@ -1748,23 +1763,23 @@ _cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font, cairo_pdf_font_t *pdf_font; int i, index; - pdf_font = _cairo_pdf_document_get_font (document, font, scale); + pdf_font = _cairo_pdf_document_get_font (document, font); if (pdf_font == NULL) return CAIRO_STATUS_NO_MEMORY; - _cairo_pdf_surface_ensure_stream (surface); + emit_pattern (surface, pattern); - fprintf (file, "0 0 0 rg BT /res%u 1 Tf", pdf_font->font_id); + fprintf (file, "BT /res%u 1 Tf", pdf_font->font_id); for (i = 0; i < num_glyphs; i++) { index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index); fprintf (file, - " %f %f %f %f %f %f Tm (%c) Tj", - scale->matrix[0][0], - scale->matrix[0][1], - scale->matrix[1][0], - -scale->matrix[1][1], + " %f %f %f %f %f %f Tm (\\%o) Tj", + font->scale.matrix[0][0], + font->scale.matrix[0][1], + font->scale.matrix[1][0], + -font->scale.matrix[1][1], glyphs[i].x, glyphs[i].y, index); @@ -1780,18 +1795,17 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = { _cairo_pdf_surface_create_similar, _cairo_pdf_surface_destroy, _cairo_pdf_surface_pixels_per_inch, - _cairo_pdf_surface_get_image, - _cairo_pdf_surface_set_image, - _cairo_pdf_surface_set_matrix, - _cairo_pdf_surface_set_filter, - _cairo_pdf_surface_set_repeat, + _cairo_pdf_surface_acquire_source_image, + _cairo_pdf_surface_release_source_image, + _cairo_pdf_surface_acquire_dest_image, + _cairo_pdf_surface_release_dest_image, + _cairo_pdf_surface_clone_similar, _cairo_pdf_surface_composite, _cairo_pdf_surface_fill_rectangles, _cairo_pdf_surface_composite_trapezoids, _cairo_pdf_surface_copy_page, _cairo_pdf_surface_show_page, _cairo_pdf_surface_set_clip_region, - _cairo_pdf_surface_create_pattern, _cairo_pdf_surface_show_glyphs }; @@ -1930,8 +1944,8 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document) fprintf (file, "%d 0 obj\r\n" "<< /Type /FontDescriptor\r\n" - " /FontName /%s\r\n" - " /Flags 32\r\n" + " /FontName /7%s\r\n" + " /Flags 4\r\n" " /FontBBox [ %ld %ld %ld %ld ]\r\n" " /ItalicAngle 0\r\n" " /Ascent %ld\r\n" diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h index 0f624af31..701a7b4a7 100644 --- a/src/cairo-pdf.h +++ b/src/cairo-pdf.h @@ -31,17 +31,20 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ -#include <cairo.h> - #ifndef CAIRO_PDF_H #define CAIRO_PDF_H + +#include <cairo.h> + #ifdef CAIRO_HAS_PDF_SURFACE #include <stdio.h> +CAIRO_BEGIN_DECLS + void cairo_set_target_pdf (cairo_t *cr, FILE *file, @@ -58,5 +61,7 @@ cairo_pdf_surface_create (FILE *file, double x_pixels_per_inch, double y_pixels_per_inch); +CAIRO_END_DECLS + #endif /* CAIRO_HAS_PDF_SURFACE */ #endif /* CAIRO_PDF_H */ diff --git a/src/cairo-pen.c b/src/cairo-pen.c index f365091dc..6ecaa00b3 100644 --- a/src/cairo-pen.c +++ b/src/cairo-pen.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo-png.h b/src/cairo-png.h index 766d6f91f..3e86210b0 100644 --- a/src/cairo-png.h +++ b/src/cairo-png.h @@ -31,17 +31,20 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ -#include <cairo.h> - #ifndef CAIRO_PNG_H #define CAIRO_PNG_H -#ifdef CAIRO_HAS_PNG_SURFACE + +#include <cairo.h> + +#ifdef CAIRO_HAS_PNG_SURFACE #include <stdio.h> +CAIRO_BEGIN_DECLS + void cairo_set_target_png (cairo_t *cr, FILE *file, @@ -55,5 +58,7 @@ cairo_png_surface_create (FILE *file, int width, int height); +CAIRO_END_DECLS + #endif /* CAIRO_HAS_PNG_SURFACE */ #endif /* CAIRO_PNG_H */ diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c index e85858033..59c615da2 100644 --- a/src/cairo-polygon.c +++ b/src/cairo-polygon.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include <stdlib.h> diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 4da8162c7..4a45fc679 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" @@ -42,6 +42,22 @@ static const cairo_surface_backend_t cairo_ps_surface_backend; +/** + * cairo_set_target_ps: + * @cr: a #cairo_t + * @file: an open, writeable file + * @width_inches: width of the output page, in inches + * @height_inches: height of the output page, in inches + * @x_pixels_per_inch: X resolution to use for image fallbacks; + * not all Cairo drawing can be represented in a postscript + * file, so Cairo will write out images for some portions + * of the output. + * @y_pixels_per_inch: Y resolution to use for image fallbacks. + * + * Directs output for a #cairo_t to a postscript file. The file must + * be kept open until the #cairo_t is destroyed or set to have a + * different target, and then must be closed by the application. + **/ void cairo_set_target_ps (cairo_t *cr, FILE *file, @@ -192,62 +208,65 @@ _cairo_ps_surface_pixels_per_inch (void *abstract_surface) return surface->y_ppi; } -static cairo_image_surface_t * -_cairo_ps_surface_get_image (void *abstract_surface) +static cairo_status_t +_cairo_ps_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { cairo_ps_surface_t *surface = abstract_surface; + + *image_out = surface->image; - cairo_surface_reference (&surface->image->base); - - return surface->image; + return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_ps_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +static void +_cairo_ps_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) { - cairo_ps_surface_t *surface = abstract_surface; - - if (image == surface->image) - return CAIRO_STATUS_SUCCESS; - - /* XXX: Need to call _cairo_image_surface_set_image here, but it's - not implemented yet. */ - - return CAIRO_INT_STATUS_UNSUPPORTED; } static cairo_status_t -_cairo_ps_surface_set_matrix (void *abstract_surface, - cairo_matrix_t *matrix) +_cairo_ps_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra) { cairo_ps_surface_t *surface = abstract_surface; + + image_rect->x = 0; + image_rect->y = 0; + image_rect->width = surface->image->width; + image_rect->height = surface->image->height; + + *image_out = surface->image; - return _cairo_image_surface_set_matrix (surface->image, matrix); + return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_ps_surface_set_filter (void *abstract_surface, - cairo_filter_t filter) +static void +_cairo_ps_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) { - cairo_ps_surface_t *surface = abstract_surface; - - return _cairo_image_surface_set_filter (surface->image, filter); } static cairo_status_t -_cairo_ps_surface_set_repeat (void *abstract_surface, - int repeat) +_cairo_ps_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { - cairo_ps_surface_t *surface = abstract_surface; - - return _cairo_image_surface_set_repeat (surface->image, repeat); + return CAIRO_INT_STATUS_UNSUPPORTED; } static cairo_int_status_t _cairo_ps_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, + cairo_pattern_t *src, + cairo_pattern_t *mask, void *abstract_dst, int src_x, int src_y, @@ -273,10 +292,14 @@ _cairo_ps_surface_fill_rectangles (void *abstract_surface, static cairo_int_status_t _cairo_ps_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, + cairo_pattern_t *generic_src, void *abstract_dst, int x_src, int y_src, + int x_dst, + int y_dst, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps) { @@ -294,12 +317,10 @@ _cairo_ps_surface_copy_page (void *abstract_surface) int i, x, y; - cairo_surface_t *white_surface; + cairo_solid_pattern_t white_pattern; char *rgb, *compressed; long rgb_size, compressed_size; - cairo_color_t white; - rgb_size = 3 * width * height; rgb = malloc (rgb_size); if (rgb == NULL) { @@ -316,26 +337,19 @@ _cairo_ps_surface_copy_page (void *abstract_surface) /* PostScript can not represent the alpha channel, so we blend the current image over a white RGB surface to eliminate it. */ - white_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1); - if (white_surface == NULL) { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL2; - } - _cairo_color_init (&white); - _cairo_surface_fill_rectangle (white_surface, - CAIRO_OPERATOR_SRC, - &white, - 0, 0, 1, 1); - cairo_surface_set_repeat (white_surface, 1); + _cairo_pattern_init_solid (&white_pattern, 1.0, 1.0, 1.0); + _cairo_surface_composite (CAIRO_OPERATOR_OVER_REVERSE, - white_surface, + &white_pattern.base, NULL, &surface->image->base, 0, 0, 0, 0, 0, 0, width, height); + + _cairo_pattern_fini (&white_pattern.base); i = 0; for (y = 0; y < height; y++) { @@ -379,8 +393,6 @@ _cairo_ps_surface_copy_page (void *abstract_surface) /* Page footer */ fprintf (file, "%%%%EndPage\n"); - cairo_surface_destroy (white_surface); - BAIL2: free (compressed); BAIL1: free (rgb); @@ -412,29 +424,20 @@ _cairo_ps_surface_set_clip_region (void *abstract_surface, return _cairo_image_surface_set_clip_region (surface->image, region); } -static cairo_int_status_t -_cairo_ps_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *extents) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_create_similar, _cairo_ps_surface_destroy, _cairo_ps_surface_pixels_per_inch, - _cairo_ps_surface_get_image, - _cairo_ps_surface_set_image, - _cairo_ps_surface_set_matrix, - _cairo_ps_surface_set_filter, - _cairo_ps_surface_set_repeat, + _cairo_ps_surface_acquire_source_image, + _cairo_ps_surface_release_source_image, + _cairo_ps_surface_acquire_dest_image, + _cairo_ps_surface_release_dest_image, + _cairo_ps_surface_clone_similar, _cairo_ps_surface_composite, _cairo_ps_surface_fill_rectangles, _cairo_ps_surface_composite_trapezoids, _cairo_ps_surface_copy_page, _cairo_ps_surface_show_page, _cairo_ps_surface_set_clip_region, - _cairo_ps_surface_create_pattern, NULL /* show_glyphs */ }; diff --git a/src/cairo-ps.h b/src/cairo-ps.h index ae8e72192..88382920e 100644 --- a/src/cairo-ps.h +++ b/src/cairo-ps.h @@ -31,17 +31,20 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ -#include <cairo.h> - #ifndef CAIRO_PS_H #define CAIRO_PS_H + +#include <cairo.h> + #ifdef CAIRO_HAS_PS_SURFACE #include <stdio.h> +CAIRO_BEGIN_DECLS + void cairo_set_target_ps (cairo_t *cr, FILE *file, @@ -59,5 +62,7 @@ cairo_ps_surface_create (FILE *file, double x_pixels_per_inch, double y_pixels_per_inch); +CAIRO_END_DECLS + #endif /* CAIRO_HAS_PS_SURFACE */ #endif /* CAIRO_PS_H */ diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index b7103b051..01b345cdc 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -1,6 +1,6 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2004 Calum Robinson + * Copyright © 2004 Calum Robinson * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public diff --git a/src/cairo-quartz.h b/src/cairo-quartz.h index 918bc18d7..5afd46426 100644 --- a/src/cairo-quartz.h +++ b/src/cairo-quartz.h @@ -31,17 +31,20 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ -#include <cairo.h> - #ifndef CAIRO_QUARTZ_H #define CAIRO_QUARTZ_H + +#include <cairo.h> + #ifdef CAIRO_HAS_QUARTZ_SURFACE #include <Carbon/Carbon.h> +CAIRO_BEGIN_DECLS + void cairo_set_target_quartz_context( cairo_t *cr, CGContextRef context, @@ -53,6 +56,8 @@ cairo_quartz_surface_create ( CGContextRef context, int width, int height); +CAIRO_END_DECLS + #endif /* CAIRO_HAS_QUARTZ_SURFACE */ #endif /* CAIRO_QUARTZ_H */ diff --git a/src/cairo-slope.c b/src/cairo-slope.c index 1a1497988..a2edec038 100644 --- a/src/cairo-slope.c +++ b/src/cairo-slope.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo-spline.c b/src/cairo-spline.c index ff290d9dd..5119a8e2b 100644 --- a/src/cairo-spline.c +++ b/src/cairo-spline.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo-surface.c b/src/cairo-surface.c index a457d2062..330d58b1e 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include <stdlib.h> @@ -151,16 +151,151 @@ _cairo_surface_pixels_per_inch (cairo_surface_t *surface) return surface->backend->pixels_per_inch (surface); } -cairo_image_surface_t * -_cairo_surface_get_image (cairo_surface_t *surface) +/** + * _cairo_surface_acquire_source_image: + * @surface: a #cairo_surface_t + * @image_out: location to store a pointer to an image surface that includes at least + * the intersection of @interest_rect with the visible area of @surface. + * This surface could be @surface itself, a surface held internal to @surface, + * or it could be a new surface with a copy of the relevant portion of @surface. + * @image_extra: location to store image specific backend data + * + * Gets an image surface to use when drawing as a fallback when drawing with + * @surface as a source. _cairo_surface_release_source_image() must be called + * when finished. + * + * Return value: %CAIRO_STATUS_SUCCESS if a an image was stored in @image_out. + * %CAIRO_INT_STATUS_UNSUPPORTED if an image cannot be retrieved for the specified + * surface. Or %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_surface_acquire_source_image (cairo_surface_t *surface, + cairo_image_surface_t **image_out, + void **image_extra) { - return surface->backend->get_image (surface); + return surface->backend->acquire_source_image (surface, image_out, image_extra); } +/** + * _cairo_surface_release_source_image: + * @surface: a #cairo_surface_t + * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image() + * + * Releases any resources obtained with _cairo_surface_acquire_source_image() + **/ +cairo_private void +_cairo_surface_release_source_image (cairo_surface_t *surface, + cairo_image_surface_t *image, + void *image_extra) +{ + surface->backend->release_source_image (surface, image, image_extra); +} + +/** + * _cairo_surface_acquire_dest_image: + * @surface: a #cairo_surface_t + * @interest_rect: area of @surface for which fallback drawing is being done. + * A value of %NULL indicates that the entire surface is desired. + * @image_out: location to store a pointer to an image surface that includes at least + * the intersection of @interest_rect with the visible area of @surface. + * This surface could be @surface itself, a surface held internal to @surface, + * or it could be a new surface with a copy of the relevant portion of @surface. + * @image_rect: location to store area of the original surface occupied + * by the surface stored in @image. + * @image_extra: location to store image specific backend data + * + * Retrieves a local image for a surface for implementing a fallback drawing + * operation. After calling this function, the implementation of the fallback + * drawing operation draws the primitive to the surface stored in @image_out + * then calls _cairo_surface_release_dest_fallback(), + * which, if a temporary surface was created, copies the bits back to the + * main surface and frees the temporary surface. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY. + * %CAIRO_INT_STATUS_UNSUPPORTED can be returned but this will mean that + * the backend can't draw with fallbacks. It's possible for the routine + * to store NULL in @local_out and return %CAIRO_STATUS_SUCCESS; + * that indicates that no part of @interest_rect is visible, so no drawing + * is necessary. _cairo_surface_release_dest_fallback() should not be called in that + * case. + **/ +cairo_status_t +_cairo_surface_acquire_dest_image (cairo_surface_t *surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra) +{ + return surface->backend->acquire_dest_image (surface, interest_rect, + image_out, image_rect, image_extra); +} + +/** + * _cairo_surface_end_fallback: + * @surface: a #cairo_surface_t + * @interest_rect: same as passed to the matching _cairo_surface_acquire_dest_image() + * @image: same as returned from the matching _cairo_surface_acquire_dest_image() + * @image_rect: same as returned from the matching _cairo_surface_acquire_dest_image() + * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image() + * + * Finishes the operation started with _cairo_surface_acquire_dest_image(), by, if + * necessary, copying the image from @image back to @surface and freeing any + * resources that were allocated. + **/ +void +_cairo_surface_release_dest_image (cairo_surface_t *surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + surface->backend->release_dest_image (surface, interest_rect, + image, image_rect, image_extra); +} + +/** + * _cairo_surface_clone_similar: + * @surface: a #cairo_surface_t + * @src: the source image + * @clone_out: location to store a surface compatible with @surface + * and with contents identical to @src. The caller must call + * cairo_surface_destroy() on the result. + * + * Creates a surface with contents identical to @src but that + * can be used efficiently with @surface. If @surface and @src are + * already compatible then it may return a new reference to @src. + * + * Return value: %CAIRO_STATUS_SUCCESS if a surface was created and stored + * in @clone_out. Otherwise %CAIRO_INT_STATUS_UNSUPPORTED or another + * error like %CAIRO_STATUS_NO_MEMORY. + **/ cairo_status_t -_cairo_surface_set_image (cairo_surface_t *surface, cairo_image_surface_t *image) +_cairo_surface_clone_similar (cairo_surface_t *surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { - return surface->backend->set_image (surface, image); + cairo_status_t status; + cairo_image_surface_t *image; + void *image_extra; + + status = surface->backend->clone_similar (surface, src, clone_out); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_surface_acquire_source_image (src, &image, &image_extra); + if (status != CAIRO_STATUS_SUCCESS) + return status; + + status = surface->backend->clone_similar (surface, &image->base, clone_out); + + /* If the above failed point, we could implement a full fallback + * using acquire_dest_image, but that's going to be very + * inefficient compared to a backend-specific implementation of + * clone_similar() with an image source. So we don't bother + */ + + _cairo_surface_release_source_image (src, image, image_extra); + return status; } cairo_status_t @@ -169,9 +304,7 @@ cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix) if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; - cairo_matrix_copy (&surface->matrix, matrix); - - return surface->backend->set_matrix (surface, matrix); + return cairo_matrix_copy (&surface->matrix, matrix); } slim_hidden_def(cairo_surface_set_matrix); @@ -192,7 +325,7 @@ cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter) return CAIRO_STATUS_NULL_POINTER; surface->filter = filter; - return surface->backend->set_filter (surface, filter); + return CAIRO_STATUS_SUCCESS; } cairo_filter_t @@ -224,14 +357,81 @@ cairo_surface_set_repeat (cairo_surface_t *surface, int repeat) surface->repeat = repeat; - return surface->backend->set_repeat (surface, repeat); + return CAIRO_STATUS_SUCCESS; } slim_hidden_def(cairo_surface_set_repeat); +typedef struct { + cairo_surface_t *dst; + cairo_rectangle_t extents; + cairo_image_surface_t *image; + cairo_rectangle_t image_rect; + void *image_extra; +} fallback_state_t; + +static cairo_status_t +_fallback_init (fallback_state_t *state, + cairo_surface_t *dst, + int x, + int y, + int width, + int height) +{ + state->extents.x = x; + state->extents.y = y; + state->extents.width = width; + state->extents.height = height; + + state->dst = dst; + + return _cairo_surface_acquire_dest_image (dst, &state->extents, + &state->image, &state->image_rect, &state->image_extra); +} + +static void +_fallback_cleanup (fallback_state_t *state) +{ + _cairo_surface_release_dest_image (state->dst, &state->extents, + state->image, &state->image_rect, state->image_extra); +} + +static cairo_status_t +_fallback_composite (cairo_operator_t operator, + cairo_pattern_t *src, + cairo_pattern_t *mask, + cairo_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + fallback_state_t state; + cairo_status_t status; + + status = _fallback_init (&state, dst, dst_x, dst_y, width, height); + if (!CAIRO_OK (status) || !state.image) + return status; + + state.image->base.backend->composite (operator, src, mask, + &state.image->base, + src_x, src_y, mask_x, mask_y, + dst_x - state.image_rect.x, + dst_y - state.image_rect.y, + width, height); + + _fallback_cleanup (&state); + + return status; +} + cairo_status_t _cairo_surface_composite (cairo_operator_t operator, - cairo_surface_t *src, - cairo_surface_t *mask, + cairo_pattern_t *src, + cairo_pattern_t *mask, cairo_surface_t *dst, int src_x, int src_y, @@ -243,7 +443,6 @@ _cairo_surface_composite (cairo_operator_t operator, unsigned int height) { cairo_int_status_t status; - cairo_image_surface_t *src_image, *mask_image = 0, *dst_image; status = dst->backend->composite (operator, src, mask, dst, @@ -254,28 +453,12 @@ _cairo_surface_composite (cairo_operator_t operator, if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; - src_image = _cairo_surface_get_image (src); - if (mask) - mask_image = _cairo_surface_get_image (mask); - dst_image = _cairo_surface_get_image (dst); - - dst_image->base.backend->composite (operator, - &src_image->base, - mask ? &mask_image->base : NULL, - dst_image, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); - - status = _cairo_surface_set_image (dst, dst_image); - - cairo_surface_destroy (&src_image->base); - if (mask) - cairo_surface_destroy (&mask_image->base); - cairo_surface_destroy (&dst_image->base); - - return status; + return _fallback_composite (operator, + src, mask, dst, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); } cairo_status_t @@ -297,6 +480,77 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface, return _cairo_surface_fill_rectangles (surface, operator, color, &rect, 1); } +static cairo_status_t +_fallback_fill_rectangles (cairo_surface_t *surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + fallback_state_t state; + cairo_rectangle_t *offset_rects = NULL; + cairo_status_t status; + int x1, y1, x2, y2; + int i; + + if (num_rects <= 0) + return CAIRO_STATUS_SUCCESS; + + /* Compute the bounds of the rectangles, so that we know what area of the + * destination surface to fetch + */ + x1 = rects[0].x; + y1 = rects[0].y; + x2 = rects[0].x + rects[0].width; + y2 = rects[0].y + rects[0].height; + + for (i = 1; i < num_rects; i++) { + if (rects[0].x < x1) + x1 = rects[0].x; + if (rects[0].y < y1) + y1 = rects[0].y; + + if (rects[0].x + rects[0].width > x2) + x2 = rects[0].x + rects[0].width; + if (rects[0].y + rects[0].height > y2) + y2 = rects[0].y + rects[0].height; + } + + status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1); + if (!CAIRO_OK (status) || !state.image) + return status; + + /* If the fetched image isn't at 0,0, we need to offset the rectangles */ + + if (state.image_rect.x != 0 || state.image_rect.y != 0) { + offset_rects = malloc (sizeof (cairo_rectangle_t) * num_rects); + if (!offset_rects) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } + + for (i = 0; i < num_rects; i++) { + offset_rects[i].x = rects[i].x - state.image_rect.x; + offset_rects[i].y = rects[i].y - state.image_rect.y; + offset_rects[i].width = rects[i].width; + offset_rects[i].height = rects[i].height; + } + + rects = offset_rects; + } + + state.image->base.backend->fill_rectangles (&state.image->base, operator, color, + rects, num_rects); + + if (offset_rects) + free (offset_rects); + + FAIL: + _fallback_cleanup (&state); + + return status; +} + cairo_status_t _cairo_surface_fill_rectangles (cairo_surface_t *surface, cairo_operator_t operator, @@ -305,7 +559,6 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, int num_rects) { cairo_int_status_t status; - cairo_image_surface_t *surface_image; if (num_rects == 0) return CAIRO_STATUS_SUCCESS; @@ -317,54 +570,105 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; - surface_image = _cairo_surface_get_image (surface); + return _fallback_fill_rectangles (surface, operator, color, rects, num_rects); +} + +static cairo_status_t +_fallback_composite_trapezoids (cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *dst, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, + cairo_trapezoid_t *traps, + int num_traps) +{ + fallback_state_t state; + cairo_trapezoid_t *offset_traps = NULL; + cairo_status_t status; + int i; + + status = _fallback_init (&state, dst, dst_x, dst_y, width, height); + if (!CAIRO_OK (status) || !state.image) + return status; - surface_image->base.backend->fill_rectangles (surface_image, - operator, - color, - rects, num_rects); + /* If the destination image isn't at 0,0, we need to offset the trapezoids */ + + if (state.image_rect.x != 0 || state.image_rect.y != 0) { + + cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x); + cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y); + + offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps); + if (!offset_traps) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } - status = _cairo_surface_set_image (surface, surface_image); + for (i = 0; i < num_traps; i++) { + offset_traps[i].top = traps[i].top - yoff; + offset_traps[i].bottom = traps[i].bottom - yoff; + offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff; + offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff; + offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff; + offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff; + offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff; + offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff; + offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff; + offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff; + } - cairo_surface_destroy (&surface_image->base); + traps = offset_traps; + } + state.image->base.backend->composite_trapezoids (operator, pattern, + &state.image->base, + src_x, src_y, + dst_x - state.image_rect.x, + dst_y - state.image_rect.y, + width, height, traps, num_traps); + if (offset_traps) + free (offset_traps); + + FAIL: + _fallback_cleanup (&state); + return status; } + cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *src, + cairo_pattern_t *pattern, cairo_surface_t *dst, - int x_src, - int y_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps) { cairo_int_status_t status; - cairo_image_surface_t *src_image, *dst_image; status = dst->backend->composite_trapezoids (operator, - src, dst, - x_src, y_src, + pattern, dst, + src_x, src_y, + dst_x, dst_y, + width, height, traps, num_traps); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; - src_image = _cairo_surface_get_image (src); - dst_image = _cairo_surface_get_image (dst); - - dst_image->base.backend->composite_trapezoids (operator, - &src_image->base, - dst_image, - x_src, y_src, - traps, num_traps); - - status = _cairo_surface_set_image (dst, dst_image); - - cairo_surface_destroy (&src_image->base); - cairo_surface_destroy (&dst_image->base); - - return status; + return _fallback_composite_trapezoids (operator, pattern, dst, + src_x, src_y, + dst_x, dst_y, + width, height, + traps, num_traps); } cairo_status_t @@ -402,109 +706,3 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *reg { return surface->backend->set_clip_region (surface, region); } - -cairo_status_t -_cairo_surface_create_pattern (cairo_surface_t *surface, - cairo_pattern_t *pattern, - cairo_box_t *box) -{ - cairo_int_status_t status; - - status = surface->backend->create_pattern (surface, pattern, box); - - /* The backend cannot accelerate this pattern, lets create an - unaccelerated source instead. */ - if (status == CAIRO_INT_STATUS_UNSUPPORTED) { - - status = CAIRO_STATUS_SUCCESS; - switch (pattern->type) { - case CAIRO_PATTERN_LINEAR: - case CAIRO_PATTERN_RADIAL: { - cairo_image_surface_t *image; - - image = _cairo_pattern_get_image (pattern, box); - if (image) { - pattern->source = &image->base; - - return CAIRO_STATUS_SUCCESS; - } else - return CAIRO_STATUS_NO_MEMORY; - - } break; - case CAIRO_PATTERN_SOLID: - pattern->source = - _cairo_surface_create_similar_solid (surface, - CAIRO_FORMAT_ARGB32, - 1, 1, - &pattern->color); - if (pattern->source) { - cairo_surface_set_repeat (pattern->source, 1); - - return CAIRO_STATUS_SUCCESS; - } else - return CAIRO_STATUS_NO_MEMORY; - break; - case CAIRO_PATTERN_SURFACE: - status = CAIRO_INT_STATUS_UNSUPPORTED; - - /* handle pattern opacity */ - if (pattern->color.alpha != 1.0) { - double x = box->p1.x >> 16; - double y = box->p1.y >> 16; - int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16); - int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16); - cairo_pattern_t alpha; - - pattern->source = - cairo_surface_create_similar (surface, - CAIRO_FORMAT_ARGB32, - width, height); - if (pattern->source) { - _cairo_pattern_init_solid (&alpha, 1.0, 1.0, 1.0); - _cairo_pattern_set_alpha (&alpha, pattern->color.alpha); - - status = _cairo_surface_create_pattern (pattern->source, - &alpha, box); - - if (status == CAIRO_STATUS_SUCCESS) { - int save_repeat = pattern->u.surface.surface->repeat; - - if (pattern->extend == CAIRO_EXTEND_REPEAT || - pattern->u.surface.surface->repeat == 1) - cairo_surface_set_repeat (pattern->u.surface.surface, 1); - else - cairo_surface_set_repeat (pattern->u.surface.surface, 0); - - status = - _cairo_surface_composite (CAIRO_OPERATOR_OVER, - pattern->u.surface.surface, - alpha.source, - pattern->source, - 0, 0, 0, 0, 0, 0, - width, height); - - cairo_surface_set_repeat (pattern->u.surface.surface, - save_repeat); - - if (status == CAIRO_STATUS_SUCCESS) - _cairo_pattern_set_source_offset (pattern, x, y); - else - cairo_surface_destroy (pattern->source); - } - - _cairo_pattern_fini (&alpha); - } - } - - if (status != CAIRO_STATUS_SUCCESS) { - pattern->source = pattern->u.surface.surface; - cairo_surface_reference (pattern->u.surface.surface); - - return CAIRO_STATUS_SUCCESS; - } - break; - } - } - - return status; -} diff --git a/src/cairo-traps.c b/src/cairo-traps.c index d17a27281..79c7e16b6 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -1,31 +1,42 @@ /* - * Copyright © 2002 Keith Packard + * Copyright © 2002 Keith Packard * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Keith R. Packard <keithp@keithp.com> + * Carl D. Worth <cworth@cworth.org> * * 2002-07-15: Converted from XRenderCompositeDoublePoly to cairo_trap. Carl D. Worth */ #include "cairoint.h" -#define CAIRO_TRAPS_GROWTH_INC 10 - /* private functions */ static cairo_status_t @@ -52,12 +63,6 @@ _compare_cairo_edge_by_slope (const void *av, const void *bv); static cairo_fixed_16_16_t _compute_x (cairo_line_t *line, cairo_fixed_t y); -static double -_compute_inverse_slope (cairo_line_t *l); - -static double -_compute_x_intercept (cairo_line_t *l, double inverse_slope); - static int _line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret); @@ -68,6 +73,8 @@ _cairo_traps_init (cairo_traps_t *traps) traps->traps_size = 0; traps->traps = NULL; + traps->extents.p1.x = traps->extents.p1.y = CAIRO_MAXSHORT << 16; + traps->extents.p2.x = traps->extents.p2.y = CAIRO_MINSHORT << 16; } void @@ -93,7 +100,8 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo } if (traps->num_traps >= traps->traps_size) { - status = _cairo_traps_grow_by (traps, CAIRO_TRAPS_GROWTH_INC); + int inc = traps->traps_size ? traps->traps_size : 32; + status = _cairo_traps_grow_by (traps, inc); if (status) return status; } @@ -104,6 +112,28 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo trap->left = *left; trap->right = *right; + if (top < traps->extents.p1.y) + traps->extents.p1.y = top; + if (bottom > traps->extents.p2.y) + traps->extents.p2.y = bottom; + /* + * This isn't generally accurate, but it is close enough for + * this purpose. Assuming that the left and right segments always + * contain the trapezoid vertical extents, these compares will + * yield a containing box. Assuming that the points all come from + * the same figure which will eventually be completely drawn, then + * the compares will yield the correct overall extents + */ + if (left->p1.x < traps->extents.p1.x) + traps->extents.p1.x = left->p1.x; + if (left->p2.x < traps->extents.p1.x) + traps->extents.p1.x = left->p2.x; + + if (right->p1.x > traps->extents.p2.x) + traps->extents.p2.x = right->p1.x; + if (right->p2.x > traps->extents.p2.x) + traps->extents.p2.x = right->p2.x; + traps->num_traps++; return CAIRO_STATUS_SUCCESS; @@ -327,40 +357,132 @@ _compare_cairo_edge_by_current_x_slope (const void *av, const void *bv) sub-computations -- just a bunch of determinants. I haven't looked at complexity, (both are probably similar and it probably doesn't matter much anyway). + */ -static double -_det (double a, double b, double c, double d) +/* XXX: Keith's new intersection code is much cleaner, and uses + * sufficient precision for correctly sorting intersections according + * to the analysis in Hobby's paper. + * + * But, when we enable this code, some things are failing, (eg. the + * stars in test/fill_rule get filled wrong). This could indicate a + * bug in one of tree places: + * + * 1) The new intersection code in this file + * + * 2) cairo_wideint.c (which is only exercised here) + * + * 3) In the current tessellator, (where the old intersection + * code, with its mystic increments could be masking the bug). + * + * It will likely be easier to revisit this when the new tessellation + * code is in place. So, for now, we'll simply disable the new + * intersection code. + */ + +#define CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE 0 + +#if CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE +static const cairo_fixed_32_32_t +_det16_32 (cairo_fixed_16_16_t a, + cairo_fixed_16_16_t b, + cairo_fixed_16_16_t c, + cairo_fixed_16_16_t d) { - return a * d - b * c; + return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d), + _cairo_int32x32_64_mul (b, c)); } -static int -_lines_intersect (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection) +static const cairo_fixed_64_64_t +_det32_64 (cairo_fixed_32_32_t a, + cairo_fixed_32_32_t b, + cairo_fixed_32_32_t c, + cairo_fixed_32_32_t d) { - double dx1 = cairo_fixed_to_double (l1->p1.x - l1->p2.x); - double dy1 = cairo_fixed_to_double (l1->p1.y - l1->p2.y); - - double dx2 = cairo_fixed_to_double (l2->p1.x - l2->p2.x); - double dy2 = cairo_fixed_to_double (l2->p1.y - l2->p2.y); - - double l1_det, l2_det; + return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d), + _cairo_int64x64_128_mul (b, c)); +} - double den_det = _det (dx1, dy1, dx2, dy2); +static const cairo_fixed_32_32_t +_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a) +{ + return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16); +} - if (den_det == 0) +static int +_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection) +{ + cairo_fixed_16_16_t dx1, dx2, dy1, dy2; + cairo_fixed_32_32_t den_det; + cairo_fixed_32_32_t l1_det, l2_det; + cairo_fixed_64_64_t num_det; + cairo_fixed_32_32_t intersect_32_32; + cairo_fixed_48_16_t intersect_48_16; + cairo_fixed_16_16_t intersect_16_16; + cairo_quorem128_t qr; + + dx1 = l1->p1.x - l1->p2.x; + dy1 = l1->p1.y - l1->p2.y; + dx2 = l2->p1.x - l2->p2.x; + dy2 = l2->p1.y - l2->p2.y; + den_det = _det16_32 (dx1, dy1, + dx2, dy2); + + if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0))) return 0; - l1_det = _det (l1->p1.x, l1->p1.y, - l1->p2.x, l1->p2.y); - l2_det = _det (l2->p1.x, l2->p1.y, - l2->p2.x, l2->p2.y); + l1_det = _det16_32 (l1->p1.x, l1->p1.y, + l1->p2.x, l1->p2.y); + l2_det = _det16_32 (l2->p1.x, l2->p1.y, + l2->p2.x, l2->p2.y); - *y_intersection = _det (l1_det, dy1, - l2_det, dy2) / den_det; + + num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1), + l2_det, _fixed_16_16_to_fixed_32_32 (dy2)); + + /* + * Ok, this one is a bit tricky in fixed point, the denominator + * needs to be left with 32-bits of fraction so that the + * result of the divide ends up with 32-bits of fraction (64 - 32 = 32) + */ + qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det)); + + intersect_32_32 = _cairo_int128_to_int64 (qr.quo); + + /* + * Find the ceiling of the quotient -- divrem returns + * the quotient truncated towards zero, so if the + * quotient should be positive (num_den and den_det have same sign) + * bump the quotient up by one. + */ + + if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) && + (_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) == + _cairo_int64_ge (den_det, _cairo_int32_to_int64 (0)))) + { + intersect_32_32 = _cairo_int64_add (intersect_32_32, + _cairo_int32_to_int64 (1)); + } + + /* + * Now convert from 32.32 to 48.16 and take the ceiling; + * this requires adding in 15 1 bits and shifting the result + */ + + intersect_32_32 = _cairo_int64_add (intersect_32_32, + _cairo_int32_to_int64 ((1 << 16) - 1)); + intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16); + + /* + * And drop the top bits + */ + intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16); + + *y_intersection = intersect_16_16; return 1; } -*/ +#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */ + static cairo_fixed_16_16_t _compute_x (cairo_line_t *line, cairo_fixed_t y) { @@ -371,6 +493,7 @@ _compute_x (cairo_line_t *line, cairo_fixed_t y) return line->p1.x + (ex / dy); } +#if ! CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE static double _compute_inverse_slope (cairo_line_t *l) { @@ -460,6 +583,7 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ return 1; } +#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */ /* The algorithm here is pretty simple: @@ -567,32 +691,32 @@ _cairo_traps_tessellate_polygon (cairo_traps_t *traps, return CAIRO_STATUS_SUCCESS; } -static int +static cairo_bool_t _cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt) { cairo_slope_t slope_left, slope_pt, slope_right; if (t->top > pt->y) - return 0; + return FALSE; if (t->bottom < pt->y) - return 0; + return FALSE; _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2); _cairo_slope_init (&slope_pt, &t->left.p1, pt); if (_cairo_slope_compare (&slope_left, &slope_pt) < 0) - return 0; + return FALSE; _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2); _cairo_slope_init (&slope_pt, &t->right.p1, pt); if (_cairo_slope_compare (&slope_pt, &slope_right) < 0) - return 0; + return FALSE; - return 1; + return TRUE; } -int +cairo_bool_t _cairo_traps_contain (cairo_traps_t *traps, double x, double y) { int i; @@ -603,45 +727,14 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y) for (i = 0; i < traps->num_traps; i++) { if (_cairo_trap_contains (&traps->traps[i], &point)) - return 1; + return TRUE; } - return 0; -} - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) > (b) ? (a) : (b)) - -static void -_cairo_trap_extents (cairo_trapezoid_t *t, cairo_box_t *extents) -{ - cairo_fixed_t x; - - if (t->top < extents->p1.y) - extents->p1.y = t->top; - - if (t->bottom > extents->p2.y) - extents->p2.y = t->bottom; - - x = MIN (_compute_x (&t->left, t->top), - _compute_x (&t->left, t->bottom)); - if (x < extents->p1.x) - extents->p1.x = x; - - x = MAX (_compute_x (&t->right, t->top), - _compute_x (&t->right, t->bottom)); - if (x > extents->p2.x) - extents->p2.x = x; + return FALSE; } void _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents) { - int i; - - extents->p1.x = extents->p1.y = CAIRO_MAXSHORT << 16; - extents->p2.x = extents->p2.y = CAIRO_MINSHORT << 16; - - for (i = 0; i < traps->num_traps; i++) - _cairo_trap_extents (&traps->traps[i], extents); + *extents = traps->extents; } diff --git a/src/cairo-unicode.c b/src/cairo-unicode.c new file mode 100644 index 000000000..92201391a --- /dev/null +++ b/src/cairo-unicode.c @@ -0,0 +1,340 @@ +/* cairo_unicode.c: Unicode conversion routines + * + * The code in this file is derived from GLib's gutf8.c and + * ultimately from libunicode. It is relicensed under the + * dual LGPL/MPL with permission of the original authors. + * + * Copyright © 1999 Tom Tromey + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is cairo_unicode.c as distributed with the + * cairo graphics library. + * + * The Initial Developer of the Original Code is Tom Tromey. + * and Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor <otaylor@redhat.com> + */ + +#include <limits.h> + +#include <cairoint.h> + +#define UTF8_COMPUTE(Char, Mask, Len) \ + if (Char < 128) \ + { \ + Len = 1; \ + Mask = 0x7f; \ + } \ + else if ((Char & 0xe0) == 0xc0) \ + { \ + Len = 2; \ + Mask = 0x1f; \ + } \ + else if ((Char & 0xf0) == 0xe0) \ + { \ + Len = 3; \ + Mask = 0x0f; \ + } \ + else if ((Char & 0xf8) == 0xf0) \ + { \ + Len = 4; \ + Mask = 0x07; \ + } \ + else if ((Char & 0xfc) == 0xf8) \ + { \ + Len = 5; \ + Mask = 0x03; \ + } \ + else if ((Char & 0xfe) == 0xfc) \ + { \ + Len = 6; \ + Mask = 0x01; \ + } \ + else \ + Len = -1; + +#define UTF8_LENGTH(Char) \ + ((Char) < 0x80 ? 1 : \ + ((Char) < 0x800 ? 2 : \ + ((Char) < 0x10000 ? 3 : \ + ((Char) < 0x200000 ? 4 : \ + ((Char) < 0x4000000 ? 5 : 6))))) + + +#define UTF8_GET(Result, Chars, Count, Mask, Len) \ + (Result) = (Chars)[0] & (Mask); \ + for ((Count) = 1; (Count) < (Len); ++(Count)) \ + { \ + if (((Chars)[(Count)] & 0xc0) != 0x80) \ + { \ + (Result) = -1; \ + break; \ + } \ + (Result) <<= 6; \ + (Result) |= ((Chars)[(Count)] & 0x3f); \ + } + +#define UNICODE_VALID(Char) \ + ((Char) < 0x110000 && \ + (((Char) & 0xFFFFF800) != 0xD800) && \ + ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \ + ((Char) & 0xFFFE) != 0xFFFE) + + +static const char utf8_skip_data[256] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 +}; + +#define UTF8_NEXT_CHAR(p) (char *)((p) + utf8_skip_data[*(unsigned char *)(p)]) + +/* Converts a sequence of bytes encoded as UTF-8 to a Unicode character. + * If @p does not point to a valid UTF-8 encoded character, results are + * undefined. + **/ +static uint32_t +_utf8_get_char (const char *p) +{ + int i, mask = 0, len; + uint32_t result; + unsigned char c = (unsigned char) *p; + + UTF8_COMPUTE (c, mask, len); + if (len == -1) + return (uint32_t)-1; + UTF8_GET (result, p, i, mask, len); + + return result; +} + +/* Like _utf8_get_char, but take a maximum length + * and return (uint32_t)-2 on incomplete trailing character + */ +static uint32_t +_utf8_get_char_extended (const char *p, + long max_len) +{ + int i, len; + uint32_t wc = (unsigned char) *p; + + if (wc < 0x80) { + return wc; + } else if (wc < 0xc0) { + return (uint32_t)-1; + } else if (wc < 0xe0) { + len = 2; + wc &= 0x1f; + } else if (wc < 0xf0) { + len = 3; + wc &= 0x0f; + } else if (wc < 0xf8) { + len = 4; + wc &= 0x07; + } else if (wc < 0xfc) { + len = 5; + wc &= 0x03; + } else if (wc < 0xfe) { + len = 6; + wc &= 0x01; + } else { + return (uint32_t)-1; + } + + if (max_len >= 0 && len > max_len) { + for (i = 1; i < max_len; i++) { + if ((((unsigned char *)p)[i] & 0xc0) != 0x80) + return (uint32_t)-1; + } + return (uint32_t)-2; + } + + for (i = 1; i < len; ++i) { + uint32_t ch = ((unsigned char *)p)[i]; + + if ((ch & 0xc0) != 0x80) { + if (ch) + return (uint32_t)-1; + else + return (uint32_t)-2; + } + + wc <<= 6; + wc |= (ch & 0x3f); + } + + if (UTF8_LENGTH(wc) != len) + return (uint32_t)-1; + + return wc; +} + +/** + * _cairo_utf8_to_utf32: + * @str: an UTF-8 string + * @len: length of @str in bytes, or -1 if it is nul-terminated. + * If @len is supplied and the string has an embedded nul + * byte, only the portion before the nul byte is converted. + * @result: location to store a pointer to a newly allocated UTF-32 + * string (always native endian). Free with free(). A 0 + * word will be written after the last character. + * @items_written: location to store number of 32-bit words + * written. (Not including the trailing 0) + * + * Converts a UTF-8 string to UCS-4. UCS-4 is an encoding of Unicode + * with 1 32-bit word per character. The string is validated to + * consist entirely of valid Unicode characters. + * + * Return value: %CAIRO_STATUS_SUCCESS if the entire string was + * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an + * an invalid sequence was found. + **/ +cairo_status_t +_cairo_utf8_to_ucs4 (const char *str, + int len, + uint32_t **result, + int *items_written) +{ + uint32_t *str32 = NULL; + int n_chars, i; + const char *in; + + in = str; + n_chars = 0; + while ((len < 0 || str + len - in > 0) && *in) + { + uint32_t wc = _utf8_get_char_extended (in, str + len - in); + if (wc & 0x80000000 || !UNICODE_VALID (wc)) + return CAIRO_STATUS_INVALID_STRING; + + n_chars++; + if (n_chars == INT_MAX) + return CAIRO_STATUS_INVALID_STRING; + + in = UTF8_NEXT_CHAR (in); + } + + str32 = malloc (sizeof (uint32_t) * (n_chars + 1)); + if (!str32) + return CAIRO_STATUS_NO_MEMORY; + + in = str; + for (i=0; i < n_chars; i++) { + str32[i] = _utf8_get_char (in); + in = UTF8_NEXT_CHAR (in); + } + str32[i] = 0; + + *result = str32; + if (items_written) + *items_written = n_chars; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_utf8_to_utf16: + * @str: an UTF-8 string + * @len: length of @str in bytes, or -1 if it is nul-terminated. + * If @len is supplied and the string has an embedded nul + * byte, only the portion before the nul byte is converted. + * @result: location to store a pointer to a newly allocated UTF-16 + * string (always native endian). Free with free(). A 0 + * word will be written after the last character. + * @items_written: location to store number of 16-bit words + * written. (Not including the trailing 0) + * + * Converts a UTF-8 string to UTF-16. UTF-16 is an encoding of Unicode + * where characters are represented either as a single 16-bit word, or + * as a pair of 16-bit "surrogates". The string is validated to + * consist entirely of valid Unicode characters. + * + * Return value: %CAIRO_STATUS_SUCCESS if the entire string was + * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an + * an invalid sequence was found. + **/ +cairo_status_t +_cairo_utf8_to_utf16 (const char *str, + int len, + uint16_t **result, + int *items_written) +{ + uint16_t *str16 = NULL; + int n16, i; + const char *in; + + in = str; + n16 = 0; + while ((len < 0 || str + len - in > 0) && *in) { + uint32_t wc = _utf8_get_char_extended (in, str + len - in); + if (wc & 0x80000000 || !UNICODE_VALID (wc)) + return CAIRO_STATUS_INVALID_STRING; + + if (wc < 0x10000) + n16 += 1; + else + n16 += 2; + + if (n16 == INT_MAX - 1 || n16 == INT_MAX) + return CAIRO_STATUS_INVALID_STRING; + + in = UTF8_NEXT_CHAR (in); + } + + + str16 = malloc (sizeof (uint16_t) * (n16 + 1)); + if (!str16) + return CAIRO_STATUS_NO_MEMORY; + + in = str; + for (i = 0; i < n16;) { + uint32_t wc = _utf8_get_char (in); + + if (wc < 0x10000) { + str16[i++] = wc; + } else { + str16[i++] = (wc - 0x10000) / 0x400 + 0xd800; + str16[i++] = (wc - 0x10000) % 0x400 + 0xdc00; + } + + in = UTF8_NEXT_CHAR (in); + } + + str16[i] = 0; + + *result = str16; + if (items_written) + *items_written = n16; + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c new file mode 100644 index 000000000..02f0cffd6 --- /dev/null +++ b/src/cairo-win32-font.c @@ -0,0 +1,1252 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + */ + +#include <string.h> +#include <stdio.h> + +#include "cairo-win32-private.h" + +#ifndef SPI_GETFONTSMOOTHINGTYPE +#define SPI_GETFONTSMOOTHINGTYPE 0x200a +#endif +#ifndef FE_FONTSMOOTHINGCLEARTYPE +#define FE_FONTSMOOTHINGCLEARTYPE 2 +#endif +#ifndef CLEARTYPE_QUALITY +#define CLEARTYPE_QUALITY 5 +#endif + +const cairo_font_backend_t cairo_win32_font_backend; + +#define LOGICAL_SCALE 32 + +typedef struct { + cairo_font_t base; + + LOGFONTW logfont; + + BYTE quality; + + /* We do drawing and metrics computation in a "logical space" which + * is similar to font space, except that it is scaled by a factor + * of the (desired font size) * (LOGICAL_SCALE). The multiplication + * by LOGICAL_SCALE allows for sub-pixel precision. + */ + double logical_scale; + + /* The size we should actually request the font at from Windows; differs + * from the logical_scale because it is quantized for orthogonal + * transformations + */ + double logical_size; + + /* Transformations from device <=> logical space + */ + cairo_matrix_t logical_to_device; + cairo_matrix_t device_to_logical; + + /* We special case combinations of 90-degree-rotations, scales and + * flips ... that is transformations that take the axes to the + * axes. If preserve_axes is true, then swap_axes/swap_x/swap_y + * encode the 8 possibilities for orientation (4 rotation angles with + * and without a flip), and scale_x, scale_y the scale components. + */ + cairo_bool_t preserve_axes; + cairo_bool_t swap_axes; + cairo_bool_t swap_x; + cairo_bool_t swap_y; + double x_scale; + double y_scale; + + /* The size of the design unit of the font + */ + int em_square; + + HFONT scaled_font; + HFONT unscaled_font; + +} cairo_win32_font_t; + +#define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.)) + +static void +_compute_transform (cairo_win32_font_t *font, + cairo_font_scale_t *sc) +{ + if (NEARLY_ZERO (sc->matrix[0][1]) && NEARLY_ZERO (sc->matrix[1][0])) { + font->preserve_axes = TRUE; + font->x_scale = sc->matrix[0][0]; + font->swap_x = (sc->matrix[0][0] < 0); + font->y_scale = sc->matrix[1][1]; + font->swap_y = (sc->matrix[1][1] < 0); + font->swap_axes = FALSE; + + } else if (NEARLY_ZERO (sc->matrix[0][0]) && NEARLY_ZERO (sc->matrix[1][1])) { + font->preserve_axes = TRUE; + font->x_scale = sc->matrix[0][1]; + font->swap_x = (sc->matrix[0][1] < 0); + font->y_scale = sc->matrix[1][0]; + font->swap_y = (sc->matrix[1][0] < 0); + font->swap_axes = TRUE; + + } else { + font->preserve_axes = FALSE; + font->swap_x = font->swap_y = font->swap_axes = FALSE; + } + + if (font->preserve_axes) { + if (font->swap_x) + font->x_scale = - font->x_scale; + if (font->swap_y) + font->y_scale = - font->y_scale; + + font->logical_scale = LOGICAL_SCALE * font->y_scale; + font->logical_size = LOGICAL_SCALE * floor (font->y_scale + 0.5); + } + + /* The font matrix has x and y "scale" components which we extract and + * use as character scale values. + */ + cairo_matrix_set_affine (&font->logical_to_device, + sc->matrix[0][0], + sc->matrix[0][1], + sc->matrix[1][0], + sc->matrix[1][1], + 0, 0); + + if (!font->preserve_axes) { + _cairo_matrix_compute_scale_factors (&font->logical_to_device, + &font->x_scale, &font->y_scale, + TRUE); /* XXX: Handle vertical text */ + + font->logical_size = floor (LOGICAL_SCALE * font->y_scale + 0.5); + font->logical_scale = LOGICAL_SCALE * font->y_scale; + } + + cairo_matrix_scale (&font->logical_to_device, + 1.0 / font->logical_scale, 1.0 / font->logical_scale); + + font->device_to_logical = font->logical_to_device; + if (!CAIRO_OK (cairo_matrix_invert (&font->device_to_logical))) + cairo_matrix_set_identity (&font->device_to_logical); +} + +static BYTE +_get_system_quality (void) +{ + BOOL font_smoothing; + + if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) { + _cairo_win32_print_gdi_error ("_get_system_quality"); + return FALSE; + } + + if (font_smoothing) { + OSVERSIONINFO version_info; + + version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + + if (!GetVersionEx (&version_info)) { + _cairo_win32_print_gdi_error ("_get_system_quality"); + return FALSE; + } + + if (version_info.dwMajorVersion > 5 || + (version_info.dwMajorVersion == 5 && + version_info.dwMinorVersion >= 1)) { /* XP or newer */ + UINT smoothing_type; + + if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE, + 0, &smoothing_type, 0)) { + _cairo_win32_print_gdi_error ("_get_system_quality"); + return FALSE; + } + + if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE) + return CLEARTYPE_QUALITY; + } + + return ANTIALIASED_QUALITY; + } else + return DEFAULT_QUALITY; +} + +static cairo_font_t * +_win32_font_create (LOGFONTW *logfont, + cairo_font_scale_t *scale) +{ + cairo_win32_font_t *f; + + f = malloc (sizeof(cairo_win32_font_t)); + if (f == NULL) + return NULL; + + f->logfont = *logfont; + f->quality = _get_system_quality (); + f->em_square = 0; + f->scaled_font = NULL; + f->unscaled_font = NULL; + + _compute_transform (f, scale); + + _cairo_font_init ((cairo_font_t *)f, scale, &cairo_win32_font_backend); + + return (cairo_font_t *)f; +} + +static cairo_status_t +_win32_font_set_world_transform (cairo_win32_font_t *font, + HDC hdc) +{ + XFORM xform; + + xform.eM11 = font->logical_to_device.m[0][0]; + xform.eM21 = font->logical_to_device.m[1][0]; + xform.eM12 = font->logical_to_device.m[0][1]; + xform.eM22 = font->logical_to_device.m[1][1]; + xform.eDx = font->logical_to_device.m[2][0]; + xform.eDy = font->logical_to_device.m[2][1]; + + if (!SetWorldTransform (hdc, &xform)) + return _cairo_win32_print_gdi_error ("_win32_font_set_world_transform"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_win32_font_set_identity_transform (HDC hdc) +{ + if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY)) + return _cairo_win32_print_gdi_error ("_win32_font_set_identity_transform"); + + return CAIRO_STATUS_SUCCESS; +} + +static HDC +_get_global_font_dc (void) +{ + static HDC hdc; + + if (!hdc) { + hdc = CreateCompatibleDC (NULL); + if (!hdc) { + _cairo_win32_print_gdi_error ("_get_global_font_dc"); + return NULL; + } + + if (!SetGraphicsMode (hdc, GM_ADVANCED)) { + _cairo_win32_print_gdi_error ("_get_global_font_dc"); + DeleteDC (hdc); + return NULL; + } + } + + return hdc; +} + +static HFONT +_win32_font_get_scaled_font (cairo_win32_font_t *font) +{ + if (!font->scaled_font) { + LOGFONTW logfont = font->logfont; + logfont.lfHeight = font->logical_size; + logfont.lfWidth = 0; + logfont.lfEscapement = 0; + logfont.lfOrientation = 0; + logfont.lfQuality = font->quality; + + font->scaled_font = CreateFontIndirectW (&logfont); + if (!font->scaled_font) { + _cairo_win32_print_gdi_error ("_win32_font_get_scaled_font"); + return NULL; + } + } + + return font->scaled_font; +} + +static HFONT +_win32_font_get_unscaled_font (cairo_win32_font_t *font, + HDC hdc) +{ + if (!font->unscaled_font) { + OUTLINETEXTMETRIC *otm; + unsigned int otm_size; + HFONT scaled_font; + LOGFONTW logfont; + + scaled_font = _win32_font_get_scaled_font (font); + if (!scaled_font) + return NULL; + + if (!SelectObject (hdc, scaled_font)) { + _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:SelectObject"); + return NULL; + } + + otm_size = GetOutlineTextMetrics (hdc, 0, NULL); + if (!otm_size) { + _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics"); + return NULL; + } + + otm = malloc (otm_size); + if (!otm) + return NULL; + + if (!GetOutlineTextMetrics (hdc, otm_size, otm)) { + _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics"); + free (otm); + return NULL; + } + + font->em_square = otm->otmEMSquare; + free (otm); + + logfont = font->logfont; + logfont.lfHeight = font->em_square; + logfont.lfWidth = 0; + logfont.lfEscapement = 0; + logfont.lfOrientation = 0; + logfont.lfQuality = font->quality; + + font->unscaled_font = CreateFontIndirectW (&logfont); + if (!font->unscaled_font) { + _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:CreateIndirect"); + return NULL; + } + } + + return font->unscaled_font; +} + +static cairo_status_t +_cairo_win32_font_select_unscaled_font (cairo_font_t *font, + HDC hdc) +{ + cairo_status_t status; + HFONT hfont; + HFONT old_hfont = NULL; + + hfont = _win32_font_get_unscaled_font ((cairo_win32_font_t *)font, hdc); + if (!hfont) + return CAIRO_STATUS_NO_MEMORY; + + old_hfont = SelectObject (hdc, hfont); + if (!old_hfont) + return _cairo_win32_print_gdi_error ("_cairo_win32_font_select_unscaled_font"); + + status = _win32_font_set_identity_transform (hdc); + if (!CAIRO_OK (status)) { + SelectObject (hdc, old_hfont); + return status; + } + + SetMapMode (hdc, MM_TEXT); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_win32_font_done_unscaled_font (cairo_font_t *font) +{ +} + +/* implement the font backend interface */ + +static cairo_status_t +_cairo_win32_font_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight, + cairo_font_scale_t *scale, + cairo_font_t **font_out) +{ + LOGFONTW logfont; + cairo_font_t *font; + uint16_t *face_name; + int face_name_len; + cairo_status_t status; + + status = _cairo_utf8_to_utf16 (family, -1, &face_name, &face_name_len); + if (!CAIRO_OK (status)) + return status; + + if (face_name_len > LF_FACESIZE - 1) { + free (face_name); + return CAIRO_STATUS_INVALID_STRING; + } + + memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * (face_name_len + 1)); + free (face_name); + + logfont.lfHeight = 0; /* filled in later */ + logfont.lfWidth = 0; /* filled in later */ + logfont.lfEscapement = 0; /* filled in later */ + logfont.lfOrientation = 0; /* filled in later */ + + switch (weight) { + case CAIRO_FONT_WEIGHT_NORMAL: + default: + logfont.lfWeight = FW_NORMAL; + break; + case CAIRO_FONT_WEIGHT_BOLD: + logfont.lfWeight = FW_BOLD; + break; + } + + switch (slant) { + case CAIRO_FONT_SLANT_NORMAL: + default: + logfont.lfItalic = FALSE; + break; + case CAIRO_FONT_SLANT_ITALIC: + case CAIRO_FONT_SLANT_OBLIQUE: + logfont.lfItalic = TRUE; + break; + } + + logfont.lfUnderline = FALSE; + logfont.lfStrikeOut = FALSE; + /* The docs for LOGFONT discourage using this, since the + * interpretation is locale-specific, but it's not clear what + * would be a better alternative. + */ + logfont.lfCharSet = DEFAULT_CHARSET; + logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; + logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logfont.lfQuality = DEFAULT_QUALITY; /* filled in later */ + logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + + if (!logfont.lfFaceName) + return CAIRO_STATUS_NO_MEMORY; + + font = _win32_font_create (&logfont, scale); + if (!font) + return CAIRO_STATUS_NO_MEMORY; + + *font_out = font; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_win32_font_destroy_font (void *abstract_font) +{ + cairo_win32_font_t *font = abstract_font; + + if (font->scaled_font) + DeleteObject (font->scaled_font); + + if (font->unscaled_font) + DeleteObject (font->unscaled_font); + + free (font); +} + +static void +_cairo_win32_font_destroy_unscaled_font (void *abstract_font) +{ +} + +static void +_cairo_win32_font_get_glyph_cache_key (void *abstract_font, + cairo_glyph_cache_key_t *key) +{ +} + +static cairo_status_t +_cairo_win32_font_text_to_glyphs (void *abstract_font, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs) +{ + cairo_win32_font_t *font = abstract_font; + uint16_t *utf16; + int n16; + GCP_RESULTSW gcp_results; + unsigned int buffer_size, i; + WCHAR *glyph_indices = NULL; + int *dx = NULL; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + double x_pos; + HDC hdc = NULL; + + status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16); + if (!CAIRO_OK (status)) + return status; + + gcp_results.lStructSize = sizeof (GCP_RESULTS); + gcp_results.lpOutString = NULL; + gcp_results.lpOrder = NULL; + gcp_results.lpCaretPos = NULL; + gcp_results.lpClass = NULL; + + buffer_size = MAX (n16 * 1.2, 16); /* Initially guess number of chars plus a few */ + if (buffer_size > INT_MAX) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL1; + } + + hdc = _get_global_font_dc (); + if (!hdc) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL1; + } + + status = cairo_win32_font_select_font (&font->base, hdc); + if (!CAIRO_OK (status)) + goto FAIL1; + + while (TRUE) { + if (glyph_indices) { + free (glyph_indices); + glyph_indices = NULL; + } + if (dx) { + free (dx); + dx = NULL; + } + + glyph_indices = malloc (sizeof (WCHAR) * buffer_size); + dx = malloc (sizeof (int) * buffer_size); + if (!glyph_indices || !dx) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; + } + + gcp_results.nGlyphs = buffer_size; + gcp_results.lpDx = dx; + gcp_results.lpGlyphs = glyph_indices; + + if (!GetCharacterPlacementW (hdc, utf16, n16, + 0, + &gcp_results, + GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER)) { + status = _cairo_win32_print_gdi_error ("_cairo_win32_font_text_to_glyphs"); + goto FAIL2; + } + + if (gcp_results.lpDx && gcp_results.lpGlyphs) + break; + + /* Too small a buffer, try again */ + + buffer_size *= 1.5; + if (buffer_size > INT_MAX) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; + } + } + + *num_glyphs = gcp_results.nGlyphs; + *glyphs = malloc (sizeof (cairo_glyph_t) * gcp_results.nGlyphs); + if (!*glyphs) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; + } + + x_pos = 0; + for (i = 0; i < gcp_results.nGlyphs; i++) { + (*glyphs)[i].index = glyph_indices[i]; + (*glyphs)[i].x = x_pos ; + (*glyphs)[i].y = 0; + + x_pos += dx[i] / font->logical_scale; + } + + FAIL2: + if (glyph_indices) + free (glyph_indices); + if (dx) + free (dx); + + cairo_win32_font_done_font (&font->base); + + FAIL1: + free (utf16); + + return status; +} + +static cairo_status_t +_cairo_win32_font_font_extents (void *abstract_font, + cairo_font_extents_t *extents) +{ + cairo_win32_font_t *font = abstract_font; + cairo_status_t status; + TEXTMETRIC metrics; + HDC hdc; + + hdc = _get_global_font_dc (); + if (!hdc) + return CAIRO_STATUS_NO_MEMORY; + + if (font->preserve_axes) { + /* For 90-degree rotations (including 0), we get the metrics + * from the GDI in logical space, then convert back to font space + */ + status = cairo_win32_font_select_font (&font->base, hdc); + if (!CAIRO_OK (status)) + return status; + GetTextMetrics (hdc, &metrics); + cairo_win32_font_done_font (&font->base); + + extents->ascent = metrics.tmAscent / font->logical_scale; + extents->descent = metrics.tmDescent / font->logical_scale; + + extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / font->logical_scale; + extents->max_x_advance = metrics.tmMaxCharWidth / font->logical_scale; + extents->max_y_advance = 0; + + } else { + /* For all other transformations, we use the design metrics + * of the font. The GDI results from GetTextMetrics() on a + * transformed font are inexplicably large and we want to + * avoid them. + */ + status = _cairo_win32_font_select_unscaled_font (&font->base, hdc); + if (!CAIRO_OK (status)) + return status; + GetTextMetrics (hdc, &metrics); + _cairo_win32_font_done_unscaled_font (&font->base); + + extents->ascent = (double)metrics.tmAscent / font->em_square; + extents->descent = metrics.tmDescent * font->em_square; + extents->height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / font->em_square; + extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / font->em_square; + extents->max_y_advance = 0; + + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_font_glyph_extents (void *abstract_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) +{ + cairo_win32_font_t *font = abstract_font; + static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; + GLYPHMETRICS metrics; + cairo_status_t status; + HDC hdc; + + hdc = _get_global_font_dc (); + if (!hdc) + return CAIRO_STATUS_NO_MEMORY; + + /* We handle only the case num_glyphs == 1, glyphs[i].x == glyphs[0].y == 0. + * This is all that the calling code triggers, and the backend interface + * will eventually be changed to match + */ + assert (num_glyphs == 1); + + if (font->preserve_axes) { + /* If we aren't rotating / skewing the axes, then we get the metrics + * from the GDI in device space and convert to font space. + */ + status = cairo_win32_font_select_font (&font->base, hdc); + if (!CAIRO_OK (status)) + return status; + GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX, + &metrics, 0, NULL, &matrix); + cairo_win32_font_done_font (&font->base); + + if (font->swap_axes) { + extents->x_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale; + extents->y_bearing = metrics.gmptGlyphOrigin.x / font->x_scale; + extents->width = metrics.gmBlackBoxY / font->y_scale; + extents->height = metrics.gmBlackBoxX / font->x_scale; + extents->x_advance = metrics.gmCellIncY / font->x_scale; + extents->y_advance = metrics.gmCellIncX / font->y_scale; + } else { + extents->x_bearing = metrics.gmptGlyphOrigin.x / font->x_scale; + extents->y_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale; + extents->width = metrics.gmBlackBoxX / font->x_scale; + extents->height = metrics.gmBlackBoxY / font->y_scale; + extents->x_advance = metrics.gmCellIncX / font->x_scale; + extents->y_advance = metrics.gmCellIncY / font->y_scale; + } + + if (font->swap_x) { + extents->x_bearing = (- extents->x_bearing - extents->width); + extents->x_advance = - extents->x_advance; + } + + if (font->swap_y) { + extents->y_bearing = (- extents->y_bearing - extents->height); + extents->y_advance = - extents->y_advance; + } + + } else { + /* For all other transformations, we use the design metrics + * of the font. + */ + status = _cairo_win32_font_select_unscaled_font (&font->base, hdc); + GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX, + &metrics, 0, NULL, &matrix); + _cairo_win32_font_done_unscaled_font (&font->base); + + extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / font->em_square; + extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / font->em_square; + extents->width = (double)metrics.gmBlackBoxX / font->em_square; + extents->height = (double)metrics.gmBlackBoxY / font->em_square; + extents->x_advance = (double)metrics.gmCellIncX / font->em_square; + extents->y_advance = (double)metrics.gmCellIncY / font->em_square; + } + + return CAIRO_STATUS_SUCCESS; +} + + +static cairo_status_t +_cairo_win32_font_glyph_bbox (void *abstract_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox) +{ + static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; + cairo_win32_font_t *font = abstract_font; + int x1 = 0, x2 = 0, y1 = 0, y2 = 0; + + if (num_glyphs > 0) { + HDC hdc = _get_global_font_dc (); + GLYPHMETRICS metrics; + cairo_status_t status; + int i; + + if (!hdc) + return CAIRO_STATUS_NO_MEMORY; + + status = cairo_win32_font_select_font (&font->base, hdc); + if (!CAIRO_OK (status)) + return status; + + for (i = 0; i < num_glyphs; i++) { + int x = floor (0.5 + glyphs[i].x); + int y = floor (0.5 + glyphs[i].y); + + GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | GGO_GLYPH_INDEX, + &metrics, 0, NULL, &matrix); + + if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x) + x1 = x + metrics.gmptGlyphOrigin.x; + if (i == 0 || y1 > y - metrics.gmptGlyphOrigin.y) + y1 = y - metrics.gmptGlyphOrigin.y; + if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX) + x2 = x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX; + if (i == 0 || y2 < y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY) + y2 = y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY; + } + + cairo_win32_font_done_font (&font->base); + } + + bbox->p1.x = _cairo_fixed_from_int (x1); + bbox->p1.y = _cairo_fixed_from_int (y1); + bbox->p2.x = _cairo_fixed_from_int (x2); + bbox->p2.y = _cairo_fixed_from_int (y2); + + return CAIRO_STATUS_SUCCESS; +} + +typedef struct { + cairo_win32_font_t *font; + HDC hdc; + + cairo_array_t glyphs; + cairo_array_t dx; + + int start_x; + int last_x; + int last_y; +} cairo_glyph_state_t; + +static void +_start_glyphs (cairo_glyph_state_t *state, + cairo_win32_font_t *font, + HDC hdc) +{ + state->hdc = hdc; + state->font = font; + + _cairo_array_init (&state->glyphs, sizeof (WCHAR)); + _cairo_array_init (&state->dx, sizeof (int)); +} + +static cairo_status_t +_flush_glyphs (cairo_glyph_state_t *state) +{ + int dx = 0; + if (!_cairo_array_append (&state->dx, &dx, 1)) + return CAIRO_STATUS_NO_MEMORY; + + if (!ExtTextOutW (state->hdc, + state->start_x, state->last_y, + ETO_GLYPH_INDEX, + NULL, + (WCHAR *)state->glyphs.elements, + state->glyphs.num_elements, + (int *)state->dx.elements)) { + return _cairo_win32_print_gdi_error ("_flush_glyphs"); + } + + _cairo_array_truncate (&state->glyphs, 0); + _cairo_array_truncate (&state->dx, 0); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_add_glyph (cairo_glyph_state_t *state, + unsigned long index, + double device_x, + double device_y) +{ + double user_x = device_x; + double user_y = device_y; + WCHAR glyph_index = index; + int logical_x, logical_y; + + cairo_matrix_transform_point (&state->font->device_to_logical, &user_x, &user_y); + + logical_x = floor (user_x + 0.5); + logical_y = floor (user_y + 0.5); + + if (state->glyphs.num_elements > 0) { + int dx; + + if (logical_y != state->last_y) { + cairo_status_t status = _flush_glyphs (state); + if (!CAIRO_OK (status)) + return status; + state->start_x = logical_x; + } + + dx = logical_x - state->last_x; + if (!_cairo_array_append (&state->dx, &dx, 1)) + return CAIRO_STATUS_NO_MEMORY; + } else { + state->start_x = logical_x; + } + + state->last_x = logical_x; + state->last_y = logical_y; + + _cairo_array_append (&state->glyphs, &glyph_index, 1); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_finish_glyphs (cairo_glyph_state_t *state) +{ + _flush_glyphs (state); + + _cairo_array_fini (&state->glyphs); + _cairo_array_fini (&state->dx); +} + +static cairo_status_t +_draw_glyphs_on_surface (cairo_win32_surface_t *surface, + cairo_win32_font_t *font, + COLORREF color, + int x_offset, + int y_offset, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + cairo_glyph_state_t state; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + int i; + + if (!SaveDC (surface->dc)) + return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC"); + + status = cairo_win32_font_select_font (&font->base, surface->dc); + if (!CAIRO_OK (status)) + goto FAIL1; + + SetTextColor (surface->dc, color); + SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT); + SetBkMode (surface->dc, TRANSPARENT); + + _start_glyphs (&state, font, surface->dc); + + for (i = 0; i < num_glyphs; i++) { + status = _add_glyph (&state, glyphs[i].index, + glyphs[i].x - x_offset, glyphs[i].y - y_offset); + if (!CAIRO_OK (status)) + goto FAIL2; + } + + FAIL2: + _finish_glyphs (&state); + cairo_win32_font_done_font (&font->base); + FAIL1: + RestoreDC (surface->dc, 1); + + return status; +} + +/* Duplicate the green channel of a 4-channel mask in the alpha channel, then + * invert the whole mask. + */ +static void +_compute_argb32_mask_alpha (cairo_win32_surface_t *mask_surface) +{ + cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image; + int i, j; + + for (i = 0; i < image->height; i++) { + uint32_t *p = (uint32_t *) (image->data + i * image->stride); + for (j = 0; j < image->width; j++) { + *p = 0xffffffff ^ (*p | ((*p & 0x0000ff00) << 16)); + p++; + } + } +} + +/* Invert a mask + */ +static void +_invert_argb32_mask (cairo_win32_surface_t *mask_surface) +{ + cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image; + int i, j; + + for (i = 0; i < image->height; i++) { + uint32_t *p = (uint32_t *) (image->data + i * image->stride); + for (j = 0; j < image->width; j++) { + *p = 0xffffffff ^ *p; + p++; + } + } +} + +/* Compute an alpha-mask from a monochrome RGB24 image + */ +static cairo_surface_t * +_compute_a8_mask (cairo_win32_surface_t *mask_surface) +{ + cairo_image_surface_t *image24 = (cairo_image_surface_t *)mask_surface->image; + cairo_image_surface_t *image8; + int i, j; + + image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8, + image24->width, image24->height); + if (!image8) + return NULL; + + for (i = 0; i < image24->height; i++) { + uint32_t *p = (uint32_t *) (image24->data + i * image24->stride); + unsigned char *q = (unsigned char *) (image8->data + i * image8->stride); + + for (j = 0; j < image24->width; j++) { + *q = 255 - ((*p & 0x0000ff00) >> 8); + p++; + q++; + } + } + + return &image8->base; +} + +static cairo_status_t +_cairo_win32_font_show_glyphs (void *abstract_font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *generic_surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + cairo_win32_font_t *font = abstract_font; + cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface; + cairo_status_t status; + + if (width == 0 || height == 0) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_surface_is_win32 (generic_surface) && + surface->format == CAIRO_FORMAT_RGB24 && + operator == CAIRO_OPERATOR_OVER && + pattern->type == CAIRO_PATTERN_SOLID && + _cairo_pattern_is_opaque (pattern)) { + + cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)pattern; + + /* When compositing OVER on a GDI-understood surface, with a + * solid opaque color, we can just call ExtTextOut directly. + */ + COLORREF new_color; + + new_color = RGB (((int)(0xffff * solid_pattern->red)) >> 8, + ((int)(0xffff * solid_pattern->green)) >> 8, + ((int)(0xffff * solid_pattern->blue)) >> 8); + + status = _draw_glyphs_on_surface (surface, font, new_color, + 0, 0, + glyphs, num_glyphs); + + return status; + } else { + /* Otherwise, we need to draw using software fallbacks. We create a mask + * surface by drawing the the glyphs onto a DIB, black-on-white then + * inverting. GDI outputs gamma-corrected images so inverted black-on-white + * is very different from white-on-black. We favor the more common + * case where the final output is dark-on-light. + */ + cairo_win32_surface_t *tmp_surface; + cairo_surface_t *mask_surface; + cairo_surface_pattern_t mask; + RECT r; + + tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height); + if (!tmp_surface) + return CAIRO_STATUS_NO_MEMORY; + + r.left = 0; + r.top = 0; + r.right = width; + r.bottom = height; + FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH)); + + _draw_glyphs_on_surface (tmp_surface, font, RGB (0, 0, 0), + dest_x, dest_y, + glyphs, num_glyphs); + + if (font->quality == CLEARTYPE_QUALITY) { + /* For ClearType, we need a 4-channel mask. If we are compositing on + * a surface with alpha, we need to compute the alpha channel of + * the mask (we just copy the green channel). But for a destination + * surface without alpha the alpha channel of the mask is ignored + */ + + if (surface->format != CAIRO_FORMAT_RGB24) + _compute_argb32_mask_alpha (tmp_surface); + else + _invert_argb32_mask (tmp_surface); + + mask_surface = &tmp_surface->base; + + /* XXX: Hacky, should expose this in cairo_image_surface */ + pixman_image_set_component_alpha (((cairo_image_surface_t *)tmp_surface->image)->pixman_image, TRUE); + + } else { + mask_surface = _compute_a8_mask (tmp_surface); + cairo_surface_destroy (&tmp_surface->base); + if (!mask_surface) + return CAIRO_STATUS_NO_MEMORY; + } + + /* For operator == OVER, no-cleartype, a possible optimization here is to + * draw onto an intermediate ARGB32 surface and alpha-blend that with the + * destination + */ + _cairo_pattern_init_for_surface (&mask, mask_surface); + + status = _cairo_surface_composite (operator, pattern, + &mask.base, + &surface->base, + source_x, source_y, + 0, 0, + dest_x, dest_y, + width, height); + + _cairo_pattern_fini (&mask.base); + + cairo_surface_destroy (mask_surface); + + return status; + } +} + +static cairo_status_t +_cairo_win32_font_glyph_path (void *abstract_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_font_create_glyph (cairo_image_glyph_cache_entry_t *val) +{ + return CAIRO_STATUS_NO_MEMORY; +} + +const cairo_font_backend_t cairo_win32_font_backend = { + _cairo_win32_font_create, + _cairo_win32_font_destroy_font, + _cairo_win32_font_destroy_unscaled_font, + _cairo_win32_font_font_extents, + _cairo_win32_font_text_to_glyphs, + _cairo_win32_font_glyph_extents, + _cairo_win32_font_glyph_bbox, + _cairo_win32_font_show_glyphs, + _cairo_win32_font_glyph_path, + _cairo_win32_font_get_glyph_cache_key, + _cairo_win32_font_create_glyph +}; + +/* implement the platform-specific interface */ + +/** + * cairo_win32_font_create_for_logfontw: + * @logfont: A #LOGFONTW structure specifying the font to use. + * The lfHeight, lfWidth, lfOrientation and lfEscapement + * fields of this structure are ignored; information from + * @scale will be used instead. + * @scale: The scale at which this font will be used. The + * scale is given by multiplying the font matrix (see + * cairo_transform_font()) by the current transformation matrix. + * The translation elements of the resulting matrix are ignored. + * + * Creates a new font for the Win32 font backend based on a + * #LOGFONT. This font can then be used with + * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend + * specific functions like cairo_win32_font_select_font(). + * + * Return value: a newly created #cairo_font_t. Free with + * cairo_font_destroy() when you are done using it. + **/ +cairo_font_t * +cairo_win32_font_create_for_logfontw (LOGFONTW *logfont, + cairo_matrix_t *scale) +{ + cairo_font_scale_t sc; + + cairo_matrix_get_affine (scale, + &sc.matrix[0][0], &sc.matrix[0][1], + &sc.matrix[1][0], &sc.matrix[1][1], + NULL, NULL); + + return _win32_font_create (logfont, &sc); +} + +/** + * cairo_win32_font_select_font: + * @font: A #cairo_font_t from the Win32 font backend. Such an + * object can be created with cairo_win32_font_create_for_logfontw(). + * @hdc: a device context + * + * Selects the font into the given device context and changes the + * map mode and world transformation of the device context to match + * that of the font. This function is intended for use when using + * layout APIs such as Uniscribe to do text layout with the + * Cairo font. After finishing using the device context, you must call + * cairo_win32_font_done_font() to release any resources allocated + * by this function. + * + * See cairo_win32_font_get_scale_factor() for converting logical + * coordinates from the device context to font space. + * + * Normally, calls to SaveDC() and RestoreDC() would be made around + * the use of this function to preserve the original graphics state. + * + * Return value: %CAIRO_STATUS_SUCCESS if the operation succeeded. + * otherwise an error such as %CAIRO_STATUS_NO_MEMORY and + * the device context is unchanged. + **/ +cairo_status_t +cairo_win32_font_select_font (cairo_font_t *font, + HDC hdc) +{ + cairo_status_t status; + HFONT hfont; + HFONT old_hfont = NULL; + int old_mode; + + hfont = _win32_font_get_scaled_font ((cairo_win32_font_t *)font); + if (!hfont) + return CAIRO_STATUS_NO_MEMORY; + + old_hfont = SelectObject (hdc, hfont); + if (!old_hfont) + return _cairo_win32_print_gdi_error ("cairo_win32_font_select_font"); + + old_mode = SetGraphicsMode (hdc, GM_ADVANCED); + if (!old_mode) { + status = _cairo_win32_print_gdi_error ("cairo_win32_font_select_font"); + SelectObject (hdc, old_hfont); + return status; + } + + status = _win32_font_set_world_transform ((cairo_win32_font_t *)font, hdc); + if (!CAIRO_OK (status)) { + SetGraphicsMode (hdc, old_mode); + SelectObject (hdc, old_hfont); + return status; + } + + SetMapMode (hdc, MM_TEXT); + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_win32_font_done_font: + * @font: A #cairo_font_t from the Win32 font backend. + * + * Releases any resources allocated by cairo_win32_font_select_font() + **/ +void +cairo_win32_font_done_font (cairo_font_t *font) +{ +} + +/** + * cairo_win32_font_get_scale_factor: + * @font: a #cairo_font_t from the Win32 font backend + * + * Gets a scale factor between logical coordinates in the coordinate + * space used by cairo_win32_font_select_font() and font space coordinates. + * + * Return value: factor to multiply logical units by to get font space + * coordinates. + **/ +double +cairo_win32_font_get_scale_factor (cairo_font_t *font) +{ + return 1. / ((cairo_win32_font_t *)font)->logical_scale; +} diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h new file mode 100644 index 000000000..71e677ad1 --- /dev/null +++ b/src/cairo-win32-private.h @@ -0,0 +1,87 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor <otaylor@redhat.com> + */ + +#ifndef CAIRO_WIN32_PRIVATE_H +#define CAIRO_WIN32_PRIVATE_H + +/* We depend on various features introduced with Win2k and Win98, + * like AlphaBlend. If it turns out to be a problem, we could + * use GetProcAddress() to look them up. + */ +#define WINVER 0x0500 + +#include <cairo-win32.h> +#include <cairoint.h> + +typedef struct _cairo_win32_surface { + cairo_surface_t base; + + cairo_format_t format; + + HDC dc; + + /* We create off-screen surfaces as DIBs */ + HBITMAP bitmap; + + /* Used to save the initial 1x1 monochrome bitmap for the DC to + * select back into the DC before deleting the DC and our + * bitmap. For Windows XP, this doesn't seem to be necessary + * ... we can just delete the DC and that automatically unselects + * out bitmap. But it's standard practice so apparently is needed + * on some versions of Windows. + */ + HBITMAP saved_dc_bitmap; + + cairo_surface_t *image; + + cairo_rectangle_t clip_rect; + + int set_clip; + HRGN saved_clip; + +} cairo_win32_surface_t; + +cairo_status_t +_cairo_win32_print_gdi_error (const char *context); + +cairo_surface_t * +_cairo_win32_surface_create_dib (cairo_format_t format, + int width, + int height); + +cairo_bool_t +_cairo_surface_is_win32 (cairo_surface_t *surface); + +#endif /* CAIRO_WIN32_PRIVATE_H */ diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c new file mode 100644 index 000000000..dcfe6d044 --- /dev/null +++ b/src/cairo-win32-surface.c @@ -0,0 +1,931 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor <otaylor@redhat.com> + */ + +#include <stdio.h> + +#include "cairo-win32-private.h" + +static const cairo_surface_backend_t cairo_win32_surface_backend; + +/** + * _cairo_win32_print_gdi_error: + * @context: context string to display along with the error + * + * Helper function to dump out a human readable form of the + * current error code. + * + * Return value: A Cairo status code for the error code + **/ +cairo_status_t +_cairo_win32_print_gdi_error (const char *context) +{ + void *lpMsgBuf; + DWORD last_error = GetLastError (); + + if (!FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + last_error, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL)) { + fprintf (stderr, "%s: Unknown GDI error", context); + } else { + fprintf (stderr, "%s: %s", context, (char *)lpMsgBuf); + + LocalFree (lpMsgBuf); + } + + /* We should switch off of last_status, but we'd either return + * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there + * is no CAIRO_STATUS_UNKNOWN_ERROR. + */ + + return CAIRO_STATUS_NO_MEMORY; +} + +void +cairo_set_target_win32 (cairo_t *cr, + HDC hdc) +{ + cairo_surface_t *surface; + + if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE) + return; + + surface = cairo_win32_surface_create (hdc); + if (surface == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + cairo_set_target_surface (cr, surface); + + /* cairo_set_target_surface takes a reference, so we must destroy ours */ + cairo_surface_destroy (surface); +} + +static cairo_status_t +_create_dc_and_bitmap (cairo_win32_surface_t *surface, + HDC original_dc, + cairo_format_t format, + int width, + int height, + char **bits_out, + int *rowstride_out) +{ + cairo_status_t status; + + BITMAPINFO *bitmap_info = NULL; + struct { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[2]; + } bmi_stack; + void *bits; + + int num_palette = 0; /* Quiet GCC */ + int i; + + surface->dc = NULL; + surface->bitmap = NULL; + + switch (format) { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + num_palette = 0; + break; + + case CAIRO_FORMAT_A8: + num_palette = 256; + break; + + case CAIRO_FORMAT_A1: + num_palette = 2; + break; + } + + if (num_palette > 2) { + bitmap_info = malloc (sizeof (BITMAPINFOHEADER) + num_palette * sizeof (RGBQUAD)); + if (!bitmap_info) + return CAIRO_STATUS_NO_MEMORY; + } else { + bitmap_info = (BITMAPINFO *)&bmi_stack; + } + + bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bitmap_info->bmiHeader.biWidth = width; + bitmap_info->bmiHeader.biHeight = - height; /* top-down */ + bitmap_info->bmiHeader.biSizeImage = 0; + bitmap_info->bmiHeader.biXPelsPerMeter = 72. / 0.0254; /* unused here */ + bitmap_info->bmiHeader.biYPelsPerMeter = 72. / 0.0254; /* unused here */ + bitmap_info->bmiHeader.biPlanes = 1; + + switch (format) { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + bitmap_info->bmiHeader.biBitCount = 32; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 0; /* unused */ + bitmap_info->bmiHeader.biClrImportant = 0; + break; + + case CAIRO_FORMAT_A8: + bitmap_info->bmiHeader.biBitCount = 8; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 256; + bitmap_info->bmiHeader.biClrImportant = 0; + + for (i = 0; i < 256; i++) { + bitmap_info->bmiColors[i].rgbBlue = i; + bitmap_info->bmiColors[i].rgbGreen = i; + bitmap_info->bmiColors[i].rgbRed = i; + bitmap_info->bmiColors[i].rgbReserved = 0; + } + + break; + + case CAIRO_FORMAT_A1: + bitmap_info->bmiHeader.biBitCount = 1; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 2; + bitmap_info->bmiHeader.biClrImportant = 0; + + for (i = 0; i < 2; i++) { + bitmap_info->bmiColors[i].rgbBlue = i * 255; + bitmap_info->bmiColors[i].rgbGreen = i * 255; + bitmap_info->bmiColors[i].rgbRed = i * 255; + bitmap_info->bmiColors[i].rgbReserved = 0; + break; + } + } + + surface->dc = CreateCompatibleDC (original_dc); + if (!surface->dc) + goto FAIL; + + surface->bitmap = CreateDIBSection (surface->dc, + bitmap_info, + DIB_RGB_COLORS, + &bits, + NULL, 0); + if (!surface->bitmap) + goto FAIL; + + surface->saved_dc_bitmap = SelectObject (surface->dc, + surface->bitmap); + if (!surface->saved_dc_bitmap) + goto FAIL; + + if (bitmap_info && num_palette > 2) + free (bitmap_info); + + if (bits_out) + *bits_out = bits; + + if (rowstride_out) { + /* Windows bitmaps are padded to 16-bit (word) boundaries */ + switch (format) { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + *rowstride_out = 4 * width; + break; + + case CAIRO_FORMAT_A8: + *rowstride_out = (width + 1) & -2; + break; + + case CAIRO_FORMAT_A1: + *rowstride_out = ((width + 15) & -16) / 8; + break; + } + } + + return CAIRO_STATUS_SUCCESS; + + FAIL: + status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap"); + + if (bitmap_info && num_palette > 2) + free (bitmap_info); + + if (surface->saved_dc_bitmap) { + SelectObject (surface->dc, surface->saved_dc_bitmap); + surface->saved_dc_bitmap = NULL; + } + + if (surface->bitmap) { + DeleteObject (surface->bitmap); + surface->bitmap = NULL; + } + + if (surface->dc) { + DeleteDC (surface->dc); + surface->dc = NULL; + } + + return status; +} + +static cairo_surface_t * +_cairo_win32_surface_create_for_dc (HDC original_dc, + cairo_format_t format, + int drawable, + int width, + int height) +{ + cairo_win32_surface_t *surface; + char *bits; + int rowstride; + + surface = malloc (sizeof (cairo_win32_surface_t)); + if (!surface) + return NULL; + + if (_create_dc_and_bitmap (surface, original_dc, format, + width, height, + &bits, &rowstride) != CAIRO_STATUS_SUCCESS) + goto FAIL; + + surface->image = cairo_image_surface_create_for_data (bits, format, + width, height, rowstride); + if (!surface->image) + goto FAIL; + + surface->format = format; + + surface->clip_rect.x = 0; + surface->clip_rect.y = 0; + surface->clip_rect.width = width; + surface->clip_rect.height = height; + + surface->set_clip = 0; + surface->saved_clip = NULL; + + _cairo_surface_init (&surface->base, &cairo_win32_surface_backend); + + return (cairo_surface_t *)surface; + + FAIL: + if (surface->bitmap) { + SelectObject (surface->dc, surface->saved_dc_bitmap); + DeleteObject (surface->bitmap); + DeleteDC (surface->dc); + } + if (surface) + free (surface); + + return NULL; + +} + +static cairo_surface_t * +_cairo_win32_surface_create_similar (void *abstract_src, + cairo_format_t format, + int drawable, + int width, + int height) +{ + cairo_win32_surface_t *src = abstract_src; + + return _cairo_win32_surface_create_for_dc (src->dc, format, drawable, + width, height); +} + +/** + * _cairo_win32_surface_create_dib: + * @format: format of pixels in the surface to create + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates a device-independent-bitmap surface not associated with + * any particular existing surface or device context. The created + * bitmap will be unititialized. + * + * Return value: the newly created surface, or %NULL if it couldn't + * be created (probably because of lack of memory) + **/ +cairo_surface_t * +_cairo_win32_surface_create_dib (cairo_format_t format, + int width, + int height) +{ + return _cairo_win32_surface_create_for_dc (NULL, format, TRUE, + width, height); +} + +static void +_cairo_win32_surface_destroy (void *abstract_surface) +{ + cairo_win32_surface_t *surface = abstract_surface; + + if (surface->image) + cairo_surface_destroy (surface->image); + + if (surface->saved_clip) + DeleteObject (surface->saved_clip); + + /* If we created the Bitmap and DC, destroy them */ + if (surface->bitmap) { + SelectObject (surface->dc, surface->saved_dc_bitmap); + DeleteObject (surface->bitmap); + DeleteDC (surface->dc); + } + + free (surface); +} + +static double +_cairo_win32_surface_pixels_per_inch (void *abstract_surface) +{ + /* XXX: We should really get this value from somewhere */ + return 96.0; +} + +static cairo_status_t +_cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface, + int x, + int y, + int width, + int height, + cairo_win32_surface_t **local_out) +{ + cairo_win32_surface_t *local; + cairo_status_t status; + + local = + (cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface, + surface->format, + 0, + width, height); + if (!local) + return CAIRO_STATUS_NO_MEMORY; + + if (!BitBlt (local->dc, + 0, 0, + width, height, + surface->dc, + x, y, + SRCCOPY)) + goto FAIL; + + *local_out = local; + + return CAIRO_STATUS_SUCCESS; + + FAIL: + status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_get_subimage"); + + if (local) + cairo_surface_destroy (&local->base); + + return status; +} + +static cairo_status_t +_cairo_win32_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_surface_t *local = NULL; + cairo_status_t status; + + if (surface->image) { + *image_out = (cairo_image_surface_t *)surface->image; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; + } + + status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0, + surface->clip_rect.width, + surface->clip_rect.height, &local); + if (CAIRO_OK (status)) { + cairo_surface_set_filter (&local->base, surface->base.filter); + cairo_surface_set_matrix (&local->base, &surface->base.matrix); + cairo_surface_set_repeat (&local->base, surface->base.repeat); + + *image_out = (cairo_image_surface_t *)local->image; + *image_extra = local; + } + + return status; +} + +static void +_cairo_win32_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_win32_surface_t *local = image_extra; + + if (local) + cairo_surface_destroy ((cairo_surface_t *)local); +} + +static cairo_status_t +_cairo_win32_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_surface_t *local = NULL; + cairo_status_t status; + RECT clip_box; + int x1, y1, x2, y2; + + if (surface->image) { + image_rect->x = 0; + image_rect->y = 0; + image_rect->width = surface->clip_rect.width; + image_rect->height = surface->clip_rect.height; + + *image_out = (cairo_image_surface_t *)surface->image; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; + } + + if (GetClipBox (surface->dc, &clip_box) == ERROR) + return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image"); + + x1 = clip_box.left; + x2 = clip_box.right; + y1 = clip_box.top; + y2 = clip_box.bottom; + + if (interest_rect->x > x1) + x1 = interest_rect->x; + if (interest_rect->y > y1) + y1 = interest_rect->y; + if (interest_rect->x + interest_rect->width < x2) + x2 = interest_rect->x + interest_rect->width; + if (interest_rect->y + interest_rect->height < y2) + y2 = interest_rect->y + interest_rect->height; + + if (x1 >= x2 || y1 >= y2) { + *image_out = NULL; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; + } + + status = _cairo_win32_surface_get_subimage (abstract_surface, + x1, y1, x2 - x1, y2 - y1, + &local); + if (CAIRO_OK (status)) { + *image_out = (cairo_image_surface_t *)local->image; + *image_extra = local; + + image_rect->x = x1; + image_rect->y = y1; + image_rect->width = x2 - x1; + image_rect->height = y2 - y1; + } + + return status; +} + +static void +_cairo_win32_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_surface_t *local = image_extra; + + if (!local) + return; + + if (!BitBlt (surface->dc, + image_rect->x, image_rect->y, + image_rect->width, image_rect->height, + local->dc, + 0, 0, + SRCCOPY)) + _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image"); + + cairo_surface_destroy ((cairo_surface_t *)local); +} + +static cairo_status_t +_cairo_win32_surface_clone_similar (void *surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_composite (cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_pattern_t *mask_pattern, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_win32_surface_t *dst = abstract_dst; + cairo_win32_surface_t *src; + cairo_surface_pattern_t *src_surface_pattern; + int alpha; + int integer_transform; + int itx, ity; + + if (pattern->type != CAIRO_PATTERN_SURFACE || + pattern->extend != CAIRO_EXTEND_NONE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (mask_pattern) { + /* FIXME: When we fully support RENDER style 4-channel + * masks we need to check r/g/b != 1.0. + */ + if (mask_pattern->type != CAIRO_PATTERN_SOLID) + return CAIRO_INT_STATUS_UNSUPPORTED; + + alpha = (int)(0xffff * pattern->alpha * mask_pattern->alpha) >> 8; + } else { + alpha = (int)(0xffff * pattern->alpha) >> 8; + } + + src_surface_pattern = (cairo_surface_pattern_t *)pattern; + src = (cairo_win32_surface_t *)src_surface_pattern->surface; + + if (src->base.backend != dst->base.backend) + return CAIRO_INT_STATUS_UNSUPPORTED; + + integer_transform = _cairo_matrix_is_integer_translation (&pattern->matrix, &itx, &ity); + if (!integer_transform) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (alpha == 255 && + src->format == dst->format && + (operator == CAIRO_OPERATOR_SRC || + (src->format == CAIRO_FORMAT_RGB24 && operator == CAIRO_OPERATOR_OVER))) { + + if (!BitBlt (dst->dc, + dst_x, dst_y, + width, height, + src->dc, + src_x + itx, src_y + ity, + SRCCOPY)) + return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite"); + + return CAIRO_STATUS_SUCCESS; + + } else if (integer_transform && + (src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) && + dst->format == CAIRO_FORMAT_RGB24 && + !src->base.repeat && + operator == CAIRO_OPERATOR_OVER) { + + BLENDFUNCTION blend_function; + + blend_function.BlendOp = AC_SRC_OVER; + blend_function.BlendFlags = 0; + blend_function.SourceConstantAlpha = alpha; + blend_function.AlphaFormat = src->format == CAIRO_FORMAT_ARGB32 ? AC_SRC_ALPHA : 0; + + if (!AlphaBlend (dst->dc, + dst_x, dst_y, + width, height, + src->dc, + src_x + itx, src_y + ity, + width, height, + blend_function)) + return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite"); + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_fill_rectangles (void *abstract_surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_status_t status; + COLORREF new_color; + HBRUSH new_brush; + int i; + + /* If we have a local image, use the fallback code; it will be as fast + * as calling out to GDI. + */ + if (surface->image) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* We could support possibly support more operators for color->alpha = 0xffff. + * for CAIRO_OPERATOR_SRC, alpha doesn't matter since we know the destination + * image doesn't have alpha. (surface->pixman_image is non-NULL for all + * surfaces with alpha.) + */ + if (operator != CAIRO_OPERATOR_SRC) + return CAIRO_INT_STATUS_UNSUPPORTED; + + new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8); + + new_brush = CreateSolidBrush (new_color); + if (!new_brush) + return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles"); + + for (i = 0; i < num_rects; i++) { + RECT rect; + + rect.left = rects[i].x; + rect.top = rects[i].y; + rect.right = rects[i].x + rects[i].width; + rect.bottom = rects[i].y + rects[i].height; + + if (!FillRect (surface->dc, &rect, new_brush)) + goto FAIL; + } + + DeleteObject (new_brush); + + return CAIRO_STATUS_SUCCESS; + + FAIL: + status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles"); + + DeleteObject (new_brush); + + return status; +} + +static cairo_int_status_t +_cairo_win32_surface_composite_trapezoids (cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_dst, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, + cairo_trapezoid_t *traps, + int num_traps) + +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_copy_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_status_t status; + + /* If we are in-memory, then we set the clip on the image surface + * as well as on the underlying GDI surface. + */ + if (surface->image) + _cairo_surface_set_clip_region (surface->image, region); + + /* The semantics we want is that any clip set by Cairo combines + * is intersected with the clip on device context that the + * surface was created for. To implement this, we need to + * save the original clip when first setting a clip on surface. + */ + + if (region == NULL) { + /* Clear any clip set by Cairo, return to the original */ + + if (surface->set_clip) { + if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR) + return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region"); + + if (surface->saved_clip) { + DeleteObject (surface->saved_clip); + surface->saved_clip = NULL; + } + + surface->set_clip = 0; + } + + + return CAIRO_STATUS_SUCCESS; + + } else { + pixman_box16_t *boxes = pixman_region_rects (region); + int num_boxes = pixman_region_num_rects (region); + pixman_box16_t *extents = pixman_region_extents (region); + RGNDATA *data; + size_t data_size; + RECT *rects; + int i; + HRGN gdi_region; + + /* Create a GDI region for the cairo region */ + + data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT); + data = malloc (data_size); + if (!data) + return CAIRO_STATUS_NO_MEMORY; + rects = (RECT *)data->Buffer; + + data->rdh.dwSize = sizeof (RGNDATAHEADER); + data->rdh.iType = RDH_RECTANGLES; + data->rdh.nCount = num_boxes; + data->rdh.nRgnSize = num_boxes * sizeof (RECT); + data->rdh.rcBound.left = extents->x1; + data->rdh.rcBound.top = extents->y1; + data->rdh.rcBound.right = extents->x2; + data->rdh.rcBound.bottom = extents->y2; + + for (i = 0; i < num_boxes; i++) { + rects[i].left = boxes[i].x1; + rects[i].top = boxes[i].y1; + rects[i].right = boxes[i].x2; + rects[i].bottom = boxes[i].y2; + } + + gdi_region = ExtCreateRegion (NULL, data_size, data); + free (data); + + if (!gdi_region) + return CAIRO_STATUS_NO_MEMORY; + + if (surface->set_clip) { + /* Combine the new region with the original clip */ + + if (surface->saved_clip) { + if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR) + goto FAIL; + } + + if (SelectClipRgn (surface->dc, gdi_region) == ERROR) + goto FAIL; + + } else { + /* Save the the current region */ + + surface->saved_clip = CreateRectRgn (0, 0, 0, 0); + if (!surface->saved_clip) { + goto FAIL; } + + /* This function has no error return! */ + if (GetClipRgn (surface->dc, surface->saved_clip) == 0) { /* No clip */ + DeleteObject (surface->saved_clip); + surface->saved_clip = NULL; + } + + if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR) + goto FAIL; + + surface->set_clip = 1; + } + + DeleteObject (gdi_region); + return CAIRO_STATUS_SUCCESS; + + FAIL: + status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region"); + DeleteObject (gdi_region); + return status; + } +} + +static cairo_status_t +_cairo_win32_surface_show_glyphs (cairo_font_t *font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +cairo_surface_t * +cairo_win32_surface_create (HDC hdc) +{ + cairo_win32_surface_t *surface; + RECT rect; + + /* Try to figure out the drawing bounds for the Device context + */ + if (GetClipBox (hdc, &rect) == ERROR) { + _cairo_win32_print_gdi_error ("cairo_win32_surface_create"); + return NULL; + } + + surface = malloc (sizeof (cairo_win32_surface_t)); + if (!surface) + return NULL; + + surface->image = NULL; + surface->format = CAIRO_FORMAT_RGB24; + + surface->dc = hdc; + surface->bitmap = NULL; + + surface->clip_rect.x = rect.left; + surface->clip_rect.y = rect.top; + surface->clip_rect.width = rect.right - rect.left; + surface->clip_rect.height = rect.bottom - rect.top; + + surface->set_clip = 0; + surface->saved_clip = NULL; + + _cairo_surface_init (&surface->base, &cairo_win32_surface_backend); + + return (cairo_surface_t *)surface; +} + +/** + * _cairo_surface_is_win32: + * @surface: a #cairo_surface_t + * + * Checks if a surface is an #cairo_win32_surface_t + * + * Return value: True if the surface is an win32 surface + **/ +int +_cairo_surface_is_win32 (cairo_surface_t *surface) +{ + return surface->backend == &cairo_win32_surface_backend; +} + +static const cairo_surface_backend_t cairo_win32_surface_backend = { + _cairo_win32_surface_create_similar, + _cairo_win32_surface_destroy, + _cairo_win32_surface_pixels_per_inch, + _cairo_win32_surface_acquire_source_image, + _cairo_win32_surface_release_source_image, + _cairo_win32_surface_acquire_dest_image, + _cairo_win32_surface_release_dest_image, + _cairo_win32_surface_clone_similar, + _cairo_win32_surface_composite, + _cairo_win32_surface_fill_rectangles, + _cairo_win32_surface_composite_trapezoids, + _cairo_win32_surface_copy_page, + _cairo_win32_surface_show_page, + _cairo_win32_surface_set_clip_region, + _cairo_win32_surface_show_glyphs +}; diff --git a/src/cairo-win32.h b/src/cairo-win32.h new file mode 100644 index 000000000..fab497aa4 --- /dev/null +++ b/src/cairo-win32.h @@ -0,0 +1,71 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor <otaylor@redhat.com> + */ + +#ifndef _CAIRO_WIN32_H_ + +#include <cairo.h> + +#ifdef CAIRO_HAS_WIN32_SURFACE + +#include <windows.h> + +CAIRO_BEGIN_DECLS + +void +cairo_set_target_win32 (cairo_t *cr, + HDC hdc); + +cairo_surface_t * +cairo_win32_surface_create (HDC hdc); + +cairo_font_t * +cairo_win32_font_create_for_logfontw (LOGFONTW *logfont, + cairo_matrix_t *scale); + +cairo_status_t +cairo_win32_font_select_font (cairo_font_t *font, + HDC hdc); + +void +cairo_win32_font_done_font (cairo_font_t *font); + +double +cairo_win32_font_get_scale_factor (cairo_font_t *font); + +#endif /* CAIRO_HAS_WIN32_SURFACE */ + +CAIRO_END_DECLS + +#endif /* _CAIRO_WIN32_H_ */ diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index 758cf26de..0694b77a2 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -31,10 +31,11 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" +#include "cairo-xcb.h" cairo_surface_t * cairo_xcb_surface_create (XCBConnection *dpy, @@ -327,14 +328,17 @@ bytes_per_line(XCBConnection *c, int width, int bpp) return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3; } -static cairo_image_surface_t * -_cairo_xcb_surface_get_image (void *abstract_surface) +static cairo_status_t +_get_image_surface (cairo_xcb_surface_t *surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect) { - cairo_xcb_surface_t *surface = abstract_surface; cairo_image_surface_t *image; XCBGetGeometryRep *geomrep; XCBGetImageRep *imagerep; int bpp; + int x1, y1, x2, y2; geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0); if(!geomrep) @@ -344,11 +348,39 @@ _cairo_xcb_surface_get_image (void *abstract_surface) surface->height = geomrep->height; free(geomrep); + x1 = 0; + y1 = 0; + x2 = surface->width; + y2 = surface->height; + + if (interest_rect) { + if (interest_rect->x > x1) + x1 = interest_rect->x; + if (interest_rect->y > y1) + y1 = interest_rect->y; + if (interest_rect->x + interest_rect->width < x2) + x2 = interest_rect->x + interest_rect->width; + if (interest_rect->y + interest_rect->height < y2) + y2 = interest_rect->y + interest_rect->height; + + if (x1 >= x2 || y1 >= y2) { + *image_out = NULL; + return CAIRO_STATUS_SUCCESS; + } + } + + if (image_rect) { + image_rect->x = x1; + image_rect->y = y1; + image_rect->width = x2 - x1; + image_rect->height = y2 - y1; + } + imagerep = XCBGetImageReply(surface->dpy, XCBGetImage(surface->dpy, ZPixmap, surface->drawable, - 0, 0, - surface->width, surface->height, + x1, y1, + x2 - x1, y2 - y1, AllPlanes), 0); if(!imagerep) return 0; @@ -368,15 +400,15 @@ _cairo_xcb_surface_get_image (void *abstract_surface) image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep), &masks, - surface->width, - surface->height, + x2 - x1, + y2 - y1, bytes_per_line(surface->dpy, surface->width, bpp)); } else { image = (cairo_image_surface_t *) cairo_image_surface_create_for_data (XCBGetImageData(imagerep), surface->format, - surface->width, - surface->height, + x2 - x1, + y2 - y1, bytes_per_line(surface->dpy, surface->width, bpp)); } @@ -388,7 +420,8 @@ _cairo_xcb_surface_get_image (void *abstract_surface) _cairo_image_surface_set_repeat (image, surface->base.repeat); _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - return image; + *image_out = image; + return CAIRO_STATUS_SUCCESS; } static void @@ -402,10 +435,11 @@ _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface) } static cairo_status_t -_cairo_xcb_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +_draw_image_surface (cairo_xcb_surface_t *surface, + cairo_image_surface_t *image, + int dst_x, + int dst_y) { - cairo_xcb_surface_t *surface = abstract_surface; int bpp, data_len; _cairo_xcb_surface_ensure_gc (surface); @@ -414,7 +448,7 @@ _cairo_xcb_surface_set_image (void *abstract_surface, XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc, image->width, image->height, - /* dst_x */ 0, /* dst_y */ 0, + dst_x, dst_y, /* left_pad */ 0, image->depth, data_len, image->data); @@ -422,9 +456,107 @@ _cairo_xcb_surface_set_image (void *abstract_surface, } static cairo_status_t -_cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) +_cairo_xcb_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; + + status = _get_image_surface (surface, NULL, &image, NULL); + if (status == CAIRO_STATUS_SUCCESS) { + cairo_surface_set_filter (&image->base, surface->base.filter); + cairo_surface_set_matrix (&image->base, &surface->base.matrix); + cairo_surface_set_repeat (&image->base, surface->base.repeat); + + *image_out = image; + } + + return status; +} + +static void +_cairo_xcb_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); +} + +static cairo_status_t +_cairo_xcb_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect_out, + void **image_extra) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; + + status = _get_image_surface (surface, interest_rect, &image, image_rect_out); + if (status == CAIRO_STATUS_SUCCESS) + *image_out = image; + + return status; +} + +static void +_cairo_xcb_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + cairo_xcb_surface_t *surface = abstract_surface; + + /* ignore errors */ + _draw_image_surface (surface, image, image_rect->x, image_rect->y); + + cairo_surface_destroy (&image->base); +} + +static cairo_status_t +_cairo_xcb_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { cairo_xcb_surface_t *surface = abstract_surface; + cairo_xcb_surface_t *clone; + + if (src->backend == surface->base.backend ) { + cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src; + + if (xcb_src->dpy == surface->dpy) { + *clone_out = src; + cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; + } + } else if (_cairo_surface_is_image (src)) { + cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; + + clone = (cairo_xcb_surface_t *) + _cairo_xcb_surface_create_similar (surface, image_src->format, 0, + image_src->width, image_src->height); + if (clone == NULL) + return CAIRO_STATUS_NO_MEMORY; + + _draw_image_surface (clone, image_src, 0, 0); + + *clone_out = &clone->base; + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface, + cairo_matrix_t *matrix) +{ XCBRenderTRANSFORM xtransform; if (!surface->picture.xid) @@ -442,27 +574,42 @@ _cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) xtransform.matrix32 = 0; xtransform.matrix33 = _cairo_fixed_from_double (1); - if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) + if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) { - XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform); - } else { - /* XXX: Need support here if using an old RENDER without support - for SetPictureTransform */ + static const XCBRenderTRANSFORM identity = { + 1 << 16, 0x00000, 0x00000, + 0x00000, 1 << 16, 0x00000, + 0x00000, 0x00000, 1 << 16 + }; + + if (memcmp (&xtransform, &identity, sizeof (XCBRenderTRANSFORM)) == 0) + return CAIRO_STATUS_SUCCESS; + + return CAIRO_INT_STATUS_UNSUPPORTED; } + + XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform); return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface, + cairo_filter_t filter) { - cairo_xcb_surface_t *surface = abstract_surface; char *render_filter; - if (!(surface->picture.xid - && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface))) + if (!surface->picture.xid) return CAIRO_STATUS_SUCCESS; - + + if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) + { + if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) + return CAIRO_STATUS_SUCCESS; + + return CAIRO_INT_STATUS_UNSUPPORTED; + } + switch (filter) { case CAIRO_FILTER_FAST: render_filter = "fast"; @@ -491,10 +638,8 @@ _cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter) } static cairo_status_t -_cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat) +_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat) { - cairo_xcb_surface_t *surface = abstract_surface; - CARD32 mask = XCBRenderCPRepeat; CARD32 pa[] = { repeat }; @@ -506,33 +651,32 @@ _cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat) return CAIRO_STATUS_SUCCESS; } -static cairo_xcb_surface_t * -_cairo_xcb_surface_clone_similar (cairo_surface_t *src, - cairo_xcb_surface_t *template, - cairo_format_t format, - int depth) +static cairo_int_status_t +_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface, + cairo_surface_attributes_t *attributes) { - cairo_xcb_surface_t *clone; - cairo_image_surface_t *src_image; - - src_image = _cairo_surface_get_image (src); - - clone = (cairo_xcb_surface_t *) - _cairo_xcb_surface_create_similar (template, format, 0, - src_image->width, - src_image->height); - if (clone == NULL) - return NULL; - - _cairo_xcb_surface_set_filter (clone, cairo_surface_get_filter(src)); - - _cairo_xcb_surface_set_image (clone, src_image); + cairo_int_status_t status; - _cairo_xcb_surface_set_matrix (clone, &(src_image->base.matrix)); + status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix); + if (status) + return status; + + switch (attributes->extend) { + case CAIRO_EXTEND_NONE: + _cairo_xcb_surface_set_repeat (surface, 0); + break; + case CAIRO_EXTEND_REPEAT: + _cairo_xcb_surface_set_repeat (surface, 1); + break; + case CAIRO_EXTEND_REFLECT: + return CAIRO_INT_STATUS_UNSUPPORTED; + } - cairo_surface_destroy (&src_image->base); + status = _cairo_xcb_surface_set_filter (surface, attributes->filter); + if (status) + return status; - return clone; + return CAIRO_STATUS_SUCCESS; } static int @@ -574,65 +718,80 @@ _render_operator (cairo_operator_t operator) static cairo_int_status_t _cairo_xcb_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, - void *abstract_dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height) + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) { - cairo_xcb_surface_t *dst = abstract_dst; - cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src; - cairo_xcb_surface_t *mask = (cairo_xcb_surface_t *) generic_mask; - cairo_xcb_surface_t *src_clone = NULL; - cairo_xcb_surface_t *mask_clone = NULL; - XCBRenderPICTURE maskpict = { 0 }; - + cairo_surface_attributes_t src_attr, mask_attr; + cairo_xcb_surface_t *dst = abstract_dst; + cairo_xcb_surface_t *src; + cairo_xcb_surface_t *mask; + cairo_int_status_t status; if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; - if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { - src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst, - CAIRO_FORMAT_ARGB32, 32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - src = src_clone; - } - if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) { - mask_clone = _cairo_xcb_surface_clone_similar (generic_mask, dst, - CAIRO_FORMAT_A8, 8); - if (!mask_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - mask = mask_clone; + status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern, + &dst->base, + src_x, src_y, + mask_x, mask_y, + width, height, + (cairo_surface_t **) &src, + (cairo_surface_t **) &mask, + &src_attr, &mask_attr); + if (status) + return status; + + status = _cairo_xcb_surface_set_attributes (src, &src_attr); + if (CAIRO_OK (status)) + { + if (mask) + { + status = _cairo_xcb_surface_set_attributes (mask, &mask_attr); + if (CAIRO_OK (status)) + XCBRenderComposite (dst->dpy, + _render_operator (operator), + src->picture, + mask->picture, + dst->picture, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + mask_x + mask_attr.x_offset, + mask_y + mask_attr.y_offset, + dst_x, dst_y, + width, height); + } + else + { + static XCBRenderPICTURE maskpict = { 0 }; + + XCBRenderComposite (dst->dpy, + _render_operator (operator), + src->picture, + maskpict, + dst->picture, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + } } - if(mask) - maskpict = mask->picture; - - XCBRenderComposite (dst->dpy, - _render_operator (operator), - src->picture, - maskpict, - dst->picture, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); - - /* XXX: This is messed up. If I can xcb_surface_create, then I - should be able to xcb_surface_destroy. */ - if (src_clone) - cairo_surface_destroy (&src_clone->base); - if (mask_clone) - cairo_surface_destroy (&mask_clone->base); + if (mask) + _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr); + + _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr); - return CAIRO_STATUS_SUCCESS; + return status; } static cairo_int_status_t @@ -664,42 +823,60 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface, static cairo_int_status_t _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, - void *abstract_dst, - int xSrc, - int ySrc, - cairo_trapezoid_t *traps, - int num_traps) + cairo_pattern_t *pattern, + void *abstract_dst, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, + cairo_trapezoid_t *traps, + int num_traps) { - cairo_xcb_surface_t *dst = abstract_dst; - cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src; - cairo_xcb_surface_t *src_clone = NULL; + cairo_surface_attributes_t attributes; + cairo_xcb_surface_t *dst = abstract_dst; + cairo_xcb_surface_t *src; + cairo_int_status_t status; + int render_reference_x, render_reference_y; + int render_src_x, render_src_y; if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; - - if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { - src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst, - CAIRO_FORMAT_ARGB32, 32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - src = src_clone; + + status = _cairo_pattern_acquire_surface (pattern, &dst->base, + src_x, src_y, width, height, + (cairo_surface_t **) &src, + &attributes); + if (status) + return status; + + if (traps[0].left.p1.y < traps[0].left.p2.y) { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y); + } else { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y); } - /* XXX: The XCBRenderTRAP cast is evil and needs to go away somehow. */ - /* XXX: format_from_cairo is slow. should cache something. */ - XCBRenderTrapezoids (dst->dpy, - _render_operator (operator), - src->picture, dst->picture, - format_from_cairo (dst->dpy, CAIRO_FORMAT_A8), - xSrc, ySrc, num_traps, (XCBRenderTRAP *) traps); - - /* XXX: This is messed up. If I can xcb_surface_create, then I - should be able to xcb_surface_destroy. */ - if (src_clone) - cairo_surface_destroy (&src_clone->base); + render_src_x = src_x + render_reference_x - dst_x; + render_src_y = src_y + render_reference_y - dst_y; - return CAIRO_STATUS_SUCCESS; + /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ + /* XXX: format_from_cairo is slow. should cache something. */ + status = _cairo_xcb_surface_set_attributes (src, &attributes); + if (CAIRO_OK (status)) + XCBRenderTrapezoids (dst->dpy, + _render_operator (operator), + src->picture, dst->picture, + format_from_cairo (dst->dpy, CAIRO_FORMAT_A8), + render_src_x + attributes.x_offset, + render_src_y + attributes.y_offset, + num_traps, (XCBRenderTRAP *) traps); + + _cairo_pattern_release_surface (&dst->base, &src->base, &attributes); + + return status; } static cairo_int_status_t @@ -722,30 +899,21 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface, return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_int_status_t -_cairo_xcb_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *extents) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - static const cairo_surface_backend_t cairo_xcb_surface_backend = { _cairo_xcb_surface_create_similar, _cairo_xcb_surface_destroy, _cairo_xcb_surface_pixels_per_inch, - _cairo_xcb_surface_get_image, - _cairo_xcb_surface_set_image, - _cairo_xcb_surface_set_matrix, - _cairo_xcb_surface_set_filter, - _cairo_xcb_surface_set_repeat, + _cairo_xcb_surface_acquire_source_image, + _cairo_xcb_surface_release_source_image, + _cairo_xcb_surface_acquire_dest_image, + _cairo_xcb_surface_release_dest_image, + _cairo_xcb_surface_clone_similar, _cairo_xcb_surface_composite, _cairo_xcb_surface_fill_rectangles, _cairo_xcb_surface_composite_trapezoids, _cairo_xcb_surface_copy_page, _cairo_xcb_surface_show_page, _cairo_xcb_surface_set_clip_region, - _cairo_xcb_surface_create_pattern, NULL /* show_glyphs */ }; diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h index 27ebad523..a5c65f441 100644 --- a/src/cairo-xcb.h +++ b/src/cairo-xcb.h @@ -31,18 +31,21 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ -#include <cairo.h> - #ifndef CAIRO_XCB_H #define CAIRO_XCB_H + +#include <cairo.h> + #ifdef CAIRO_HAS_XCB_SURFACE #include <X11/XCB/xcb.h> #include <X11/XCB/render.h> +CAIRO_BEGIN_DECLS + void cairo_set_target_xcb (cairo_t *cr, XCBConnection *dpy, @@ -50,5 +53,7 @@ cairo_set_target_xcb (cairo_t *cr, XCBVISUALTYPE *visual, cairo_format_t format); +CAIRO_END_DECLS + #endif /* CAIRO_HAS_XCB_SURFACE */ #endif /* CAIRO_XCB_H */ diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index d9d74f583..3eaef57e5 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -31,12 +31,28 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" #include "cairo-xlib.h" +/** + * cairo_set_target_drawable: + * @cr: a #cairo_t + * @dpy: an X display + * @drawable: a window or pixmap on the default screen of @dpy + * + * Directs output for a #cairo_t to an Xlib drawable. @drawable must + * be a Window or Pixmap on the default screen of @dpy using the + * default colormap and visual. Using this function is slow because + * the function must retrieve information about @drawable from the X + * server. + + * The combination of cairo_xlib_surface_create() and + * cairo_set_target_surface() is somewhat more flexible, although + * it still is slow. + **/ void cairo_set_target_drawable (cairo_t *cr, Display *dpy, @@ -87,6 +103,8 @@ typedef struct _cairo_xlib_surface { #define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) +#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) + #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1) #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1) @@ -141,18 +159,13 @@ _cairo_xlib_surface_create_similar (void *abstract_src, Pixmap pix; cairo_xlib_surface_t *surface; - /* XXX: There's a pretty lame heuristic here. This assumes that - * all non-Render X servers do not support depth-32 pixmaps, (and - * that they do support depths 1, 8, and 24). Obviously, it would - * be much better to check the depths that are actually - * supported. */ - if (!dpy - || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src) - && format == CAIRO_FORMAT_ARGB32)) - { - return NULL; + /* As a good first approximation, if the display doesn't have COMPOSITE, + * we're better off using image surfaces for all temporary operations + */ + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE(src)) { + return cairo_image_surface_create (format, width, height); } - + scr = DefaultScreen (dpy); pix = XCreatePixmap (dpy, DefaultRootWindow (dpy), @@ -196,15 +209,17 @@ _cairo_xlib_surface_pixels_per_inch (void *abstract_surface) return 96.0; } -static cairo_image_surface_t * -_cairo_xlib_surface_get_image (void *abstract_surface) +static cairo_status_t +_get_image_surface (cairo_xlib_surface_t *surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect) { - cairo_xlib_surface_t *surface = abstract_surface; cairo_image_surface_t *image; - XImage *ximage; Window root_ignore; int x_ignore, y_ignore, bwidth_ignore, depth_ignore; + int x1, y1, x2, y2; XGetGeometry (surface->dpy, surface->drawable, @@ -212,11 +227,39 @@ _cairo_xlib_surface_get_image (void *abstract_surface) &surface->width, &surface->height, &bwidth_ignore, &depth_ignore); + x1 = 0; + y1 = 0; + x2 = surface->width; + y2 = surface->height; + + if (interest_rect) { + if (interest_rect->x > x1) + x1 = interest_rect->x; + if (interest_rect->y > y1) + y1 = interest_rect->y; + if (interest_rect->x + interest_rect->width < x2) + x2 = interest_rect->x + interest_rect->width; + if (interest_rect->y + interest_rect->height < y2) + y2 = interest_rect->y + interest_rect->height; + + if (x1 >= x2 || y1 >= y2) { + *image_out = NULL; + return CAIRO_STATUS_SUCCESS; + } + } + + if (image_rect) { + image_rect->x = x1; + image_rect->y = y1; + image_rect->width = x2 - x1; + image_rect->height = y2 - y1; + } + /* XXX: This should try to use the XShm extension if availible */ ximage = XGetImage (surface->dpy, surface->drawable, - 0, 0, - surface->width, surface->height, + x1, y1, + x2 - x1, y2 - y1, AllPlanes, ZPixmap); if (surface->visual) { @@ -253,7 +296,8 @@ _cairo_xlib_surface_get_image (void *abstract_surface) _cairo_image_surface_set_repeat (image, surface->base.repeat); _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - return image; + *image_out = image; + return CAIRO_STATUS_SUCCESS; } static void @@ -266,10 +310,11 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface) } static cairo_status_t -_cairo_xlib_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +_draw_image_surface (cairo_xlib_surface_t *surface, + cairo_image_surface_t *image, + int dst_x, + int dst_y) { - cairo_xlib_surface_t *surface = abstract_surface; XImage *ximage; unsigned bitmap_pad; @@ -295,9 +340,8 @@ _cairo_xlib_surface_set_image (void *abstract_surface, _cairo_xlib_surface_ensure_gc (surface); XPutImage(surface->dpy, surface->drawable, surface->gc, - ximage, 0, 0, 0, 0, - surface->width, - surface->height); + ximage, 0, 0, dst_x, dst_y, + image->width, image->height); /* Foolish XDestroyImage thinks it can free my data, but I won't stand for it. */ @@ -305,17 +349,116 @@ _cairo_xlib_surface_set_image (void *abstract_surface, XDestroyImage (ximage); return CAIRO_STATUS_SUCCESS; + +} + +static cairo_status_t +_cairo_xlib_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_xlib_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; + + status = _get_image_surface (surface, NULL, &image, NULL); + if (status == CAIRO_STATUS_SUCCESS) { + cairo_surface_set_filter (&image->base, surface->base.filter); + cairo_surface_set_matrix (&image->base, &surface->base.matrix); + cairo_surface_set_repeat (&image->base, surface->base.repeat); + + *image_out = image; + } + + return status; +} + +static void +_cairo_xlib_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); +} + +static cairo_status_t +_cairo_xlib_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect_out, + void **image_extra) +{ + cairo_xlib_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; + + status = _get_image_surface (surface, interest_rect, &image, image_rect_out); + if (status == CAIRO_STATUS_SUCCESS) + *image_out = image; + + return status; +} + +static void +_cairo_xlib_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + cairo_xlib_surface_t *surface = abstract_surface; + + /* ignore errors */ + _draw_image_surface (surface, image, image_rect->x, image_rect->y); + + cairo_surface_destroy (&image->base); } static cairo_status_t -_cairo_xlib_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) +_cairo_xlib_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { cairo_xlib_surface_t *surface = abstract_surface; + cairo_xlib_surface_t *clone; + + if (src->backend == surface->base.backend ) { + cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src; + + if (xlib_src->dpy == surface->dpy) { + *clone_out = src; + cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; + } + } else if (_cairo_surface_is_image (src)) { + cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; + + clone = (cairo_xlib_surface_t *) + _cairo_xlib_surface_create_similar (surface, image_src->format, 0, + image_src->width, image_src->height); + if (clone == NULL) + return CAIRO_STATUS_NO_MEMORY; + + _draw_image_surface (clone, image_src, 0, 0); + + *clone_out = &clone->base; + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface, + cairo_matrix_t *matrix) +{ XTransform xtransform; if (!surface->picture) return CAIRO_STATUS_SUCCESS; - + xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); @@ -328,26 +471,41 @@ _cairo_xlib_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) xtransform.matrix[2][1] = 0; xtransform.matrix[2][2] = _cairo_fixed_from_double (1); - if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) + if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) { - XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform); - } else { - /* XXX: Need support here if using an old RENDER without support - for SetPictureTransform */ + static const XTransform identity = { { + { 1 << 16, 0x00000, 0x00000 }, + { 0x00000, 1 << 16, 0x00000 }, + { 0x00000, 0x00000, 1 << 16 }, + } }; + + if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0) + return CAIRO_STATUS_SUCCESS; + + return CAIRO_INT_STATUS_UNSUPPORTED; } + XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform); + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +_cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface, + cairo_filter_t filter) { - cairo_xlib_surface_t *surface = abstract_surface; char *render_filter; - if (!(surface->picture - && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface))) + if (!surface->picture) return CAIRO_STATUS_SUCCESS; + + if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) + { + if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) + return CAIRO_STATUS_SUCCESS; + + return CAIRO_INT_STATUS_UNSUPPORTED; + } switch (filter) { case CAIRO_FILTER_FAST: @@ -377,11 +535,10 @@ _cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter) } static cairo_status_t -_cairo_xlib_surface_set_repeat (void *abstract_surface, int repeat) +_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat) { - cairo_xlib_surface_t *surface = abstract_surface; - unsigned long mask; XRenderPictureAttributes pa; + unsigned long mask; if (!surface->picture) return CAIRO_STATUS_SUCCESS; @@ -394,33 +551,32 @@ _cairo_xlib_surface_set_repeat (void *abstract_surface, int repeat) return CAIRO_STATUS_SUCCESS; } -static cairo_xlib_surface_t * -_cairo_xlib_surface_clone_similar (cairo_surface_t *src, - cairo_xlib_surface_t *template, - cairo_format_t format, - int depth) +static cairo_int_status_t +_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, + cairo_surface_attributes_t *attributes) { - cairo_xlib_surface_t *clone; - cairo_image_surface_t *src_image; + cairo_int_status_t status; - src_image = _cairo_surface_get_image (src); - - clone = (cairo_xlib_surface_t *) - _cairo_xlib_surface_create_similar (template, format, 0, - src_image->width, - src_image->height); - if (clone == NULL) - return NULL; - - _cairo_xlib_surface_set_filter (clone, cairo_surface_get_filter(src)); - - _cairo_xlib_surface_set_image (clone, src_image); - - _cairo_xlib_surface_set_matrix (clone, &(src_image->base.matrix)); + status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix); + if (status) + return status; + + switch (attributes->extend) { + case CAIRO_EXTEND_NONE: + _cairo_xlib_surface_set_repeat (surface, 0); + break; + case CAIRO_EXTEND_REPEAT: + _cairo_xlib_surface_set_repeat (surface, 1); + break; + case CAIRO_EXTEND_REFLECT: + return CAIRO_INT_STATUS_UNSUPPORTED; + } - cairo_surface_destroy (&src_image->base); + status = _cairo_xlib_surface_set_filter (surface, attributes->filter); + if (status) + return status; - return clone; + return CAIRO_STATUS_SUCCESS; } static int @@ -462,8 +618,8 @@ _render_operator (cairo_operator_t operator) static cairo_int_status_t _cairo_xlib_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, void *abstract_dst, int src_x, int src_y, @@ -474,73 +630,66 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, unsigned int width, unsigned int height) { - cairo_xlib_surface_t *dst = abstract_dst; - cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) generic_src; - cairo_xlib_surface_t *mask = (cairo_xlib_surface_t *) generic_mask; - cairo_xlib_surface_t *src_clone = NULL; - cairo_xlib_surface_t *mask_clone = NULL; - XGCValues gc_values; - int src_x_off, src_y_off, dst_x_off, dst_y_off; + cairo_surface_attributes_t src_attr, mask_attr; + cairo_xlib_surface_t *dst = abstract_dst; + cairo_xlib_surface_t *src; + cairo_xlib_surface_t *mask; + cairo_int_status_t status; if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; - if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { - src_clone = _cairo_xlib_surface_clone_similar (generic_src, dst, - CAIRO_FORMAT_ARGB32, 32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - src = src_clone; - } - if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) { - mask_clone = _cairo_xlib_surface_clone_similar (generic_mask, dst, - CAIRO_FORMAT_A8, 8); - if (!mask_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - mask = mask_clone; - } - - if (operator == CAIRO_OPERATOR_SRC - && !mask - && _cairo_matrix_is_integer_translation(&(src->base.matrix), - &src_x_off, &src_y_off) - && _cairo_matrix_is_integer_translation(&(dst->base.matrix), - &dst_x_off, &dst_y_off)) { - /* Fast path for copying "raw" areas. */ - _cairo_xlib_surface_ensure_gc (dst); - XGetGCValues(dst->dpy, dst->gc, GCGraphicsExposures, &gc_values); - XSetGraphicsExposures(dst->dpy, dst->gc, False); - XCopyArea(dst->dpy, - src->drawable, - dst->drawable, - dst->gc, - src_x + src_x_off, - src_y + src_y_off, - width, height, - dst_x + dst_x_off, - dst_y + dst_y_off); - XSetGraphicsExposures(dst->dpy, dst->gc, gc_values.graphics_exposures); - - } else { - XRenderComposite (dst->dpy, - _render_operator (operator), - src->picture, - mask ? mask->picture : 0, - dst->picture, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); + status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern, + &dst->base, + src_x, src_y, + mask_x, mask_y, + width, height, + (cairo_surface_t **) &src, + (cairo_surface_t **) &mask, + &src_attr, &mask_attr); + if (status) + return status; + + status = _cairo_xlib_surface_set_attributes (src, &src_attr); + if (CAIRO_OK (status)) + { + if (mask) + { + status = _cairo_xlib_surface_set_attributes (mask, &mask_attr); + if (CAIRO_OK (status)) + XRenderComposite (dst->dpy, + _render_operator (operator), + src->picture, + mask->picture, + dst->picture, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + mask_x + mask_attr.x_offset, + mask_y + mask_attr.y_offset, + dst_x, dst_y, + width, height); + } + else + { + XRenderComposite (dst->dpy, + _render_operator (operator), + src->picture, + 0, + dst->picture, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + } } - /* XXX: This is messed up. If I can xlib_surface_create, then I - should be able to xlib_surface_destroy. */ - if (src_clone) - cairo_surface_destroy (&src_clone->base); - if (mask_clone) - cairo_surface_destroy (&mask_clone->base); + if (mask) + _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr); + + _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr); - return CAIRO_STATUS_SUCCESS; + return status; } static cairo_int_status_t @@ -572,41 +721,59 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, static cairo_int_status_t _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, + cairo_pattern_t *pattern, void *abstract_dst, - int xSrc, - int ySrc, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps) { - cairo_xlib_surface_t *dst = abstract_dst; - cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) generic_src; - cairo_xlib_surface_t *src_clone = NULL; + cairo_surface_attributes_t attributes; + cairo_xlib_surface_t *dst = abstract_dst; + cairo_xlib_surface_t *src; + cairo_int_status_t status; + int render_reference_x, render_reference_y; + int render_src_x, render_src_y; if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; - - if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { - src_clone = _cairo_xlib_surface_clone_similar (generic_src, dst, - CAIRO_FORMAT_ARGB32, 32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - src = src_clone; + + status = _cairo_pattern_acquire_surface (pattern, &dst->base, + src_x, src_y, width, height, + (cairo_surface_t **) &src, + &attributes); + if (status) + return status; + + if (traps[0].left.p1.y < traps[0].left.p2.y) { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y); + } else { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y); } - /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ - XRenderCompositeTrapezoids (dst->dpy, - _render_operator (operator), - src->picture, dst->picture, - XRenderFindStandardFormat (dst->dpy, PictStandardA8), - xSrc, ySrc, (XTrapezoid *) traps, num_traps); + render_src_x = src_x + render_reference_x - dst_x; + render_src_y = src_y + render_reference_y - dst_y; - /* XXX: This is messed up. If I can xlib_surface_create, then I - should be able to xlib_surface_destroy. */ - if (src_clone) - cairo_surface_destroy (&src_clone->base); + /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ + status = _cairo_xlib_surface_set_attributes (src, &attributes); + if (CAIRO_OK (status)) + XRenderCompositeTrapezoids (dst->dpy, + _render_operator (operator), + src->picture, dst->picture, + XRenderFindStandardFormat (dst->dpy, PictStandardA8), + render_src_x + attributes.x_offset, + render_src_y + attributes.y_offset, + (XTrapezoid *) traps, num_traps); + + _cairo_pattern_release_surface (&dst->base, &src->base, &attributes); - return CAIRO_STATUS_SUCCESS; + return status; } static cairo_int_status_t @@ -685,22 +852,17 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_xlib_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *extents) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - static cairo_status_t -_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_xlib_surface_show_glyphs (cairo_font_t *font, cairo_operator_t operator, - cairo_surface_t *source, + cairo_pattern_t *pattern, void *abstract_surface, int source_x, int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs); @@ -708,18 +870,17 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, _cairo_xlib_surface_destroy, _cairo_xlib_surface_pixels_per_inch, - _cairo_xlib_surface_get_image, - _cairo_xlib_surface_set_image, - _cairo_xlib_surface_set_matrix, - _cairo_xlib_surface_set_filter, - _cairo_xlib_surface_set_repeat, + _cairo_xlib_surface_acquire_source_image, + _cairo_xlib_surface_release_source_image, + _cairo_xlib_surface_acquire_dest_image, + _cairo_xlib_surface_release_dest_image, + _cairo_xlib_surface_clone_similar, _cairo_xlib_surface_composite, _cairo_xlib_surface_fill_rectangles, _cairo_xlib_surface_composite_trapezoids, _cairo_xlib_surface_copy_page, _cairo_xlib_surface_show_page, _cairo_xlib_surface_set_clip_region, - _cairo_xlib_surface_create_pattern, _cairo_xlib_surface_show_glyphs }; @@ -827,6 +988,7 @@ typedef struct { cairo_glyph_cache_key_t key; Glyph glyph; XGlyphInfo info; + int refcount; } glyphset_cache_entry_t; static Glyph @@ -854,17 +1016,18 @@ _xlib_glyphset_cache_create_entry (void *cache, _cairo_lock_global_image_glyph_cache (); im_cache = _cairo_get_global_image_glyph_cache (); - if (g == NULL || v == NULL ||g == NULL || im_cache == NULL) { + if (g == NULL || v == NULL || im_cache == NULL) { _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_NO_MEMORY; } - status = _cairo_cache_lookup (im_cache, key, (void **) (&im)); + status = _cairo_cache_lookup (im_cache, key, (void **) (&im), NULL); if (status != CAIRO_STATUS_SUCCESS || im == NULL) { _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_NO_MEMORY; } + v->refcount = 1; v->key = *k; _cairo_unscaled_font_reference (v->key.unscaled); @@ -925,6 +1088,12 @@ _xlib_glyphset_cache_create_entry (void *cache, return CAIRO_STATUS_SUCCESS; } +static void +_glyphset_cache_entry_reference (glyphset_cache_entry_t *e) +{ + e->refcount++; +} + static void _xlib_glyphset_cache_destroy_cache (void *cache) { @@ -940,6 +1109,9 @@ _xlib_glyphset_cache_destroy_entry (void *cache, void *entry) g = (glyphset_cache_t *) cache; v = (glyphset_cache_entry_t *) entry; + if (--v->refcount > 0) + return; + _cairo_unscaled_font_destroy (v->key.unscaled); XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1); free (v); @@ -1014,8 +1186,7 @@ _get_glyphset_cache (Display *d) #define N_STACK_BUF 1024 static cairo_status_t -_cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_xlib_surface_show_glyphs32 (cairo_font_t *font, cairo_operator_t operator, glyphset_cache_t *g, cairo_glyph_cache_key_t *key, @@ -1092,8 +1263,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font, static cairo_status_t -_cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_xlib_surface_show_glyphs16 (cairo_font_t *font, cairo_operator_t operator, glyphset_cache_t *g, cairo_glyph_cache_key_t *key, @@ -1169,10 +1339,9 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font, } static cairo_status_t -_cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_xlib_surface_show_glyphs8 (cairo_font_t *font, cairo_operator_t operator, - glyphset_cache_t *g, + glyphset_cache_t *g, cairo_glyph_cache_key_t *key, cairo_xlib_surface_t *src, cairo_xlib_surface_t *self, @@ -1247,27 +1416,44 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font, static cairo_status_t -_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_xlib_surface_show_glyphs (cairo_font_t *font, cairo_operator_t operator, - cairo_surface_t *source, + cairo_pattern_t *pattern, void *abstract_surface, int source_x, int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs) { + cairo_surface_attributes_t attributes; + cairo_int_status_t status; unsigned int elt_size; cairo_xlib_surface_t *self = abstract_surface; - cairo_image_surface_t *tmp = NULL; - cairo_xlib_surface_t *src = NULL; + cairo_xlib_surface_t *src; glyphset_cache_t *g; - cairo_status_t status; cairo_glyph_cache_key_t key; glyphset_cache_entry_t **entries; glyphset_cache_entry_t *stack_entries [N_STACK_BUF]; int i; + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_pattern_acquire_surface (pattern, &self->base, + source_x, source_y, width, height, + (cairo_surface_t **) &src, + &attributes); + if (status) + return status; + + status = _cairo_xlib_surface_set_attributes (src, &attributes); + if (status) + goto FAIL; + /* Acquire an entry array of suitable size. */ if (num_glyphs < N_STACK_BUF) { entries = stack_entries; @@ -1278,26 +1464,6 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, goto FAIL; } - /* prep the source surface. */ - if (source->backend == self->base.backend) { - src = (cairo_xlib_surface_t *) source; - - } else { - tmp = _cairo_surface_get_image (source); - if (tmp == NULL) - goto FREE_ENTRIES; - - src = (cairo_xlib_surface_t *) - _cairo_surface_create_similar_scratch (&self->base, self->format, 1, - tmp->width, tmp->height); - - if (src == NULL) - goto FREE_TMP; - - if (_cairo_surface_set_image (&(src->base), tmp) != CAIRO_STATUS_SUCCESS) - goto FREE_SRC; - } - _lock_xlib_glyphset_caches (); g = _get_glyphset_cache (self->dpy); if (g == NULL) @@ -1305,15 +1471,23 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, /* Work out the index size to use. */ elt_size = 8; - key.scale = *scale; - key.unscaled = font; + _cairo_font_get_glyph_cache_key (font, &key); for (i = 0; i < num_glyphs; ++i) { key.index = glyphs[i].index; - status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i])); + status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]), NULL); if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL) goto UNLOCK; + /* Referencing the glyph entries we use prevents them from + * being freed if lookup of later entries causes them to + * be ejected from the cache. It would be more efficient + * (though more complex) to prevent them from being ejected + * from the cache at all, so they could get reused later + * in the same string. + */ + _glyphset_cache_entry_reference (entries[i]); + if (elt_size == 8 && entries[i]->glyph > 0xff) elt_size = 16; if (elt_size == 16 && entries[i]->glyph > 0xffff) { @@ -1325,43 +1499,32 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, /* Call the appropriate sub-function. */ if (elt_size == 8) - status = _cairo_xlib_surface_show_glyphs8 (font, scale, operator, g, &key, src, self, - source_x, source_y, + status = _cairo_xlib_surface_show_glyphs8 (font, operator, g, &key, src, self, + source_x + attributes.x_offset, + source_y + attributes.y_offset, glyphs, entries, num_glyphs); else if (elt_size == 16) - status = _cairo_xlib_surface_show_glyphs16 (font, scale, operator, g, &key, src, self, - source_x, source_y, + status = _cairo_xlib_surface_show_glyphs16 (font, operator, g, &key, src, self, + source_x + attributes.x_offset, + source_y + attributes.y_offset, glyphs, entries, num_glyphs); else - status = _cairo_xlib_surface_show_glyphs32 (font, scale, operator, g, &key, src, self, - source_x, source_y, + status = _cairo_xlib_surface_show_glyphs32 (font, operator, g, &key, src, self, + source_x + attributes.x_offset, + source_y + attributes.y_offset, glyphs, entries, num_glyphs); - _unlock_xlib_glyphset_caches (); - - if (tmp != NULL) { - cairo_surface_destroy (&(src->base)); - cairo_surface_destroy (&(tmp->base)); - } - - if (num_glyphs >= N_STACK_BUF) - free (entries); - - return status; + for (i = 0; i < num_glyphs; ++i) + _xlib_glyphset_cache_destroy_entry (g, entries[i]); UNLOCK: _unlock_xlib_glyphset_caches (); - FREE_SRC: - cairo_surface_destroy (&(src->base)); - - FREE_TMP: - cairo_surface_destroy (&(tmp->base)); - - FREE_ENTRIES: if (num_glyphs >= N_STACK_BUF) free (entries); FAIL: - return CAIRO_STATUS_NO_MEMORY; + _cairo_pattern_release_surface (&self->base, &src->base, &attributes); + + return status; } diff --git a/src/cairo-xlib.h b/src/cairo-xlib.h index 4f241b034..18db7b114 100644 --- a/src/cairo-xlib.h +++ b/src/cairo-xlib.h @@ -31,17 +31,20 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ -#include <cairo.h> - #ifndef CAIRO_XLIB_H #define CAIRO_XLIB_H + +#include <cairo.h> + #ifdef CAIRO_HAS_XLIB_SURFACE #include <X11/extensions/Xrender.h> +CAIRO_BEGIN_DECLS + /* XXX: This shold be renamed to cairo_set_target_xlib to match the * other backends */ void @@ -66,6 +69,8 @@ cairo_status_t cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height); */ +CAIRO_END_DECLS + #endif /* CAIRO_HAS_XLIB_SURFACE */ #endif /* CAIRO_XLIB_H */ diff --git a/src/cairo.c b/src/cairo.c index 20d94938c..fd10b5cac 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ @@ -68,6 +68,18 @@ cairo_sane_state (cairo_t *cr) #endif +/** + * cairo_create: + * + * Creates a new #cairo_t with default values. The target + * surface must be set on the #cairo_t with cairo_set_target_surface(), + * or a backend-specific function like cairo_set_target_image() before + * drawing with the #cairo_t. + * + * Return value: a newly allocated #cairo_t with a reference + * count of 1. The initial reference count should be released + * with cairo_destroy() when you are done using the #cairo_t. + **/ cairo_t * cairo_create (void) { @@ -88,6 +100,14 @@ cairo_create (void) return cr; } +/** + * cairo_reference: + * @cr: a #cairo_t + * + * Increases the reference count on @cr by one. This prevents + * @cr from being destroyed until a matching call to cairo_destroy() + * is made. + **/ void cairo_reference (cairo_t *cr) { @@ -99,6 +119,14 @@ cairo_reference (cairo_t *cr) CAIRO_CHECK_SANITY (cr); } +/** + * cairo_destroy: + * @cr: a #cairo_t + * + * Decreases the reference count on @cr by one. If the result + * is zero, then @cr and all associated resources are freed. + * See cairo_destroy(). + **/ void cairo_destroy (cairo_t *cr) { @@ -117,6 +145,22 @@ cairo_destroy (cairo_t *cr) free (cr); } +/** + * cairo_save: + * @cr: a #cairo_t + * + * Makes a copy of the current state of @cr and saves it + * on an internal stack of saved states for @cr. When + * cairo_restore() is called, @cr will be restored to + * the saved state. Multiple calls to cairo_save() and + * cairo_restore() can be nested; each call to cairo_restore() + * restores the state from the matching paired cairo_save(). + * + * It isn't necessary to clear all saved states before + * a #cairo_t is freed. If the reference count of a #cairo_t + * drops to zero in response to a call to cairo_destroy(), + * any saved states will be freed along with the #cairo_t. + **/ void cairo_save (cairo_t *cr) { @@ -144,6 +188,14 @@ cairo_save (cairo_t *cr) } slim_hidden_def(cairo_save); +/** + * cairo_restore: + * @cr: a #cairo_t + * + * Restores @cr to the state saved by a preceding call to + * cairo_save() and removes that state from the stack of + * saved states. + **/ void cairo_restore (cairo_t *cr) { @@ -170,6 +222,20 @@ cairo_restore (cairo_t *cr) } slim_hidden_def(cairo_restore); +/** + * cairo_copy: + * @dest: a #cairo_t + * @src: another #cairo_t + * + * This function copies all current state information from src to + * dest. This includes the current point and path, the target surface, + * the transformation matrix, and so forth. + * + * The stack of states saved with cairo_save() is <emphasis>not</emphasis> + * not copied; nor are any saved states on @dest cleared. The + * operation only copies the current state of @src to the current + * state of @dest. + **/ void cairo_copy (cairo_t *dest, cairo_t *src) { @@ -216,6 +282,16 @@ cairo_pop_group (cairo_t *cr) } */ +/** + * cairo_set_target_surface: + * @cr: a #cairo_t + * @surface: a #cairo_surface_t + * + * Directs output for a #cairo_t to a given surface. The surface + * will be referenced by the #cairo_t, so you can immediately + * call cairo_surface_destroy() on it if you don't need to + * keep a reference to it around. + **/ void cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface) { @@ -228,6 +304,26 @@ cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface) } slim_hidden_def(cairo_set_target_surface); +/** + * cairo_set_target_image: + * @cr: a #cairo_t + * @data: a pointer to a buffer supplied by the application + * in which to write contents. + * @format: the format of pixels in the buffer + * @width: the width of the image to be stored in the buffer + * @height: the eight of the image to be stored in the buffer + * @stride: the number of bytes between the start of rows + * in the buffer. Having this be specified separate from @width + * allows for padding at the end of rows, or for writing + * to a subportion of a larger image. + * + * Directs output for a #cairo_t to an in-memory image. The output + * buffer must be kept around until the #cairo_t is destroyed or set + * to to have a different target. The initial contents of @buffer + * will be used as the inital image contents; you must explicitely + * clear the buffer, using, for example, cairo_rectangle() and + * cairo_fill() if you want it cleared. + **/ void cairo_set_target_image (cairo_t *cr, char *data, @@ -268,6 +364,18 @@ cairo_set_operator (cairo_t *cr, cairo_operator_t op) CAIRO_CHECK_SANITY (cr); } +/** + * cairo_set_rgb_color: + * @cr: a #cairo_t + * @red: red component of color + * @green: green component of color + * @blue: blue component of color + * + * Sets a constant color for filling and stroking. This replaces any + * pattern set with cairo_set_pattern(). The color components are + * floating point numbers in the range 0 to 1. If the values passed in + * are outside that range, they will be clamped. + **/ void cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue) { @@ -301,6 +409,19 @@ cairo_current_pattern (cairo_t *cr) return _cairo_gstate_current_pattern (cr->gstate); } +/** + * cairo_set_tolerance: + * @cr: a #cairo_t + * @tolerance: the tolerance, in device units (typically pixels) + * + * Sets the tolerance used when converting paths into trapezoids. + * Curved segments of the path will be subdivided until the maximum + * deviation between the original path and the polygonal approximation + * is less than @tolerance. The default value is 0.1. A larger + * value will give better performance, a smaller value, better + * appearance. (Reducing the value from the default value of 0.1 + * is unlikely to improve appearance significantly.) + **/ void cairo_set_tolerance (cairo_t *cr, double tolerance) { @@ -314,6 +435,17 @@ cairo_set_tolerance (cairo_t *cr, double tolerance) CAIRO_CHECK_SANITY (cr); } +/** + * cairo_set_alpha: + * @cr: a #cairo_t + * @alpha: the alpha value. 0 is transparent, 1 fully opaque. + * if the value is outside the range 0 to 1, it will be + * clamped to that range. + * + * Sets an overall alpha value used for stroking and filling. This + * value is multiplied with any alpha value coming from a gradient or + * image pattern. + **/ void cairo_set_alpha (cairo_t *cr, double alpha) { @@ -569,6 +701,39 @@ cairo_curve_to (cairo_t *cr, CAIRO_CHECK_SANITY (cr); } +/** + * cairo_arc: + * @cr: a Cairo context + * @xc: X position of the center of the arc + * @yc: Y position of the center of the arc + * @radius: the radius of the arc + * @angle1: the start angle, in radians + * @angle2: the end angle, in radians + * + * Adds an arc from @angle1 to @angle2 to the current path. If there + * is a current point, that point is connected to the start of the arc + * by a straight line segment. Angles are measured in radians with an + * angle of 0 along the X axis and an angle of %M_PI radians (90 + * degrees) along the Y axis, so with the default transformation + * matrix, positive angles are clockwise. (To convert from degrees to + * radians, use <literal>degrees * (M_PI / 180.)</literal>.) This + * function gives the arc in the direction of increasing angle; see + * cairo_arc_negative() to get the arc in the direction of decreasing + * angle. + * + * A full arc is drawn as a circle. To make an oval arc, you can scale + * the current transformation matrix by different amounts in the X and + * Y directions. For example, to draw a full oval in the box given + * by @x, @y, @width, @height: + + * <informalexample><programlisting> + * cairo_save (cr); + * cairo_translate (x + width / 2., y + height / 2.); + * cairo_scale (1. / (height / 2.), 1. / (width / 2.)); + * cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI); + * cairo_restore (cr); + * </programlisting></informalexample> + **/ void cairo_arc (cairo_t *cr, double xc, double yc, @@ -586,6 +751,20 @@ cairo_arc (cairo_t *cr, CAIRO_CHECK_SANITY (cr); } +/** + * cairo_arc_negative: + * @cr: a Cairo context + * @xc: X position of the center of the arc + * @yc: Y position of the center of the arc + * @radius: the radius of the arc + * @angle1: the start angle, in radians + * @angle2: the end angle, in radians + * + * Adds an arc from @angle1 to @angle2 to the current path. The + * function behaves identically to cairo_arc() except that instead of + * giving the arc in the direction of increasing angle, it gives + * the arc in the direction of decreasing angle. + **/ void cairo_arc_negative (cairo_t *cr, double xc, double yc, @@ -744,7 +923,7 @@ cairo_show_page (cairo_t *cr) CAIRO_CHECK_SANITY (cr); } -int +cairo_bool_t cairo_in_stroke (cairo_t *cr, double x, double y) { int inside; @@ -842,6 +1021,20 @@ cairo_select_font (cairo_t *cr, CAIRO_CHECK_SANITY (cr); } +/** + * cairo_current_font: + * @cr: a #cairo_t + * + * Gets the current font object for a #cairo_t. If there is no current + * font object, because the font parameters, transform, or target + * surface has been changed since a font was last used, a font object + * will be created and stored in in the #cairo_t. + * + * Return value: the current font object. Can return %NULL + * on out-of-memory or if the context is already in + * an error state. This object is owned by Cairo. To keep + * a reference to it, you must call cairo_font_reference(). + **/ cairo_font_t * cairo_current_font (cairo_t *cr) { @@ -869,6 +1062,22 @@ cairo_current_font_extents (cairo_t *cr, } +/** + * cairo_set_font: + * @cr: a #cairo_t + * @font: a #cairo_font_t, or %NULL to unset any previously set font. + * + * Replaces the current #cairo_font_t object in the #cairo_t with + * @font. The replaced font in the #cairo_t will be destroyed if there + * are no other references to it. Since a #cairo_font_t is specific to + * a particular output device and size, changing the transformation, + * font transformation, or target surfaces of a #cairo_t will clear + * any previously set font. Setting the font using cairo_set_font() is + * exclusive with the simple font selection API provided by + * cairo_select_font(). The size and transformation set by + * cairo_scale_font() and cairo_transform_font() are ignored unless + * they were taken into account when creating @font. + **/ void cairo_set_font (cairo_t *cr, cairo_font_t *font) { @@ -914,6 +1123,16 @@ cairo_text_extents (cairo_t *cr, if (cr->status) return; + if (utf8 == NULL) { + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + extents->x_advance = 0.0; + extents->y_advance = 0.0; + return; + } + cr->status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8, &glyphs, &nglyphs); CAIRO_CHECK_SANITY (cr); @@ -1205,6 +1424,8 @@ cairo_status_string (cairo_t *cr) return "no target surface has been set"; case CAIRO_STATUS_NULL_POINTER: return "NULL pointer"; + case CAIRO_STATUS_INVALID_STRING: + return "input string not valid UTF-8"; } return "<unknown error status>"; diff --git a/src/cairo.h b/src/cairo.h index b7bcc1dbb..03e063242 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -31,23 +31,83 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #ifndef CAIRO_H #define CAIRO_H +#ifdef __cplusplus +# define CAIRO_BEGIN_DECLS extern "C" { +# define CAIRO_END_DECLS } +#else +# define CAIRO_BEGIN_DECLS +# define CAIRO_END_DECLS +#endif + #include <cairo-features.h> #include <pixman.h> +CAIRO_BEGIN_DECLS + +/** + * cairo_bool_t: + * + * #cairo_bool_t is used for boolean values. Returns of type + * #cairo_bool_t will always be either 0 or 1, but testing against + * these values explicitely is not encouraged; just use the + * value as a boolean condition. + * + * <informalexample><programlisting> + * if (cairo_in_stroke (cr, x, y)) { + * /<!-- -->* do something *<!-- -->/ + * } + * </programlisting></informalexample> + */ +typedef int cairo_bool_t; + +/** + * cairo_t: + * + * A #cairo_t contains the current state of the rendering device, + * including coordinates of yet to be drawn shapes. + **/ typedef struct _cairo cairo_t; + +/** + * cairo_surface_t: + * + * A #cairo_surface_t represents an image, either as the destination + * of a drawing operation or as source when drawing onto another + * surface. There are different subtypes of cairo_surface_t for + * different drawing backends; for example, cairo_image_surface_create() + * creates a bitmap image in memory. + * + * Memory management of #cairo_surface_t is done with + * cairo_surface_reference() and cairo_surface_destroy(). + */ typedef struct _cairo_surface cairo_surface_t; + +/** + * cairo_matrix_t: + * + * A #cairo_matrix_t holds an affine transformation, such as a scale, + * rotation, or shear, or a combination of those. + **/ typedef struct _cairo_matrix cairo_matrix_t; typedef struct _cairo_pattern cairo_pattern_t; -#ifdef __cplusplus -extern "C" { -#endif +typedef enum cairo_status { + CAIRO_STATUS_SUCCESS = 0, + CAIRO_STATUS_NO_MEMORY, + CAIRO_STATUS_INVALID_RESTORE, + CAIRO_STATUS_INVALID_POP_GROUP, + CAIRO_STATUS_NO_CURRENT_POINT, + CAIRO_STATUS_INVALID_MATRIX, + CAIRO_STATUS_NO_TARGET_SURFACE, + CAIRO_STATUS_NULL_POINTER, + CAIRO_STATUS_INVALID_STRING +} cairo_status_t; /* Functions for manipulating state objects */ cairo_t * @@ -81,6 +141,28 @@ cairo_pop_group (cairo_t *cr); void cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface); +/** + * cairo_format_t + * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with + * alpha in the upper 8 bits, then red, then green, then blue. + * The 32-bit quanties are stored native-endian. Pre-multiplied + * alpha is used. (That is, 50% transparent red is 0x80800000, + * not 0x80ff0000.) + * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with + * the upper 8 bits unused. Red, Green, and Blue are stored + * in the remaining 24 bits in that order. + * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding + * an alpha value. + * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding + * an alpha value. Pixels are packed together into 32-bit + * quantities. The ordering of the bits matches the + * endianess of the platform. On a big-endian machine, the + * first pixel is in the uppermost bit, on a little-endian + * machine the first pixel is in the least-significant bit. + * + * #cairo_format_t is used to identify the memory format of + * image data. + */ typedef enum cairo_format { CAIRO_FORMAT_ARGB32, CAIRO_FORMAT_RGB24, @@ -88,6 +170,7 @@ typedef enum cairo_format { CAIRO_FORMAT_A1 } cairo_format_t; +/* XXX: Need to add cairo_set_target_image_data */ void cairo_set_target_image (cairo_t *cr, char *data, @@ -149,6 +232,27 @@ cairo_set_alpha (cairo_t *cr, double alpha); void cairo_set_tolerance (cairo_t *cr, double tolerance); +/** + * cairo_fill_rule_t + * @CAIRO_FILL_RULE_WINDING: If the path crosses the ray from + * left-to-right, counts +1. If the path crosses the ray + * from right to left, counts -1. (Left and right are determined + * from the perspective of looking along the ray from the starting + * point.) If the total count is non-zero, the point will be filled. + * @CAIRO_FILL_RULE_EVEN_ODD: Counts the total number of + * intersections, without regard to the orientation of the contour. If + * the total number of intersections is odd, the point will be + * filled. + * + * #cairo_fill_rule_t is used to select how paths are filled. For both + * fill rules, whether or not a point is included in the fill is + * determined by taking a ray from that point to infinity and looking + * at intersections with the path. The ray can be in any direction, + * as long as it doesn't pass through the end point of a segment + * or have a tricky intersection such as intersecting tangent to the path. + * (Note that filling is not actually implemented in this way. This + * is just a description of the rule that is applied.) + **/ typedef enum cairo_fill_rule { CAIRO_FILL_RULE_WINDING, CAIRO_FILL_RULE_EVEN_ODD @@ -160,6 +264,15 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule); void cairo_set_line_width (cairo_t *cr, double width); + +/** + * cairo_line_cap_t + * @CAIRO_LINE_CAP_BUTT: start(stop) the line exactly at the start(end) point + * @CAIRO_LINE_CAP_ROUND: use a round ending, the center of the circle is the end point + * @CAIRO_LINE_CAP_SQUARE: use squared ending, the center of the square is the end point + * + * enumeration for style of line-endings + **/ typedef enum cairo_line_cap { CAIRO_LINE_CAP_BUTT, CAIRO_LINE_CAP_ROUND, @@ -303,10 +416,10 @@ void cairo_show_page (cairo_t *cr); /* Insideness testing */ -int +cairo_bool_t cairo_in_stroke (cairo_t *cr, double x, double y); -int +cairo_bool_t cairo_in_fill (cairo_t *cr, double x, double y); /* Rectangular extents */ @@ -330,14 +443,75 @@ cairo_clip (cairo_t *cr); /* Font/Text functions */ +/** + * cairo_font_t: + * + * A #cairo_font_t is a font scaled to a particular size and device + * resolution. A font can be set on a #cairo_t by using + * cairo_set_font() assuming that the current transformation and + * target surface of the #cairo_t match that for which the + * #cairo_font_t was created. The effect of using a mismatched + * #cairo_font_t will be incorrect font metrics. + */ typedef struct _cairo_font cairo_font_t; +/** + * cairo_glyph_t: + * @index: glyph index in the font. The exact interpretation of the + * glyph index depends on the font technology being used. + * @x: the offset in the X direction between the origin used for + * drawing or measuring the string and the origin of this glyph. + * @y: the offset in the Y direction between the origin used for + * drawing or measuring the string and the origin of this glyph. + * + * The #cairo_glyph_t structure holds information about a single glyph + * when drawing or measuring text. A font is (in simple terms) a + * collection of shapes used to draw text. A glyph is one of these + * shapes. There can be multiple glyphs for a single character + * (alternates to be used in different contexts, for example), or a + * glyph can be a <firstterm>ligature</firstterm> of multiple + * characters. Cairo doesn't expose any way of converting input text + * into glyphs, so in order to use the Cairo interfaces that take + * arrays of glyphs, you must directly access the appropriate + * underlying font system. + * + * Note that the offsets given by @x and @y are not cumulative. When + * drawing or measuring text, each glyph is individually positioned + * with respect to the overall origin + **/ typedef struct { unsigned long index; double x; double y; } cairo_glyph_t; +/** + * cairo_text_extents_t: + * @x_bearing: the horizontal distance from the origin to the + * leftmost part of the glyphs as drawn. Positive if the + * glyphs lie entirely to the right of the origin. + * @y_bearing: the vertical distance from the origin to the + * topmost part of the glyphs as drawn. Positive only if the + * glyphs lie completely below the origin; will usually be + * negative. + * @width: width of the glyphs as drawn + * @height: height of the glyphs as drawn + * @x_advance:distance to advance in the X direction + * after drawing these glyphs + * @y_advance: distance to advance in the Y direction + * after drawing these glyphs. Will typically be zero except + * for vertical text layout as found in East-Asian languages. + * + * The #cairo_text_extents_t< structure stores the extents of a single + * glyph or a string of glyphs in user-space coordinates. Because text + * extents are in user-space coordinates, they don't scale along with + * the current transformation matrix. If you call + * <literal>cairo_scale(cr, 2.0, 2.0)</literal>, text will + * be drawn twice as big, but the reported text extents will not be + * doubled. They will change slightly due to hinting (so you can't + * assume that metrics are independent of the transformation matrix), + * but otherwise will remain unchanged. + */ typedef struct { double x_bearing; double y_bearing; @@ -422,13 +596,17 @@ cairo_font_reference (cairo_font_t *font); void cairo_font_destroy (cairo_font_t *font); -void -cairo_font_set_transform (cairo_font_t *font, - cairo_matrix_t *matrix); +cairo_status_t +cairo_font_extents (cairo_font_t *font, + cairo_matrix_t *font_matrix, + cairo_font_extents_t *extents); void -cairo_font_current_transform (cairo_font_t *font, - cairo_matrix_t *matrix); +cairo_font_glyph_extents (cairo_font_t *font, + cairo_matrix_t *font_matrix, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents); /* Image functions */ @@ -521,17 +699,6 @@ cairo_current_path_flat (cairo_t *cr, /* Error status queries */ -typedef enum cairo_status { - CAIRO_STATUS_SUCCESS = 0, - CAIRO_STATUS_NO_MEMORY, - CAIRO_STATUS_INVALID_RESTORE, - CAIRO_STATUS_INVALID_POP_GROUP, - CAIRO_STATUS_NO_CURRENT_POINT, - CAIRO_STATUS_INVALID_MATRIX, - CAIRO_STATUS_NO_TARGET_SURFACE, - CAIRO_STATUS_NULL_POINTER -} cairo_status_t; - cairo_status_t cairo_status (cairo_t *cr); @@ -671,7 +838,7 @@ cairo_status_t cairo_matrix_set_identity (cairo_matrix_t *matrix); cairo_status_t -cairo_matrix_set_affine (cairo_matrix_t *cr, +cairo_matrix_set_affine (cairo_matrix_t *matrix, double a, double b, double c, double d, double tx, double ty); @@ -724,8 +891,6 @@ cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y); #define cairo_get_status_string cairo_get_status_string_DEPRECATED_BY_cairo_status_string #endif -#ifdef __cplusplus -} -#endif +CAIRO_END_DECLS #endif /* CAIRO_H */ diff --git a/src/cairo_atsui_font.c b/src/cairo_atsui_font.c index 52cfc6bd8..cb4b1c5d7 100644 --- a/src/cairo_atsui_font.c +++ b/src/cairo_atsui_font.c @@ -1,6 +1,6 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2004 Calum Robinson + * Copyright © 2004 Calum Robinson * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public diff --git a/src/cairo_cache.c b/src/cairo_cache.c index b097b609b..d1ad5a4e2 100644 --- a/src/cairo_cache.c +++ b/src/cairo_cache.c @@ -94,9 +94,9 @@ static const cairo_cache_arrangement_t cache_arrangements [] = { * a mostly-dead table. * * Generally you do not need to worry about freeing cache entries; the - * cache will expire entries randomly as it experiences memory pressure. - * There is currently no explicit entry-removing call, though one can be - * added easily. + * cache will expire entries randomly as it experiences memory pressure. + * If max_memory is set, entries are not expired, and must be explicitely + * removed. * * This table is open-addressed with double hashing. Each table size is a * prime chosen to be a little more than double the high water mark for a @@ -282,17 +282,51 @@ _load_factor (cairo_cache_t *cache) } #endif -static unsigned long -_random_live_entry (cairo_cache_t *cache) -{ - unsigned long idx; - assert(cache != NULL); - do { - idx = rand () % cache->arrangement->size; - } while (! LIVE_ENTRY_P(cache, idx)); - return idx; -} +/* Find a random in the cache matching the given predicate. We use the + * same algorithm as the probing algorithm to walk over the entries in + * the hash table in a pseudo-random order. Walking linearly would + * favor entries following gaps in the hash table. We could also + * call rand() repeatedly, which works well for almost-full tables, + * but degrades when the table is almost empty, or predicate + * returns false for most entries. + */ +static cairo_cache_entry_base_t ** +_random_entry (cairo_cache_t *cache, + int (*predicate)(void*)) +{ + cairo_cache_entry_base_t **probe; + unsigned long hash; + unsigned long table_size, i, idx, step; + + _cache_sane_state (cache); + + table_size = cache->arrangement->size; + hash = rand (); + idx = hash % table_size; + step = 0; + + for (i = 0; i < table_size; ++i) + { + assert(idx < table_size); + probe = cache->entries + idx; + if (LIVE_ENTRY_P(cache, idx) + && (!predicate || predicate (*probe))) + return probe; + + if (step == 0) { + step = hash % cache->arrangement->rehash; + if (step == 0) + step = 1; + } + + idx += step; + if (idx >= table_size) + idx -= table_size; + } + + return NULL; +} /* public API follows */ @@ -356,8 +390,9 @@ _cairo_cache_destroy (cairo_cache_t *cache) cairo_status_t _cairo_cache_lookup (cairo_cache_t *cache, - void *key, - void **entry_return) + void *key, + void **entry_return, + int *created_entry) { unsigned long idx; @@ -392,6 +427,8 @@ _cairo_cache_lookup (cairo_cache_t *cache, cache->hits++; #endif *entry_return = *slot; + if (created_entry) + *created_entry = 0; return status; } @@ -401,19 +438,18 @@ _cairo_cache_lookup (cairo_cache_t *cache, /* Build the new entry. */ status = cache->backend->create_entry (cache, key, - entry_return); + (void **)&new_entry); if (status != CAIRO_STATUS_SUCCESS) return status; - new_entry = (cairo_cache_entry_base_t *) (*entry_return); - /* Store the hash value in case the backend forgot. */ new_entry->hashcode = cache->backend->hash (cache, key); /* Make some entries die if we're under memory pressure. */ while (cache->live_entries > 0 && + cache->max_memory > 0 && ((cache->max_memory - cache->used_memory) < new_entry->memory)) { - idx = _random_live_entry (cache); + idx = _random_entry (cache, NULL) - cache->entries; assert (idx < cache->arrangement->size); _entry_destroy (cache, idx); } @@ -425,7 +461,6 @@ _cairo_cache_lookup (cairo_cache_t *cache, status = _resize_cache (cache, cache->live_entries + 1); if (status != CAIRO_STATUS_SUCCESS) { cache->backend->destroy_entry (cache, new_entry); - *entry_return = NULL; return status; } @@ -439,9 +474,38 @@ _cairo_cache_lookup (cairo_cache_t *cache, _cache_sane_state (cache); + *entry_return = new_entry; + if (created_entry) + *created_entry = 1; + return status; } +cairo_status_t +_cairo_cache_remove (cairo_cache_t *cache, + void *key) +{ + cairo_cache_entry_base_t **slot; + + _cache_sane_state (cache); + + /* See if we have an entry in the table already. */ + slot = _find_exact_live_entry_for (cache, key); + if (slot != NULL) + _entry_destroy (cache, slot - cache->entries); + + return CAIRO_STATUS_SUCCESS; +} + +void * +_cairo_cache_random_entry (cairo_cache_t *cache, + int (*predicate)(void*)) +{ + cairo_cache_entry_base_t **slot = _random_entry (cache, predicate); + + return slot ? *slot : NULL; +} + unsigned long _cairo_hash_string (const char *c) { diff --git a/src/cairo_color.c b/src/cairo_color.c index 899b1e3d5..f203d96cc 100644 --- a/src/cairo_color.c +++ b/src/cairo_color.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" @@ -67,7 +67,8 @@ _cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blu } void -_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue) +_cairo_color_get_rgb (const cairo_color_t *color, + double *red, double *green, double *blue) { if (red) *red = color->red; diff --git a/src/cairo_fixed.c b/src/cairo_fixed.c index ee31718ef..a4faa1708 100644 --- a/src/cairo_fixed.c +++ b/src/cairo_fixed.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo_font.c b/src/cairo_font.c index f5fc0e981..529c1c7c3 100644 --- a/src/cairo_font.c +++ b/src/cairo_font.c @@ -1,6 +1,7 @@ /* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -31,293 +32,129 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> + * Graydon Hoare <graydon@redhat.com> + * Owen Taylor <otaylor@redhat.com> */ #include "cairoint.h" -/* First we implement a global font cache for named fonts. */ - -typedef struct { - cairo_cache_entry_base_t base; - const char *family; - cairo_font_slant_t slant; - cairo_font_weight_t weight; -} cairo_font_cache_key_t; - -typedef struct { - cairo_font_cache_key_t key; - cairo_unscaled_font_t *unscaled; -} cairo_font_cache_entry_t; - -static unsigned long -_font_cache_hash (void *cache, void *key) -{ - unsigned long hash; - cairo_font_cache_key_t *in; - in = (cairo_font_cache_key_t *) key; - - /* 1607 and 1451 are just a couple random primes. */ - hash = _cairo_hash_string (in->family); - hash += ((unsigned long) in->slant) * 1607; - hash += ((unsigned long) in->weight) * 1451; - return hash; -} - - -static int -_font_cache_keys_equal (void *cache, - void *k1, - void *k2) -{ - cairo_font_cache_key_t *a, *b; - a = (cairo_font_cache_key_t *) k1; - b = (cairo_font_cache_key_t *) k2; - - return (strcmp (a->family, b->family) == 0) - && (a->weight == b->weight) - && (a->slant == b->slant); -} - - -static cairo_status_t -_font_cache_create_entry (void *cache, - void *key, - void **return_value) -{ - const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT; - cairo_font_cache_key_t *k; - cairo_font_cache_entry_t *entry; - k = (cairo_font_cache_key_t *) key; - - /* XXX: The current freetype backend may return NULL, (for example - * if no fonts are installed), but I would like to guarantee that - * the toy API always returns at least *some* font, so I would - * like to build in some sort fo font here, (even a really lame, - * ugly one if necessary). */ - - entry = malloc (sizeof (cairo_font_cache_entry_t)); - if (entry == NULL) - goto FAIL; - - entry->key.slant = k->slant; - entry->key.weight = k->weight; - entry->key.family = strdup(k->family); - if (entry->key.family == NULL) - goto FREE_ENTRY; - - entry->unscaled = backend->create (k->family, k->slant, k->weight); - if (entry->unscaled == NULL) - goto FREE_FAMILY; - - /* Not sure how to measure backend font mem; use a simple count for now.*/ - entry->key.base.memory = 1; - *return_value = entry; - return CAIRO_STATUS_SUCCESS; - - FREE_FAMILY: - free ((void *) entry->key.family); - - FREE_ENTRY: - free (entry); - - FAIL: - return CAIRO_STATUS_NO_MEMORY; -} - -static void -_font_cache_destroy_entry (void *cache, - void *entry) -{ - cairo_font_cache_entry_t *e; - - e = (cairo_font_cache_entry_t *) entry; - _cairo_unscaled_font_destroy (e->unscaled); - free ((void *) e->key.family); - free (e); -} - -static void -_font_cache_destroy_cache (void *cache) -{ - free (cache); -} - -static const cairo_cache_backend_t cairo_font_cache_backend = { - _font_cache_hash, - _font_cache_keys_equal, - _font_cache_create_entry, - _font_cache_destroy_entry, - _font_cache_destroy_cache -}; - -static void -_lock_global_font_cache (void) -{ - /* FIXME: implement locking. */ -} - -static void -_unlock_global_font_cache (void) -{ - /* FIXME: implement locking. */ -} - -static cairo_cache_t * -_global_font_cache = NULL; - -static cairo_cache_t * -_get_global_font_cache (void) -{ - if (_global_font_cache == NULL) { - _global_font_cache = malloc (sizeof (cairo_cache_t)); - - if (_global_font_cache == NULL) - goto FAIL; - - if (_cairo_cache_init (_global_font_cache, - &cairo_font_cache_backend, - CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT)) - goto FAIL; - } - - return _global_font_cache; - - FAIL: - if (_global_font_cache) - free (_global_font_cache); - _global_font_cache = NULL; - return NULL; -} - - /* Now the internal "unscaled + scale" font API */ -cairo_unscaled_font_t * -_cairo_unscaled_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight) +cairo_private cairo_status_t +_cairo_font_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight, + cairo_font_scale_t *sc, + cairo_font_t **font) { - cairo_cache_t * cache; - cairo_font_cache_key_t key; - cairo_font_cache_entry_t *font; - cairo_status_t status; - - _lock_global_font_cache (); - cache = _get_global_font_cache (); - if (cache == NULL) { - _unlock_global_font_cache (); - return NULL; - } - - key.family = family; - key.slant = slant; - key.weight = weight; - - status = _cairo_cache_lookup (cache, &key, (void **) &font); - if (status) { - _unlock_global_font_cache (); - return NULL; - } + const cairo_font_backend_t *backend = CAIRO_FONT_BACKEND_DEFAULT; - _cairo_unscaled_font_reference (font->unscaled); - _unlock_global_font_cache (); - return font->unscaled; + return backend->create (family, slant, weight, sc, font); } void -_cairo_font_init (cairo_font_t *scaled, - cairo_font_scale_t *scale, - cairo_unscaled_font_t *unscaled) +_cairo_font_init (cairo_font_t *font, + cairo_font_scale_t *scale, + const cairo_font_backend_t *backend) { - scaled->scale = *scale; - scaled->unscaled = unscaled; - scaled->refcount = 1; + font->scale = *scale; + font->refcount = 1; + font->backend = backend; } -cairo_status_t -_cairo_unscaled_font_init (cairo_unscaled_font_t *font, - const cairo_font_backend_t *backend) +void +_cairo_unscaled_font_init (cairo_unscaled_font_t *font, + const cairo_font_backend_t *backend) { font->refcount = 1; font->backend = backend; - return CAIRO_STATUS_SUCCESS; } - cairo_status_t -_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - const unsigned char *utf8, - cairo_glyph_t **glyphs, - int *num_glyphs) +_cairo_font_text_to_glyphs (cairo_font_t *font, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs) { - return font->backend->text_to_glyphs (font, scale, utf8, glyphs, num_glyphs); + return font->backend->text_to_glyphs (font, utf8, glyphs, num_glyphs); } cairo_status_t -_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents) +_cairo_font_glyph_extents (cairo_font_t *font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) { - return font->backend->glyph_extents(font, scale, glyphs, num_glyphs, extents); + return font->backend->glyph_extents(font, glyphs, num_glyphs, extents); } cairo_status_t -_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox) +_cairo_font_glyph_bbox (cairo_font_t *font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox) { - return font->backend->glyph_bbox (font, scale, glyphs, num_glyphs, bbox); + return font->backend->glyph_bbox (font, glyphs, num_glyphs, bbox); } cairo_status_t -_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_font_show_glyphs (cairo_font_t *font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + cairo_glyph_t *glyphs, + int num_glyphs) { cairo_status_t status; if (surface->backend->show_glyphs != NULL) { - status = surface->backend->show_glyphs (font, scale, operator, source, - surface, source_x, source_y, + status = surface->backend->show_glyphs (font, operator, pattern, + surface, + source_x, source_y, + dest_x, dest_y, + width, height, glyphs, num_glyphs); if (status == CAIRO_STATUS_SUCCESS) return status; } /* Surface display routine either does not exist or failed. */ - return font->backend->show_glyphs (font, scale, operator, source, - surface, source_x, source_y, + return font->backend->show_glyphs (font, operator, pattern, + surface, + source_x, source_y, + dest_x, dest_y, + width, height, glyphs, num_glyphs); } cairo_status_t -_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_t *path) +_cairo_font_glyph_path (cairo_font_t *font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path) +{ + return font->backend->glyph_path (font, glyphs, num_glyphs, path); +} + +void +_cairo_font_get_glyph_cache_key (cairo_font_t *font, + cairo_glyph_cache_key_t *key) { - return font->backend->glyph_path (font, scale, glyphs, num_glyphs, path); + font->backend->get_glyph_cache_key (font, key); } cairo_status_t -_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_font_extents_t *extents) +_cairo_font_font_extents (cairo_font_t *font, + cairo_font_extents_t *extents) { - return font->backend->font_extents(font, scale, extents); + return font->backend->font_extents (font, extents); } void @@ -332,8 +169,7 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font) if (--(font->refcount) > 0) return; - if (font->backend) - font->backend->destroy (font); + font->backend->destroy_unscaled_font (font); } @@ -352,37 +188,154 @@ cairo_font_destroy (cairo_font_t *font) if (--(font->refcount) > 0) return; - if (font->unscaled) - _cairo_unscaled_font_destroy (font->unscaled); - - free (font); + font->backend->destroy_font (font); } -void -cairo_font_set_transform (cairo_font_t *font, - cairo_matrix_t *matrix) +/** + * cairo_font_extents: + * @font: a #cairo_font_t + * @font_matrix: the font transformation for which this font was + * created. (See cairo_transform_font()). This is needed + * properly convert the metrics from the font into user space. + * @extents: a #cairo_font_extents_t which to store the retrieved extents. + * + * Gets the metrics for a #cairo_font_t. + * + * Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an + * error such as %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_status_t +cairo_font_extents (cairo_font_t *font, + cairo_matrix_t *font_matrix, + cairo_font_extents_t *extents) { - double dummy; - cairo_matrix_get_affine (matrix, - &font->scale.matrix[0][0], - &font->scale.matrix[0][1], - &font->scale.matrix[1][0], - &font->scale.matrix[1][1], - &dummy, &dummy); + cairo_int_status_t status; + double font_scale_x, font_scale_y; + + status = _cairo_font_font_extents (font, extents); + + if (!CAIRO_OK (status)) + return status; + + _cairo_matrix_compute_scale_factors (font_matrix, + &font_scale_x, &font_scale_y, + /* XXX */ 1); + + /* + * The font responded in unscaled units, scale by the font + * matrix scale factors to get to user space + */ + + extents->ascent *= font_scale_y; + extents->descent *= font_scale_y; + extents->height *= font_scale_y; + extents->max_x_advance *= font_scale_x; + extents->max_y_advance *= font_scale_y; + + return status; } +/** + * cairo_font_glyph_extents: + * @font: a #cairo_font_t + * @font_matrix: the font transformation for which this font was + * created. (See cairo_transform_font()). This is needed + * properly convert the metrics from the font into user space. + * @glyphs: an array of glyph IDs with X and Y offsets. + * @num_glyphs: the number of glyphs in the @glyphs array + * @extents: a #cairo_text_extents_t which to store the retrieved extents. + * + * cairo_font_glyph_extents() gets the overall metrics for a string of + * glyphs. The X and Y offsets in @glyphs are taken from an origin of 0,0. + **/ void -cairo_font_current_transform (cairo_font_t *font, - cairo_matrix_t *matrix) +cairo_font_glyph_extents (cairo_font_t *font, + cairo_matrix_t *font_matrix, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) { - cairo_matrix_set_affine (matrix, - font->scale.matrix[0][0], - font->scale.matrix[0][1], - font->scale.matrix[1][0], - font->scale.matrix[1][1], - 0, 0); -} + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_glyph_t origin_glyph; + cairo_text_extents_t origin_extents; + int i; + double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0; + double x_pos = 0.0, y_pos = 0.0; + int set = 0; + + if (!num_glyphs) + { + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + extents->x_advance = 0.0; + extents->y_advance = 0.0; + + return; + } + for (i = 0; i < num_glyphs; i++) + { + double x, y; + double wm, hm; + + origin_glyph = glyphs[i]; + origin_glyph.x = 0.0; + origin_glyph.y = 0.0; + status = _cairo_font_glyph_extents (font, + &origin_glyph, 1, + &origin_extents); + + /* + * Transform font space metrics into user space metrics + * by running the corners through the font matrix and + * expanding the bounding box as necessary + */ + x = origin_extents.x_bearing; + y = origin_extents.y_bearing; + cairo_matrix_transform_point (font_matrix, + &x, &y); + + for (hm = 0.0; hm <= 1.0; hm += 1.0) + for (wm = 0.0; wm <= 1.0; wm += 1.0) + { + x = origin_extents.x_bearing + origin_extents.width * wm; + y = origin_extents.y_bearing + origin_extents.height * hm; + cairo_matrix_transform_point (font_matrix, + &x, &y); + x += glyphs[i].x; + y += glyphs[i].y; + if (!set) + { + min_x = max_x = x; + min_y = max_y = y; + set = 1; + } + else + { + if (x < min_x) min_x = x; + if (x > max_x) max_x = x; + if (y < min_y) min_y = y; + if (y > max_y) max_y = y; + } + } + + x = origin_extents.x_advance; + y = origin_extents.y_advance; + cairo_matrix_transform_point (font_matrix, + &x, &y); + x_pos = glyphs[i].x + x; + y_pos = glyphs[i].y + y; + } + + extents->x_bearing = min_x - glyphs[0].x; + extents->y_bearing = min_y - glyphs[0].y; + extents->width = max_x - min_x; + extents->height = max_y - min_y; + extents->x_advance = x_pos - glyphs[0].x; + extents->y_advance = y_pos - glyphs[0].y; +} /* Now we implement functions to access a default global image & metrics * cache. @@ -398,7 +351,8 @@ _cairo_glyph_cache_hash (void *cache, void *key) ^ ((unsigned long) in->scale.matrix[0][0]) ^ ((unsigned long) in->scale.matrix[0][1]) ^ ((unsigned long) in->scale.matrix[1][0]) - ^ ((unsigned long) in->scale.matrix[1][1]) + ^ ((unsigned long) in->scale.matrix[1][1]) + ^ (in->flags * 1451) /* 1451 is just an abitrary prime */ ^ in->index; } @@ -412,6 +366,7 @@ _cairo_glyph_cache_keys_equal (void *cache, b = (cairo_glyph_cache_key_t *) k2; return (a->index == b->index) && (a->unscaled == b->unscaled) + && (a->flags == b->flags) && (a->scale.matrix[0][0] == b->scale.matrix[0][0]) && (a->scale.matrix[0][1] == b->scale.matrix[0][1]) && (a->scale.matrix[1][0] == b->scale.matrix[1][0]) diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c index b928b04fc..44e1b0e84 100644 --- a/src/cairo_ft_font.c +++ b/src/cairo_ft_font.c @@ -1,29 +1,40 @@ -/* - * Copyright © 2003 Red Hat Inc. +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and that - * both that copyright notice and this permission notice appear in - * supporting documentation, and that the name of Red Hat Inc. not be used - * in advertising or publicity pertaining to distribution of the software - * without specific, written prior permission. Red Hat Inc. makes no - * representations about the suitability of this software for any purpose. - * It is provided "as is" without express or implied warranty. + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * RED HAT INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL RED HAT INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. * - * Author: Graydon Hoare <graydon@redhat.com> + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Graydon Hoare <graydon@redhat.com> + * Owen Taylor <otaylor@redhat.com> */ -#include "cairoint.h" -#include "cairo-ft.h" +#include "cairo-ft-private.h" #include <fontconfig/fontconfig.h> #include <fontconfig/fcfreetype.h> @@ -38,19 +49,9 @@ #define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) #define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) -/* - * First we make a private, sharable implementation object which can be - * stored both in a private cache and in public font objects (including - * those connected to fonts we don't own) +/* This is the max number of FT_face objects we keep open at once */ - -typedef struct { - int refcount; - - FT_Face face; - int owns_face; - -} ft_font_val_t; +#define MAX_OPEN_FACES 10 /* * The simple 2x2 matrix is converted into separate scale and shape @@ -62,141 +63,126 @@ typedef struct { double shape[2][2]; } ft_font_transform_t; -static ft_font_val_t * -_create_from_face (FT_Face face, int owns_face) -{ - ft_font_val_t *tmp = malloc (sizeof(ft_font_val_t)); - if (tmp) { - tmp->refcount = 1; - tmp->face = face; - tmp->owns_face = owns_face; - FT_Set_Char_Size (face, - DOUBLE_TO_26_6 (1.0), - DOUBLE_TO_26_6 (1.0), - 0, 0); - } - return tmp; -} +/* + * We create an object that corresponds to a single font on the disk; + * (identified by a filename/id pair) these are shared between all + * fonts using that file. For cairo_ft_font_create_for_ft_face(), we + * just create a one-off version with a permanent face value. + */ -static void -_reference_font_val (ft_font_val_t *f) -{ - f->refcount++; -} +typedef struct { + cairo_unscaled_font_t base; -static void -_destroy_font_val (ft_font_val_t *f) -{ - if (--(f->refcount) > 0) - return; + int from_face; /* from cairo_ft_font_create_for_ft_face()? */ + FT_Face face; /* provided or cached face */ - if (f->owns_face) - FT_Done_Face (f->face); + /* only set if from_face is false */ + FT_Library library; + char *filename; + int id; - free (f); -} + /* We temporarily scale the unscaled font as neede */ + int have_scale; + cairo_font_scale_t current_scale; + double x_scale; /* Extracted X scale factor */ + double y_scale; /* Extracted Y scale factor */ + + int lock; /* count of how many times this font has been locked */ +} ft_unscaled_font_t; -static ft_font_val_t * -_create_from_library_and_pattern (FT_Library ft_library, FcPattern *pattern) -{ - ft_font_val_t *f = NULL; - char *filename = NULL; - int owns_face = 0; - FT_Face face = NULL; - FcPattern *resolved = NULL; - FcResult result = FcResultMatch; +const cairo_font_backend_t cairo_ft_font_backend; - if (pattern == NULL) - goto FAIL; +static ft_unscaled_font_t * +_ft_unscaled_font_create_from_face (FT_Face face) +{ + ft_unscaled_font_t *unscaled = malloc (sizeof(ft_unscaled_font_t)); + if (!unscaled) + return NULL; + + unscaled->from_face = 1; + unscaled->face = face; - FcConfigSubstitute (0, pattern, FcMatchPattern); - FcDefaultSubstitute (pattern); + unscaled->library = NULL; + unscaled->filename = NULL; + unscaled->id = 0; - resolved = FcFontMatch (0, pattern, &result); - if (!resolved) - goto FAIL; + unscaled->have_scale = 0; + unscaled->lock = 0; - if (result != FcResultMatch) - goto FREE_RESOLVED; + _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled, + &cairo_ft_font_backend); + return unscaled; +} + +static ft_unscaled_font_t * +_ft_unscaled_font_create_from_filename (FT_Library library, + const char *filename, + int id) +{ + ft_unscaled_font_t *unscaled; + char *new_filename; - /* If the pattern has an FT_Face object, use that. */ - if (FcPatternGetFTFace (resolved, FC_FT_FACE, 0, &face) != FcResultMatch - || face == NULL) - { - /* otherwise it had better have a filename */ - result = FcPatternGetString (resolved, FC_FILE, 0, (FcChar8 **)(&filename)); - - if (result == FcResultMatch) - if (FT_New_Face (ft_library, filename, 0, &face)) - goto FREE_RESOLVED; - - if (face == NULL) - goto FREE_RESOLVED; - - owns_face = 1; + new_filename = strdup (filename); + if (!new_filename) + return NULL; + + unscaled = malloc (sizeof (ft_unscaled_font_t)); + if (!unscaled) { + free (new_filename); + return NULL; } + + unscaled->from_face = 0; + unscaled->face = NULL; - f = _create_from_face (face, owns_face); - - FcPatternDestroy (resolved); - return f; + unscaled->library = library; + unscaled->filename = new_filename; + unscaled->id = id; - FREE_RESOLVED: - if (resolved) - FcPatternDestroy (resolved); - - FAIL: - return NULL; + unscaled->have_scale = 0; + unscaled->lock = 0; + + _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled, + &cairo_ft_font_backend); + return unscaled; } - -/* - * We then make the user-exposed structure out of one of these impls, such - * that it is reasonably cheap to copy and/or destroy. Unfortunately this - * duplicates a certain amount of the caching machinery in the font cache, - * but that's unavoidable as we also provide an FcPattern resolution API, - * which is not part of cairo's generic font finding system. - */ - -typedef struct { - cairo_unscaled_font_t base; - FcPattern *pattern; - ft_font_val_t *val; -} cairo_ft_font_t; - -/* - * We then make a key and entry type which are compatible with the generic - * cache system. This cache serves to share single ft_font_val_t instances - * between fonts (or between font lifecycles). +/* + * We keep a global cache from [file/id] => [ft_unscaled_font_t]. This + * hash isn't limited in size. However, we limit the number of + * FT_Face objects we keep around; when we've exceeeded that + * limit and need to create a new FT_Face, we dump the FT_Face from + * a random ft_unscaled_font_t. */ typedef struct { cairo_cache_entry_base_t base; - FcPattern *pattern; + char *filename; + int id; } cairo_ft_cache_key_t; typedef struct { cairo_ft_cache_key_t key; - ft_font_val_t *val; + ft_unscaled_font_t *unscaled; } cairo_ft_cache_entry_t; -/* - * Then we create a cache which maps FcPattern keys to the refcounted - * ft_font_val_t values. - */ - typedef struct { cairo_cache_t base; FT_Library lib; + int n_faces; /* Number of open FT_Face objects */ } ft_cache_t; - static unsigned long _ft_font_cache_hash (void *cache, void *key) { - cairo_ft_cache_key_t *in; - in = (cairo_ft_cache_key_t *) key; - return FcPatternHash (in->pattern); + cairo_ft_cache_key_t *in = (cairo_ft_cache_key_t *) key; + unsigned long hash; + + /* 1607 is just a random prime. */ + hash = _cairo_hash_string (in->filename); + hash += ((unsigned long) in->id) * 1607; + + return hash; } static int @@ -208,10 +194,10 @@ _ft_font_cache_keys_equal (void *cache, cairo_ft_cache_key_t *b; a = (cairo_ft_cache_key_t *) k1; b = (cairo_ft_cache_key_t *) k2; - - return FcPatternEqual (a->pattern, b->pattern); -} + return strcmp (a->filename, b->filename) == 0 && + a->id == b->id; +} static cairo_status_t _ft_font_cache_create_entry (void *cache, @@ -226,27 +212,33 @@ _ft_font_cache_create_entry (void *cache, if (entry == NULL) return CAIRO_STATUS_NO_MEMORY; - entry->key.pattern = FcPatternDuplicate (k->pattern); - if (!entry->key.pattern) { + entry->unscaled = _ft_unscaled_font_create_from_filename (ftcache->lib, + k->filename, + k->id); + if (!entry->unscaled) { free (entry); return CAIRO_STATUS_NO_MEMORY; } - - entry->val = _create_from_library_and_pattern (ftcache->lib, entry->key.pattern); - entry->key.base.memory = 1; - + + entry->key.base.memory = 0; + entry->key.filename = entry->unscaled->filename; + entry->key.id = entry->unscaled->id; + *return_entry = entry; return CAIRO_STATUS_SUCCESS; } +/* Entries are never spontaneously destroyed; but only when + * we remove them from the cache specifically. We free entry->unscaled + * in the code that removes the entry from the cache + */ static void _ft_font_cache_destroy_entry (void *cache, void *entry) { cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry; - FcPatternDestroy (e->key.pattern); - _destroy_font_val (e->val); + free (e); } @@ -291,11 +283,12 @@ _get_global_ft_cache (void) if (_cairo_cache_init (&_global_ft_cache->base, &_ft_font_cache_backend, - CAIRO_FT_CACHE_NUM_FONTS_DEFAULT)) + 0)) /* No memory limit */ goto FAIL; if (FT_Init_FreeType (&_global_ft_cache->lib)) goto FAIL; + _global_ft_cache->n_faces = 0; } return &_global_ft_cache->base; @@ -306,30 +299,304 @@ _get_global_ft_cache (void) return NULL; } -/* implement the backend interface */ +/* Finds or creates a ft_unscaled_font for the filename/id from pattern. + * Returns a new reference to the unscaled font. + */ +static ft_unscaled_font_t * +_ft_unscaled_font_get_for_pattern (FcPattern *pattern) +{ + cairo_ft_cache_entry_t *entry; + cairo_ft_cache_key_t key; + cairo_cache_t *cache; + cairo_status_t status; + FcChar8 *filename; + int created_entry; + + if (FcPatternGetString (pattern, FC_FILE, 0, &filename) != FcResultMatch) + return NULL; + key.filename = (char *)filename; + + if (FcPatternGetInteger (pattern, FC_INDEX, 0, &key.id) != FcResultMatch) + return NULL; + + _lock_global_ft_cache (); + cache = _get_global_ft_cache (); + if (cache == NULL) { + _unlock_global_ft_cache (); + return NULL; + } + + status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry); + _unlock_global_ft_cache (); + if (status) + return NULL; + + if (!created_entry) + _cairo_unscaled_font_reference ((cairo_unscaled_font_t *)entry->unscaled); + + return entry->unscaled; +} + +static int +_has_unlocked_face (void *entry) +{ + cairo_ft_cache_entry_t *e = entry; -const cairo_font_backend_t cairo_ft_font_backend; + return (e->unscaled->lock == 0 && e->unscaled->face); +} + +/* Ensures that an unscaled font has a face object. If we exceed + * MAX_OPEN_FACES, try to close some. + */ +static FT_Face +_ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled) +{ + ft_cache_t *ftcache; + FT_Face face = NULL; + + if (unscaled->face) { + unscaled->lock++; + return unscaled->face; + } -static cairo_unscaled_font_t * -_cairo_ft_font_create (const char *family, + assert (!unscaled->from_face); + + _lock_global_ft_cache (); + ftcache = (ft_cache_t *) _get_global_ft_cache (); + assert (ftcache != NULL); + + while (ftcache->n_faces >= MAX_OPEN_FACES) { + cairo_ft_cache_entry_t *entry; + + entry = _cairo_cache_random_entry ((cairo_cache_t *)ftcache, _has_unlocked_face); + if (entry) { + FT_Done_Face (entry->unscaled->face); + entry->unscaled->face = NULL; + entry->unscaled->have_scale = 0; + ftcache->n_faces--; + } else { + break; + } + } + + if (FT_New_Face (ftcache->lib, + unscaled->filename, + unscaled->id, + &face) != FT_Err_Ok) + goto FAIL; + + unscaled->face = face; + unscaled->lock++; + ftcache->n_faces++; + + FAIL: + _unlock_global_ft_cache (); + return face; +} + +/* Unlock unscaled font locked with _ft_unscaled_font_lock_face + */ +static void +_ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled) +{ + assert (unscaled->lock > 0); + + unscaled->lock--; +} + +static void +_compute_transform (ft_font_transform_t *sf, + cairo_font_scale_t *sc) +{ + cairo_matrix_t normalized; + double tx, ty; + + /* The font matrix has x and y "scale" components which we extract and + * use as character scale values. These influence the way freetype + * chooses hints, as well as selecting different bitmaps in + * hand-rendered fonts. We also copy the normalized matrix to + * freetype's transformation. + */ + + cairo_matrix_set_affine (&normalized, + sc->matrix[0][0], + sc->matrix[0][1], + sc->matrix[1][0], + sc->matrix[1][1], + 0, 0); + + _cairo_matrix_compute_scale_factors (&normalized, + &sf->x_scale, &sf->y_scale, + /* XXX */ 1); + cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale); + cairo_matrix_get_affine (&normalized, + &sf->shape[0][0], &sf->shape[0][1], + &sf->shape[1][0], &sf->shape[1][1], + &tx, &ty); +} + +/* Temporarily scales an unscaled font to the give scale. We catch + * scaling to the same size, since changing a FT_Face is expensive. + */ +static void +_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled, + cairo_font_scale_t *scale) +{ + ft_font_transform_t sf; + FT_Matrix mat; + + assert (unscaled->face != NULL); + + if (unscaled->have_scale && + scale->matrix[0][0] == unscaled->current_scale.matrix[0][0] && + scale->matrix[0][1] == unscaled->current_scale.matrix[0][1] && + scale->matrix[1][0] == unscaled->current_scale.matrix[1][0] && + scale->matrix[1][1] == unscaled->current_scale.matrix[1][1]) + return; + + unscaled->have_scale = 1; + unscaled->current_scale = *scale; + + _compute_transform (&sf, scale); + + unscaled->x_scale = sf.x_scale; + unscaled->y_scale = sf.y_scale; + + mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]); + mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]); + mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]); + mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]); + + FT_Set_Transform(unscaled->face, &mat, NULL); + + FT_Set_Pixel_Sizes(unscaled->face, + (FT_UInt) sf.x_scale, + (FT_UInt) sf.y_scale); +} + +/* implement the font backend interface */ + +typedef struct { + cairo_font_t base; + FcPattern *pattern; + int load_flags; + ft_unscaled_font_t *unscaled; +} cairo_ft_font_t; + +/* for compatibility with older freetype versions */ +#ifndef FT_LOAD_TARGET_MONO +#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME +#endif + +/* The load flags passed to FT_Load_Glyph control aspects like hinting and + * antialiasing. Here we compute them from the fields of a FcPattern. + */ +static int +_get_load_flags (FcPattern *pattern) +{ + FcBool antialias, hinting, autohint; +#ifdef FC_HINT_STYLE + int hintstyle; +#endif + int load_flags = 0; + + /* disable antialiasing if requested */ + if (FcPatternGetBool (pattern, + FC_ANTIALIAS, 0, &antialias) != FcResultMatch) + antialias = FcTrue; + + if (antialias) + load_flags |= FT_LOAD_NO_BITMAP; + else + load_flags |= FT_LOAD_TARGET_MONO; + + /* disable hinting if requested */ + if (FcPatternGetBool (pattern, + FC_HINTING, 0, &hinting) != FcResultMatch) + hinting = FcTrue; + +#ifdef FC_HINT_STYLE + if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) + hintstyle = FC_HINT_FULL; + + if (!hinting || hintstyle == FC_HINT_NONE) + load_flags |= FT_LOAD_NO_HINTING; + + switch (hintstyle) { + case FC_HINT_SLIGHT: + case FC_HINT_MEDIUM: + load_flags |= FT_LOAD_TARGET_LIGHT; + break; + default: + load_flags |= FT_LOAD_TARGET_NORMAL; + break; + } +#else /* !FC_HINT_STYLE */ + if (!hinting) + load_flags |= FT_LOAD_NO_HINTING; +#endif /* FC_FHINT_STYLE */ + + /* force autohinting if requested */ + if (FcPatternGetBool (pattern, + FC_AUTOHINT, 0, &autohint) != FcResultMatch) + autohint = FcFalse; + + if (autohint) + load_flags |= FT_LOAD_FORCE_AUTOHINT; + + return load_flags; +} + +/* Like the public cairo_ft_font_create, but takes a cairo_font_scale_t, + * rather than a cairo_font_t + */ +static cairo_font_t * +_ft_font_create (FcPattern *pattern, + cairo_font_scale_t *scale) +{ + cairo_ft_font_t *f = NULL; + ft_unscaled_font_t *unscaled = NULL; + + unscaled = _ft_unscaled_font_get_for_pattern (pattern); + if (unscaled == NULL) + return NULL; + + f = malloc (sizeof(cairo_ft_font_t)); + if (f == NULL) + goto FREE_UNSCALED; + + f->unscaled = unscaled; + f->pattern = pattern; + FcPatternReference (pattern); + f->load_flags = _get_load_flags (pattern); + + _cairo_font_init ((cairo_font_t *)f, scale, &cairo_ft_font_backend); + + return (cairo_font_t *)f; + + FREE_UNSCALED: + _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled); + + return NULL; +} + +static cairo_status_t +_cairo_ft_font_create (const char *family, cairo_font_slant_t slant, - cairo_font_weight_t weight) + cairo_font_weight_t weight, + cairo_font_scale_t *scale, + cairo_font_t **font) { - cairo_status_t status; - cairo_ft_font_t *font = NULL; + FcPattern *pattern, *resolved; + cairo_font_t *new_font; + FcResult result; int fcslant; int fcweight; - cairo_cache_t *cache; - cairo_ft_cache_entry_t *entry; - cairo_ft_cache_key_t key; - - key.pattern = FcPatternCreate (); - if (key.pattern == NULL) - goto FAIL; + ft_font_transform_t sf; - font = malloc (sizeof (cairo_ft_font_t)); - if (font == NULL) - goto FREE_PATTERN; + pattern = FcPatternCreate (); + if (!pattern) + return CAIRO_STATUS_NO_MEMORY; switch (weight) { @@ -356,46 +623,44 @@ _cairo_ft_font_create (const char *family, break; } - FcPatternAddString (key.pattern, FC_FAMILY, family); - FcPatternAddInteger (key.pattern, FC_SLANT, fcslant); - FcPatternAddInteger (key.pattern, FC_WEIGHT, fcweight); - - if (_cairo_unscaled_font_init (&font->base, &cairo_ft_font_backend)) + if (!FcPatternAddString (pattern, FC_FAMILY, family)) goto FREE_PATTERN; - - _lock_global_ft_cache (); - cache = _get_global_ft_cache (); - if (cache == NULL) { - _unlock_global_ft_cache (); + if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) + goto FREE_PATTERN; + if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) goto FREE_PATTERN; - } - status = _cairo_cache_lookup (cache, &key, (void **) &entry); - _unlock_global_ft_cache (); + _compute_transform (&sf, scale); - if (status) - goto FREE_PATTERN; + FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale); - font->pattern = FcPatternDuplicate (entry->key.pattern); - if (font->pattern == NULL) + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + FcDefaultSubstitute (pattern); + + resolved = FcFontMatch (NULL, pattern, &result); + if (!resolved) goto FREE_PATTERN; - font->val = entry->val; - _reference_font_val (font->val); - - return &font->base; + new_font = _ft_font_create (resolved, scale); - FREE_PATTERN: - FcPatternDestroy (key.pattern); + FcPatternDestroy (resolved); + FcPatternDestroy (pattern); - FAIL: - return NULL; + if (new_font) { + *font = new_font; + return CAIRO_STATUS_SUCCESS; + } else { + return CAIRO_STATUS_NO_MEMORY; /* A guess */ + } -} + FREE_PATTERN: + FcPatternDestroy (pattern); + return CAIRO_STATUS_NO_MEMORY; +} static void -_cairo_ft_font_destroy (void *abstract_font) +_cairo_ft_font_destroy_font (void *abstract_font) { cairo_ft_font_t * font = abstract_font; @@ -405,179 +670,94 @@ _cairo_ft_font_destroy (void *abstract_font) if (font->pattern != NULL) FcPatternDestroy (font->pattern); - _destroy_font_val (font->val); + _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)font->unscaled); free (font); } static void -_utf8_to_ucs4 (char const *utf8, - FT_ULong **ucs4, - int *nchars) +_cairo_ft_font_destroy_unscaled_font (void *abstract_font) { - int len = 0, step = 0; - int n = 0, alloc = 0; - FcChar32 u = 0; + ft_unscaled_font_t *unscaled = abstract_font; - if (utf8 == NULL || ucs4 == NULL || nchars == NULL) - return; + if (!unscaled->from_face) { + cairo_cache_t *cache; + cairo_ft_cache_key_t key; + + _lock_global_ft_cache (); + cache = _get_global_ft_cache (); + assert (cache); - len = strlen (utf8); - alloc = len; - *ucs4 = malloc (sizeof (FT_ULong) * alloc); - if (*ucs4 == NULL) - return; - - while (len && (step = FcUtf8ToUcs4(utf8, &u, len)) > 0) - { - if (n == alloc) - { - alloc *= 2; - *ucs4 = realloc (*ucs4, sizeof (FT_ULong) * alloc); - if (*ucs4 == NULL) - return; - } - (*ucs4)[n++] = u; - len -= step; - utf8 += step; + key.filename = unscaled->filename; + key.id = unscaled->id; + + _cairo_cache_remove (cache, &key); + + _unlock_global_ft_cache (); } - *nchars = n; -} - -/* - * Split a matrix into the component pieces of scale and shape - */ - -static void -_cairo_ft_font_compute_transform (ft_font_transform_t *sf, cairo_font_scale_t *sc) -{ - cairo_matrix_t normalized; - double tx, ty; - /* The font matrix has x and y "scale" components which we extract and - * use as character scale values. These influence the way freetype - * chooses hints, as well as selecting different bitmaps in - * hand-rendered fonts. We also copy the normalized matrix to - * freetype's transformation. - */ - - cairo_matrix_set_affine (&normalized, - sc->matrix[0][0], - sc->matrix[0][1], - sc->matrix[1][0], - sc->matrix[1][1], - 0, 0); - - _cairo_matrix_compute_scale_factors (&normalized, - &sf->x_scale, &sf->y_scale, - /* XXX */ 1); - cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale); - cairo_matrix_get_affine (&normalized, - &sf->shape[0][0], &sf->shape[0][1], - &sf->shape[1][0], &sf->shape[1][1], - &tx, &ty); -} - -/* - * Set the font transformation - */ - -static void -_cairo_ft_font_install_transform (ft_font_transform_t *sf, FT_Face face) -{ - FT_Matrix mat; - - mat.xx = DOUBLE_TO_16_16(sf->shape[0][0]); - mat.yx = -DOUBLE_TO_16_16(sf->shape[0][1]); - mat.xy = -DOUBLE_TO_16_16(sf->shape[1][0]); - mat.yy = DOUBLE_TO_16_16(sf->shape[1][1]); + if (unscaled == NULL) + return; - FT_Set_Transform(face, &mat, NULL); + if (!unscaled->from_face && unscaled->face) + FT_Done_Face (unscaled->face); - FT_Set_Char_Size(face, - (FT_F26Dot6) (sf->x_scale * 64.0), - (FT_F26Dot6) (sf->y_scale * 64.0), - 0, 0); + if (unscaled->filename) + free (unscaled->filename); + + free (unscaled); } static void -_install_font_scale (cairo_font_scale_t *sc, FT_Face face) +_cairo_ft_font_get_glyph_cache_key (void *abstract_font, + cairo_glyph_cache_key_t *key) { - cairo_matrix_t normalized; - double x_scale, y_scale; - double xx, xy, yx, yy, tx, ty; - FT_Matrix mat; - - /* The font matrix has x and y "scale" components which we extract and - * use as character scale values. These influence the way freetype - * chooses hints, as well as selecting different bitmaps in - * hand-rendered fonts. We also copy the normalized matrix to - * freetype's transformation. - */ - - cairo_matrix_set_affine (&normalized, - sc->matrix[0][0], - sc->matrix[0][1], - sc->matrix[1][0], - sc->matrix[1][1], - 0, 0); - - _cairo_matrix_compute_scale_factors (&normalized, &x_scale, &y_scale, - /* XXX */ 1); - cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale); - cairo_matrix_get_affine (&normalized, - &xx /* 00 */ , &yx /* 01 */, - &xy /* 10 */, &yy /* 11 */, - &tx, &ty); - - mat.xx = DOUBLE_TO_16_16(xx); - mat.xy = -DOUBLE_TO_16_16(xy); - mat.yx = -DOUBLE_TO_16_16(yx); - mat.yy = DOUBLE_TO_16_16(yy); - - FT_Set_Transform(face, &mat, NULL); + cairo_ft_font_t *font = abstract_font; - FT_Set_Pixel_Sizes(face, - (FT_UInt) x_scale, - (FT_UInt) y_scale); + key->unscaled = (cairo_unscaled_font_t *)font->unscaled; + key->scale = font->base.scale; + key->flags = font->load_flags; } static cairo_status_t _cairo_ft_font_text_to_glyphs (void *abstract_font, - cairo_font_scale_t *sc, const unsigned char *utf8, cairo_glyph_t **glyphs, int *nglyphs) { double x = 0., y = 0.; size_t i; - FT_ULong *ucs4 = NULL; + uint32_t *ucs4 = NULL; cairo_ft_font_t *font = abstract_font; - FT_Face face = font->val->face; + FT_Face face; cairo_glyph_cache_key_t key; cairo_image_glyph_cache_entry_t *val; - cairo_cache_t *cache; + cairo_cache_t *cache = NULL; + cairo_status_t status = CAIRO_STATUS_SUCCESS; - key.unscaled = &font->base; - key.scale = *sc; + _cairo_ft_font_get_glyph_cache_key (font, &key); - _utf8_to_ucs4 (utf8, &ucs4, nglyphs); - - if (ucs4 == NULL) - return CAIRO_STATUS_NO_MEMORY; + status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, nglyphs); + if (!CAIRO_OK (status)) + return status; - *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t))); - if (*glyphs == NULL) - { - free (ucs4); - return CAIRO_STATUS_NO_MEMORY; + face = cairo_ft_font_lock_face ((cairo_font_t *)font); + if (!face) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL1; } _cairo_lock_global_image_glyph_cache (); cache = _cairo_get_global_image_glyph_cache (); if (cache == NULL) { - _cairo_unlock_global_image_glyph_cache (); - return CAIRO_STATUS_NO_MEMORY; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; + } + + *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t))); + if (*glyphs == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; } for (i = 0; i < *nglyphs; i++) @@ -589,51 +769,62 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font, val = NULL; key.index = (*glyphs)[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &val) + if (_cairo_cache_lookup (cache, &key, (void **) &val, NULL) != CAIRO_STATUS_SUCCESS || val == NULL) continue; x += val->extents.x_advance; y += val->extents.y_advance; } - _cairo_unlock_global_image_glyph_cache (); + FAIL2: + if (cache) + _cairo_unlock_global_image_glyph_cache (); + + cairo_ft_font_unlock_face ((cairo_font_t *)font); + + FAIL1: free (ucs4); - return CAIRO_STATUS_SUCCESS; + + return status; } static cairo_status_t _cairo_ft_font_font_extents (void *abstract_font, - cairo_font_scale_t *sc, cairo_font_extents_t *extents) { cairo_ft_font_t *font = abstract_font; - FT_Face face = font->val->face; - FT_Size_Metrics *metrics = &face->size->metrics; - ft_font_transform_t sf; + FT_Face face; + FT_Size_Metrics *metrics; + + face = _ft_unscaled_font_lock_face (font->unscaled); + if (!face) + return CAIRO_STATUS_NO_MEMORY; - _cairo_ft_font_compute_transform (&sf, sc); - _cairo_ft_font_install_transform (&sf, face); + metrics = &face->size->metrics; + _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale); + /* * Get to unscaled metrics so that the upper level can get back to * user space */ - extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / sf.y_scale; - extents->descent = DOUBLE_FROM_26_6(metrics->descender) / sf.y_scale; - extents->height = DOUBLE_FROM_26_6(metrics->height) / sf.y_scale; - extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / sf.x_scale; + extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / font->unscaled->y_scale; + extents->descent = DOUBLE_FROM_26_6(metrics->descender) / font->unscaled->y_scale; + extents->height = DOUBLE_FROM_26_6(metrics->height) / font->unscaled->y_scale; + extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / font->unscaled->x_scale; /* FIXME: this doesn't do vertical layout atm. */ extents->max_y_advance = 0.0; + _ft_unscaled_font_unlock_face (font->unscaled); + return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_ft_font_glyph_extents (void *abstract_font, - cairo_font_scale_t *sc, cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents) @@ -670,14 +861,13 @@ _cairo_ft_font_glyph_extents (void *abstract_font, return CAIRO_STATUS_NO_MEMORY; } - key.unscaled = &font->base; - key.scale = *sc; + _cairo_ft_font_get_glyph_cache_key (font, &key); for (i = 0; i < num_glyphs; i++) { img = NULL; key.index = glyphs[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &img) + if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL) != CAIRO_STATUS_SUCCESS || img == NULL) continue; @@ -721,7 +911,6 @@ _cairo_ft_font_glyph_extents (void *abstract_font, static cairo_status_t _cairo_ft_font_glyph_bbox (void *abstract_font, - cairo_font_scale_t *sc, const cairo_glyph_t *glyphs, int num_glyphs, cairo_box_t *bbox) @@ -747,16 +936,15 @@ _cairo_ft_font_glyph_bbox (void *abstract_font, return CAIRO_STATUS_NO_MEMORY; } - key.unscaled = &font->base; - key.scale = *sc; - + _cairo_ft_font_get_glyph_cache_key (font, &key); + for (i = 0; i < num_glyphs; i++) { img = NULL; key.index = glyphs[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &img) + if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL) != CAIRO_STATUS_SUCCESS || img == NULL) continue; @@ -785,12 +973,15 @@ _cairo_ft_font_glyph_bbox (void *abstract_font, static cairo_status_t _cairo_ft_font_show_glyphs (void *abstract_font, - cairo_font_scale_t *sc, cairo_operator_t operator, - cairo_surface_t *source, + cairo_pattern_t *pattern, cairo_surface_t *surface, int source_x, int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs) { @@ -798,9 +989,9 @@ _cairo_ft_font_show_glyphs (void *abstract_font, cairo_cache_t *cache; cairo_glyph_cache_key_t key; cairo_ft_font_t *font = abstract_font; + cairo_surface_pattern_t glyph_pattern; cairo_status_t status; - - double x, y; + int x, y; int i; _cairo_lock_global_image_glyph_cache (); @@ -808,47 +999,54 @@ _cairo_ft_font_show_glyphs (void *abstract_font, if (cache == NULL || font == NULL - || source == NULL + || pattern == NULL || surface == NULL || glyphs == NULL) { _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_NO_MEMORY; } - key.unscaled = &font->base; - key.scale = *sc; + key.unscaled = (cairo_unscaled_font_t *)font->unscaled; + key.scale = font->base.scale; + key.flags = font->load_flags; for (i = 0; i < num_glyphs; i++) { img = NULL; key.index = glyphs[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &img) + if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL) != CAIRO_STATUS_SUCCESS || img == NULL || img->image == NULL) continue; - x = glyphs[i].x; - y = glyphs[i].y; + x = (int) floor (glyphs[i].x + 0.5); + y = (int) floor (glyphs[i].y + 0.5); + + _cairo_pattern_init_for_surface (&glyph_pattern, &(img->image->base)); - status = _cairo_surface_composite (operator, source, - &(img->image->base), + status = _cairo_surface_composite (operator, pattern, + &glyph_pattern.base, surface, - source_x + x + img->size.x, - source_y + y + img->size.y, + x + img->size.x, + y + img->size.y, 0, 0, x + img->size.x, y + img->size.y, (double) img->size.width, (double) img->size.height); + _cairo_pattern_fini (&glyph_pattern.base); + if (status) { - _cairo_unlock_global_image_glyph_cache (); + _cairo_unlock_global_image_glyph_cache (); return status; } } + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_SUCCESS; } @@ -932,7 +1130,6 @@ _cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closur static cairo_status_t _cairo_ft_font_glyph_path (void *abstract_font, - cairo_font_scale_t *sc, cairo_glyph_t *glyphs, int num_glyphs, cairo_path_t *path) @@ -940,6 +1137,7 @@ _cairo_ft_font_glyph_path (void *abstract_font, int i; cairo_ft_font_t *font = abstract_font; FT_GlyphSlot glyph; + FT_Face face; FT_Error error; FT_Outline_Funcs outline_funcs = { _move_to, @@ -949,10 +1147,12 @@ _cairo_ft_font_glyph_path (void *abstract_font, 0, /* shift */ 0, /* delta */ }; + + face = cairo_ft_font_lock_face (abstract_font); + if (!face) + return CAIRO_STATUS_NO_MEMORY; - glyph = font->val->face->glyph; - - _install_font_scale (sc, font->val->face); + glyph = face->glyph; for (i = 0; i < num_glyphs; i++) { @@ -961,7 +1161,7 @@ _cairo_ft_font_glyph_path (void *abstract_font, 0, DOUBLE_TO_16_16 (-1.0), }; - error = FT_Load_Glyph (font->val->face, glyphs[i].index, FT_LOAD_DEFAULT); + error = FT_Load_Glyph (font->unscaled->face, glyphs[i].index, font->load_flags | FT_LOAD_NO_BITMAP); /* XXX: What to do in this error case? */ if (error) continue; @@ -977,32 +1177,39 @@ _cairo_ft_font_glyph_path (void *abstract_font, FT_Outline_Decompose (&glyph->outline, &outline_funcs, path); } _cairo_path_close_path (path); + + cairo_ft_font_unlock_face (abstract_font); return CAIRO_STATUS_SUCCESS; } - static cairo_status_t -_cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) +_cairo_ft_font_create_glyph (cairo_image_glyph_cache_entry_t *val) { - cairo_ft_font_t *font = (cairo_ft_font_t *)val->key.unscaled; + ft_unscaled_font_t *unscaled = (ft_unscaled_font_t *)val->key.unscaled; FT_GlyphSlot glyphslot; unsigned int width, height, stride; + FT_Face face; FT_Outline *outline; FT_BBox cbox; FT_Bitmap bitmap; FT_Glyph_Metrics *metrics; - ft_font_transform_t sf; + cairo_status_t status = CAIRO_STATUS_SUCCESS; - glyphslot = font->val->face->glyph; + glyphslot = unscaled->face->glyph; metrics = &glyphslot->metrics; - _cairo_ft_font_compute_transform (&sf, &val->key.scale); - _cairo_ft_font_install_transform (&sf, font->val->face); - - if (FT_Load_Glyph (font->val->face, val->key.index, FT_LOAD_DEFAULT) != 0) + face = _ft_unscaled_font_lock_face (unscaled); + if (!face) return CAIRO_STATUS_NO_MEMORY; + _ft_unscaled_font_set_scale (unscaled, &val->key.scale); + + if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } + /* * Note: the font's coordinate system is upside down from ours, so the * Y coordinates of the bearing and advance need to be negated. @@ -1011,11 +1218,11 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) * by FreeType */ - val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / sf.x_scale; - val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / sf.y_scale; + val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale; + val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale; - val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / sf.x_scale; - val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / sf.y_scale; + val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale; + val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale; /* * use untransformed advance values @@ -1023,8 +1230,8 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) should provide FT_LOAD_VERTICAL_LAYOUT */ - val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->metrics.horiAdvance) / sf.x_scale; - val->extents.y_advance = 0 / sf.y_scale; + val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale; + val->extents.y_advance = 0 / unscaled->y_scale; outline = &glyphslot->outline; @@ -1052,14 +1259,16 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) bitmap.buffer = calloc (1, stride * height); if (bitmap.buffer == NULL) { - return CAIRO_STATUS_NO_MEMORY; - }; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin); if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) { free (bitmap.buffer); - return CAIRO_STATUS_NO_MEMORY; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; } val->image = (cairo_image_surface_t *) @@ -1068,7 +1277,8 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) width, height, stride); if (val->image == NULL) { free (bitmap.buffer); - return CAIRO_STATUS_NO_MEMORY; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; } _cairo_image_surface_assume_ownership_of_data (val->image); @@ -1084,138 +1294,245 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) val->size.x = (short) (cbox.xMin >> 6); val->size.y = - (short) (cbox.yMax >> 6); - return CAIRO_STATUS_SUCCESS; + FAIL: + _ft_unscaled_font_unlock_face (unscaled); + + return status; } const cairo_font_backend_t cairo_ft_font_backend = { _cairo_ft_font_create, - _cairo_ft_font_destroy, + _cairo_ft_font_destroy_font, + _cairo_ft_font_destroy_unscaled_font, _cairo_ft_font_font_extents, _cairo_ft_font_text_to_glyphs, _cairo_ft_font_glyph_extents, _cairo_ft_font_glyph_bbox, _cairo_ft_font_show_glyphs, _cairo_ft_font_glyph_path, + _cairo_ft_font_get_glyph_cache_key, _cairo_ft_font_create_glyph }; - /* implement the platform-specific interface */ +/** + * cairo_ft_font_create: + * @pattern: A fully resolved fontconfig + * pattern. A pattern can be resolved, by, among other things, calling + * FcConfigSubstitute(), FcDefaultSubstitute(), then + * FcFontMatch(). Cairo will call FcPatternReference() on this + * pattern, so you should not further modify the pattern, but you can + * release your reference to the pattern with FcPatternDestroy() if + * you no longer need to access it. + * @scale: The scale at which this font will be used. The + * scale is given by multiplying the font matrix (see + * cairo_transform_font()) by the current transformation matrix. + * The translation elements of the resulting matrix are ignored. + * + * Creates a new font for the FreeType font backend based on a + * fontconfig pattern. This font can then be used with + * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend + * specific functions like cairo_ft_font_lock_face(). + * + * Return value: a newly created #cairo_font_t. Free with + * cairo_font_destroy() when you are done using it. + **/ cairo_font_t * -cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern) +cairo_ft_font_create (FcPattern *pattern, + cairo_matrix_t *scale) { - cairo_font_scale_t scale; - cairo_font_t *scaled; - cairo_ft_font_t *f = NULL; - ft_font_val_t *v = NULL; - FcPattern *dup; - - scale.matrix[0][0] = 1.; - scale.matrix[0][1] = 0.; - scale.matrix[1][0] = 0.; - scale.matrix[1][1] = 1.; - - scaled = malloc (sizeof (cairo_font_t)); - if (scaled == NULL) - goto FAIL; - - dup = FcPatternDuplicate(pattern); - if (dup == NULL) - goto FREE_SCALED; - - v = _create_from_library_and_pattern (ft_library, pattern); - if (v == NULL) - goto FREE_PATTERN; - - f = malloc (sizeof(cairo_ft_font_t)); - if (f == NULL) - goto FREE_VAL; - - if (_cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend)) - goto FREE_VAL; - - f->pattern = dup; - f->val = v; - - _cairo_font_init (scaled, &scale, &f->base); - - return scaled; - - FREE_VAL: - _destroy_font_val (v); - - FREE_PATTERN: - FcPatternDestroy (dup); + cairo_font_scale_t sc; + double tx, ty; - FREE_SCALED: - free (scaled); + cairo_matrix_get_affine (scale, + &sc.matrix[0][0], &sc.matrix[0][1], + &sc.matrix[1][0], &sc.matrix[1][1], + &tx, &ty); - FAIL: - return NULL; + return _ft_font_create (pattern, &sc); } +/** + * cairo_ft_font_create_for_ft_face: + * @face: A FreeType face object, already opened. This must + * be kept around until the font object's refcount drops to + * zero and it is freed. The font object can be kept alive by + * internal caching, so it's safest to keep the face object + * around forever. + * @load_flags: The flags to pass to FT_Load_Glyph when loading + * glyphs from the font. These flags control aspects of + * rendering such as hinting and antialiasing. See the FreeType + * docs for full information. + * @scale: The scale at which this font will be used. The + * scale is given by multiplying the font matrix (see + * cairo_transform_font()) by the current transformation matrix. + * The translation elements of the resulting matrix are ignored. + * + * Creates a new font forthe FreeType font backend from a pre-opened + * FreeType face. This font can then be used with cairo_set_font(), + * cairo_font_glyph_extents(), or FreeType backend specific + * functions like cairo_ft_font_lock_face() Cairo will determine the + * pixel size and transformation from the @scale parameter and call + * FT_Set_Transform() and FT_Set_Pixel_Sizes(). + * + * Return value: a newly created #cairo_font_t. Free with + * cairo_font_destroy() when you are done using it. + **/ cairo_font_t * -cairo_ft_font_create_for_ft_face (FT_Face face) +cairo_ft_font_create_for_ft_face (FT_Face face, + int load_flags, + cairo_matrix_t *scale) { - cairo_font_scale_t scale; - cairo_font_t *scaled; cairo_ft_font_t *f = NULL; - ft_font_val_t *v = NULL; - - scale.matrix[0][0] = 1.; - scale.matrix[0][1] = 0.; - scale.matrix[1][0] = 0.; - scale.matrix[1][1] = 1.; - - scaled = malloc (sizeof (cairo_font_t)); - if (scaled == NULL) - goto FAIL; + ft_unscaled_font_t *unscaled = NULL; + cairo_font_scale_t sc; + double tx, ty; - v = _create_from_face (face, 0); - if (v == NULL) - goto FREE_SCALED; + unscaled = _ft_unscaled_font_create_from_face (face); + if (unscaled == NULL) + return NULL; f = malloc (sizeof(cairo_ft_font_t)); if (f == NULL) - goto FREE_VAL; + goto FREE_UNSCALED; - _cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend); + f->unscaled = unscaled; f->pattern = NULL; - f->val = v; + f->load_flags = load_flags; - _cairo_font_init (scaled, &scale, &f->base); + cairo_matrix_get_affine (scale, + &sc.matrix[0][0], &sc.matrix[0][1], + &sc.matrix[1][0], &sc.matrix[1][1], + &tx, &ty); - return scaled; + _cairo_font_init ((cairo_font_t *)f, &sc, &cairo_ft_font_backend); - FREE_VAL: - _destroy_font_val (v); + return (cairo_font_t *)f; - FREE_SCALED: - free (scaled); + FREE_UNSCALED: + _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled); - FAIL: return NULL; } + +/** + * cairo_ft_font_lock_face: + * @ft_font: A #cairo_font_t from the FreeType font backend. Such an + * object can be created with cairo_ft_font_create() or + * cairo_ft_font_create_for_ft_face(). On some platforms the font from + * cairo_current_font() will also be a FreeType font, but using this + * functionality with fonts you don't create yourself is not + * recommended. + * + * cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType + * backend font and scales it appropriately for the font. You must + * release the face with cairo_ft_font_unlock_face() + * when you are done using it. Since the #FT_Face object can be + * shared between multiple #cairo_font_t objects, you must not + * lock any other font objects until you unlock this one. A count is + * kept of the number of times cairo_ft_font_lock_face() is + * called. cairo_ft_font_unlock_face() must be called the same number + * of times. + * + * You must be careful when using this function in a library or in a + * threaded application, because other threads may lock faces that + * share the same #FT_Face object. For this reason, you must call + * cairo_ft_lock() before locking any face objects, and + * cairo_ft_unlock() after you are done. (These functions are not yet + * implemented, so this function cannot be currently safely used in a + * threaded application.) + + * Return value: The #FT_Face object for @font, scaled appropriately. + **/ FT_Face -cairo_ft_font_face (cairo_font_t *abstract_font) +cairo_ft_font_lock_face (cairo_font_t *abstract_font) { - cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled; + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + FT_Face face; - if (font == NULL || font->val == NULL) - return NULL; + face = _ft_unscaled_font_lock_face (font->unscaled); + if (!face) + return NULL; + + _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale); + + return face; +} - return font->val->face; +/** + * cairo_ft_font_unlock_face: + * @ft_font: A #cairo_font_t from the FreeType font backend. Such an + * object can be created with cairo_ft_font_create() or + * cairo_ft_font_create_for_ft_face(). On some platforms the font from + * cairo_current_font() will also be a FreeType font, but using this + * functionality with fonts you don't create yourself is not + * recommended. + * + * Releases a face obtained with cairo_ft_font_lock_face(). See the + * documentation for that function for full details. + **/ +void +cairo_ft_font_unlock_face (cairo_font_t *abstract_font) +{ + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + + _ft_unscaled_font_unlock_face (font->unscaled); } +/** + * cairo_ft_font_get_pattern: + * @ft_font: A #cairo_font_t from the FreeType font backend. Such an + * object can be created with cairo_ft_font_create() or + * cairo_ft_font_create_for_ft_face(). On some platforms the font from + * cairo_current_font() will also be a FreeType font, but using this + * functionality with fonts you don't create yourself is not + * recommended. + * + * cairo_ft_font_get_pattern() gets the #FcPattern for a FreeType + * backend font. + + * Return value: The #FcPattenr for @font. The return value is owned + * by the font, so you must not modify it, and must call + * FcPatternReference() to keep a persistant reference to the + * pattern. If the font was created with cairo_ft_font_create_for_ft_face() + * returns %NULL. + **/ FcPattern * -cairo_ft_font_pattern (cairo_font_t *abstract_font) +cairo_ft_font_get_pattern (cairo_font_t *abstract_font) { - cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled; + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; if (font == NULL) return NULL; return font->pattern; } + +/* We expose our unscaled font implementation internally for the the + * PDF backend, which needs to keep track of the the different + * fonts-on-disk used by a document, so it can embed them. + */ +cairo_unscaled_font_t * +_cairo_ft_font_get_unscaled_font (cairo_font_t *abstract_font) +{ + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + + return (cairo_unscaled_font_t *)font->unscaled; +} + +/* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't + * set the scale on the face, but just returns it at the last scale. + */ +FT_Face +_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font) +{ + return _ft_unscaled_font_lock_face ((ft_unscaled_font_t *)unscaled_font); +} + +void +_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font) +{ + _ft_unscaled_font_unlock_face ((ft_unscaled_font_t *)unscaled_font); +} diff --git a/src/cairo_gdip_font.cpp b/src/cairo_gdip_font.cpp deleted file mode 100644 index e932e3bac..000000000 --- a/src/cairo_gdip_font.cpp +++ /dev/null @@ -1,665 +0,0 @@ -/* cairo - a vector graphics library with display and print output - * - * Copyright © 2004 Stuart Parmenter - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * The Original Code is the cairo graphics library. - * - * The Initial Developer of the Original Code is Stuart Parmenter. - * - * Contributor(s): - * Stuart Parmenter <pavlov@pavlov.net> - */ - -extern "C" { -#include "cairoint.h" -} - -#include <windows.h> - -#include <gdiplus.h> -using namespace Gdiplus; - -#if 0 -#include <fontconfig/fontconfig.h> -#include <fontconfig/fcfreetype.h> - -#include <ft2build.h> -#include FT_FREETYPE_H -#include FT_OUTLINE_H -#include FT_IMAGE_H -#endif - -typedef struct { - cairo_font_t base; - HDC hdc; - HFONT hfont; -} cairo_win32_font_t; - - - -static int -_utf8_to_glyphs (cairo_win32_font_t *font, - const unsigned char *utf8, - double x0, - double y0, - cairo_glyph_t **glyphs, - size_t *nglyphs) -{ - /* XXX implement me */ - *glyphs = NULL; - *nglyphs = 0; - - return 0; -} - -/* implement the platform-specific interface */ - -cairo_font_t * -cairo_win32_font_create (HFONT hfont) -{ - cairo_win32_font_t *f = (cairo_win32_font_t*)malloc(sizeof(cairo_win32_font_t)); - if (f == NULL) - return NULL; - - f->hfont = hfont; - - _cairo_font_init (&f->base, &cairo_win32_font_backend); - - return (cairo_font_t *) f; -} - -#if 0 -FT_Face -cairo_win32_font_face (cairo_font_t *abstract_font) -{ - cairo_win32_font_t *font = (cairo_win32_font_t *) abstract_font; - - if (font == NULL) - return NULL; - - return font->face; -} - -FcPattern * -cairo_win32_font_pattern (cairo_font_t *abstract_font) -{ - cairo_win32_font_t *font = (cairo_win32_font_t *) abstract_font; - - if (font == NULL) - return NULL; - - return font->pattern; -} -#endif - -/* implement the backend interface */ - -static cairo_font_t * -_cairo_win32_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight) -{ - int fontHeight = 60; // in Pixels in this case - int fontWidth = 0; - int italic = 0; - int bold = FW_REGULAR; - - switch (slant) { - case CAIRO_FONT_SLANT_ITALIC: - italic = 1; - case CAIRO_FONT_SLANT_OBLIQUE: - case CAIRO_FONT_SLANT_NORMAL: - default: - break; - } - - if (weight == CAIRO_FONT_WEIGHT_BOLD) - bold = FW_BOLD; - - HFONT hfont = CreateFont(fontHeight, // height of font - fontWidth, // average character width - 0, // angle of escapement - 0, // base-line orientation angle - bold, // font weight - italic, // italic attribute option - FALSE, // underline attribute option - FALSE, // strikeout attribute option - ANSI_CHARSET, // character set identifier - OUT_DEFAULT_PRECIS, // output precision - CLIP_DEFAULT_PRECIS, // clipping precision - ANTIALIASED_QUALITY, // output quality - FF_DONTCARE, // pitch and family - family); // typeface name - - return cairo_win32_font_create(hfont); -} - -static cairo_font_t * -_cairo_win32_font_copy (void *abstract_font) -{ - cairo_win32_font_t *font_new = NULL; - cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font; - - if (font->base.backend != &cairo_win32_font_backend) - return NULL; - - font_new = (cairo_win32_font_t *) cairo_win32_font_create(font->hfont); - if (font_new == NULL) - return NULL; - - return (cairo_font_t *) font_new; -} - -static void -_cairo_win32_font_destroy (void *abstract_font) -{ - cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font; - - //delete font->font; - - free (font); -} - -static cairo_status_t -_cairo_win32_font_font_extents (void *abstract_font, - cairo_font_extents_t *extents) -{ - cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font; - - TEXTMETRIC metrics; - GetTextMetrics(font->hdc, &metrics); - - extents->ascent = metrics.tmAscent; - extents->descent = metrics.tmDescent; - extents->height = metrics.tmHeight; - extents->max_x_advance = 0; /* XXX */ - extents->max_y_advance = 0; /* XXX */ - - -#if 0 - FT_Face face = font->face; - double scale_x, scale_y; - - double upm = face->units_per_EM; - - _cairo_matrix_compute_scale_factors (&font->base.matrix, &scale_x, &scale_y); - - extents->ascent = face->ascender / upm * scale_y; - extents->descent = face->descender / upm * scale_y; - extents->height = face->height / upm * scale_y; - extents->max_x_advance = face->max_advance_width / upm * scale_x; - extents->max_y_advance = face->max_advance_height / upm * scale_y; -#endif - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_win32_font_glyph_extents (void *abstract_font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents) -{ - cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font; - - int i; - for (i = 0; i < num_glyphs; ++i) { - GLYPHMETRICS metrics; - GetGlyphOutline(font->hdc, 'a', GGO_METRICS, &metrics, 0, NULL, NULL); - - extents->width += metrics.gmBlackBoxX; - extents->height += metrics.gmBlackBoxY; - /* metrics has: - UINT gmBlackBoxX; - UINT gmBlackBoxY; - POINT gmptGlyphOrigin; - short gmCellIncX; - short gmCellIncY; - - extents has: - double x_bearing; - double y_bearing; - double width; - double height; - double x_advance; - double y_advance; - */ - } - -#if 0 - int i; - cairo_win32_font_t *font = abstract_font; - cairo_point_double_t origin; - cairo_point_double_t glyph_min, glyph_max; - cairo_point_double_t total_min, total_max; - FT_Error error; - FT_Face face = font->face; - FT_GlyphSlot glyph = face->glyph; - FT_Glyph_Metrics *metrics = &glyph->metrics; - - if (num_glyphs == 0) - { - extents->x_bearing = 0.0; - extents->y_bearing = 0.0; - extents->width = 0.0; - extents->height = 0.0; - extents->x_advance = 0.0; - extents->y_advance = 0.0; - - return CAIRO_STATUS_SUCCESS; - } - - origin.x = glyphs[0].x; - origin.y = glyphs[0].y; - - _install_font_matrix (&font->base.matrix, face); - - for (i = 0; i < num_glyphs; i++) - { - error = FT_Load_Glyph (face, glyphs[i].index, FT_LOAD_DEFAULT); - /* XXX: What to do in this error case? */ - if (error) - continue; - - /* XXX: Need to add code here to check the font's FcPattern - for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y - instead. This will require that - cairo_win32_font_create_for_ft_face accept an - FcPattern. */ - glyph_min.x = glyphs[i].x + DOUBLE_FROM_26_6 (metrics->horiBearingX); - glyph_min.y = glyphs[i].y - DOUBLE_FROM_26_6 (metrics->horiBearingY); - glyph_max.x = glyph_min.x + DOUBLE_FROM_26_6 (metrics->width); - glyph_max.y = glyph_min.y + DOUBLE_FROM_26_6 (metrics->height); - - if (i==0) { - total_min = glyph_min; - total_max = glyph_max; - } else { - if (glyph_min.x < total_min.x) - total_min.x = glyph_min.x; - if (glyph_min.y < total_min.y) - total_min.y = glyph_min.y; - - if (glyph_max.x > total_max.x) - total_max.x = glyph_max.x; - if (glyph_max.y > total_max.y) - total_max.y = glyph_max.y; - } - } - - extents->x_bearing = total_min.x - origin.x; - extents->y_bearing = total_min.y - origin.y; - extents->width = total_max.x - total_min.x; - extents->height = total_max.y - total_min.y; - extents->x_advance = glyphs[i-1].x + DOUBLE_FROM_26_6 (metrics->horiAdvance) - origin.x; - extents->y_advance = glyphs[i-1].y + 0 - origin.y; -#endif - return CAIRO_STATUS_SUCCESS; -} - - -static cairo_status_t -_cairo_win32_font_text_extents (void *abstract_font, - const unsigned char *utf8, - cairo_text_extents_t *extents) -{ - cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font; - - cairo_glyph_t *glyphs; - size_t nglyphs; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - - if (_utf8_to_glyphs (font, utf8, 0, 0, &glyphs, &nglyphs)) - { - status = _cairo_win32_font_glyph_extents (font, glyphs, nglyphs, - extents); - free (glyphs); - } - - return status; -} - -static cairo_status_t -_cairo_win32_font_glyph_bbox (void *abstract_font, - cairo_surface_t *surface, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox) -{ - cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font; -#if 0 - cairo_surface_t *mask = NULL; - cairo_glyph_size_t size; - - cairo_fixed_t x1, y1, x2, y2; - int i; - - bbox->p1.x = bbox->p1.y = CAIRO_MAXSHORT << 16; - bbox->p2.x = bbox->p2.y = CAIRO_MINSHORT << 16; - - if (font == NULL - || surface == NULL - || glyphs == NULL) - return CAIRO_STATUS_NO_MEMORY; - - for (i = 0; i < num_glyphs; i++) - { - mask = _cairo_font_lookup_glyph (&font->base, surface, - &glyphs[i], &size); - if (mask == NULL) - continue; - - x1 = _cairo_fixed_from_double (glyphs[i].x + size.x); - y1 = _cairo_fixed_from_double (glyphs[i].y - size.y); - x2 = x1 + _cairo_fixed_from_double (size.width); - y2 = y1 + _cairo_fixed_from_double (size.height); - - if (x1 < bbox->p1.x) - bbox->p1.x = x1; - - if (y1 < bbox->p1.y) - bbox->p1.y = y1; - - if (x2 > bbox->p2.x) - bbox->p2.x = x2; - - if (y2 > bbox->p2.y) - bbox->p2.y = y2; - - if (mask) - cairo_surface_destroy (mask); - } -#endif - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_win32_font_text_bbox (void *abstract_font, - cairo_surface_t *surface, - double x0, - double y0, - const unsigned char *utf8, - cairo_box_t *bbox) -{ - cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font; - - cairo_glyph_t *glyphs; - size_t num_glyphs; - - if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) - { - cairo_status_t res; - res = _cairo_win32_font_glyph_bbox (font, surface, - glyphs, num_glyphs, bbox); - free (glyphs); - return res; - } - else - return CAIRO_STATUS_NO_MEMORY; -} - -static cairo_status_t -_cairo_win32_font_show_glyphs (void *abstract_font, - cairo_operator_t op, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - const cairo_glyph_t *glyphs, - int num_glyphs) -{ - cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font; -#if 0 - cairo_status_t status; - cairo_surface_t *mask = NULL; - cairo_glyph_size_t size; - - double x, y; - int i; - - if (font == NULL - || source == NULL - || surface == NULL - || glyphs == NULL) - return CAIRO_STATUS_NO_MEMORY; - - for (i = 0; i < num_glyphs; i++) - { - mask = _cairo_font_lookup_glyph (&font->base, surface, - &glyphs[i], &size); - if (mask == NULL) - continue; - - x = glyphs[i].x; - y = glyphs[i].y; - - status = _cairo_surface_composite (operator, source, mask, surface, - source_x + x + size.x, - source_y + y - size.y, - 0, 0, - x + size.x, - y - size.y, - (double) size.width, - (double) size.height); - - cairo_surface_destroy (mask); - - if (status) - return status; - } -#endif - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_win32_font_show_text (void *abstract_font, - cairo_operator_t op, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - double x0, - double y0, - const unsigned char *utf8) -{ - cairo_win32_font_t *font = (cairo_win32_font_t*)abstract_font; - - cairo_glyph_t *glyphs; - size_t num_glyphs; - - if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) - { - cairo_status_t res; - res = _cairo_win32_font_show_glyphs (font, op, - source, surface, - source_x, source_y, - glyphs, num_glyphs); - free (glyphs); - return res; - } - else - return CAIRO_STATUS_NO_MEMORY; -} - -static cairo_status_t -_cairo_win32_font_glyph_path (void *abstract_font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_t *path) -{ -#if 0 - int i; - cairo_win32_font_t *font = abstract_font; - FT_GlyphSlot glyph; - FT_Error error; - FT_Outline_Funcs outline_funcs = { - _move_to, - _line_to, - _conic_to, - _cubic_to, - 0, /* shift */ - 0, /* delta */ - }; - - glyph = font->face->glyph; - _install_font_matrix (&font->base.matrix, font->face); - - for (i = 0; i < num_glyphs; i++) - { - FT_Matrix invert_y = { - DOUBLE_TO_16_16 (1.0), 0, - 0, DOUBLE_TO_16_16 (-1.0), - }; - - error = FT_Load_Glyph (font->face, glyphs[i].index, FT_LOAD_DEFAULT); - /* XXX: What to do in this error case? */ - if (error) - continue; - /* XXX: Do we want to support bitmap fonts here? */ - if (glyph->format == ft_glyph_format_bitmap) - continue; - - /* Font glyphs have an inverted Y axis compared to cairo. */ - FT_Outline_Transform (&glyph->outline, &invert_y); - FT_Outline_Translate (&glyph->outline, - DOUBLE_TO_26_6(glyphs[i].x), - DOUBLE_TO_26_6(glyphs[i].y)); - FT_Outline_Decompose (&glyph->outline, &outline_funcs, path); - } - _cairo_path_close_path (path); -#endif - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_win32_font_text_path (void *abstract_font, - double x, - double y, - const unsigned char *utf8, - cairo_path_t *path) -{ -#if 0 - cairo_win32_font_t *font = abstract_font; - cairo_glyph_t *glyphs; - size_t nglyphs; - - if (_utf8_to_glyphs (font, utf8, x, y, &glyphs, &nglyphs)) - { - cairo_status_t res; - res = _cairo_win32_font_glyph_path (font, glyphs, nglyphs, path); - free (glyphs); - return res; - } - else -#endif - return CAIRO_STATUS_NO_MEMORY; -} - -static cairo_surface_t * -_cairo_win32_font_create_glyph (void *abstract_font, - const cairo_glyph_t *glyph, - cairo_glyph_size_t *return_size) -{ -#if 0 - cairo_win32_font_t *font = abstract_font; - cairo_image_surface_t *image; - FT_GlyphSlot glyphslot; - unsigned int width, height, stride; - FT_Outline *outline;s - FT_BBox cbox; - FT_Bitmap bitmap; - - glyphslot = font->face->glyph; - _install_font_matrix (&font->base.matrix, font->face); - - FT_Load_Glyph (font->face, glyph->index, FT_LOAD_DEFAULT); - - outline = &glyphslot->outline; - - FT_Outline_Get_CBox (outline, &cbox); - - cbox.xMin &= -64; - cbox.yMin &= -64; - cbox.xMax = (cbox.xMax + 63) & -64; - cbox.yMax = (cbox.yMax + 63) & -64; - - width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); - height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); - stride = (width + 3) & -4; - - bitmap.pixel_mode = ft_pixel_mode_grays; - bitmap.num_grays = 256; - bitmap.width = width; - bitmap.rows = height; - bitmap.pitch = stride; - - if (width * height == 0) - return NULL; - - bitmap.buffer = malloc (stride * height); - if (bitmap.buffer == NULL) - return NULL; - - memset (bitmap.buffer, 0x0, stride * height); - - FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin); - FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap); - - image = (cairo_image_surface_t *) - cairo_image_surface_create_for_data ((char *) bitmap.buffer, - CAIRO_FORMAT_A8, - width, height, stride); - if (image == NULL) { - free (bitmap.buffer); - return NULL; - } - - _cairo_image_surface_assume_ownership_of_data (image); - - return_size->width = (unsigned short) width; - return_size->height = (unsigned short) height; - return_size->x = (short) (cbox.xMin >> 6); - return_size->y = (short) (cbox.yMax >> 6); - - return &image->base; -#endif - return NULL; -} - -const struct cairo_font_backend cairo_win32_font_backend = { - _cairo_win32_font_create, - _cairo_win32_font_copy, - _cairo_win32_font_destroy, - _cairo_win32_font_font_extents, - _cairo_win32_font_text_extents, - _cairo_win32_font_glyph_extents, - _cairo_win32_font_text_bbox, - _cairo_win32_font_glyph_bbox, - _cairo_win32_font_show_text, - _cairo_win32_font_show_glyphs, - _cairo_win32_font_text_path, - _cairo_win32_font_glyph_path, - _cairo_win32_font_create_glyph -}; diff --git a/src/cairo_gdip_surface.cpp b/src/cairo_gdip_surface.cpp deleted file mode 100644 index ec1982b55..000000000 --- a/src/cairo_gdip_surface.cpp +++ /dev/null @@ -1,727 +0,0 @@ -/* cairo - a vector graphics library with display and print output - * - * Copyright © 2004 Stuart Parmenter - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * The Original Code is the cairo graphics library. - * - * The Initial Developer of the Original Code is Stuart Parmenter. - * - * Contributor(s): - * Stuart Parmenter <pavlov@pavlov.net> - */ - -extern "C" { -#include "cairoint.h" -} - -/* export symbols, for cairo.dll only */ - -#pragma comment(linker, "/EXPORT:_cairo_create") -#pragma comment(linker, "/EXPORT:_cairo_reference") -#pragma comment(linker, "/EXPORT:_cairo_destroy") -#pragma comment(linker, "/EXPORT:_cairo_save") -#pragma comment(linker, "/EXPORT:_cairo_restore") -#pragma comment(linker, "/EXPORT:_cairo_copy") -#pragma comment(linker, "/EXPORT:_cairo_set_target_surface") -#pragma comment(linker, "/EXPORT:_cairo_set_target_image") - -#ifdef CAIRO_HAS_PS_SURFACE -#pragma comment(linker, "/EXPORT:_cairo_set_target_ps") -#endif - -#ifdef CAIRO_HAS_PS_SURFACE -#pragma comment(linker, "/EXPORT:_cairo_set_target_pdf") -#endif - -#ifdef CAIRO_HAS_PNG_SURFACE -#pragma comment(linker, "/EXPORT:_cairo_set_target_png") -#endif - -#ifdef CAIRO_HAS_GL_SURFACE -#pragma comment(linker, "/EXPORT:_cairo_set_target_gl") -#endif - -#ifdef CAIRO_HAS_WIN32_SURFACE -#pragma comment(linker, "/EXPORT:_cairo_set_target_win32") -#endif - -#pragma comment(linker, "/EXPORT:_cairo_set_operator") -#pragma comment(linker, "/EXPORT:_cairo_set_rgb_color") -#pragma comment(linker, "/EXPORT:_cairo_set_pattern") -#pragma comment(linker, "/EXPORT:_cairo_set_alpha") -#pragma comment(linker, "/EXPORT:_cairo_set_tolerance") -#pragma comment(linker, "/EXPORT:_cairo_set_fill_rule") -#pragma comment(linker, "/EXPORT:_cairo_set_line_width") -#pragma comment(linker, "/EXPORT:_cairo_set_line_cap") -#pragma comment(linker, "/EXPORT:_cairo_set_line_join") -#pragma comment(linker, "/EXPORT:_cairo_set_dash") -#pragma comment(linker, "/EXPORT:_cairo_set_miter_limit") -#pragma comment(linker, "/EXPORT:_cairo_set_line_cap") - -#pragma comment(linker, "/EXPORT:_cairo_translate") -#pragma comment(linker, "/EXPORT:_cairo_scale") -#pragma comment(linker, "/EXPORT:_cairo_rotate") - -#pragma comment(linker, "/EXPORT:_cairo_concat_matrix") -#pragma comment(linker, "/EXPORT:_cairo_set_matrix") -#pragma comment(linker, "/EXPORT:_cairo_default_matrix") -#pragma comment(linker, "/EXPORT:_cairo_identity_matrix") -#pragma comment(linker, "/EXPORT:_cairo_transform_point") -#pragma comment(linker, "/EXPORT:_cairo_transform_distance") -#pragma comment(linker, "/EXPORT:_cairo_inverse_transform_point") -#pragma comment(linker, "/EXPORT:_cairo_inverse_transform_distance") - -#pragma comment(linker, "/EXPORT:_cairo_new_path") -#pragma comment(linker, "/EXPORT:_cairo_move_to") -#pragma comment(linker, "/EXPORT:_cairo_line_to") -#pragma comment(linker, "/EXPORT:_cairo_curve_to") -#pragma comment(linker, "/EXPORT:_cairo_arc") -#pragma comment(linker, "/EXPORT:_cairo_arc_negative") -#pragma comment(linker, "/EXPORT:_cairo_rel_move_to") -#pragma comment(linker, "/EXPORT:_cairo_rel_line_to") -#pragma comment(linker, "/EXPORT:_cairo_rel_curve_to") -#pragma comment(linker, "/EXPORT:_cairo_rectangle") -#pragma comment(linker, "/EXPORT:_cairo_close_path") - -#pragma comment(linker, "/EXPORT:_cairo_stroke") -#pragma comment(linker, "/EXPORT:_cairo_fill") -#pragma comment(linker, "/EXPORT:_cairo_copy_page") -#pragma comment(linker, "/EXPORT:_cairo_show_page") -#pragma comment(linker, "/EXPORT:_cairo_in_stroke") -#pragma comment(linker, "/EXPORT:_cairo_in_fill") -#pragma comment(linker, "/EXPORT:_cairo_stroke_extents") -#pragma comment(linker, "/EXPORT:_cairo_fill_extents") - -#pragma comment(linker, "/EXPORT:_cairo_init_clip") -#pragma comment(linker, "/EXPORT:_cairo_clip") -#pragma comment(linker, "/EXPORT:_cairo_select_font") -#pragma comment(linker, "/EXPORT:_cairo_scale_font") -#pragma comment(linker, "/EXPORT:_cairo_transform_font") -#pragma comment(linker, "/EXPORT:_cairo_show_text") -#pragma comment(linker, "/EXPORT:_cairo_show_glyphs") -#pragma comment(linker, "/EXPORT:_cairo_current_font") -#pragma comment(linker, "/EXPORT:_cairo_current_font_extents") -#pragma comment(linker, "/EXPORT:_cairo_set_font") -#pragma comment(linker, "/EXPORT:_cairo_text_extents") -#pragma comment(linker, "/EXPORT:_cairo_glyph_extents") -#pragma comment(linker, "/EXPORT:_cairo_text_path") -#pragma comment(linker, "/EXPORT:_cairo_glyph_path") -#pragma comment(linker, "/EXPORT:_cairo_font_reference") -#pragma comment(linker, "/EXPORT:_cairo_font_destroy") -#pragma comment(linker, "/EXPORT:_cairo_font_set_transform") -#pragma comment(linker, "/EXPORT:_cairo_font_current_transform") - -/*#pragma comment(linker, "/EXPORT:_cairo_ft_font_create") -#pragma comment(linker, "/EXPORT:_cairo_ft_font_create_for_ft_face") -*/ -#if 0 -/* hmm, this function doesn't exist, but __cairo_ft_font_destroy does */ -#pragma comment(linker, "/EXPORT:_cairo_ft_font_destroy") -#endif -/* -#pragma comment(linker, "/EXPORT:_cairo_ft_font_face") -#pragma comment(linker, "/EXPORT:_cairo_ft_font_pattern") -*/ -#pragma comment(linker, "/EXPORT:_cairo_show_surface") -#pragma comment(linker, "/EXPORT:_cairo_current_operator") -#pragma comment(linker, "/EXPORT:_cairo_current_rgb_color") -#pragma comment(linker, "/EXPORT:_cairo_current_pattern") -#pragma comment(linker, "/EXPORT:_cairo_current_alpha") -#pragma comment(linker, "/EXPORT:_cairo_current_tolerance") -#pragma comment(linker, "/EXPORT:_cairo_current_point") -#pragma comment(linker, "/EXPORT:_cairo_current_fill_rule") -#pragma comment(linker, "/EXPORT:_cairo_current_line_width") -#pragma comment(linker, "/EXPORT:_cairo_current_line_cap") -#pragma comment(linker, "/EXPORT:_cairo_current_line_join") -#pragma comment(linker, "/EXPORT:_cairo_current_rgb_color") -#pragma comment(linker, "/EXPORT:_cairo_current_miter_limit") -#pragma comment(linker, "/EXPORT:_cairo_current_matrix") -#pragma comment(linker, "/EXPORT:_cairo_current_target_surface") -#pragma comment(linker, "/EXPORT:_cairo_current_path") -#pragma comment(linker, "/EXPORT:_cairo_current_path_flat") - -#pragma comment(linker, "/EXPORT:_cairo_status") -#pragma comment(linker, "/EXPORT:_cairo_status_string") - -#pragma comment(linker, "/EXPORT:_cairo_surface_create_for_image") -#pragma comment(linker, "/EXPORT:_cairo_surface_create_similar") -#pragma comment(linker, "/EXPORT:_cairo_surface_reference") -#pragma comment(linker, "/EXPORT:_cairo_surface_destroy") -#pragma comment(linker, "/EXPORT:_cairo_surface_set_repeat") -#pragma comment(linker, "/EXPORT:_cairo_surface_set_matrix") -#pragma comment(linker, "/EXPORT:_cairo_surface_get_matrix") -#pragma comment(linker, "/EXPORT:_cairo_surface_set_filter") -#pragma comment(linker, "/EXPORT:_cairo_surface_get_filter") - -#pragma comment(linker, "/EXPORT:_cairo_image_surface_create") -#pragma comment(linker, "/EXPORT:_cairo_image_surface_create_for_data") -#pragma comment(linker, "/EXPORT:_cairo_pattern_create_for_surface") -#pragma comment(linker, "/EXPORT:_cairo_pattern_create_linear") -#pragma comment(linker, "/EXPORT:_cairo_pattern_create_radial") -#pragma comment(linker, "/EXPORT:_cairo_pattern_reference") -#pragma comment(linker, "/EXPORT:_cairo_pattern_destroy") -#pragma comment(linker, "/EXPORT:_cairo_pattern_add_color_stop") -#pragma comment(linker, "/EXPORT:_cairo_pattern_set_matrix") -#pragma comment(linker, "/EXPORT:_cairo_pattern_get_matrix") -#pragma comment(linker, "/EXPORT:_cairo_pattern_set_extend") -#pragma comment(linker, "/EXPORT:_cairo_pattern_get_extend") -#pragma comment(linker, "/EXPORT:_cairo_pattern_set_filter") -#pragma comment(linker, "/EXPORT:_cairo_pattern_get_filter") - -#ifdef CAIRO_HAS_PS_SURFACE -#pragma comment(linker, "/EXPORT:_cairo_ps_surface_create") -#endif - -#ifdef CAIRO_HAS_PNG_SURFACE -#pragma comment(linker, "/EXPORT:_cairo_png_surface_create") -#endif - -#ifdef CAIRO_HAS_GL_SURFACE -#pragma comment(linker, "/EXPORT:_cairo_gl_surface_create") -#endif - -#pragma comment(linker, "/EXPORT:_cairo_matrix_create") -#pragma comment(linker, "/EXPORT:_cairo_matrix_destroy") -#pragma comment(linker, "/EXPORT:_cairo_matrix_copy") -#pragma comment(linker, "/EXPORT:_cairo_matrix_set_identity") -#pragma comment(linker, "/EXPORT:_cairo_matrix_set_affine") -#pragma comment(linker, "/EXPORT:_cairo_matrix_get_affine") -#pragma comment(linker, "/EXPORT:_cairo_matrix_translate") -#pragma comment(linker, "/EXPORT:_cairo_matrix_scale") -#pragma comment(linker, "/EXPORT:_cairo_matrix_rotate") -#pragma comment(linker, "/EXPORT:_cairo_matrix_invert") -#pragma comment(linker, "/EXPORT:_cairo_matrix_multiply") -#pragma comment(linker, "/EXPORT:_cairo_matrix_transform_distance") -#pragma comment(linker, "/EXPORT:_cairo_matrix_transform_point") - -#include <windows.h> - -#include <gdiplus.h> -using namespace Gdiplus; - -extern const cairo_surface_backend_t cairo_win32_surface_backend; - -cairo_surface_t *_cairo_win32_surface_create (HDC dc); - -void -cairo_set_target_win32(cairo_t *cr, HDC dc) -{ - cairo_surface_t *surface; - - surface = _cairo_win32_surface_create(dc); - if (surface == NULL) { - cr->status = CAIRO_STATUS_NO_MEMORY; - return; - } - - cairo_set_target_surface (cr, surface); - - /* cairo_set_target_surface takes a reference, so we must destroy ours */ - cairo_surface_destroy (surface); -} - -typedef struct cairo_win32_surface { - cairo_surface_t base; - Graphics *gr; - - Brush *brush; -} cairo_win32_surface_t; - - -static void -_cairo_win32_surface_erase(cairo_win32_surface_t *surface); - -cairo_surface_t * -_cairo_win32_surface_create(HDC dc) -{ - cairo_win32_surface_t *surface; - - surface = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t)); - if (surface == NULL) - return NULL; - - surface->gr = new Graphics(dc); - surface->brush = NULL; -// surface->gr->TranslateTransform(-2000*2.5, -3000*2.2); -// surface->gr->ScaleTransform(20, 20); - - surface->gr->SetSmoothingMode(SmoothingModeAntiAlias); - - /* do pixmap creation, etc */ - - _cairo_surface_init(&surface->base, &cairo_win32_surface_backend); - - _cairo_win32_surface_erase(surface); - - return &surface->base; -} - -static cairo_surface_t * -_cairo_win32_surface_create_similar(void *abstract_src, - cairo_format_t format, - int drawable, - int width, - int height) -{ - return NULL; -} - -static void -_cairo_win32_surface_destroy (void *abstract_surface) -{ - cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface; - - delete surface->gr; - delete surface->brush; - - free(surface); -} - -static void -_cairo_win32_surface_erase(cairo_win32_surface_t *surface) -{ - surface->gr->Clear(Color(255, 0, 0, 0)); -} - -/* XXX: We should re-work this interface to return both X/Y ppi values. */ -static double -_cairo_win32_surface_pixels_per_inch(void *abstract_surface) -{ - cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface; - - return surface->gr->GetDpiY(); -} - -static Image * -make_image(cairo_image_surface_t *image) -{ - Rect r(0, 0, image->width, image->height); - Bitmap *b = new Bitmap(image->width, image->height, PixelFormat32bppPARGB); - BitmapData data; - - b->LockBits(&r, ImageLockModeWrite, PixelFormat32bppPARGB, &data); - - memcpy(data.Scan0, image->data, image->stride * image->height); - - b->UnlockBits(&data); - - return b; -} - -static cairo_image_surface_t * -_cairo_win32_surface_get_image(void *abstract_surface) -{ - cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface; - - /* need to figure out how to get the data from a Graphics and turn it in to an Image */ - return NULL; -} - - -static cairo_status_t -_cairo_win32_surface_set_image(void *abstract_surface, - cairo_image_surface_t *image) -{ - cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface; - - Image *img = make_image(image); - surface->gr->DrawImage(img, 0, 0); - delete img; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_win32_surface_set_matrix(void *abstract_surface, - cairo_matrix_t *matrix) -{ - cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface; - - Matrix m((float)matrix->m[0][0], (float)matrix->m[1][0], (float)matrix->m[2][0], - (float)matrix->m[0][1], (float)matrix->m[1][1], (float)matrix->m[2][1]); - - - surface->gr->SetTransform(&m); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_win32_surface_set_filter (void *abstract_surface, - cairo_filter_t filter) -{ - cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface; - SmoothingMode mode; - - switch (filter) { - case CAIRO_FILTER_FAST: - mode = SmoothingModeNone; - break; - case CAIRO_FILTER_GOOD: - case CAIRO_FILTER_BEST: - case CAIRO_FILTER_NEAREST: - case CAIRO_FILTER_BILINEAR: - case CAIRO_FILTER_GAUSSIAN: - default: - mode = SmoothingModeAntiAlias; - break; - } - surface->gr->SetSmoothingMode(mode); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_win32_surface_set_repeat (void *abstract_surface, - int repeat) -{ - /* what is this function supposed to do? */ - cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface; - - return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED; -} - -static cairo_int_status_t -_cairo_win32_surface_composite(cairo_operator_t op, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, - void *abstract_dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - - -static cairo_int_status_t -_cairo_win32_surface_fill_rectangles(void *abstract_surface, - cairo_operator_t op, - const cairo_color_t *color, - cairo_rectangle_t *rects, - int num_rects) -{ - cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface; - - SolidBrush brush(Color(color->alpha_short, color->red_short, color->green_short, color->blue_short)); - - RectF *r = new RectF[num_rects]; /* should really allocate a small number here on the stack and use those if possible */ - for (int i = 0; i < num_rects; ++i) { - r[i].X = rects[i].x; - r[i].Y = rects[i].y; - r[i].Width = rects[i].width; - r[i].Height = rects[i].height; - } - - surface->gr->FillRectangles(&brush, r, num_rects); - - delete[] r; - - return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; -} - - - -static int -_cairo_win32_extract_rectangle (cairo_trapezoid_t *trap, - RectF *rect) -{ - if (trap->left.p1.x == trap->left.p2.x && - trap->right.p1.x == trap->right.p2.x && - trap->left.p1.y == trap->right.p1.y && - trap->left.p2.y == trap->right.p2.y) { - - double x = _cairo_fixed_to_double (trap->left.p1.x); - double y = _cairo_fixed_to_double (trap->left.p1.y); - rect->X = (float)x; - rect->Y = (float)y; - rect->Width = (float)(_cairo_fixed_to_double(trap->right.p1.x) - x); - rect->Height = (float)(_cairo_fixed_to_double(trap->left.p2.y) - y); - - return 1; - } - - return 0; -} - -static cairo_int_status_t -_cairo_win32_surface_composite_trapezoids (cairo_operator_t op, - cairo_surface_t *generic_src, - void *abstract_dst, - int x_src, - int y_src, - cairo_trapezoid_t *traps, - int num_traps) -{ - cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_dst; - - static int zzz = 0; - zzz += num_traps; - - Image *img = NULL; - Brush *brush = NULL; /* i'd really like to not allocate this on the heap.. */ - -#define FIXED_TO_FLOAT(x) (float)_cairo_fixed_to_double((x)) - - /* ugh.. figure out if we're a "native" pattern or an image_surface pattern.. */ - if (generic_src->backend == &cairo_win32_surface_backend) { - brush = ((cairo_win32_surface_t*)generic_src)->brush; - /* XXX move this outside so that TextureBrushes can take advantage of it */ - /* Check to see if we can represent these traps as a rectangle. */ - RectF rect; - if (num_traps == 1 && _cairo_win32_extract_rectangle(traps, &rect)) { - surface->gr->FillRectangle(brush, rect); - return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; - } - } else { - /* I would really love to move this code in to create_pattern if possible */ - img = make_image((cairo_image_surface_t*)generic_src); - brush = new TextureBrush(img); - - // XXX this will probably break. Don't know why we have +1 and +2 offsets.. - float xoff = (FIXED_TO_FLOAT(traps[0].left.p1.x) + 0.5f); - float yoff = (FIXED_TO_FLOAT(traps[0].left.p1.y) + 1.5f); - static_cast<TextureBrush*>(brush)->TranslateTransform((int)(-x_src + xoff), - (int)(-y_src + yoff)); - } - - CompositingMode mode; - switch (op) { - case CAIRO_OPERATOR_OVER: - mode = CompositingModeSourceOver; - break; - case CAIRO_OPERATOR_CLEAR: - mode = CompositingModeSourceCopy; - break; - case CAIRO_OPERATOR_SRC: - case CAIRO_OPERATOR_DST: - case CAIRO_OPERATOR_OVER_REVERSE: - case CAIRO_OPERATOR_IN: - case CAIRO_OPERATOR_IN_REVERSE: - case CAIRO_OPERATOR_OUT: - case CAIRO_OPERATOR_OUT_REVERSE: - case CAIRO_OPERATOR_ATOP: - case CAIRO_OPERATOR_ATOP_REVERSE: - case CAIRO_OPERATOR_XOR: - case CAIRO_OPERATOR_ADD: - case CAIRO_OPERATOR_SATURATE: - mode = CompositingModeSourceOver; - break; - } - surface->gr->SetCompositingMode(mode); - - PointF points[4]; - for (int i = 0; i < num_traps; ++i) { - float top = FIXED_TO_FLOAT(traps[i].top); - float bottom = FIXED_TO_FLOAT(traps[i].bottom); - - /* left line */ - points[0].X = FIXED_TO_FLOAT(traps[i].left.p1.x); - points[0].Y = FIXED_TO_FLOAT(traps[i].left.p1.y); - points[1].X = FIXED_TO_FLOAT(traps[i].left.p2.x); - points[1].Y = FIXED_TO_FLOAT(traps[i].left.p2.y); - - /* right line */ - points[2].X = FIXED_TO_FLOAT(traps[i].right.p2.x); - points[2].Y = FIXED_TO_FLOAT(traps[i].right.p2.y); - points[3].X = FIXED_TO_FLOAT(traps[i].right.p1.x); - points[3].Y = FIXED_TO_FLOAT(traps[i].right.p1.y); - - surface->gr->FillPolygon(brush, points, 4); - //Pen p(Color(255,0,0,0), 1.0f/10.0f); - //surface->gr->DrawPolygon(&p, points, 4); - } - -#undef FIXED_TO_FLOAT - - delete img; - return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_win32_surface_copy_page (void *abstract_surface) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - - -static cairo_int_status_t -_cairo_win32_surface_show_page (void *abstract_surface) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - - -static cairo_int_status_t -_cairo_win32_surface_set_clip_region (void *abstract_surface, - pixman_region16_t *region) -{ - cairo_win32_surface_t *surface = (cairo_win32_surface_t *)abstract_surface; - - pixman_box16_t *box; - int n = pixman_region_num_rects(region); - - if (n == 0) - return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; - - box = pixman_region_rects(region); - - surface->gr->ResetClip(); - for (int i = 0; i < n; ++i) { - Rect r(box[i].x1, box[i].y1, box[i].x2 - box[i].x1, box[i].y2 - box[i].y1); - surface->gr->SetClip(r, CombineModeUnion); /* do I need to do replace once and then union? */ - } - - return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_win32_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *box) -{ - /* SOLID is easy -> SolidBrush - LINEAR we can only do a gradient from 1 color to another -> LinearGradientBrush - We should do this if thats all we need, otherwise use software. - RADIAL we can't really do it. Let it fall back to software I guess. */ - - - /* in the case of PATTERN_SOLID, we really just want to create a brush and hand that back... */ - if (pattern->type == CAIRO_PATTERN_SOLID) { - - /* ugh, this surface creation code should _really_ live somewhere else */ - cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t)); - if (src == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; - - _cairo_surface_init(&src->base, &cairo_win32_surface_backend); - pattern->source = &src->base; - - src->gr = NULL; - src->brush = new SolidBrush(Color(pattern->color.alpha_short, - pattern->color.red_short, - pattern->color.green_short, - pattern->color.blue_short)); - - - return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; - } - - else if (pattern->type == CAIRO_PATTERN_LINEAR && pattern->n_stops == 2) { - - /* ugh, this surface creation code should _really_ live somewhere else */ - cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t)); - if (src == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; - - _cairo_surface_init(&src->base, &cairo_win32_surface_backend); - pattern->source = &src->base; - - src->gr = NULL; - - RectF r((float)pattern->u.linear.point0.x, - (float)pattern->u.linear.point0.y, - ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16), - ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16)); - - src->brush = new LinearGradientBrush(r, - Color(pattern->stops[0].color_char[3], - pattern->stops[0].color_char[0], - pattern->stops[0].color_char[1], - pattern->stops[0].color_char[2]), - Color(pattern->stops[1].color_char[3], - pattern->stops[1].color_char[0], - pattern->stops[1].color_char[1], - pattern->stops[1].color_char[2]), - 90.0, FALSE); - - static_cast<LinearGradientBrush*>(src->brush)->TranslateTransform((float)pattern->source_offset.x, - (float)pattern->source_offset.y); - return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; - } - - else if (pattern->type == CAIRO_PATTERN_RADIAL) { -#if 0 /* XXX not sure this will work.. do we have to draw with FillPath() in order for this brush to work properly? */ - /* use PathGradientBrush here */ - - /* ugh, this surface creation code should _really_ live somewhere else */ - cairo_win32_surface_t *src = (cairo_win32_surface_t*)malloc(sizeof(cairo_win32_surface_t)); - if (src == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; - - _cairo_surface_init(&src->base, &cairo_win32_surface_backend); - pattern->source = &src->base; - - src->gr = NULL; - - PointF center(pattern->u.radial.center1.x, pattern->u.radial.center1.y); - - GraphicsPath path; - path.AddEllipse(0, 0, 140, 70); - - // Use the path to construct a brush. - PathGradientBrush *brush = new PathGradientBrush(&path); - src->brush = brush; - - // Set the color at the center of the path to blue. - brush->SetCenterColor(Color(50, 100, 0, 255)); - - // Set the color along the entire boundary of the path to aqua. - Color colors[] = {Color(255, 0, 255, 255)}; - int count = 1; - brush->SetSurroundColors(colors, &count); - - brush->SetCenterPoint(center); - - return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; -#endif - - } - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -static const cairo_surface_backend_t cairo_win32_surface_backend = { - _cairo_win32_surface_create_similar, - _cairo_win32_surface_destroy, - _cairo_win32_surface_pixels_per_inch, - _cairo_win32_surface_get_image, - _cairo_win32_surface_set_image, - _cairo_win32_surface_set_matrix, - _cairo_win32_surface_set_filter, - _cairo_win32_surface_set_repeat, - _cairo_win32_surface_composite, - _cairo_win32_surface_fill_rectangles, - _cairo_win32_surface_composite_trapezoids, - _cairo_win32_surface_copy_page, - _cairo_win32_surface_show_page, - _cairo_win32_surface_set_clip_region, - _cairo_win32_surface_create_pattern, -}; diff --git a/src/cairo_glitz_surface.c b/src/cairo_glitz_surface.c index 69fc82f2e..ee664e1cc 100644 --- a/src/cairo_glitz_surface.c +++ b/src/cairo_glitz_surface.c @@ -21,30 +21,12 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * Author: David Reveman <c99drn@cs.umu.se> + * Author: David Reveman <davidr@novell.com> */ #include "cairoint.h" #include "cairo-glitz.h" -#define GLITZ_FIXED_TO_FLOAT(f) \ - (((glitz_float_t) (f)) / 65536) - -#define GLITZ_FIXED_LINE_X_TO_FLOAT(line, v) \ - (((glitz_float_t) \ - ((line).p1.x + (cairo_fixed_16_16_t) \ - (((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ - ((line).p2.x - (line).p1.x)) / \ - ((line).p2.y - (line).p1.y)))) / 65536) - -#define GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \ - (((glitz_float_t) \ - ((line).p1.x + (cairo_fixed_16_16_t) \ - (((((line).p2.y - (line).p1.y) - 1) + \ - ((cairo_fixed_32_32_t) ((v) - (line).p1.y) * \ - ((line).p2.x - (line).p1.x))) / \ - ((line).p2.y - (line).p1.y)))) / 65536) - void cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface) { @@ -65,13 +47,11 @@ cairo_set_target_glitz (cairo_t *cr, glitz_surface_t *surface) } typedef struct _cairo_glitz_surface { - cairo_surface_t base; - - glitz_surface_t *surface; - glitz_format_t *format; + cairo_surface_t base; - cairo_pattern_t pattern; - cairo_box_t pattern_box; + glitz_surface_t *surface; + glitz_format_t *format; + pixman_region16_t *clip; } cairo_glitz_surface_t; static void @@ -79,11 +59,60 @@ _cairo_glitz_surface_destroy (void *abstract_surface) { cairo_glitz_surface_t *surface = abstract_surface; + if (surface->clip) + { + glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); + pixman_region_destroy (surface->clip); + } + glitz_surface_destroy (surface->surface); + free (surface); +} - _cairo_pattern_fini (&surface->pattern); +static glitz_format_name_t +_glitz_format (cairo_format_t format) +{ + switch (format) { + default: + case CAIRO_FORMAT_ARGB32: + return GLITZ_STANDARD_ARGB32; + case CAIRO_FORMAT_RGB24: + return GLITZ_STANDARD_RGB24; + case CAIRO_FORMAT_A8: + return GLITZ_STANDARD_A8; + case CAIRO_FORMAT_A1: + return GLITZ_STANDARD_A1; + } +} - free (surface); +static cairo_surface_t * +_cairo_glitz_surface_create_similar (void *abstract_src, + cairo_format_t format, + int draw, + int width, + int height) +{ + cairo_glitz_surface_t *src = abstract_src; + cairo_surface_t *crsurface; + glitz_drawable_t *drawable; + glitz_surface_t *surface; + glitz_format_t *gformat; + + drawable = glitz_surface_get_drawable (src->surface); + + gformat = glitz_find_standard_format (drawable, _glitz_format (format)); + if (!gformat) + return NULL; + + surface = glitz_surface_create (drawable, gformat, width, height, 0, NULL); + if (!surface) + return NULL; + + crsurface = cairo_glitz_surface_create (surface); + + glitz_surface_destroy (surface); + + return crsurface; } static double @@ -92,31 +121,54 @@ _cairo_glitz_surface_pixels_per_inch (void *abstract_surface) return 96.0; } -static cairo_image_surface_t * -_cairo_glitz_surface_get_image (void *abstract_surface) +static cairo_status_t +_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, + cairo_rectangle_t *interest, + cairo_image_surface_t **image_out, + cairo_rectangle_t *rect_out) { - cairo_glitz_surface_t *surface = abstract_surface; cairo_image_surface_t *image; - char *pixels; - int width, height; - cairo_format_masks_t format; - glitz_buffer_t *buffer; - glitz_pixel_format_t pf; - - if (surface->pattern.type != CAIRO_PATTERN_SURFACE) { - cairo_box_t box; - - box.p1.x = box.p1.y = 0; - box.p2.x = surface->pattern_box.p2.x; - box.p2.y = surface->pattern_box.p2.y; - - return _cairo_pattern_get_image (&surface->pattern, &box); + int x1, y1, x2, y2; + int width, height; + char *pixels; + cairo_format_masks_t format; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + + x1 = 0; + y1 = 0; + x2 = glitz_surface_get_width (surface->surface); + y2 = glitz_surface_get_height (surface->surface); + + if (interest) + { + if (interest->x > x1) + x1 = interest->x; + if (interest->y > y1) + y1 = interest->y; + if (interest->x + interest->width < x2) + x2 = interest->x + interest->width; + if (interest->y + interest->height < y2) + y2 = interest->y + interest->height; + + if (x1 >= x2 || y1 >= y2) + { + *image_out = NULL; + return CAIRO_STATUS_SUCCESS; + } } + width = x2 - x1; + height = y2 - y1; - width = glitz_surface_get_width (surface->surface); - height = glitz_surface_get_height (surface->surface); - + if (rect_out) + { + rect_out->x = x1; + rect_out->y = y1; + rect_out->width = width; + rect_out->height = height; + } + if (surface->format->type == GLITZ_FORMAT_TYPE_COLOR) { if (surface->format->color.red_size > 0) { format.bpp = 32; @@ -149,21 +201,24 @@ _cairo_glitz_surface_get_image (void *abstract_surface) pf.masks.blue_mask = format.blue_mask; pf.xoffset = 0; pf.skip_lines = 0; + + /* XXX: we should eventually return images with negative stride, + need to verify that libpixman have no problem with this first. */ pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4; pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; pixels = malloc (height * pf.bytes_per_line); if (!pixels) - return NULL; + return CAIRO_STATUS_NO_MEMORY; buffer = glitz_buffer_create_for_data (pixels); if (!buffer) { free (pixels); - return NULL; + return CAIRO_STATUS_NO_MEMORY; } glitz_get_pixels (surface->surface, - 0, 0, + x1, y1, width, height, &pf, buffer); @@ -175,27 +230,38 @@ _cairo_glitz_surface_get_image (void *abstract_surface) &format, width, height, pf.bytes_per_line); - + + if (!image) + { + free (pixels); + return CAIRO_STATUS_NO_MEMORY; + } + _cairo_image_surface_assume_ownership_of_data (image); _cairo_image_surface_set_repeat (image, surface->base.repeat); _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - return image; + *image_out = image; + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_glitz_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +_cairo_glitz_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image, + int x_dst, + int y_dst) { cairo_glitz_surface_t *surface = abstract_surface; - glitz_buffer_t *buffer; - glitz_pixel_format_t pf; - pixman_format_t *format; - int am, rm, gm, bm; + glitz_buffer_t *buffer; + glitz_pixel_format_t pf; + pixman_format_t *format; + int am, rm, gm, bm; + char *data; format = pixman_image_get_format (image->pixman_image); - if (format == NULL) + if (!format) return CAIRO_STATUS_NO_MEMORY; pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm); @@ -206,15 +272,27 @@ _cairo_glitz_surface_set_image (void *abstract_surface, pf.masks.blue_mask = bm; pf.xoffset = 0; pf.skip_lines = 0; - pf.bytes_per_line = image->stride; - pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; - buffer = glitz_buffer_create_for_data (image->data); + /* check for negative stride */ + if (image->stride < 0) + { + pf.bytes_per_line = -image->stride; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP; + data = (char *) image->data + image->stride * (image->height - 1); + } + else + { + pf.bytes_per_line = image->stride; + pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; + data = (char *) image->data; + } + + buffer = glitz_buffer_create_for_data (data); if (!buffer) return CAIRO_STATUS_NO_MEMORY; glitz_set_pixels (surface->surface, - 0, 0, + x_dst, y_dst, image->width, image->height, &pf, buffer); @@ -225,63 +303,118 @@ _cairo_glitz_surface_set_image (void *abstract_surface, } static cairo_status_t -_cairo_glitz_surface_set_matrix (void *abstract_surface, - cairo_matrix_t *matrix) +_cairo_glitz_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { cairo_glitz_surface_t *surface = abstract_surface; - glitz_transform_t transform; - transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); - transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); - transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); + *image_extra = NULL; + + return _cairo_glitz_surface_get_image (surface, NULL, image_out, NULL); +} - transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); - transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); - transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); +static void +_cairo_glitz_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); +} - transform.matrix[2][0] = 0; - transform.matrix[2][1] = 0; - transform.matrix[2][2] = 1 << 16; +static cairo_status_t +_cairo_glitz_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect_out, + void **image_extra) +{ + cairo_glitz_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; - glitz_surface_set_transform (surface->surface, &transform); + status = _cairo_glitz_surface_get_image (surface, interest_rect, &image, + image_rect_out); + if (status) + return status; - return CAIRO_STATUS_SUCCESS; + *image_out = image; + *image_extra = NULL; + + return status; } +static void +_cairo_glitz_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + cairo_glitz_surface_t *surface = abstract_surface; + + _cairo_glitz_surface_set_image (surface, image, + image_rect->x, image_rect->y); + + cairo_surface_destroy (&image->base); +} + + static cairo_status_t -_cairo_glitz_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +_cairo_glitz_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { cairo_glitz_surface_t *surface = abstract_surface; - glitz_filter_t glitz_filter; + cairo_glitz_surface_t *clone; - switch (filter) { - case CAIRO_FILTER_FAST: - case CAIRO_FILTER_NEAREST: - glitz_filter = GLITZ_FILTER_NEAREST; - break; - case CAIRO_FILTER_GOOD: - case CAIRO_FILTER_BEST: - case CAIRO_FILTER_BILINEAR: - default: - glitz_filter = GLITZ_FILTER_BILINEAR; - break; + if (src->backend == surface->base.backend) + { + *clone_out = src; + cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; } + else if (_cairo_surface_is_image (src)) + { + cairo_image_surface_t *image_src = (cairo_image_surface_t *) src; + + clone = (cairo_glitz_surface_t *) + _cairo_glitz_surface_create_similar (surface, image_src->format, 0, + image_src->width, + image_src->height); + if (!clone) + return CAIRO_STATUS_NO_MEMORY; - glitz_surface_set_filter (surface->surface, glitz_filter, NULL, 0); + _cairo_glitz_surface_set_image (clone, image_src, 0, 0); + + *clone_out = &clone->base; - return CAIRO_STATUS_SUCCESS; + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_status_t -_cairo_glitz_surface_set_repeat (void *abstract_surface, int repeat) +static void +_cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface, + cairo_matrix_t *matrix) { - cairo_glitz_surface_t *surface = abstract_surface; + glitz_transform_t transform; + + transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); + transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); + transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); - glitz_surface_set_fill (surface->surface, - (repeat)? GLITZ_FILL_REPEAT: - GLITZ_FILL_TRANSPARENT); + transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); + transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); + transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); - return CAIRO_STATUS_SUCCESS; + transform.matrix[2][0] = 0; + transform.matrix[2][1] = 0; + transform.matrix[2][2] = 1 << 16; + + glitz_surface_set_transform (surface->surface, &transform); } static glitz_operator_t @@ -318,32 +451,6 @@ _glitz_operator (cairo_operator_t op) } } -static glitz_surface_t * -_glitz_surface_create_solid (glitz_surface_t *other, - glitz_format_name_t format_name, - glitz_color_t *color) -{ - glitz_drawable_t *drawable; - glitz_format_t *format; - glitz_surface_t *surface; - - drawable = glitz_surface_get_drawable (other); - - format = glitz_find_standard_format (drawable, format_name); - if (format == NULL) - return NULL; - - surface = glitz_surface_create (drawable, format, 1, 1); - if (surface == NULL) - return NULL; - - glitz_set_rectangle (surface, color, 0, 0, 1, 1); - - glitz_surface_set_fill (surface, GLITZ_FILL_REPEAT); - - return surface; -} - static glitz_status_t _glitz_ensure_target (glitz_surface_t *surface) { @@ -355,7 +462,6 @@ _glitz_ensure_target (glitz_surface_t *surface) glitz_drawable_format_t templ; glitz_format_t *format; glitz_drawable_t *pbuffer; - glitz_pbuffer_attributes_t attributes; unsigned long mask; int i; @@ -397,21 +503,13 @@ _glitz_ensure_target (glitz_surface_t *surface) if (!dformat) return CAIRO_INT_STATUS_UNSUPPORTED; - attributes.width = glitz_surface_get_width (surface); - attributes.height = glitz_surface_get_height (surface); - mask = GLITZ_PBUFFER_WIDTH_MASK | GLITZ_PBUFFER_HEIGHT_MASK; - - pbuffer = glitz_create_pbuffer_drawable (drawable, dformat, - &attributes, mask); + pbuffer = + glitz_create_pbuffer_drawable (drawable, dformat, + glitz_surface_get_width (surface), + glitz_surface_get_height (surface)); if (!pbuffer) return CAIRO_INT_STATUS_UNSUPPORTED; - if (glitz_drawable_get_width (pbuffer) < attributes.width || - glitz_drawable_get_height (pbuffer) < attributes.height) { - glitz_drawable_destroy (pbuffer); - return CAIRO_INT_STATUS_UNSUPPORTED; - } - glitz_surface_attach (surface, pbuffer, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR, 0, 0); @@ -422,388 +520,711 @@ _glitz_ensure_target (glitz_surface_t *surface) return CAIRO_STATUS_SUCCESS; } -static glitz_format_name_t -_glitz_format (cairo_format_t format) +typedef struct _cairo_glitz_surface_attributes { + cairo_surface_attributes_t base; + + glitz_fill_t fill; + glitz_filter_t filter; + glitz_fixed16_16_t *params; + int n_params; + cairo_bool_t acquired; +} cairo_glitz_surface_attributes_t; + +static cairo_int_status_t +_cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, + cairo_glitz_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_glitz_surface_t **surface_out, + cairo_glitz_surface_attributes_t *attr) { - switch (format) { + cairo_glitz_surface_t *src = NULL; + + attr->acquired = FALSE; + + switch (pattern->type) { + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_gradient_pattern_t *gradient = + (cairo_gradient_pattern_t *) pattern; + glitz_drawable_t *drawable; + glitz_fixed16_16_t *params; + int n_params; + int i; + unsigned short alpha; + + /* XXX: the current color gradient acceleration provided by glitz is + * experimental, it's been proven inappropriate in a number of ways, + * most importantly, it's currently implemented as filters and + * gradients are not filters. eventually, it will be replaced with + * something more appropriate. + */ + + if (gradient->n_stops < 2) + break; + + /* glitz doesn't support inner and outer circle with different + center points. */ + if (pattern->type == CAIRO_PATTERN_RADIAL) + { + cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern; + + if (grad->center0.x != grad->center1.x || + grad->center0.y != grad->center1.y) + break; + } + + drawable = glitz_surface_get_drawable (dst->surface); + if (!(glitz_drawable_get_features (drawable) & + GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK)) + break; + + if (pattern->filter != CAIRO_FILTER_BILINEAR && + pattern->filter != CAIRO_FILTER_GOOD && + pattern->filter != CAIRO_FILTER_BEST) + break; + + alpha = (gradient->stops[0].color.alpha * pattern->alpha) * 0xffff; + for (i = 1; i < gradient->n_stops; i++) + { + unsigned short a; + + a = (gradient->stops[i].color.alpha * pattern->alpha) * 0xffff; + if (a != alpha) + break; + } + + /* we can't have color stops with different alpha as gradient color + interpolation should be done to unpremultiplied colors. */ + if (i < gradient->n_stops) + break; + + n_params = gradient->n_stops * 3 + 4; + + params = malloc (sizeof (glitz_fixed16_16_t) * n_params); + if (!params) + return CAIRO_STATUS_NO_MEMORY; + + src = (cairo_glitz_surface_t *) + _cairo_surface_create_similar_scratch (&dst->base, + CAIRO_FORMAT_ARGB32, 0, + gradient->n_stops, 1); + if (!src) + { + free (params); + return CAIRO_STATUS_NO_MEMORY; + } + + for (i = 0; i < gradient->n_stops; i++) { + glitz_color_t color; + + color.red = gradient->stops[i].color.red * alpha; + color.green = gradient->stops[i].color.green * alpha; + color.blue = gradient->stops[i].color.blue * alpha; + color.alpha = alpha; + + glitz_set_rectangle (src->surface, &color, i, 0, 1, 1); + + params[4 + 3 * i] = gradient->stops[i].offset; + params[5 + 3 * i] = i << 16; + params[6 + 3 * i] = 0; + } + + if (pattern->type == CAIRO_PATTERN_LINEAR) + { + cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern; + + params[0] = _cairo_fixed_from_double (grad->point0.x); + params[1] = _cairo_fixed_from_double (grad->point0.y); + params[2] = _cairo_fixed_from_double (grad->point1.x); + params[3] = _cairo_fixed_from_double (grad->point1.y); + attr->filter = GLITZ_FILTER_LINEAR_GRADIENT; + } + else + { + cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern; + + params[0] = _cairo_fixed_from_double (grad->center0.x); + params[1] = _cairo_fixed_from_double (grad->center0.y); + params[2] = _cairo_fixed_from_double (grad->radius0); + params[3] = _cairo_fixed_from_double (grad->radius1); + attr->filter = GLITZ_FILTER_RADIAL_GRADIENT; + } + + switch (pattern->extend) { + case CAIRO_EXTEND_NONE: + attr->fill = GLITZ_FILL_NEAREST; + break; + case CAIRO_EXTEND_REPEAT: + attr->fill = GLITZ_FILL_REPEAT; + break; + case CAIRO_EXTEND_REFLECT: + attr->fill = GLITZ_FILL_REFLECT; + break; + } + + attr->params = params; + attr->n_params = n_params; + attr->base.matrix = pattern->matrix; + attr->base.x_offset = 0; + attr->base.y_offset = 0; + } break; default: - case CAIRO_FORMAT_ARGB32: - return GLITZ_STANDARD_ARGB32; - case CAIRO_FORMAT_RGB24: - return GLITZ_STANDARD_RGB24; - case CAIRO_FORMAT_A8: - return GLITZ_STANDARD_A8; - case CAIRO_FORMAT_A1: - return GLITZ_STANDARD_A1; + break; } -} -static cairo_surface_t * -_cairo_glitz_surface_create_similar (void *abstract_src, - cairo_format_t format, - int draw, - int width, - int height) -{ - cairo_glitz_surface_t *src = abstract_src; - cairo_surface_t *crsurface; - glitz_drawable_t *drawable; - glitz_surface_t *surface; - glitz_format_t *gformat; + if (!src) + { + cairo_int_status_t status; - drawable = glitz_surface_get_drawable (src->surface); - - gformat = glitz_find_standard_format (drawable, _glitz_format (format)); - if (gformat == NULL) - return NULL; - - surface = glitz_surface_create (drawable, gformat, width, height); - if (surface == NULL) - return NULL; + status = _cairo_pattern_acquire_surface (pattern, &dst->base, + x, y, width, height, + (cairo_surface_t **) &src, + &attr->base); + if (status) + return status; + + if (src) + { + switch (attr->base.extend) { + case CAIRO_EXTEND_NONE: + attr->fill = GLITZ_FILL_TRANSPARENT; + break; + case CAIRO_EXTEND_REPEAT: + attr->fill = GLITZ_FILL_REPEAT; + break; + case CAIRO_EXTEND_REFLECT: + attr->fill = GLITZ_FILL_REFLECT; + break; + } - crsurface = cairo_glitz_surface_create (surface); - - glitz_surface_destroy (surface); + switch (attr->base.filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + attr->filter = GLITZ_FILTER_NEAREST; + break; + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + default: + attr->filter = GLITZ_FILTER_BILINEAR; + break; + } + + attr->params = NULL; + attr->n_params = 0; + attr->acquired = TRUE; + } + } - return crsurface; + *surface_out = src; + + return CAIRO_STATUS_SUCCESS; } -static cairo_glitz_surface_t * -_cairo_glitz_surface_clone_similar (cairo_glitz_surface_t *templ, - cairo_surface_t *src, - cairo_format_t format) +static void +_cairo_glitz_pattern_release_surface (cairo_glitz_surface_t *dst, + cairo_glitz_surface_t *surface, + cairo_glitz_surface_attributes_t *attr) { - cairo_glitz_surface_t *clone; - cairo_image_surface_t *src_image; + if (attr->acquired) + _cairo_pattern_release_surface (&dst->base, &surface->base, + &attr->base); + else + _cairo_glitz_surface_destroy (surface); +} - src_image = _cairo_surface_get_image (src); +static cairo_int_status_t +_cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src, + cairo_pattern_t *mask, + cairo_glitz_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + unsigned int width, + unsigned int height, + cairo_glitz_surface_t **src_out, + cairo_glitz_surface_t **mask_out, + cairo_glitz_surface_attributes_t *sattr, + cairo_glitz_surface_attributes_t *mattr) +{ + cairo_int_status_t status; + cairo_pattern_union_t tmp; + cairo_bool_t src_opaque, mask_opaque; + double src_alpha, mask_alpha; - clone = (cairo_glitz_surface_t *) - _cairo_glitz_surface_create_similar (templ, format, 0, - src_image->width, - src_image->height); - if (clone == NULL) - return NULL; - - _cairo_glitz_surface_set_filter (clone, cairo_surface_get_filter (src)); + src_opaque = _cairo_pattern_is_opaque (src); + mask_opaque = !mask || _cairo_pattern_is_opaque (mask); - _cairo_glitz_surface_set_image (clone, src_image); - - _cairo_glitz_surface_set_matrix (clone, &(src_image->base.matrix)); + /* For surface patterns, we move any translucency from src->alpha + * to mask->alpha so we can use the source unchanged. Otherwise we + * move the translucency from mask->alpha to src->alpha so that + * we can drop the mask if possible. + */ + if (src->type == CAIRO_PATTERN_SURFACE) + { + if (mask) { + mask_opaque = mask_opaque && src_opaque; + mask_alpha = mask->alpha * src->alpha; + } else { + mask_opaque = src_opaque; + mask_alpha = src->alpha; + } + + src_alpha = 1.0; + src_opaque = TRUE; + } + else + { + if (mask) + { + src_opaque = mask_opaque && src_opaque; + src_alpha = mask->alpha * src->alpha; + /* FIXME: This needs changing when we support RENDER + * style 4-channel masks. + */ + if (mask->type == CAIRO_PATTERN_SOLID) + mask = NULL; + } else + src_alpha = src->alpha; + + mask_alpha = 1.0; + mask_opaque = TRUE; + } + + _cairo_pattern_init_copy (&tmp.base, src); + _cairo_pattern_set_alpha (&tmp.base, src_alpha); + + status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, + src_x, src_y, + width, height, + src_out, sattr); - cairo_surface_destroy (&src_image->base); + _cairo_pattern_fini (&tmp.base); - return clone; -} + if (status) + return status; -static cairo_int_status_t -_glitz_composite (glitz_operator_t op, - glitz_surface_t *src, - glitz_surface_t *mask, - glitz_surface_t *dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - int width, - int height, - glitz_buffer_t *geometry, - glitz_geometry_format_t *format) -{ - if (_glitz_ensure_target (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (mask || !mask_opaque) + { + if (mask) + _cairo_pattern_init_copy (&tmp.base, mask); + else + _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0); - if (glitz_surface_get_status (dst)) - return CAIRO_STATUS_NO_TARGET_SURFACE; - - glitz_set_geometry (dst, - 0, 0, - format, geometry); - - glitz_composite (op, - src, - mask, - dst, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); - - glitz_set_geometry (dst, 0, 0, NULL, NULL); + _cairo_pattern_set_alpha (&tmp.base, mask_alpha); + + status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, + mask_x, mask_y, + width, height, + mask_out, mattr); + + _cairo_pattern_fini (&tmp.base); - if (glitz_surface_get_status (dst) == GLITZ_STATUS_NOT_SUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (status) + { + _cairo_glitz_pattern_release_surface (dst, *src_out, sattr); + return status; + } + } + else + { + *mask_out = NULL; + } return CAIRO_STATUS_SUCCESS; } +static void +_cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface, + cairo_glitz_surface_attributes_t *a) +{ + _cairo_glitz_surface_set_matrix (surface, &a->base.matrix); + glitz_surface_set_fill (surface->surface, a->fill); + glitz_surface_set_filter (surface->surface, a->filter, + a->params, a->n_params); +} + static cairo_int_status_t _cairo_glitz_surface_composite (cairo_operator_t op, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, - void *abstract_dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height) + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) { - cairo_glitz_surface_t *dst = abstract_dst; - cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; - cairo_glitz_surface_t *mask = (cairo_glitz_surface_t *) generic_mask; - cairo_glitz_surface_t *src_clone = NULL; - cairo_glitz_surface_t *mask_clone = NULL; - cairo_int_status_t status; + cairo_glitz_surface_attributes_t src_attr, mask_attr; + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src; + cairo_glitz_surface_t *mask; + cairo_int_status_t status; if (op == CAIRO_OPERATOR_SATURATE) return CAIRO_INT_STATUS_UNSUPPORTED; - if (generic_src->backend != dst->base.backend) { - src_clone = _cairo_glitz_surface_clone_similar (dst, generic_src, - CAIRO_FORMAT_ARGB32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (_glitz_ensure_target (dst->surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern, + dst, + src_x, src_y, + mask_x, mask_y, + width, height, + &src, &mask, + &src_attr, &mask_attr); + if (status) + return status; + + _cairo_glitz_surface_set_attributes (src, &src_attr); + if (mask) + { + _cairo_glitz_surface_set_attributes (mask, &mask_attr); + glitz_composite (_glitz_operator (op), + src->surface, + mask->surface, + dst->surface, + src_x + src_attr.base.x_offset, + src_y + src_attr.base.y_offset, + mask_x + mask_attr.base.x_offset, + mask_y + mask_attr.base.y_offset, + dst_x, dst_y, + width, height); - src = src_clone; - } - - if (generic_mask && (generic_mask->backend != dst->base.backend)) { - mask_clone = _cairo_glitz_surface_clone_similar (dst, generic_mask, - CAIRO_FORMAT_A8); - if (!mask_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; + if (mask_attr.n_params) + free (mask_attr.params); - mask = mask_clone; + _cairo_glitz_pattern_release_surface (dst, mask, &mask_attr); + } + else + { + glitz_composite (_glitz_operator (op), + src->surface, + NULL, + dst->surface, + src_x + src_attr.base.x_offset, + src_y + src_attr.base.y_offset, + 0, 0, + dst_x, dst_y, + width, height); } - status = _glitz_composite (_glitz_operator (op), - src->surface, - (mask)? mask->surface: NULL, - dst->surface, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height, - NULL, NULL); - - if (src_clone) - cairo_surface_destroy (&src_clone->base); - - if (mask_clone) - cairo_surface_destroy (&mask_clone->base); + if (src_attr.n_params) + free (src_attr.params); - return status; + _cairo_glitz_pattern_release_surface (dst, src, &src_attr); + + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t -_cairo_glitz_surface_fill_rectangles (void *abstract_dst, - cairo_operator_t op, +_cairo_glitz_surface_fill_rectangles (void *abstract_dst, + cairo_operator_t op, const cairo_color_t *color, - cairo_rectangle_t *rects, - int n_rects) + cairo_rectangle_t *rects, + int n_rects) { cairo_glitz_surface_t *dst = abstract_dst; - glitz_color_t glitz_color; - if (op == CAIRO_OPERATOR_SATURATE) - return CAIRO_INT_STATUS_UNSUPPORTED; - - glitz_color.red = color->red_short; - glitz_color.green = color->green_short; - glitz_color.blue = color->blue_short; - glitz_color.alpha = color->alpha_short; + if (op == CAIRO_OPERATOR_SRC) + { + glitz_color_t glitz_color; + + glitz_color.red = color->red_short; + glitz_color.green = color->green_short; + glitz_color.blue = color->blue_short; + glitz_color.alpha = color->alpha_short; + + if (glitz_surface_get_width (dst->surface) != 1 || + glitz_surface_get_height (dst->surface) != 1) + _glitz_ensure_target (dst->surface); - if (op != CAIRO_OPERATOR_SRC) { - glitz_surface_t *solid; - glitz_float_t *vertices; - glitz_buffer_t *buffer; - glitz_geometry_format_t gf; - cairo_int_status_t status; - int width, height; - void *data; + glitz_set_rectangles (dst->surface, &glitz_color, + (glitz_rectangle_t *) rects, n_rects); + } + else + { + cairo_glitz_surface_t *src; - gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; - gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_SHARP; - gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; - gf.type = GLITZ_DATA_TYPE_FLOAT; - gf.first = 0; - gf.count = n_rects * 4; - - data = malloc (n_rects * 8 * sizeof (glitz_float_t)); - if (!data) - return CAIRO_STATUS_NO_MEMORY; - - buffer = glitz_buffer_create_for_data (data); - if (buffer == NULL) { - free (data); - return CAIRO_STATUS_NO_MEMORY; - } + if (op == CAIRO_OPERATOR_SATURATE) + return CAIRO_INT_STATUS_UNSUPPORTED; - width = height = 0; - vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); - for (; n_rects; rects++, n_rects--) { - *vertices++ = (glitz_float_t) rects->x; - *vertices++ = (glitz_float_t) rects->y; - *vertices++ = (glitz_float_t) (rects->x + rects->width); - *vertices++ = (glitz_float_t) rects->y; - *vertices++ = (glitz_float_t) (rects->x + rects->width); - *vertices++ = (glitz_float_t) (rects->y + rects->height); - *vertices++ = (glitz_float_t) rects->x; - *vertices++ = (glitz_float_t) (rects->y + rects->height); - - if ((rects->x + rects->width) > width) - width = rects->x + rects->width; - - if ((rects->y + rects->height) > height) - height = rects->y + rects->height; - } - glitz_buffer_unmap (buffer); + if (_glitz_ensure_target (dst->surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; - solid = _glitz_surface_create_solid (dst->surface, - GLITZ_STANDARD_ARGB32, - &glitz_color); - if (solid == NULL) + src = (cairo_glitz_surface_t *) + _cairo_surface_create_similar_solid (&dst->base, + CAIRO_FORMAT_ARGB32, 1, 1, + (cairo_color_t *) color); + if (!src) return CAIRO_STATUS_NO_MEMORY; - - status = _glitz_composite (_glitz_operator (op), - solid, - NULL, - dst->surface, - 0, 0, - 0, 0, - 0, 0, - width, height, - buffer, &gf); - - glitz_surface_destroy (solid); - glitz_buffer_destroy (buffer); - free (data); - - return status; - } else { - if (glitz_surface_get_width (dst->surface) != 1 || - glitz_surface_get_height (dst->surface) != 1) { - if (_glitz_ensure_target (dst->surface)) - return CAIRO_INT_STATUS_UNSUPPORTED; + + while (n_rects--) + { + glitz_composite (_glitz_operator (op), + src->surface, + NULL, + dst->surface, + 0, 0, + 0, 0, + rects->x, rects->y, + rects->width, rects->height); + rects++; } - glitz_set_rectangles (dst->surface, &glitz_color, - (glitz_rectangle_t *) rects, n_rects); + cairo_surface_destroy (&src->base); } + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t -_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, - cairo_surface_t *generic_src, - void *abstract_dst, - int x_src, - int y_src, +_cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, + cairo_pattern_t *pattern, + void *abstract_dst, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, - int n_traps) + int n_traps) { - cairo_glitz_surface_t *dst = abstract_dst; - cairo_glitz_surface_t *src = (cairo_glitz_surface_t *) generic_src; - glitz_surface_t *mask = NULL; - glitz_float_t *vertices; - glitz_buffer_t *buffer; - glitz_geometry_format_t gf; - cairo_int_status_t status; - int x_dst, y_dst, x_rel, y_rel, width, height; - void *data; + cairo_glitz_surface_attributes_t attributes; + cairo_glitz_surface_t *dst = abstract_dst; + cairo_glitz_surface_t *src; + cairo_glitz_surface_t *mask = NULL; + glitz_buffer_t *buffer = NULL; + void *data = NULL; + cairo_int_status_t status; + unsigned short alpha; if (op == CAIRO_OPERATOR_SATURATE) return CAIRO_INT_STATUS_UNSUPPORTED; - if (generic_src->backend != dst->base.backend) + if (_glitz_ensure_target (dst->surface)) return CAIRO_INT_STATUS_UNSUPPORTED; - gf.mode = GLITZ_GEOMETRY_MODE_DIRECT; - gf.edge_hint = GLITZ_GEOMETRY_EDGE_HINT_GOOD_SMOOTH; - gf.primitive = GLITZ_GEOMETRY_PRIMITIVE_QUADS; - gf.type = GLITZ_DATA_TYPE_FLOAT; - gf.first = 0; - gf.count = n_traps * 4; + if (pattern->type == CAIRO_PATTERN_SURFACE) + { + cairo_pattern_union_t tmp; - data = malloc (n_traps * 8 * sizeof (glitz_float_t)); - if (!data) - return CAIRO_STATUS_NO_MEMORY; - - buffer = glitz_buffer_create_for_data (data); - if (buffer == NULL) { - free (data); - return CAIRO_STATUS_NO_MEMORY; - } - - x_dst = traps[0].left.p1.x >> 16; - y_dst = traps[0].left.p1.y >> 16; + _cairo_pattern_init_copy (&tmp.base, pattern); + _cairo_pattern_set_alpha (&tmp.base, 1.0); - vertices = glitz_buffer_map (buffer, GLITZ_BUFFER_ACCESS_WRITE_ONLY); - for (; n_traps; traps++, n_traps--) { - glitz_float_t top, bottom; + status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst, + src_x, src_y, + width, height, + &src, &attributes); - top = GLITZ_FIXED_TO_FLOAT (traps->top); - bottom = GLITZ_FIXED_TO_FLOAT (traps->bottom); + _cairo_pattern_fini (&tmp.base); - *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->top); - *vertices++ = top; - *vertices++ = - GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->top); - *vertices++ = top; - *vertices++ = - GLITZ_FIXED_LINE_X_CEIL_TO_FLOAT (traps->right, traps->bottom); - *vertices++ = bottom; - *vertices++ = GLITZ_FIXED_LINE_X_TO_FLOAT (traps->left, traps->bottom); - *vertices++ = bottom; + alpha = pattern->alpha * 0xffff; } - glitz_buffer_unmap (buffer); + else + { + status = _cairo_glitz_pattern_acquire_surface (pattern, dst, + src_x, src_y, + width, height, + &src, &attributes); + alpha = 0xffff; + } + + if (status) + return status; + + if (op == CAIRO_OPERATOR_ADD || n_traps <= 1) + { + static glitz_color_t clear_black = { 0, 0, 0, 0 }; + glitz_color_t color; + glitz_geometry_format_t format; + int n_trap_added; + int offset = 0; + int data_size = 0; + int size = 30 * n_traps; /* just a guess */ + + format.vertex.primitive = GLITZ_PRIMITIVE_QUADS; + format.vertex.type = GLITZ_DATA_TYPE_FLOAT; + format.vertex.bytes_per_vertex = 3 * sizeof (glitz_float_t); + format.vertex.attributes = GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK; + format.vertex.mask.type = GLITZ_DATA_TYPE_FLOAT; + format.vertex.mask.size = GLITZ_COORDINATE_SIZE_X; + format.vertex.mask.offset = 2 * sizeof (glitz_float_t); + + mask = (cairo_glitz_surface_t *) + _cairo_glitz_surface_create_similar (&dst->base, + CAIRO_FORMAT_A8, 0, + 2, 1); + if (!mask) + { + _cairo_glitz_pattern_release_surface (dst, src, &attributes); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + color.red = color.green = color.blue = color.alpha = alpha; - if ((src->pattern.type == CAIRO_PATTERN_SURFACE) && - (src->pattern.color.alpha != 1.0)) { - glitz_color_t color; + glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1); + glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1); + + glitz_surface_set_fill (mask->surface, GLITZ_FILL_NEAREST); + glitz_surface_set_filter (mask->surface, + GLITZ_FILTER_BILINEAR, + NULL, 0); + + size *= format.vertex.bytes_per_vertex; - color.red = color.green = color.blue = 0; - color.alpha = src->pattern.color.alpha_short; + while (n_traps) + { + if (data_size < size) + { + data_size = size; + data = realloc (data, data_size); + if (!data) + { + _cairo_glitz_pattern_release_surface (dst, src, + &attributes); + return CAIRO_STATUS_NO_MEMORY; + } + + if (buffer) + glitz_buffer_destroy (buffer); + + buffer = glitz_buffer_create_for_data (data); + if (!buffer) { + free (data); + _cairo_glitz_pattern_release_surface (dst, src, + &attributes); + return CAIRO_STATUS_NO_MEMORY; + } + } - mask = _glitz_surface_create_solid (dst->surface, - GLITZ_STANDARD_A8, - &color); + offset += + glitz_add_trapezoids (buffer, + offset, size - offset, + format.vertex.type, mask->surface, + (glitz_trapezoid_t *) traps, n_traps, + &n_trap_added); + + n_traps -= n_trap_added; + traps += n_trap_added; + size *= 2; + } + + glitz_set_geometry (dst->surface, + GLITZ_GEOMETRY_TYPE_VERTEX, + &format, buffer); + glitz_set_array (dst->surface, 0, 3, + offset / format.vertex.bytes_per_vertex, + 0, 0); } + else + { + cairo_image_surface_t *image; + char *ptr; + int stride; + + stride = (width + 3) & -4; + data = malloc (stride * height); + if (!data) + { + _cairo_glitz_pattern_release_surface (dst, src, &attributes); + return CAIRO_STATUS_NO_MEMORY; + } + + memset (data, 0, stride * height); - x_rel = (src->pattern_box.p1.x >> 16) + x_src - x_dst; - y_rel = (src->pattern_box.p1.y >> 16) + y_src - y_dst; + /* using negative stride */ + ptr = (char *) data + stride * (height - 1); + + image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (ptr, + CAIRO_FORMAT_A8, + width, height, + -stride); + if (!image) + { + cairo_surface_destroy (&src->base); + free (data); + return CAIRO_STATUS_NO_MEMORY; + } - x_dst = src->pattern_box.p1.x >> 16; - y_dst = src->pattern_box.p1.y >> 16; + pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y, + (pixman_trapezoid_t *) traps, n_traps); + + if (alpha != 0xffff) + { + pixman_color_t color; + + color.red = color.green = color.blue = color.alpha = alpha; + + pixman_fill_rectangle (PIXMAN_OPERATOR_IN, + image->pixman_image, + &color, + 0, 0, width, height); + } + + mask = (cairo_glitz_surface_t *) + _cairo_surface_create_similar_scratch (&dst->base, + CAIRO_FORMAT_A8, 0, + width, height); + if (!mask) + { + _cairo_glitz_pattern_release_surface (dst, src, &attributes); + free (data); + cairo_surface_destroy (&image->base); + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_glitz_surface_set_image (mask, image, 0, 0); + } + + _cairo_glitz_surface_set_attributes (src, &attributes); - width = ((src->pattern_box.p2.x + 65535) >> 16) - - (src->pattern_box.p1.x >> 16); - height = ((src->pattern_box.p2.y + 65535) >> 16) - - (src->pattern_box.p1.y >> 16); + glitz_composite (_glitz_operator (op), + src->surface, + mask->surface, + dst->surface, + src_x + attributes.base.x_offset, + src_y + attributes.base.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + + if (attributes.n_params) + free (attributes.params); + + glitz_set_geometry (dst->surface, + GLITZ_GEOMETRY_TYPE_NONE, + NULL, NULL); + + if (buffer) + glitz_buffer_destroy (buffer); - status = _glitz_composite (_glitz_operator (op), - src->surface, - mask, - dst->surface, - x_rel, y_rel, - 0, 0, - x_dst, y_dst, - width, height, - buffer, &gf); + free (data); + _cairo_glitz_pattern_release_surface (dst, src, &attributes); if (mask) - glitz_surface_destroy (mask); + cairo_surface_destroy (&mask->base); - glitz_buffer_destroy (buffer); - free (data); + if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -819,173 +1240,56 @@ _cairo_glitz_surface_show_page (void *abstract_surface) } static cairo_int_status_t -_cairo_glitz_surface_create_pattern (void *abstract_dst, - cairo_pattern_t *pattern, - cairo_box_t *box) +_cairo_glitz_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) { - cairo_glitz_surface_t *dst = abstract_dst; - cairo_surface_t *generic_src = NULL; - cairo_image_surface_t *image = NULL; - cairo_glitz_surface_t *src; - - switch (pattern->type) { - case CAIRO_PATTERN_SOLID: - generic_src = - _cairo_surface_create_similar_solid (abstract_dst, - CAIRO_FORMAT_ARGB32, - 1, 1, - &pattern->color); - if (generic_src) - cairo_surface_set_repeat (generic_src, 1); - break; - case CAIRO_PATTERN_RADIAL: - /* glitz doesn't support inner and outer circle with different - center points. */ - if (pattern->u.radial.center0.x != pattern->u.radial.center1.x || - pattern->u.radial.center0.y != pattern->u.radial.center1.y) - break; - /* fall-through */ - case CAIRO_PATTERN_LINEAR: { - glitz_drawable_t *drawable; - glitz_fixed16_16_t *params; - int i, n_params; - - drawable = glitz_surface_get_drawable (dst->surface); - if (!(glitz_drawable_get_features (drawable) & - GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK)) - break; - - if (pattern->filter != CAIRO_FILTER_BILINEAR) - break; - - n_params = pattern->n_stops * 3 + 4; - - params = malloc (sizeof (glitz_fixed16_16_t) * n_params); - if (params == NULL) - return CAIRO_STATUS_NO_MEMORY; - - generic_src = - _cairo_glitz_surface_create_similar (abstract_dst, - CAIRO_FORMAT_ARGB32, 0, - pattern->n_stops, 1); - if (generic_src == NULL) { - free (params); - return CAIRO_STATUS_NO_MEMORY; - } - - src = (cairo_glitz_surface_t *) generic_src; - - for (i = 0; i < pattern->n_stops; i++) { - glitz_color_t color; + cairo_glitz_surface_t *surface = abstract_surface; - color.alpha = pattern->stops[i].color_char[3]; - color.red = pattern->stops[i].color_char[0] * color.alpha; - color.green = pattern->stops[i].color_char[1] * color.alpha; - color.blue = pattern->stops[i].color_char[2] * color.alpha; - color.alpha *= 256; + if (region) + { + glitz_box_t *box; + int n; - glitz_set_rectangle (src->surface, &color, i, 0, 1, 1); - - params[4 + 3 * i] = pattern->stops[i].offset; - params[5 + 3 * i] = i << 16; - params[6 + 3 * i] = 0; - } - - if (pattern->type == CAIRO_PATTERN_LINEAR) { - params[0] = _cairo_fixed_from_double (pattern->u.linear.point0.x); - params[1] = _cairo_fixed_from_double (pattern->u.linear.point0.y); - params[2] = _cairo_fixed_from_double (pattern->u.linear.point1.x); - params[3] = _cairo_fixed_from_double (pattern->u.linear.point1.y); - - glitz_surface_set_filter (src->surface, - GLITZ_FILTER_LINEAR_GRADIENT, - params, n_params); - } else { - params[0] = _cairo_fixed_from_double (pattern->u.radial.center0.x); - params[1] = _cairo_fixed_from_double (pattern->u.radial.center0.y); - params[2] = _cairo_fixed_from_double (pattern->u.radial.radius0); - params[3] = _cairo_fixed_from_double (pattern->u.radial.radius1); - - glitz_surface_set_filter (src->surface, - GLITZ_FILTER_RADIAL_GRADIENT, - params, n_params); - } - - switch (pattern->extend) { - case CAIRO_EXTEND_REPEAT: - glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); - break; - case CAIRO_EXTEND_REFLECT: - glitz_surface_set_fill (src->surface, GLITZ_FILL_REFLECT); - break; - case CAIRO_EXTEND_NONE: - default: - glitz_surface_set_fill (src->surface, GLITZ_FILL_NEAREST); - break; + if (!surface->clip) + { + surface->clip = pixman_region_create (); + if (!surface->clip) + return CAIRO_STATUS_NO_MEMORY; } + pixman_region_copy (surface->clip, region); - cairo_surface_set_matrix (&src->base, &pattern->matrix); - - free (params); - } break; - case CAIRO_PATTERN_SURFACE: - generic_src = pattern->u.surface.surface; - cairo_surface_reference (generic_src); - break; - } - - if (generic_src == NULL) { - image = _cairo_pattern_get_image (pattern, box); - if (image == NULL) - return CAIRO_STATUS_NO_MEMORY; - - generic_src = &image->base; + box = (glitz_box_t *) pixman_region_rects (surface->clip); + n = pixman_region_num_rects (surface->clip); + glitz_surface_set_clip_region (surface->surface, 0, 0, box, n); } + else + { + glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); - if (generic_src->backend != dst->base.backend) { - src = _cairo_glitz_surface_clone_similar (dst, generic_src, - CAIRO_FORMAT_ARGB32); - if (src == NULL) - return CAIRO_STATUS_NO_MEMORY; - - cairo_surface_set_repeat (&src->base, generic_src->repeat); - } else - src = (cairo_glitz_surface_t *) generic_src; + if (surface->clip) + pixman_region_destroy (surface->clip); - if (image) - cairo_surface_destroy (&image->base); - - _cairo_pattern_init_copy (&src->pattern, pattern); - src->pattern_box = *box; - - pattern->source = &src->base; + surface->clip = NULL; + } return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_glitz_surface_set_clip_region (void *abstract_surface, - pixman_region16_t *region) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - static const cairo_surface_backend_t cairo_glitz_surface_backend = { _cairo_glitz_surface_create_similar, _cairo_glitz_surface_destroy, _cairo_glitz_surface_pixels_per_inch, - _cairo_glitz_surface_get_image, - _cairo_glitz_surface_set_image, - _cairo_glitz_surface_set_matrix, - _cairo_glitz_surface_set_filter, - _cairo_glitz_surface_set_repeat, + _cairo_glitz_surface_acquire_source_image, + _cairo_glitz_surface_release_source_image, + _cairo_glitz_surface_acquire_dest_image, + _cairo_glitz_surface_release_dest_image, + _cairo_glitz_surface_clone_similar, _cairo_glitz_surface_composite, _cairo_glitz_surface_fill_rectangles, _cairo_glitz_surface_composite_trapezoids, _cairo_glitz_surface_copy_page, _cairo_glitz_surface_show_page, _cairo_glitz_surface_set_clip_region, - _cairo_glitz_surface_create_pattern, NULL /* show_glyphs */ }; @@ -1004,12 +1308,10 @@ cairo_glitz_surface_create (glitz_surface_t *surface) _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend); glitz_surface_reference (surface); - crsurface->surface = surface; - crsurface->format = glitz_surface_get_format (surface); - _cairo_pattern_init (&crsurface->pattern); - crsurface->pattern.type = CAIRO_PATTERN_SURFACE; - crsurface->pattern.u.surface.surface = NULL; + crsurface->surface = surface; + crsurface->format = glitz_surface_get_format (surface); + crsurface->clip = NULL; return (cairo_surface_t *) crsurface; } diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c index e855a7a66..d6db560a3 100644 --- a/src/cairo_gstate.c +++ b/src/cairo_gstate.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include <stdlib.h> @@ -46,20 +46,33 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, cairo_surface_t *dst, cairo_traps_t *traps); +static cairo_status_t +_cairo_gstate_ensure_font (cairo_gstate_t *gstate); + +static void +_cairo_gstate_unset_font (cairo_gstate_t *gstate); + cairo_gstate_t * _cairo_gstate_create () { + cairo_status_t status; cairo_gstate_t *gstate; gstate = malloc (sizeof (cairo_gstate_t)); if (gstate) - _cairo_gstate_init (gstate); + { + status = _cairo_gstate_init (gstate); + if (status) { + free (gstate); + return NULL; + } + } return gstate; } -void +cairo_status_t _cairo_gstate_init (cairo_gstate_t *gstate) { gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT; @@ -77,9 +90,11 @@ _cairo_gstate_init (cairo_gstate_t *gstate) gstate->num_dashes = 0; gstate->dash_offset = 0.0; - gstate->font = _cairo_unscaled_font_create (CAIRO_FONT_FAMILY_DEFAULT, - CAIRO_FONT_SLANT_DEFAULT, - CAIRO_FONT_WEIGHT_DEFAULT); + gstate->font_family = NULL; + gstate->font_slant = CAIRO_FONT_SLANT_DEFAULT; + gstate->font_weight = CAIRO_FONT_WEIGHT_DEFAULT; + + gstate->font = NULL; gstate->surface = NULL; @@ -87,6 +102,9 @@ _cairo_gstate_init (cairo_gstate_t *gstate) gstate->clip.surface = NULL; gstate->pattern = _cairo_pattern_create_solid (0.0, 0.0, 0.0); + if (!gstate->pattern) + return CAIRO_STATUS_NO_MEMORY; + gstate->alpha = 1.0; gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT; @@ -97,6 +115,8 @@ _cairo_gstate_init (cairo_gstate_t *gstate) _cairo_pen_init_empty (&gstate->pen_regular); gstate->next = NULL; + + return CAIRO_STATUS_SUCCESS; } cairo_status_t @@ -118,9 +138,15 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double)); } + if (other->font_family) { + gstate->font_family = strdup (other->font_family); + if (!gstate->font_family) + goto CLEANUP_DASH; + } + if (other->font) { gstate->font = other->font; - _cairo_unscaled_font_reference (gstate->font); + cairo_font_reference (gstate->font); } if (other->clip.region) @@ -148,18 +174,29 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) _cairo_path_fini (&gstate->path); CLEANUP_FONT: - _cairo_unscaled_font_destroy (gstate->font); + cairo_font_destroy (gstate->font); + gstate->font = NULL; + + if (gstate->font_family) { + free (gstate->font_family); + gstate->font_family = NULL; + } + CLEANUP_DASH: free (gstate->dash); gstate->dash = NULL; - return status; + return CAIRO_STATUS_NO_MEMORY; } void _cairo_gstate_fini (cairo_gstate_t *gstate) { - _cairo_unscaled_font_destroy (gstate->font); + if (gstate->font_family) + free (gstate->font_family); + + if (gstate->font) + cairo_font_destroy (gstate->font); if (gstate->surface) cairo_surface_destroy (gstate->surface); @@ -323,6 +360,8 @@ _cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surfa { double scale; + _cairo_gstate_unset_font (gstate); + if (gstate->surface) cairo_surface_destroy (gstate->surface); @@ -365,11 +404,9 @@ _cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern) if (pattern == NULL) return CAIRO_STATUS_NULL_POINTER; - if (gstate->pattern) - cairo_pattern_destroy (gstate->pattern); - - gstate->pattern = pattern; cairo_pattern_reference (pattern); + cairo_pattern_destroy (gstate->pattern); + gstate->pattern = pattern; return CAIRO_STATUS_SUCCESS; } @@ -407,6 +444,8 @@ _cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, d cairo_pattern_destroy (gstate->pattern); gstate->pattern = _cairo_pattern_create_solid (red, green, blue); + if (!gstate->pattern) + return CAIRO_STATUS_NO_MEMORY; return CAIRO_STATUS_SUCCESS; } @@ -549,6 +588,8 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty) { cairo_matrix_t tmp; + _cairo_gstate_unset_font (gstate); + _cairo_matrix_set_translate (&tmp, tx, ty); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -566,6 +607,8 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy) if (sx == 0 || sy == 0) return CAIRO_STATUS_INVALID_MATRIX; + _cairo_gstate_unset_font (gstate); + _cairo_matrix_set_scale (&tmp, sx, sy); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -580,6 +623,8 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle) { cairo_matrix_t tmp; + _cairo_gstate_unset_font (gstate); + _cairo_matrix_set_rotate (&tmp, angle); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -595,6 +640,8 @@ _cairo_gstate_concat_matrix (cairo_gstate_t *gstate, { cairo_matrix_t tmp; + _cairo_gstate_unset_font (gstate); + cairo_matrix_copy (&tmp, matrix); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -610,6 +657,8 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate, { cairo_status_t status; + _cairo_gstate_unset_font (gstate); + cairo_matrix_copy (&gstate->ctm, matrix); cairo_matrix_copy (&gstate->ctm_inverse, matrix); @@ -627,6 +676,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate) if (scale == 0) scale = 1; + _cairo_gstate_unset_font (gstate); + cairo_matrix_set_identity (&gstate->font_matrix); cairo_matrix_set_identity (&gstate->ctm); @@ -640,6 +691,8 @@ _cairo_gstate_default_matrix (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_identity_matrix (cairo_gstate_t *gstate) { + _cairo_gstate_unset_font (gstate); + cairo_matrix_set_identity (&gstate->ctm); cairo_matrix_set_identity (&gstate->ctm_inverse); @@ -1256,54 +1309,17 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate, &gpi); } -/* This function modifies the pattern and the state of the pattern surface it - may contain. The pattern surface will be restored to its orignal state - when the pattern is destroyed. The appropriate way is to pass a copy of - the original pattern to this function just before the pattern should be - used and destroy the copy when done. */ -static cairo_status_t -_cairo_gstate_create_pattern (cairo_gstate_t *gstate, - cairo_pattern_t *pattern, - cairo_box_t *extents) +/* XXX: gstate->alpha will be going away before too long, and when it + * does, it may make sense for this function to just disappear. + */ +static void +_cairo_gstate_pattern_init_copy (cairo_gstate_t *gstate, + cairo_pattern_union_t *pattern, + cairo_pattern_t *src) { - cairo_int_status_t status; - - if (gstate->surface == NULL) { - _cairo_pattern_fini (pattern); - return CAIRO_STATUS_NO_TARGET_SURFACE; - } - - if (pattern->type == CAIRO_PATTERN_LINEAR || - pattern->type == CAIRO_PATTERN_RADIAL) { - if (pattern->n_stops < 2) { - pattern->type = CAIRO_PATTERN_SOLID; - - if (pattern->n_stops) { - cairo_color_stop_t *stop = pattern->stops; - - _cairo_color_set_rgb (&pattern->color, - (double) stop->color_char[0] / 0xff, - (double) stop->color_char[1] / 0xff, - (double) stop->color_char[2] / 0xff); - _cairo_color_set_alpha (&pattern->color, - (double) stop->color_char[3] / 0xff); - } - } - } - - _cairo_pattern_set_alpha (pattern, gstate->alpha); - _cairo_pattern_transform (pattern, &gstate->ctm_inverse); - - status = _cairo_surface_create_pattern (gstate->surface, pattern, extents); - if (status) { - _cairo_pattern_fini (pattern); - return status; - } - - if (pattern->type == CAIRO_PATTERN_SURFACE) - _cairo_pattern_prepare_surface (pattern); - - return CAIRO_STATUS_SUCCESS; + _cairo_pattern_init_copy (&pattern->base, src); + _cairo_pattern_transform (&pattern->base, &gstate->ctm_inverse); + _cairo_pattern_set_alpha (&pattern->base, gstate->alpha); } cairo_status_t @@ -1342,7 +1358,7 @@ cairo_status_t _cairo_gstate_in_stroke (cairo_gstate_t *gstate, double x, double y, - int *inside_ret) + cairo_bool_t *inside_ret) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_traps_t traps; @@ -1365,51 +1381,85 @@ BAIL: return status; } -static cairo_status_t -_calculate_region_for_intermediate_clip_surface (pixman_region16_t *out, - cairo_box_t *extents, - cairo_clip_rec_t *clip_rect) +/* XXX We currently have a confusing mix of boxes and rectangles as + * exemplified by this function. A cairo_box_t is a rectangular area + * represented by the coordinates of the upper left and lower right + * corners, expressed in fixed point numbers. A cairo_rectangle_t is + * also a rectangular area, but represented by the upper left corner + * and the width and the height, as integer numbers. + * + * This function converts a cairo_box_t to a cairo_rectangle_t by + * increasing the area to the nearest integer coordinates. We should + * standardize on cairo_rectangle_t and cairo_rectangle_fixed_t, and + * this function could be renamed to the more reasonable + * _cairo_rectangle_fixed_round. + */ + +static void +_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle) { - cairo_status_t status; - pixman_region16_t *extents_region, *clip_region; - pixman_box16_t clip_box, pixman_extents; - - pixman_extents.x1 = _cairo_fixed_integer_floor (extents->p1.x); - pixman_extents.y1 = _cairo_fixed_integer_floor (extents->p1.y); - pixman_extents.x2 = _cairo_fixed_integer_ceil (extents->p2.x); - pixman_extents.y2 = _cairo_fixed_integer_ceil (extents->p2.y); - extents_region = pixman_region_create_simple (&pixman_extents); - if (extents_region == NULL) - { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; - } + rectangle->x = _cairo_fixed_integer_floor (box->p1.x); + rectangle->y = _cairo_fixed_integer_floor (box->p1.y); + rectangle->width = _cairo_fixed_integer_ceil (box->p2.x) - rectangle->x; + rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y; +} - clip_box.x1 = clip_rect->x; - clip_box.y1 = clip_rect->y; - clip_box.x2 = clip_rect->x + clip_rect->width; - clip_box.y2 = clip_rect->y + clip_rect->height; - clip_region = pixman_region_create_simple (&clip_box); - if (clip_region == NULL) - { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL1; - } +static void +_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src) +{ + int x1, y1, x2, y2; - if (pixman_region_intersect (out, - extents_region, - clip_region) - == PIXMAN_REGION_STATUS_FAILURE) - status = CAIRO_STATUS_NO_MEMORY; - else - status = CAIRO_STATUS_SUCCESS; - - pixman_region_destroy (extents_region); - BAIL1: - pixman_region_destroy (clip_region); - - BAIL0: - return status; + x1 = MAX (dest->x, src->x); + y1 = MAX (dest->y, src->y); + x2 = MIN (dest->x + dest->width, src->x + src->width); + y2 = MIN (dest->y + dest->height, src->y + src->height); + + if (x1 >= x2 || y1 >= y2) { + dest->x = 0; + dest->y = 0; + dest->width = 0; + dest->height = 0; + } else { + dest->x = x1; + dest->y = y1; + dest->width = x2 - x1; + dest->height = y2 - y1; + } +} + +static int +_cairo_rectangle_empty (cairo_rectangle_t *rect) +{ + return rect->width == 0 || rect->height == 0; +} + +static void +translate_traps (cairo_traps_t *traps, int x, int y) +{ + cairo_fixed_t xoff, yoff; + cairo_trapezoid_t *t; + int i; + + /* Ugh. The cairo_composite/(Render) interface doesn't allow + an offset for the trapezoids. Need to manually shift all + the coordinates to align with the offset origin of the + intermediate surface. */ + + xoff = _cairo_fixed_from_int (x); + yoff = _cairo_fixed_from_int (y); + + for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) { + t->top += yoff; + t->bottom += yoff; + t->left.p1.x += xoff; + t->left.p1.y += yoff; + t->left.p2.x += xoff; + t->left.p2.y += yoff; + t->right.p1.x += xoff; + t->right.p1.y += yoff; + t->right.p2.x += xoff; + t->right.p2.y += yoff; + } } @@ -1422,173 +1472,148 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, cairo_traps_t *traps) { cairo_status_t status; - cairo_pattern_t pattern; - cairo_box_t extents; - int x_src, y_src; + cairo_pattern_union_t pattern; + cairo_rectangle_t extents; + cairo_box_t trap_extents; if (traps->num_traps == 0) return CAIRO_STATUS_SUCCESS; + if (gstate->surface == NULL) + return CAIRO_STATUS_NO_TARGET_SURFACE; + + _cairo_traps_extents (traps, &trap_extents); + _cairo_box_round_to_rectangle (&trap_extents, &extents); + if (gstate->clip.surface) { - cairo_fixed_t xoff, yoff; - cairo_trapezoid_t *t; - int i; cairo_surface_t *intermediate; + cairo_surface_pattern_t intermediate_pattern; cairo_color_t empty_color; - pixman_box16_t *draw_extents; - pixman_region16_t *draw_region; - draw_region = pixman_region_create (); - if (draw_region == NULL) - { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; - } - - _cairo_traps_extents (traps, &extents); - - status = _calculate_region_for_intermediate_clip_surface (draw_region, - &extents, - &gstate->clip); - if (status) - goto BAIL1; + _cairo_rectangle_intersect (&extents, &gstate->clip.rect); - /* Shortcut if empty */ - if (!pixman_region_not_empty (draw_region)) { + if (_cairo_rectangle_empty (&extents)) { status = CAIRO_STATUS_SUCCESS; goto BAIL1; } - draw_extents = pixman_region_extents (draw_region); - - /* Ugh. The cairo_composite/(Render) interface doesn't allow - an offset for the trapezoids. Need to manually shift all - the coordinates to align with the offset origin of the - intermediate surface. */ - xoff = _cairo_fixed_from_int (draw_extents->x1); - yoff = _cairo_fixed_from_int (draw_extents->y1); - for (i=0, t=traps->traps; i < traps->num_traps; i++, t++) { - t->top -= yoff; - t->bottom -= yoff; - t->left.p1.x -= xoff; - t->left.p1.y -= yoff; - t->left.p2.x -= xoff; - t->left.p2.y -= yoff; - t->right.p1.x -= xoff; - t->right.p1.y -= yoff; - t->right.p2.x -= xoff; - t->right.p2.y -= yoff; - } - - if (traps->traps[0].left.p1.y < traps->traps[0].left.p2.y) { - x_src = _cairo_fixed_to_double (traps->traps[0].left.p1.x); - y_src = _cairo_fixed_to_double (traps->traps[0].left.p1.y); - } else { - x_src = _cairo_fixed_to_double (traps->traps[0].left.p2.x); - y_src = _cairo_fixed_to_double (traps->traps[0].left.p2.y); - } - - _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); - _cairo_pattern_set_alpha (&pattern, 1.0); - - status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); - if (status) - goto BAIL1; + translate_traps (traps, -extents.x, -extents.y); _cairo_color_init (&empty_color); _cairo_color_set_alpha (&empty_color, 0.); intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, CAIRO_FORMAT_A8, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1, + extents.width, + extents.height, &empty_color); if (intermediate == NULL) { status = CAIRO_STATUS_NO_MEMORY; - goto BAIL2; + goto BAIL1; } + _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0); + status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD, - pattern.source, intermediate, - x_src, - y_src, + &pattern.base, + intermediate, + extents.x, extents.y, + 0, 0, + extents.width, + extents.height, traps->traps, traps->num_traps); + _cairo_pattern_fini (&pattern.base); + if (status) - goto BAIL3; + goto BAIL2; + + + _cairo_pattern_init_for_surface (&pattern.surface, + gstate->clip.surface); status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - gstate->clip.surface, + &pattern.base, NULL, intermediate, - draw_extents->x1 - gstate->clip.x, - draw_extents->y1 - gstate->clip.y, + extents.x - gstate->clip.rect.x, + extents.y - gstate->clip.rect.y, 0, 0, 0, 0, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); - if (status) - goto BAIL3; - - _cairo_pattern_fini (&pattern); + extents.width, extents.height); + _cairo_pattern_fini (&pattern.base); - _cairo_pattern_init_copy (&pattern, src); - - extents.p1.x = _cairo_fixed_from_int (draw_extents->x1); - extents.p1.y = _cairo_fixed_from_int (draw_extents->y1); - extents.p2.x = _cairo_fixed_from_int (draw_extents->x2); - extents.p2.y = _cairo_fixed_from_int (draw_extents->y2); - status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); if (status) - goto BAIL3; + goto BAIL2; - if (dst == gstate->clip.surface) - xoff = yoff = 0; + _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); + _cairo_gstate_pattern_init_copy (gstate, &pattern, src); status = _cairo_surface_composite (operator, - pattern.source, intermediate, dst, - 0, 0, + &pattern.base, + &intermediate_pattern.base, + dst, + extents.x, extents.y, 0, 0, - xoff >> 16, - yoff >> 16, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); + extents.x, extents.y, + extents.width, extents.height); + _cairo_pattern_fini (&pattern.base); + _cairo_pattern_fini (&intermediate_pattern.base); - BAIL3: - cairo_surface_destroy (intermediate); BAIL2: - _cairo_pattern_fini (&pattern); + cairo_surface_destroy (intermediate); BAIL1: - pixman_region_destroy (draw_region); - BAIL0: if (status) return status; } else { - if (traps->traps[0].left.p1.y < traps->traps[0].left.p2.y) { - x_src = _cairo_fixed_to_double (traps->traps[0].left.p1.x); - y_src = _cairo_fixed_to_double (traps->traps[0].left.p1.y); - } else { - x_src = _cairo_fixed_to_double (traps->traps[0].left.p2.x); - y_src = _cairo_fixed_to_double (traps->traps[0].left.p2.y); + if (gstate->clip.region) { + pixman_box16_t box; + pixman_box16_t *intersection_extents; + pixman_region16_t *rect, *intersection; + + box.x1 = _cairo_fixed_integer_floor (trap_extents.p1.x); + box.y1 = _cairo_fixed_integer_floor (trap_extents.p1.y); + box.x2 = _cairo_fixed_integer_ceil (trap_extents.p2.x); + box.y2 = _cairo_fixed_integer_ceil (trap_extents.p2.y); + + rect = pixman_region_create_simple (&box); + if (rect == NULL) + goto bail1; + intersection = pixman_region_create(); + if (intersection == NULL) + goto bail2; + + if (pixman_region_intersect (intersection, gstate->clip.region, + rect) != PIXMAN_REGION_STATUS_SUCCESS) + goto bail3; + intersection_extents = pixman_region_extents (intersection); + + extents.x = intersection_extents->x1; + extents.y = intersection_extents->y1; + extents.width = intersection_extents->x2 - intersection_extents->x1; + extents.height = intersection_extents->y2 - intersection_extents->y1; + bail3: + pixman_region_destroy (intersection); + bail2: + pixman_region_destroy (rect); + bail1: + ; } - _cairo_pattern_init_copy (&pattern, src); + _cairo_gstate_pattern_init_copy (gstate, &pattern, src); - _cairo_traps_extents (traps, &extents); - status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); - if (status) - return status; - status = _cairo_surface_composite_trapezoids (gstate->operator, - pattern.source, dst, - x_src - pattern.source_offset.x, - y_src - pattern.source_offset.y, + &pattern.base, dst, + extents.x, extents.y, + extents.x, extents.y, + extents.width, + extents.height, traps->traps, traps->num_traps); - _cairo_pattern_fini (&pattern); + _cairo_pattern_fini (&pattern.base); if (status) return status; @@ -1628,7 +1653,7 @@ cairo_status_t _cairo_gstate_in_fill (cairo_gstate_t *gstate, double x, double y, - int *inside_ret) + cairo_bool_t *inside_ret) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_traps_t traps; @@ -1807,9 +1832,10 @@ cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate) { cairo_status_t status; - cairo_pattern_t pattern; + cairo_pattern_union_t pattern; cairo_traps_t traps; cairo_color_t white_color; + cairo_box_t extents; pixman_box16_t box; /* Fill the clip region as traps. */ @@ -1871,33 +1897,32 @@ _cairo_gstate_clip (cairo_gstate_t *gstate) _cairo_color_init (&white_color); if (gstate->clip.surface == NULL) { - cairo_box_t extents; - _cairo_traps_extents (&traps, &extents); - gstate->clip.x = extents.p1.x >> 16; - gstate->clip.y = extents.p1.y >> 16; - gstate->clip.width = ((extents.p2.x + 65535) >> 16) - gstate->clip.x; - gstate->clip.height = ((extents.p2.y + 65535) >> 16) - gstate->clip.y; + _cairo_box_round_to_rectangle (&extents, &gstate->clip.rect); gstate->clip.surface = _cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, - gstate->clip.width, - gstate->clip.height, + gstate->clip.rect.width, + gstate->clip.rect.height, &white_color); if (gstate->clip.surface == NULL) return CAIRO_STATUS_NO_MEMORY; } - _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); - _cairo_pattern_set_alpha (&pattern, 1.0); - - _cairo_gstate_clip_and_composite_trapezoids (gstate, - &pattern, - CAIRO_OPERATOR_IN, - gstate->clip.surface, - &traps); + translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y); + _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0); - _cairo_pattern_fini (&pattern); + status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN, + &pattern.base, + gstate->clip.surface, + 0, 0, + 0, 0, + gstate->clip.rect.width, + gstate->clip.rect.height, + traps.traps, + traps.num_traps); + + _cairo_pattern_fini (&pattern.base); _cairo_traps_fini (&traps); @@ -1978,19 +2003,15 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, * */ - cairo_status_t status; - cairo_matrix_t user_to_image, image_to_user; - cairo_matrix_t image_to_device, device_to_image; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_matrix_t image_to_user, image_to_device; double device_x, device_y; double device_width, device_height; - cairo_pattern_t pattern; + cairo_surface_pattern_t pattern; cairo_box_t pattern_extents; + cairo_rectangle_t extents; - cairo_surface_get_matrix (surface, &user_to_image); - cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image); - cairo_surface_set_matrix (surface, &device_to_image); - - image_to_user = user_to_image; + cairo_surface_get_matrix (surface, &image_to_user); cairo_matrix_invert (&image_to_user); cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm); @@ -2001,126 +2022,82 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, &device_x, &device_y, &device_width, &device_height); - _cairo_pattern_init (&pattern); + _cairo_pattern_init_for_surface (&pattern, surface); + + /* inherit surface attributes while surface attribute functions still + exist */ + pattern.base.matrix = surface->matrix; + pattern.base.filter = surface->filter; + if (surface->repeat) + pattern.base.extend = CAIRO_EXTEND_REPEAT; + else + pattern.base.extend = CAIRO_EXTEND_NONE; + + _cairo_pattern_transform (&pattern.base, &gstate->ctm_inverse); + _cairo_pattern_set_alpha (&pattern.base, gstate->alpha); pattern_extents.p1.x = _cairo_fixed_from_double (device_x); pattern_extents.p1.y = _cairo_fixed_from_double (device_y); pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width); pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height); - - if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) || - (gstate->alpha != 1.0)) { - /* I'm allowing any type of pattern for the mask right now. - Maybe this is bad. Will allow for some cool effects though. */ - _cairo_pattern_init_copy (&pattern, gstate->pattern); - status = _cairo_gstate_create_pattern (gstate, &pattern, &pattern_extents); - if (status) - return status; - } - + _cairo_box_round_to_rectangle (&pattern_extents, &extents); + if (gstate->clip.surface) { - cairo_surface_t *intermediate; - cairo_color_t empty_color; - pixman_box16_t *draw_extents; - pixman_region16_t *draw_region; - - draw_region = pixman_region_create (); - if (draw_region == NULL) - { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; + _cairo_rectangle_intersect (&extents, &gstate->clip.rect); + + /* We only need to composite if the rectangle is not empty. */ + if (!_cairo_rectangle_empty (&extents)) { + cairo_surface_pattern_t clip_pattern; + + _cairo_pattern_init_for_surface (&clip_pattern, + gstate->clip.surface); + + status = _cairo_surface_composite (gstate->operator, + &pattern.base, + &clip_pattern.base, + gstate->surface, + extents.x, extents.y, + 0, 0, + extents.x, extents.y, + extents.width, extents.height); + + _cairo_pattern_fini (&clip_pattern.base); } - - status = _calculate_region_for_intermediate_clip_surface (draw_region, - &pattern_extents, - &gstate->clip); - if (status) - goto BAIL1; - - /* Shortcut if empty */ - if (!pixman_region_not_empty (draw_region)) { - status = CAIRO_STATUS_SUCCESS; - goto BAIL1; - } - - draw_extents = pixman_region_extents (draw_region); - - _cairo_color_init (&empty_color); - _cairo_color_set_alpha (&empty_color, .0); - intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, - CAIRO_FORMAT_A8, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1, - &empty_color); - - /* it is not completely clear what the "right" way to combine the - pattern and mask surface is. I will use the the clip as a source - and the pattern as a mask in building up my temporary, because - this is not *totally* bogus and accomodates the case where - pattern's source image is NULL reasonably well. feel free to - correct this if you see a reason. */ - - status = _cairo_surface_composite (CAIRO_OPERATOR_SRC, - gstate->clip.surface, - pattern.source, - intermediate, - draw_extents->x1 - gstate->clip.x, - draw_extents->y1 - gstate->clip.y, - 0, 0, - 0, 0, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); - - - if (status) - goto BAIL2; - - status = _cairo_surface_composite (gstate->operator, - surface, - intermediate, - gstate->surface, - draw_extents->x1, draw_extents->y1, - 0, 0, - draw_extents->x1, draw_extents->y1, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); - - BAIL2: - cairo_surface_destroy (intermediate); - BAIL1: - pixman_region_destroy (draw_region); - BAIL0: - ; } else { - - /* XXX: The rendered size is sometimes 1 or 2 pixels short from - what I expect. Need to fix this. */ + /* XXX: The rendered size is sometimes 1 or 2 pixels short + * from what I expect. Need to fix this. + * KRH: I'm guessing this was due to rounding error when + * passing double coordinates for integer arguments. Using + * the extents rectangle should fix this, since it's properly + * rounded. Is this still the case? + */ status = _cairo_surface_composite (gstate->operator, - surface, - pattern.source, + &pattern.base, + NULL, gstate->surface, - device_x, device_y, + extents.x, extents.y, 0, 0, - device_x, device_y, - device_width, - device_height); + extents.x, extents.y, + extents.width, extents.height); } - _cairo_pattern_fini (&pattern); + _cairo_pattern_fini (&pattern.base); - /* restore the matrix originally in the surface */ - cairo_surface_set_matrix (surface, &user_to_image); - - if (status) - return status; - - return CAIRO_STATUS_SUCCESS; + return status; } +static void +_cairo_gstate_unset_font (cairo_gstate_t *gstate) +{ + if (gstate->font) { + cairo_font_destroy (gstate->font); + gstate->font = NULL; + } +} cairo_status_t _cairo_gstate_select_font (cairo_gstate_t *gstate, @@ -2128,12 +2105,17 @@ _cairo_gstate_select_font (cairo_gstate_t *gstate, cairo_font_slant_t slant, cairo_font_weight_t weight) { - if (gstate->font) - _cairo_unscaled_font_destroy (gstate->font); + char *new_family; - gstate->font = _cairo_unscaled_font_create (family, slant, weight); - if (gstate->font == NULL) + new_family = strdup (family); + if (!new_family) return CAIRO_STATUS_NO_MEMORY; + + _cairo_gstate_unset_font (gstate); + + gstate->font_family = new_family; + gstate->font_slant = slant; + gstate->font_weight = weight; cairo_matrix_set_identity (&gstate->font_matrix); @@ -2144,6 +2126,8 @@ cairo_status_t _cairo_gstate_scale_font (cairo_gstate_t *gstate, double scale) { + _cairo_gstate_unset_font (gstate); + return cairo_matrix_scale (&gstate->font_matrix, scale, scale); } @@ -2153,6 +2137,9 @@ _cairo_gstate_transform_font (cairo_gstate_t *gstate, { cairo_matrix_t tmp; double a, b, c, d, tx, ty; + + _cairo_gstate_unset_font (gstate); + cairo_matrix_get_affine (matrix, &a, &b, &c, &d, &tx, &ty); cairo_matrix_set_affine (&tmp, a, b, c, d, 0, 0); return cairo_matrix_multiply (&gstate->font_matrix, &gstate->font_matrix, &tmp); @@ -2160,28 +2147,16 @@ _cairo_gstate_transform_font (cairo_gstate_t *gstate, cairo_status_t -_cairo_gstate_current_font (cairo_gstate_t *gstate, - cairo_font_t **font) +_cairo_gstate_current_font (cairo_gstate_t *gstate, + cairo_font_t **font) { - cairo_font_scale_t scale; - cairo_font_t *scaled; - double dummy; - - scaled = malloc (sizeof (cairo_font_t)); - if (scaled == NULL) - return CAIRO_STATUS_NO_MEMORY; - - cairo_matrix_get_affine (&gstate->font_matrix, - &scale.matrix[0][0], - &scale.matrix[0][1], - &scale.matrix[1][0], - &scale.matrix[1][1], - &dummy, &dummy); - - _cairo_font_init (scaled, &scale, gstate->font); - _cairo_unscaled_font_reference (gstate->font); + cairo_status_t status; - *font = scaled; + status = _cairo_gstate_ensure_font (gstate); + if (status) + return status; + + *font = gstate->font; return CAIRO_STATUS_SUCCESS; } @@ -2190,6 +2165,8 @@ void _cairo_gstate_set_font_transform (cairo_gstate_t *gstate, cairo_matrix_t *matrix) { + _cairo_gstate_unset_font (gstate); + cairo_matrix_copy (&gstate->font_matrix, matrix); } @@ -2214,12 +2191,10 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate, * independently scale the user coordinate system *or* the font matrix, in * order to adjust the rendered size of the font. * - * If the user asks for a permanent reference to "a font", they are given a - * handle to a structure holding a scale matrix and an unscaled font. This - * effectively decouples the font from further changes to user space. Even - * if the user then "sets" the current cairo_t font to the handle they were - * passed, further changes to the cairo_t CTM will not affect externally - * held references to the font. + * The only font type exposed to the user is cairo_font_t which is a + * a font specialized to a particular scale matrix, CTM, and target + * surface. The user is responsible for not using a cairo_font_t + * after changing the parameters; doing so will produce garbled metrics. * * * The font's view @@ -2279,9 +2254,9 @@ _cairo_gstate_current_font_transform (cairo_gstate_t *gstate, * */ -static void -_build_font_scale (cairo_gstate_t *gstate, - cairo_font_scale_t *sc) +void +_cairo_gstate_current_font_scale (cairo_gstate_t *gstate, + cairo_font_scale_t *sc) { cairo_matrix_t tmp; double dummy; @@ -2294,34 +2269,46 @@ _build_font_scale (cairo_gstate_t *gstate, &dummy, &dummy); } -cairo_status_t -_cairo_gstate_current_font_extents (cairo_gstate_t *gstate, - cairo_font_extents_t *extents) +static cairo_status_t +_cairo_gstate_ensure_font (cairo_gstate_t *gstate) { - cairo_int_status_t status; cairo_font_scale_t sc; - double font_scale_x, font_scale_y; + cairo_status_t status; + const char *family; + + if (gstate->font) + return CAIRO_STATUS_SUCCESS; + + _cairo_gstate_current_font_scale (gstate, &sc); - _build_font_scale (gstate, &sc); + if (gstate->font_family) + family = gstate->font_family; + else + family = CAIRO_FONT_FAMILY_DEFAULT; + + status = _cairo_font_create (family, + gstate->font_slant, + gstate->font_weight, + &sc, + &gstate->font); - status = _cairo_unscaled_font_font_extents (gstate->font, &sc, extents); + if (status) + return status; - _cairo_matrix_compute_scale_factors (&gstate->font_matrix, - &font_scale_x, &font_scale_y, - /* XXX */ 1); - - /* - * The font responded in unscaled units, scale by the font - * matrix scale factors to get to user space - */ - - extents->ascent *= font_scale_y; - extents->descent *= font_scale_y; - extents->height *= font_scale_y; - extents->max_x_advance *= font_scale_x; - extents->max_y_advance *= font_scale_y; - - return status; + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_current_font_extents (cairo_gstate_t *gstate, + cairo_font_extents_t *extents) +{ + cairo_status_t status = _cairo_gstate_ensure_font (gstate); + if (status) + return status; + + return cairo_font_extents (gstate->font, + &gstate->font_matrix, + extents); } cairo_status_t @@ -2331,14 +2318,15 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, int *nglyphs) { cairo_status_t status; - cairo_font_scale_t sc; cairo_point_t point; double origin_x, origin_y; int i; - _build_font_scale (gstate, &sc); - + status = _cairo_gstate_ensure_font (gstate); + if (status) + return status; + status = _cairo_path_current_point (&gstate->path, &point); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { origin_x = 0.0; @@ -2350,8 +2338,8 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, &origin_x, &origin_y); } - status = _cairo_unscaled_font_text_to_glyphs (gstate->font, - &sc, utf8, glyphs, nglyphs); + status = _cairo_font_text_to_glyphs (gstate->font, + utf8, glyphs, nglyphs); if (status || !glyphs || !nglyphs || !(*glyphs) || !(nglyphs)) return status; @@ -2373,18 +2361,16 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, cairo_status_t _cairo_gstate_set_font (cairo_gstate_t *gstate, - cairo_font_t *font) -{ - if (gstate->font != NULL) - _cairo_unscaled_font_destroy (gstate->font); - gstate->font = font->unscaled; - _cairo_unscaled_font_reference (gstate->font); - cairo_matrix_set_affine (&gstate->font_matrix, - font->scale.matrix[0][0], - font->scale.matrix[0][1], - font->scale.matrix[1][0], - font->scale.matrix[1][1], - 0, 0); + cairo_font_t *font) +{ + if (font != gstate->font) { + if (gstate->font) + cairo_font_destroy (gstate->font); + gstate->font = font; + if (gstate->font) + cairo_font_reference (gstate->font); + } + return CAIRO_STATUS_SUCCESS; } @@ -2394,90 +2380,18 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, int num_glyphs, cairo_text_extents_t *extents) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_glyph_t origin_glyph; - cairo_text_extents_t origin_extents; - cairo_font_scale_t sc; - int i; - double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0; - double x_pos = 0.0, y_pos = 0.0; - int set = 0; - - if (!num_glyphs) - { - extents->x_bearing = 0.0; - extents->y_bearing = 0.0; - extents->width = 0.0; - extents->height = 0.0; - extents->x_advance = 0.0; - extents->y_advance = 0.0; - return CAIRO_STATUS_SUCCESS; - } - - _build_font_scale (gstate, &sc); - - for (i = 0; i < num_glyphs; i++) - { - double x, y; - double wm, hm; - - origin_glyph = glyphs[i]; - origin_glyph.x = 0.0; - origin_glyph.y = 0.0; - status = _cairo_unscaled_font_glyph_extents (gstate->font, &sc, - &origin_glyph, 1, - &origin_extents); - - /* - * Transform font space metrics into user space metrics - * by running the corners through the font matrix and - * expanding the bounding box as necessary - */ - x = origin_extents.x_bearing; - y = origin_extents.y_bearing; - cairo_matrix_transform_point (&gstate->font_matrix, - &x, &y); - - for (hm = 0.0; hm <= 1.0; hm += 1.0) - for (wm = 0.0; wm <= 1.0; wm += 1.0) - { - x = origin_extents.x_bearing + origin_extents.width * wm; - y = origin_extents.y_bearing + origin_extents.height * hm; - cairo_matrix_transform_point (&gstate->font_matrix, - &x, &y); - x += glyphs[i].x; - y += glyphs[i].y; - if (!set) - { - min_x = max_x = x; - min_y = max_y = y; - set = 1; - } - else - { - if (x < min_x) min_x = x; - if (x > max_x) max_x = x; - if (y < min_y) min_y = y; - if (y > max_y) max_y = y; - } - } + cairo_status_t status; - x = origin_extents.x_advance; - y = origin_extents.y_advance; - cairo_matrix_transform_point (&gstate->font_matrix, - &x, &y); - x_pos = glyphs[i].x + x; - y_pos = glyphs[i].y + y; - } + status = _cairo_gstate_ensure_font (gstate); + if (status) + return status; - extents->x_bearing = min_x - glyphs[0].x; - extents->y_bearing = min_y - glyphs[0].y; - extents->width = max_x - min_x; - extents->height = max_y - min_y; - extents->x_advance = x_pos - glyphs[0].x; - extents->y_advance = y_pos - glyphs[0].y; + cairo_font_glyph_extents (gstate->font, + &gstate->font_matrix, + glyphs, num_glyphs, + extents); - return status; + return CAIRO_STATUS_SUCCESS; } cairo_status_t @@ -2488,12 +2402,14 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_status_t status; int i; cairo_glyph_t *transformed_glyphs = NULL; - cairo_font_scale_t sc; - cairo_pattern_t pattern; + cairo_pattern_union_t pattern; cairo_box_t bbox; + cairo_rectangle_t extents; - _build_font_scale (gstate, &sc); - + status = _cairo_gstate_ensure_font (gstate); + if (status) + return status; + transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) return CAIRO_STATUS_NO_MEMORY; @@ -2506,52 +2422,34 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, &transformed_glyphs[i].y); } - _cairo_pattern_init_copy (&pattern, gstate->pattern); - status = _cairo_unscaled_font_glyph_bbox (gstate->font, &sc, - transformed_glyphs, num_glyphs, - &bbox); - if (status) - goto CLEANUP_GLYPHS; + status = _cairo_font_glyph_bbox (gstate->font, + transformed_glyphs, num_glyphs, + &bbox); + _cairo_box_round_to_rectangle (&bbox, &extents); - status = _cairo_gstate_create_pattern (gstate, &pattern, &bbox); if (status) goto CLEANUP_GLYPHS; - + if (gstate->clip.surface) { cairo_surface_t *intermediate; + cairo_surface_pattern_t intermediate_pattern; cairo_color_t empty_color; - pixman_box16_t *draw_extents; - pixman_region16_t *draw_region; - - draw_region = pixman_region_create (); - if (draw_region == NULL) - { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; - } - status = _calculate_region_for_intermediate_clip_surface (draw_region, - &bbox, - &gstate->clip); - if (status) { - goto BAIL1; - } + _cairo_rectangle_intersect (&extents, &gstate->clip.rect); /* Shortcut if empty */ - if (!pixman_region_not_empty (draw_region)) { + if (_cairo_rectangle_empty (&extents)) { status = CAIRO_STATUS_SUCCESS; goto BAIL1; } - draw_extents = pixman_region_extents (draw_region); - _cairo_color_init (&empty_color); _cairo_color_set_alpha (&empty_color, .0); intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, CAIRO_FORMAT_A8, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1, + extents.width, + extents.height, &empty_color); if (intermediate == NULL) { status = CAIRO_STATUS_NO_MEMORY; @@ -2561,66 +2459,77 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, /* move the glyphs again, from dev space to intermediate space */ for (i = 0; i < num_glyphs; ++i) { - transformed_glyphs[i].x -= draw_extents->x1; - transformed_glyphs[i].y -= draw_extents->y1; + transformed_glyphs[i].x -= extents.x; + transformed_glyphs[i].y -= extents.y; } - status = _cairo_unscaled_font_show_glyphs (gstate->font, - &sc, - CAIRO_OPERATOR_ADD, - pattern.source, intermediate, - draw_extents->x1 - pattern.source_offset.x, - draw_extents->y1 - pattern.source_offset.y, - transformed_glyphs, num_glyphs); + _cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0); + + status = _cairo_font_show_glyphs (gstate->font, + CAIRO_OPERATOR_ADD, + &pattern.base, intermediate, + extents.x, extents.y, + 0, 0, + extents.width, extents.height, + transformed_glyphs, num_glyphs); + + _cairo_pattern_fini (&pattern.base); if (status) goto BAIL2; + _cairo_pattern_init_for_surface (&pattern.surface, + gstate->clip.surface); + status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - gstate->clip.surface, + &pattern.base, NULL, intermediate, - draw_extents->x1 - gstate->clip.x, - draw_extents->y1 - gstate->clip.y, + extents.x - gstate->clip.rect.x, + extents.y - gstate->clip.rect.y, 0, 0, 0, 0, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); + extents.width, extents.height); + + _cairo_pattern_fini (&pattern.base); if (status) goto BAIL2; + _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); + _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern); + status = _cairo_surface_composite (gstate->operator, - pattern.source, - intermediate, + &pattern.base, + &intermediate_pattern.base, gstate->surface, - 0, 0, + extents.x, extents.y, 0, 0, - draw_extents->x1, - draw_extents->y1, - draw_extents->x2 - draw_extents->x1, - draw_extents->y2 - draw_extents->y1); + extents.x, extents.y, + extents.width, extents.height); + _cairo_pattern_fini (&pattern.base); + _cairo_pattern_fini (&intermediate_pattern.base); BAIL2: cairo_surface_destroy (intermediate); BAIL1: - pixman_region_destroy (draw_region); - BAIL0: ; } else { - status = _cairo_unscaled_font_show_glyphs (gstate->font, - &sc, - gstate->operator, pattern.source, - gstate->surface, - -pattern.source_offset.x, - -pattern.source_offset.y, - transformed_glyphs, num_glyphs); + _cairo_gstate_pattern_init_copy (gstate, &pattern, gstate->pattern); + + status = _cairo_font_show_glyphs (gstate->font, + gstate->operator, &pattern.base, + gstate->surface, + extents.x, extents.y, + extents.x, extents.y, + extents.width, extents.height, + transformed_glyphs, num_glyphs); + + _cairo_pattern_fini (&pattern.base); } - _cairo_pattern_fini (&pattern); - CLEANUP_GLYPHS: free (transformed_glyphs); @@ -2635,9 +2544,6 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_status_t status; int i; cairo_glyph_t *transformed_glyphs = NULL; - cairo_font_scale_t sc; - - _build_font_scale (gstate, &sc); transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) @@ -2651,9 +2557,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, &(transformed_glyphs[i].y)); } - status = _cairo_unscaled_font_glyph_path (gstate->font, &sc, - transformed_glyphs, num_glyphs, - &gstate->path); + status = _cairo_font_glyph_path (gstate->font, + transformed_glyphs, num_glyphs, + &gstate->path); free (transformed_glyphs); return status; diff --git a/src/cairo_hull.c b/src/cairo_hull.c index 99b16d1ae..c93d70625 100644 --- a/src/cairo_hull.c +++ b/src/cairo_hull.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c index 14e30f695..9745b3150 100644 --- a/src/cairo_image_surface.c +++ b/src/cairo_image_surface.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" @@ -54,7 +54,8 @@ _cairo_format_bpp (cairo_format_t format) } static cairo_image_surface_t * -_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image) +_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, + cairo_format_t format) { cairo_image_surface_t *surface; @@ -66,6 +67,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image) surface->pixman_image = pixman_image; + surface->format = format; surface->data = (char *) pixman_image_get_data (pixman_image); surface->owns_data = 0; @@ -105,7 +107,8 @@ _cairo_image_surface_create_with_masks (char *data, if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_pixman_image (pixman_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image, + (cairo_format_t)-1); return surface; } @@ -130,6 +133,20 @@ _create_pixman_format (cairo_format_t format) } } +/** + * cairo_image_surface_create: + * @format: format of pixels in the surface to create + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates an image surface of the specified format and + * dimensions. The initial contents of the surface is undefined; you + * must explicitely clear the buffer, using, for example, + * cairo_rectangle() and cairo_fill() if you want it cleared. + * + * Return value: the newly created surface, or %NULL if it couldn't + * be created because of lack of memory + **/ cairo_surface_t * cairo_image_surface_create (cairo_format_t format, int width, @@ -150,11 +167,33 @@ cairo_image_surface_create (cairo_format_t format, if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_pixman_image (pixman_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format); return &surface->base; } +/** + * cairo_image_surface_create_for_data: + * @data: a pointer to a buffer supplied by the application + * in which to write contents. + * @format: the format of pixels in the buffer + * @width: the width of the image to be stored in the buffer + * @height: the height of the image to be stored in the buffer + * @stride: the number of bytes between the start of rows + * in the buffer. Having this be specified separate from @width + * allows for padding at the end of rows, or for writing + * to a subportion of a larger image. + * + * Creates an image surface for the provided pixel data. The output + * buffer must be kept around until the #cairo_surface_t is destroyed + * or cairo_surface_finish() is called on the surface. The initial + * contents of @buffer will be used as the inital image contents; you + * must explicitely clear the buffer, using, for example, + * cairo_rectangle() and cairo_fill() if you want it cleared. + * + * Return value: the newly created surface, or %NULL if it couldn't + * be created because of lack of memory + **/ cairo_surface_t * cairo_image_surface_create_for_data (char *data, cairo_format_t format, @@ -180,7 +219,7 @@ cairo_image_surface_create_for_data (char *data, if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_pixman_image (pixman_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image, format); return &surface->base; } @@ -224,33 +263,66 @@ _cairo_image_surface_pixels_per_inch (void *abstract_surface) return 96.0; } -static cairo_image_surface_t * -_cairo_image_surface_get_image (void *abstract_surface) +static cairo_status_t +_cairo_image_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { - cairo_image_surface_t *surface = abstract_surface; - - cairo_surface_reference (&surface->base); + *image_out = abstract_surface; + + return CAIRO_STATUS_SUCCESS; +} - return surface; +static void +_cairo_image_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ } static cairo_status_t -_cairo_image_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +_cairo_image_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect_out, + void **image_extra) { - if (image == abstract_surface) - return CAIRO_STATUS_SUCCESS; + cairo_image_surface_t *surface = abstract_surface; + + image_rect_out->x = 0; + image_rect_out->y = 0; + image_rect_out->width = surface->width; + image_rect_out->height = surface->height; + + *image_out = surface; - /* XXX: This case has not yet been implemented. We'll lie for now. */ return CAIRO_STATUS_SUCCESS; } +static void +_cairo_image_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ +} + static cairo_status_t -_cairo_image_abstract_surface_set_matrix (void *abstract_surface, - cairo_matrix_t *matrix) +_cairo_image_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { cairo_image_surface_t *surface = abstract_surface; - return _cairo_image_surface_set_matrix (surface, matrix); + + if (src->backend == surface->base.backend) { + *clone_out = src; + cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; } cairo_status_t @@ -276,14 +348,6 @@ _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_image_abstract_surface_set_filter (void *abstract_surface, cairo_filter_t filter) -{ - cairo_image_surface_t *surface = abstract_surface; - - return _cairo_image_surface_set_filter (surface, filter); -} - cairo_status_t _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter) { @@ -314,13 +378,6 @@ _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_image_abstract_surface_set_repeat (void *abstract_surface, int repeat) -{ - cairo_image_surface_t *surface = abstract_surface; - return _cairo_image_surface_set_repeat (surface, repeat); -} - cairo_status_t _cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat) { @@ -329,6 +386,34 @@ _cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat) return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_image_surface_set_attributes (cairo_image_surface_t *surface, + cairo_surface_attributes_t *attributes) +{ + cairo_int_status_t status; + + status = _cairo_image_surface_set_matrix (surface, &attributes->matrix); + if (status) + return status; + + switch (attributes->extend) { + case CAIRO_EXTEND_NONE: + _cairo_image_surface_set_repeat (surface, 0); + break; + case CAIRO_EXTEND_REPEAT: + _cairo_image_surface_set_repeat (surface, 1); + break; + case CAIRO_EXTEND_REFLECT: + /* XXX: Obviously wrong. */ + _cairo_image_surface_set_repeat (surface, 1); + break; + } + + status = _cairo_image_surface_set_filter (surface, attributes->filter); + + return status; +} + static pixman_operator_t _pixman_operator (cairo_operator_t operator) { @@ -368,8 +453,8 @@ _pixman_operator (cairo_operator_t operator) static cairo_int_status_t _cairo_image_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, void *abstract_dst, int src_x, int src_y, @@ -380,26 +465,61 @@ _cairo_image_surface_composite (cairo_operator_t operator, unsigned int width, unsigned int height) { - cairo_image_surface_t *dst = abstract_dst; - cairo_image_surface_t *src = (cairo_image_surface_t *) generic_src; - cairo_image_surface_t *mask = (cairo_image_surface_t *) generic_mask; - - if (generic_src->backend != dst->base.backend || - (generic_mask && (generic_mask->backend != dst->base.backend))) + cairo_surface_attributes_t src_attr, mask_attr; + cairo_image_surface_t *dst = abstract_dst; + cairo_image_surface_t *src; + cairo_image_surface_t *mask; + cairo_int_status_t status; + + status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern, + &dst->base, + src_x, src_y, + mask_x, mask_y, + width, height, + (cairo_surface_t **) &src, + (cairo_surface_t **) &mask, + &src_attr, &mask_attr); + if (status) + return status; + + status = _cairo_image_surface_set_attributes (src, &src_attr); + if (CAIRO_OK (status)) { - return CAIRO_INT_STATUS_UNSUPPORTED; + if (mask) + { + status = _cairo_image_surface_set_attributes (mask, &mask_attr); + if (CAIRO_OK (status)) + pixman_composite (_pixman_operator (operator), + src->pixman_image, + mask->pixman_image, + dst->pixman_image, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + mask_x + mask_attr.x_offset, + mask_y + mask_attr.y_offset, + dst_x, dst_y, + width, height); + } + else + { + pixman_composite (_pixman_operator (operator), + src->pixman_image, + NULL, + dst->pixman_image, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + } } - pixman_composite (_pixman_operator (operator), - src->pixman_image, - mask ? mask->pixman_image : NULL, - dst->pixman_image, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); - - return CAIRO_STATUS_SUCCESS; + if (mask) + _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr); + + _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr); + + return status; } static cairo_int_status_t @@ -427,24 +547,56 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, static cairo_int_status_t _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, + cairo_pattern_t *pattern, void *abstract_dst, - int x_src, - int y_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps) { - cairo_image_surface_t *dst = abstract_dst; - cairo_image_surface_t *src = (cairo_image_surface_t *) generic_src; + cairo_surface_attributes_t attributes; + cairo_image_surface_t *dst = abstract_dst; + cairo_image_surface_t *src; + cairo_int_status_t status; + int render_reference_x, render_reference_y; + int render_src_x, render_src_y; + + status = _cairo_pattern_acquire_surface (pattern, &dst->base, + src_x, src_y, width, height, + (cairo_surface_t **) &src, + &attributes); + if (status) + return status; + + if (traps[0].left.p1.y < traps[0].left.p2.y) { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y); + } else { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y); + } - if (generic_src->backend != dst->base.backend) - return CAIRO_INT_STATUS_UNSUPPORTED; + render_src_x = src_x + render_reference_x - dst_x; + render_src_y = src_y + render_reference_y - dst_y; - /* XXX: The pixman_trapezoid_t cast is evil and needs to go away somehow. */ - pixman_composite_trapezoids (operator, src->pixman_image, dst->pixman_image, - x_src, y_src, (pixman_trapezoid_t *) traps, num_traps); + /* XXX: The pixman_trapezoid_t cast is evil and needs to go away + * somehow. */ + status = _cairo_image_surface_set_attributes (src, &attributes); + if (CAIRO_OK (status)) + pixman_composite_trapezoids (operator, + src->pixman_image, + dst->pixman_image, + render_src_x + attributes.x_offset, + render_src_y + attributes.y_offset, + (pixman_trapezoid_t *) traps, num_traps); - return CAIRO_STATUS_SUCCESS; + _cairo_pattern_release_surface (&dst->base, &src->base, &attributes); + + return status; } static cairo_int_status_t @@ -490,41 +642,34 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_image_abstract_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *box) +/** + * _cairo_surface_is_image: + * @surface: a #cairo_surface_t + * + * Checks if a surface is an #cairo_image_surface_t + * + * Return value: True if the surface is an image surface + **/ +int +_cairo_surface_is_image (cairo_surface_t *surface) { - cairo_image_surface_t *image; - - /* Fall back to general pattern creation for surface patterns. */ - if (pattern->type == CAIRO_PATTERN_SURFACE) - return CAIRO_INT_STATUS_UNSUPPORTED; - - image = _cairo_pattern_get_image (pattern, box); - if (image) { - pattern->source = &image->base; - - return CAIRO_STATUS_SUCCESS; - } else - return CAIRO_STATUS_NO_MEMORY; + return surface->backend == &cairo_image_surface_backend; } - + static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_create_similar, _cairo_image_abstract_surface_destroy, _cairo_image_surface_pixels_per_inch, - _cairo_image_surface_get_image, - _cairo_image_surface_set_image, - _cairo_image_abstract_surface_set_matrix, - _cairo_image_abstract_surface_set_filter, - _cairo_image_abstract_surface_set_repeat, + _cairo_image_surface_acquire_source_image, + _cairo_image_surface_release_source_image, + _cairo_image_surface_acquire_dest_image, + _cairo_image_surface_release_dest_image, + _cairo_image_surface_clone_similar, _cairo_image_surface_composite, _cairo_image_surface_fill_rectangles, _cairo_image_surface_composite_trapezoids, _cairo_image_surface_copy_page, _cairo_image_surface_show_page, _cairo_image_abstract_surface_set_clip_region, - _cairo_image_abstract_surface_create_pattern, NULL /* show_glyphs */ }; diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c index b964b688c..88e536e8a 100644 --- a/src/cairo_matrix.c +++ b/src/cairo_matrix.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #define _GNU_SOURCE @@ -54,6 +54,14 @@ _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar); static void _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix); +/** + * cairo_matrix_create: + * + * Creates a new identity matrix. + * + * Return value: a newly created matrix; free with cairo_matrix_destroy(), + * or %NULL if memory couldn't be allocated. + **/ cairo_matrix_t * cairo_matrix_create (void) { @@ -80,6 +88,12 @@ _cairo_matrix_fini (cairo_matrix_t *matrix) /* nothing to do here */ } +/** + * cairo_matrix_destroy: + * @matrix: a #cairo_matrix_t + * + * Frees a matrix created with cairo_matrix_create. + **/ void cairo_matrix_destroy (cairo_matrix_t *matrix) { @@ -87,6 +101,15 @@ cairo_matrix_destroy (cairo_matrix_t *matrix) free (matrix); } +/** + * cairo_matrix_copy: + * @matrix: a #cairo_matrix_t + * @other: another #cairo_ + * + * Modifies @matrix to be identical to @other. + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other) { @@ -96,6 +119,14 @@ cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other) } slim_hidden_def(cairo_matrix_copy); +/** + * cairo_matrix_set_identity: + * @matrix: a #cairo_matrix_t + * + * Modifies @matrix to be an identity transformation. + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_set_identity (cairo_matrix_t *matrix) { @@ -105,6 +136,26 @@ cairo_matrix_set_identity (cairo_matrix_t *matrix) } slim_hidden_def(cairo_matrix_set_identity); +/** + * cairo_matrix_set_affine: + * @matrix: a cairo_matrix_t + * @a: a component of the affine transformation + * @b: b component of the affine transformation + * @c: c component of the affine transformation + * @d: d component of the affine transformation + * @tx: X translation component of the affine transformation + * @ty: Y translation component of the affine transformation + * + * Sets @matrix to be the affine transformation given by + * @a, b, @c, @d, @tx, @ty. The transformation is given + * by: + * <programlisting> + * x_new = x * a + y * c + tx; + * y_new = x * b + y * d + ty; + * </programlisting> + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_set_affine (cairo_matrix_t *matrix, double a, double b, @@ -119,6 +170,21 @@ cairo_matrix_set_affine (cairo_matrix_t *matrix, } slim_hidden_def(cairo_matrix_set_affine); +/** + * cairo_matrix_get_affine: + * @matrix: a @cairo_matrix_t + * @a: location to store a component of affine transformation, or %NULL + * @b: location to store b component of affine transformation, or %NULL + * @c: location to store c component of affine transformation, or %NULL + * @d: location to store d component of affine transformation, or %NULL + * @tx: location to store X-translation component of affine transformation, or %NULL + * @ty: location to store Y-translation component of affine transformation, or %NULL + * + * Gets the matrix values for the affine tranformation that @matrix represents. + * See cairo_matrix_set_affine(). + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_get_affine (cairo_matrix_t *matrix, double *a, double *b, @@ -153,6 +219,18 @@ _cairo_matrix_set_translate (cairo_matrix_t *matrix, tx, ty); } +/** + * cairo_matrix_translate: + * @matrix: a cairo_matrix_t + * @tx: amount to rotate in the X direction + * @ty: amount to rotate in the Y direction + * + * Applies a translation by @tx, @ty to the transformation in + * @matrix. The new transformation is given by first translating by + * @tx, @ty then applying the original transformation + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty) { @@ -173,6 +251,18 @@ _cairo_matrix_set_scale (cairo_matrix_t *matrix, 0, 0); } +/** + * cairo_matrix_scale: + * @matrix: a #cairo_matrix_t + * @sx: Scale factor in the X direction + * @sy: Scale factor in the Y direction + * + * Applies scaling by @tx, @ty to the transformation in + * @matrix. The new transformation is given by first scaling by @sx + * and @sy then applying the original transformation + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy) { @@ -202,6 +292,21 @@ _cairo_matrix_set_rotate (cairo_matrix_t *matrix, 0, 0); } +/** + * cairo_matrix_rotate: + * @matrix: a @cairo_matrix_t + * @radians: angle of rotation, in radians. Angles are defined + * so that an angle of 90 degrees (%M_PI radians) rotates the + * positive X axis into the positive Y axis. With the default + * Cairo choice of axis orientation, positive rotations are + * clockwise. + * + * Applies rotation by @radians to the transformation in + * @matrix. The new transformation is given by first rotating by + * @radians then applying the original transformation + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_rotate (cairo_matrix_t *matrix, double radians) { @@ -212,6 +317,19 @@ cairo_matrix_rotate (cairo_matrix_t *matrix, double radians) return cairo_matrix_multiply (matrix, &tmp, matrix); } +/** + * cairo_matrix_multiply: + * @result: a @cairo_matrix_t in which to store the result + * @a: a @cairo_matrix_t + * @b: a @cairo_matrix_t + * + * Multiplies the affine transformations in @a and @b together + * and stores the result in @result. The resulting transformation + * is given by first applying the transformation in @b then + * applying the transformation in @a. + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b) { @@ -238,6 +356,27 @@ cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const ca } slim_hidden_def(cairo_matrix_multiply); +/** + * cairo_matrix_transform_distance: + * @matrix: a @cairo_matrix_t + * @dx: a distance in the X direction. An in/out parameter + * @dy: a distance in the Y direction. An in/out parameter + * + * Transforms the vector (@dx,@dy) by @matrix. Translation is + * ignored. In terms of the components of the affine transformation: + * + * <programlisting> + * dx2 = dx1 * a + dy1 * c; + * dy2 = dx1 * b + dy1 * d; + * </programlisting> + * + * Affine transformations are position invariant, so the same vector + * always transforms to the same vector. If (@x1,@y1) transforms + * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to + * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2. + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy) { @@ -255,6 +394,16 @@ cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy) } slim_hidden_def(cairo_matrix_transform_distance); +/** + * cairo_matrix_transform_point: + * @matrix: a @cairo_matrix_t + * @x: X position. An in/out parameter + * @y: Y position. An in/out parameter + * + * Transforms the point (@x, @y) by @matrix. + * + * Return value: %CAIRO_STATUS_SUCCESS, always. + **/ cairo_status_t cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y) { @@ -351,6 +500,19 @@ _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix) c*ty - d*tx, b*tx - a*ty); } +/** + * cairo_matrix_invert: + * @matrix: a @cairo_matrix_t + * + * Changes @matrix to be the inverse of it's original value. Not + * all transformation matrices have inverses; if the matrix + * collapses points together (it is <firstterm>degenerate</firstterm>), + * then it has no inverse and this function will fail. + * + * Returns: If @matrix has an inverse, modifies @matrix to + * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise, + * returns %CAIRO_STATUS_INVALID_MATRIX. + **/ cairo_status_t cairo_matrix_invert (cairo_matrix_t *matrix) { @@ -458,7 +620,7 @@ _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double return CAIRO_STATUS_SUCCESS; } -int +cairo_bool_t _cairo_matrix_is_integer_translation(cairo_matrix_t *mat, int *itx, int *ity) { @@ -477,7 +639,7 @@ _cairo_matrix_is_integer_translation(cairo_matrix_t *mat, if (ok) { *itx = _cairo_fixed_integer_part(ttx); *ity = _cairo_fixed_integer_part(tty); - return 1; + return TRUE; } - return 0; + return FALSE; } diff --git a/src/cairo_path.c b/src/cairo_path.c index 36c25d637..8314f601c 100644 --- a/src/cairo_path.c +++ b/src/cairo_path.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include <stdlib.h> @@ -100,6 +100,7 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other) for (other_op = other->op_head; other_op; other_op = other_op->next) { op = _cairo_path_op_buf_create (); if (op == NULL) { + _cairo_path_fini(path); return CAIRO_STATUS_NO_MEMORY; } *op = *other_op; @@ -109,6 +110,7 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other) for (other_arg = other->arg_head; other_arg; other_arg = other_arg->next) { arg = _cairo_path_arg_buf_create (); if (arg == NULL) { + _cairo_path_fini(path); return CAIRO_STATUS_NO_MEMORY; } *arg = *other_arg; diff --git a/src/cairo_path_bounds.c b/src/cairo_path_bounds.c index cfcdd97ee..7c5772a82 100644 --- a/src/cairo_path_bounds.c +++ b/src/cairo_path_bounds.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo_path_fill.c b/src/cairo_path_fill.c index 6c6ebd976..dc79b6b96 100644 --- a/src/cairo_path_fill.c +++ b/src/cairo_path_fill.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo_path_stroke.c b/src/cairo_path_stroke.c index ad0220370..08b380902 100644 --- a/src/cairo_path_stroke.c +++ b/src/cairo_path_stroke.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo_pattern.c b/src/cairo_pattern.c index 6cb981458..283c36dbd 100644 --- a/src/cairo_pattern.c +++ b/src/cairo_pattern.c @@ -21,58 +21,108 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * Author: David Reveman <c99drn@cs.umu.se> + * Author: David Reveman <davidr@novell.com> */ #include "cairoint.h" +typedef void (*cairo_shader_function_t) (unsigned char *color0, + unsigned char *color1, + cairo_fixed_t factor, + uint32_t *pixel); + +typedef struct _cairo_shader_color_stop { + cairo_fixed_t offset; + cairo_fixed_48_16_t scale; + int id; + unsigned char color_char[4]; +} cairo_shader_color_stop_t; + +typedef struct _cairo_shader_op { + cairo_shader_color_stop_t *stops; + int n_stops; + cairo_extend_t extend; + cairo_shader_function_t shader_function; +} cairo_shader_op_t; + #define MULTIPLY_COLORCOMP(c1, c2) \ ((unsigned char) \ ((((unsigned char) (c1)) * (int) ((unsigned char) (c2))) / 0xff)) -void -_cairo_pattern_init (cairo_pattern_t *pattern) +static void +_cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) { + pattern->type = type; pattern->ref_count = 1; - - pattern->extend = CAIRO_EXTEND_DEFAULT; - pattern->filter = CAIRO_FILTER_DEFAULT; - - _cairo_color_init (&pattern->color); + pattern->extend = CAIRO_EXTEND_DEFAULT; + pattern->filter = CAIRO_FILTER_DEFAULT; + pattern->alpha = 1.0; _cairo_matrix_init (&pattern->matrix); +} - pattern->stops = NULL; - pattern->n_stops = 0; +static cairo_status_t +_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, + cairo_gradient_pattern_t *other) +{ + if (other->base.type == CAIRO_PATTERN_LINEAR) + { + cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern; + cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other; + + *dst = *src; + } + else + { + cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern; + cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other; + + *dst = *src; + } - pattern->type = CAIRO_PATTERN_SOLID; + if (other->n_stops) + { + pattern->stops = malloc (other->n_stops * sizeof (cairo_color_stop_t)); + if (!pattern->stops) + return CAIRO_STATUS_NO_MEMORY; + + memcpy (pattern->stops, other->stops, + other->n_stops * sizeof (cairo_color_stop_t)); + } - pattern->source = NULL; - pattern->source_offset.x = 0.0; - pattern->source_offset.y = 0.0; + return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other) { - *pattern = *other; - - pattern->ref_count = 1; + switch (other->type) { + case CAIRO_PATTERN_SOLID: { + cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern; + cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other; - if (pattern->n_stops) { - pattern->stops = - malloc (sizeof (cairo_color_stop_t) * pattern->n_stops); - if (pattern->stops == NULL) - return CAIRO_STATUS_NO_MEMORY; - memcpy (pattern->stops, other->stops, - sizeof (cairo_color_stop_t) * other->n_stops); + *dst = *src; + } break; + case CAIRO_PATTERN_SURFACE: { + cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern; + cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other; + + *dst = *src; + cairo_surface_reference (dst->surface); + } break; + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern; + cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other; + cairo_status_t status; + + status = _cairo_gradient_pattern_init_copy (dst, src); + if (status) + return status; + } break; } - - if (pattern->source) - cairo_surface_reference (other->source); - - if (pattern->type == CAIRO_PATTERN_SURFACE) - cairo_surface_reference (other->u.surface.surface); + + pattern->ref_count = 1; return CAIRO_STATUS_SUCCESS; } @@ -80,110 +130,145 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other) void _cairo_pattern_fini (cairo_pattern_t *pattern) { - if (pattern->n_stops) - free (pattern->stops); - - if (pattern->type == CAIRO_PATTERN_SURFACE) { - /* show_surface require us to restore surface matrix, repeat - attribute, filter type */ - if (pattern->source) { - cairo_surface_set_matrix (pattern->source, - &pattern->u.surface.save_matrix); - cairo_surface_set_repeat (pattern->source, - pattern->u.surface.save_repeat); - cairo_surface_set_filter (pattern->source, - pattern->u.surface.save_filter); - } - cairo_surface_destroy (pattern->u.surface.surface); + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: + break; + case CAIRO_PATTERN_SURFACE: { + cairo_surface_pattern_t *fini = (cairo_surface_pattern_t *) pattern; + + cairo_surface_destroy (fini->surface); + } break; + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_gradient_pattern_t *fini = (cairo_gradient_pattern_t *) pattern; + + if (fini->n_stops) + free (fini->stops); + } break; } +} + +void +_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, + double red, + double green, + double blue) +{ + _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SOLID); - if (pattern->source) - cairo_surface_destroy (pattern->source); + pattern->red = red; + pattern->green = green; + pattern->blue = blue; } void -_cairo_pattern_init_solid (cairo_pattern_t *pattern, - double red, double green, double blue) +_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern, + cairo_surface_t *surface) { - _cairo_pattern_init (pattern); + _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SURFACE); + + pattern->surface = surface; + cairo_surface_reference (surface); +} - pattern->type = CAIRO_PATTERN_SOLID; - _cairo_color_set_rgb (&pattern->color, red, green, blue); +static void +_cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern, + cairo_pattern_type_t type) +{ + _cairo_pattern_init (&pattern->base, type); + + pattern->stops = 0; + pattern->n_stops = 0; +} + +void +_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern, + double x0, double y0, double x1, double y1) +{ + _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_LINEAR); + + pattern->point0.x = x0; + pattern->point0.y = y0; + pattern->point1.x = x1; + pattern->point1.y = y1; +} + +void +_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, + double cx0, double cy0, double radius0, + double cx1, double cy1, double radius1) +{ + _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_RADIAL); + + pattern->center0.x = cx0; + pattern->center0.y = cy0; + pattern->radius0 = fabs (radius0); + pattern->center1.x = cx1; + pattern->center1.y = cy1; + pattern->radius1 = fabs (radius1); } cairo_pattern_t * _cairo_pattern_create_solid (double red, double green, double blue) { - cairo_pattern_t *pattern; + cairo_solid_pattern_t *pattern; - pattern = malloc (sizeof (cairo_pattern_t)); + pattern = malloc (sizeof (cairo_solid_pattern_t)); if (pattern == NULL) return NULL; _cairo_pattern_init_solid (pattern, red, green, blue); - return pattern; + return &pattern->base; } cairo_pattern_t * cairo_pattern_create_for_surface (cairo_surface_t *surface) { - cairo_pattern_t *pattern; + cairo_surface_pattern_t *pattern; - pattern = malloc (sizeof (cairo_pattern_t)); + pattern = malloc (sizeof (cairo_surface_pattern_t)); if (pattern == NULL) return NULL; - _cairo_pattern_init (pattern); - - pattern->type = CAIRO_PATTERN_SURFACE; - pattern->u.surface.surface = surface; - cairo_surface_reference (surface); + _cairo_pattern_init_for_surface (pattern, surface); + + /* this will go away when we completely remove the surface attributes */ + if (surface->repeat) + pattern->base.extend = CAIRO_EXTEND_REPEAT; + else + pattern->base.extend = CAIRO_EXTEND_DEFAULT; - return pattern; + return &pattern->base; } cairo_pattern_t * cairo_pattern_create_linear (double x0, double y0, double x1, double y1) { - cairo_pattern_t *pattern; + cairo_linear_pattern_t *pattern; - pattern = malloc (sizeof (cairo_pattern_t)); + pattern = malloc (sizeof (cairo_linear_pattern_t)); if (pattern == NULL) return NULL; - _cairo_pattern_init (pattern); - - pattern->type = CAIRO_PATTERN_LINEAR; - pattern->u.linear.point0.x = x0; - pattern->u.linear.point0.y = y0; - pattern->u.linear.point1.x = x1; - pattern->u.linear.point1.y = y1; + _cairo_pattern_init_linear (pattern, x0, y0, x1, y1); - return pattern; + return &pattern->base.base; } cairo_pattern_t * cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1) { - cairo_pattern_t *pattern; + cairo_radial_pattern_t *pattern; - pattern = malloc (sizeof (cairo_pattern_t)); + pattern = malloc (sizeof (cairo_radial_pattern_t)); if (pattern == NULL) return NULL; - _cairo_pattern_init (pattern); - - pattern->type = CAIRO_PATTERN_RADIAL; - pattern->u.radial.center0.x = cx0; - pattern->u.radial.center0.y = cy0; - pattern->u.radial.radius0 = fabs (radius0); - pattern->u.radial.center1.x = cx1; - pattern->u.radial.center1.y = cy1; - pattern->u.radial.radius1 = fabs (radius1); + _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1); - return pattern; + return &pattern->base.base; } void @@ -209,37 +294,19 @@ cairo_pattern_destroy (cairo_pattern_t *pattern) free (pattern); } -static int -_cairo_pattern_stop_compare (const void *elem1, const void *elem2) -{ - return - (((cairo_color_stop_t *) elem1)->offset == - ((cairo_color_stop_t *) elem2)->offset) ? - /* equal offsets, sort on id */ - ((((cairo_color_stop_t *) elem1)->id < - ((cairo_color_stop_t *) elem2)->id) ? -1 : 1) : - /* sort on offset */ - ((((cairo_color_stop_t *) elem1)->offset < - ((cairo_color_stop_t *) elem2)->offset) ? -1 : 1); -} - -cairo_status_t -cairo_pattern_add_color_stop (cairo_pattern_t *pattern, - double offset, - double red, double green, double blue, - double alpha) +static cairo_status_t +_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, + double offset, + double red, + double green, + double blue, + double alpha) { cairo_color_stop_t *stop; - int i; - - _cairo_restrict_value (&offset, 0.0, 1.0); - _cairo_restrict_value (&red, 0.0, 1.0); - _cairo_restrict_value (&green, 0.0, 1.0); - _cairo_restrict_value (&blue, 0.0, 1.0); pattern->n_stops++; pattern->stops = realloc (pattern->stops, - sizeof (cairo_color_stop_t) * pattern->n_stops); + pattern->n_stops * sizeof (cairo_color_stop_t)); if (pattern->stops == NULL) { pattern->n_stops = 0; @@ -249,41 +316,51 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern, stop = &pattern->stops[pattern->n_stops - 1]; stop->offset = _cairo_fixed_from_double (offset); - stop->id = pattern->n_stops; - stop->color_char[0] = red * 0xff; - stop->color_char[1] = green * 0xff; - stop->color_char[2] = blue * 0xff; - stop->color_char[3] = alpha * 0xff; + _cairo_color_init (&stop->color); + _cairo_color_set_rgb (&stop->color, red, green, blue); + _cairo_color_set_alpha (&stop->color, alpha); - /* sort stops in ascending order */ - qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t), - _cairo_pattern_stop_compare); - - for (i = 0; i < pattern->n_stops - 1; i++) { - pattern->stops[i + 1].scale = - pattern->stops[i + 1].offset - pattern->stops[i].offset; - if (pattern->stops[i + 1].scale == 65536) - pattern->stops[i + 1].scale = 0; + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_pattern_add_color_stop (cairo_pattern_t *pattern, + double offset, + double red, + double green, + double blue, + double alpha) +{ + if (pattern->type != CAIRO_PATTERN_LINEAR && + pattern->type != CAIRO_PATTERN_RADIAL) + { + /* XXX: CAIRO_STATUS_INVALID_PATTERN? */ + return CAIRO_STATUS_SUCCESS; } - return CAIRO_STATUS_SUCCESS; + _cairo_restrict_value (&offset, 0.0, 1.0); + _cairo_restrict_value (&red, 0.0, 1.0); + _cairo_restrict_value (&green, 0.0, 1.0); + _cairo_restrict_value (&blue, 0.0, 1.0); + _cairo_restrict_value (&alpha, 0.0, 1.0); + + return _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, + offset, + red, green, blue, + alpha); } cairo_status_t cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) { - cairo_matrix_copy (&pattern->matrix, matrix); - - return CAIRO_STATUS_SUCCESS; + return cairo_matrix_copy (&pattern->matrix, matrix); } cairo_status_t cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) { - cairo_matrix_copy (matrix, &pattern->matrix); - - return CAIRO_STATUS_SUCCESS; + return cairo_matrix_copy (matrix, &pattern->matrix); } cairo_status_t @@ -316,9 +393,20 @@ cairo_pattern_get_extend (cairo_pattern_t *pattern) cairo_status_t _cairo_pattern_get_rgb (cairo_pattern_t *pattern, - double *red, double *green, double *blue) + double *red, + double *green, + double *blue) { - _cairo_color_get_rgb (&pattern->color, red, green, blue); + + if (pattern->type == CAIRO_PATTERN_SOLID) + { + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; + + *red = solid->red; + *green = solid->green; + *blue = solid->blue; + } else + *red = *green = *blue = 1.0; return CAIRO_STATUS_SUCCESS; } @@ -326,63 +414,16 @@ _cairo_pattern_get_rgb (cairo_pattern_t *pattern, void _cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha) { - int i; - - _cairo_color_set_alpha (&pattern->color, alpha); - - for (i = 0; i < pattern->n_stops; i++) - pattern->stops[i].color_char[3] = - MULTIPLY_COLORCOMP (pattern->stops[i].color_char[3], alpha * 0xff); -} - -void -_cairo_pattern_set_source_offset (cairo_pattern_t *pattern, - double x, double y) -{ - pattern->source_offset.x = x; - pattern->source_offset.y = y; + pattern->alpha = alpha; } void _cairo_pattern_transform (cairo_pattern_t *pattern, - cairo_matrix_t *ctm_inverse) + cairo_matrix_t *ctm_inverse) { cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix); } -void -_cairo_pattern_prepare_surface (cairo_pattern_t *pattern) -{ - cairo_matrix_t device_to_source; - cairo_matrix_t user_to_source; - - /* should the surface matrix interface be remove from the API? - for now we multiple the surface matrix with the pattern matrix */ - cairo_surface_get_matrix (pattern->u.surface.surface, &user_to_source); - cairo_matrix_multiply (&device_to_source, &pattern->matrix, - &user_to_source); - cairo_surface_set_matrix (pattern->source, &device_to_source); - - /* storing original surface matrix in pattern */ - pattern->u.surface.save_matrix = user_to_source; - - /* storing original surface repeat mode in pattern */ - pattern->u.surface.save_repeat = pattern->source->repeat; - - /* what do we do with extend types pad and reflect? */ - if (pattern->extend == CAIRO_EXTEND_REPEAT - || pattern->source->repeat == 1) - cairo_surface_set_repeat (pattern->source, 1); - else - cairo_surface_set_repeat (pattern->source, 0); - - /* storing original surface filter in pattern */ - pattern->u.surface.save_filter = - cairo_surface_get_filter (pattern->source); - - cairo_surface_set_filter (pattern->source, pattern->filter); -} - #define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \ ((factor < 32768)? c1: c2) @@ -390,7 +431,7 @@ static void _cairo_pattern_shader_nearest (unsigned char *color0, unsigned char *color1, cairo_fixed_t factor, - int *pixel) + uint32_t *pixel) { *pixel = ((INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor) << 24) | @@ -408,7 +449,7 @@ static void _cairo_pattern_shader_linear (unsigned char *color0, unsigned char *color1, cairo_fixed_t factor, - int *pixel) + uint32_t *pixel) { *pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) | (INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) | @@ -422,7 +463,7 @@ static void _cairo_pattern_shader_gaussian (unsigned char *color0, unsigned char *color1, cairo_fixed_t factor, - int *pixel) + uint32_t *pixel) { double f = ((double) factor) / 65536.0; @@ -436,17 +477,59 @@ _cairo_pattern_shader_gaussian (unsigned char *color0, #undef INTERPOLATE_COLOR_LINEAR -void -_cairo_pattern_shader_init (cairo_pattern_t *pattern, - cairo_shader_op_t *op) -{ - op->stops = pattern->stops; - op->n_stops = pattern->n_stops - 1; - op->min_offset = pattern->stops[0].offset; - op->max_offset = pattern->stops[op->n_stops].offset; - op->extend = pattern->extend; - - switch (pattern->filter) { +static int +_cairo_shader_color_stop_compare (const void *elem1, const void *elem2) +{ + cairo_shader_color_stop_t *s1 = (cairo_shader_color_stop_t *) elem1; + cairo_shader_color_stop_t *s2 = (cairo_shader_color_stop_t *) elem2; + + return + (s1->offset == s2->offset) ? + /* equal offsets, sort on id */ + ((s1->id < s2->id) ? -1 : 1) : + /* sort on offset */ + ((s1->offset < s2->offset) ? -1 : 1); +} + +static cairo_status_t +_cairo_pattern_shader_init (cairo_gradient_pattern_t *pattern, + cairo_shader_op_t *op) +{ + int i; + + op->stops = malloc (pattern->n_stops * sizeof (cairo_shader_color_stop_t)); + if (!op->stops) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < pattern->n_stops; i++) + { + op->stops[i].color_char[0] = pattern->stops[i].color.red * 0xff; + op->stops[i].color_char[1] = pattern->stops[i].color.green * 0xff; + op->stops[i].color_char[2] = pattern->stops[i].color.blue * 0xff; + op->stops[i].color_char[3] = pattern->stops[i].color.alpha * + pattern->base.alpha * 0xff; + op->stops[i].offset = pattern->stops[i].offset; + op->stops[i].id = i; + } + + /* sort stops in ascending order */ + qsort (op->stops, pattern->n_stops, sizeof (cairo_shader_color_stop_t), + _cairo_shader_color_stop_compare); + + for (i = 0; i < pattern->n_stops - 1; i++) + { + op->stops[i + 1].scale = op->stops[i + 1].offset - op->stops[i].offset; + if (op->stops[i + 1].scale == 65536) + op->stops[i + 1].scale = 0; + } + + op->n_stops = pattern->n_stops; + op->extend = pattern->base.extend; + + /* XXX: this is wrong, the filter should not be used for selecting + color stop interpolation function. function should always be 'linear' + and filter should be used for computing pixels. */ + switch (pattern->base.filter) { case CAIRO_FILTER_FAST: case CAIRO_FILTER_NEAREST: op->shader_function = _cairo_pattern_shader_nearest; @@ -460,15 +543,56 @@ _cairo_pattern_shader_init (cairo_pattern_t *pattern, op->shader_function = _cairo_pattern_shader_linear; break; } + + return CAIRO_STATUS_SUCCESS; } -void -_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op, - cairo_fixed_t factor, - int *pixel) +static void +_cairo_pattern_shader_fini (cairo_shader_op_t *op) +{ + if (op->stops) + free (op->stops); +} + +/* Find two color stops bounding the given offset. If the given offset + * is before the first or after the last stop offset, the nearest + * offset is returned twice. + */ +static void +_cairo_shader_op_find_color_stops (cairo_shader_op_t *op, + cairo_fixed_t offset, + cairo_shader_color_stop_t *stops[2]) { int i; - + + /* Before first stop. */ + if (offset <= op->stops[0].offset) { + stops[0] = &op->stops[0]; + stops[1] = &op->stops[0]; + return; + } + + /* Between two stops. */ + for (i = 0; i < op->n_stops - 1; i++) { + if (offset <= op->stops[i + 1].offset) { + stops[0] = &op->stops[i]; + stops[1] = &op->stops[i + 1]; + return; + } + } + + /* After last stop. */ + stops[0] = &op->stops[op->n_stops - 1]; + stops[1] = &op->stops[op->n_stops - 1]; +} + +static void +_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op, + cairo_fixed_t factor, + uint32_t *pixel) +{ + cairo_shader_color_stop_t *stops[2]; + switch (op->extend) { case CAIRO_EXTEND_REPEAT: factor -= factor & 0xffff0000; @@ -485,96 +609,158 @@ _cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op, break; } - if (factor < op->min_offset) - factor = op->min_offset; - else if (factor > op->max_offset) - factor = op->max_offset; - - for (i = 0; i < op->n_stops; i++) { - if (factor <= op->stops[i + 1].offset) { - - /* take offset as new 0 of coordinate system */ - factor -= op->stops[i].offset; - - /* difference between two offsets == 0, abrubt change */ - if (op->stops[i + 1].scale) - factor = ((cairo_fixed_48_16_t) factor << 16) / - op->stops[i + 1].scale; + _cairo_shader_op_find_color_stops (op, factor, stops); + + /* take offset as new 0 of coordinate system */ + factor -= stops[0]->offset; - op->shader_function (op->stops[i].color_char, - op->stops[i + 1].color_char, - factor, pixel); + /* difference between two offsets == 0, abrubt change */ + if (stops[1]->scale) + factor = ((cairo_fixed_48_16_t) factor << 16) / + stops[1]->scale; + + op->shader_function (stops[0]->color_char, + stops[1]->color_char, + factor, pixel); - /* multiply alpha */ - if (((unsigned char) (*pixel >> 24)) != 0xff) { - *pixel = (*pixel & 0xff000000) | - (MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) | - (MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) | - (MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0); - } - break; - } + /* multiply alpha */ + if (((unsigned char) (*pixel >> 24)) != 0xff) { + *pixel = (*pixel & 0xff000000) | + (MULTIPLY_COLORCOMP (*pixel >> 16, *pixel >> 24) << 16) | + (MULTIPLY_COLORCOMP (*pixel >> 8, *pixel >> 24) << 8) | + (MULTIPLY_COLORCOMP (*pixel >> 0, *pixel >> 24) << 0); } } -static void -_cairo_image_data_set_linear (cairo_pattern_t *pattern, - double offset_x, - double offset_y, - int *pixels, - int width, - int height) +static cairo_status_t +_cairo_image_data_set_linear (cairo_linear_pattern_t *pattern, + double offset_x, + double offset_y, + uint32_t *pixels, + int width, + int height) { int x, y; cairo_point_double_t point0, point1; - double px, py, ex, ey; double a, b, c, d, tx, ty; - double length, start, angle, fx, fy, factor; + double scale, start, dx, dy, factor; cairo_shader_op_t op; - - _cairo_pattern_shader_init (pattern, &op); - - point0.x = pattern->u.linear.point0.x; - point0.y = pattern->u.linear.point0.y; - point1.x = pattern->u.linear.point1.x; - point1.y = pattern->u.linear.point1.y; - - cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty); - - length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) + - (point1.y - point0.y) * (point1.y - point0.y)); - length = (length) ? 1.0 / length : CAIRO_MAXSHORT; - - angle = -atan2 (point1.y - point0.y, point1.x - point0.x); - fx = cos (angle); - fy = -sin (angle); - - start = fx * point0.x; - start += fy * point0.y; + cairo_status_t status; + + status = _cairo_pattern_shader_init (&pattern->base, &op); + if (status) + return status; + + /* We compute the position in the linear gradient for + * a point q as: + * + * [q . (p1 - p0) - p0 . (p1 - p0)] / (p1 - p0) ^ 2 + * + * The computation is done in pattern space. The + * calculation could be heavily optimized by using the + * fact that 'factor' increases linearly in both + * directions. + */ + point0.x = pattern->point0.x; + point0.y = pattern->point0.y; + point1.x = pattern->point1.x; + point1.y = pattern->point1.y; + + cairo_matrix_get_affine (&pattern->base.base.matrix, + &a, &b, &c, &d, &tx, &ty); + + dx = point1.x - point0.x; + dy = point1.y - point0.y; + scale = dx * dx + dy * dy; + scale = (scale) ? 1.0 / scale : 1.0; + + start = dx * point0.x + dy * point0.y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { - px = x + offset_x; - py = y + offset_y; + double qx_device = x + offset_x; + double qy_device = y + offset_y; - /* transform fragment */ - ex = a * px + c * py + tx; - ey = b * px + d * py + ty; + /* transform fragment into pattern space */ + double qx = a * qx_device + c * qy_device + tx; + double qy = b * qx_device + d * qy_device + ty; - factor = ((fx * ex + fy * ey) - start) * length; + factor = ((dx * qx + dy * qy) - start) * scale; _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++); } } + + _cairo_pattern_shader_fini (&op); + + return CAIRO_STATUS_SUCCESS; } static void -_cairo_image_data_set_radial (cairo_pattern_t *pattern, - double offset_x, - double offset_y, - int *pixels, - int width, - int height) +_cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern, + double offset_x, + double offset_y, + int width, + int height, + cairo_bool_t *is_horizontal, + cairo_bool_t *is_vertical) +{ + cairo_point_double_t point0, point1; + double a, b, c, d, tx, ty; + double scale, start, dx, dy; + cairo_fixed_t factors[3]; + int i; + + /* To classidy a pattern as horizontal or vertical, we first + * compute the (fixed point) factors at the corners of the + * pattern. We actually only need 3/4 corners, so we skip the + * fourth. + */ + point0.x = pattern->point0.x; + point0.y = pattern->point0.y; + point1.x = pattern->point1.x; + point1.y = pattern->point1.y; + + cairo_matrix_get_affine (&pattern->base.base.matrix, + &a, &b, &c, &d, &tx, &ty); + + dx = point1.x - point0.x; + dy = point1.y - point0.y; + scale = dx * dx + dy * dy; + scale = (scale) ? 1.0 / scale : 1.0; + + start = dx * point0.x + dy * point0.y; + + for (i = 0; i < 3; i++) { + double qx_device = (i % 2) * (width - 1) + offset_x; + double qy_device = (i / 2) * (height - 1) + offset_y; + + /* transform fragment into pattern space */ + double qx = a * qx_device + c * qy_device + tx; + double qy = b * qx_device + d * qy_device + ty; + + factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale); + } + + /* We consider a pattern to be vertical if the fixed point factor + * at the two upper corners is the same. We could accept a small + * change, but determining what change is acceptable would require + * sorting the stops in the pattern and looking at the differences. + * + * Horizontal works the same way with the two left corners. + */ + + *is_vertical = factors[1] == factors[0]; + *is_horizontal = factors[2] == factors[0]; +} + +static cairo_status_t +_cairo_image_data_set_radial (cairo_radial_pattern_t *pattern, + double offset_x, + double offset_y, + uint32_t *pixels, + int width, + int height) { int x, y, aligned_circles; cairo_point_double_t c0, c1; @@ -584,15 +770,18 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern, c0_c1_x, c0_c1_y, c0_c1, angle_c0, c1_y, y_x, c0_y, c0_x, r1_2, denumerator, fraction, factor; cairo_shader_op_t op; + cairo_status_t status; - _cairo_pattern_shader_init (pattern, &op); + status = _cairo_pattern_shader_init (&pattern->base, &op); + if (status) + return status; - c0.x = pattern->u.radial.center0.x; - c0.y = pattern->u.radial.center0.y; - r0 = pattern->u.radial.radius0; - c1.x = pattern->u.radial.center1.x; - c1.y = pattern->u.radial.center1.y; - r1 = pattern->u.radial.radius1; + c0.x = pattern->center0.x; + c0.y = pattern->center0.y; + r0 = pattern->radius0; + c1.x = pattern->center1.x; + c1.y = pattern->center1.y; + r1 = pattern->radius1; if (c0.x != c1.x || c0.y != c1.y) { aligned_circles = 0; @@ -606,7 +795,8 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern, r1_2 = c0_c1 = 0.0; /* shut up compiler */ } - cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty); + cairo_matrix_get_affine (&pattern->base.base.matrix, + &a, &b, &c, &d, &tx, &ty); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { @@ -682,70 +872,454 @@ _cairo_image_data_set_radial (cairo_pattern_t *pattern, _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++); } } + + _cairo_pattern_shader_fini (&op); + + return CAIRO_STATUS_SUCCESS; } -cairo_image_surface_t * -_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box) +static cairo_int_status_t +_cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern, + cairo_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_surface_t **out, + cairo_surface_attributes_t *attr) { - cairo_surface_t *surface; + cairo_image_surface_t *image; + cairo_status_t status; + uint32_t *data; + cairo_bool_t repeat = FALSE; + + if (pattern->base.type == CAIRO_PATTERN_LINEAR) { + cairo_bool_t is_horizontal; + cairo_bool_t is_vertical; + + _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern, + x, y, width, height, + &is_horizontal, &is_vertical); + if (is_horizontal) { + height = 1; + repeat = TRUE; + } + if (is_vertical) { + width = 1; + repeat = TRUE; + } + } + + data = malloc (width * height * 4); + if (!data) + return CAIRO_STATUS_NO_MEMORY; + + if (pattern->base.type == CAIRO_PATTERN_LINEAR) + { + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern; + + status = _cairo_image_data_set_linear (linear, x, y, data, + width, height); + } + else + { + cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern; + + status = _cairo_image_data_set_radial (radial, x, y, data, + width, height); + } - switch (pattern->type) { - case CAIRO_PATTERN_LINEAR: - case CAIRO_PATTERN_RADIAL: { - char *data; - double x = box->p1.x >> 16; - double y = box->p1.y >> 16; - int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16); - int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16); + if (status) { + free (data); + return status; + } + + image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data ((char *) data, + CAIRO_FORMAT_ARGB32, + width, height, + width * 4); + + if (image == NULL) { + free (data); + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_image_surface_assume_ownership_of_data (image); + + status = _cairo_surface_clone_similar (dst, &image->base, out); + + cairo_surface_destroy (&image->base); + + attr->x_offset = -x; + attr->y_offset = -y; + cairo_matrix_set_identity (&attr->matrix); + attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE; + attr->filter = CAIRO_FILTER_NEAREST; + attr->acquired = FALSE; + + return status; +} + +static cairo_int_status_t +_cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern, + cairo_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_surface_t **out, + cairo_surface_attributes_t *attribs) +{ + cairo_color_t color; + + _cairo_color_init (&color); + _cairo_color_set_rgb (&color, pattern->red, pattern->green, pattern->blue); + _cairo_color_set_alpha (&color, pattern->base.alpha); + + *out = _cairo_surface_create_similar_solid (dst, + CAIRO_FORMAT_ARGB32, + 1, 1, + &color); + + if (*out == NULL) + return CAIRO_STATUS_NO_MEMORY; + + attribs->x_offset = attribs->y_offset = 0; + cairo_matrix_set_identity (&attribs->matrix); + attribs->extend = CAIRO_EXTEND_REPEAT; + attribs->filter = CAIRO_FILTER_NEAREST; + attribs->acquired = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + + +/** + * _cairo_pattern_is_opaque + * + * Convenience function to determine whether a pattern has an opaque + * alpha value. This is done by testing whether the pattern's alpha + * value when converted to a byte is 255, so if a backend actually + * supported deep alpha channels this function might not do the right + * thing. + * + * Note that for a gradient or surface pattern, the overall resulting + * alpha for the pattern can be non-opaque even this function returns + * %TRUE, since the resulting alpha is the multiplication of the + * alpha of the gradient or surface with the pattern's alpha. In + * the future, alpha will be moved from the base pattern to the + * solid pattern subtype, at which point this function should + * probably be renamed to _cairo_pattern_is_opaque_solid() + * + * Return value: %TRUE if the pattern is opaque + **/ +cairo_bool_t +_cairo_pattern_is_opaque (cairo_pattern_t *pattern) +{ + return (pattern->alpha >= ((double)0xff00 / (double)0xffff)); +} + +static cairo_int_status_t +_cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern, + cairo_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_surface_t **out, + cairo_surface_attributes_t *attr) +{ + cairo_int_status_t status; + + attr->acquired = FALSE; + + /* handle pattern opacity */ + if (!_cairo_pattern_is_opaque (&pattern->base)) + { + cairo_surface_pattern_t tmp; + cairo_color_t color; + + _cairo_color_init (&color); + _cairo_color_set_alpha (&color, pattern->base.alpha); + + *out = _cairo_surface_create_similar_solid (dst, + CAIRO_FORMAT_ARGB32, + width, height, + &color); + if (*out == NULL) + return CAIRO_STATUS_NO_MEMORY; + + status = _cairo_pattern_init_copy (&tmp.base, &pattern->base); + if (CAIRO_OK (status)) + { + tmp.base.alpha = 1.0; + status = _cairo_surface_composite (CAIRO_OPERATOR_IN, + &tmp.base, + NULL, + *out, + x, y, 0, 0, 0, 0, + width, height); + + _cairo_pattern_fini (&tmp.base); + } + + if (status) { + cairo_surface_destroy (*out); + return status; + } - data = malloc (width * height * 4); - if (!data) - return NULL; + attr->x_offset = -x; + attr->y_offset = -y; + attr->extend = CAIRO_EXTEND_NONE; + attr->filter = CAIRO_FILTER_NEAREST; + + cairo_matrix_set_identity (&attr->matrix); + } + else + { + int tx, ty; + + if (_cairo_surface_is_image (dst)) + { + cairo_image_surface_t *image; + + status = _cairo_surface_acquire_source_image (pattern->surface, + &image, + &attr->extra); + if (CAIRO_OK (status)) + *out = &image->base; + + attr->acquired = TRUE; + } + else + status = _cairo_surface_clone_similar (dst, pattern->surface, out); - if (pattern->type == CAIRO_PATTERN_RADIAL) - _cairo_image_data_set_radial (pattern, x, y, (int *) data, - width, height); + attr->extend = pattern->base.extend; + attr->filter = pattern->base.filter; + if (_cairo_matrix_is_integer_translation (&pattern->base.matrix, + &tx, &ty)) + { + cairo_matrix_set_identity (&attr->matrix); + attr->x_offset = tx; + attr->y_offset = ty; + } else - _cairo_image_data_set_linear (pattern, x, y, (int *) data, - width, height); + { + attr->matrix = pattern->base.matrix; + attr->x_offset = attr->y_offset = 0; + } + } + + return status; +} - _cairo_pattern_set_source_offset (pattern, x, y); +/** + * _cairo_pattern_acquire_surface: + * @pattern: a #cairo_pattern_t + * @dst: destination surface + * @x: X coordinate in source corresponding to left side of destination area + * @y: Y coordinate in source corresponding to top side of destination area + * @width: width of destination area + * @height: height of destination area + * @surface_out: location to store a pointer to a surface + * @attributes: surface attributes that destination backend should apply to + * the returned surface + * + * A convenience function to obtain a surface to use as the source for + * drawing on @dst. + * + * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out. + **/ +cairo_int_status_t +_cairo_pattern_acquire_surface (cairo_pattern_t *pattern, + cairo_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_surface_t **surface_out, + cairo_surface_attributes_t *attributes) +{ + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: { + cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern; + + return _cairo_pattern_acquire_surface_for_solid (src, dst, + x, y, width, height, + surface_out, + attributes); + } break; + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern; + + /* fast path for gradients with less than 2 color stops */ + if (src->n_stops < 2) + { + cairo_solid_pattern_t solid; + + if (src->n_stops) + { + _cairo_pattern_init_solid (&solid, + src->stops->color.red, + src->stops->color.green, + src->stops->color.blue); + _cairo_pattern_set_alpha (&solid.base, + src->stops->color.alpha); + } + else + { + _cairo_pattern_init_solid (&solid, 0.0, 0.0, 0.0); + _cairo_pattern_set_alpha (&solid.base, 0.0); + } - surface = cairo_image_surface_create_for_data (data, - CAIRO_FORMAT_ARGB32, - width, height, - width * 4); + return _cairo_pattern_acquire_surface_for_solid (&solid, dst, + x, y, + width, height, + surface_out, + attributes); + } + else + return _cairo_pattern_acquire_surface_for_gradient (src, dst, + x, y, + width, height, + surface_out, + attributes); + } break; + case CAIRO_PATTERN_SURFACE: { + cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern; - if (surface) - _cairo_image_surface_assume_ownership_of_data ( - (cairo_image_surface_t *) surface); + return _cairo_pattern_acquire_surface_for_surface (src, dst, + x, y, width, height, + surface_out, + attributes); + } break; } - break; - case CAIRO_PATTERN_SOLID: - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); - if (surface) { - _cairo_surface_fill_rectangle (surface, - CAIRO_OPERATOR_SRC, - &pattern->color, 0, 0, 1, 1); - cairo_surface_set_repeat (surface, 1); + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +/** + * _cairo_pattern_release_surface: + * @pattern: a #cairo_pattern_t + * @info: pointer to #cairo_surface_attributes_t filled in by + * _cairo_pattern_acquire_surface + * + * Releases resources obtained by _cairo_pattern_acquire_surface. + **/ +void +_cairo_pattern_release_surface (cairo_surface_t *dst, + cairo_surface_t *surface, + cairo_surface_attributes_t *attributes) +{ + if (attributes->acquired) + _cairo_surface_release_source_image (dst, + (cairo_image_surface_t *) surface, + attributes->extra); + else + cairo_surface_destroy (surface); +} + +cairo_int_status_t +_cairo_pattern_acquire_surfaces (cairo_pattern_t *src, + cairo_pattern_t *mask, + cairo_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + unsigned int width, + unsigned int height, + cairo_surface_t **src_out, + cairo_surface_t **mask_out, + cairo_surface_attributes_t *src_attributes, + cairo_surface_attributes_t *mask_attributes) +{ + cairo_int_status_t status; + + cairo_pattern_union_t tmp; + cairo_bool_t src_opaque, mask_opaque; + double src_alpha, mask_alpha; + + src_opaque = _cairo_pattern_is_opaque (src); + mask_opaque = !mask || _cairo_pattern_is_opaque (mask); + + /* For surface patterns, we move any translucency from src->alpha + * to mask->alpha so we can use the source unchanged. Otherwise we + * move the translucency from mask->alpha to src->alpha so that + * we can drop the mask if possible. + */ + if (src->type == CAIRO_PATTERN_SURFACE) + { + if (mask) { + mask_opaque = mask_opaque && src_opaque; + mask_alpha = mask->alpha * src->alpha; + } else { + mask_opaque = src_opaque; + mask_alpha = src->alpha; } - break; - case CAIRO_PATTERN_SURFACE: { - cairo_image_surface_t *image; + + src_alpha = 1.0; + src_opaque = TRUE; + } + else + { + if (mask) + { + src_opaque = mask_opaque && src_opaque; + src_alpha = mask->alpha * src->alpha; + /* FIXME: This needs changing when we support RENDER + * style 4-channel masks. + */ + if (mask->type == CAIRO_PATTERN_SOLID) + mask = NULL; + } else + src_alpha = src->alpha; + + mask_alpha = 1.0; + mask_opaque = TRUE; + } - image = _cairo_surface_get_image (pattern->u.surface.surface); - if (image) - surface = &image->base; + _cairo_pattern_init_copy (&tmp.base, src); + _cairo_pattern_set_alpha (&tmp.base, src_alpha); + + status = _cairo_pattern_acquire_surface (&tmp.base, dst, + src_x, src_y, + width, height, + src_out, src_attributes); + + _cairo_pattern_fini (&tmp.base); + + if (status) + return status; + + if (mask || !mask_opaque) + { + if (mask) + _cairo_pattern_init_copy (&tmp.base, mask); else - surface = NULL; + _cairo_pattern_init_solid (&tmp.solid, 0.0, 0.0, 0.0); + + _cairo_pattern_set_alpha (&tmp.base, mask_alpha); + + status = _cairo_pattern_acquire_surface (&tmp.base, dst, + mask_x, mask_y, + width, height, + mask_out, mask_attributes); + _cairo_pattern_fini (&tmp.base); + + if (status) + { + _cairo_pattern_release_surface (dst, *src_out, src_attributes); + return status; + } } - break; - default: - surface = NULL; - break; + else + { + *mask_out = NULL; } - - return (cairo_image_surface_t *) surface; + + return CAIRO_STATUS_SUCCESS; } - diff --git a/src/cairo_pdf_surface.c b/src/cairo_pdf_surface.c index 23230aa74..fee918355 100644 --- a/src/cairo_pdf_surface.c +++ b/src/cairo_pdf_surface.c @@ -36,9 +36,8 @@ #include "cairoint.h" #include "cairo-pdf.h" -/* XXX: This seems broken to me. What about users without freetype - * that want to use a cairo PDF surface? */ -#include "cairo-ft.h" +/* XXX: Eventually, we need to handle other font backends */ +#include "cairo-ft-private.h" #include <ft2build.h> #include FT_FREETYPE_H @@ -54,10 +53,6 @@ * - Why doesn't pages inherit /alpha%d GS dictionaries from the Pages * object? * - * - Why isn't the pattern passed to composite traps instead of - * pattern->source? If composite traps needs an image or a surface it - * can call create_pattern(). - * * - We embed an image in the stream each time it's composited. We * could add generation counters to surfaces and remember the stream * ID for a particular generation for a particular surface. @@ -183,9 +178,6 @@ struct cairo_pdf_surface { double width_inches; double height_inches; - /* HACK: Non-null if this surface was created for a pattern. */ - cairo_pattern_t *pattern; - cairo_pdf_document_t *document; cairo_pdf_stream_t *current_stream; @@ -240,8 +232,6 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend; #define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) ) #define SFNT_VERSION 0x00010000 -#define OFFSET_TABLE_SIZE 12 -#define TABLE_DIRECTORY_ENTRY_SIZE 16 #ifdef WORDS_BIGENDIAN @@ -300,19 +290,15 @@ cairo_pdf_font_destroy (cairo_pdf_font_t *font) } static cairo_pdf_font_t * -cairo_pdf_ft_font_create (cairo_pdf_document_t *document, - cairo_unscaled_font_t *unscaled_font, - cairo_font_scale_t *scale) +cairo_pdf_ft_font_create (cairo_pdf_document_t *document, + cairo_unscaled_font_t *unscaled_font) { - cairo_font_t scaled_font; FT_Face face; cairo_pdf_ft_font_t *font; unsigned long size; int i, j; - /* FIXME: Why do I have to pass a scaled font to get the FT_Face? */ - _cairo_font_init (&scaled_font, scale, unscaled_font); - face = cairo_ft_font_face (&scaled_font); + face = _cairo_ft_unscaled_font_lock_face (unscaled_font); /* We currently only support freetype truetype fonts. */ size = 0; @@ -333,7 +319,8 @@ cairo_pdf_ft_font_create (cairo_pdf_document_t *document, if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS) goto fail1; - font->face = face; + font->base.unscaled_font = unscaled_font; + _cairo_unscaled_font_reference (unscaled_font); font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t)); if (font->glyphs == NULL) goto fail2; @@ -364,6 +351,8 @@ cairo_pdf_ft_font_create (cairo_pdf_document_t *document, if (font->base.widths == NULL) goto fail5; + _cairo_ft_unscaled_font_unlock_face (unscaled_font); + font->status = CAIRO_STATUS_SUCCESS; return &font->base; @@ -447,7 +436,7 @@ cairo_pdf_ft_font_write_cmap_table (cairo_pdf_ft_font_t *font, unsigned long tag cairo_pdf_ft_font_write_be16 (font, 0); cairo_pdf_ft_font_write_be16 (font, 1); - cairo_pdf_ft_font_write_be16 (font, 0); + cairo_pdf_ft_font_write_be16 (font, 1); cairo_pdf_ft_font_write_be16 (font, 0); cairo_pdf_ft_font_write_be32 (font, 12); @@ -764,12 +753,15 @@ cairo_pdf_ft_font_generate (void *abstract_font, unsigned long start, end, next, checksum; int i; + font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font); + if (cairo_pdf_ft_font_write_offset_table (font)) - return font->status; + goto fail; start = cairo_pdf_ft_font_align_output (font); end = start; + end = 0; for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) { if (truetype_tables[i].write (font, truetype_tables[i].tag)) goto fail; @@ -789,6 +781,9 @@ cairo_pdf_ft_font_generate (void *abstract_font, *length = _cairo_array_num_elements (&font->output); fail: + _cairo_ft_unscaled_font_unlock_face (font->base.unscaled_font); + font->face = NULL; + return font->status; } @@ -947,14 +942,13 @@ _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document, surface->width_inches = width_inches; surface->height_inches = height_inches; - surface->pattern = NULL; _cairo_pdf_document_reference (document); surface->document = document; _cairo_array_init (&surface->streams, sizeof (cairo_pdf_stream_t *)); _cairo_array_init (&surface->patterns, sizeof (cairo_pdf_resource_t)); _cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t)); _cairo_array_init (&surface->alphas, sizeof (double)); - _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t)); + _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_resource_t)); return &surface->base; } @@ -1102,38 +1096,46 @@ _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface) } } -static cairo_image_surface_t * -_cairo_pdf_surface_get_image (void *abstract_surface) +static cairo_status_t +_cairo_pdf_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { - return NULL; + return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_status_t -_cairo_pdf_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +static void +_cairo_pdf_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) { - return CAIRO_INT_STATUS_UNSUPPORTED; } static cairo_status_t -_cairo_pdf_surface_set_matrix (void *abstract_surface, - cairo_matrix_t *matrix) +_cairo_pdf_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra) { - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_status_t -_cairo_pdf_surface_set_filter (void *abstract_surface, - cairo_filter_t filter) +static void +_cairo_pdf_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) { - return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_pdf_surface_set_repeat (void *abstract_surface, - int repeat) +_cairo_pdf_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { - return CAIRO_STATUS_SUCCESS; + return CAIRO_INT_STATUS_UNSUPPORTED; } static void * @@ -1210,23 +1212,34 @@ emit_image_data (cairo_pdf_document_t *document, } static cairo_int_status_t -_cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, - cairo_image_surface_t *image) +_cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, + cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; FILE *file = document->file; unsigned id; cairo_matrix_t i2u; + cairo_status_t status; + cairo_image_surface_t *image; + cairo_surface_t *src; + void *image_extra; + + src = pattern->surface; + status = _cairo_surface_acquire_source_image (src, &image, &image_extra); + if (!CAIRO_OK (status)) + return status; id = emit_image_data (dst->document, image); - if (id == 0) - return CAIRO_STATUS_NO_MEMORY; + if (id == 0) { + status = CAIRO_STATUS_NO_MEMORY; + goto bail; + } _cairo_pdf_surface_add_xobject (dst, id); _cairo_pdf_surface_ensure_stream (dst); - cairo_matrix_copy (&i2u, &image->base.matrix); + cairo_matrix_copy (&i2u, &pattern->base.matrix); cairo_matrix_invert (&i2u); cairo_matrix_translate (&i2u, 0, image->height); cairo_matrix_scale (&i2u, image->width, -image->height); @@ -1238,7 +1251,10 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, i2u.m[2][0], i2u.m[2][1], id); - return CAIRO_STATUS_SUCCESS; + bail: + _cairo_surface_release_source_image (src, image, image_extra); + + return status; } /* The contents of the surface is already transformed into PDF units, @@ -1253,20 +1269,19 @@ _cairo_pdf_surface_composite_image (cairo_pdf_surface_t *dst, static cairo_int_status_t _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst, - cairo_pdf_surface_t *src, - int width, int height) + cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; FILE *file = document->file; cairo_matrix_t i2u; cairo_pdf_stream_t *stream; int num_streams, i; - - if (src->pattern != NULL) - return CAIRO_STATUS_SUCCESS; + cairo_pdf_surface_t *src; _cairo_pdf_surface_ensure_stream (dst); + src = (cairo_pdf_surface_t *) pattern->surface; + cairo_matrix_copy (&i2u, &src->base.matrix); cairo_matrix_invert (&i2u); cairo_matrix_scale (&i2u, @@ -1297,8 +1312,8 @@ _cairo_pdf_surface_composite_pdf (cairo_pdf_surface_t *dst, static cairo_int_status_t _cairo_pdf_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, void *abstract_dst, int src_x, int src_y, @@ -1310,17 +1325,18 @@ _cairo_pdf_surface_composite (cairo_operator_t operator, unsigned int height) { cairo_pdf_surface_t *dst = abstract_dst; - cairo_pdf_surface_t *src; - cairo_image_surface_t *image; + cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) src_pattern; - if (generic_src->backend == &cairo_pdf_surface_backend) { - src = (cairo_pdf_surface_t *) generic_src; - return _cairo_pdf_surface_composite_pdf (dst, src, width, height); - } - else { - image = _cairo_surface_get_image (generic_src); - return _cairo_pdf_surface_composite_image (dst, image); - } + if (mask_pattern) + return CAIRO_STATUS_SUCCESS; + + if (src_pattern->type != CAIRO_PATTERN_SURFACE) + return CAIRO_STATUS_SUCCESS; + + if (src->surface->backend == &cairo_pdf_surface_backend) + return _cairo_pdf_surface_composite_pdf (dst, src); + else + return _cairo_pdf_surface_composite_image (dst, src); } static cairo_int_status_t @@ -1335,9 +1351,6 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface, FILE *file = document->file; int i; - if (surface->pattern != NULL) - return CAIRO_STATUS_SUCCESS; - _cairo_pdf_surface_ensure_stream (surface); fprintf (file, @@ -1355,23 +1368,44 @@ _cairo_pdf_surface_fill_rectangles (void *abstract_surface, } static void -emit_tiling_pattern (cairo_operator_t operator, - cairo_pdf_surface_t *dst, - cairo_pattern_t *pattern) +emit_solid_pattern (cairo_pdf_surface_t *surface, + cairo_solid_pattern_t *pattern) +{ + cairo_pdf_document_t *document = surface->document; + FILE *file = document->file; + unsigned int alpha; + + alpha = _cairo_pdf_surface_add_alpha (surface, pattern->base.alpha); + _cairo_pdf_surface_ensure_stream (surface); + fprintf (file, + "%f %f %f rg /a%d gs\r\n", + pattern->red, + pattern->green, + pattern->blue, + alpha); +} + +static void +emit_surface_pattern (cairo_pdf_surface_t *dst, + cairo_surface_pattern_t *pattern) { cairo_pdf_document_t *document = dst->document; FILE *file = document->file; cairo_pdf_stream_t *stream; cairo_image_surface_t *image; + void *image_extra; + cairo_status_t status; char entries[250]; unsigned int id, alpha; cairo_matrix_t pm; - if (pattern->u.surface.surface->backend == &cairo_pdf_surface_backend) { + if (pattern->surface->backend == &cairo_pdf_surface_backend) { return; } - - image = _cairo_surface_get_image (pattern->u.surface.surface); + + status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra); + if (!CAIRO_OK (status)) + return; _cairo_pdf_document_close_stream (document); @@ -1382,7 +1416,7 @@ emit_tiling_pattern (cairo_operator_t operator, cairo_matrix_set_identity (&pm); cairo_matrix_scale (&pm, image->width, image->height); - cairo_matrix_copy (&pm, &pattern->matrix); + cairo_matrix_copy (&pm, &pattern->base.matrix); cairo_matrix_invert (&pm); snprintf (entries, sizeof entries, @@ -1401,6 +1435,8 @@ emit_tiling_pattern (cairo_operator_t operator, stream = _cairo_pdf_document_open_stream (document, entries); + /* FIXME: emit code to show surface here. */ + _cairo_pdf_surface_add_pattern (dst, stream->id); _cairo_pdf_surface_ensure_stream (dst); @@ -1408,10 +1444,12 @@ emit_tiling_pattern (cairo_operator_t operator, fprintf (file, "/Pattern cs /res%d scn /a%d gs\r\n", stream->id, alpha); + + _cairo_surface_release_source_image (pattern->surface, image, image_extra); } static unsigned int -emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) +emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_gradient_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; FILE *file = document->file; @@ -1430,12 +1468,12 @@ emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) "stream\r\n", function_id); - fputc (pattern->stops[0].color_char[0], file); - fputc (pattern->stops[0].color_char[1], file); - fputc (pattern->stops[0].color_char[2], file); - fputc (pattern->stops[1].color_char[0], file); - fputc (pattern->stops[1].color_char[1], file); - fputc (pattern->stops[1].color_char[2], file); + fputc (pattern->stops[0].color.red * 0xff, file); + fputc (pattern->stops[0].color.green * 0xff, file); + fputc (pattern->stops[0].color.blue * 0xff, file); + fputc (pattern->stops[1].color.red * 0xff, file); + fputc (pattern->stops[1].color.green * 0xff, file); + fputc (pattern->stops[1].color.blue * 0xff, file); fprintf (file, "\r\n" @@ -1446,7 +1484,7 @@ emit_pattern_stops (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) } static void -emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) +emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_linear_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; FILE *file = document->file; @@ -1456,16 +1494,16 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) _cairo_pdf_document_close_stream (document); - function_id = emit_pattern_stops (surface, pattern); + function_id = emit_pattern_stops (surface, &pattern->base); - cairo_matrix_copy (&p2u, &pattern->matrix); + cairo_matrix_copy (&p2u, &pattern->base.base.matrix); cairo_matrix_invert (&p2u); - x0 = pattern->u.linear.point0.x; - y0 = pattern->u.linear.point0.y; + x0 = pattern->point0.x; + y0 = pattern->point0.y; cairo_matrix_transform_point (&p2u, &x0, &y0); - x1 = pattern->u.linear.point1.x; - y1 = pattern->u.linear.point1.y; + x1 = pattern->point1.x; + y1 = pattern->point1.y; cairo_matrix_transform_point (&p2u, &x1, &y1); pattern_id = _cairo_pdf_document_new_object (document); @@ -1479,16 +1517,14 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) " /ColorSpace /DeviceRGB\r\n" " /Coords [ %f %f %f %f ]\r\n" " /Function %d 0 R\r\n" - " /Extend [ %s %s ]\r\n" + " /Extend [ true true ]\r\n" " >>\r\n" ">>\r\n" "endobj\r\n", pattern_id, document->height_inches * document->y_ppi, x0, y0, x1, y1, - function_id, - (1 || pattern->extend) ? "true" : "false", - (1 || pattern->extend) ? "true" : "false"); + function_id); _cairo_pdf_surface_add_pattern (surface, pattern_id); @@ -1502,7 +1538,7 @@ emit_linear_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) } static void -emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) +emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_radial_pattern_t *pattern) { cairo_pdf_document_t *document = surface->document; FILE *file = document->file; @@ -1512,24 +1548,31 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) _cairo_pdf_document_close_stream (document); - function_id = emit_pattern_stops (surface, pattern); + function_id = emit_pattern_stops (surface, &pattern->base); - cairo_matrix_copy (&p2u, &pattern->matrix); + cairo_matrix_copy (&p2u, &pattern->base.base.matrix); cairo_matrix_invert (&p2u); - x0 = pattern->u.radial.center0.x; - y0 = pattern->u.radial.center0.y; - r0 = pattern->u.radial.radius0; + x0 = pattern->center0.x; + y0 = pattern->center0.y; + r0 = pattern->radius0; cairo_matrix_transform_point (&p2u, &x0, &y0); - x1 = pattern->u.radial.center1.x; - y1 = pattern->u.radial.center1.y; - r1 = pattern->u.radial.radius1; + x1 = pattern->center1.x; + y1 = pattern->center1.y; + r1 = pattern->radius1; cairo_matrix_transform_point (&p2u, &x1, &y1); /* FIXME: This is surely crack, but how should you scale a radius * in a non-orthogonal coordinate system? */ cairo_matrix_transform_distance (&p2u, &r0, &r1); + /* FIXME: There is a difference between the cairo gradient extend + * semantics and PDF extend semantics. PDFs extend=false means + * that nothing is painted outside the gradient boundaries, + * whereas cairo takes this to mean that the end color is padded + * to infinity. Setting extend=true in PDF gives the cairo default + * behavoir, not yet sure how to implement the cairo mirror and + * repeat behaviour. */ pattern_id = _cairo_pdf_document_new_object (document); fprintf (file, "%d 0 obj\r\n" @@ -1541,16 +1584,14 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) " /ColorSpace /DeviceRGB\r\n" " /Coords [ %f %f %f %f %f %f ]\r\n" " /Function %d 0 R\r\n" - " /Extend [ %s %s ]\r\n" + " /Extend [ true true ]\r\n" " >>\r\n" ">>\r\n" "endobj\r\n", pattern_id, document->height_inches * document->y_ppi, x0, y0, r0, x1, y1, r1, - function_id, - (1 || pattern->extend) ? "true" : "false", - (1 || pattern->extend) ? "true" : "false"); + function_id); _cairo_pdf_surface_add_pattern (surface, pattern_id); @@ -1563,6 +1604,28 @@ emit_radial_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) pattern_id, alpha); } +static void +emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern) +{ + switch (pattern->type) { + case CAIRO_PATTERN_SOLID: + emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern); + break; + + case CAIRO_PATTERN_SURFACE: + emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern); + break; + + case CAIRO_PATTERN_LINEAR: + emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern); + break; + + case CAIRO_PATTERN_RADIAL: + emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern); + break; + } +} + static double intersect (cairo_line_t *line, cairo_fixed_t y) { @@ -1574,60 +1637,23 @@ intersect (cairo_line_t *line, cairo_fixed_t y) static cairo_int_status_t _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, + cairo_pattern_t *pattern, void *abstract_dst, int x_src, int y_src, + int x_dst, + int y_dst, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps) { cairo_pdf_surface_t *surface = abstract_dst; - cairo_pdf_surface_t *source = (cairo_pdf_surface_t *) generic_src; cairo_pdf_document_t *document = surface->document; - cairo_pattern_t *pattern; FILE *file = document->file; int i; - unsigned int alpha; - /* FIXME: we really just want the original pattern here, not a - * source surface. */ - pattern = source->pattern; - - if (source->base.backend != &cairo_pdf_surface_backend) { - printf ("_cairo_pdf_surface_composite_trapezoids: not a pdf source\r"); - return CAIRO_STATUS_SUCCESS; - } - - if (pattern == NULL) { - printf ("_cairo_pdf_surface_composite_trapezoids: " - "non-pattern pdf source\r"); - return CAIRO_STATUS_SUCCESS; - } - - switch (pattern->type) { - case CAIRO_PATTERN_SOLID: - alpha = _cairo_pdf_surface_add_alpha (surface, pattern->color.alpha); - _cairo_pdf_surface_ensure_stream (surface); - fprintf (file, - "%f %f %f rg /a%d gs\r\n", - pattern->color.red, - pattern->color.green, - pattern->color.blue, - alpha); - break; - - case CAIRO_PATTERN_SURFACE: - emit_tiling_pattern (operator, surface, pattern); - break; - - case CAIRO_PATTERN_LINEAR: - emit_linear_pattern (surface, pattern); - break; - - case CAIRO_PATTERN_RADIAL: - emit_radial_pattern (surface, pattern ); - break; - } + emit_pattern (surface, pattern); /* After the above switch the current stream should belong to this * surface, so no need to _cairo_pdf_surface_ensure_stream() */ @@ -1686,59 +1712,48 @@ _cairo_pdf_surface_set_clip_region (void *abstract_surface, return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_int_status_t -_cairo_pdf_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *extents) -{ - cairo_pdf_surface_t *surface = abstract_surface; - cairo_pdf_surface_t *source; - - source = (cairo_pdf_surface_t *) - _cairo_pdf_surface_create_for_document (surface->document, 0, 0); - source->pattern = pattern; - pattern->source = &source->base; - - return CAIRO_STATUS_SUCCESS; -} - static cairo_pdf_font_t * _cairo_pdf_document_get_font (cairo_pdf_document_t *document, - cairo_unscaled_font_t *unscaled_font, - cairo_font_scale_t *scale) + cairo_font_t *font) { - cairo_pdf_font_t *font; + cairo_unscaled_font_t *unscaled_font; + cairo_pdf_font_t *pdf_font; unsigned int num_fonts, i; + unscaled_font = _cairo_ft_font_get_unscaled_font (font); + num_fonts = _cairo_array_num_elements (&document->fonts); for (i = 0; i < num_fonts; i++) { - _cairo_array_copy_element (&document->fonts, i, &font); - if (font->unscaled_font == unscaled_font) - return font; + _cairo_array_copy_element (&document->fonts, i, &pdf_font); + if (pdf_font->unscaled_font == unscaled_font) + return pdf_font; } /* FIXME: Figure out here which font backend is in use and call * the appropriate constructor. */ - font = cairo_pdf_ft_font_create (document, unscaled_font, scale); - if (font == NULL) + pdf_font = cairo_pdf_ft_font_create (document, unscaled_font); + if (pdf_font == NULL) return NULL; - if (_cairo_array_append (&document->fonts, &font, 1) == NULL) { - cairo_pdf_font_destroy (font); + if (_cairo_array_append (&document->fonts, &pdf_font, 1) == NULL) { + cairo_pdf_font_destroy (pdf_font); return NULL; } - return font; + return pdf_font; } static cairo_status_t -_cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_pdf_surface_show_glyphs (cairo_font_t *font, cairo_operator_t operator, - cairo_surface_t *source, + cairo_pattern_t *pattern, void *abstract_surface, int source_x, int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs) { @@ -1748,23 +1763,23 @@ _cairo_pdf_surface_show_glyphs (cairo_unscaled_font_t *font, cairo_pdf_font_t *pdf_font; int i, index; - pdf_font = _cairo_pdf_document_get_font (document, font, scale); + pdf_font = _cairo_pdf_document_get_font (document, font); if (pdf_font == NULL) return CAIRO_STATUS_NO_MEMORY; - _cairo_pdf_surface_ensure_stream (surface); + emit_pattern (surface, pattern); - fprintf (file, "0 0 0 rg BT /res%u 1 Tf", pdf_font->font_id); + fprintf (file, "BT /res%u 1 Tf", pdf_font->font_id); for (i = 0; i < num_glyphs; i++) { index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index); fprintf (file, - " %f %f %f %f %f %f Tm (%c) Tj", - scale->matrix[0][0], - scale->matrix[0][1], - scale->matrix[1][0], - -scale->matrix[1][1], + " %f %f %f %f %f %f Tm (\\%o) Tj", + font->scale.matrix[0][0], + font->scale.matrix[0][1], + font->scale.matrix[1][0], + -font->scale.matrix[1][1], glyphs[i].x, glyphs[i].y, index); @@ -1780,18 +1795,17 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = { _cairo_pdf_surface_create_similar, _cairo_pdf_surface_destroy, _cairo_pdf_surface_pixels_per_inch, - _cairo_pdf_surface_get_image, - _cairo_pdf_surface_set_image, - _cairo_pdf_surface_set_matrix, - _cairo_pdf_surface_set_filter, - _cairo_pdf_surface_set_repeat, + _cairo_pdf_surface_acquire_source_image, + _cairo_pdf_surface_release_source_image, + _cairo_pdf_surface_acquire_dest_image, + _cairo_pdf_surface_release_dest_image, + _cairo_pdf_surface_clone_similar, _cairo_pdf_surface_composite, _cairo_pdf_surface_fill_rectangles, _cairo_pdf_surface_composite_trapezoids, _cairo_pdf_surface_copy_page, _cairo_pdf_surface_show_page, _cairo_pdf_surface_set_clip_region, - _cairo_pdf_surface_create_pattern, _cairo_pdf_surface_show_glyphs }; @@ -1930,8 +1944,8 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document) fprintf (file, "%d 0 obj\r\n" "<< /Type /FontDescriptor\r\n" - " /FontName /%s\r\n" - " /Flags 32\r\n" + " /FontName /7%s\r\n" + " /Flags 4\r\n" " /FontBBox [ %ld %ld %ld %ld ]\r\n" " /ItalicAngle 0\r\n" " /Ascent %ld\r\n" diff --git a/src/cairo_pen.c b/src/cairo_pen.c index f365091dc..6ecaa00b3 100644 --- a/src/cairo_pen.c +++ b/src/cairo_pen.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c index 2279b07a9..1ae745cb5 100644 --- a/src/cairo_png_surface.c +++ b/src/cairo_png_surface.c @@ -32,7 +32,7 @@ * * Contributor(s): * Olivier Andrieu <oliv__a@users.sourceforge.net> - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include <png.h> @@ -185,62 +185,65 @@ _cairo_png_surface_pixels_per_inch (void *abstract_surface) return 96.0; } -static cairo_image_surface_t * -_cairo_png_surface_get_image (void *abstract_surface) +static cairo_status_t +_cairo_png_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { cairo_png_surface_t *surface = abstract_surface; + + *image_out = surface->image; - cairo_surface_reference (&surface->image->base); - - return surface->image; + return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_png_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +static void +_cairo_png_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) { - cairo_png_surface_t *surface = abstract_surface; - - if (image == surface->image) - return CAIRO_STATUS_SUCCESS; - - /* XXX: Need to call _cairo_image_surface_set_image here, but it's - not implemented yet. */ - - return CAIRO_INT_STATUS_UNSUPPORTED; } static cairo_status_t -_cairo_png_surface_set_matrix (void *abstract_surface, - cairo_matrix_t *matrix) +_cairo_png_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra) { cairo_png_surface_t *surface = abstract_surface; + + image_rect->x = 0; + image_rect->y = 0; + image_rect->width = surface->image->width; + image_rect->height = surface->image->height; + + *image_out = surface->image; - return _cairo_image_surface_set_matrix (surface->image, matrix); + return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_png_surface_set_filter (void *abstract_surface, - cairo_filter_t filter) +static void +_cairo_png_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) { - cairo_png_surface_t *surface = abstract_surface; - - return _cairo_image_surface_set_filter (surface->image, filter); } static cairo_status_t -_cairo_png_surface_set_repeat (void *abstract_surface, - int repeat) +_cairo_png_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { - cairo_png_surface_t *surface = abstract_surface; - - return _cairo_image_surface_set_repeat (surface->image, repeat); + return CAIRO_INT_STATUS_UNSUPPORTED; } static cairo_int_status_t _cairo_png_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, + cairo_pattern_t *src, + cairo_pattern_t *mask, void *abstract_dst, int src_x, int src_y, @@ -266,10 +269,14 @@ _cairo_png_surface_fill_rectangles (void *abstract_surface, static cairo_int_status_t _cairo_png_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, + cairo_pattern_t *pattern, void *abstract_dst, - int x_src, - int y_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps) { @@ -297,18 +304,20 @@ _cairo_png_surface_copy_page (void *abstract_surface) rows[i] = surface->image->data + i * surface->image->stride; png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (png == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (png == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto BAIL1; + } info = png_create_info_struct (png); if (info == NULL) { - png_destroy_write_struct (&png, NULL); - return CAIRO_STATUS_NO_MEMORY; + status = CAIRO_STATUS_NO_MEMORY; + goto BAIL2; } if (setjmp (png_jmpbuf (png))) { status = CAIRO_STATUS_NO_MEMORY; - goto BAIL; + goto BAIL2; } png_init_io (png, surface->file); @@ -332,7 +341,7 @@ _cairo_png_surface_copy_page (void *abstract_surface) break; default: status = CAIRO_STATUS_NULL_POINTER; - goto BAIL; + goto BAIL2; } png_set_IHDR (png, info, @@ -365,9 +374,9 @@ _cairo_png_surface_copy_page (void *abstract_surface) surface->copied = 1; -BAIL: +BAIL2: png_destroy_write_struct (&png, &info); - +BAIL1: free (rows); return status; @@ -397,29 +406,20 @@ _cairo_png_surface_set_clip_region (void *abstract_surface, return _cairo_image_surface_set_clip_region (surface->image, region); } -static cairo_int_status_t -_cairo_png_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *extents) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - static const cairo_surface_backend_t cairo_png_surface_backend = { _cairo_png_surface_create_similar, _cairo_png_surface_destroy, _cairo_png_surface_pixels_per_inch, - _cairo_png_surface_get_image, - _cairo_png_surface_set_image, - _cairo_png_surface_set_matrix, - _cairo_png_surface_set_filter, - _cairo_png_surface_set_repeat, + _cairo_png_surface_acquire_source_image, + _cairo_png_surface_release_source_image, + _cairo_png_surface_acquire_dest_image, + _cairo_png_surface_release_dest_image, + _cairo_png_surface_clone_similar, _cairo_png_surface_composite, _cairo_png_surface_fill_rectangles, _cairo_png_surface_composite_trapezoids, _cairo_png_surface_copy_page, _cairo_png_surface_show_page, _cairo_png_surface_set_clip_region, - _cairo_png_surface_create_pattern, NULL /* show_glyphs */ }; diff --git a/src/cairo_polygon.c b/src/cairo_polygon.c index e85858033..59c615da2 100644 --- a/src/cairo_polygon.c +++ b/src/cairo_polygon.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include <stdlib.h> diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c index 4da8162c7..4a45fc679 100644 --- a/src/cairo_ps_surface.c +++ b/src/cairo_ps_surface.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" @@ -42,6 +42,22 @@ static const cairo_surface_backend_t cairo_ps_surface_backend; +/** + * cairo_set_target_ps: + * @cr: a #cairo_t + * @file: an open, writeable file + * @width_inches: width of the output page, in inches + * @height_inches: height of the output page, in inches + * @x_pixels_per_inch: X resolution to use for image fallbacks; + * not all Cairo drawing can be represented in a postscript + * file, so Cairo will write out images for some portions + * of the output. + * @y_pixels_per_inch: Y resolution to use for image fallbacks. + * + * Directs output for a #cairo_t to a postscript file. The file must + * be kept open until the #cairo_t is destroyed or set to have a + * different target, and then must be closed by the application. + **/ void cairo_set_target_ps (cairo_t *cr, FILE *file, @@ -192,62 +208,65 @@ _cairo_ps_surface_pixels_per_inch (void *abstract_surface) return surface->y_ppi; } -static cairo_image_surface_t * -_cairo_ps_surface_get_image (void *abstract_surface) +static cairo_status_t +_cairo_ps_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { cairo_ps_surface_t *surface = abstract_surface; + + *image_out = surface->image; - cairo_surface_reference (&surface->image->base); - - return surface->image; + return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_ps_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +static void +_cairo_ps_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) { - cairo_ps_surface_t *surface = abstract_surface; - - if (image == surface->image) - return CAIRO_STATUS_SUCCESS; - - /* XXX: Need to call _cairo_image_surface_set_image here, but it's - not implemented yet. */ - - return CAIRO_INT_STATUS_UNSUPPORTED; } static cairo_status_t -_cairo_ps_surface_set_matrix (void *abstract_surface, - cairo_matrix_t *matrix) +_cairo_ps_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra) { cairo_ps_surface_t *surface = abstract_surface; + + image_rect->x = 0; + image_rect->y = 0; + image_rect->width = surface->image->width; + image_rect->height = surface->image->height; + + *image_out = surface->image; - return _cairo_image_surface_set_matrix (surface->image, matrix); + return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_cairo_ps_surface_set_filter (void *abstract_surface, - cairo_filter_t filter) +static void +_cairo_ps_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) { - cairo_ps_surface_t *surface = abstract_surface; - - return _cairo_image_surface_set_filter (surface->image, filter); } static cairo_status_t -_cairo_ps_surface_set_repeat (void *abstract_surface, - int repeat) +_cairo_ps_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { - cairo_ps_surface_t *surface = abstract_surface; - - return _cairo_image_surface_set_repeat (surface->image, repeat); + return CAIRO_INT_STATUS_UNSUPPORTED; } static cairo_int_status_t _cairo_ps_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, + cairo_pattern_t *src, + cairo_pattern_t *mask, void *abstract_dst, int src_x, int src_y, @@ -273,10 +292,14 @@ _cairo_ps_surface_fill_rectangles (void *abstract_surface, static cairo_int_status_t _cairo_ps_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, + cairo_pattern_t *generic_src, void *abstract_dst, int x_src, int y_src, + int x_dst, + int y_dst, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps) { @@ -294,12 +317,10 @@ _cairo_ps_surface_copy_page (void *abstract_surface) int i, x, y; - cairo_surface_t *white_surface; + cairo_solid_pattern_t white_pattern; char *rgb, *compressed; long rgb_size, compressed_size; - cairo_color_t white; - rgb_size = 3 * width * height; rgb = malloc (rgb_size); if (rgb == NULL) { @@ -316,26 +337,19 @@ _cairo_ps_surface_copy_page (void *abstract_surface) /* PostScript can not represent the alpha channel, so we blend the current image over a white RGB surface to eliminate it. */ - white_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1); - if (white_surface == NULL) { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL2; - } - _cairo_color_init (&white); - _cairo_surface_fill_rectangle (white_surface, - CAIRO_OPERATOR_SRC, - &white, - 0, 0, 1, 1); - cairo_surface_set_repeat (white_surface, 1); + _cairo_pattern_init_solid (&white_pattern, 1.0, 1.0, 1.0); + _cairo_surface_composite (CAIRO_OPERATOR_OVER_REVERSE, - white_surface, + &white_pattern.base, NULL, &surface->image->base, 0, 0, 0, 0, 0, 0, width, height); + + _cairo_pattern_fini (&white_pattern.base); i = 0; for (y = 0; y < height; y++) { @@ -379,8 +393,6 @@ _cairo_ps_surface_copy_page (void *abstract_surface) /* Page footer */ fprintf (file, "%%%%EndPage\n"); - cairo_surface_destroy (white_surface); - BAIL2: free (compressed); BAIL1: free (rgb); @@ -412,29 +424,20 @@ _cairo_ps_surface_set_clip_region (void *abstract_surface, return _cairo_image_surface_set_clip_region (surface->image, region); } -static cairo_int_status_t -_cairo_ps_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *extents) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_create_similar, _cairo_ps_surface_destroy, _cairo_ps_surface_pixels_per_inch, - _cairo_ps_surface_get_image, - _cairo_ps_surface_set_image, - _cairo_ps_surface_set_matrix, - _cairo_ps_surface_set_filter, - _cairo_ps_surface_set_repeat, + _cairo_ps_surface_acquire_source_image, + _cairo_ps_surface_release_source_image, + _cairo_ps_surface_acquire_dest_image, + _cairo_ps_surface_release_dest_image, + _cairo_ps_surface_clone_similar, _cairo_ps_surface_composite, _cairo_ps_surface_fill_rectangles, _cairo_ps_surface_composite_trapezoids, _cairo_ps_surface_copy_page, _cairo_ps_surface_show_page, _cairo_ps_surface_set_clip_region, - _cairo_ps_surface_create_pattern, NULL /* show_glyphs */ }; diff --git a/src/cairo_quartz_surface.c b/src/cairo_quartz_surface.c index b7103b051..01b345cdc 100644 --- a/src/cairo_quartz_surface.c +++ b/src/cairo_quartz_surface.c @@ -1,6 +1,6 @@ /* cairo - a vector graphics library with display and print output * - * Copyright © 2004 Calum Robinson + * Copyright © 2004 Calum Robinson * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public diff --git a/src/cairo_slope.c b/src/cairo_slope.c index 1a1497988..a2edec038 100644 --- a/src/cairo_slope.c +++ b/src/cairo_slope.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo_spline.c b/src/cairo_spline.c index ff290d9dd..5119a8e2b 100644 --- a/src/cairo_spline.c +++ b/src/cairo_spline.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" diff --git a/src/cairo_surface.c b/src/cairo_surface.c index a457d2062..330d58b1e 100644 --- a/src/cairo_surface.c +++ b/src/cairo_surface.c @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include <stdlib.h> @@ -151,16 +151,151 @@ _cairo_surface_pixels_per_inch (cairo_surface_t *surface) return surface->backend->pixels_per_inch (surface); } -cairo_image_surface_t * -_cairo_surface_get_image (cairo_surface_t *surface) +/** + * _cairo_surface_acquire_source_image: + * @surface: a #cairo_surface_t + * @image_out: location to store a pointer to an image surface that includes at least + * the intersection of @interest_rect with the visible area of @surface. + * This surface could be @surface itself, a surface held internal to @surface, + * or it could be a new surface with a copy of the relevant portion of @surface. + * @image_extra: location to store image specific backend data + * + * Gets an image surface to use when drawing as a fallback when drawing with + * @surface as a source. _cairo_surface_release_source_image() must be called + * when finished. + * + * Return value: %CAIRO_STATUS_SUCCESS if a an image was stored in @image_out. + * %CAIRO_INT_STATUS_UNSUPPORTED if an image cannot be retrieved for the specified + * surface. Or %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_surface_acquire_source_image (cairo_surface_t *surface, + cairo_image_surface_t **image_out, + void **image_extra) { - return surface->backend->get_image (surface); + return surface->backend->acquire_source_image (surface, image_out, image_extra); } +/** + * _cairo_surface_release_source_image: + * @surface: a #cairo_surface_t + * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image() + * + * Releases any resources obtained with _cairo_surface_acquire_source_image() + **/ +cairo_private void +_cairo_surface_release_source_image (cairo_surface_t *surface, + cairo_image_surface_t *image, + void *image_extra) +{ + surface->backend->release_source_image (surface, image, image_extra); +} + +/** + * _cairo_surface_acquire_dest_image: + * @surface: a #cairo_surface_t + * @interest_rect: area of @surface for which fallback drawing is being done. + * A value of %NULL indicates that the entire surface is desired. + * @image_out: location to store a pointer to an image surface that includes at least + * the intersection of @interest_rect with the visible area of @surface. + * This surface could be @surface itself, a surface held internal to @surface, + * or it could be a new surface with a copy of the relevant portion of @surface. + * @image_rect: location to store area of the original surface occupied + * by the surface stored in @image. + * @image_extra: location to store image specific backend data + * + * Retrieves a local image for a surface for implementing a fallback drawing + * operation. After calling this function, the implementation of the fallback + * drawing operation draws the primitive to the surface stored in @image_out + * then calls _cairo_surface_release_dest_fallback(), + * which, if a temporary surface was created, copies the bits back to the + * main surface and frees the temporary surface. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY. + * %CAIRO_INT_STATUS_UNSUPPORTED can be returned but this will mean that + * the backend can't draw with fallbacks. It's possible for the routine + * to store NULL in @local_out and return %CAIRO_STATUS_SUCCESS; + * that indicates that no part of @interest_rect is visible, so no drawing + * is necessary. _cairo_surface_release_dest_fallback() should not be called in that + * case. + **/ +cairo_status_t +_cairo_surface_acquire_dest_image (cairo_surface_t *surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra) +{ + return surface->backend->acquire_dest_image (surface, interest_rect, + image_out, image_rect, image_extra); +} + +/** + * _cairo_surface_end_fallback: + * @surface: a #cairo_surface_t + * @interest_rect: same as passed to the matching _cairo_surface_acquire_dest_image() + * @image: same as returned from the matching _cairo_surface_acquire_dest_image() + * @image_rect: same as returned from the matching _cairo_surface_acquire_dest_image() + * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image() + * + * Finishes the operation started with _cairo_surface_acquire_dest_image(), by, if + * necessary, copying the image from @image back to @surface and freeing any + * resources that were allocated. + **/ +void +_cairo_surface_release_dest_image (cairo_surface_t *surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + surface->backend->release_dest_image (surface, interest_rect, + image, image_rect, image_extra); +} + +/** + * _cairo_surface_clone_similar: + * @surface: a #cairo_surface_t + * @src: the source image + * @clone_out: location to store a surface compatible with @surface + * and with contents identical to @src. The caller must call + * cairo_surface_destroy() on the result. + * + * Creates a surface with contents identical to @src but that + * can be used efficiently with @surface. If @surface and @src are + * already compatible then it may return a new reference to @src. + * + * Return value: %CAIRO_STATUS_SUCCESS if a surface was created and stored + * in @clone_out. Otherwise %CAIRO_INT_STATUS_UNSUPPORTED or another + * error like %CAIRO_STATUS_NO_MEMORY. + **/ cairo_status_t -_cairo_surface_set_image (cairo_surface_t *surface, cairo_image_surface_t *image) +_cairo_surface_clone_similar (cairo_surface_t *surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { - return surface->backend->set_image (surface, image); + cairo_status_t status; + cairo_image_surface_t *image; + void *image_extra; + + status = surface->backend->clone_similar (surface, src, clone_out); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_surface_acquire_source_image (src, &image, &image_extra); + if (status != CAIRO_STATUS_SUCCESS) + return status; + + status = surface->backend->clone_similar (surface, &image->base, clone_out); + + /* If the above failed point, we could implement a full fallback + * using acquire_dest_image, but that's going to be very + * inefficient compared to a backend-specific implementation of + * clone_similar() with an image source. So we don't bother + */ + + _cairo_surface_release_source_image (src, image, image_extra); + return status; } cairo_status_t @@ -169,9 +304,7 @@ cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix) if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; - cairo_matrix_copy (&surface->matrix, matrix); - - return surface->backend->set_matrix (surface, matrix); + return cairo_matrix_copy (&surface->matrix, matrix); } slim_hidden_def(cairo_surface_set_matrix); @@ -192,7 +325,7 @@ cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter) return CAIRO_STATUS_NULL_POINTER; surface->filter = filter; - return surface->backend->set_filter (surface, filter); + return CAIRO_STATUS_SUCCESS; } cairo_filter_t @@ -224,14 +357,81 @@ cairo_surface_set_repeat (cairo_surface_t *surface, int repeat) surface->repeat = repeat; - return surface->backend->set_repeat (surface, repeat); + return CAIRO_STATUS_SUCCESS; } slim_hidden_def(cairo_surface_set_repeat); +typedef struct { + cairo_surface_t *dst; + cairo_rectangle_t extents; + cairo_image_surface_t *image; + cairo_rectangle_t image_rect; + void *image_extra; +} fallback_state_t; + +static cairo_status_t +_fallback_init (fallback_state_t *state, + cairo_surface_t *dst, + int x, + int y, + int width, + int height) +{ + state->extents.x = x; + state->extents.y = y; + state->extents.width = width; + state->extents.height = height; + + state->dst = dst; + + return _cairo_surface_acquire_dest_image (dst, &state->extents, + &state->image, &state->image_rect, &state->image_extra); +} + +static void +_fallback_cleanup (fallback_state_t *state) +{ + _cairo_surface_release_dest_image (state->dst, &state->extents, + state->image, &state->image_rect, state->image_extra); +} + +static cairo_status_t +_fallback_composite (cairo_operator_t operator, + cairo_pattern_t *src, + cairo_pattern_t *mask, + cairo_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + fallback_state_t state; + cairo_status_t status; + + status = _fallback_init (&state, dst, dst_x, dst_y, width, height); + if (!CAIRO_OK (status) || !state.image) + return status; + + state.image->base.backend->composite (operator, src, mask, + &state.image->base, + src_x, src_y, mask_x, mask_y, + dst_x - state.image_rect.x, + dst_y - state.image_rect.y, + width, height); + + _fallback_cleanup (&state); + + return status; +} + cairo_status_t _cairo_surface_composite (cairo_operator_t operator, - cairo_surface_t *src, - cairo_surface_t *mask, + cairo_pattern_t *src, + cairo_pattern_t *mask, cairo_surface_t *dst, int src_x, int src_y, @@ -243,7 +443,6 @@ _cairo_surface_composite (cairo_operator_t operator, unsigned int height) { cairo_int_status_t status; - cairo_image_surface_t *src_image, *mask_image = 0, *dst_image; status = dst->backend->composite (operator, src, mask, dst, @@ -254,28 +453,12 @@ _cairo_surface_composite (cairo_operator_t operator, if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; - src_image = _cairo_surface_get_image (src); - if (mask) - mask_image = _cairo_surface_get_image (mask); - dst_image = _cairo_surface_get_image (dst); - - dst_image->base.backend->composite (operator, - &src_image->base, - mask ? &mask_image->base : NULL, - dst_image, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); - - status = _cairo_surface_set_image (dst, dst_image); - - cairo_surface_destroy (&src_image->base); - if (mask) - cairo_surface_destroy (&mask_image->base); - cairo_surface_destroy (&dst_image->base); - - return status; + return _fallback_composite (operator, + src, mask, dst, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); } cairo_status_t @@ -297,6 +480,77 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface, return _cairo_surface_fill_rectangles (surface, operator, color, &rect, 1); } +static cairo_status_t +_fallback_fill_rectangles (cairo_surface_t *surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + fallback_state_t state; + cairo_rectangle_t *offset_rects = NULL; + cairo_status_t status; + int x1, y1, x2, y2; + int i; + + if (num_rects <= 0) + return CAIRO_STATUS_SUCCESS; + + /* Compute the bounds of the rectangles, so that we know what area of the + * destination surface to fetch + */ + x1 = rects[0].x; + y1 = rects[0].y; + x2 = rects[0].x + rects[0].width; + y2 = rects[0].y + rects[0].height; + + for (i = 1; i < num_rects; i++) { + if (rects[0].x < x1) + x1 = rects[0].x; + if (rects[0].y < y1) + y1 = rects[0].y; + + if (rects[0].x + rects[0].width > x2) + x2 = rects[0].x + rects[0].width; + if (rects[0].y + rects[0].height > y2) + y2 = rects[0].y + rects[0].height; + } + + status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1); + if (!CAIRO_OK (status) || !state.image) + return status; + + /* If the fetched image isn't at 0,0, we need to offset the rectangles */ + + if (state.image_rect.x != 0 || state.image_rect.y != 0) { + offset_rects = malloc (sizeof (cairo_rectangle_t) * num_rects); + if (!offset_rects) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } + + for (i = 0; i < num_rects; i++) { + offset_rects[i].x = rects[i].x - state.image_rect.x; + offset_rects[i].y = rects[i].y - state.image_rect.y; + offset_rects[i].width = rects[i].width; + offset_rects[i].height = rects[i].height; + } + + rects = offset_rects; + } + + state.image->base.backend->fill_rectangles (&state.image->base, operator, color, + rects, num_rects); + + if (offset_rects) + free (offset_rects); + + FAIL: + _fallback_cleanup (&state); + + return status; +} + cairo_status_t _cairo_surface_fill_rectangles (cairo_surface_t *surface, cairo_operator_t operator, @@ -305,7 +559,6 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, int num_rects) { cairo_int_status_t status; - cairo_image_surface_t *surface_image; if (num_rects == 0) return CAIRO_STATUS_SUCCESS; @@ -317,54 +570,105 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; - surface_image = _cairo_surface_get_image (surface); + return _fallback_fill_rectangles (surface, operator, color, rects, num_rects); +} + +static cairo_status_t +_fallback_composite_trapezoids (cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *dst, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, + cairo_trapezoid_t *traps, + int num_traps) +{ + fallback_state_t state; + cairo_trapezoid_t *offset_traps = NULL; + cairo_status_t status; + int i; + + status = _fallback_init (&state, dst, dst_x, dst_y, width, height); + if (!CAIRO_OK (status) || !state.image) + return status; - surface_image->base.backend->fill_rectangles (surface_image, - operator, - color, - rects, num_rects); + /* If the destination image isn't at 0,0, we need to offset the trapezoids */ + + if (state.image_rect.x != 0 || state.image_rect.y != 0) { + + cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x); + cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y); + + offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps); + if (!offset_traps) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } - status = _cairo_surface_set_image (surface, surface_image); + for (i = 0; i < num_traps; i++) { + offset_traps[i].top = traps[i].top - yoff; + offset_traps[i].bottom = traps[i].bottom - yoff; + offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff; + offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff; + offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff; + offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff; + offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff; + offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff; + offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff; + offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff; + } - cairo_surface_destroy (&surface_image->base); + traps = offset_traps; + } + state.image->base.backend->composite_trapezoids (operator, pattern, + &state.image->base, + src_x, src_y, + dst_x - state.image_rect.x, + dst_y - state.image_rect.y, + width, height, traps, num_traps); + if (offset_traps) + free (offset_traps); + + FAIL: + _fallback_cleanup (&state); + return status; } + cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *src, + cairo_pattern_t *pattern, cairo_surface_t *dst, - int x_src, - int y_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps) { cairo_int_status_t status; - cairo_image_surface_t *src_image, *dst_image; status = dst->backend->composite_trapezoids (operator, - src, dst, - x_src, y_src, + pattern, dst, + src_x, src_y, + dst_x, dst_y, + width, height, traps, num_traps); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; - src_image = _cairo_surface_get_image (src); - dst_image = _cairo_surface_get_image (dst); - - dst_image->base.backend->composite_trapezoids (operator, - &src_image->base, - dst_image, - x_src, y_src, - traps, num_traps); - - status = _cairo_surface_set_image (dst, dst_image); - - cairo_surface_destroy (&src_image->base); - cairo_surface_destroy (&dst_image->base); - - return status; + return _fallback_composite_trapezoids (operator, pattern, dst, + src_x, src_y, + dst_x, dst_y, + width, height, + traps, num_traps); } cairo_status_t @@ -402,109 +706,3 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *reg { return surface->backend->set_clip_region (surface, region); } - -cairo_status_t -_cairo_surface_create_pattern (cairo_surface_t *surface, - cairo_pattern_t *pattern, - cairo_box_t *box) -{ - cairo_int_status_t status; - - status = surface->backend->create_pattern (surface, pattern, box); - - /* The backend cannot accelerate this pattern, lets create an - unaccelerated source instead. */ - if (status == CAIRO_INT_STATUS_UNSUPPORTED) { - - status = CAIRO_STATUS_SUCCESS; - switch (pattern->type) { - case CAIRO_PATTERN_LINEAR: - case CAIRO_PATTERN_RADIAL: { - cairo_image_surface_t *image; - - image = _cairo_pattern_get_image (pattern, box); - if (image) { - pattern->source = &image->base; - - return CAIRO_STATUS_SUCCESS; - } else - return CAIRO_STATUS_NO_MEMORY; - - } break; - case CAIRO_PATTERN_SOLID: - pattern->source = - _cairo_surface_create_similar_solid (surface, - CAIRO_FORMAT_ARGB32, - 1, 1, - &pattern->color); - if (pattern->source) { - cairo_surface_set_repeat (pattern->source, 1); - - return CAIRO_STATUS_SUCCESS; - } else - return CAIRO_STATUS_NO_MEMORY; - break; - case CAIRO_PATTERN_SURFACE: - status = CAIRO_INT_STATUS_UNSUPPORTED; - - /* handle pattern opacity */ - if (pattern->color.alpha != 1.0) { - double x = box->p1.x >> 16; - double y = box->p1.y >> 16; - int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16); - int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16); - cairo_pattern_t alpha; - - pattern->source = - cairo_surface_create_similar (surface, - CAIRO_FORMAT_ARGB32, - width, height); - if (pattern->source) { - _cairo_pattern_init_solid (&alpha, 1.0, 1.0, 1.0); - _cairo_pattern_set_alpha (&alpha, pattern->color.alpha); - - status = _cairo_surface_create_pattern (pattern->source, - &alpha, box); - - if (status == CAIRO_STATUS_SUCCESS) { - int save_repeat = pattern->u.surface.surface->repeat; - - if (pattern->extend == CAIRO_EXTEND_REPEAT || - pattern->u.surface.surface->repeat == 1) - cairo_surface_set_repeat (pattern->u.surface.surface, 1); - else - cairo_surface_set_repeat (pattern->u.surface.surface, 0); - - status = - _cairo_surface_composite (CAIRO_OPERATOR_OVER, - pattern->u.surface.surface, - alpha.source, - pattern->source, - 0, 0, 0, 0, 0, 0, - width, height); - - cairo_surface_set_repeat (pattern->u.surface.surface, - save_repeat); - - if (status == CAIRO_STATUS_SUCCESS) - _cairo_pattern_set_source_offset (pattern, x, y); - else - cairo_surface_destroy (pattern->source); - } - - _cairo_pattern_fini (&alpha); - } - } - - if (status != CAIRO_STATUS_SUCCESS) { - pattern->source = pattern->u.surface.surface; - cairo_surface_reference (pattern->u.surface.surface); - - return CAIRO_STATUS_SUCCESS; - } - break; - } - } - - return status; -} diff --git a/src/cairo_traps.c b/src/cairo_traps.c index d17a27281..79c7e16b6 100644 --- a/src/cairo_traps.c +++ b/src/cairo_traps.c @@ -1,31 +1,42 @@ /* - * Copyright © 2002 Keith Packard + * Copyright © 2002 Keith Packard * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Keith R. Packard <keithp@keithp.com> + * Carl D. Worth <cworth@cworth.org> * * 2002-07-15: Converted from XRenderCompositeDoublePoly to cairo_trap. Carl D. Worth */ #include "cairoint.h" -#define CAIRO_TRAPS_GROWTH_INC 10 - /* private functions */ static cairo_status_t @@ -52,12 +63,6 @@ _compare_cairo_edge_by_slope (const void *av, const void *bv); static cairo_fixed_16_16_t _compute_x (cairo_line_t *line, cairo_fixed_t y); -static double -_compute_inverse_slope (cairo_line_t *l); - -static double -_compute_x_intercept (cairo_line_t *l, double inverse_slope); - static int _line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret); @@ -68,6 +73,8 @@ _cairo_traps_init (cairo_traps_t *traps) traps->traps_size = 0; traps->traps = NULL; + traps->extents.p1.x = traps->extents.p1.y = CAIRO_MAXSHORT << 16; + traps->extents.p2.x = traps->extents.p2.y = CAIRO_MINSHORT << 16; } void @@ -93,7 +100,8 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo } if (traps->num_traps >= traps->traps_size) { - status = _cairo_traps_grow_by (traps, CAIRO_TRAPS_GROWTH_INC); + int inc = traps->traps_size ? traps->traps_size : 32; + status = _cairo_traps_grow_by (traps, inc); if (status) return status; } @@ -104,6 +112,28 @@ _cairo_traps_add_trap (cairo_traps_t *traps, cairo_fixed_t top, cairo_fixed_t bo trap->left = *left; trap->right = *right; + if (top < traps->extents.p1.y) + traps->extents.p1.y = top; + if (bottom > traps->extents.p2.y) + traps->extents.p2.y = bottom; + /* + * This isn't generally accurate, but it is close enough for + * this purpose. Assuming that the left and right segments always + * contain the trapezoid vertical extents, these compares will + * yield a containing box. Assuming that the points all come from + * the same figure which will eventually be completely drawn, then + * the compares will yield the correct overall extents + */ + if (left->p1.x < traps->extents.p1.x) + traps->extents.p1.x = left->p1.x; + if (left->p2.x < traps->extents.p1.x) + traps->extents.p1.x = left->p2.x; + + if (right->p1.x > traps->extents.p2.x) + traps->extents.p2.x = right->p1.x; + if (right->p2.x > traps->extents.p2.x) + traps->extents.p2.x = right->p2.x; + traps->num_traps++; return CAIRO_STATUS_SUCCESS; @@ -327,40 +357,132 @@ _compare_cairo_edge_by_current_x_slope (const void *av, const void *bv) sub-computations -- just a bunch of determinants. I haven't looked at complexity, (both are probably similar and it probably doesn't matter much anyway). + */ -static double -_det (double a, double b, double c, double d) +/* XXX: Keith's new intersection code is much cleaner, and uses + * sufficient precision for correctly sorting intersections according + * to the analysis in Hobby's paper. + * + * But, when we enable this code, some things are failing, (eg. the + * stars in test/fill_rule get filled wrong). This could indicate a + * bug in one of tree places: + * + * 1) The new intersection code in this file + * + * 2) cairo_wideint.c (which is only exercised here) + * + * 3) In the current tessellator, (where the old intersection + * code, with its mystic increments could be masking the bug). + * + * It will likely be easier to revisit this when the new tessellation + * code is in place. So, for now, we'll simply disable the new + * intersection code. + */ + +#define CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE 0 + +#if CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE +static const cairo_fixed_32_32_t +_det16_32 (cairo_fixed_16_16_t a, + cairo_fixed_16_16_t b, + cairo_fixed_16_16_t c, + cairo_fixed_16_16_t d) { - return a * d - b * c; + return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d), + _cairo_int32x32_64_mul (b, c)); } -static int -_lines_intersect (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection) +static const cairo_fixed_64_64_t +_det32_64 (cairo_fixed_32_32_t a, + cairo_fixed_32_32_t b, + cairo_fixed_32_32_t c, + cairo_fixed_32_32_t d) { - double dx1 = cairo_fixed_to_double (l1->p1.x - l1->p2.x); - double dy1 = cairo_fixed_to_double (l1->p1.y - l1->p2.y); - - double dx2 = cairo_fixed_to_double (l2->p1.x - l2->p2.x); - double dy2 = cairo_fixed_to_double (l2->p1.y - l2->p2.y); - - double l1_det, l2_det; + return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d), + _cairo_int64x64_128_mul (b, c)); +} - double den_det = _det (dx1, dy1, dx2, dy2); +static const cairo_fixed_32_32_t +_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a) +{ + return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16); +} - if (den_det == 0) +static int +_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection) +{ + cairo_fixed_16_16_t dx1, dx2, dy1, dy2; + cairo_fixed_32_32_t den_det; + cairo_fixed_32_32_t l1_det, l2_det; + cairo_fixed_64_64_t num_det; + cairo_fixed_32_32_t intersect_32_32; + cairo_fixed_48_16_t intersect_48_16; + cairo_fixed_16_16_t intersect_16_16; + cairo_quorem128_t qr; + + dx1 = l1->p1.x - l1->p2.x; + dy1 = l1->p1.y - l1->p2.y; + dx2 = l2->p1.x - l2->p2.x; + dy2 = l2->p1.y - l2->p2.y; + den_det = _det16_32 (dx1, dy1, + dx2, dy2); + + if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0))) return 0; - l1_det = _det (l1->p1.x, l1->p1.y, - l1->p2.x, l1->p2.y); - l2_det = _det (l2->p1.x, l2->p1.y, - l2->p2.x, l2->p2.y); + l1_det = _det16_32 (l1->p1.x, l1->p1.y, + l1->p2.x, l1->p2.y); + l2_det = _det16_32 (l2->p1.x, l2->p1.y, + l2->p2.x, l2->p2.y); - *y_intersection = _det (l1_det, dy1, - l2_det, dy2) / den_det; + + num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1), + l2_det, _fixed_16_16_to_fixed_32_32 (dy2)); + + /* + * Ok, this one is a bit tricky in fixed point, the denominator + * needs to be left with 32-bits of fraction so that the + * result of the divide ends up with 32-bits of fraction (64 - 32 = 32) + */ + qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det)); + + intersect_32_32 = _cairo_int128_to_int64 (qr.quo); + + /* + * Find the ceiling of the quotient -- divrem returns + * the quotient truncated towards zero, so if the + * quotient should be positive (num_den and den_det have same sign) + * bump the quotient up by one. + */ + + if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) && + (_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) == + _cairo_int64_ge (den_det, _cairo_int32_to_int64 (0)))) + { + intersect_32_32 = _cairo_int64_add (intersect_32_32, + _cairo_int32_to_int64 (1)); + } + + /* + * Now convert from 32.32 to 48.16 and take the ceiling; + * this requires adding in 15 1 bits and shifting the result + */ + + intersect_32_32 = _cairo_int64_add (intersect_32_32, + _cairo_int32_to_int64 ((1 << 16) - 1)); + intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16); + + /* + * And drop the top bits + */ + intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16); + + *y_intersection = intersect_16_16; return 1; } -*/ +#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */ + static cairo_fixed_16_16_t _compute_x (cairo_line_t *line, cairo_fixed_t y) { @@ -371,6 +493,7 @@ _compute_x (cairo_line_t *line, cairo_fixed_t y) return line->p1.x + (ex / dy); } +#if ! CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE static double _compute_inverse_slope (cairo_line_t *l) { @@ -460,6 +583,7 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ return 1; } +#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */ /* The algorithm here is pretty simple: @@ -567,32 +691,32 @@ _cairo_traps_tessellate_polygon (cairo_traps_t *traps, return CAIRO_STATUS_SUCCESS; } -static int +static cairo_bool_t _cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt) { cairo_slope_t slope_left, slope_pt, slope_right; if (t->top > pt->y) - return 0; + return FALSE; if (t->bottom < pt->y) - return 0; + return FALSE; _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2); _cairo_slope_init (&slope_pt, &t->left.p1, pt); if (_cairo_slope_compare (&slope_left, &slope_pt) < 0) - return 0; + return FALSE; _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2); _cairo_slope_init (&slope_pt, &t->right.p1, pt); if (_cairo_slope_compare (&slope_pt, &slope_right) < 0) - return 0; + return FALSE; - return 1; + return TRUE; } -int +cairo_bool_t _cairo_traps_contain (cairo_traps_t *traps, double x, double y) { int i; @@ -603,45 +727,14 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y) for (i = 0; i < traps->num_traps; i++) { if (_cairo_trap_contains (&traps->traps[i], &point)) - return 1; + return TRUE; } - return 0; -} - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) > (b) ? (a) : (b)) - -static void -_cairo_trap_extents (cairo_trapezoid_t *t, cairo_box_t *extents) -{ - cairo_fixed_t x; - - if (t->top < extents->p1.y) - extents->p1.y = t->top; - - if (t->bottom > extents->p2.y) - extents->p2.y = t->bottom; - - x = MIN (_compute_x (&t->left, t->top), - _compute_x (&t->left, t->bottom)); - if (x < extents->p1.x) - extents->p1.x = x; - - x = MAX (_compute_x (&t->right, t->top), - _compute_x (&t->right, t->bottom)); - if (x > extents->p2.x) - extents->p2.x = x; + return FALSE; } void _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents) { - int i; - - extents->p1.x = extents->p1.y = CAIRO_MAXSHORT << 16; - extents->p2.x = extents->p2.y = CAIRO_MINSHORT << 16; - - for (i = 0; i < traps->num_traps; i++) - _cairo_trap_extents (&traps->traps[i], extents); + *extents = traps->extents; } diff --git a/src/cairo_unicode.c b/src/cairo_unicode.c new file mode 100644 index 000000000..92201391a --- /dev/null +++ b/src/cairo_unicode.c @@ -0,0 +1,340 @@ +/* cairo_unicode.c: Unicode conversion routines + * + * The code in this file is derived from GLib's gutf8.c and + * ultimately from libunicode. It is relicensed under the + * dual LGPL/MPL with permission of the original authors. + * + * Copyright © 1999 Tom Tromey + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is cairo_unicode.c as distributed with the + * cairo graphics library. + * + * The Initial Developer of the Original Code is Tom Tromey. + * and Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor <otaylor@redhat.com> + */ + +#include <limits.h> + +#include <cairoint.h> + +#define UTF8_COMPUTE(Char, Mask, Len) \ + if (Char < 128) \ + { \ + Len = 1; \ + Mask = 0x7f; \ + } \ + else if ((Char & 0xe0) == 0xc0) \ + { \ + Len = 2; \ + Mask = 0x1f; \ + } \ + else if ((Char & 0xf0) == 0xe0) \ + { \ + Len = 3; \ + Mask = 0x0f; \ + } \ + else if ((Char & 0xf8) == 0xf0) \ + { \ + Len = 4; \ + Mask = 0x07; \ + } \ + else if ((Char & 0xfc) == 0xf8) \ + { \ + Len = 5; \ + Mask = 0x03; \ + } \ + else if ((Char & 0xfe) == 0xfc) \ + { \ + Len = 6; \ + Mask = 0x01; \ + } \ + else \ + Len = -1; + +#define UTF8_LENGTH(Char) \ + ((Char) < 0x80 ? 1 : \ + ((Char) < 0x800 ? 2 : \ + ((Char) < 0x10000 ? 3 : \ + ((Char) < 0x200000 ? 4 : \ + ((Char) < 0x4000000 ? 5 : 6))))) + + +#define UTF8_GET(Result, Chars, Count, Mask, Len) \ + (Result) = (Chars)[0] & (Mask); \ + for ((Count) = 1; (Count) < (Len); ++(Count)) \ + { \ + if (((Chars)[(Count)] & 0xc0) != 0x80) \ + { \ + (Result) = -1; \ + break; \ + } \ + (Result) <<= 6; \ + (Result) |= ((Chars)[(Count)] & 0x3f); \ + } + +#define UNICODE_VALID(Char) \ + ((Char) < 0x110000 && \ + (((Char) & 0xFFFFF800) != 0xD800) && \ + ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \ + ((Char) & 0xFFFE) != 0xFFFE) + + +static const char utf8_skip_data[256] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 +}; + +#define UTF8_NEXT_CHAR(p) (char *)((p) + utf8_skip_data[*(unsigned char *)(p)]) + +/* Converts a sequence of bytes encoded as UTF-8 to a Unicode character. + * If @p does not point to a valid UTF-8 encoded character, results are + * undefined. + **/ +static uint32_t +_utf8_get_char (const char *p) +{ + int i, mask = 0, len; + uint32_t result; + unsigned char c = (unsigned char) *p; + + UTF8_COMPUTE (c, mask, len); + if (len == -1) + return (uint32_t)-1; + UTF8_GET (result, p, i, mask, len); + + return result; +} + +/* Like _utf8_get_char, but take a maximum length + * and return (uint32_t)-2 on incomplete trailing character + */ +static uint32_t +_utf8_get_char_extended (const char *p, + long max_len) +{ + int i, len; + uint32_t wc = (unsigned char) *p; + + if (wc < 0x80) { + return wc; + } else if (wc < 0xc0) { + return (uint32_t)-1; + } else if (wc < 0xe0) { + len = 2; + wc &= 0x1f; + } else if (wc < 0xf0) { + len = 3; + wc &= 0x0f; + } else if (wc < 0xf8) { + len = 4; + wc &= 0x07; + } else if (wc < 0xfc) { + len = 5; + wc &= 0x03; + } else if (wc < 0xfe) { + len = 6; + wc &= 0x01; + } else { + return (uint32_t)-1; + } + + if (max_len >= 0 && len > max_len) { + for (i = 1; i < max_len; i++) { + if ((((unsigned char *)p)[i] & 0xc0) != 0x80) + return (uint32_t)-1; + } + return (uint32_t)-2; + } + + for (i = 1; i < len; ++i) { + uint32_t ch = ((unsigned char *)p)[i]; + + if ((ch & 0xc0) != 0x80) { + if (ch) + return (uint32_t)-1; + else + return (uint32_t)-2; + } + + wc <<= 6; + wc |= (ch & 0x3f); + } + + if (UTF8_LENGTH(wc) != len) + return (uint32_t)-1; + + return wc; +} + +/** + * _cairo_utf8_to_utf32: + * @str: an UTF-8 string + * @len: length of @str in bytes, or -1 if it is nul-terminated. + * If @len is supplied and the string has an embedded nul + * byte, only the portion before the nul byte is converted. + * @result: location to store a pointer to a newly allocated UTF-32 + * string (always native endian). Free with free(). A 0 + * word will be written after the last character. + * @items_written: location to store number of 32-bit words + * written. (Not including the trailing 0) + * + * Converts a UTF-8 string to UCS-4. UCS-4 is an encoding of Unicode + * with 1 32-bit word per character. The string is validated to + * consist entirely of valid Unicode characters. + * + * Return value: %CAIRO_STATUS_SUCCESS if the entire string was + * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an + * an invalid sequence was found. + **/ +cairo_status_t +_cairo_utf8_to_ucs4 (const char *str, + int len, + uint32_t **result, + int *items_written) +{ + uint32_t *str32 = NULL; + int n_chars, i; + const char *in; + + in = str; + n_chars = 0; + while ((len < 0 || str + len - in > 0) && *in) + { + uint32_t wc = _utf8_get_char_extended (in, str + len - in); + if (wc & 0x80000000 || !UNICODE_VALID (wc)) + return CAIRO_STATUS_INVALID_STRING; + + n_chars++; + if (n_chars == INT_MAX) + return CAIRO_STATUS_INVALID_STRING; + + in = UTF8_NEXT_CHAR (in); + } + + str32 = malloc (sizeof (uint32_t) * (n_chars + 1)); + if (!str32) + return CAIRO_STATUS_NO_MEMORY; + + in = str; + for (i=0; i < n_chars; i++) { + str32[i] = _utf8_get_char (in); + in = UTF8_NEXT_CHAR (in); + } + str32[i] = 0; + + *result = str32; + if (items_written) + *items_written = n_chars; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_utf8_to_utf16: + * @str: an UTF-8 string + * @len: length of @str in bytes, or -1 if it is nul-terminated. + * If @len is supplied and the string has an embedded nul + * byte, only the portion before the nul byte is converted. + * @result: location to store a pointer to a newly allocated UTF-16 + * string (always native endian). Free with free(). A 0 + * word will be written after the last character. + * @items_written: location to store number of 16-bit words + * written. (Not including the trailing 0) + * + * Converts a UTF-8 string to UTF-16. UTF-16 is an encoding of Unicode + * where characters are represented either as a single 16-bit word, or + * as a pair of 16-bit "surrogates". The string is validated to + * consist entirely of valid Unicode characters. + * + * Return value: %CAIRO_STATUS_SUCCESS if the entire string was + * succesfully converted. %CAIRO_STATUS_INVALID_STRING if an + * an invalid sequence was found. + **/ +cairo_status_t +_cairo_utf8_to_utf16 (const char *str, + int len, + uint16_t **result, + int *items_written) +{ + uint16_t *str16 = NULL; + int n16, i; + const char *in; + + in = str; + n16 = 0; + while ((len < 0 || str + len - in > 0) && *in) { + uint32_t wc = _utf8_get_char_extended (in, str + len - in); + if (wc & 0x80000000 || !UNICODE_VALID (wc)) + return CAIRO_STATUS_INVALID_STRING; + + if (wc < 0x10000) + n16 += 1; + else + n16 += 2; + + if (n16 == INT_MAX - 1 || n16 == INT_MAX) + return CAIRO_STATUS_INVALID_STRING; + + in = UTF8_NEXT_CHAR (in); + } + + + str16 = malloc (sizeof (uint16_t) * (n16 + 1)); + if (!str16) + return CAIRO_STATUS_NO_MEMORY; + + in = str; + for (i = 0; i < n16;) { + uint32_t wc = _utf8_get_char (in); + + if (wc < 0x10000) { + str16[i++] = wc; + } else { + str16[i++] = (wc - 0x10000) / 0x400 + 0xd800; + str16[i++] = (wc - 0x10000) % 0x400 + 0xdc00; + } + + in = UTF8_NEXT_CHAR (in); + } + + str16[i] = 0; + + *result = str16; + if (items_written) + *items_written = n16; + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo_win32_font.c b/src/cairo_win32_font.c new file mode 100644 index 000000000..02f0cffd6 --- /dev/null +++ b/src/cairo_win32_font.c @@ -0,0 +1,1252 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + */ + +#include <string.h> +#include <stdio.h> + +#include "cairo-win32-private.h" + +#ifndef SPI_GETFONTSMOOTHINGTYPE +#define SPI_GETFONTSMOOTHINGTYPE 0x200a +#endif +#ifndef FE_FONTSMOOTHINGCLEARTYPE +#define FE_FONTSMOOTHINGCLEARTYPE 2 +#endif +#ifndef CLEARTYPE_QUALITY +#define CLEARTYPE_QUALITY 5 +#endif + +const cairo_font_backend_t cairo_win32_font_backend; + +#define LOGICAL_SCALE 32 + +typedef struct { + cairo_font_t base; + + LOGFONTW logfont; + + BYTE quality; + + /* We do drawing and metrics computation in a "logical space" which + * is similar to font space, except that it is scaled by a factor + * of the (desired font size) * (LOGICAL_SCALE). The multiplication + * by LOGICAL_SCALE allows for sub-pixel precision. + */ + double logical_scale; + + /* The size we should actually request the font at from Windows; differs + * from the logical_scale because it is quantized for orthogonal + * transformations + */ + double logical_size; + + /* Transformations from device <=> logical space + */ + cairo_matrix_t logical_to_device; + cairo_matrix_t device_to_logical; + + /* We special case combinations of 90-degree-rotations, scales and + * flips ... that is transformations that take the axes to the + * axes. If preserve_axes is true, then swap_axes/swap_x/swap_y + * encode the 8 possibilities for orientation (4 rotation angles with + * and without a flip), and scale_x, scale_y the scale components. + */ + cairo_bool_t preserve_axes; + cairo_bool_t swap_axes; + cairo_bool_t swap_x; + cairo_bool_t swap_y; + double x_scale; + double y_scale; + + /* The size of the design unit of the font + */ + int em_square; + + HFONT scaled_font; + HFONT unscaled_font; + +} cairo_win32_font_t; + +#define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.)) + +static void +_compute_transform (cairo_win32_font_t *font, + cairo_font_scale_t *sc) +{ + if (NEARLY_ZERO (sc->matrix[0][1]) && NEARLY_ZERO (sc->matrix[1][0])) { + font->preserve_axes = TRUE; + font->x_scale = sc->matrix[0][0]; + font->swap_x = (sc->matrix[0][0] < 0); + font->y_scale = sc->matrix[1][1]; + font->swap_y = (sc->matrix[1][1] < 0); + font->swap_axes = FALSE; + + } else if (NEARLY_ZERO (sc->matrix[0][0]) && NEARLY_ZERO (sc->matrix[1][1])) { + font->preserve_axes = TRUE; + font->x_scale = sc->matrix[0][1]; + font->swap_x = (sc->matrix[0][1] < 0); + font->y_scale = sc->matrix[1][0]; + font->swap_y = (sc->matrix[1][0] < 0); + font->swap_axes = TRUE; + + } else { + font->preserve_axes = FALSE; + font->swap_x = font->swap_y = font->swap_axes = FALSE; + } + + if (font->preserve_axes) { + if (font->swap_x) + font->x_scale = - font->x_scale; + if (font->swap_y) + font->y_scale = - font->y_scale; + + font->logical_scale = LOGICAL_SCALE * font->y_scale; + font->logical_size = LOGICAL_SCALE * floor (font->y_scale + 0.5); + } + + /* The font matrix has x and y "scale" components which we extract and + * use as character scale values. + */ + cairo_matrix_set_affine (&font->logical_to_device, + sc->matrix[0][0], + sc->matrix[0][1], + sc->matrix[1][0], + sc->matrix[1][1], + 0, 0); + + if (!font->preserve_axes) { + _cairo_matrix_compute_scale_factors (&font->logical_to_device, + &font->x_scale, &font->y_scale, + TRUE); /* XXX: Handle vertical text */ + + font->logical_size = floor (LOGICAL_SCALE * font->y_scale + 0.5); + font->logical_scale = LOGICAL_SCALE * font->y_scale; + } + + cairo_matrix_scale (&font->logical_to_device, + 1.0 / font->logical_scale, 1.0 / font->logical_scale); + + font->device_to_logical = font->logical_to_device; + if (!CAIRO_OK (cairo_matrix_invert (&font->device_to_logical))) + cairo_matrix_set_identity (&font->device_to_logical); +} + +static BYTE +_get_system_quality (void) +{ + BOOL font_smoothing; + + if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) { + _cairo_win32_print_gdi_error ("_get_system_quality"); + return FALSE; + } + + if (font_smoothing) { + OSVERSIONINFO version_info; + + version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + + if (!GetVersionEx (&version_info)) { + _cairo_win32_print_gdi_error ("_get_system_quality"); + return FALSE; + } + + if (version_info.dwMajorVersion > 5 || + (version_info.dwMajorVersion == 5 && + version_info.dwMinorVersion >= 1)) { /* XP or newer */ + UINT smoothing_type; + + if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE, + 0, &smoothing_type, 0)) { + _cairo_win32_print_gdi_error ("_get_system_quality"); + return FALSE; + } + + if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE) + return CLEARTYPE_QUALITY; + } + + return ANTIALIASED_QUALITY; + } else + return DEFAULT_QUALITY; +} + +static cairo_font_t * +_win32_font_create (LOGFONTW *logfont, + cairo_font_scale_t *scale) +{ + cairo_win32_font_t *f; + + f = malloc (sizeof(cairo_win32_font_t)); + if (f == NULL) + return NULL; + + f->logfont = *logfont; + f->quality = _get_system_quality (); + f->em_square = 0; + f->scaled_font = NULL; + f->unscaled_font = NULL; + + _compute_transform (f, scale); + + _cairo_font_init ((cairo_font_t *)f, scale, &cairo_win32_font_backend); + + return (cairo_font_t *)f; +} + +static cairo_status_t +_win32_font_set_world_transform (cairo_win32_font_t *font, + HDC hdc) +{ + XFORM xform; + + xform.eM11 = font->logical_to_device.m[0][0]; + xform.eM21 = font->logical_to_device.m[1][0]; + xform.eM12 = font->logical_to_device.m[0][1]; + xform.eM22 = font->logical_to_device.m[1][1]; + xform.eDx = font->logical_to_device.m[2][0]; + xform.eDy = font->logical_to_device.m[2][1]; + + if (!SetWorldTransform (hdc, &xform)) + return _cairo_win32_print_gdi_error ("_win32_font_set_world_transform"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_win32_font_set_identity_transform (HDC hdc) +{ + if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY)) + return _cairo_win32_print_gdi_error ("_win32_font_set_identity_transform"); + + return CAIRO_STATUS_SUCCESS; +} + +static HDC +_get_global_font_dc (void) +{ + static HDC hdc; + + if (!hdc) { + hdc = CreateCompatibleDC (NULL); + if (!hdc) { + _cairo_win32_print_gdi_error ("_get_global_font_dc"); + return NULL; + } + + if (!SetGraphicsMode (hdc, GM_ADVANCED)) { + _cairo_win32_print_gdi_error ("_get_global_font_dc"); + DeleteDC (hdc); + return NULL; + } + } + + return hdc; +} + +static HFONT +_win32_font_get_scaled_font (cairo_win32_font_t *font) +{ + if (!font->scaled_font) { + LOGFONTW logfont = font->logfont; + logfont.lfHeight = font->logical_size; + logfont.lfWidth = 0; + logfont.lfEscapement = 0; + logfont.lfOrientation = 0; + logfont.lfQuality = font->quality; + + font->scaled_font = CreateFontIndirectW (&logfont); + if (!font->scaled_font) { + _cairo_win32_print_gdi_error ("_win32_font_get_scaled_font"); + return NULL; + } + } + + return font->scaled_font; +} + +static HFONT +_win32_font_get_unscaled_font (cairo_win32_font_t *font, + HDC hdc) +{ + if (!font->unscaled_font) { + OUTLINETEXTMETRIC *otm; + unsigned int otm_size; + HFONT scaled_font; + LOGFONTW logfont; + + scaled_font = _win32_font_get_scaled_font (font); + if (!scaled_font) + return NULL; + + if (!SelectObject (hdc, scaled_font)) { + _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:SelectObject"); + return NULL; + } + + otm_size = GetOutlineTextMetrics (hdc, 0, NULL); + if (!otm_size) { + _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics"); + return NULL; + } + + otm = malloc (otm_size); + if (!otm) + return NULL; + + if (!GetOutlineTextMetrics (hdc, otm_size, otm)) { + _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:GetOutlineTextMetrics"); + free (otm); + return NULL; + } + + font->em_square = otm->otmEMSquare; + free (otm); + + logfont = font->logfont; + logfont.lfHeight = font->em_square; + logfont.lfWidth = 0; + logfont.lfEscapement = 0; + logfont.lfOrientation = 0; + logfont.lfQuality = font->quality; + + font->unscaled_font = CreateFontIndirectW (&logfont); + if (!font->unscaled_font) { + _cairo_win32_print_gdi_error ("_win32_font_get_unscaled_font:CreateIndirect"); + return NULL; + } + } + + return font->unscaled_font; +} + +static cairo_status_t +_cairo_win32_font_select_unscaled_font (cairo_font_t *font, + HDC hdc) +{ + cairo_status_t status; + HFONT hfont; + HFONT old_hfont = NULL; + + hfont = _win32_font_get_unscaled_font ((cairo_win32_font_t *)font, hdc); + if (!hfont) + return CAIRO_STATUS_NO_MEMORY; + + old_hfont = SelectObject (hdc, hfont); + if (!old_hfont) + return _cairo_win32_print_gdi_error ("_cairo_win32_font_select_unscaled_font"); + + status = _win32_font_set_identity_transform (hdc); + if (!CAIRO_OK (status)) { + SelectObject (hdc, old_hfont); + return status; + } + + SetMapMode (hdc, MM_TEXT); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_win32_font_done_unscaled_font (cairo_font_t *font) +{ +} + +/* implement the font backend interface */ + +static cairo_status_t +_cairo_win32_font_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight, + cairo_font_scale_t *scale, + cairo_font_t **font_out) +{ + LOGFONTW logfont; + cairo_font_t *font; + uint16_t *face_name; + int face_name_len; + cairo_status_t status; + + status = _cairo_utf8_to_utf16 (family, -1, &face_name, &face_name_len); + if (!CAIRO_OK (status)) + return status; + + if (face_name_len > LF_FACESIZE - 1) { + free (face_name); + return CAIRO_STATUS_INVALID_STRING; + } + + memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * (face_name_len + 1)); + free (face_name); + + logfont.lfHeight = 0; /* filled in later */ + logfont.lfWidth = 0; /* filled in later */ + logfont.lfEscapement = 0; /* filled in later */ + logfont.lfOrientation = 0; /* filled in later */ + + switch (weight) { + case CAIRO_FONT_WEIGHT_NORMAL: + default: + logfont.lfWeight = FW_NORMAL; + break; + case CAIRO_FONT_WEIGHT_BOLD: + logfont.lfWeight = FW_BOLD; + break; + } + + switch (slant) { + case CAIRO_FONT_SLANT_NORMAL: + default: + logfont.lfItalic = FALSE; + break; + case CAIRO_FONT_SLANT_ITALIC: + case CAIRO_FONT_SLANT_OBLIQUE: + logfont.lfItalic = TRUE; + break; + } + + logfont.lfUnderline = FALSE; + logfont.lfStrikeOut = FALSE; + /* The docs for LOGFONT discourage using this, since the + * interpretation is locale-specific, but it's not clear what + * would be a better alternative. + */ + logfont.lfCharSet = DEFAULT_CHARSET; + logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; + logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logfont.lfQuality = DEFAULT_QUALITY; /* filled in later */ + logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + + if (!logfont.lfFaceName) + return CAIRO_STATUS_NO_MEMORY; + + font = _win32_font_create (&logfont, scale); + if (!font) + return CAIRO_STATUS_NO_MEMORY; + + *font_out = font; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_win32_font_destroy_font (void *abstract_font) +{ + cairo_win32_font_t *font = abstract_font; + + if (font->scaled_font) + DeleteObject (font->scaled_font); + + if (font->unscaled_font) + DeleteObject (font->unscaled_font); + + free (font); +} + +static void +_cairo_win32_font_destroy_unscaled_font (void *abstract_font) +{ +} + +static void +_cairo_win32_font_get_glyph_cache_key (void *abstract_font, + cairo_glyph_cache_key_t *key) +{ +} + +static cairo_status_t +_cairo_win32_font_text_to_glyphs (void *abstract_font, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs) +{ + cairo_win32_font_t *font = abstract_font; + uint16_t *utf16; + int n16; + GCP_RESULTSW gcp_results; + unsigned int buffer_size, i; + WCHAR *glyph_indices = NULL; + int *dx = NULL; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + double x_pos; + HDC hdc = NULL; + + status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16); + if (!CAIRO_OK (status)) + return status; + + gcp_results.lStructSize = sizeof (GCP_RESULTS); + gcp_results.lpOutString = NULL; + gcp_results.lpOrder = NULL; + gcp_results.lpCaretPos = NULL; + gcp_results.lpClass = NULL; + + buffer_size = MAX (n16 * 1.2, 16); /* Initially guess number of chars plus a few */ + if (buffer_size > INT_MAX) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL1; + } + + hdc = _get_global_font_dc (); + if (!hdc) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL1; + } + + status = cairo_win32_font_select_font (&font->base, hdc); + if (!CAIRO_OK (status)) + goto FAIL1; + + while (TRUE) { + if (glyph_indices) { + free (glyph_indices); + glyph_indices = NULL; + } + if (dx) { + free (dx); + dx = NULL; + } + + glyph_indices = malloc (sizeof (WCHAR) * buffer_size); + dx = malloc (sizeof (int) * buffer_size); + if (!glyph_indices || !dx) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; + } + + gcp_results.nGlyphs = buffer_size; + gcp_results.lpDx = dx; + gcp_results.lpGlyphs = glyph_indices; + + if (!GetCharacterPlacementW (hdc, utf16, n16, + 0, + &gcp_results, + GCP_DIACRITIC | GCP_LIGATE | GCP_GLYPHSHAPE | GCP_REORDER)) { + status = _cairo_win32_print_gdi_error ("_cairo_win32_font_text_to_glyphs"); + goto FAIL2; + } + + if (gcp_results.lpDx && gcp_results.lpGlyphs) + break; + + /* Too small a buffer, try again */ + + buffer_size *= 1.5; + if (buffer_size > INT_MAX) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; + } + } + + *num_glyphs = gcp_results.nGlyphs; + *glyphs = malloc (sizeof (cairo_glyph_t) * gcp_results.nGlyphs); + if (!*glyphs) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; + } + + x_pos = 0; + for (i = 0; i < gcp_results.nGlyphs; i++) { + (*glyphs)[i].index = glyph_indices[i]; + (*glyphs)[i].x = x_pos ; + (*glyphs)[i].y = 0; + + x_pos += dx[i] / font->logical_scale; + } + + FAIL2: + if (glyph_indices) + free (glyph_indices); + if (dx) + free (dx); + + cairo_win32_font_done_font (&font->base); + + FAIL1: + free (utf16); + + return status; +} + +static cairo_status_t +_cairo_win32_font_font_extents (void *abstract_font, + cairo_font_extents_t *extents) +{ + cairo_win32_font_t *font = abstract_font; + cairo_status_t status; + TEXTMETRIC metrics; + HDC hdc; + + hdc = _get_global_font_dc (); + if (!hdc) + return CAIRO_STATUS_NO_MEMORY; + + if (font->preserve_axes) { + /* For 90-degree rotations (including 0), we get the metrics + * from the GDI in logical space, then convert back to font space + */ + status = cairo_win32_font_select_font (&font->base, hdc); + if (!CAIRO_OK (status)) + return status; + GetTextMetrics (hdc, &metrics); + cairo_win32_font_done_font (&font->base); + + extents->ascent = metrics.tmAscent / font->logical_scale; + extents->descent = metrics.tmDescent / font->logical_scale; + + extents->height = (metrics.tmHeight + metrics.tmExternalLeading) / font->logical_scale; + extents->max_x_advance = metrics.tmMaxCharWidth / font->logical_scale; + extents->max_y_advance = 0; + + } else { + /* For all other transformations, we use the design metrics + * of the font. The GDI results from GetTextMetrics() on a + * transformed font are inexplicably large and we want to + * avoid them. + */ + status = _cairo_win32_font_select_unscaled_font (&font->base, hdc); + if (!CAIRO_OK (status)) + return status; + GetTextMetrics (hdc, &metrics); + _cairo_win32_font_done_unscaled_font (&font->base); + + extents->ascent = (double)metrics.tmAscent / font->em_square; + extents->descent = metrics.tmDescent * font->em_square; + extents->height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / font->em_square; + extents->max_x_advance = (double)(metrics.tmMaxCharWidth) / font->em_square; + extents->max_y_advance = 0; + + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_font_glyph_extents (void *abstract_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) +{ + cairo_win32_font_t *font = abstract_font; + static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; + GLYPHMETRICS metrics; + cairo_status_t status; + HDC hdc; + + hdc = _get_global_font_dc (); + if (!hdc) + return CAIRO_STATUS_NO_MEMORY; + + /* We handle only the case num_glyphs == 1, glyphs[i].x == glyphs[0].y == 0. + * This is all that the calling code triggers, and the backend interface + * will eventually be changed to match + */ + assert (num_glyphs == 1); + + if (font->preserve_axes) { + /* If we aren't rotating / skewing the axes, then we get the metrics + * from the GDI in device space and convert to font space. + */ + status = cairo_win32_font_select_font (&font->base, hdc); + if (!CAIRO_OK (status)) + return status; + GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX, + &metrics, 0, NULL, &matrix); + cairo_win32_font_done_font (&font->base); + + if (font->swap_axes) { + extents->x_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale; + extents->y_bearing = metrics.gmptGlyphOrigin.x / font->x_scale; + extents->width = metrics.gmBlackBoxY / font->y_scale; + extents->height = metrics.gmBlackBoxX / font->x_scale; + extents->x_advance = metrics.gmCellIncY / font->x_scale; + extents->y_advance = metrics.gmCellIncX / font->y_scale; + } else { + extents->x_bearing = metrics.gmptGlyphOrigin.x / font->x_scale; + extents->y_bearing = - metrics.gmptGlyphOrigin.y / font->y_scale; + extents->width = metrics.gmBlackBoxX / font->x_scale; + extents->height = metrics.gmBlackBoxY / font->y_scale; + extents->x_advance = metrics.gmCellIncX / font->x_scale; + extents->y_advance = metrics.gmCellIncY / font->y_scale; + } + + if (font->swap_x) { + extents->x_bearing = (- extents->x_bearing - extents->width); + extents->x_advance = - extents->x_advance; + } + + if (font->swap_y) { + extents->y_bearing = (- extents->y_bearing - extents->height); + extents->y_advance = - extents->y_advance; + } + + } else { + /* For all other transformations, we use the design metrics + * of the font. + */ + status = _cairo_win32_font_select_unscaled_font (&font->base, hdc); + GetGlyphOutlineW (hdc, glyphs[0].index, GGO_METRICS | GGO_GLYPH_INDEX, + &metrics, 0, NULL, &matrix); + _cairo_win32_font_done_unscaled_font (&font->base); + + extents->x_bearing = (double)metrics.gmptGlyphOrigin.x / font->em_square; + extents->y_bearing = (double)metrics.gmptGlyphOrigin.y / font->em_square; + extents->width = (double)metrics.gmBlackBoxX / font->em_square; + extents->height = (double)metrics.gmBlackBoxY / font->em_square; + extents->x_advance = (double)metrics.gmCellIncX / font->em_square; + extents->y_advance = (double)metrics.gmCellIncY / font->em_square; + } + + return CAIRO_STATUS_SUCCESS; +} + + +static cairo_status_t +_cairo_win32_font_glyph_bbox (void *abstract_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox) +{ + static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; + cairo_win32_font_t *font = abstract_font; + int x1 = 0, x2 = 0, y1 = 0, y2 = 0; + + if (num_glyphs > 0) { + HDC hdc = _get_global_font_dc (); + GLYPHMETRICS metrics; + cairo_status_t status; + int i; + + if (!hdc) + return CAIRO_STATUS_NO_MEMORY; + + status = cairo_win32_font_select_font (&font->base, hdc); + if (!CAIRO_OK (status)) + return status; + + for (i = 0; i < num_glyphs; i++) { + int x = floor (0.5 + glyphs[i].x); + int y = floor (0.5 + glyphs[i].y); + + GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | GGO_GLYPH_INDEX, + &metrics, 0, NULL, &matrix); + + if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x) + x1 = x + metrics.gmptGlyphOrigin.x; + if (i == 0 || y1 > y - metrics.gmptGlyphOrigin.y) + y1 = y - metrics.gmptGlyphOrigin.y; + if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX) + x2 = x + metrics.gmptGlyphOrigin.x + metrics.gmBlackBoxX; + if (i == 0 || y2 < y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY) + y2 = y - metrics.gmptGlyphOrigin.y + metrics.gmBlackBoxY; + } + + cairo_win32_font_done_font (&font->base); + } + + bbox->p1.x = _cairo_fixed_from_int (x1); + bbox->p1.y = _cairo_fixed_from_int (y1); + bbox->p2.x = _cairo_fixed_from_int (x2); + bbox->p2.y = _cairo_fixed_from_int (y2); + + return CAIRO_STATUS_SUCCESS; +} + +typedef struct { + cairo_win32_font_t *font; + HDC hdc; + + cairo_array_t glyphs; + cairo_array_t dx; + + int start_x; + int last_x; + int last_y; +} cairo_glyph_state_t; + +static void +_start_glyphs (cairo_glyph_state_t *state, + cairo_win32_font_t *font, + HDC hdc) +{ + state->hdc = hdc; + state->font = font; + + _cairo_array_init (&state->glyphs, sizeof (WCHAR)); + _cairo_array_init (&state->dx, sizeof (int)); +} + +static cairo_status_t +_flush_glyphs (cairo_glyph_state_t *state) +{ + int dx = 0; + if (!_cairo_array_append (&state->dx, &dx, 1)) + return CAIRO_STATUS_NO_MEMORY; + + if (!ExtTextOutW (state->hdc, + state->start_x, state->last_y, + ETO_GLYPH_INDEX, + NULL, + (WCHAR *)state->glyphs.elements, + state->glyphs.num_elements, + (int *)state->dx.elements)) { + return _cairo_win32_print_gdi_error ("_flush_glyphs"); + } + + _cairo_array_truncate (&state->glyphs, 0); + _cairo_array_truncate (&state->dx, 0); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_add_glyph (cairo_glyph_state_t *state, + unsigned long index, + double device_x, + double device_y) +{ + double user_x = device_x; + double user_y = device_y; + WCHAR glyph_index = index; + int logical_x, logical_y; + + cairo_matrix_transform_point (&state->font->device_to_logical, &user_x, &user_y); + + logical_x = floor (user_x + 0.5); + logical_y = floor (user_y + 0.5); + + if (state->glyphs.num_elements > 0) { + int dx; + + if (logical_y != state->last_y) { + cairo_status_t status = _flush_glyphs (state); + if (!CAIRO_OK (status)) + return status; + state->start_x = logical_x; + } + + dx = logical_x - state->last_x; + if (!_cairo_array_append (&state->dx, &dx, 1)) + return CAIRO_STATUS_NO_MEMORY; + } else { + state->start_x = logical_x; + } + + state->last_x = logical_x; + state->last_y = logical_y; + + _cairo_array_append (&state->glyphs, &glyph_index, 1); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_finish_glyphs (cairo_glyph_state_t *state) +{ + _flush_glyphs (state); + + _cairo_array_fini (&state->glyphs); + _cairo_array_fini (&state->dx); +} + +static cairo_status_t +_draw_glyphs_on_surface (cairo_win32_surface_t *surface, + cairo_win32_font_t *font, + COLORREF color, + int x_offset, + int y_offset, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + cairo_glyph_state_t state; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + int i; + + if (!SaveDC (surface->dc)) + return _cairo_win32_print_gdi_error ("_draw_glyphs_on_surface:SaveDC"); + + status = cairo_win32_font_select_font (&font->base, surface->dc); + if (!CAIRO_OK (status)) + goto FAIL1; + + SetTextColor (surface->dc, color); + SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT); + SetBkMode (surface->dc, TRANSPARENT); + + _start_glyphs (&state, font, surface->dc); + + for (i = 0; i < num_glyphs; i++) { + status = _add_glyph (&state, glyphs[i].index, + glyphs[i].x - x_offset, glyphs[i].y - y_offset); + if (!CAIRO_OK (status)) + goto FAIL2; + } + + FAIL2: + _finish_glyphs (&state); + cairo_win32_font_done_font (&font->base); + FAIL1: + RestoreDC (surface->dc, 1); + + return status; +} + +/* Duplicate the green channel of a 4-channel mask in the alpha channel, then + * invert the whole mask. + */ +static void +_compute_argb32_mask_alpha (cairo_win32_surface_t *mask_surface) +{ + cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image; + int i, j; + + for (i = 0; i < image->height; i++) { + uint32_t *p = (uint32_t *) (image->data + i * image->stride); + for (j = 0; j < image->width; j++) { + *p = 0xffffffff ^ (*p | ((*p & 0x0000ff00) << 16)); + p++; + } + } +} + +/* Invert a mask + */ +static void +_invert_argb32_mask (cairo_win32_surface_t *mask_surface) +{ + cairo_image_surface_t *image = (cairo_image_surface_t *)mask_surface->image; + int i, j; + + for (i = 0; i < image->height; i++) { + uint32_t *p = (uint32_t *) (image->data + i * image->stride); + for (j = 0; j < image->width; j++) { + *p = 0xffffffff ^ *p; + p++; + } + } +} + +/* Compute an alpha-mask from a monochrome RGB24 image + */ +static cairo_surface_t * +_compute_a8_mask (cairo_win32_surface_t *mask_surface) +{ + cairo_image_surface_t *image24 = (cairo_image_surface_t *)mask_surface->image; + cairo_image_surface_t *image8; + int i, j; + + image8 = (cairo_image_surface_t *)cairo_image_surface_create (CAIRO_FORMAT_A8, + image24->width, image24->height); + if (!image8) + return NULL; + + for (i = 0; i < image24->height; i++) { + uint32_t *p = (uint32_t *) (image24->data + i * image24->stride); + unsigned char *q = (unsigned char *) (image8->data + i * image8->stride); + + for (j = 0; j < image24->width; j++) { + *q = 255 - ((*p & 0x0000ff00) >> 8); + p++; + q++; + } + } + + return &image8->base; +} + +static cairo_status_t +_cairo_win32_font_show_glyphs (void *abstract_font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *generic_surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + cairo_win32_font_t *font = abstract_font; + cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface; + cairo_status_t status; + + if (width == 0 || height == 0) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_surface_is_win32 (generic_surface) && + surface->format == CAIRO_FORMAT_RGB24 && + operator == CAIRO_OPERATOR_OVER && + pattern->type == CAIRO_PATTERN_SOLID && + _cairo_pattern_is_opaque (pattern)) { + + cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)pattern; + + /* When compositing OVER on a GDI-understood surface, with a + * solid opaque color, we can just call ExtTextOut directly. + */ + COLORREF new_color; + + new_color = RGB (((int)(0xffff * solid_pattern->red)) >> 8, + ((int)(0xffff * solid_pattern->green)) >> 8, + ((int)(0xffff * solid_pattern->blue)) >> 8); + + status = _draw_glyphs_on_surface (surface, font, new_color, + 0, 0, + glyphs, num_glyphs); + + return status; + } else { + /* Otherwise, we need to draw using software fallbacks. We create a mask + * surface by drawing the the glyphs onto a DIB, black-on-white then + * inverting. GDI outputs gamma-corrected images so inverted black-on-white + * is very different from white-on-black. We favor the more common + * case where the final output is dark-on-light. + */ + cairo_win32_surface_t *tmp_surface; + cairo_surface_t *mask_surface; + cairo_surface_pattern_t mask; + RECT r; + + tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height); + if (!tmp_surface) + return CAIRO_STATUS_NO_MEMORY; + + r.left = 0; + r.top = 0; + r.right = width; + r.bottom = height; + FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH)); + + _draw_glyphs_on_surface (tmp_surface, font, RGB (0, 0, 0), + dest_x, dest_y, + glyphs, num_glyphs); + + if (font->quality == CLEARTYPE_QUALITY) { + /* For ClearType, we need a 4-channel mask. If we are compositing on + * a surface with alpha, we need to compute the alpha channel of + * the mask (we just copy the green channel). But for a destination + * surface without alpha the alpha channel of the mask is ignored + */ + + if (surface->format != CAIRO_FORMAT_RGB24) + _compute_argb32_mask_alpha (tmp_surface); + else + _invert_argb32_mask (tmp_surface); + + mask_surface = &tmp_surface->base; + + /* XXX: Hacky, should expose this in cairo_image_surface */ + pixman_image_set_component_alpha (((cairo_image_surface_t *)tmp_surface->image)->pixman_image, TRUE); + + } else { + mask_surface = _compute_a8_mask (tmp_surface); + cairo_surface_destroy (&tmp_surface->base); + if (!mask_surface) + return CAIRO_STATUS_NO_MEMORY; + } + + /* For operator == OVER, no-cleartype, a possible optimization here is to + * draw onto an intermediate ARGB32 surface and alpha-blend that with the + * destination + */ + _cairo_pattern_init_for_surface (&mask, mask_surface); + + status = _cairo_surface_composite (operator, pattern, + &mask.base, + &surface->base, + source_x, source_y, + 0, 0, + dest_x, dest_y, + width, height); + + _cairo_pattern_fini (&mask.base); + + cairo_surface_destroy (mask_surface); + + return status; + } +} + +static cairo_status_t +_cairo_win32_font_glyph_path (void *abstract_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_font_create_glyph (cairo_image_glyph_cache_entry_t *val) +{ + return CAIRO_STATUS_NO_MEMORY; +} + +const cairo_font_backend_t cairo_win32_font_backend = { + _cairo_win32_font_create, + _cairo_win32_font_destroy_font, + _cairo_win32_font_destroy_unscaled_font, + _cairo_win32_font_font_extents, + _cairo_win32_font_text_to_glyphs, + _cairo_win32_font_glyph_extents, + _cairo_win32_font_glyph_bbox, + _cairo_win32_font_show_glyphs, + _cairo_win32_font_glyph_path, + _cairo_win32_font_get_glyph_cache_key, + _cairo_win32_font_create_glyph +}; + +/* implement the platform-specific interface */ + +/** + * cairo_win32_font_create_for_logfontw: + * @logfont: A #LOGFONTW structure specifying the font to use. + * The lfHeight, lfWidth, lfOrientation and lfEscapement + * fields of this structure are ignored; information from + * @scale will be used instead. + * @scale: The scale at which this font will be used. The + * scale is given by multiplying the font matrix (see + * cairo_transform_font()) by the current transformation matrix. + * The translation elements of the resulting matrix are ignored. + * + * Creates a new font for the Win32 font backend based on a + * #LOGFONT. This font can then be used with + * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend + * specific functions like cairo_win32_font_select_font(). + * + * Return value: a newly created #cairo_font_t. Free with + * cairo_font_destroy() when you are done using it. + **/ +cairo_font_t * +cairo_win32_font_create_for_logfontw (LOGFONTW *logfont, + cairo_matrix_t *scale) +{ + cairo_font_scale_t sc; + + cairo_matrix_get_affine (scale, + &sc.matrix[0][0], &sc.matrix[0][1], + &sc.matrix[1][0], &sc.matrix[1][1], + NULL, NULL); + + return _win32_font_create (logfont, &sc); +} + +/** + * cairo_win32_font_select_font: + * @font: A #cairo_font_t from the Win32 font backend. Such an + * object can be created with cairo_win32_font_create_for_logfontw(). + * @hdc: a device context + * + * Selects the font into the given device context and changes the + * map mode and world transformation of the device context to match + * that of the font. This function is intended for use when using + * layout APIs such as Uniscribe to do text layout with the + * Cairo font. After finishing using the device context, you must call + * cairo_win32_font_done_font() to release any resources allocated + * by this function. + * + * See cairo_win32_font_get_scale_factor() for converting logical + * coordinates from the device context to font space. + * + * Normally, calls to SaveDC() and RestoreDC() would be made around + * the use of this function to preserve the original graphics state. + * + * Return value: %CAIRO_STATUS_SUCCESS if the operation succeeded. + * otherwise an error such as %CAIRO_STATUS_NO_MEMORY and + * the device context is unchanged. + **/ +cairo_status_t +cairo_win32_font_select_font (cairo_font_t *font, + HDC hdc) +{ + cairo_status_t status; + HFONT hfont; + HFONT old_hfont = NULL; + int old_mode; + + hfont = _win32_font_get_scaled_font ((cairo_win32_font_t *)font); + if (!hfont) + return CAIRO_STATUS_NO_MEMORY; + + old_hfont = SelectObject (hdc, hfont); + if (!old_hfont) + return _cairo_win32_print_gdi_error ("cairo_win32_font_select_font"); + + old_mode = SetGraphicsMode (hdc, GM_ADVANCED); + if (!old_mode) { + status = _cairo_win32_print_gdi_error ("cairo_win32_font_select_font"); + SelectObject (hdc, old_hfont); + return status; + } + + status = _win32_font_set_world_transform ((cairo_win32_font_t *)font, hdc); + if (!CAIRO_OK (status)) { + SetGraphicsMode (hdc, old_mode); + SelectObject (hdc, old_hfont); + return status; + } + + SetMapMode (hdc, MM_TEXT); + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_win32_font_done_font: + * @font: A #cairo_font_t from the Win32 font backend. + * + * Releases any resources allocated by cairo_win32_font_select_font() + **/ +void +cairo_win32_font_done_font (cairo_font_t *font) +{ +} + +/** + * cairo_win32_font_get_scale_factor: + * @font: a #cairo_font_t from the Win32 font backend + * + * Gets a scale factor between logical coordinates in the coordinate + * space used by cairo_win32_font_select_font() and font space coordinates. + * + * Return value: factor to multiply logical units by to get font space + * coordinates. + **/ +double +cairo_win32_font_get_scale_factor (cairo_font_t *font) +{ + return 1. / ((cairo_win32_font_t *)font)->logical_scale; +} diff --git a/src/cairo_win32_surface.c b/src/cairo_win32_surface.c new file mode 100644 index 000000000..dcfe6d044 --- /dev/null +++ b/src/cairo_win32_surface.c @@ -0,0 +1,931 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor <otaylor@redhat.com> + */ + +#include <stdio.h> + +#include "cairo-win32-private.h" + +static const cairo_surface_backend_t cairo_win32_surface_backend; + +/** + * _cairo_win32_print_gdi_error: + * @context: context string to display along with the error + * + * Helper function to dump out a human readable form of the + * current error code. + * + * Return value: A Cairo status code for the error code + **/ +cairo_status_t +_cairo_win32_print_gdi_error (const char *context) +{ + void *lpMsgBuf; + DWORD last_error = GetLastError (); + + if (!FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + last_error, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL)) { + fprintf (stderr, "%s: Unknown GDI error", context); + } else { + fprintf (stderr, "%s: %s", context, (char *)lpMsgBuf); + + LocalFree (lpMsgBuf); + } + + /* We should switch off of last_status, but we'd either return + * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there + * is no CAIRO_STATUS_UNKNOWN_ERROR. + */ + + return CAIRO_STATUS_NO_MEMORY; +} + +void +cairo_set_target_win32 (cairo_t *cr, + HDC hdc) +{ + cairo_surface_t *surface; + + if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE) + return; + + surface = cairo_win32_surface_create (hdc); + if (surface == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + cairo_set_target_surface (cr, surface); + + /* cairo_set_target_surface takes a reference, so we must destroy ours */ + cairo_surface_destroy (surface); +} + +static cairo_status_t +_create_dc_and_bitmap (cairo_win32_surface_t *surface, + HDC original_dc, + cairo_format_t format, + int width, + int height, + char **bits_out, + int *rowstride_out) +{ + cairo_status_t status; + + BITMAPINFO *bitmap_info = NULL; + struct { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[2]; + } bmi_stack; + void *bits; + + int num_palette = 0; /* Quiet GCC */ + int i; + + surface->dc = NULL; + surface->bitmap = NULL; + + switch (format) { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + num_palette = 0; + break; + + case CAIRO_FORMAT_A8: + num_palette = 256; + break; + + case CAIRO_FORMAT_A1: + num_palette = 2; + break; + } + + if (num_palette > 2) { + bitmap_info = malloc (sizeof (BITMAPINFOHEADER) + num_palette * sizeof (RGBQUAD)); + if (!bitmap_info) + return CAIRO_STATUS_NO_MEMORY; + } else { + bitmap_info = (BITMAPINFO *)&bmi_stack; + } + + bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bitmap_info->bmiHeader.biWidth = width; + bitmap_info->bmiHeader.biHeight = - height; /* top-down */ + bitmap_info->bmiHeader.biSizeImage = 0; + bitmap_info->bmiHeader.biXPelsPerMeter = 72. / 0.0254; /* unused here */ + bitmap_info->bmiHeader.biYPelsPerMeter = 72. / 0.0254; /* unused here */ + bitmap_info->bmiHeader.biPlanes = 1; + + switch (format) { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + bitmap_info->bmiHeader.biBitCount = 32; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 0; /* unused */ + bitmap_info->bmiHeader.biClrImportant = 0; + break; + + case CAIRO_FORMAT_A8: + bitmap_info->bmiHeader.biBitCount = 8; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 256; + bitmap_info->bmiHeader.biClrImportant = 0; + + for (i = 0; i < 256; i++) { + bitmap_info->bmiColors[i].rgbBlue = i; + bitmap_info->bmiColors[i].rgbGreen = i; + bitmap_info->bmiColors[i].rgbRed = i; + bitmap_info->bmiColors[i].rgbReserved = 0; + } + + break; + + case CAIRO_FORMAT_A1: + bitmap_info->bmiHeader.biBitCount = 1; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 2; + bitmap_info->bmiHeader.biClrImportant = 0; + + for (i = 0; i < 2; i++) { + bitmap_info->bmiColors[i].rgbBlue = i * 255; + bitmap_info->bmiColors[i].rgbGreen = i * 255; + bitmap_info->bmiColors[i].rgbRed = i * 255; + bitmap_info->bmiColors[i].rgbReserved = 0; + break; + } + } + + surface->dc = CreateCompatibleDC (original_dc); + if (!surface->dc) + goto FAIL; + + surface->bitmap = CreateDIBSection (surface->dc, + bitmap_info, + DIB_RGB_COLORS, + &bits, + NULL, 0); + if (!surface->bitmap) + goto FAIL; + + surface->saved_dc_bitmap = SelectObject (surface->dc, + surface->bitmap); + if (!surface->saved_dc_bitmap) + goto FAIL; + + if (bitmap_info && num_palette > 2) + free (bitmap_info); + + if (bits_out) + *bits_out = bits; + + if (rowstride_out) { + /* Windows bitmaps are padded to 16-bit (word) boundaries */ + switch (format) { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + *rowstride_out = 4 * width; + break; + + case CAIRO_FORMAT_A8: + *rowstride_out = (width + 1) & -2; + break; + + case CAIRO_FORMAT_A1: + *rowstride_out = ((width + 15) & -16) / 8; + break; + } + } + + return CAIRO_STATUS_SUCCESS; + + FAIL: + status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap"); + + if (bitmap_info && num_palette > 2) + free (bitmap_info); + + if (surface->saved_dc_bitmap) { + SelectObject (surface->dc, surface->saved_dc_bitmap); + surface->saved_dc_bitmap = NULL; + } + + if (surface->bitmap) { + DeleteObject (surface->bitmap); + surface->bitmap = NULL; + } + + if (surface->dc) { + DeleteDC (surface->dc); + surface->dc = NULL; + } + + return status; +} + +static cairo_surface_t * +_cairo_win32_surface_create_for_dc (HDC original_dc, + cairo_format_t format, + int drawable, + int width, + int height) +{ + cairo_win32_surface_t *surface; + char *bits; + int rowstride; + + surface = malloc (sizeof (cairo_win32_surface_t)); + if (!surface) + return NULL; + + if (_create_dc_and_bitmap (surface, original_dc, format, + width, height, + &bits, &rowstride) != CAIRO_STATUS_SUCCESS) + goto FAIL; + + surface->image = cairo_image_surface_create_for_data (bits, format, + width, height, rowstride); + if (!surface->image) + goto FAIL; + + surface->format = format; + + surface->clip_rect.x = 0; + surface->clip_rect.y = 0; + surface->clip_rect.width = width; + surface->clip_rect.height = height; + + surface->set_clip = 0; + surface->saved_clip = NULL; + + _cairo_surface_init (&surface->base, &cairo_win32_surface_backend); + + return (cairo_surface_t *)surface; + + FAIL: + if (surface->bitmap) { + SelectObject (surface->dc, surface->saved_dc_bitmap); + DeleteObject (surface->bitmap); + DeleteDC (surface->dc); + } + if (surface) + free (surface); + + return NULL; + +} + +static cairo_surface_t * +_cairo_win32_surface_create_similar (void *abstract_src, + cairo_format_t format, + int drawable, + int width, + int height) +{ + cairo_win32_surface_t *src = abstract_src; + + return _cairo_win32_surface_create_for_dc (src->dc, format, drawable, + width, height); +} + +/** + * _cairo_win32_surface_create_dib: + * @format: format of pixels in the surface to create + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates a device-independent-bitmap surface not associated with + * any particular existing surface or device context. The created + * bitmap will be unititialized. + * + * Return value: the newly created surface, or %NULL if it couldn't + * be created (probably because of lack of memory) + **/ +cairo_surface_t * +_cairo_win32_surface_create_dib (cairo_format_t format, + int width, + int height) +{ + return _cairo_win32_surface_create_for_dc (NULL, format, TRUE, + width, height); +} + +static void +_cairo_win32_surface_destroy (void *abstract_surface) +{ + cairo_win32_surface_t *surface = abstract_surface; + + if (surface->image) + cairo_surface_destroy (surface->image); + + if (surface->saved_clip) + DeleteObject (surface->saved_clip); + + /* If we created the Bitmap and DC, destroy them */ + if (surface->bitmap) { + SelectObject (surface->dc, surface->saved_dc_bitmap); + DeleteObject (surface->bitmap); + DeleteDC (surface->dc); + } + + free (surface); +} + +static double +_cairo_win32_surface_pixels_per_inch (void *abstract_surface) +{ + /* XXX: We should really get this value from somewhere */ + return 96.0; +} + +static cairo_status_t +_cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface, + int x, + int y, + int width, + int height, + cairo_win32_surface_t **local_out) +{ + cairo_win32_surface_t *local; + cairo_status_t status; + + local = + (cairo_win32_surface_t *) _cairo_win32_surface_create_similar (surface, + surface->format, + 0, + width, height); + if (!local) + return CAIRO_STATUS_NO_MEMORY; + + if (!BitBlt (local->dc, + 0, 0, + width, height, + surface->dc, + x, y, + SRCCOPY)) + goto FAIL; + + *local_out = local; + + return CAIRO_STATUS_SUCCESS; + + FAIL: + status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_get_subimage"); + + if (local) + cairo_surface_destroy (&local->base); + + return status; +} + +static cairo_status_t +_cairo_win32_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_surface_t *local = NULL; + cairo_status_t status; + + if (surface->image) { + *image_out = (cairo_image_surface_t *)surface->image; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; + } + + status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0, + surface->clip_rect.width, + surface->clip_rect.height, &local); + if (CAIRO_OK (status)) { + cairo_surface_set_filter (&local->base, surface->base.filter); + cairo_surface_set_matrix (&local->base, &surface->base.matrix); + cairo_surface_set_repeat (&local->base, surface->base.repeat); + + *image_out = (cairo_image_surface_t *)local->image; + *image_extra = local; + } + + return status; +} + +static void +_cairo_win32_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_win32_surface_t *local = image_extra; + + if (local) + cairo_surface_destroy ((cairo_surface_t *)local); +} + +static cairo_status_t +_cairo_win32_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_surface_t *local = NULL; + cairo_status_t status; + RECT clip_box; + int x1, y1, x2, y2; + + if (surface->image) { + image_rect->x = 0; + image_rect->y = 0; + image_rect->width = surface->clip_rect.width; + image_rect->height = surface->clip_rect.height; + + *image_out = (cairo_image_surface_t *)surface->image; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; + } + + if (GetClipBox (surface->dc, &clip_box) == ERROR) + return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image"); + + x1 = clip_box.left; + x2 = clip_box.right; + y1 = clip_box.top; + y2 = clip_box.bottom; + + if (interest_rect->x > x1) + x1 = interest_rect->x; + if (interest_rect->y > y1) + y1 = interest_rect->y; + if (interest_rect->x + interest_rect->width < x2) + x2 = interest_rect->x + interest_rect->width; + if (interest_rect->y + interest_rect->height < y2) + y2 = interest_rect->y + interest_rect->height; + + if (x1 >= x2 || y1 >= y2) { + *image_out = NULL; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; + } + + status = _cairo_win32_surface_get_subimage (abstract_surface, + x1, y1, x2 - x1, y2 - y1, + &local); + if (CAIRO_OK (status)) { + *image_out = (cairo_image_surface_t *)local->image; + *image_extra = local; + + image_rect->x = x1; + image_rect->y = y1; + image_rect->width = x2 - x1; + image_rect->height = y2 - y1; + } + + return status; +} + +static void +_cairo_win32_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_win32_surface_t *local = image_extra; + + if (!local) + return; + + if (!BitBlt (surface->dc, + image_rect->x, image_rect->y, + image_rect->width, image_rect->height, + local->dc, + 0, 0, + SRCCOPY)) + _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image"); + + cairo_surface_destroy ((cairo_surface_t *)local); +} + +static cairo_status_t +_cairo_win32_surface_clone_similar (void *surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_composite (cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_pattern_t *mask_pattern, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_win32_surface_t *dst = abstract_dst; + cairo_win32_surface_t *src; + cairo_surface_pattern_t *src_surface_pattern; + int alpha; + int integer_transform; + int itx, ity; + + if (pattern->type != CAIRO_PATTERN_SURFACE || + pattern->extend != CAIRO_EXTEND_NONE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (mask_pattern) { + /* FIXME: When we fully support RENDER style 4-channel + * masks we need to check r/g/b != 1.0. + */ + if (mask_pattern->type != CAIRO_PATTERN_SOLID) + return CAIRO_INT_STATUS_UNSUPPORTED; + + alpha = (int)(0xffff * pattern->alpha * mask_pattern->alpha) >> 8; + } else { + alpha = (int)(0xffff * pattern->alpha) >> 8; + } + + src_surface_pattern = (cairo_surface_pattern_t *)pattern; + src = (cairo_win32_surface_t *)src_surface_pattern->surface; + + if (src->base.backend != dst->base.backend) + return CAIRO_INT_STATUS_UNSUPPORTED; + + integer_transform = _cairo_matrix_is_integer_translation (&pattern->matrix, &itx, &ity); + if (!integer_transform) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (alpha == 255 && + src->format == dst->format && + (operator == CAIRO_OPERATOR_SRC || + (src->format == CAIRO_FORMAT_RGB24 && operator == CAIRO_OPERATOR_OVER))) { + + if (!BitBlt (dst->dc, + dst_x, dst_y, + width, height, + src->dc, + src_x + itx, src_y + ity, + SRCCOPY)) + return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite"); + + return CAIRO_STATUS_SUCCESS; + + } else if (integer_transform && + (src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) && + dst->format == CAIRO_FORMAT_RGB24 && + !src->base.repeat && + operator == CAIRO_OPERATOR_OVER) { + + BLENDFUNCTION blend_function; + + blend_function.BlendOp = AC_SRC_OVER; + blend_function.BlendFlags = 0; + blend_function.SourceConstantAlpha = alpha; + blend_function.AlphaFormat = src->format == CAIRO_FORMAT_ARGB32 ? AC_SRC_ALPHA : 0; + + if (!AlphaBlend (dst->dc, + dst_x, dst_y, + width, height, + src->dc, + src_x + itx, src_y + ity, + width, height, + blend_function)) + return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite"); + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_fill_rectangles (void *abstract_surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_status_t status; + COLORREF new_color; + HBRUSH new_brush; + int i; + + /* If we have a local image, use the fallback code; it will be as fast + * as calling out to GDI. + */ + if (surface->image) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* We could support possibly support more operators for color->alpha = 0xffff. + * for CAIRO_OPERATOR_SRC, alpha doesn't matter since we know the destination + * image doesn't have alpha. (surface->pixman_image is non-NULL for all + * surfaces with alpha.) + */ + if (operator != CAIRO_OPERATOR_SRC) + return CAIRO_INT_STATUS_UNSUPPORTED; + + new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8); + + new_brush = CreateSolidBrush (new_color); + if (!new_brush) + return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles"); + + for (i = 0; i < num_rects; i++) { + RECT rect; + + rect.left = rects[i].x; + rect.top = rects[i].y; + rect.right = rects[i].x + rects[i].width; + rect.bottom = rects[i].y + rects[i].height; + + if (!FillRect (surface->dc, &rect, new_brush)) + goto FAIL; + } + + DeleteObject (new_brush); + + return CAIRO_STATUS_SUCCESS; + + FAIL: + status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles"); + + DeleteObject (new_brush); + + return status; +} + +static cairo_int_status_t +_cairo_win32_surface_composite_trapezoids (cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_dst, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, + cairo_trapezoid_t *traps, + int num_traps) + +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_copy_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + cairo_win32_surface_t *surface = abstract_surface; + cairo_status_t status; + + /* If we are in-memory, then we set the clip on the image surface + * as well as on the underlying GDI surface. + */ + if (surface->image) + _cairo_surface_set_clip_region (surface->image, region); + + /* The semantics we want is that any clip set by Cairo combines + * is intersected with the clip on device context that the + * surface was created for. To implement this, we need to + * save the original clip when first setting a clip on surface. + */ + + if (region == NULL) { + /* Clear any clip set by Cairo, return to the original */ + + if (surface->set_clip) { + if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR) + return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region"); + + if (surface->saved_clip) { + DeleteObject (surface->saved_clip); + surface->saved_clip = NULL; + } + + surface->set_clip = 0; + } + + + return CAIRO_STATUS_SUCCESS; + + } else { + pixman_box16_t *boxes = pixman_region_rects (region); + int num_boxes = pixman_region_num_rects (region); + pixman_box16_t *extents = pixman_region_extents (region); + RGNDATA *data; + size_t data_size; + RECT *rects; + int i; + HRGN gdi_region; + + /* Create a GDI region for the cairo region */ + + data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT); + data = malloc (data_size); + if (!data) + return CAIRO_STATUS_NO_MEMORY; + rects = (RECT *)data->Buffer; + + data->rdh.dwSize = sizeof (RGNDATAHEADER); + data->rdh.iType = RDH_RECTANGLES; + data->rdh.nCount = num_boxes; + data->rdh.nRgnSize = num_boxes * sizeof (RECT); + data->rdh.rcBound.left = extents->x1; + data->rdh.rcBound.top = extents->y1; + data->rdh.rcBound.right = extents->x2; + data->rdh.rcBound.bottom = extents->y2; + + for (i = 0; i < num_boxes; i++) { + rects[i].left = boxes[i].x1; + rects[i].top = boxes[i].y1; + rects[i].right = boxes[i].x2; + rects[i].bottom = boxes[i].y2; + } + + gdi_region = ExtCreateRegion (NULL, data_size, data); + free (data); + + if (!gdi_region) + return CAIRO_STATUS_NO_MEMORY; + + if (surface->set_clip) { + /* Combine the new region with the original clip */ + + if (surface->saved_clip) { + if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR) + goto FAIL; + } + + if (SelectClipRgn (surface->dc, gdi_region) == ERROR) + goto FAIL; + + } else { + /* Save the the current region */ + + surface->saved_clip = CreateRectRgn (0, 0, 0, 0); + if (!surface->saved_clip) { + goto FAIL; } + + /* This function has no error return! */ + if (GetClipRgn (surface->dc, surface->saved_clip) == 0) { /* No clip */ + DeleteObject (surface->saved_clip); + surface->saved_clip = NULL; + } + + if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR) + goto FAIL; + + surface->set_clip = 1; + } + + DeleteObject (gdi_region); + return CAIRO_STATUS_SUCCESS; + + FAIL: + status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region"); + DeleteObject (gdi_region); + return status; + } +} + +static cairo_status_t +_cairo_win32_surface_show_glyphs (cairo_font_t *font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + void *abstract_surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +cairo_surface_t * +cairo_win32_surface_create (HDC hdc) +{ + cairo_win32_surface_t *surface; + RECT rect; + + /* Try to figure out the drawing bounds for the Device context + */ + if (GetClipBox (hdc, &rect) == ERROR) { + _cairo_win32_print_gdi_error ("cairo_win32_surface_create"); + return NULL; + } + + surface = malloc (sizeof (cairo_win32_surface_t)); + if (!surface) + return NULL; + + surface->image = NULL; + surface->format = CAIRO_FORMAT_RGB24; + + surface->dc = hdc; + surface->bitmap = NULL; + + surface->clip_rect.x = rect.left; + surface->clip_rect.y = rect.top; + surface->clip_rect.width = rect.right - rect.left; + surface->clip_rect.height = rect.bottom - rect.top; + + surface->set_clip = 0; + surface->saved_clip = NULL; + + _cairo_surface_init (&surface->base, &cairo_win32_surface_backend); + + return (cairo_surface_t *)surface; +} + +/** + * _cairo_surface_is_win32: + * @surface: a #cairo_surface_t + * + * Checks if a surface is an #cairo_win32_surface_t + * + * Return value: True if the surface is an win32 surface + **/ +int +_cairo_surface_is_win32 (cairo_surface_t *surface) +{ + return surface->backend == &cairo_win32_surface_backend; +} + +static const cairo_surface_backend_t cairo_win32_surface_backend = { + _cairo_win32_surface_create_similar, + _cairo_win32_surface_destroy, + _cairo_win32_surface_pixels_per_inch, + _cairo_win32_surface_acquire_source_image, + _cairo_win32_surface_release_source_image, + _cairo_win32_surface_acquire_dest_image, + _cairo_win32_surface_release_dest_image, + _cairo_win32_surface_clone_similar, + _cairo_win32_surface_composite, + _cairo_win32_surface_fill_rectangles, + _cairo_win32_surface_composite_trapezoids, + _cairo_win32_surface_copy_page, + _cairo_win32_surface_show_page, + _cairo_win32_surface_set_clip_region, + _cairo_win32_surface_show_glyphs +}; diff --git a/src/cairo_xcb_surface.c b/src/cairo_xcb_surface.c index 758cf26de..0694b77a2 100644 --- a/src/cairo_xcb_surface.c +++ b/src/cairo_xcb_surface.c @@ -31,10 +31,11 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" +#include "cairo-xcb.h" cairo_surface_t * cairo_xcb_surface_create (XCBConnection *dpy, @@ -327,14 +328,17 @@ bytes_per_line(XCBConnection *c, int width, int bpp) return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3; } -static cairo_image_surface_t * -_cairo_xcb_surface_get_image (void *abstract_surface) +static cairo_status_t +_get_image_surface (cairo_xcb_surface_t *surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect) { - cairo_xcb_surface_t *surface = abstract_surface; cairo_image_surface_t *image; XCBGetGeometryRep *geomrep; XCBGetImageRep *imagerep; int bpp; + int x1, y1, x2, y2; geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0); if(!geomrep) @@ -344,11 +348,39 @@ _cairo_xcb_surface_get_image (void *abstract_surface) surface->height = geomrep->height; free(geomrep); + x1 = 0; + y1 = 0; + x2 = surface->width; + y2 = surface->height; + + if (interest_rect) { + if (interest_rect->x > x1) + x1 = interest_rect->x; + if (interest_rect->y > y1) + y1 = interest_rect->y; + if (interest_rect->x + interest_rect->width < x2) + x2 = interest_rect->x + interest_rect->width; + if (interest_rect->y + interest_rect->height < y2) + y2 = interest_rect->y + interest_rect->height; + + if (x1 >= x2 || y1 >= y2) { + *image_out = NULL; + return CAIRO_STATUS_SUCCESS; + } + } + + if (image_rect) { + image_rect->x = x1; + image_rect->y = y1; + image_rect->width = x2 - x1; + image_rect->height = y2 - y1; + } + imagerep = XCBGetImageReply(surface->dpy, XCBGetImage(surface->dpy, ZPixmap, surface->drawable, - 0, 0, - surface->width, surface->height, + x1, y1, + x2 - x1, y2 - y1, AllPlanes), 0); if(!imagerep) return 0; @@ -368,15 +400,15 @@ _cairo_xcb_surface_get_image (void *abstract_surface) image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep), &masks, - surface->width, - surface->height, + x2 - x1, + y2 - y1, bytes_per_line(surface->dpy, surface->width, bpp)); } else { image = (cairo_image_surface_t *) cairo_image_surface_create_for_data (XCBGetImageData(imagerep), surface->format, - surface->width, - surface->height, + x2 - x1, + y2 - y1, bytes_per_line(surface->dpy, surface->width, bpp)); } @@ -388,7 +420,8 @@ _cairo_xcb_surface_get_image (void *abstract_surface) _cairo_image_surface_set_repeat (image, surface->base.repeat); _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - return image; + *image_out = image; + return CAIRO_STATUS_SUCCESS; } static void @@ -402,10 +435,11 @@ _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface) } static cairo_status_t -_cairo_xcb_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +_draw_image_surface (cairo_xcb_surface_t *surface, + cairo_image_surface_t *image, + int dst_x, + int dst_y) { - cairo_xcb_surface_t *surface = abstract_surface; int bpp, data_len; _cairo_xcb_surface_ensure_gc (surface); @@ -414,7 +448,7 @@ _cairo_xcb_surface_set_image (void *abstract_surface, XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc, image->width, image->height, - /* dst_x */ 0, /* dst_y */ 0, + dst_x, dst_y, /* left_pad */ 0, image->depth, data_len, image->data); @@ -422,9 +456,107 @@ _cairo_xcb_surface_set_image (void *abstract_surface, } static cairo_status_t -_cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) +_cairo_xcb_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; + + status = _get_image_surface (surface, NULL, &image, NULL); + if (status == CAIRO_STATUS_SUCCESS) { + cairo_surface_set_filter (&image->base, surface->base.filter); + cairo_surface_set_matrix (&image->base, &surface->base.matrix); + cairo_surface_set_repeat (&image->base, surface->base.repeat); + + *image_out = image; + } + + return status; +} + +static void +_cairo_xcb_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); +} + +static cairo_status_t +_cairo_xcb_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect_out, + void **image_extra) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; + + status = _get_image_surface (surface, interest_rect, &image, image_rect_out); + if (status == CAIRO_STATUS_SUCCESS) + *image_out = image; + + return status; +} + +static void +_cairo_xcb_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + cairo_xcb_surface_t *surface = abstract_surface; + + /* ignore errors */ + _draw_image_surface (surface, image, image_rect->x, image_rect->y); + + cairo_surface_destroy (&image->base); +} + +static cairo_status_t +_cairo_xcb_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { cairo_xcb_surface_t *surface = abstract_surface; + cairo_xcb_surface_t *clone; + + if (src->backend == surface->base.backend ) { + cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src; + + if (xcb_src->dpy == surface->dpy) { + *clone_out = src; + cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; + } + } else if (_cairo_surface_is_image (src)) { + cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; + + clone = (cairo_xcb_surface_t *) + _cairo_xcb_surface_create_similar (surface, image_src->format, 0, + image_src->width, image_src->height); + if (clone == NULL) + return CAIRO_STATUS_NO_MEMORY; + + _draw_image_surface (clone, image_src, 0, 0); + + *clone_out = &clone->base; + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface, + cairo_matrix_t *matrix) +{ XCBRenderTRANSFORM xtransform; if (!surface->picture.xid) @@ -442,27 +574,42 @@ _cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) xtransform.matrix32 = 0; xtransform.matrix33 = _cairo_fixed_from_double (1); - if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) + if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) { - XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform); - } else { - /* XXX: Need support here if using an old RENDER without support - for SetPictureTransform */ + static const XCBRenderTRANSFORM identity = { + 1 << 16, 0x00000, 0x00000, + 0x00000, 1 << 16, 0x00000, + 0x00000, 0x00000, 1 << 16 + }; + + if (memcmp (&xtransform, &identity, sizeof (XCBRenderTRANSFORM)) == 0) + return CAIRO_STATUS_SUCCESS; + + return CAIRO_INT_STATUS_UNSUPPORTED; } + + XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform); return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface, + cairo_filter_t filter) { - cairo_xcb_surface_t *surface = abstract_surface; char *render_filter; - if (!(surface->picture.xid - && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface))) + if (!surface->picture.xid) return CAIRO_STATUS_SUCCESS; - + + if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) + { + if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) + return CAIRO_STATUS_SUCCESS; + + return CAIRO_INT_STATUS_UNSUPPORTED; + } + switch (filter) { case CAIRO_FILTER_FAST: render_filter = "fast"; @@ -491,10 +638,8 @@ _cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter) } static cairo_status_t -_cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat) +_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat) { - cairo_xcb_surface_t *surface = abstract_surface; - CARD32 mask = XCBRenderCPRepeat; CARD32 pa[] = { repeat }; @@ -506,33 +651,32 @@ _cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat) return CAIRO_STATUS_SUCCESS; } -static cairo_xcb_surface_t * -_cairo_xcb_surface_clone_similar (cairo_surface_t *src, - cairo_xcb_surface_t *template, - cairo_format_t format, - int depth) +static cairo_int_status_t +_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface, + cairo_surface_attributes_t *attributes) { - cairo_xcb_surface_t *clone; - cairo_image_surface_t *src_image; - - src_image = _cairo_surface_get_image (src); - - clone = (cairo_xcb_surface_t *) - _cairo_xcb_surface_create_similar (template, format, 0, - src_image->width, - src_image->height); - if (clone == NULL) - return NULL; - - _cairo_xcb_surface_set_filter (clone, cairo_surface_get_filter(src)); - - _cairo_xcb_surface_set_image (clone, src_image); + cairo_int_status_t status; - _cairo_xcb_surface_set_matrix (clone, &(src_image->base.matrix)); + status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix); + if (status) + return status; + + switch (attributes->extend) { + case CAIRO_EXTEND_NONE: + _cairo_xcb_surface_set_repeat (surface, 0); + break; + case CAIRO_EXTEND_REPEAT: + _cairo_xcb_surface_set_repeat (surface, 1); + break; + case CAIRO_EXTEND_REFLECT: + return CAIRO_INT_STATUS_UNSUPPORTED; + } - cairo_surface_destroy (&src_image->base); + status = _cairo_xcb_surface_set_filter (surface, attributes->filter); + if (status) + return status; - return clone; + return CAIRO_STATUS_SUCCESS; } static int @@ -574,65 +718,80 @@ _render_operator (cairo_operator_t operator) static cairo_int_status_t _cairo_xcb_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, - void *abstract_dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height) + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) { - cairo_xcb_surface_t *dst = abstract_dst; - cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src; - cairo_xcb_surface_t *mask = (cairo_xcb_surface_t *) generic_mask; - cairo_xcb_surface_t *src_clone = NULL; - cairo_xcb_surface_t *mask_clone = NULL; - XCBRenderPICTURE maskpict = { 0 }; - + cairo_surface_attributes_t src_attr, mask_attr; + cairo_xcb_surface_t *dst = abstract_dst; + cairo_xcb_surface_t *src; + cairo_xcb_surface_t *mask; + cairo_int_status_t status; if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; - if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { - src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst, - CAIRO_FORMAT_ARGB32, 32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - src = src_clone; - } - if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) { - mask_clone = _cairo_xcb_surface_clone_similar (generic_mask, dst, - CAIRO_FORMAT_A8, 8); - if (!mask_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - mask = mask_clone; + status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern, + &dst->base, + src_x, src_y, + mask_x, mask_y, + width, height, + (cairo_surface_t **) &src, + (cairo_surface_t **) &mask, + &src_attr, &mask_attr); + if (status) + return status; + + status = _cairo_xcb_surface_set_attributes (src, &src_attr); + if (CAIRO_OK (status)) + { + if (mask) + { + status = _cairo_xcb_surface_set_attributes (mask, &mask_attr); + if (CAIRO_OK (status)) + XCBRenderComposite (dst->dpy, + _render_operator (operator), + src->picture, + mask->picture, + dst->picture, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + mask_x + mask_attr.x_offset, + mask_y + mask_attr.y_offset, + dst_x, dst_y, + width, height); + } + else + { + static XCBRenderPICTURE maskpict = { 0 }; + + XCBRenderComposite (dst->dpy, + _render_operator (operator), + src->picture, + maskpict, + dst->picture, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + } } - if(mask) - maskpict = mask->picture; - - XCBRenderComposite (dst->dpy, - _render_operator (operator), - src->picture, - maskpict, - dst->picture, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); - - /* XXX: This is messed up. If I can xcb_surface_create, then I - should be able to xcb_surface_destroy. */ - if (src_clone) - cairo_surface_destroy (&src_clone->base); - if (mask_clone) - cairo_surface_destroy (&mask_clone->base); + if (mask) + _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr); + + _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr); - return CAIRO_STATUS_SUCCESS; + return status; } static cairo_int_status_t @@ -664,42 +823,60 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface, static cairo_int_status_t _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, - void *abstract_dst, - int xSrc, - int ySrc, - cairo_trapezoid_t *traps, - int num_traps) + cairo_pattern_t *pattern, + void *abstract_dst, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, + cairo_trapezoid_t *traps, + int num_traps) { - cairo_xcb_surface_t *dst = abstract_dst; - cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src; - cairo_xcb_surface_t *src_clone = NULL; + cairo_surface_attributes_t attributes; + cairo_xcb_surface_t *dst = abstract_dst; + cairo_xcb_surface_t *src; + cairo_int_status_t status; + int render_reference_x, render_reference_y; + int render_src_x, render_src_y; if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; - - if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { - src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst, - CAIRO_FORMAT_ARGB32, 32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - src = src_clone; + + status = _cairo_pattern_acquire_surface (pattern, &dst->base, + src_x, src_y, width, height, + (cairo_surface_t **) &src, + &attributes); + if (status) + return status; + + if (traps[0].left.p1.y < traps[0].left.p2.y) { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y); + } else { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y); } - /* XXX: The XCBRenderTRAP cast is evil and needs to go away somehow. */ - /* XXX: format_from_cairo is slow. should cache something. */ - XCBRenderTrapezoids (dst->dpy, - _render_operator (operator), - src->picture, dst->picture, - format_from_cairo (dst->dpy, CAIRO_FORMAT_A8), - xSrc, ySrc, num_traps, (XCBRenderTRAP *) traps); - - /* XXX: This is messed up. If I can xcb_surface_create, then I - should be able to xcb_surface_destroy. */ - if (src_clone) - cairo_surface_destroy (&src_clone->base); + render_src_x = src_x + render_reference_x - dst_x; + render_src_y = src_y + render_reference_y - dst_y; - return CAIRO_STATUS_SUCCESS; + /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ + /* XXX: format_from_cairo is slow. should cache something. */ + status = _cairo_xcb_surface_set_attributes (src, &attributes); + if (CAIRO_OK (status)) + XCBRenderTrapezoids (dst->dpy, + _render_operator (operator), + src->picture, dst->picture, + format_from_cairo (dst->dpy, CAIRO_FORMAT_A8), + render_src_x + attributes.x_offset, + render_src_y + attributes.y_offset, + num_traps, (XCBRenderTRAP *) traps); + + _cairo_pattern_release_surface (&dst->base, &src->base, &attributes); + + return status; } static cairo_int_status_t @@ -722,30 +899,21 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface, return CAIRO_INT_STATUS_UNSUPPORTED; } -static cairo_int_status_t -_cairo_xcb_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *extents) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - static const cairo_surface_backend_t cairo_xcb_surface_backend = { _cairo_xcb_surface_create_similar, _cairo_xcb_surface_destroy, _cairo_xcb_surface_pixels_per_inch, - _cairo_xcb_surface_get_image, - _cairo_xcb_surface_set_image, - _cairo_xcb_surface_set_matrix, - _cairo_xcb_surface_set_filter, - _cairo_xcb_surface_set_repeat, + _cairo_xcb_surface_acquire_source_image, + _cairo_xcb_surface_release_source_image, + _cairo_xcb_surface_acquire_dest_image, + _cairo_xcb_surface_release_dest_image, + _cairo_xcb_surface_clone_similar, _cairo_xcb_surface_composite, _cairo_xcb_surface_fill_rectangles, _cairo_xcb_surface_composite_trapezoids, _cairo_xcb_surface_copy_page, _cairo_xcb_surface_show_page, _cairo_xcb_surface_set_clip_region, - _cairo_xcb_surface_create_pattern, NULL /* show_glyphs */ }; diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c index d9d74f583..3eaef57e5 100644 --- a/src/cairo_xlib_surface.c +++ b/src/cairo_xlib_surface.c @@ -31,12 +31,28 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ #include "cairoint.h" #include "cairo-xlib.h" +/** + * cairo_set_target_drawable: + * @cr: a #cairo_t + * @dpy: an X display + * @drawable: a window or pixmap on the default screen of @dpy + * + * Directs output for a #cairo_t to an Xlib drawable. @drawable must + * be a Window or Pixmap on the default screen of @dpy using the + * default colormap and visual. Using this function is slow because + * the function must retrieve information about @drawable from the X + * server. + + * The combination of cairo_xlib_surface_create() and + * cairo_set_target_surface() is somewhat more flexible, although + * it still is slow. + **/ void cairo_set_target_drawable (cairo_t *cr, Display *dpy, @@ -87,6 +103,8 @@ typedef struct _cairo_xlib_surface { #define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) +#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) + #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1) #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1) @@ -141,18 +159,13 @@ _cairo_xlib_surface_create_similar (void *abstract_src, Pixmap pix; cairo_xlib_surface_t *surface; - /* XXX: There's a pretty lame heuristic here. This assumes that - * all non-Render X servers do not support depth-32 pixmaps, (and - * that they do support depths 1, 8, and 24). Obviously, it would - * be much better to check the depths that are actually - * supported. */ - if (!dpy - || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src) - && format == CAIRO_FORMAT_ARGB32)) - { - return NULL; + /* As a good first approximation, if the display doesn't have COMPOSITE, + * we're better off using image surfaces for all temporary operations + */ + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE(src)) { + return cairo_image_surface_create (format, width, height); } - + scr = DefaultScreen (dpy); pix = XCreatePixmap (dpy, DefaultRootWindow (dpy), @@ -196,15 +209,17 @@ _cairo_xlib_surface_pixels_per_inch (void *abstract_surface) return 96.0; } -static cairo_image_surface_t * -_cairo_xlib_surface_get_image (void *abstract_surface) +static cairo_status_t +_get_image_surface (cairo_xlib_surface_t *surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect) { - cairo_xlib_surface_t *surface = abstract_surface; cairo_image_surface_t *image; - XImage *ximage; Window root_ignore; int x_ignore, y_ignore, bwidth_ignore, depth_ignore; + int x1, y1, x2, y2; XGetGeometry (surface->dpy, surface->drawable, @@ -212,11 +227,39 @@ _cairo_xlib_surface_get_image (void *abstract_surface) &surface->width, &surface->height, &bwidth_ignore, &depth_ignore); + x1 = 0; + y1 = 0; + x2 = surface->width; + y2 = surface->height; + + if (interest_rect) { + if (interest_rect->x > x1) + x1 = interest_rect->x; + if (interest_rect->y > y1) + y1 = interest_rect->y; + if (interest_rect->x + interest_rect->width < x2) + x2 = interest_rect->x + interest_rect->width; + if (interest_rect->y + interest_rect->height < y2) + y2 = interest_rect->y + interest_rect->height; + + if (x1 >= x2 || y1 >= y2) { + *image_out = NULL; + return CAIRO_STATUS_SUCCESS; + } + } + + if (image_rect) { + image_rect->x = x1; + image_rect->y = y1; + image_rect->width = x2 - x1; + image_rect->height = y2 - y1; + } + /* XXX: This should try to use the XShm extension if availible */ ximage = XGetImage (surface->dpy, surface->drawable, - 0, 0, - surface->width, surface->height, + x1, y1, + x2 - x1, y2 - y1, AllPlanes, ZPixmap); if (surface->visual) { @@ -253,7 +296,8 @@ _cairo_xlib_surface_get_image (void *abstract_surface) _cairo_image_surface_set_repeat (image, surface->base.repeat); _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); - return image; + *image_out = image; + return CAIRO_STATUS_SUCCESS; } static void @@ -266,10 +310,11 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface) } static cairo_status_t -_cairo_xlib_surface_set_image (void *abstract_surface, - cairo_image_surface_t *image) +_draw_image_surface (cairo_xlib_surface_t *surface, + cairo_image_surface_t *image, + int dst_x, + int dst_y) { - cairo_xlib_surface_t *surface = abstract_surface; XImage *ximage; unsigned bitmap_pad; @@ -295,9 +340,8 @@ _cairo_xlib_surface_set_image (void *abstract_surface, _cairo_xlib_surface_ensure_gc (surface); XPutImage(surface->dpy, surface->drawable, surface->gc, - ximage, 0, 0, 0, 0, - surface->width, - surface->height); + ximage, 0, 0, dst_x, dst_y, + image->width, image->height); /* Foolish XDestroyImage thinks it can free my data, but I won't stand for it. */ @@ -305,17 +349,116 @@ _cairo_xlib_surface_set_image (void *abstract_surface, XDestroyImage (ximage); return CAIRO_STATUS_SUCCESS; + +} + +static cairo_status_t +_cairo_xlib_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_xlib_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; + + status = _get_image_surface (surface, NULL, &image, NULL); + if (status == CAIRO_STATUS_SUCCESS) { + cairo_surface_set_filter (&image->base, surface->base.filter); + cairo_surface_set_matrix (&image->base, &surface->base.matrix); + cairo_surface_set_repeat (&image->base, surface->base.repeat); + + *image_out = image; + } + + return status; +} + +static void +_cairo_xlib_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); +} + +static cairo_status_t +_cairo_xlib_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect_out, + void **image_extra) +{ + cairo_xlib_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; + + status = _get_image_surface (surface, interest_rect, &image, image_rect_out); + if (status == CAIRO_STATUS_SUCCESS) + *image_out = image; + + return status; +} + +static void +_cairo_xlib_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra) +{ + cairo_xlib_surface_t *surface = abstract_surface; + + /* ignore errors */ + _draw_image_surface (surface, image, image_rect->x, image_rect->y); + + cairo_surface_destroy (&image->base); } static cairo_status_t -_cairo_xlib_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) +_cairo_xlib_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + cairo_surface_t **clone_out) { cairo_xlib_surface_t *surface = abstract_surface; + cairo_xlib_surface_t *clone; + + if (src->backend == surface->base.backend ) { + cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src; + + if (xlib_src->dpy == surface->dpy) { + *clone_out = src; + cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; + } + } else if (_cairo_surface_is_image (src)) { + cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; + + clone = (cairo_xlib_surface_t *) + _cairo_xlib_surface_create_similar (surface, image_src->format, 0, + image_src->width, image_src->height); + if (clone == NULL) + return CAIRO_STATUS_NO_MEMORY; + + _draw_image_surface (clone, image_src, 0, 0); + + *clone_out = &clone->base; + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface, + cairo_matrix_t *matrix) +{ XTransform xtransform; if (!surface->picture) return CAIRO_STATUS_SUCCESS; - + xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); @@ -328,26 +471,41 @@ _cairo_xlib_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) xtransform.matrix[2][1] = 0; xtransform.matrix[2][2] = _cairo_fixed_from_double (1); - if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) + if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) { - XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform); - } else { - /* XXX: Need support here if using an old RENDER without support - for SetPictureTransform */ + static const XTransform identity = { { + { 1 << 16, 0x00000, 0x00000 }, + { 0x00000, 1 << 16, 0x00000 }, + { 0x00000, 0x00000, 1 << 16 }, + } }; + + if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0) + return CAIRO_STATUS_SUCCESS; + + return CAIRO_INT_STATUS_UNSUPPORTED; } + XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform); + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +_cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface, + cairo_filter_t filter) { - cairo_xlib_surface_t *surface = abstract_surface; char *render_filter; - if (!(surface->picture - && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface))) + if (!surface->picture) return CAIRO_STATUS_SUCCESS; + + if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) + { + if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) + return CAIRO_STATUS_SUCCESS; + + return CAIRO_INT_STATUS_UNSUPPORTED; + } switch (filter) { case CAIRO_FILTER_FAST: @@ -377,11 +535,10 @@ _cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter) } static cairo_status_t -_cairo_xlib_surface_set_repeat (void *abstract_surface, int repeat) +_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat) { - cairo_xlib_surface_t *surface = abstract_surface; - unsigned long mask; XRenderPictureAttributes pa; + unsigned long mask; if (!surface->picture) return CAIRO_STATUS_SUCCESS; @@ -394,33 +551,32 @@ _cairo_xlib_surface_set_repeat (void *abstract_surface, int repeat) return CAIRO_STATUS_SUCCESS; } -static cairo_xlib_surface_t * -_cairo_xlib_surface_clone_similar (cairo_surface_t *src, - cairo_xlib_surface_t *template, - cairo_format_t format, - int depth) +static cairo_int_status_t +_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, + cairo_surface_attributes_t *attributes) { - cairo_xlib_surface_t *clone; - cairo_image_surface_t *src_image; + cairo_int_status_t status; - src_image = _cairo_surface_get_image (src); - - clone = (cairo_xlib_surface_t *) - _cairo_xlib_surface_create_similar (template, format, 0, - src_image->width, - src_image->height); - if (clone == NULL) - return NULL; - - _cairo_xlib_surface_set_filter (clone, cairo_surface_get_filter(src)); - - _cairo_xlib_surface_set_image (clone, src_image); - - _cairo_xlib_surface_set_matrix (clone, &(src_image->base.matrix)); + status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix); + if (status) + return status; + + switch (attributes->extend) { + case CAIRO_EXTEND_NONE: + _cairo_xlib_surface_set_repeat (surface, 0); + break; + case CAIRO_EXTEND_REPEAT: + _cairo_xlib_surface_set_repeat (surface, 1); + break; + case CAIRO_EXTEND_REFLECT: + return CAIRO_INT_STATUS_UNSUPPORTED; + } - cairo_surface_destroy (&src_image->base); + status = _cairo_xlib_surface_set_filter (surface, attributes->filter); + if (status) + return status; - return clone; + return CAIRO_STATUS_SUCCESS; } static int @@ -462,8 +618,8 @@ _render_operator (cairo_operator_t operator) static cairo_int_status_t _cairo_xlib_surface_composite (cairo_operator_t operator, - cairo_surface_t *generic_src, - cairo_surface_t *generic_mask, + cairo_pattern_t *src_pattern, + cairo_pattern_t *mask_pattern, void *abstract_dst, int src_x, int src_y, @@ -474,73 +630,66 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, unsigned int width, unsigned int height) { - cairo_xlib_surface_t *dst = abstract_dst; - cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) generic_src; - cairo_xlib_surface_t *mask = (cairo_xlib_surface_t *) generic_mask; - cairo_xlib_surface_t *src_clone = NULL; - cairo_xlib_surface_t *mask_clone = NULL; - XGCValues gc_values; - int src_x_off, src_y_off, dst_x_off, dst_y_off; + cairo_surface_attributes_t src_attr, mask_attr; + cairo_xlib_surface_t *dst = abstract_dst; + cairo_xlib_surface_t *src; + cairo_xlib_surface_t *mask; + cairo_int_status_t status; if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; - if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { - src_clone = _cairo_xlib_surface_clone_similar (generic_src, dst, - CAIRO_FORMAT_ARGB32, 32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - src = src_clone; - } - if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) { - mask_clone = _cairo_xlib_surface_clone_similar (generic_mask, dst, - CAIRO_FORMAT_A8, 8); - if (!mask_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - mask = mask_clone; - } - - if (operator == CAIRO_OPERATOR_SRC - && !mask - && _cairo_matrix_is_integer_translation(&(src->base.matrix), - &src_x_off, &src_y_off) - && _cairo_matrix_is_integer_translation(&(dst->base.matrix), - &dst_x_off, &dst_y_off)) { - /* Fast path for copying "raw" areas. */ - _cairo_xlib_surface_ensure_gc (dst); - XGetGCValues(dst->dpy, dst->gc, GCGraphicsExposures, &gc_values); - XSetGraphicsExposures(dst->dpy, dst->gc, False); - XCopyArea(dst->dpy, - src->drawable, - dst->drawable, - dst->gc, - src_x + src_x_off, - src_y + src_y_off, - width, height, - dst_x + dst_x_off, - dst_y + dst_y_off); - XSetGraphicsExposures(dst->dpy, dst->gc, gc_values.graphics_exposures); - - } else { - XRenderComposite (dst->dpy, - _render_operator (operator), - src->picture, - mask ? mask->picture : 0, - dst->picture, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); + status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern, + &dst->base, + src_x, src_y, + mask_x, mask_y, + width, height, + (cairo_surface_t **) &src, + (cairo_surface_t **) &mask, + &src_attr, &mask_attr); + if (status) + return status; + + status = _cairo_xlib_surface_set_attributes (src, &src_attr); + if (CAIRO_OK (status)) + { + if (mask) + { + status = _cairo_xlib_surface_set_attributes (mask, &mask_attr); + if (CAIRO_OK (status)) + XRenderComposite (dst->dpy, + _render_operator (operator), + src->picture, + mask->picture, + dst->picture, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + mask_x + mask_attr.x_offset, + mask_y + mask_attr.y_offset, + dst_x, dst_y, + width, height); + } + else + { + XRenderComposite (dst->dpy, + _render_operator (operator), + src->picture, + 0, + dst->picture, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + } } - /* XXX: This is messed up. If I can xlib_surface_create, then I - should be able to xlib_surface_destroy. */ - if (src_clone) - cairo_surface_destroy (&src_clone->base); - if (mask_clone) - cairo_surface_destroy (&mask_clone->base); + if (mask) + _cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr); + + _cairo_pattern_release_surface (&dst->base, &src->base, &src_attr); - return CAIRO_STATUS_SUCCESS; + return status; } static cairo_int_status_t @@ -572,41 +721,59 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, static cairo_int_status_t _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *generic_src, + cairo_pattern_t *pattern, void *abstract_dst, - int xSrc, - int ySrc, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps) { - cairo_xlib_surface_t *dst = abstract_dst; - cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) generic_src; - cairo_xlib_surface_t *src_clone = NULL; + cairo_surface_attributes_t attributes; + cairo_xlib_surface_t *dst = abstract_dst; + cairo_xlib_surface_t *src; + cairo_int_status_t status; + int render_reference_x, render_reference_y; + int render_src_x, render_src_y; if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; - - if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { - src_clone = _cairo_xlib_surface_clone_similar (generic_src, dst, - CAIRO_FORMAT_ARGB32, 32); - if (!src_clone) - return CAIRO_INT_STATUS_UNSUPPORTED; - src = src_clone; + + status = _cairo_pattern_acquire_surface (pattern, &dst->base, + src_x, src_y, width, height, + (cairo_surface_t **) &src, + &attributes); + if (status) + return status; + + if (traps[0].left.p1.y < traps[0].left.p2.y) { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y); + } else { + render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x); + render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y); } - /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ - XRenderCompositeTrapezoids (dst->dpy, - _render_operator (operator), - src->picture, dst->picture, - XRenderFindStandardFormat (dst->dpy, PictStandardA8), - xSrc, ySrc, (XTrapezoid *) traps, num_traps); + render_src_x = src_x + render_reference_x - dst_x; + render_src_y = src_y + render_reference_y - dst_y; - /* XXX: This is messed up. If I can xlib_surface_create, then I - should be able to xlib_surface_destroy. */ - if (src_clone) - cairo_surface_destroy (&src_clone->base); + /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ + status = _cairo_xlib_surface_set_attributes (src, &attributes); + if (CAIRO_OK (status)) + XRenderCompositeTrapezoids (dst->dpy, + _render_operator (operator), + src->picture, dst->picture, + XRenderFindStandardFormat (dst->dpy, PictStandardA8), + render_src_x + attributes.x_offset, + render_src_y + attributes.y_offset, + (XTrapezoid *) traps, num_traps); + + _cairo_pattern_release_surface (&dst->base, &src->base, &attributes); - return CAIRO_STATUS_SUCCESS; + return status; } static cairo_int_status_t @@ -685,22 +852,17 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } -static cairo_int_status_t -_cairo_xlib_surface_create_pattern (void *abstract_surface, - cairo_pattern_t *pattern, - cairo_box_t *extents) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; -} - static cairo_status_t -_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_xlib_surface_show_glyphs (cairo_font_t *font, cairo_operator_t operator, - cairo_surface_t *source, + cairo_pattern_t *pattern, void *abstract_surface, int source_x, int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs); @@ -708,18 +870,17 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, _cairo_xlib_surface_destroy, _cairo_xlib_surface_pixels_per_inch, - _cairo_xlib_surface_get_image, - _cairo_xlib_surface_set_image, - _cairo_xlib_surface_set_matrix, - _cairo_xlib_surface_set_filter, - _cairo_xlib_surface_set_repeat, + _cairo_xlib_surface_acquire_source_image, + _cairo_xlib_surface_release_source_image, + _cairo_xlib_surface_acquire_dest_image, + _cairo_xlib_surface_release_dest_image, + _cairo_xlib_surface_clone_similar, _cairo_xlib_surface_composite, _cairo_xlib_surface_fill_rectangles, _cairo_xlib_surface_composite_trapezoids, _cairo_xlib_surface_copy_page, _cairo_xlib_surface_show_page, _cairo_xlib_surface_set_clip_region, - _cairo_xlib_surface_create_pattern, _cairo_xlib_surface_show_glyphs }; @@ -827,6 +988,7 @@ typedef struct { cairo_glyph_cache_key_t key; Glyph glyph; XGlyphInfo info; + int refcount; } glyphset_cache_entry_t; static Glyph @@ -854,17 +1016,18 @@ _xlib_glyphset_cache_create_entry (void *cache, _cairo_lock_global_image_glyph_cache (); im_cache = _cairo_get_global_image_glyph_cache (); - if (g == NULL || v == NULL ||g == NULL || im_cache == NULL) { + if (g == NULL || v == NULL || im_cache == NULL) { _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_NO_MEMORY; } - status = _cairo_cache_lookup (im_cache, key, (void **) (&im)); + status = _cairo_cache_lookup (im_cache, key, (void **) (&im), NULL); if (status != CAIRO_STATUS_SUCCESS || im == NULL) { _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_NO_MEMORY; } + v->refcount = 1; v->key = *k; _cairo_unscaled_font_reference (v->key.unscaled); @@ -925,6 +1088,12 @@ _xlib_glyphset_cache_create_entry (void *cache, return CAIRO_STATUS_SUCCESS; } +static void +_glyphset_cache_entry_reference (glyphset_cache_entry_t *e) +{ + e->refcount++; +} + static void _xlib_glyphset_cache_destroy_cache (void *cache) { @@ -940,6 +1109,9 @@ _xlib_glyphset_cache_destroy_entry (void *cache, void *entry) g = (glyphset_cache_t *) cache; v = (glyphset_cache_entry_t *) entry; + if (--v->refcount > 0) + return; + _cairo_unscaled_font_destroy (v->key.unscaled); XRenderFreeGlyphs (g->display, g->glyphset, &(v->glyph), 1); free (v); @@ -1014,8 +1186,7 @@ _get_glyphset_cache (Display *d) #define N_STACK_BUF 1024 static cairo_status_t -_cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_xlib_surface_show_glyphs32 (cairo_font_t *font, cairo_operator_t operator, glyphset_cache_t *g, cairo_glyph_cache_key_t *key, @@ -1092,8 +1263,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_unscaled_font_t *font, static cairo_status_t -_cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_xlib_surface_show_glyphs16 (cairo_font_t *font, cairo_operator_t operator, glyphset_cache_t *g, cairo_glyph_cache_key_t *key, @@ -1169,10 +1339,9 @@ _cairo_xlib_surface_show_glyphs16 (cairo_unscaled_font_t *font, } static cairo_status_t -_cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_xlib_surface_show_glyphs8 (cairo_font_t *font, cairo_operator_t operator, - glyphset_cache_t *g, + glyphset_cache_t *g, cairo_glyph_cache_key_t *key, cairo_xlib_surface_t *src, cairo_xlib_surface_t *self, @@ -1247,27 +1416,44 @@ _cairo_xlib_surface_show_glyphs8 (cairo_unscaled_font_t *font, static cairo_status_t -_cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, +_cairo_xlib_surface_show_glyphs (cairo_font_t *font, cairo_operator_t operator, - cairo_surface_t *source, + cairo_pattern_t *pattern, void *abstract_surface, int source_x, int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs) { + cairo_surface_attributes_t attributes; + cairo_int_status_t status; unsigned int elt_size; cairo_xlib_surface_t *self = abstract_surface; - cairo_image_surface_t *tmp = NULL; - cairo_xlib_surface_t *src = NULL; + cairo_xlib_surface_t *src; glyphset_cache_t *g; - cairo_status_t status; cairo_glyph_cache_key_t key; glyphset_cache_entry_t **entries; glyphset_cache_entry_t *stack_entries [N_STACK_BUF]; int i; + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_pattern_acquire_surface (pattern, &self->base, + source_x, source_y, width, height, + (cairo_surface_t **) &src, + &attributes); + if (status) + return status; + + status = _cairo_xlib_surface_set_attributes (src, &attributes); + if (status) + goto FAIL; + /* Acquire an entry array of suitable size. */ if (num_glyphs < N_STACK_BUF) { entries = stack_entries; @@ -1278,26 +1464,6 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, goto FAIL; } - /* prep the source surface. */ - if (source->backend == self->base.backend) { - src = (cairo_xlib_surface_t *) source; - - } else { - tmp = _cairo_surface_get_image (source); - if (tmp == NULL) - goto FREE_ENTRIES; - - src = (cairo_xlib_surface_t *) - _cairo_surface_create_similar_scratch (&self->base, self->format, 1, - tmp->width, tmp->height); - - if (src == NULL) - goto FREE_TMP; - - if (_cairo_surface_set_image (&(src->base), tmp) != CAIRO_STATUS_SUCCESS) - goto FREE_SRC; - } - _lock_xlib_glyphset_caches (); g = _get_glyphset_cache (self->dpy); if (g == NULL) @@ -1305,15 +1471,23 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, /* Work out the index size to use. */ elt_size = 8; - key.scale = *scale; - key.unscaled = font; + _cairo_font_get_glyph_cache_key (font, &key); for (i = 0; i < num_glyphs; ++i) { key.index = glyphs[i].index; - status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i])); + status = _cairo_cache_lookup (&g->base, &key, (void **) (&entries[i]), NULL); if (status != CAIRO_STATUS_SUCCESS || entries[i] == NULL) goto UNLOCK; + /* Referencing the glyph entries we use prevents them from + * being freed if lookup of later entries causes them to + * be ejected from the cache. It would be more efficient + * (though more complex) to prevent them from being ejected + * from the cache at all, so they could get reused later + * in the same string. + */ + _glyphset_cache_entry_reference (entries[i]); + if (elt_size == 8 && entries[i]->glyph > 0xff) elt_size = 16; if (elt_size == 16 && entries[i]->glyph > 0xffff) { @@ -1325,43 +1499,32 @@ _cairo_xlib_surface_show_glyphs (cairo_unscaled_font_t *font, /* Call the appropriate sub-function. */ if (elt_size == 8) - status = _cairo_xlib_surface_show_glyphs8 (font, scale, operator, g, &key, src, self, - source_x, source_y, + status = _cairo_xlib_surface_show_glyphs8 (font, operator, g, &key, src, self, + source_x + attributes.x_offset, + source_y + attributes.y_offset, glyphs, entries, num_glyphs); else if (elt_size == 16) - status = _cairo_xlib_surface_show_glyphs16 (font, scale, operator, g, &key, src, self, - source_x, source_y, + status = _cairo_xlib_surface_show_glyphs16 (font, operator, g, &key, src, self, + source_x + attributes.x_offset, + source_y + attributes.y_offset, glyphs, entries, num_glyphs); else - status = _cairo_xlib_surface_show_glyphs32 (font, scale, operator, g, &key, src, self, - source_x, source_y, + status = _cairo_xlib_surface_show_glyphs32 (font, operator, g, &key, src, self, + source_x + attributes.x_offset, + source_y + attributes.y_offset, glyphs, entries, num_glyphs); - _unlock_xlib_glyphset_caches (); - - if (tmp != NULL) { - cairo_surface_destroy (&(src->base)); - cairo_surface_destroy (&(tmp->base)); - } - - if (num_glyphs >= N_STACK_BUF) - free (entries); - - return status; + for (i = 0; i < num_glyphs; ++i) + _xlib_glyphset_cache_destroy_entry (g, entries[i]); UNLOCK: _unlock_xlib_glyphset_caches (); - FREE_SRC: - cairo_surface_destroy (&(src->base)); - - FREE_TMP: - cairo_surface_destroy (&(tmp->base)); - - FREE_ENTRIES: if (num_glyphs >= N_STACK_BUF) free (entries); FAIL: - return CAIRO_STATUS_NO_MEMORY; + _cairo_pattern_release_surface (&self->base, &src->base, &attributes); + + return status; } diff --git a/src/cairoint.h b/src/cairoint.h index 6f9d50617..50899eca8 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -31,7 +31,7 @@ * California. * * Contributor(s): - * Carl D. Worth <cworth@isi.edu> + * Carl D. Worth <cworth@cworth.org> */ /* @@ -39,7 +39,7 @@ * and constitute no kind of standard. If you need any of these * functions, please drop me a note. Either the library needs new * functionality, or there's a way to do what you need using the - * existing published interfaces. cworth@isi.edu + * existing published interfaces. cworth@cworth.org */ #ifndef _CAIROINT_H_ @@ -108,6 +108,17 @@ #define __attribute__(x) #endif +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + #include "cairo-wideint.h" typedef int32_t cairo_fixed_16_16_t; @@ -166,6 +177,8 @@ typedef enum cairo_int_status { CAIRO_INT_STATUS_UNSUPPORTED } cairo_int_status_t; +#define CAIRO_OK(status) ((status) == CAIRO_STATUS_SUCCESS) + typedef enum cairo_path_op { CAIRO_PATH_OP_MOVE_TO = 0, CAIRO_PATH_OP_LINE_TO = 1, @@ -373,43 +386,49 @@ _cairo_cache_destroy (cairo_cache_t *cache); cairo_private cairo_status_t _cairo_cache_lookup (cairo_cache_t *cache, - void *key, - void **entry_return); + void *key, + void **entry_return, + int *created_entry); + +cairo_private cairo_status_t +_cairo_cache_remove (cairo_cache_t *cache, + void *key); + +cairo_private void * +_cairo_cache_random_entry (cairo_cache_t *cache, + int (*predicate) (void*)); cairo_private unsigned long _cairo_hash_string (const char *c); #define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000 #define CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT 0x100000 -#define CAIRO_FONT_CACHE_NUM_FONTS_DEFAULT 20 -#define CAIRO_FT_CACHE_NUM_FONTS_DEFAULT 20 typedef struct { - double matrix[2][2]; + double matrix[2][2]; } cairo_font_scale_t; struct _cairo_font_backend; +/* + * A cairo_unscaled_font_t is just an opaque handle we use in the + * glyph cache. + */ typedef struct { int refcount; const struct _cairo_font_backend *backend; } cairo_unscaled_font_t; -/* - * A cairo_font contains a pointer to a cairo_unscaled_font_t and a scale - * matrix. These are the things the user holds references to. - */ - struct _cairo_font { int refcount; - cairo_font_scale_t scale; - cairo_unscaled_font_t *unscaled; + cairo_font_scale_t scale; /* font space => device space */ + const struct _cairo_font_backend *backend; }; -/* cairo_font.c is responsible for two global caches: +/* cairo_font.c is responsible for a global glyph cache: * - * - font entries: [[[base], name, weight, slant], cairo_unscaled_font_t ] - * - glyph entries: [[[base], cairo_font_t, index], image, size, extents ] + * - glyph entries: [[[base], cairo_unscaled_font_t, scale, flags, index], + * image, size, extents] * * Surfaces may build their own glyph caches if they have surface-specific * glyph resources to maintain; those caches can feed off of the global @@ -420,6 +439,7 @@ typedef struct { cairo_cache_entry_base_t base; cairo_unscaled_font_t *unscaled; cairo_font_scale_t scale; + int flags; unsigned long index; } cairo_glyph_cache_key_t; @@ -452,49 +472,52 @@ _cairo_glyph_cache_keys_equal (void *cache, /* the font backend interface */ typedef struct _cairo_font_backend { - cairo_unscaled_font_t *(*create) (const char *family, + cairo_status_t (*create) (const char *family, cairo_font_slant_t slant, - cairo_font_weight_t weight); + cairo_font_weight_t weight, + cairo_font_scale_t *scale, + cairo_font_t **font); - void (*destroy) (void *font); + void (*destroy_font) (void *font); + void (*destroy_unscaled_font) (void *font); cairo_status_t (*font_extents) (void *font, - cairo_font_scale_t *scale, cairo_font_extents_t *extents); cairo_status_t (*text_to_glyphs) (void *font, - cairo_font_scale_t *scale, const unsigned char *utf8, cairo_glyph_t **glyphs, int *num_glyphs); cairo_status_t (*glyph_extents) (void *font, - cairo_font_scale_t *scale, cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents); cairo_status_t (*glyph_bbox) (void *font, - cairo_font_scale_t *scale, const cairo_glyph_t *glyphs, int num_glyphs, cairo_box_t *bbox); cairo_status_t (*show_glyphs) (void *font, - cairo_font_scale_t *scale, cairo_operator_t operator, - cairo_surface_t *source, + cairo_pattern_t *pattern, cairo_surface_t *surface, int source_x, int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs); cairo_status_t (*glyph_path) (void *font, - cairo_font_scale_t *scale, cairo_glyph_t *glyphs, int num_glyphs, cairo_path_t *path); + void (*get_glyph_cache_key) (void *font, + cairo_glyph_cache_key_t *key); cairo_status_t (*create_glyph) (cairo_image_glyph_cache_entry_t *entry); @@ -507,6 +530,12 @@ extern const cairo_private struct _cairo_font_backend cairo_ft_font_backend; #endif +#ifdef CAIRO_HAS_WIN32_FONT + +extern const cairo_private struct _cairo_font_backend cairo_win32_font_backend; + +#endif + #ifdef CAIRO_HAS_ATSUI_FONT extern const cairo_private struct _cairo_font_backend cairo_atsui_font_backend; @@ -527,35 +556,40 @@ typedef struct _cairo_surface_backend { double (*pixels_per_inch) (void *surface); - /* XXX: We could use a better name than get_image here. Something - to suggest the fact that the function will create a new - surface, (and hence that it needs to be destroyed). Perhaps - clone_image or maybe simply clone? */ - - cairo_image_surface_t * - (*get_image) (void *surface); - cairo_status_t - (*set_image) (void *surface, - cairo_image_surface_t *image); + (* acquire_source_image) (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra); - cairo_status_t - (*set_matrix) (void *surface, - cairo_matrix_t *matrix); + void + (* release_source_image) (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra); cairo_status_t - (*set_filter) (void *surface, - cairo_filter_t filter); + (*acquire_dest_image) (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra); + void + (*release_dest_image) (void *abstract_surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra); + cairo_status_t - (*set_repeat) (void *surface, - int repeat); - + (*clone_similar) (void *surface, + cairo_surface_t *src, + cairo_surface_t **clone_out); + /* XXX: dst should be the first argument for consistency */ cairo_int_status_t (*composite) (cairo_operator_t operator, - cairo_surface_t *src, - cairo_surface_t *mask, + cairo_pattern_t *src, + cairo_pattern_t *mask, void *dst, int src_x, int src_y, @@ -576,10 +610,14 @@ typedef struct _cairo_surface_backend { /* XXX: dst should be the first argument for consistency */ cairo_int_status_t (*composite_trapezoids) (cairo_operator_t operator, - cairo_surface_t *src, + cairo_pattern_t *pattern, void *dst, - int xSrc, - int ySrc, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int num_traps); @@ -592,24 +630,22 @@ typedef struct _cairo_surface_backend { cairo_int_status_t (*set_clip_region) (void *surface, pixman_region16_t *region); - cairo_int_status_t - (*create_pattern) (void *surface, - cairo_pattern_t *pattern, - cairo_box_t *extents); - /* * This is an optional entry to let the surface manage its own glyph * resources. If null, the font will be asked to render against this * surface, using image surfaces as glyphs. */ cairo_status_t - (*show_glyphs) (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, + (*show_glyphs) (cairo_font_t *font, cairo_operator_t operator, - cairo_surface_t *source, + cairo_pattern_t *pattern, void *surface, int source_x, int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs); } cairo_surface_backend_t; @@ -640,6 +676,7 @@ struct _cairo_image_surface { cairo_surface_t base; /* libic-specific fields */ + cairo_format_t format; char *data; int owns_data; @@ -681,60 +718,77 @@ typedef enum { typedef struct _cairo_color_stop { cairo_fixed_t offset; - cairo_fixed_48_16_t scale; - int id; - unsigned char color_char[4]; + cairo_color_t color; } cairo_color_stop_t; -typedef void (*cairo_shader_function_t) (unsigned char *color0, - unsigned char *color1, - cairo_fixed_t factor, - int *pixel); +struct _cairo_pattern { + cairo_pattern_type_t type; + unsigned int ref_count; + cairo_matrix_t matrix; + cairo_filter_t filter; + cairo_extend_t extend; + double alpha; +}; + +typedef struct _cairo_solid_pattern { + cairo_pattern_t base; + + double red, green, blue; +} cairo_solid_pattern_t; + +typedef struct _cairo_surface_pattern { + cairo_pattern_t base; + + cairo_surface_t *surface; +} cairo_surface_pattern_t; -typedef struct _cairo_shader_op { +typedef struct _cairo_gradient_pattern { + cairo_pattern_t base; + cairo_color_stop_t *stops; - int n_stops; - cairo_fixed_t min_offset; - cairo_fixed_t max_offset; - cairo_extend_t extend; - cairo_shader_function_t shader_function; -} cairo_shader_op_t; + int n_stops; +} cairo_gradient_pattern_t; -struct _cairo_pattern { - unsigned int ref_count; - +typedef struct _cairo_linear_pattern { + cairo_gradient_pattern_t base; + + cairo_point_double_t point0; + cairo_point_double_t point1; +} cairo_linear_pattern_t; + +typedef struct _cairo_radial_pattern { + cairo_gradient_pattern_t base; + + cairo_point_double_t center0; + cairo_point_double_t center1; + double radius0; + double radius1; +} cairo_radial_pattern_t; + +typedef union { + cairo_gradient_pattern_t base; + + cairo_linear_pattern_t linear; + cairo_radial_pattern_t radial; +} cairo_gradient_pattern_union_t; + +typedef union { + cairo_pattern_t base; + + cairo_solid_pattern_t solid; + cairo_surface_pattern_t surface; + cairo_gradient_pattern_union_t gradient; +} cairo_pattern_union_t; + +typedef struct _cairo_surface_attributes { + cairo_matrix_t matrix; cairo_extend_t extend; cairo_filter_t filter; - cairo_matrix_t matrix; - - cairo_color_stop_t *stops; - int n_stops; - - cairo_color_t color; - - cairo_surface_t *source; - cairo_point_double_t source_offset; - - cairo_pattern_type_t type; - union { - struct { - cairo_surface_t *surface; - cairo_matrix_t save_matrix; - int save_repeat; - cairo_filter_t save_filter; - } surface; - struct { - cairo_point_double_t point0; - cairo_point_double_t point1; - } linear; - struct { - cairo_point_double_t center0; - cairo_point_double_t center1; - double radius0; - double radius1; - } radial; - } u; -}; + int x_offset; + int y_offset; + cairo_bool_t acquired; + void *extra; +} cairo_surface_attributes_t; typedef struct _cairo_traps { cairo_trapezoid_t *traps; @@ -746,19 +800,21 @@ typedef struct _cairo_traps { #define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL #define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL -#ifdef CAIRO_HAS_FT_FONT - -#define CAIRO_FONT_FAMILY_DEFAULT "serif" +#if defined (CAIRO_HAS_WIN32_FONT) -/* XXX: Platform-specific. Other platforms may want a different default */ -#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend +#define CAIRO_FONT_FAMILY_DEFAULT "Arial" +#define CAIRO_FONT_BACKEND_DEFAULT &cairo_win32_font_backend -#elif defined(CAIRO_HAS_ATSUI_FONT) +#elif defined (CAIRO_HAS_ATSUI_FONT) #define CAIRO_FONT_FAMILY_DEFAULT "Monaco" - #define CAIRO_FONT_BACKEND_DEFAULT &cairo_atsui_font_backend +#elif defined (CAIRO_HAS_FT_FONT) + +#define CAIRO_FONT_FAMILY_DEFAULT "serif" +#define CAIRO_FONT_BACKEND_DEFAULT &cairo_ft_font_backend + #endif #define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER @@ -772,10 +828,7 @@ typedef struct _cairo_traps { /* Need a name distinct from the cairo_clip function */ typedef struct _cairo_clip_rec { - int x; - int y; - int width; - int height; + cairo_rectangle_t rect; pixman_region16_t *region; cairo_surface_t *surface; } cairo_clip_rec_t; @@ -797,7 +850,11 @@ typedef struct _cairo_gstate { int num_dashes; double dash_offset; - cairo_unscaled_font_t *font; + char *font_family; /* NULL means CAIRO_FONT_FAMILY_DEFAULT; */ + cairo_font_slant_t font_slant; + cairo_font_weight_t font_weight; + + cairo_font_t *font; /* Specific to the current CTM */ cairo_surface_t *surface; @@ -868,7 +925,7 @@ _cairo_fixed_integer_ceil (cairo_fixed_t f); cairo_private cairo_gstate_t * _cairo_gstate_create (void); -cairo_private void +cairo_private cairo_status_t _cairo_gstate_init (cairo_gstate_t *gstate); cairo_private cairo_status_t @@ -1086,13 +1143,13 @@ cairo_private cairo_status_t _cairo_gstate_in_stroke (cairo_gstate_t *gstate, double x, double y, - int *inside_ret); + cairo_bool_t *inside_ret); cairo_private cairo_status_t _cairo_gstate_in_fill (cairo_gstate_t *gstate, double x, double y, - int *inside_ret); + cairo_bool_t *inside_ret); cairo_private cairo_status_t _cairo_gstate_init_clip (cairo_gstate_t *gstate); @@ -1119,6 +1176,10 @@ cairo_private cairo_status_t _cairo_gstate_scale_font (cairo_gstate_t *gstate, double scale); +cairo_private void +_cairo_gstate_current_font_scale (cairo_gstate_t *gstate, + cairo_font_scale_t *sc); + cairo_private cairo_status_t _cairo_gstate_transform_font (cairo_gstate_t *gstate, cairo_matrix_t *matrix); @@ -1177,26 +1238,29 @@ cairo_private void _cairo_color_set_rgb (cairo_color_t *color, double red, double green, double blue); cairo_private void -_cairo_color_get_rgb (cairo_color_t *color, double *red, double *green, double *blue); +_cairo_color_get_rgb (const cairo_color_t *color, + double *red, double *green, double *blue); cairo_private void _cairo_color_set_alpha (cairo_color_t *color, double alpha); /* cairo_font.c */ -cairo_private cairo_unscaled_font_t * -_cairo_unscaled_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight); +cairo_private cairo_status_t +_cairo_font_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight, + cairo_font_scale_t *sc, + cairo_font_t **font); cairo_private void -_cairo_font_init (cairo_font_t *scaled, - cairo_font_scale_t *scale, - cairo_unscaled_font_t *unscaled); +_cairo_font_init (cairo_font_t *font, + cairo_font_scale_t *scale, + const cairo_font_backend_t *backend); -cairo_private cairo_status_t -_cairo_unscaled_font_init (cairo_unscaled_font_t *font, - const struct _cairo_font_backend *backend); +cairo_private void +_cairo_unscaled_font_init (cairo_unscaled_font_t *font, + const struct _cairo_font_backend *backend); cairo_private void _cairo_unscaled_font_reference (cairo_unscaled_font_t *font); @@ -1205,48 +1269,56 @@ cairo_private void _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font); cairo_private cairo_status_t -_cairo_unscaled_font_font_extents (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_font_extents_t *extents); +_cairo_font_font_extents (cairo_font_t *font, + cairo_font_extents_t *extents); + +cairo_private cairo_status_t +_cairo_font_text_to_glyphs (cairo_font_t *font, + const unsigned char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs); cairo_private cairo_status_t -_cairo_unscaled_font_text_to_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - const unsigned char *utf8, - cairo_glyph_t **glyphs, - int *num_glyphs); +_cairo_font_glyph_extents (cairo_font_t *font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents); cairo_private cairo_status_t -_cairo_unscaled_font_glyph_extents (cairo_unscaled_font_t *font, - cairo_font_scale_t *scale, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents); +_cairo_font_glyph_bbox (cairo_font_t *font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox); cairo_private cairo_status_t -_cairo_unscaled_font_glyph_bbox (cairo_unscaled_font_t *font, - cairo_font_scale_t *size, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox); +_cairo_font_show_glyphs (cairo_font_t *font, + cairo_operator_t operator, + cairo_pattern_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int widht, + unsigned int height, + cairo_glyph_t *glyphs, + int num_glyphs); cairo_private cairo_status_t -_cairo_unscaled_font_show_glyphs (cairo_unscaled_font_t *font, - cairo_font_scale_t *size, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - int source_x, - int source_y, - cairo_glyph_t *glyphs, - int num_glyphs); +_cairo_font_glyph_path (cairo_font_t *font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path); cairo_private cairo_status_t -_cairo_unscaled_font_glyph_path (cairo_unscaled_font_t *font, - cairo_font_scale_t *size, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_t *path); +_cairo_font_glyph_path (cairo_font_t *font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path); + +cairo_private void +_cairo_font_get_glyph_cache_key (cairo_font_t *font, + cairo_glyph_cache_key_t *key); /* cairo_hull.c */ cairo_private cairo_status_t @@ -1355,8 +1427,8 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface, cairo_private cairo_status_t _cairo_surface_composite (cairo_operator_t operator, - cairo_surface_t *src, - cairo_surface_t *mask, + cairo_pattern_t *src, + cairo_pattern_t *mask, cairo_surface_t *dst, int src_x, int src_y, @@ -1376,10 +1448,14 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, cairo_private cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t operator, - cairo_surface_t *src, + cairo_pattern_t *pattern, cairo_surface_t *dst, - int xSrc, - int ySrc, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, cairo_trapezoid_t *traps, int ntraps); @@ -1392,20 +1468,37 @@ _cairo_surface_show_page (cairo_surface_t *surface); cairo_private double _cairo_surface_pixels_per_inch (cairo_surface_t *surface); -cairo_private cairo_image_surface_t * -_cairo_surface_get_image (cairo_surface_t *surface); +cairo_private cairo_status_t +_cairo_surface_acquire_source_image (cairo_surface_t *surface, + cairo_image_surface_t **image_out, + void **image_extra); + +cairo_private void +_cairo_surface_release_source_image (cairo_surface_t *surface, + cairo_image_surface_t *image, + void *image_extra); cairo_private cairo_status_t -_cairo_surface_set_image (cairo_surface_t *surface, - cairo_image_surface_t *image); +_cairo_surface_acquire_dest_image (cairo_surface_t *surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_t *image_rect, + void **image_extra); +cairo_private void +_cairo_surface_release_dest_image (cairo_surface_t *surface, + cairo_rectangle_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_t *image_rect, + void *image_extra); + cairo_private cairo_status_t -_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region); +_cairo_surface_clone_similar (cairo_surface_t *surface, + cairo_surface_t *src, + cairo_surface_t **clone_out); cairo_private cairo_status_t -_cairo_surface_create_pattern (cairo_surface_t *surface, - cairo_pattern_t *pattern, - cairo_box_t *extents); +_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region); /* cairo_image_surface.c */ @@ -1435,6 +1528,9 @@ cairo_private cairo_int_status_t _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, pixman_region16_t *region); +cairo_private int +_cairo_surface_is_image (cairo_surface_t *surface); + /* cairo_pen.c */ cairo_private cairo_status_t _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate); @@ -1540,7 +1636,7 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou cairo_private cairo_status_t _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy, int x_major); -cairo_private int +cairo_private cairo_bool_t _cairo_matrix_is_integer_translation(cairo_matrix_t *matrix, int *itx, int *ity); /* cairo_traps.c */ @@ -1581,18 +1677,29 @@ cairo_private int _cairo_slope_counter_clockwise (cairo_slope_t *a, cairo_slope_t *b); /* cairo_pattern.c */ -cairo_private void -_cairo_pattern_init (cairo_pattern_t *pattern); cairo_private cairo_status_t _cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other); cairo_private void -_cairo_pattern_fini (cairo_pattern_t *pattern); +_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, + double red, double green, double blue); cairo_private void -_cairo_pattern_init_solid (cairo_pattern_t *pattern, - double red, double green, double blue); +_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern, + cairo_surface_t *surface); + +cairo_private void +_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern, + double x0, double y0, double x1, double y1); + +cairo_private void +_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, + double cx0, double cy0, double radius0, + double cx1, double cy1, double radius1); + +cairo_private void +_cairo_pattern_fini (cairo_pattern_t *pattern); cairo_private cairo_pattern_t * _cairo_pattern_create_solid (double red, double green, double blue); @@ -1605,27 +1712,56 @@ cairo_private void _cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha); cairo_private void -_cairo_pattern_set_source_offset (cairo_pattern_t *pattern, - double x, double y); - -cairo_private void _cairo_pattern_transform (cairo_pattern_t *pattern, cairo_matrix_t *ctm_inverse); -cairo_private void -_cairo_pattern_prepare_surface (cairo_pattern_t *pattern); +cairo_private cairo_bool_t +_cairo_pattern_is_opaque (cairo_pattern_t *pattern); -cairo_private void -_cairo_pattern_shader_init (cairo_pattern_t *pattern, - cairo_shader_op_t *op); +cairo_private cairo_int_status_t +_cairo_pattern_acquire_surface (cairo_pattern_t *pattern, + cairo_surface_t *dst, + int x, + int y, + unsigned int width, + unsigned int height, + cairo_surface_t **surface_out, + cairo_surface_attributes_t *attributes); cairo_private void -_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op, - cairo_fixed_t factor, - int *pixel); +_cairo_pattern_release_surface (cairo_surface_t *dst, + cairo_surface_t *surface, + cairo_surface_attributes_t *attributes); -cairo_private cairo_image_surface_t * -_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box); +cairo_private cairo_int_status_t +_cairo_pattern_acquire_surfaces (cairo_pattern_t *src, + cairo_pattern_t *mask, + cairo_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + unsigned int width, + unsigned int height, + cairo_surface_t **src_out, + cairo_surface_t **mask_out, + cairo_surface_attributes_t *src_attributes, + cairo_surface_attributes_t *mask_attributes); + + +/* cairo_unicode.c */ + +cairo_private cairo_status_t +_cairo_utf8_to_ucs4 (const char *str, + int len, + uint32_t **result, + int *items_written); + +cairo_private cairo_status_t +_cairo_utf8_to_utf16 (const char *str, + int len, + uint16_t **result, + int *items_written); /* Avoid unnecessary PLT entries. */ diff --git a/test/.cvsignore b/test/.cvsignore index 27e57c1d4..6194e2678 100644 --- a/test/.cvsignore +++ b/test/.cvsignore @@ -2,12 +2,16 @@ .libs Makefile Makefile.in +coverage fill_rule +imagediff leaky_polygon line_width move_to_show_surface +pixman_rotate text_cache_crash text_rotate +clip_twice *-out.png *-diff.png diff --git a/test/Makefile.am b/test/Makefile.am index e7fd3fd6b..04d42e2d6 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -3,18 +3,27 @@ TESTS = \ fill_rule \ leaky_polygon \ line_width \ +linear_gradient \ move_to_show_surface \ text_cache_crash \ -text_rotate +text_rotate \ +coverage \ +clip_twice \ +pixman_rotate -# And all new test go here too. I really don't like having to repeat +# 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 \ -move_to_show_surface-ref.png +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 # 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. @@ -29,6 +38,7 @@ move_to_show_surface-ref.png # be fixed before the code is committed. XFAIL_TESTS = \ move_to_show_surface \ +pixman_rotate \ text_rotate check_PROGRAMS = $(TESTS) @@ -42,6 +52,8 @@ INCLUDES = -D_GNU_SOURCE -I$(srcdir) $(CAIRO_CFLAGS) -I$(srcdir)/../src AM_LDFLAGS = $(CAIRO_LIBS) ../src/libcairo.la cairo_test_lib =\ +buffer_diff.c \ +buffer_diff.h \ cairo_test.c \ cairo_test.h \ read_png.c \ @@ -57,8 +69,15 @@ xmalloc.h 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) + +noinst_PROGRAMS = imagediff +imagediff_SOURCES = imagediff.c $(cairo_test_lib) -CLEANFILES = *-out.png *-diff.png +CLEANFILES = *-out.png *-diff.png *.log diff --git a/test/buffer-diff.c b/test/buffer-diff.c new file mode 100644 index 000000000..07abd62a3 --- /dev/null +++ b/test/buffer-diff.c @@ -0,0 +1,73 @@ +/* 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 new file mode 100644 index 000000000..9ee51c3cf --- /dev/null +++ b/test/buffer-diff.h @@ -0,0 +1,38 @@ +/* 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/buffer_diff.c b/test/buffer_diff.c new file mode 100644 index 000000000..07abd62a3 --- /dev/null +++ b/test/buffer_diff.c @@ -0,0 +1,73 @@ +/* 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 new file mode 100644 index 000000000..9ee51c3cf --- /dev/null +++ b/test/buffer_diff.h @@ -0,0 +1,38 @@ +/* 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 2364570a2..06f7672fd 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -32,10 +32,12 @@ #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" @@ -43,9 +45,10 @@ 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); @@ -54,53 +57,42 @@ xasprintf (char **strp, const char *fmt, ...) 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 */ } -/* 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. - */ -static int -image_diff (char *buf_a, char *buf_b, char *buf_diff, - int width, int height, int stride) +static void +xunlink (const char *pathname) { - 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) */ - } + if (unlink (pathname) < 0 && errno != ENOENT) { + fprintf (stderr, " Error: Cannot remove %s: %s\n", + pathname, strerror (errno)); + exit (1); } - - return total_pixels_changed; } cairo_test_status_t @@ -109,12 +101,14 @@ 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 *png_name, *ref_name, *diff_name; + 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 (); @@ -142,57 +136,68 @@ cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw) 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); - write_png_argb32 (png_buf, png_name, test->width, test->height, stride); + 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 (stderr, " Error: No reference image found: %s\n", ref_name); + fprintf (log_file, "Error: No reference image found: %s\n", ref_name); break; case READ_PNG_FILE_NOT_PNG: - fprintf (stderr, " Error: %s is not a png image\n", ref_name); + fprintf (log_file, "Error: %s is not a png image\n", ref_name); break; default: - fprintf (stderr, " Error: Failed to read %s\n", ref_name); + 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) { - fprintf (stderr, - " Error: Image size mismatch: (%dx%d) vs. (%dx%d)\n" - " for %s vs %s\n", + 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 = image_diff (png_buf, ref_buf, diff_buf, - test->width, test->height, stride); + pixels_changed = buffer_diff (png_buf, ref_buf, diff_buf, + test->width, test->height, stride); if (pixels_changed) { - fprintf (stderr, " Error: %d pixels differ from reference image %s\n", + log_file = fopen (log_name, "a"); + fprintf (log_file, "Error: %d pixels differ from reference image %s\n", pixels_changed, ref_name); - write_png_argb32 (diff_buf, diff_name, test->width, test->height, stride); + 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 { - if (unlink (diff_name) < 0 && errno != ENOENT) { - fprintf (stderr, " Error: Cannot remove %s: %s\n", - diff_name, strerror (errno)); - ret = CAIRO_TEST_FAILURE; - goto BAIL; - } + xunlink (diff_name); } ret = CAIRO_TEST_SUCCESS; @@ -201,9 +206,42 @@ 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/cairo-test.h b/test/cairo-test.h index 58936d568..912ce8917 100644 --- a/test/cairo-test.h +++ b/test/cairo-test.h @@ -47,5 +47,9 @@ typedef void (*cairo_test_draw_function_t) (cairo_t *cr, int width, int height) 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 diff --git a/test/cairo_test.c b/test/cairo_test.c index 2364570a2..06f7672fd 100644 --- a/test/cairo_test.c +++ b/test/cairo_test.c @@ -32,10 +32,12 @@ #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" @@ -43,9 +45,10 @@ 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); @@ -54,53 +57,42 @@ xasprintf (char **strp, const char *fmt, ...) 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 */ } -/* 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. - */ -static int -image_diff (char *buf_a, char *buf_b, char *buf_diff, - int width, int height, int stride) +static void +xunlink (const char *pathname) { - 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) */ - } + if (unlink (pathname) < 0 && errno != ENOENT) { + fprintf (stderr, " Error: Cannot remove %s: %s\n", + pathname, strerror (errno)); + exit (1); } - - return total_pixels_changed; } cairo_test_status_t @@ -109,12 +101,14 @@ 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 *png_name, *ref_name, *diff_name; + 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 (); @@ -142,57 +136,68 @@ cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw) 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); - write_png_argb32 (png_buf, png_name, test->width, test->height, stride); + 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 (stderr, " Error: No reference image found: %s\n", ref_name); + fprintf (log_file, "Error: No reference image found: %s\n", ref_name); break; case READ_PNG_FILE_NOT_PNG: - fprintf (stderr, " Error: %s is not a png image\n", ref_name); + fprintf (log_file, "Error: %s is not a png image\n", ref_name); break; default: - fprintf (stderr, " Error: Failed to read %s\n", ref_name); + 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) { - fprintf (stderr, - " Error: Image size mismatch: (%dx%d) vs. (%dx%d)\n" - " for %s vs %s\n", + 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 = image_diff (png_buf, ref_buf, diff_buf, - test->width, test->height, stride); + pixels_changed = buffer_diff (png_buf, ref_buf, diff_buf, + test->width, test->height, stride); if (pixels_changed) { - fprintf (stderr, " Error: %d pixels differ from reference image %s\n", + log_file = fopen (log_name, "a"); + fprintf (log_file, "Error: %d pixels differ from reference image %s\n", pixels_changed, ref_name); - write_png_argb32 (diff_buf, diff_name, test->width, test->height, stride); + 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 { - if (unlink (diff_name) < 0 && errno != ENOENT) { - fprintf (stderr, " Error: Cannot remove %s: %s\n", - diff_name, strerror (errno)); - ret = CAIRO_TEST_FAILURE; - goto BAIL; - } + xunlink (diff_name); } ret = CAIRO_TEST_SUCCESS; @@ -201,9 +206,42 @@ 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/cairo_test.h b/test/cairo_test.h index 58936d568..912ce8917 100644 --- a/test/cairo_test.h +++ b/test/cairo_test.h @@ -47,5 +47,9 @@ typedef void (*cairo_test_draw_function_t) (cairo_t *cr, int width, int height) 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 diff --git a/test/clip-twice-ref.png b/test/clip-twice-ref.png Binary files differnew file mode 100644 index 000000000..ab0ae1aeb --- /dev/null +++ b/test/clip-twice-ref.png diff --git a/test/clip-twice.c b/test/clip-twice.c new file mode 100644 index 000000000..00215e62c --- /dev/null +++ b/test/clip-twice.c @@ -0,0 +1,72 @@ +/* + * 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_test.h" + +#define WIDTH 64 +#define HEIGHT 64 + +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 +}; + +static void +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_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); + + cairo_set_rgb_color (cr, 0, 0, 0.6); + + 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_fill (cr); +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/clip_twice-ref.png b/test/clip_twice-ref.png Binary files differnew file mode 100644 index 000000000..ab0ae1aeb --- /dev/null +++ b/test/clip_twice-ref.png diff --git a/test/clip_twice.c b/test/clip_twice.c new file mode 100644 index 000000000..00215e62c --- /dev/null +++ b/test/clip_twice.c @@ -0,0 +1,72 @@ +/* + * 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_test.h" + +#define WIDTH 64 +#define HEIGHT 64 + +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 +}; + +static void +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_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); + + cairo_set_rgb_color (cr, 0, 0, 0.6); + + 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_fill (cr); +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/coverage-ref.png b/test/coverage-ref.png Binary files differnew file mode 100644 index 000000000..9b7104057 --- /dev/null +++ b/test/coverage-ref.png diff --git a/test/coverage.c b/test/coverage.c new file mode 100644 index 000000000..00c86a1d5 --- /dev/null +++ b/test/coverage.c @@ -0,0 +1,182 @@ +/* + * 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 <math.h> +#include "cairo_test.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); +} + +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); +} + +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 (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); +} + +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_pattern (cr, pattern); + cairo_set_alpha (cr, 1); +} + +static void +set_translucent_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, 0.5); +} + +static void +draw_text (cairo_t *cr, int x, int y) +{ + cairo_rel_move_to (cr, 0, fontsize); + cairo_show_text (cr, "Aa"); +} + +static void +draw_polygon (cairo_t *cr, int x, int y) +{ + cairo_new_path (cr); + cairo_move_to (cr, x, y); + cairo_line_to (cr, x, y + HEIGHT); + cairo_line_to (cr, x + WIDTH / 2, y + 3 * HEIGHT / 4); + cairo_line_to (cr, x + WIDTH, y + HEIGHT); + cairo_line_to (cr, x + WIDTH, y); + cairo_line_to (cr, x + WIDTH / 2, y + HEIGHT / 4); + cairo_close_path (cr); + cairo_fill (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_polygon, +}; + +#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) + +static cairo_test_t test = { + "coverage", + "Various coverage test of cairo", + IMAGE_WIDTH, IMAGE_HEIGHT +}; + + +static void +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); + + 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); + + cairo_move_to (cr, x, y); + pattern_funcs[i] (cr, x, y); + draw_funcs[j] (cr, x, y); + + cairo_restore (cr); + + } + } +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/imagediff.c b/test/imagediff.c new file mode 100644 index 000000000..36962f11f --- /dev/null +++ b/test/imagediff.c @@ -0,0 +1,84 @@ +/* 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 <stdio.h> +#include <stdlib.h> + +#include "buffer_diff.h" +#include "read_png.h" +#include "write_png.h" +#include "xmalloc.h" + +int +main (int argc, char *argv[]) +{ + unsigned char *buffer_a; + unsigned int width_a, height_a, stride_a; + unsigned char *buffer_b; + unsigned int width_b, height_b, stride_b; + + unsigned char *buffer; + unsigned int width, height, stride; + int buffer_size, total_pixels_changed; + + if (argc < 2) { + fprintf (stderr, "Usage: %s image1.png image2.png\n", argv[0]); + fprintf (stderr, "Computes an output image designed to present a \"visual diff\" such that even\n"); + fprintf (stderr, "small errors in single pixels are readily apparent in the output.\n"); + fprintf (stderr, "The output image is written on stdout.\n"); + exit (1); + } + + read_png_argb32 (argv[1], &buffer_a, &width_a, &height_a, &stride_a); + read_png_argb32 (argv[2], &buffer_b, &width_b, &height_b, &stride_b); + + if ((width_a == width_b) && (height_a == height_b) && (stride_a == stride_b)) + { + width = width_a; + height = height_a; + stride = stride_a; + } else { + fprintf (stderr, "Error. Both images must be the same size\n"); + return 1; + } + + buffer_size = stride * height; + buffer = xmalloc (buffer_size); + + total_pixels_changed = buffer_diff (buffer_a, buffer_b, buffer, + width_a, height_a, stride_a); + + + if (total_pixels_changed) + fprintf (stderr, "Total pixels changed: %d\n", total_pixels_changed); + write_png_argb32 (buffer, stdout, width, height, stride); + + free (buffer); + + return 0; +} + + + diff --git a/test/linear-gradient-ref.png b/test/linear-gradient-ref.png Binary files differnew file mode 100644 index 000000000..77904144d --- /dev/null +++ b/test/linear-gradient-ref.png diff --git a/test/linear-gradient.c b/test/linear-gradient.c new file mode 100644 index 000000000..189b50065 --- /dev/null +++ b/test/linear-gradient.c @@ -0,0 +1,141 @@ +/* + * 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/linear_gradient-ref.png b/test/linear_gradient-ref.png Binary files differnew file mode 100644 index 000000000..77904144d --- /dev/null +++ b/test/linear_gradient-ref.png diff --git a/test/linear_gradient.c b/test/linear_gradient.c new file mode 100644 index 000000000..189b50065 --- /dev/null +++ b/test/linear_gradient.c @@ -0,0 +1,141 @@ +/* + * 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/pixman-rotate-ref.png b/test/pixman-rotate-ref.png Binary files differnew file mode 100644 index 000000000..7e47a4d8f --- /dev/null +++ b/test/pixman-rotate-ref.png diff --git a/test/pixman-rotate.c b/test/pixman-rotate.c new file mode 100644 index 000000000..6a64a9a77 --- /dev/null +++ b/test/pixman-rotate.c @@ -0,0 +1,78 @@ +#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/pixman_rotate-ref.png b/test/pixman_rotate-ref.png Binary files differnew file mode 100644 index 000000000..7e47a4d8f --- /dev/null +++ b/test/pixman_rotate-ref.png diff --git a/test/pixman_rotate.c b/test/pixman_rotate.c new file mode 100644 index 000000000..6a64a9a77 --- /dev/null +++ b/test/pixman_rotate.c @@ -0,0 +1,78 @@ +#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/read-png.c b/test/read-png.c index 23f91e831..e7e2a92ca 100644 --- a/test/read-png.c +++ b/test/read-png.c @@ -47,9 +47,9 @@ premultiply_data (png_structp png, unsigned char alpha = base[3]; unsigned long p; - red = (unsigned) red * (unsigned) alpha / 255; - green = (unsigned) green * (unsigned) alpha / 255; - blue = (unsigned) blue * (unsigned) alpha / 255; + 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)); } diff --git a/test/read_png.c b/test/read_png.c index 23f91e831..e7e2a92ca 100644 --- a/test/read_png.c +++ b/test/read_png.c @@ -47,9 +47,9 @@ premultiply_data (png_structp png, unsigned char alpha = base[3]; unsigned long p; - red = (unsigned) red * (unsigned) alpha / 255; - green = (unsigned) green * (unsigned) alpha / 255; - blue = (unsigned) blue * (unsigned) alpha / 255; + 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)); } diff --git a/test/romedalen.png b/test/romedalen.png Binary files differnew file mode 100644 index 000000000..0c41eb0cf --- /dev/null +++ b/test/romedalen.png diff --git a/test/testsvg b/test/testsvg new file mode 100755 index 000000000..520442948 --- /dev/null +++ b/test/testsvg @@ -0,0 +1,51 @@ +#!/bin/sh + +IMAGEDIFF=./imagediff + +OUTDIR=testsvg-output +REFDIR=testsvg-reference +DIFFDIR=testsvg-diff +IMAGELIST=testsvg-imagelist + +if [ $# -lt 1 ]; then + argv0=`basename $0` + echo "Usage: $argv0 file.svg [...]" >&2 + exit 1; +fi + +mkdir -p $OUTDIR +mkdir -p $DIFFDIR +rm -f $IMAGELIST + +err=0 +for svg in $@; do + svgbase=`basename $svg` + png=${svgbase/\.svg/.png} + outpng=$OUTDIR/$png + refpng=$REFDIR/$png + diffpng=$DIFFDIR/$png +# if xsvg $svg -p $outpng ; then + if svg2png $svg $outpng ; then + if [ -e $refpng ]; then + if diff $refpng $outpng > /dev/null; then + echo "Rendering of $svg matches." >&2 + else + echo "ERROR: Rendering of $svg differs from reference image." >&2 + $IMAGEDIFF $refpng $outpng > $diffpng + echo $refpng $outpng $diffpng >> $IMAGELIST + err=$(($err+1)) + fi + else + echo "WARNING: No reference file found for $svg (looked in $refpng)" >&2 + fi + else + echo "ERROR: Failed to render $svg" >&2 + err=$(($err+1)) + fi +done + +if [ $err -gt 0 ] ; then + echo "Differences found in $err renderings." +else + echo "All renderings matched reference images." +fi diff --git a/test/write-png.c b/test/write-png.c index 2ea29d062..0ff5bcd3a 100644 --- a/test/write-png.c +++ b/test/write-png.c @@ -1,5 +1,5 @@ /* - * Copyright © 2003 USC, Information Sciences Institute + * 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 @@ -22,7 +22,7 @@ * 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> + * Author: Carl D. Worth <cworth@cworth.org> */ #include <stdio.h> @@ -46,26 +46,24 @@ unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data) 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[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, char *filename, +write_png_argb32 (char *buffer, FILE *file, int width, int height, int stride) { - FILE *f; int i; png_struct *png; png_info *info; png_byte **rows; png_color_16 white; - f = fopen (filename, "w"); rows = malloc (height * sizeof(png_byte*)); for (i = 0; i < height; i++) { @@ -75,7 +73,7 @@ write_png_argb32 (char *buffer, char *filename, png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct (png); - png_init_io (png, f); + png_init_io (png, file); png_set_IHDR (png, info, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, @@ -98,5 +96,4 @@ write_png_argb32 (char *buffer, char *filename, png_destroy_write_struct (&png, &info); free (rows); - fclose (f); } diff --git a/test/write-png.h b/test/write-png.h index a71ca6a32..fe0e92b20 100644 --- a/test/write-png.h +++ b/test/write-png.h @@ -1,5 +1,5 @@ /* - * Copyright © 2003 USC, Information Sciences Institute + * 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 @@ -29,7 +29,7 @@ #define WRITE_PNG_H void -write_png_argb32 (char *buffer, char *filename, +write_png_argb32 (char *buffer, FILE * file, int width, int height, int stride); #endif diff --git a/test/write_png.c b/test/write_png.c index 2ea29d062..0ff5bcd3a 100644 --- a/test/write_png.c +++ b/test/write_png.c @@ -1,5 +1,5 @@ /* - * Copyright © 2003 USC, Information Sciences Institute + * 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 @@ -22,7 +22,7 @@ * 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> + * Author: Carl D. Worth <cworth@cworth.org> */ #include <stdio.h> @@ -46,26 +46,24 @@ unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data) 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[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, char *filename, +write_png_argb32 (char *buffer, FILE *file, int width, int height, int stride) { - FILE *f; int i; png_struct *png; png_info *info; png_byte **rows; png_color_16 white; - f = fopen (filename, "w"); rows = malloc (height * sizeof(png_byte*)); for (i = 0; i < height; i++) { @@ -75,7 +73,7 @@ write_png_argb32 (char *buffer, char *filename, png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct (png); - png_init_io (png, f); + png_init_io (png, file); png_set_IHDR (png, info, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, @@ -98,5 +96,4 @@ write_png_argb32 (char *buffer, char *filename, png_destroy_write_struct (&png, &info); free (rows); - fclose (f); } diff --git a/test/write_png.h b/test/write_png.h index a71ca6a32..fe0e92b20 100644 --- a/test/write_png.h +++ b/test/write_png.h @@ -1,5 +1,5 @@ /* - * Copyright © 2003 USC, Information Sciences Institute + * 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 @@ -29,7 +29,7 @@ #define WRITE_PNG_H void -write_png_argb32 (char *buffer, char *filename, +write_png_argb32 (char *buffer, FILE * file, int width, int height, int stride); #endif |