diff options
author | Carl Worth <cworth@cworth.org> | 2006-02-13 16:47:50 -0800 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2006-02-13 16:47:50 -0800 |
commit | 1049c3c077c6000e25001a1a55e5fc48cf12a61e (patch) | |
tree | 33b01fadaed6ea549babbe9d2fb09ca68661ad70 | |
parent | 73c2eada0d0c80763f0a953cce7fc144f7931fa1 (diff) | |
parent | 4bec3d6af49f9a720121617819700bc700ba5951 (diff) |
Remove pixman from RELEASE_0_9_0RELEASE_0_9_0
81 files changed, 5005 insertions, 2190 deletions
@@ -5,50 +5,11 @@ that display. -- -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. - --- - -cairo_font_set_transform should be renamed cairo_font_set_matrix -cairo_font_current_transform should be renamed cairo_font_get_matrix - --- - -Alexis Georges reports a segfault on AMD64 with a simple program, -(that works in a 32bit chroot). - --- - -The caches need to have some locking (see: [cairo] Static caches and thread-safety) - --- - -Scaling of surface patterns is all broken, (try xsvg -gradPatt-pattern-BE-07.svg and zoom in and out). - --- - -centi_unfinished.svg has big black portions when drawn with svg2png, -(but not when drawn with xsvg). - --- - The caches need to be invalidated at font destruction time. -- @@ -96,24 +57,6 @@ confirmed on a quite default install of debian unstable. -- -cairo_scale_font modifies objects that the user expects to not change. For example: - - cairo_font_t *font; - - cairo_select_font (cr, "fixed", 0, 0); - font = cairo_current_font (cr); - cairo_scale_font (cr, 10); - cairo_show_text (cr, "all is good"); - cairo_set_font (cr, font); - cairo_scale_font (cr, 10); - cairo_show_text (cr, "WAY TOO BIG!!); - -We could fix this by not storing the scale in the font object. Or -maybe we could just force the size to its default after set_font. Need -to think about this in more detail. - --- - cairo_show_text is not updating the current point by the string's advance values. -- @@ -128,34 +71,9 @@ places. -- -Patterns are broken in various ways. The SVG test case demonstrates -some regressions, so something has changed in cairo. Also, -transformation plus repeat doesn't work in either Xrender or -libpixman, (nor in glitz?). - --- - font-size="0" in an SVG file does very bad things. -- -move_to_show_surface (see cairo/test): - - * 2004-10-25 Carl Worth <cworth@cworth.org> - * - * It looks like cairo_show_surface has no effect if it follows a - * call to cairo_move_to to any coordinate other than 0,0. A little - * bit of poking around suggests this isn't a regression, (at least - * not since the last pixman snapshot). - --- - cairo falls over with XFree86 4.2 (probably braindead depth handling somewhere). - --- - -The caches abort when asked for a too-large item, (should be possible -to trigger by asking for a giant font, "cairo_scale_font (cr, 2000)" -perhaps). Even if the caches don't want to hold them, we need to be -able to allocate these objects. @@ -1,3 +1,719 @@ +2005-08-08 Carl Worth <cworth@cworth.org> + + * NEWS: Added notes for release 0.9.0. + + * configure.in: Increment CAIRO_VERSION to 0.9.0. Increment + LT_CURRENT to 2 to mark the beginning of proper soname management. + +2005-08-08 Carl Worth <cworth@cworth.org> + + * src/Makefile.am (libcairo_la_SOURCES): Add missing cairo-debug.h + which was hold up make distcheck. + +2005-08-08 Carl Worth <cworth@cworth.org> + + * test/Makefile.am (EXTRA_DIST): Fix typo that was holding up make + distcheck from working. + +2005-08-08 Billy Biggs <vektor@dumbterm.net> + + * src/cairo-path-data-private.h: Declare _cairo_path_nil as extern. + +2005-08-08 Billy Biggs <vektor@dumbterm.net> + + reviewed by: cworth, otaylor + + * src/cairo.c: (cairo_set_antialias), (cairo_get_antialias): + * src/cairo.h: Add a new API for disabling antialiasing of shapes + drawn by cairo. This is a hint and is not supported by all backends. + + * src/cairoint.h: + * src/cairo-gstate-private.h: + * src/cairo-gstate.c: (_cairo_gstate_init), + (_composite_traps_draw_func), + (_cairo_surface_clip_and_composite_trapezoids), + (_cairo_gstate_clip_and_composite_trapezoids), + (_cairo_gstate_clip), (_cairo_gstate_set_antialias), + (_cairo_gstate_get_antialias): Store the antialiasing mode in the + gstate and pass it to the backend for trapezoid rendering and for + clipping. + + * src/cairo-clip-private.h: + * src/cairo-clip.c: (_cairo_clip_intersect_path), + (_cairo_clip_intersect_mask), (_cairo_clip_clip): Pass the + antialiasing parameter down to the backend where appropriate. + + * src/cairo-surface.c: (_fallback_composite_trapezoids), + (_cairo_surface_composite_trapezoids), (_cairo_surface_reset_clip), + (_cairo_surface_intersect_clip_path), + (_cairo_surface_set_clip_path_recursive), + (_cairo_surface_set_clip_path): Pass the antialiasing parameter down + to the backend where appropriate. + + * src/cairo-image-surface.c: + (_cairo_image_surface_composite_trapezoids): Add support for A1 format + trapezoid rendering, and remove the _create_mask_image function, + creating a temporary image from memory we allocate and clear. + + * src/cairo-xcb-surface.c: + (_cairo_xcb_surface_composite_trapezoids): Support A1 masks to disable + antialiasing using the RENDER extension when requested. + + * src/cairo-xlib-surface.c: (_create_trapezoid_mask), + (_cairo_xlib_surface_composite_trapezoids): Support A1 masks to disable + antialiasing using the RENDER extension when requested. + + * src/cairo-meta-surface-private.h: + * src/cairo-meta-surface.c: + (_cairo_meta_surface_composite_trapezoids), + (_cairo_meta_surface_intersect_clip_path), + (_cairo_meta_surface_replay): Blindly pass through the antialising + parameter. + + * src/cairo-glitz-surface.c: + (_cairo_glitz_surface_composite_trapezoids): + * src/cairo-pdf-surface.c: + (_cairo_pdf_surface_composite_trapezoids), + (_cairo_pdf_surface_intersect_clip_path): + * src/cairo-ps-surface.c: (_cairo_ps_surface_composite_trapezoids), + (_cairo_ps_surface_intersect_clip_path), + (_ps_output_composite_trapezoids), + (_ps_output_intersect_clip_path): Add the antialiasing parameter but + don't support it. + + * test/Makefile.am: + * test/unantialiased-shapes-ref.png: + * test/unantialiased-shapes.c: (big_star_path), (draw), (main): + Add a test case and a reference image from the latest libpixman. + + * doc/public/tmpl/cairo-font.sgml: + * doc/public/tmpl/cairo.sgml: + * doc/public/cairo-sections.txt: Add the new antialiasing disabling API to + the docs. + + * TODO: Update progress on a parameter to disable antialiasing. + +2005-08-08 Carl Worth <cworth@cworth.org> + + * test/.cvsignore: Ignore clip-operator and unbounded-operator. + +2005-08-08 Carl Worth <cworth@cworth.org> + + * RELEASING: Fix gnome-announce-list address. + +2005-08-08 Owen Taylor <otaylor@redhat.com> + + * src/cairo-xlib-surface.c (_xlib_glyphset_cache_destroy_entry): + Don't free the glyph if the entry doesn't have a glyph. + (Maybe #3909, Carlos Garnacho Parro) + +2005-08-08 Carl Worth <cworth@cworth.org> + + * src/cairo-gstate.c: (_cairo_operator_bounded): Add a return + value after ASSERT_NOT_REACHED to quiet an anxious compiler. + +2005-08-08 Owen Taylor <otaylor@redhat.com> + + * src/cairo-gstate.c: (_cairo_surface_clip_and_composite_trapezoids): + Fix accidentally committed line. + +2005-08-08 Kristian Høgsberg <krh@redhat.com> + + * src/cairo-surface.c (_cairo_surface_set_clip_path): Update doc + comment. + +2005-08-08 Owen Taylor <otaylor@redhat.com> + + * src/cairo-gstate.c (_cairo_operator_bounded): Add a function to test + whether a cairo_operator_t is bounded (does nothing for 0 src/mask) + + * src/cairo-surface.c (_cairo_surface_composite_fixup_unbounded) cairoint.h: + Add a helper function to take clearing areas that are outside the source/mask + but are cleared by unbounded operations. + + * src/cairo-image-surface.c (_cairo_image_surface_composite) + src/cairo-xlib-surface.c (_cairo_xlib_surface_composite): Use + _cairo_surface_composite_fixup_unbounded() as needed. + + * src/cairo-image-surface.c src/cairint.h: Keep track of whether the surface + has a clip or not ... we need this for determining when we can bypass + an intermediate mask for composite_trapezoids(). + + * src/cairo-image-surface.c (_cairo_image_surface_composite_trapezoids): + Create an intermediate mask of the right size with pixman_add_trapezoids() + and composite that. + + * src/cairo-xlib-surface.c (_cairo_xlib_surface_composite_trapezoids): + When rendering with an unbounded operator, create the intermediate mask + ourselves and render with ADD to that, then composite the result. + + * src/cairo-ft-font.c (_cairo_ft_scaled_font_show_glyphs): Create an + intermediate surface the size of the extents, render the glyphs to that + then composite the results. + + * src/cairo-xlib-surface.c (glyphset_cache_entry_t): Add the size of the glyph + + * src/cairo-xlib-surface.c (_show_glyphs_fixup_unbounded): Compute the size + of the glyph mask, then use _cairo_surface_composite_fixup_unbounded(). + + * src/cairo-xlib-surface.c (_cairo_xlib_surface_show_glyphs32): Use the right + mask format. (Unrelated bugfix) + + * src/cairo-gstate.c (_cairo_gstate_clip_and_composite): New function taking + a drawing function as a parameter to encapsulate shared logic between + compositing trapezoid, glyphs, and masks. + + * src/cairo-gstate.c (_cairo_gstate_mask, + _cairo_surface_clip_and_composite_trapezoids, _cairo_gstate_show_glyphs): + Use _cairo_gstate_clip_and_composite(). Also fix extents computations for + unbounded operators. + + * src/cairo-clip.c src/cairo-clip-private.h (_cairo_clip_combine_to_surface): + Add the destination as an extra parameter to allow combining to an intermediate + surface. + + * tests/unbounded-operator.c tests/Makefile.am: Add a test for the + operation of the 6 unbounded operators against different shapes. + + * tests/clip-operator.c tests/Makefile.am: Add a test that tests + surface clipping with different shapes against all the operators. + + * test/composite-integer-translate-over-repeat.c (draw): Make use OVER + like the name and description. With fixed semantics, SOURCE does something + different. + +2005-08-06 Carl Worth <cworth@cworth.org> + + * BUGS: Remove several bugs that have been fixed. + + * ROADMAP: Slip group support off of the 1.0 roadmap. Update + status of clipping work which otaylor is working on. + + * TODO: Update for progress on cairo_surface_mark_dirty + (committed), non-antialiased rendering (patch), cairo_arc_to + (patch), consistent error handling (committed), cairo_content_t + (committed). Remove details for some completed items. + + * src/cairo-gstate.c (_cairo_gstate_set_font_face): Don't crash if + font_face is NULL, (this is a documented mechanism for returning + to the default font_face). + +2005-08-06 Carl Worth <cworth@cworth.org> + + * src/cairo.c (cairo_get_font_face): Fix to return + &_cairo_font_face_nil instead of NULL on error. + +2005-08-06 Jeff Muizelaar <jeff@infidigm.net> + + * test/a8-mask.c: (main): Give reason for failure. + +2005-08-06 Owen Taylor <otaylor@redhat.com> + + * src/cairo-win32-font.c (_cairo_win32_scaled_font_show_glyphs): + Remove a non-sensical XXX that crept in at some point; for + a solid color, there is no difference between premultiplied + and non-premultiplied colors. + +2005-08-06 Carl Worth <cworth@cworth.org> + + * src/cairo-ft-font.c: (_cairo_ft_scaled_font_create), + (_cairo_ft_scaled_font_create_toy), + (_cairo_ft_scaled_font_glyph_extents), + (_cairo_ft_font_face_scaled_font_create): Fix up some stale + comments. Rename _cairo_ft_scaled_font_create_for_unscaled to its + proper name of _cairo_ft_scaled_font_create (which is available + now that _cairo_ft_scaled_font_create_toy has its correct + name). Also prefer 'scaled_font' over 'f' as an identifier. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairo-ft-font.c: (_cairo_ft_unscaled_font_init), + (_cairo_ft_unscaled_font_create_from_face), + (_cairo_ft_unscaled_font_create_from_filename): Unify + initialization for _cairo_ft_unscaled_font_create_from_face and + _cairo_ft_unscaled_font_create_from_filename through new + _cairo_ft_unscaled_font_init. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairo-ft-font.c: (_cairo_ft_font_face_create): Rename + _ft_font_face_backend to be preoperly namespaced as + _cairo_ft_font_face_backend. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairo-ft-font.c: (_cairo_ft_font_face_destroy), + (_cairo_ft_font_face_create): Rename cairo_ft_font_face->next_face + to next. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: Include cairo-hash-private.h. + + * src/Makefile.am (libcairo_la_SOURCES): Add cairo-hash.c and + cairo-hash-private.h since we're actually going to start using + them now. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairo-gstate.c: (_cairo_gstate_set_font_face): Simplify the + implementation by taking advantage of the fact that destroy and + reference are safe for NULL, and that reference returns its + argument. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairo-gstate.c: (_cairo_gstate_translate), + (_cairo_gstate_scale), (_cairo_gstate_rotate), + (_cairo_gstate_transform), (_cairo_gstate_set_matrix), + (_cairo_gstate_identity_matrix), (_cairo_gstate_unset_scaled_font), + (_cairo_gstate_set_font_size), (_cairo_gstate_set_font_matrix), + (_cairo_gstate_set_font_options), + (_cairo_gstate_ensure_scaled_font), + (_cairo_gstate_get_font_extents), (_cairo_gstate_text_to_glyphs), + (_cairo_gstate_set_font_face), (_cairo_gstate_glyph_extents), + (_cairo_gstate_show_glyphs), (_cairo_gstate_glyph_path): + Rename two functions: + + _cairo_gstate_unset_font -> _cairo_gstate_unset_scaled_font + _cairo_gstate_ensure_font -> _cairo_gstate_ensure_scaled_font + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: Entagle the cairo_unscaled_font_t typedef. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: Rename font_face_backend->create_font to + scaled_font_create. Group the scaled_font prototypes together. A + little more simple -> toy renaming. + + * src/cairo-font.c: (_cairo_toy_font_face_create_from_cache_key), + (_cairo_toy_font_face_destroy), + (_cairo_toy_font_face_create): + * src/cairo-gstate.c: (_cairo_gstate_select_font_face), + (_cairo_gstate_ensure_font_face): + A little more simple -> toy renaming. + + * src/cairo-font.c: (_cairo_toy_font_face_scaled_font_create), + (_cairo_inner_font_cache_create_entry): + * src/cairo-ft-font.c: (_cairo_ft_font_face_scaled_font_create): + * src/cairo-win32-font.c: (_cairo_win32_font_face_scaled_font_create): + Track rename of font_face_backend->scaled_font_create. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: Rather gratuitous (though mostly harmless) + whitespace changes for font backend tables. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairo.c: Document the implicit closing of sub-paths for + cairo_fill and cairo_fill_preserve. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: Rename parameters to scalend_font_backend from + font to scaled_font. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: Rename scaled_font_backend->destroy to the more + accurate fini, (since it frees only the dependent data within the + scaled_font and not the scaled_font itself). + + * src/cairo-atsui-font.c: (_cairo_atsui_font_fini): + * src/cairo-font.c: (cairo_scaled_font_destroy): + * src/cairo-ft-font.c: (_cairo_ft_scaled_font_fini): + * src/cairo-win32-font.c: (_cairo_win32_scaled_font_fini): + Track rename of scaled_font_backend->fini. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairoint.h: Rename scaled_font_backend->create to + create_toy. Move declaration of cairo_simple_font_face_t from + cairo_font.c to cairoint.h and rename it + cairo_toy_font_face_t. Rework create_toy to accept a + cairo_toy_font_face_t rather than separate family, slant, and + weight. + + * src/cairo-atsui-font.c: (_cairo_atsui_font_create_toy): + * src/cairo-ft-font.c: (_cairo_ft_scaled_font_create_toy): + * src/cairo-win32-font.c: (_cairo_win32_scaled_font_create_toy): + Track change in create_toy interface. + + * src/cairo-font.c: (_cairo_toy_font_face_create_from_cache_key), + (_cairo_simple_font_cache_create_entry), + (_cairo_simple_font_face_destroy), + (_cairo_simple_font_face_create_font): + Partial rename of simple->toy. It's not complete as this is a step + in the process of merging in a large patch of mine which actually + removes most of the affected code. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * test/.cvsignore: ignore a8-mask + +2005-08-05 Carl Worth <cworth@cworth.org> + + * test/a8-mask.c (draw): Patch memory leaks. + +2005-08-05 Jeff Muizelaar <jeff@infidigm.net> + + * test/Makefile.am: + * test/a8-mask-ref.png: + * test/a8-mask.c: (draw), (main): + Add a test case for CAIRO_FORMAT_A8 masks that fails with + libpixman. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * autogen.sh (automake_min_vers): Bump automake_min_vers up to 1.7 + since we clearly don't work with 1.4 anymore. + +2005-08-05 Jeff Muizelaar <jeff@infidigm.net> + + * test/xlib-surface.c: (do_test): use the newly added + buffer_diff_noalpha for comparing buffers of + CAIRO_FORMAT_RGB24. + +2005-08-05 Jeff Muizelaar <jeff@infidigm.net> + + * test/buffer-diff.c: (buffer_diff_core), (buffer_diff), + (buffer_diff_noalpha): + * test/buffer-diff.h: rewrite buffer_diff to be endian safe + and add a new fuction buffer_diff_noalpha + +2005-08-05 Carl Worth <cworth@cworth.org> + + * doc/public/cairo-sections.txt: Remove CAIRO_BEGIN_DECLS and + CAIRO_END_DECLS which don't belong here. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * test/surface-finish-twice.c (draw): Remove unused variable. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * doc/public/Makefile.am: Ignore cairo-clip-private.h. + + * doc/public/cairo-docs.xml: Drop non-existent cairo-atsui.xml. + + * src/cairo-font.c: Fix misnamed parameters in comment blocks. + + * test/cairo-test.c: Include config.h so HAVE_UNISTD_H gets + picked up as necessary. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * doc/public/Makefile.am (IGNORE_HFILES): Ignore + cairo-clip-private.h. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * doc/public/cairo-sections.txt: Add some missing declarations to + the appropriate sections. + + * doc/public/tmpl/cairo-font.sgml: + * doc/public/tmpl/cairo-surface.sgml: + * doc/public/tmpl/cairo-xlib.sgml: + * doc/public/tmpl/cairo.sgml: churn + + * src/cairo-path-data-private.h: Rename cairo_path_nil to + _cairo_path_nil since it may be exported, and tag it cairo_private + to try to avoid exporting it. Qualify it as const well. + + * src/cairo-path-data.c: (_cairo_path_data_create_real): + * src/cairo.c: (cairo_copy_path), (cairo_copy_path_flat): + Track new name of _cairo_path_nil and cast away the const as + required. + +2005-08-05 Carl Worth <cworth@cworth.org> + + * src/cairo-arc.c: + * src/cairo-matrix.c: Remove include of math.h since cairoint.h + does it more carefully, (for annoying platforms for which just + including math.h without extra defines is not enough). + + * src/cairo.c: Replace Cairo with cairo. + + * test/buffer-diff.c: Include config.h so HAVE_UNISTD_H gets + picked up as necessary. + + * test/cairo-test.c: Fix non-UTF-8 copyright symbol. + +2005-08-05 Carl Worth <cworth@cworth.org> + + Patch from John Ehresman <jpe@wingide.com> to aid win32 + compilation: + + * src/cairo-output-stream.c: Define snprintf as _snprintf when + under the influence of _MSC_VER. + + * test/read-png.c: (read_png_argb32): + * src/cairo-wideint.h: Define int32_t and friends as __int32 and + friends when under the influence of _MSC_VER. + + * test/buffer-diff.c: + * test/cairo-test.c: Make include of unistd.h conditional on + HAVE_UNISTD_H. + +2005-08-05 Kristian Høgsberg <krh@redhat.com> + + Patch from Adrian Johnson <ajohnson@redneon.com> + + * src/cairo-font-subset.c (cairo_pdf_ft_font_write_glyf_table) + (cairo_pdf_ft_font_remap_composite_glyph): Remap composite glyps + to use subset font glyph indices. + +2005-08-05 Kristian Høgsberg <krh@redhat.com> + + Reviewed by: otaylor + + * src/Makefile.am: + * src/cairo-clip-private.h: + * src/cairo-clip.c: New files. Move code for manipulating + cairo_clip_t out into cairo_clip_* functions and put them in + cairo-clip.c. + + * src/cairo-gstate-private.h: + * src/cairo-gstate.c: Rewrite to use new cairo_clip_t functions + for manipulating the clip state, change the + clip_and_composite_trapezoids call tree to use cairo_clip_t + instead of cairo_gstate_t. + + * src/cairo-meta-surface.c: Use new cairo_clip_t function to + maintain clip state while replaying. + + * src/cairo-path-fill.c: (_cairo_filler_init), + (_cairo_filler_curve_to), (_cairo_path_fixed_fill_to_traps): Pass + fill rule and tolerance directly, to break gstate dependency. + + * src/cairo-surface.c: (_cairo_surface_set_clip): New function. + Set the clip for a surface as specified by the cairo_clip_t. + + * src/cairo-traps.c: (_cairo_traps_translate): Move + translate_traps() from cairo-gstate.c to here and rename it. + +2005-08-04 Kristian Høgsberg <krh@redhat.com> + + * src/cairo-font.c: (cairo_font_face_reference), + (_cairo_unscaled_font_reference), (cairo_scaled_font_reference): + * src/cairo-gstate.c: (_cairo_clip_path_reference): + * src/cairo-pattern.c: (cairo_pattern_reference): + * src/cairo-pdf-surface.c: (_cairo_pdf_document_reference): + * src/cairo-surface.c: (cairo_surface_reference): + * src/cairo.c: (cairo_reference): + * src/cairo.h: + * src/cairoint.h: + Change *_reference() functions to return the object being + referenced. + +2005-07-29 T Rowley <tim.rowley@gmail.com> + + Reviewed by: otaylor + + * src/cairo-xlib-surface.c ( _categorize_composite_operation): + Check for render bug involving repeated patterns with a general + transform matrix. + +2005-08-04 Carl Worth <cworth@cworth.org> + + Originally 2005-07-13 Carl Worth <cworth@cworth.org> + + Reviewed by: otaylor + + * src/cairo-ft-private.h: Export opaque cairo_ft_unscaled_font_t + and change _cairo_ft_unscaled_font_[un]lock_face to accept + cairo_ft_unscaled_font_t rather than cairo_unscaled_font_t. + + * src/cairo-font-subset.c: (_cairo_font_subset_create), + (cairo_pdf_ft_font_generate): Cast explicitly to + cairo_ft_unscaled_font_t to track change in prototype of + _cairo_ft_unscaled_font_[un]lock_face. + + * src/cairo-ft-font.c: Lots of renaming to use consistent + namespacing: + + ft_font_transform_t -> cairo_ft_font_transform_t + ft_font_face_t -> cairo_ft_font_face_t + ft_unscaled_font_t -> cairo_ft_unscaled_font_t + + Add missing _cairo prefix to many functions. + + Disambiguate _ft_scaled_font_create and + _cairo_ft_scaled_font_create by renaming the former to + _cairo_ft_scaled_font_create_for_unscaled. + +2005-08-03 Carl Worth <cworth@cworth.org> + + Fix for bug #3951: + + * configure.in: Add new _CHECK_FUNCS_WITH_FLAGS to abstract out + the pain of temporarily setting flags for AC_CHECK_FUNCS. Use this + to check for the existence of FcFini. + + * test/cairo-test.c: (cairo_test_expecting): Make call to FcFini + conditional on HAVE_FCFINI. + + * test/text-cache-crash.c: (main): Remove stale comment about + cleaning up memory which is now handled by cairo-test.c. + +2005-08-01 Owen Taylor <otaylor@redhat.com> + + reviewed by: cworth + + * src/cairo-gstate.c src/cairo-gstate-private.h: Store the + inverse CTM at the time of cairo_gstate_set_source() to + "lock" the user space matrix. + + * src/cairo-gstate.c: Move the source pattern transformation + to the outside of _cairo_gstate_clip_and_composite_trapezoids() + instead of doing it at the leaves. + + * test/source-surface-scale-paint.c: Change size of output + surface for aesthetics. + + * test/source-surface-scale-paint-ref.png: Updated to correspond + to the current definition. + + * test/Makefile.am (XFAIL_TESTS): + Remove source-surface-scale-paint. + +2005-08-01 Carl Worth <cworth@cworth.org> + + * src/cairo-debug.h: New public header file. + + * src/cairo-debug.c: (cairo_debug_reset_static_data): New function + to reset all static data (eg. caches) to their initial state. + + * Makefile.am: Fix check-valgrind target to depend on the 'all' + target. + + * configure.in: Add check for a new, proposed, XrmFinalize + function. + + * src/Makefile.am: Add cairo-debug.c. + + * src/cairo.h: + * src/cairo-features.h.in: Move the definition of + CAIRO_BEGIN_DECLS to cairo-features.h so that it can be shared + between public header files, and so that it doesn't clutter + cairo.h + + * src/cairoint.h: + * src/cairo-font.c: (_get_global_simple_cache), + (_get_outer_font_cache), (_get_inner_font_cache), + (_cairo_unlock_global_image_glyph_cache), + (_cairo_font_reset_static_data): + * src/cairo-ft-font.c: (_cairo_ft_font_reset_static_data): + * src/cairo-xlib-screen.c: (_cairo_xlib_close_display), + (_cairo_xlib_screen_info_reset), + (_cairo_xlib_screen_reset_static_data): + * src/cairo-xlib-surface.c: (_unlock_xlib_glyphset_caches), + (_destroy_glyphset_cache_recurse), + (_cairo_xlib_surface_reset_static_data): Implement + reset_static_data in all modules as required. + + * test/xlib-surface.c: (main): + * test/cairo-test.h: + * test/cairo-test.c: (cairo_test_for_target), + (cairo_test_expecting): Call cairo_debug_reset_static_data and + FcFini so that we can have all tests be valgrind-clean with + respect to memory leaks and still-reachable data. + +2005-08-01 Owen Taylor <otaylor@redhat.com> + + * src/cairo.h src/cairoint.h src/cairo-surface.c: + Add cairo_mark_dirty[_rectangle]() and cairo_flush() for + + * src/cairo-win32-surface.c: Implement a cairo_flush() + that restores the original clip. Also restore the original + flush when a surface is finished. + + * ROADMAP: Check off the item. + +2005-07-31 Billy Biggs <vektor@dumbterm.net> + + reviewed by: keithp + + * src/cairo-ft-font.c: (_ft_unscaled_font_set_scale): Support + versions of freetype without exact FT_Bitmap_Size.x/y_ppem + values by using the pixel width and height values instead. + + * configure.in: Add a check for FT_Bitmap_Size.y_ppem. + +2005-07-31 Billy Biggs <vektor@dumbterm.net> + + * src/cairo-quartz-surface.c: (cairo_quartz_surface_create): + Cast away the const on the nil surface to avoid a compiler warning. + +2005-07-31 Billy Biggs <vektor@dumbterm.net> + + * src/cairo-atsui-font.c: (_cairo_atsui_font_create): Pass the + options down to the scaled font object to keep things compiling. + +2005-07-30 Keith Packard <keithp@keithp.com> + + * src/cairo-wideint.c: (_cairo_int32x32_64_mul), + (_cairo_uint64_divrem), (_cairo_uint128_divrem): + * src/cairo-wideint.h: + + Replace wide integer divide algorithms with + trivial bit-at-a-time code. Original code was + of unclear provenance, this new code is + completely different. + +2005-07-29 Carl Worth <cworth@cworth.org> + + * ROADMAP: Remove completed 0.6 tasks. Add cairo_surface_flush to + the cairo_surface_mark_dirty task. + +2005-07-29 T Rowley <tim.rowley@gmail.com> + + * src/cairo-atsui-font.c ( _cairo_atsui_font_create): + src/cairo-quartz-surface.c (_cairo_quartz_surface_acquire_dest_image): + Minor updates to keep quartz backend limping along. + +2005-07-29 Owen Taylor <otaylor@redhat.com> + + * src/cairo-font.c src/cairo-ft-font.c src/cairo-win32-font.c + src/cairoint.h: Move the font options into the base + cairo_scaled_font_t object so that we have them available + to use when we are removing a scaled font from the cache. + (http://bugzilla.gnome.org/show_bug.cgi?id=311299, + Ali Akcaagac, Behdad Esfahbod) + +2005-07-28 Carl Worth <cworth@cworth.org> + + * src/cairo-gstate.c: (_cairo_gstate_mask): Run the mask pattern + through the CTM in the same way as the source pattern. This fixes + the bug demonstrated by the mask-ctm and mask-surface-ctm tests so + they should no longer fail. + +2005-07-28 Carl Worth <cworth@cworth.org> + + * test/.cvsignore: + * test/Makefile.am: + * test/mask-ctm-ref.png: + * test/mask-ctm.c: (draw), (main): + * test/mask-surface-ctm-ref.png: + * test/mask-surface-ctm.c: (draw), (main): Add two new tests: + mask-ctm + mask-surface-ctm + demonstrating that masks are not currently being modified by the + CTM. + +2005-07-28 Carl Worth <cworth@cworth.org> + + * RELEASING: CC gnome-announce-list@gnome.org on cairo release + announcements. + +2005-07-28 Carl Worth <cworth@cworth.org> + + * configure.in: Add -head to CAIRO_VERSION after tagging with + SNAPSHOT_0_6_0. + 2005-07-28 Carl Worth <cworth@cworth.org> * NEWS: Added notes for snapshot 0.6.0 @@ -550,6 +1266,19 @@ 2005-07-18 Carl Worth <cworth@cworth.org> + * test/.valgrind-suppressions: Add valgrind suppressions for + libpng/libz use of uninitialized data. There are clearly bugs here + that are not cairo's fault as zeroing the buffer before writing + the png image actually causes more errors(!). And, notably, + setting all the data to random bytes usually makes the errors go + away. + + * test/Makefile.am: Change the check-valgrind target to include + the .valgrind-suppresions file and to tee output into + valgrind.log. + +2005-07-18 Carl Worth <cworth@cworth.org> + * configure.in: Add -head to CAIRO_VERSION after tagging with SNAPSHOT_0_5_2. diff --git a/Makefile.am b/Makefile.am index c2a9965a..e375b1b1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,6 +15,9 @@ EXTRA_DIST = \ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = cairo.pc +check-valgrind: all + $(MAKE) -C test check-valgrind + DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc # Some custom targets to make it easier to release things. @@ -1,3 +1,80 @@ +Release 0.9.0 (2005-08-08 Carl Worth <cworth@cworth.org>) +========================================================= +API additions +------------- + + * Add a new function call to set the current antialiasing mode in the + graphics state: + + cairo_set_antialias + + This call accepts the same modes recently added for font options + (NONE or GRAY) but affects the rendering of geometry other than + text. The intent of this call is to enable more precise control of + which pixels are affected by each operation, for example to allow + for full-scene antialiasing for seam-free rendering. It is not + expected that non-antialiased rendering will perform better than + anti-aliased rendering. + + * Three new functions were added to provide support for mixed cairo- + and non-cairo drawing to the same surface: + + cairo_surface_mark_dirty + cairo_surface_mark_dirty_rectangle + cairo_flush + + * The return type of the several "reference" functions was change, + (API compatibly), from void to the same type as the argument. The + affected functions are: + + cairo_font_face_reference + cairo_scaled_font_reference + cairo_pattern_reference + cairo_surface_reference + cairo_reference + + This allows a convenient way to assign and reference in a single + statement. + +cairo-win32 +----------- + * Some portability improvements, (eg. workaround for missing stdint.h). + +cairo-ft +-------- + * Updated to allow compilation with older versions of freetype. + +Bug fixes +--------- + * Fix the unbounded operators to actually produce a correct result, + (previously the results were artificially restricited to the + bounding box of whatever shape was being drawn rather than + extending out infinitely). The fixed operators are: + + CAIRO_OPERATOR_CLEAR + CAIRO_OPERATOR_SOURCE + CAIRO_OPERATOR_OUT + CAIRO_OPERATOR_IN + CAIRO_OPERATOR_DEST_IN + CAIRO_OPERATOR_DEST_ATOP + + * Fix cairo_mask and cairo_mask_surface to transform the mask by the + current transformation matrix (CTM). + + * Fix cairo_set_source to lock the CTM used to transform the pattern. + + * Workaround for X server Render bug involving repeating patterns + with a general transformation matrix. + + * cairo_get_font_face fixed to return a "nil" font face object rather + than NULL on error. + + * cairo_set_font_face fixed to not crash if given a NULL font face, + (which is the documented interface for restoring the defauly font + face). + + * Fix xlib glyphset caching to not try to free a NULL glyph. + Snapshot 0.6.0 (2005-07-28 Carl Worth <cworth@cworth.org>) ========================================================== API changes @@ -81,6 +81,7 @@ fixes are committed. Here are the steps to follow: 8) Add a "-head" to CAIRO_VERSION in configure, and commit. -9) Send a message to cairo-announce@cairographics.org to announce the +9) Send a message to cairo-announce@cairographics.org and CC + gnome-announce-list@gnome.org to announce the new snapshot using the text provided from "make release-publish". @@ -1,29 +1,10 @@ -cairo 0.6 release requirements -============================== -The cairo 0.6 snapshot is intended to intended to have the last of the -API _changes_ prior to cairo 1.0. Here they are: - -API changes ------------ -✓ A9. consistent error handling for all objects - Difficulty: Easy to implement to get the API right. Hard to test. - Status: Done. - -✓ A10. cairo_font_options_t - Difficulty: Moderate - Status: Done. - -✓ A11. cairo_xlib_surface_create needs to be screen-aware - Difficulty: Easy - Status: Done. - cairo 1.0 release requirements ============================== Implementation work ------------------- I1. Fix clipping to be sane Dificulty: moderate - Status: cworth has started looking at this + Status: otalyor is working on this. I2. Real PostScript/PDF fallbacks (cairo_meta_surface_t) Difficulty: hard @@ -51,19 +32,12 @@ Implementation work API additions (more detail in TODO file) ---------------------------------------- - A3. Add cairo_begin/end/get_group - Difficulty: easy to hard (depending on how sophisticated an - implementation is acceptable, and whether the - cairo_meta_surface_t mentioned in [I2] is done) - - Status: cworth has a posted a preliminary patch, and keithp, - krh, and otaylor answered all the tough questions it - raised. There's not much work left to finish this one. - - A7. cairo_surface_mark_dirty +✓A7. cairo_surface_mark_dirty and cairo_surface_flush Difficulty: trivial to add API, moderate to actually optimize based on it - Status: cworth has sent API proposal to list + Status: cworth has sent an API proposal to the list for + cairo_surface_mark_dirty. Recent discussions suggest + that cairo_surface_flush will need to reset the clip. ✓A12. cairo_xlib_surface_set_drawable Difficulty: Easy @@ -77,3 +51,14 @@ Performance work P3. Glyph measurement needs to be sped up. Status: Now planned as part of I4 above ("cache lock deadlock") + +Things that have been dropped from the 1.0 roadmap +================================================== + A3. Add cairo_begin/end/get_group + Difficulty: easy to hard (depending on how sophisticated an + implementation is acceptable, and whether the + cairo_meta_surface_t mentioned in [I2] is done) + + Status: cworth has a posted a preliminary patch, and keithp, + krh, and otaylor answered all the tough questions it + raised. There's not much work left to finish this one. @@ -10,12 +10,12 @@ Changes that are expected to impact the public API Backwards compatible (API additions only) ----------------------------------------- cairo_begin_group, cairo_end_group, cairo_get_group - cairo_surface_mark_dirty (see below for details) - Add support for non-antialiased rendering. API ? +PDR C cairo_surface_mark_dirty (see below for details) +PDRTC Add support for non-antialiased rendering + API Add CAIRO_FILL_RULE_INVERSE_WINDING and CAIRO_FILL_RULE_INVERSE_EVEN_ODD Add cairo_text_glyphs (see below for details) Add support for programmatic patterns, (ie. arbitrary gradients) - Add cairo_arc_to. +P Add cairo_arc_to. Add support for custom caps (see below for details) Add support for getting at image data from image surface Add CAIRO_STATUS_DESTROYED @@ -25,29 +25,12 @@ Backwards incompatible (API deletions or changes) ------------------------------------------------- PDR C cairo_surface_finish, cairo_surface_flush PDR C A hidden offset for the xlib backend -P Consistent error handling for all objects - Split cairo_format_t (see below for details) +PDR C Consistent error handling for all objects +PDRTC Split cairo_format_t (see below for details) P---C Remove cairo_status_string in favor of cairo_status_to_string Details on some of the above changes ------------------------------------ -* cairo_surface_mark_dirty - - One question is what the function should accept. A single - device-space rectangle seems like a consistent approach. That would - allow us to avoid needing backend-specific functions with - backend-specific region datatypes, (cf. clipping support) - - In order to get the intended efficiency benefits, we'll need to make - two changes: - - 1) In the fallback code, never fetch any data from the clean - region. - - 2) Mark clean any region drawn with device-pixel aligned - rectangles, (cairo_paint with no clip is the most iportant - one here). - * cairo_text_glyphs: It would function as a sort of bridge between the toy and the @@ -78,51 +61,13 @@ Details on some of the above changes current path. We may also need to provide the coordinates of the faces of every dash as well. -* split cairo_format_t into two things: - - - An enumeration that determines the "capabilities" of a surface - - A vs. ARGB. vs. RGB - - An enumeration that determines a specific in-memory representation - of data. (A1/A8/ARGB32/etc.. Could be extensible to things like - RGBA32_BYTES_NONPREMULTIPLIED. Some consistent naming convention would - be be good.) - - One issue here is that some interfaces, like cairo_surface_create_similar() - might be useful with either one. We might want to create an A1 surface - compatible with the backend (are there examples other than A1? Should - bilevel just be another "capability"?), or we might want to just create - an alpha surface without caring about the depth. - - If we want to support this, we could do something like: - - typedef enum cairo_pixel_format_t { - CAIRO_PIXEL_FORMAT_A8 = CAIRO_FORMAT_ALPHA, - CAIRO_PIXEL_FORMAT_RGB24 = CAIRO_FORMAT_RGB, - CAIRO_PIXEL_FORMAT_A1, - }; - - To allow passing either in. - - (I don't particularly like this idea for create_similar() because then you - aren't really saying ALPHA-dont-care, you are saying ALPHA-8. I think it - would be better to have a separate path for create_similar_with_pixel_format() - if we need that. But it might be useful for cairo_image_surface_create() ... - people are going to screw up and pass CAIRO_FORMAT_RGB into that, and if it - "just worked" that would save people trouble....) - Changes that do not affect the public API ========================================= -* Clean up the cache code a bit, (there is at least one redundant - level of cacheing, and there are some minor style issues). - * Fix clipping to work for all operators. The equation we have come up with is: ((src Op dest) In clip) Add (dest Out clip) -* Make a more interesting PS backend, (other than the current - "giant-image for every page" approach). - * Change stroke code to go through one giant polygon. This will fix problems with stroking self-intersecting paths. @@ -14,8 +14,7 @@ AUTOCONF=${AUTOCONF-autoconf} # automake 1.8 requires autoconf 2.58 # automake 1.7 requires autoconf 2.54 -# I don't know what automake 1.4 wants, but the following seems to work... -automake_min_vers=1.4 +automake_min_vers=1.7 aclocal_min_vers=$automake_min_vers autoconf_min_vers=2.54 libtoolize_min_vers=1.4 diff --git a/configure.in b/configure.in index 27fe96fa..bb38c53c 100644 --- a/configure.in +++ b/configure.in @@ -5,12 +5,12 @@ AC_INIT(src/cairo.h) dnl =========================================================================== # Package version number, (as distinct from shared library version) -CAIRO_VERSION=0.6.0 +CAIRO_VERSION=0.9.0 # libtool shared library version # Increment if the interface has additions, changes, removals. -LT_CURRENT=1 +LT_CURRENT=2 # Increment any time the source changes; set to # 0 if you increment CURRENT @@ -37,6 +37,27 @@ AM_PROG_LIBTOOL AC_STDC_HEADERS AC_C_BIGENDIAN +dnl =========================================================================== +dnl === Local macros +dnl =========================================================================== + +# _CHECK_FUNCS_WITH_FLAGS(FUNCTION..., CFLAGS, LIBS +# [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +# Like AC_CHECK_FUNCS but with additional CFLAGS and LIBS +# -------------------------------------------------------------------- +AC_DEFUN([_CHECK_FUNCS_WITH_FLAGS], +[ + save_cflags="$CFLAGS" + save_libs="$LIBS" + CFLAGS="$CFLAGS $2" + LIBS="$LIBS $3" + AC_CHECK_FUNCS($1, $4, $5) + CFLAGS="$save_cflags" + LIBS="$save_libs" +]) + +dnl =========================================================================== + AC_CHECK_FUNCS(vasnprintf) AC_CHECK_LIBM @@ -61,6 +82,7 @@ if test "x$use_xlib" = "xyes"; then XRENDER_LIBS="$X_LIBS -lXrender -lXext -lX11 $X_EXTRA_LIBS" use_xlib=yes], [ use_xlib="no (requires Xrender http://freedesktop.org/Software/xlibs)"])]) + _CHECK_FUNCS_WITH_FLAGS(XrmFinalize, $XRENDER_CFLAGS, $XRENDER_LIBS) fi AM_CONDITIONAL(CAIRO_HAS_XLIB_SURFACE, test "x$use_xlib" = "xyes") @@ -225,6 +247,7 @@ AC_ARG_ENABLE(freetype, if test "x$use_freetype" = "xyes"; then PKG_CHECK_MODULES(FONTCONFIG, fontconfig, [use_freetype=yes], [use_freetype=no]) + _CHECK_FUNCS_WITH_FLAGS(FcFini, $FONTCONFIG_CFLAGS, $FONTCONFIG_LIBS) fi CAIRO_CFLAGS="$CAIRO_CFLAGS $FONTCONFIG_CFLAGS" @@ -273,6 +296,20 @@ if test "x$use_freetype" = "xyes"; then AC_SUBST(FREETYPE_CFLAGS) AC_SUBST(FREETYPE_LIBS) AC_SUBST(FREETYPE_REQUIRES) + + temp_save_libs="$LIBS" + temp_save_cflags="$CFLAGS" + LIBS="$LIBS $FREETYPE_LIBS" + CFLAGS="$CFLAGS $FREETYPE_CFLAGS" + AC_CHECK_MEMBER(FT_Bitmap_Size.y_ppem, + HAVE_FT_BITMAP_SIZE_Y_PPEM=1, + HAVE_FT_BITMAP_SIZE_Y_PPEM=0, + [#include<ft2build.h> + #include FT_FREETYPE_H]) + AC_DEFINE_UNQUOTED(HAVE_FT_BITMAP_SIZE_Y_PPEM,$HAVE_FT_BITMAP_SIZE_Y_PPEM, + [FT_Bitmap_Size structure includes y_ppem field]) + LIBS="$temp_save_libs" + CFLAGS="$temp_save_cflags" fi CAIRO_CFLAGS="$CAIRO_CFLAGS $FREETYPE_CFLAGS" diff --git a/doc/public/Makefile.am b/doc/public/Makefile.am index a9faef84..fdd421cb 100644 --- a/doc/public/Makefile.am +++ b/doc/public/Makefile.am @@ -20,6 +20,7 @@ CFILE_GLOB=$(top_srcdir)/src/*.c $(top_srcdir)/src/*.h # Headers to ignore IGNORE_HFILES= \ + cairo-clip-private.h \ cairo-features.h \ cairo-font-subset-private.h \ cairo-ft-private.h \ diff --git a/doc/public/cairo-docs.xml b/doc/public/cairo-docs.xml index 729738aa..5270f950 100644 --- a/doc/public/cairo-docs.xml +++ b/doc/public/cairo-docs.xml @@ -13,7 +13,6 @@ <xi:include href="xml/cairo-pattern.xml"/> <xi:include href="xml/cairo-matrix.xml"/> <xi:include href="xml/cairo-font.xml"/> - <xi:include href="xml/cairo-atsui.xml"/> <xi:include href="xml/cairo-ft.xml"/> <xi:include href="xml/cairo-glitz.xml"/> <xi:include href="xml/cairo-pdf.xml"/> diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt index 2e237b02..a27a2945 100644 --- a/doc/public/cairo-sections.txt +++ b/doc/public/cairo-sections.txt @@ -75,6 +75,7 @@ cairo_xcb_surface_create_with_xrender_format cairo_xlib_surface_create cairo_xlib_surface_create_for_bitmap cairo_xlib_surface_set_size +cairo_xlib_surface_set_drawable </SECTION> <SECTION> @@ -90,10 +91,14 @@ cairo_surface_t cairo_surface_create_similar cairo_surface_reference cairo_surface_destroy +cairo_surface_status cairo_surface_finish cairo_surface_get_font_options cairo_surface_set_user_data cairo_surface_get_user_data +cairo_surface_flush +cairo_surface_mark_dirty +cairo_surface_mark_dirty_rectangle cairo_surface_set_device_offset </SECTION> @@ -145,11 +150,13 @@ cairo_font_face_t cairo_scaled_font_t cairo_font_face_reference cairo_font_face_destroy +cairo_font_face_status cairo_font_face_get_user_data cairo_font_face_set_user_data cairo_scaled_font_create cairo_scaled_font_reference cairo_scaled_font_destroy +cairo_scaled_font_status cairo_font_extents_t cairo_scaled_font_extents cairo_text_extents_t @@ -162,7 +169,6 @@ cairo_font_options_status cairo_font_options_merge cairo_font_options_hash cairo_font_options_equal -cairo_antialias_t cairo_font_options_set_antialias cairo_font_options_get_antialias cairo_subpixel_order_t @@ -196,6 +202,8 @@ cairo_set_source_rgba cairo_set_source cairo_set_source_surface cairo_set_tolerance +cairo_antialias_t +cairo_set_antialias cairo_fill_rule_t cairo_set_fill_rule cairo_set_line_width @@ -265,6 +273,7 @@ cairo_glyph_path cairo_get_operator cairo_get_source cairo_get_tolerance +cairo_get_antialias cairo_get_current_point cairo_get_fill_rule cairo_get_line_width @@ -293,9 +302,8 @@ cairo_destroy_func_t cairo_user_data_key_t cairo_read_func_t cairo_write_func_t +cairo_debug_reset_static_data <SUBSECTION Private> -CAIRO_BEGIN_DECLS -CAIRO_END_DECLS cairo_current_font_extents cairo_get_font_extents cairo_current_operator diff --git a/doc/public/tmpl/cairo-font.sgml b/doc/public/tmpl/cairo-font.sgml index a41b7cce..78c9d3bf 100644 --- a/doc/public/tmpl/cairo-font.sgml +++ b/doc/public/tmpl/cairo-font.sgml @@ -35,6 +35,7 @@ Font Handling </para> @font_face: +@Returns: <!-- ##### FUNCTION cairo_font_face_destroy ##### --> @@ -45,6 +46,15 @@ Font Handling @font_face: +<!-- ##### FUNCTION cairo_font_face_status ##### --> +<para> + +</para> + +@font_face: +@Returns: + + <!-- ##### FUNCTION cairo_font_face_get_user_data ##### --> <para> @@ -85,6 +95,7 @@ Font Handling </para> @scaled_font: +@Returns: <!-- ##### FUNCTION cairo_scaled_font_destroy ##### --> @@ -95,6 +106,15 @@ Font Handling @scaled_font: +<!-- ##### FUNCTION cairo_scaled_font_status ##### --> +<para> + +</para> + +@scaled_font: +@Returns: + + <!-- ##### STRUCT cairo_font_extents_t ##### --> <para> @@ -208,16 +228,6 @@ Font Handling @Returns: -<!-- ##### ENUM cairo_antialias_t ##### --> -<para> - -</para> - -@CAIRO_ANTIALIAS_DEFAULT: -@CAIRO_ANTIALIAS_NONE: -@CAIRO_ANTIALIAS_GRAY: -@CAIRO_ANTIALIAS_SUBPIXEL: - <!-- ##### FUNCTION cairo_font_options_set_antialias ##### --> <para> diff --git a/doc/public/tmpl/cairo-pattern.sgml b/doc/public/tmpl/cairo-pattern.sgml index a837252c..78964ef4 100644 --- a/doc/public/tmpl/cairo-pattern.sgml +++ b/doc/public/tmpl/cairo-pattern.sgml @@ -87,6 +87,7 @@ cairo_pattern_t </para> @pattern: +@Returns: <!-- ##### FUNCTION cairo_pattern_destroy ##### --> diff --git a/doc/public/tmpl/cairo-surface.sgml b/doc/public/tmpl/cairo-surface.sgml index 5d069fc2..64e65f9d 100644 --- a/doc/public/tmpl/cairo-surface.sgml +++ b/doc/public/tmpl/cairo-surface.sgml @@ -43,6 +43,7 @@ cairo_surface_t </para> @surface: +@Returns: <!-- ##### FUNCTION cairo_surface_destroy ##### --> @@ -53,6 +54,15 @@ cairo_surface_t @surface: +<!-- ##### FUNCTION cairo_surface_status ##### --> +<para> + +</para> + +@surface: +@Returns: + + <!-- ##### FUNCTION cairo_surface_finish ##### --> <para> @@ -94,6 +104,34 @@ cairo_surface_t @Returns: +<!-- ##### FUNCTION cairo_surface_flush ##### --> +<para> + +</para> + +@surface: + + +<!-- ##### FUNCTION cairo_surface_mark_dirty ##### --> +<para> + +</para> + +@surface: + + +<!-- ##### FUNCTION cairo_surface_mark_dirty_rectangle ##### --> +<para> + +</para> + +@surface: +@x: +@y: +@width: +@height: + + <!-- ##### FUNCTION cairo_surface_set_device_offset ##### --> <para> diff --git a/doc/public/tmpl/cairo-xlib.sgml b/doc/public/tmpl/cairo-xlib.sgml index cc106e8c..d4cda456 100644 --- a/doc/public/tmpl/cairo-xlib.sgml +++ b/doc/public/tmpl/cairo-xlib.sgml @@ -53,3 +53,14 @@ XLib Backend @height: +<!-- ##### FUNCTION cairo_xlib_surface_set_drawable ##### --> +<para> + +</para> + +@surface: +@drawable: +@width: +@height: + + diff --git a/doc/public/tmpl/cairo.sgml b/doc/public/tmpl/cairo.sgml index c3398425..3f2ec8d6 100644 --- a/doc/public/tmpl/cairo.sgml +++ b/doc/public/tmpl/cairo.sgml @@ -48,6 +48,7 @@ Drawing contexts. </para> @cr: +@Returns: <!-- ##### FUNCTION cairo_destroy ##### --> @@ -190,6 +191,25 @@ Drawing contexts. @tolerance: +<!-- ##### ENUM cairo_antialias_t ##### --> +<para> + +</para> + +@CAIRO_ANTIALIAS_DEFAULT: +@CAIRO_ANTIALIAS_NONE: +@CAIRO_ANTIALIAS_GRAY: +@CAIRO_ANTIALIAS_SUBPIXEL: + +<!-- ##### FUNCTION cairo_set_antialias ##### --> +<para> + +</para> + +@cr: +@antialias: + + <!-- ##### ENUM cairo_fill_rule_t ##### --> <para> @@ -845,6 +865,15 @@ Drawing contexts. @Returns: +<!-- ##### FUNCTION cairo_get_antialias ##### --> +<para> + +</para> + +@cr: +@Returns: + + <!-- ##### FUNCTION cairo_get_current_point ##### --> <para> @@ -1115,3 +1144,10 @@ Drawing contexts. @Returns: +<!-- ##### FUNCTION cairo_debug_reset_static_data ##### --> +<para> + +</para> + + + diff --git a/src/Makefile.am b/src/Makefile.am index 16cbb1c5..de7d8004 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -85,12 +85,18 @@ libcairo_la_SOURCES = \ cairo-arc-private.h \ cairo-array.c \ cairo-cache.c \ + cairo-clip.c \ + cairo-clip-private.h \ cairo-color.c \ + cairo-debug.c \ + cairo-debug.h \ cairo-fixed.c \ cairo-font.c \ cairo-font-options.c \ cairo-gstate.c \ cairo-gstate-private.h \ + cairo-hash.c \ + cairo-hash-private.h \ cairo-hull.c \ cairo-image-surface.c \ cairo-matrix.c \ diff --git a/src/cairo-arc.c b/src/cairo-arc.c index e653fcda..e9f35993 100644 --- a/src/cairo-arc.c +++ b/src/cairo-arc.c @@ -34,8 +34,6 @@ * Carl D. Worth <cworth@cworth.org> */ -#include <math.h> - #include "cairo-arc-private.h" /* Spline deviation from the circle in radius would be given by: diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c index 990a2311..8aff8cd6 100644 --- a/src/cairo-atsui-font.c +++ b/src/cairo-atsui-font.c @@ -105,12 +105,11 @@ CreateSizedCopyOfStyle(ATSUStyle inStyle, cairo_matrix_t *scale) static cairo_status_t -_cairo_atsui_font_create(const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - cairo_scaled_font_t **font_out) +_cairo_atsui_font_create_toy(const cairo_toy_font_face *toy_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font_out) { cairo_atsui_font_t *font = NULL; ATSUStyle style; @@ -118,11 +117,11 @@ _cairo_atsui_font_create(const char *family, OSStatus err; Boolean isItalic, isBold; cairo_matrix_t scale; + const char *family = toy_face->family; err = ATSUCreateStyle(&style); - - switch (weight) { + switch (toy_face->weight) { case CAIRO_FONT_WEIGHT_BOLD: isBold = true; break; @@ -132,7 +131,7 @@ _cairo_atsui_font_create(const char *family, break; } - switch (slant) { + switch (toy_face->slant) { case CAIRO_FONT_SLANT_ITALIC: isItalic = true; break; @@ -188,7 +187,7 @@ _cairo_atsui_font_create(const char *family, font = malloc(sizeof(cairo_atsui_font_t)); - _cairo_scaled_font_init(&font->base, font_matrix, ctm, + _cairo_scaled_font_init(&font->base, font_matrix, ctm, options, &cairo_atsui_scaled_font_backend); cairo_matrix_multiply(&scale, font_matrix, ctm); @@ -213,9 +212,8 @@ _cairo_atsui_font_create(const char *family, return CAIRO_STATUS_SUCCESS; } - static void -_cairo_atsui_font_destroy_font(void *abstract_font) +_cairo_atsui_font_fini(void *abstract_font) { cairo_atsui_font_t *font = abstract_font; @@ -690,8 +688,8 @@ _cairo_atsui_font_glyph_path(void *abstract_font, } const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = { - _cairo_atsui_font_create, - _cairo_atsui_font_destroy_font, + _cairo_atsui_font_create_toy, + _cairo_atsui_font_fini, _cairo_atsui_font_font_extents, _cairo_atsui_font_text_to_glyphs, _cairo_atsui_font_glyph_extents, diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h new file mode 100644 index 00000000..23eb78c9 --- /dev/null +++ b/src/cairo-clip-private.h @@ -0,0 +1,123 @@ +/* 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): + * Kristian Høgsberg <krh@redhat.com> + */ + +#ifndef CAIRO_CLIP_PRIVATE_H +#define CAIRO_CLIP_PRIVATE_H + +#include "cairo-path-fixed-private.h" + +enum _cairo_clip_mode { + CAIRO_CLIP_MODE_PATH, + CAIRO_CLIP_MODE_REGION, + CAIRO_CLIP_MODE_MASK +}; + +struct _cairo_clip_path { + unsigned int ref_count; + cairo_path_fixed_t path; + cairo_fill_rule_t fill_rule; + double tolerance; + cairo_antialias_t antialias; + cairo_clip_path_t *prev; +}; + +struct _cairo_clip { + cairo_clip_mode_t mode; + + /* + * Mask-based clipping for cases where the backend + * clipping isn't sufficiently able. + * + * The rectangle here represents the + * portion of the destination surface that this + * clip surface maps to, it does not + * represent the extents of the clip region or + * clip paths + */ + cairo_surface_t *surface; + cairo_rectangle_t surface_rect; + /* + * Surface clip serial number to store + * in the surface when this clip is set + */ + unsigned int serial; + /* + * A clip region that can be placed in the surface + */ + pixman_region16_t *region; + /* + * If the surface supports path clipping, we store the list of + * clipping paths that has been set here as a linked list. + */ + cairo_clip_path_t *path; +}; + +cairo_private void +_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target); + +cairo_private void +_cairo_clip_fini (cairo_clip_t *clip); + +cairo_private void +_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other); + +cairo_private cairo_status_t +_cairo_clip_reset (cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_clip_clip (cairo_clip_t *clip, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_surface_t *target); + +cairo_private cairo_status_t +_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip, + cairo_rectangle_t *rectangle); + +cairo_private cairo_status_t +_cairo_clip_intersect_to_region (cairo_clip_t *clip, + pixman_region16_t *region); + +cairo_private cairo_status_t +_cairo_clip_combine_to_surface (cairo_clip_t *clip, + cairo_operator_t operator, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents); + +#endif /* CAIRO_CLIP_PRIVATE_H */ diff --git a/src/cairo-clip.c b/src/cairo-clip.c new file mode 100644 index 00000000..d479da8f --- /dev/null +++ b/src/cairo-clip.c @@ -0,0 +1,466 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + * Kristian Høgsberg <krh@redhat.com> + */ + +#include "cairoint.h" +#include "cairo-clip-private.h" + +static cairo_clip_path_t * +_cairo_clip_path_reference (cairo_clip_path_t *clip_path); + +static void +_cairo_clip_path_destroy (cairo_clip_path_t *clip_path); + +/* Creates a region from a cairo_rectangle_t */ +static cairo_status_t +_region_new_from_rect (cairo_rectangle_t *rect, + pixman_region16_t **region) +{ + *region = pixman_region_create (); + if (pixman_region_union_rect (*region, *region, + rect->x, rect->y, + rect->width, rect->height) != PIXMAN_REGION_STATUS_SUCCESS) { + pixman_region_destroy (*region); + return CAIRO_STATUS_NO_MEMORY; + } + + return CAIRO_STATUS_SUCCESS; +} + +/* Gets the bounding box of a region as a cairo_rectangle_t */ +static void +_region_rect_extents (pixman_region16_t *region, + cairo_rectangle_t *rect) +{ + pixman_box16_t *region_extents = pixman_region_extents (region); + + rect->x = region_extents->x1; + rect->y = region_extents->y1; + rect->width = region_extents->x2 - region_extents->x1; + rect->height = region_extents->y2 - region_extents->y1; +} + +void +_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target) +{ + clip->mode = _cairo_surface_get_clip_mode (target); + clip->region = NULL; + clip->surface = NULL; + clip->serial = 0; + clip->path = NULL; +} + +void +_cairo_clip_fini (cairo_clip_t *clip) +{ + if (clip->surface) + cairo_surface_destroy (clip->surface); + clip->surface = NULL; + + if (clip->path) + _cairo_clip_path_destroy (clip->path); + clip->path = NULL; + + if (clip->region) + pixman_region_destroy (clip->region); + clip->region = NULL; + clip->serial = 0; +} + +void +_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other) +{ + if (other->region) { + clip->region = pixman_region_create (); + pixman_region_copy (clip->region, other->region); + } + + cairo_surface_reference (other->surface); + clip->surface = other->surface; + _cairo_clip_path_reference (other->path); + clip->path = other->path; +} + +cairo_status_t +_cairo_clip_reset (cairo_clip_t *clip) +{ + /* destroy any existing clip-region artifacts */ + if (clip->surface) + cairo_surface_destroy (clip->surface); + clip->surface = NULL; + + if (clip->region) + pixman_region_destroy (clip->region); + clip->region = NULL; + + if (clip->path) + _cairo_clip_path_destroy (clip->path); + clip->path = NULL; + + clip->serial = 0; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip, + cairo_rectangle_t *rectangle) +{ + if (clip->path) { + /* Intersect path extents here. */ + } + + if (clip->region) { + pixman_region16_t *intersection; + cairo_status_t status; + pixman_region_status_t pixman_status; + + status = _region_new_from_rect (rectangle, &intersection); + if (status) + return status; + + pixman_status = pixman_region_intersect (intersection, + clip->region, + intersection); + if (pixman_status == PIXMAN_REGION_STATUS_SUCCESS) + _region_rect_extents (intersection, rectangle); + else + status = CAIRO_STATUS_NO_MEMORY; + + pixman_region_destroy (intersection); + + if (status) + return status; + } + + if (clip->surface) + _cairo_rectangle_intersect (rectangle, &clip->surface_rect); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_clip_intersect_to_region (cairo_clip_t *clip, + pixman_region16_t *region) +{ + if (clip->path) { + /* Intersect clip path into region. */ + } + + if (clip->region) + pixman_region_intersect (region, clip->region, region); + + if (clip->surface) { + pixman_region16_t *clip_rect; + pixman_region_status_t pixman_status; + cairo_status_t status; + + status = _region_new_from_rect (&clip->surface_rect, &clip_rect); + if (status) + return status; + + pixman_status = pixman_region_intersect (region, + clip_rect, + region); + if (pixman_status != PIXMAN_REGION_STATUS_SUCCESS) + status = CAIRO_STATUS_NO_MEMORY; + + pixman_region_destroy (clip_rect); + + if (status) + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +/* Combines the region of clip->surface given by extents in + * device backend coordinates into the given temporary surface, + * which has its origin at dst_x, dst_y in backend coordinates + */ +cairo_status_t +_cairo_clip_combine_to_surface (cairo_clip_t *clip, + cairo_operator_t operator, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents) +{ + cairo_pattern_union_t pattern; + cairo_status_t status; + + _cairo_pattern_init_for_surface (&pattern.surface, clip->surface); + + status = _cairo_surface_composite (operator, + &pattern.base, + NULL, + dst, + extents->x - clip->surface_rect.x, + extents->y - clip->surface_rect.y, + 0, 0, + extents->x - dst_x, + extents->y - dst_y, + extents->width, extents->height); + + _cairo_pattern_fini (&pattern.base); + + return status; +} + +static cairo_status_t +_cairo_clip_intersect_path (cairo_clip_t *clip, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_surface_t *target) +{ + cairo_clip_path_t *clip_path; + cairo_status_t status; + + if (clip->mode != CAIRO_CLIP_MODE_PATH) + return CAIRO_INT_STATUS_UNSUPPORTED; + + clip_path = malloc (sizeof (cairo_clip_path_t)); + if (clip_path == NULL) + return CAIRO_STATUS_NO_MEMORY; + + status = _cairo_path_fixed_init_copy (&clip_path->path, path); + if (status) + return status; + + clip_path->ref_count = 1; + clip_path->fill_rule = fill_rule; + clip_path->tolerance = tolerance; + clip_path->antialias = antialias; + clip_path->prev = clip->path; + clip->path = clip_path; + clip->serial = _cairo_surface_allocate_clip_serial (target); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_clip_path_t * +_cairo_clip_path_reference (cairo_clip_path_t *clip_path) +{ + if (clip_path == NULL) + return NULL; + + clip_path->ref_count++; + + return clip_path; +} + +static void +_cairo_clip_path_destroy (cairo_clip_path_t *clip_path) +{ + if (clip_path == NULL) + return; + + clip_path->ref_count--; + if (clip_path->ref_count) + return; + + _cairo_path_fixed_fini (&clip_path->path); + _cairo_clip_path_destroy (clip_path->prev); + free (clip_path); +} + +static cairo_status_t +_cairo_clip_intersect_region (cairo_clip_t *clip, + cairo_traps_t *traps, + cairo_surface_t *target) +{ + pixman_region16_t *region; + cairo_status_t status; + + if (clip->mode != CAIRO_CLIP_MODE_REGION) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_traps_extract_region (traps, ®ion); + if (status) + return status; + + if (region == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = CAIRO_STATUS_SUCCESS; + if (clip->region == NULL) { + clip->region = region; + } else { + pixman_region16_t *intersection = pixman_region_create(); + + if (pixman_region_intersect (intersection, + clip->region, region) + == PIXMAN_REGION_STATUS_SUCCESS) { + pixman_region_destroy (clip->region); + clip->region = intersection; + } else { + status = CAIRO_STATUS_NO_MEMORY; + } + pixman_region_destroy (region); + } + + clip->serial = _cairo_surface_allocate_clip_serial (target); + + return status; +} + +static cairo_status_t +_cairo_clip_intersect_mask (cairo_clip_t *clip, + cairo_traps_t *traps, + cairo_antialias_t antialias, + cairo_surface_t *target) +{ + cairo_pattern_union_t pattern; + cairo_box_t extents; + cairo_rectangle_t surface_rect; + cairo_surface_t *surface; + cairo_status_t status; + + /* Represent the clip as a mask surface. We create a new surface + * the size of the intersection of the old mask surface and the + * extents of the new clip path. */ + + _cairo_traps_extents (traps, &extents); + _cairo_box_round_to_rectangle (&extents, &surface_rect); + + if (clip->surface != NULL) + _cairo_rectangle_intersect (&surface_rect, &clip->surface_rect); + + surface = _cairo_surface_create_similar_solid (target, + CAIRO_CONTENT_ALPHA, + surface_rect.width, + surface_rect.height, + CAIRO_COLOR_WHITE); + if (surface->status) + return CAIRO_STATUS_NO_MEMORY; + + /* Render the new clipping path into the new mask surface. */ + + _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y); + _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); + + status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN, + &pattern.base, + surface, + antialias, + 0, 0, + 0, 0, + surface_rect.width, + surface_rect.height, + traps->traps, + traps->num_traps); + + _cairo_pattern_fini (&pattern.base); + + if (status) { + cairo_surface_destroy (surface); + return status; + } + + /* If there was a clip surface already, combine it with the new + * mask surface using the IN operator, so we get the intersection + * of the old and new clipping paths. */ + + if (clip->surface != NULL) { + _cairo_pattern_init_for_surface (&pattern.surface, clip->surface); + + status = _cairo_surface_composite (CAIRO_OPERATOR_IN, + &pattern.base, + NULL, + surface, + surface_rect.x - clip->surface_rect.x, + surface_rect.y - clip->surface_rect.y, + 0, 0, + 0, 0, + surface_rect.width, + surface_rect.height); + + _cairo_pattern_fini (&pattern.base); + + if (status) { + cairo_surface_destroy (surface); + return status; + } + + cairo_surface_destroy (clip->surface); + } + + clip->surface = surface; + clip->surface_rect = surface_rect; + clip->serial = _cairo_surface_allocate_clip_serial (target); + + return status; +} + +cairo_status_t +_cairo_clip_clip (cairo_clip_t *clip, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_surface_t *target) +{ + cairo_status_t status; + cairo_traps_t traps; + + status = _cairo_clip_intersect_path (clip, + path, fill_rule, tolerance, + antialias, target); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + _cairo_traps_init (&traps); + status = _cairo_path_fixed_fill_to_traps (path, + fill_rule, + tolerance, + &traps); + if (status) + goto bail; + + status = _cairo_clip_intersect_region (clip, &traps, target); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto bail; + + status = _cairo_clip_intersect_mask (clip, &traps, antialias, target); + + bail: + _cairo_traps_fini (&traps); + + return status; +} diff --git a/src/cairo-debug.c b/src/cairo-debug.c new file mode 100644 index 00000000..31eefc5a --- /dev/null +++ b/src/cairo-debug.c @@ -0,0 +1,73 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + */ + +#include "cairoint.h" + +/** + * cairo_debug_reset_static_data: + * + * Resets all static data within cairo to its original state, + * (ie. identical to the state at the time of program invocation). For + * example, all caches within cairo will be flushed empty. + * + * This function is intended to be useful when using memory-checking + * tools such as valgrind. When valgrind's memcheck analyzes a + * cairo-using program without a call to cairo_debug_reset_static_data, + * it will report all data reachable via cairo's static objects as + * "still reachable". Calling cairo_debug_reset_static_data just prior + * to program termination will make it easier to get squeaky clean + * reports from valgrind. + * + * WARNING: It is only safe to call this function when there are no + * active cairo objects remaining, (ie. the appropriate destroy + * functions have been called as necessary). If there are active cairo + * objects, this call is likely to cause a crash, (eg. an assertion + * failure due to a hash table being destroyed when non-empty). + **/ +void +cairo_debug_reset_static_data (void) +{ +#if CAIRO_HAS_XLIB_SURFACE + _cairo_xlib_surface_reset_static_data (); + _cairo_xlib_screen_reset_static_data (); +#endif + + _cairo_font_reset_static_data (); + +#if CAIRO_HAS_FT_FONT + _cairo_ft_font_reset_static_data (); +#endif +} + diff --git a/src/cairo-debug.h b/src/cairo-debug.h new file mode 100644 index 00000000..1dab2c74 --- /dev/null +++ b/src/cairo-debug.h @@ -0,0 +1,48 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth <cworth@cworth.org> + */ + +#ifndef CAIRO_DEBUG_H +#define CAIRO_DEBUG_H + +#include <cairo-features.h> + +CAIRO_BEGIN_DECLS + +void +cairo_debug_reset_static_data (void); + +CAIRO_END_DECLS + +#endif /* CAIRO_H */ diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in index 8065be35..fdc1e37e 100644 --- a/src/cairo-features.h.in +++ b/src/cairo-features.h.in @@ -37,6 +37,14 @@ #ifndef CAIRO_FEATURES_H #define CAIRO_FEATURES_H +#ifdef __cplusplus +# define CAIRO_BEGIN_DECLS extern "C" { +# define CAIRO_END_DECLS } +#else +# define CAIRO_BEGIN_DECLS +# define CAIRO_END_DECLS +#endif + @PS_SURFACE_FEATURE@ @PDF_SURFACE_FEATURE@ diff --git a/src/cairo-font-subset.c b/src/cairo-font-subset.c index e3a2784c..bd113f98 100644 --- a/src/cairo-font-subset.c +++ b/src/cairo-font-subset.c @@ -71,6 +71,10 @@ struct cairo_pdf_ft_font { cairo_status_t status; }; +static int +cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph); + + #define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) ) #define SFNT_VERSION 0x00010000 @@ -134,6 +138,7 @@ _cairo_font_subset_destroy (cairo_font_subset_t *font) cairo_font_subset_t * _cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font) { + cairo_ft_unscaled_font_t *ft_unscaled_font; FT_Face face; cairo_pdf_ft_font_t *font; unsigned long size; @@ -143,7 +148,9 @@ _cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font) if (! _cairo_unscaled_font_is_ft (unscaled_font)) return NULL; - face = _cairo_ft_unscaled_font_lock_face (unscaled_font); + ft_unscaled_font = (cairo_ft_unscaled_font_t *) unscaled_font; + + face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font); /* We currently only support freetype truetype fonts. */ size = 0; @@ -155,8 +162,7 @@ _cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font) if (font == NULL) return NULL; - font->base.unscaled_font = unscaled_font; - _cairo_unscaled_font_reference (unscaled_font); + font->base.unscaled_font = _cairo_unscaled_font_reference (unscaled_font); font->base.backend = &cairo_pdf_ft_font_backend; _cairo_array_init (&font->output, sizeof (char)); @@ -193,7 +199,7 @@ _cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font) if (font->base.widths == NULL) goto fail5; - _cairo_ft_unscaled_font_unlock_face (unscaled_font); + _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font); font->status = CAIRO_STATUS_SUCCESS; @@ -310,6 +316,62 @@ cairo_pdf_ft_font_write_generic_table (cairo_pdf_ft_font_t *font, return 0; } + +typedef struct composite_glyph composite_glyph_t; +struct composite_glyph { + unsigned short flags; + unsigned short index; + unsigned short args[7]; /* 1 to 7 arguments depending on value of flags */ +}; + +typedef struct glyph_data glyph_data_t; +struct glyph_data { + short num_contours; + char data[8]; + composite_glyph_t glyph; +}; + +/* composite_glyph_t flags */ +#define ARG_1_AND_2_ARE_WORDS 0x0001 +#define WE_HAVE_A_SCALE 0x0008 +#define MORE_COMPONENTS 0x0020 +#define WE_HAVE_AN_X_AND_Y_SCALE 0x0040 +#define WE_HAVE_A_TWO_BY_TWO 0x0080 + +static void +cairo_pdf_ft_font_remap_composite_glyph (cairo_pdf_ft_font_t *font, + unsigned char *buffer) +{ + glyph_data_t *glyph_data; + composite_glyph_t *composite_glyph; + int num_args; + int has_more_components; + unsigned short flags; + unsigned short index; + + glyph_data = (glyph_data_t *) buffer; + if ((short)be16_to_cpu (glyph_data->num_contours) >= 0) + return; + + composite_glyph = &glyph_data->glyph; + do { + flags = be16_to_cpu (composite_glyph->flags); + has_more_components = flags & MORE_COMPONENTS; + index = cairo_pdf_ft_font_use_glyph (font, be16_to_cpu (composite_glyph->index)); + composite_glyph->index = cpu_to_be16 (index); + num_args = 1; + if (flags & ARG_1_AND_2_ARE_WORDS) + num_args += 1; + if (flags & WE_HAVE_A_SCALE) + num_args += 1; + else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) + num_args += 2; + else if (flags & WE_HAVE_A_TWO_BY_TWO) + num_args += 3; + composite_glyph = (composite_glyph_t *) &(composite_glyph->args[num_args]); + } while (has_more_components); +} + static int cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font, unsigned long tag) @@ -357,8 +419,10 @@ cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font, buffer = cairo_pdf_ft_font_write (font, NULL, size); if (buffer == NULL) break; - FT_Load_Sfnt_Table (font->face, TTAG_glyf, begin, buffer, &size); - /* FIXME: remap composite glyphs */ + if (size != 0) { + FT_Load_Sfnt_Table (font->face, TTAG_glyf, begin, buffer, &size); + cairo_pdf_ft_font_remap_composite_glyph (font, buffer); + } } font->glyphs[i].location = @@ -513,10 +577,14 @@ struct table { }; static const table_t truetype_tables[] = { + /* As we write out the glyf table we remap composite glyphs. + * Remapping composite glyphs will reference the sub glyphs the + * composite glyph is made up of. That needs to be done first so + * we have all the glyphs in the subset before going further. */ + { TTAG_glyf, cairo_pdf_ft_font_write_glyf_table }, { TTAG_cmap, cairo_pdf_ft_font_write_cmap_table }, { TTAG_cvt, cairo_pdf_ft_font_write_generic_table }, { TTAG_fpgm, cairo_pdf_ft_font_write_generic_table }, - { TTAG_glyf, cairo_pdf_ft_font_write_glyf_table }, { TTAG_head, cairo_pdf_ft_font_write_head_table }, { TTAG_hhea, cairo_pdf_ft_font_write_hhea_table }, { TTAG_hmtx, cairo_pdf_ft_font_write_hmtx_table }, @@ -589,11 +657,18 @@ static cairo_status_t cairo_pdf_ft_font_generate (void *abstract_font, const char **data, unsigned long *length) { + cairo_ft_unscaled_font_t *ft_unscaled_font; cairo_pdf_ft_font_t *font = abstract_font; unsigned long start, end, next, checksum, *checksum_location; int i; - font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font); + /* XXX: It would be cleaner to do something besides this cast + * here. Perhaps cairo_pdf_ft_font_t should just have the + * cairo_ft_unscaled_font_t rather than having the generic + * cairo_unscaled_font_t in the base class? */ + ft_unscaled_font = (cairo_ft_unscaled_font_t *) font->base.unscaled_font; + + font->face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font); if (cairo_pdf_ft_font_write_offset_table (font)) goto fail; @@ -622,7 +697,7 @@ 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); + _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font); font->face = NULL; return font->status; diff --git a/src/cairo-font.c b/src/cairo-font.c index 9645f3df..10fcb5f5 100644 --- a/src/cairo-font.c +++ b/src/cairo-font.c @@ -42,7 +42,7 @@ /* Forward declare so we can use it as an arbitrary backend for * _cairo_font_face_nil. */ -static const cairo_font_face_backend_t _cairo_simple_font_face_backend; +static const cairo_font_face_backend_t _cairo_toy_font_face_backend; /* cairo_font_face_t */ @@ -50,7 +50,7 @@ const cairo_font_face_t _cairo_font_face_nil = { CAIRO_STATUS_NO_MEMORY, /* status */ -1, /* ref_count */ { 0, 0, 0, NULL }, /* user_data */ - &_cairo_simple_font_face_backend + &_cairo_toy_font_face_backend }; void @@ -72,17 +72,21 @@ _cairo_font_face_init (cairo_font_face_t *font_face, * Increases the reference count on @font_face by one. This prevents * @font_face from being destroyed until a matching call to * cairo_font_face_destroy() is made. + * + * Return value: the referenced #cairo_font_face_t. **/ -void +cairo_font_face_t * cairo_font_face_reference (cairo_font_face_t *font_face) { if (font_face == NULL) - return; + return NULL; if (font_face->ref_count == (unsigned int)-1) - return; + return font_face; font_face->ref_count++; + + return font_face; } /** @@ -121,7 +125,7 @@ cairo_font_face_destroy (cairo_font_face_t *font_face) /** * cairo_font_face_status: - * @surface: a #cairo_font_face_t + * @font_face: a #cairo_font_face_t * * Checks whether an error has previously occurred for this * font face @@ -184,19 +188,6 @@ cairo_font_face_set_user_data (cairo_font_face_t *font_face, key, user_data, destroy); } -/* cairo_simple_font_face_t - simple family/slant/weight font faces used for - * the built-in font API - */ - -typedef struct _cairo_simple_font_face cairo_simple_font_face_t; - -struct _cairo_simple_font_face { - cairo_font_face_t base; - char *family; - cairo_font_slant_t slant; - cairo_font_weight_t weight; -}; - /* We maintain a global cache from family/weight/slant => cairo_font_face_t * for cairo_simple_font_t. The primary purpose of this cache is to provide * unique cairo_font_face_t values so that our cache from @@ -214,7 +205,7 @@ typedef struct { typedef struct { cairo_simple_cache_key_t key; - cairo_simple_font_face_t *font_face; + cairo_toy_font_face_t *font_face; } cairo_simple_cache_entry_t; static const cairo_cache_backend_t _cairo_simple_font_cache_backend; @@ -233,11 +224,11 @@ _unlock_global_simple_cache (void) CAIRO_MUTEX_UNLOCK (_global_simple_cache_mutex); } +static cairo_cache_t *global_simple_cache = NULL; + static cairo_cache_t * _get_global_simple_cache (void) { - static cairo_cache_t *global_simple_cache = NULL; - if (global_simple_cache == NULL) { global_simple_cache = malloc (sizeof (cairo_cache_t)); @@ -287,12 +278,12 @@ _cairo_simple_font_cache_keys_equal (void *cache, a->weight == b->weight; } -static cairo_simple_font_face_t * -_cairo_simple_font_face_create_from_cache_key (cairo_simple_cache_key_t *key) +static cairo_toy_font_face_t * +_cairo_toy_font_face_create_from_cache_key (cairo_simple_cache_key_t *key) { - cairo_simple_font_face_t *simple_face; + cairo_toy_font_face_t *simple_face; - simple_face = malloc (sizeof (cairo_simple_font_face_t)); + simple_face = malloc (sizeof (cairo_toy_font_face_t)); if (!simple_face) return NULL; @@ -305,7 +296,7 @@ _cairo_simple_font_face_create_from_cache_key (cairo_simple_cache_key_t *key) simple_face->slant = key->slant; simple_face->weight = key->weight; - _cairo_font_face_init (&simple_face->base, &_cairo_simple_font_face_backend); + _cairo_font_face_init (&simple_face->base, &_cairo_toy_font_face_backend); return simple_face; } @@ -322,7 +313,7 @@ _cairo_simple_font_cache_create_entry (void *cache, if (entry == NULL) return CAIRO_STATUS_NO_MEMORY; - entry->font_face = _cairo_simple_font_face_create_from_cache_key (k); + entry->font_face = _cairo_toy_font_face_create_from_cache_key (k); if (!entry->font_face) { free (entry); return CAIRO_STATUS_NO_MEMORY; @@ -366,9 +357,9 @@ static const cairo_cache_backend_t _cairo_simple_font_cache_backend = { }; static void -_cairo_simple_font_face_destroy (void *abstract_face) +_cairo_toy_font_face_destroy (void *abstract_face) { - cairo_simple_font_face_t *simple_face = abstract_face; + cairo_toy_font_face_t *simple_face = abstract_face; cairo_cache_t *cache; cairo_simple_cache_key_t key; @@ -391,27 +382,27 @@ _cairo_simple_font_face_destroy (void *abstract_face) } static cairo_status_t -_cairo_simple_font_face_create_font (void *abstract_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **scaled_font) +_cairo_toy_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font) { const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT; - cairo_simple_font_face_t *simple_face = abstract_face; + cairo_toy_font_face_t *simple_face = abstract_face; - return backend->create (simple_face->family, simple_face->slant, simple_face->weight, - font_matrix, ctm, options, scaled_font); + return backend->create_toy (simple_face, + font_matrix, ctm, options, scaled_font); } -static const cairo_font_face_backend_t _cairo_simple_font_face_backend = { - _cairo_simple_font_face_destroy, - _cairo_simple_font_face_create_font, +static const cairo_font_face_backend_t _cairo_toy_font_face_backend = { + _cairo_toy_font_face_destroy, + _cairo_toy_font_face_scaled_font_create }; /** - * _cairo_simple_font_face_create: + * _cairo_toy_font_face_create: * @family: a font family name, encoded in UTF-8 * @slant: the slant for the font * @weight: the weight for the font @@ -424,9 +415,9 @@ static const cairo_font_face_backend_t _cairo_simple_font_face_backend = { * cairo_font_face_destroy() **/ cairo_font_face_t * -_cairo_simple_font_face_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight) +_cairo_toy_font_face_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) { cairo_simple_cache_entry_t *entry; cairo_simple_cache_key_t key; @@ -466,6 +457,10 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = { { 1., 0., 0., 1., 0, 0}, /* font_matrix */ { 1., 0., 0., 1., 0, 0}, /* ctm */ { 1., 0., 0., 1., 0, 0}, /* scale */ + { CAIRO_ANTIALIAS_DEFAULT, /* options */ + CAIRO_SUBPIXEL_ORDER_DEFAULT, + CAIRO_HINT_STYLE_DEFAULT, + CAIRO_HINT_METRICS_DEFAULT} , NULL, /* font_face */ CAIRO_SCALED_FONT_BACKEND_DEFAULT, }; @@ -497,7 +492,7 @@ _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font, /** * cairo_scaled_font_status: - * @surface: a #cairo_scaled_font_t + * @scaled_font: a #cairo_scaled_font_t * * Checks whether an error has previously occurred for this * scaled_font. @@ -560,11 +555,11 @@ _unlock_global_font_cache (void) CAIRO_MUTEX_UNLOCK (_global_font_cache_mutex); } +static cairo_cache_t *outer_font_cache = NULL; + static cairo_cache_t * _get_outer_font_cache (void) { - static cairo_cache_t *outer_font_cache = NULL; - if (outer_font_cache == NULL) { outer_font_cache = malloc (sizeof (cairo_cache_t)); @@ -585,11 +580,11 @@ _get_outer_font_cache (void) return NULL; } +static cairo_cache_t *inner_font_cache = NULL; + static cairo_cache_t * _get_inner_font_cache (void) { - static cairo_cache_t *inner_font_cache = NULL; - if (inner_font_cache == NULL) { inner_font_cache = malloc (sizeof (cairo_cache_t)); @@ -743,11 +738,11 @@ _cairo_inner_font_cache_create_entry (void *cache, if (entry == NULL) return CAIRO_STATUS_NO_MEMORY; - status = k->font_face->backend->create_font (k->font_face, - k->font_matrix, - k->ctm, - &k->options, - &entry->scaled_font); + status = k->font_face->backend->scaled_font_create (k->font_face, + k->font_matrix, + k->ctm, + &k->options, + &entry->scaled_font); if (status) { free (entry); return status; @@ -864,6 +859,7 @@ void _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, + const cairo_font_options_t *options, const cairo_scaled_font_backend_t *backend) { scaled_font->status = CAIRO_STATUS_SUCCESS; @@ -871,6 +867,8 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, scaled_font->font_matrix = *font_matrix; scaled_font->ctm = *ctm; cairo_matrix_multiply (&scaled_font->scale, &scaled_font->font_matrix, &scaled_font->ctm); + + scaled_font->options = *options; scaled_font->ref_count = 1; scaled_font->backend = backend; @@ -992,13 +990,15 @@ _cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font, unscaled_font->backend = backend; } -void +cairo_unscaled_font_t * _cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font) { if (unscaled_font == NULL) - return; + return NULL; unscaled_font->ref_count++; + + return unscaled_font; } void @@ -1027,17 +1027,21 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font) * Increases the reference count on @scaled_font by one. This prevents * @scaled_font from being destroyed until a matching call to * cairo_scaled_font_destroy() is made. + * + * Return value: the referenced #cairo_scaled_font_t. **/ -void +cairo_scaled_font_t * cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font) { if (scaled_font == NULL) - return; + return NULL; if (scaled_font->ref_count == (unsigned int)-1) - return; + return scaled_font; scaled_font->ref_count++; + + return scaled_font; } /** @@ -1071,6 +1075,7 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) key.font_face = scaled_font->font_face; key.font_matrix = &scaled_font->font_matrix; key.ctm = &scaled_font->ctm; + key.options = scaled_font->options; _cairo_cache_remove (cache, &key); _unlock_global_font_cache (); @@ -1078,7 +1083,7 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) cairo_font_face_destroy (scaled_font->font_face); } - scaled_font->backend->destroy (scaled_font); + scaled_font->backend->fini (scaled_font); free (scaled_font); } @@ -1089,9 +1094,6 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) * @extents: a #cairo_font_extents_t which to store the retrieved extents. * * Gets the metrics for a #cairo_scaled_font_t. - * - * Return value: %CAIRO_STATUS_SUCCESS on success. Otherwise, an - * error such as %CAIRO_STATUS_NO_MEMORY. **/ void cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font, @@ -1344,8 +1346,10 @@ _cairo_lock_global_image_glyph_cache() void _cairo_unlock_global_image_glyph_cache() { - _cairo_cache_shrink_to (_global_image_glyph_cache, - CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT); + if (_global_image_glyph_cache) { + _cairo_cache_shrink_to (_global_image_glyph_cache, + CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT); + } CAIRO_MUTEX_UNLOCK (_global_image_glyph_cache_mutex); } @@ -1372,3 +1376,24 @@ _cairo_get_global_image_glyph_cache () _global_image_glyph_cache = NULL; return NULL; } + +void +_cairo_font_reset_static_data (void) +{ + _lock_global_font_cache (); + _cairo_cache_destroy (outer_font_cache); + outer_font_cache = NULL; + _cairo_cache_destroy (inner_font_cache); + inner_font_cache = NULL; + _unlock_global_font_cache (); + + _cairo_lock_global_image_glyph_cache(); + _cairo_cache_destroy (_global_image_glyph_cache); + _global_image_glyph_cache = NULL; + _cairo_unlock_global_image_glyph_cache(); + + _lock_global_simple_cache (); + _cairo_cache_destroy (global_simple_cache); + global_simple_cache = NULL; + _unlock_global_simple_cache (); +} diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index afe80dff..36a0c674 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -76,31 +76,31 @@ * factors so that hinting works right */ -typedef struct { +typedef struct _cairo_ft_font_transform { double x_scale, y_scale; double shape[2][2]; -} ft_font_transform_t; +} cairo_ft_font_transform_t; /* * We create an object that corresponds to a single font on the disk; * (identified by a filename/id pair) these are shared between all - * fonts using that file. For cairo_ft_scaled_font_create_for_ft_face(), we + * fonts using that file. For cairo_ft_font_face_create_for_ft_face(), we * just create a one-off version with a permanent face value. */ -typedef struct _ft_font_face ft_font_face_t; +typedef struct _cairo_ft_font_face cairo_ft_font_face_t; -typedef struct { +struct _cairo_ft_unscaled_font { cairo_unscaled_font_t base; - cairo_bool_t from_face; /* from cairo_ft_scaled_font_create_for_ft_face()? */ + cairo_bool_t from_face; /* from cairo_ft_font_face_create_for_ft_face()? */ FT_Face face; /* provided or cached face */ /* only set if from_face is false */ char *filename; int id; - /* We temporarily scale the unscaled font as neede */ + /* We temporarily scale the unscaled font as needed */ cairo_bool_t have_scale; cairo_matrix_t current_scale; double x_scale; /* Extracted X scale factor */ @@ -109,38 +109,91 @@ typedef struct { int lock; /* count of how many times this font has been locked */ - ft_font_face_t *faces; /* Linked list of faces for this font */ -} ft_unscaled_font_t; + cairo_ft_font_face_t *faces; /* Linked list of faces for this font */ +}; -struct _ft_font_face { +struct _cairo_ft_font_face { cairo_font_face_t base; - ft_unscaled_font_t *unscaled; + cairo_ft_unscaled_font_t *unscaled; int load_flags; - ft_font_face_t *next_face; + cairo_ft_font_face_t *next; }; const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend; -static ft_unscaled_font_t * -_ft_unscaled_font_create_from_face (FT_Face face) +/** + * _cairo_ft_unscaled_font_init: + * + * Initialize a cairo_ft_unscaled_font_t. + * + * There are two basic flavors of cairo_ft_unscaled_font_t, one + * created from an FT_Face and the other created from a filename/id + * pair. These two flavors are identified as from_face and !from_face. + * + * To initialize a from_face font, pass filename==NULL, id=0 and the + * desired face. + * + * To initialize a !from_face font, pass the filename/id as desired + * and face==NULL. + * + * Note that the code handles these two flavors in very distinct + * ways. For example there is a hash_table mapping + * filename/id->cairo_unscaled_font_t in the !from_face case, but no + * parallel in the from_face case, (where the calling code would have + * to do its own mapping to ensure similar sharing). + **/ +static cairo_status_t +_cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, + const char *filename, + int id, + 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; + char *filename_copy = NULL; + + if (filename) { + filename_copy = strdup (filename); + if (filename_copy == NULL) + return CAIRO_STATUS_NO_MEMORY; + } + + unscaled->filename = filename_copy; + unscaled->id = id; + + if (face) { + unscaled->from_face = 1; + unscaled->face = face; + } else { + unscaled->from_face = 0; + unscaled->face = NULL; + } - unscaled->filename = NULL; - unscaled->id = 0; - unscaled->have_scale = 0; unscaled->lock = 0; - + unscaled->faces = NULL; _cairo_unscaled_font_init (&unscaled->base, &cairo_ft_unscaled_font_backend); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_ft_unscaled_font_t * +_cairo_ft_unscaled_font_create_from_face (FT_Face face) +{ + cairo_status_t status; + cairo_ft_unscaled_font_t *unscaled; + + unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); + if (unscaled == NULL) + return NULL; + + status = _cairo_ft_unscaled_font_init (unscaled, NULL, 0, face); + if (status) { + free (unscaled); + return NULL; + } + return unscaled; } @@ -150,36 +203,23 @@ _cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font) return unscaled_font->backend == &cairo_ft_unscaled_font_backend; } -static ft_unscaled_font_t * -_ft_unscaled_font_create_from_filename (const char *filename, - int id) +static cairo_ft_unscaled_font_t * +_cairo_ft_unscaled_font_create_from_filename (const char *filename, + int id) { - ft_unscaled_font_t *unscaled; - char *new_filename; + cairo_status_t status; + cairo_ft_unscaled_font_t *unscaled; - new_filename = strdup (filename); - if (!new_filename) + unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); + if (unscaled == NULL) return NULL; - unscaled = malloc (sizeof (ft_unscaled_font_t)); - if (!unscaled) { - free (new_filename); + status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL); + if (status) { + free (unscaled); return NULL; } - - unscaled->from_face = 0; - unscaled->face = NULL; - - unscaled->filename = new_filename; - unscaled->id = id; - - unscaled->have_scale = 0; - unscaled->lock = 0; - - unscaled->faces = NULL; - _cairo_unscaled_font_init (&unscaled->base, - &cairo_ft_unscaled_font_backend); return unscaled; } @@ -199,7 +239,7 @@ typedef struct { typedef struct { cairo_ft_cache_key_t key; - ft_unscaled_font_t *unscaled; + cairo_ft_unscaled_font_t *unscaled; } cairo_ft_cache_entry_t; typedef struct { @@ -209,7 +249,7 @@ typedef struct { } ft_cache_t; static unsigned long -_ft_font_cache_hash (void *cache, void *key) +_cairo_ft_font_cache_hash (void *cache, void *key) { cairo_ft_cache_key_t *in = (cairo_ft_cache_key_t *) key; unsigned long hash; @@ -222,9 +262,9 @@ _ft_font_cache_hash (void *cache, void *key) } static int -_ft_font_cache_keys_equal (void *cache, - void *k1, - void *k2) +_cairo_ft_font_cache_keys_equal (void *cache, + void *k1, + void *k2) { cairo_ft_cache_key_t *a; cairo_ft_cache_key_t *b; @@ -236,9 +276,9 @@ _ft_font_cache_keys_equal (void *cache, } static cairo_status_t -_ft_font_cache_create_entry (void *cache, - void *key, - void **return_entry) +_cairo_ft_font_cache_create_entry (void *cache, + void *key, + void **return_entry) { cairo_ft_cache_key_t *k = key; cairo_ft_cache_entry_t *entry; @@ -247,8 +287,8 @@ _ft_font_cache_create_entry (void *cache, if (entry == NULL) return CAIRO_STATUS_NO_MEMORY; - entry->unscaled = _ft_unscaled_font_create_from_filename (k->filename, - k->id); + entry->unscaled = _cairo_ft_unscaled_font_create_from_filename (k->filename, + k->id); if (!entry->unscaled) { free (entry); return CAIRO_STATUS_NO_MEMORY; @@ -268,8 +308,8 @@ _ft_font_cache_create_entry (void *cache, * in the code that removes the entry from the cache */ static void -_ft_font_cache_destroy_entry (void *cache, - void *entry) +_cairo_ft_font_cache_destroy_entry (void *cache, + void *entry) { cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry; @@ -277,7 +317,7 @@ _ft_font_cache_destroy_entry (void *cache, } static void -_ft_font_cache_destroy_cache (void *cache) +_cairo_ft_font_cache_destroy_cache (void *cache) { ft_cache_t *fc = (ft_cache_t *) cache; @@ -286,11 +326,11 @@ _ft_font_cache_destroy_cache (void *cache) } static const cairo_cache_backend_t _ft_font_cache_backend = { - _ft_font_cache_hash, - _ft_font_cache_keys_equal, - _ft_font_cache_create_entry, - _ft_font_cache_destroy_entry, - _ft_font_cache_destroy_cache + _cairo_ft_font_cache_hash, + _cairo_ft_font_cache_keys_equal, + _cairo_ft_font_cache_create_entry, + _cairo_ft_font_cache_destroy_entry, + _cairo_ft_font_cache_destroy_cache }; static ft_cache_t *_global_ft_cache = NULL; @@ -339,8 +379,8 @@ _get_global_ft_cache (void) /* 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) +static cairo_ft_unscaled_font_t * +_cairo_ft_unscaled_font_get_for_pattern (FcPattern *pattern) { cairo_ft_cache_entry_t *entry; cairo_ft_cache_key_t key; @@ -384,9 +424,12 @@ _has_unlocked_face (void *entry) /* Ensures that an unscaled font has a face object. If we exceed * MAX_OPEN_FACES, try to close some. + * + * 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. */ -static FT_Face -_ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled) +FT_Face +_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled) { ft_cache_t *ftcache; FT_Face face = NULL; @@ -433,8 +476,8 @@ _ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled) /* Unlock unscaled font locked with _ft_unscaled_font_lock_face */ -static void -_ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled) +void +_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled) { assert (unscaled->lock > 0); @@ -442,7 +485,7 @@ _ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled) } static void -_compute_transform (ft_font_transform_t *sf, +_compute_transform (cairo_ft_font_transform_t *sf, cairo_matrix_t *scale) { cairo_matrix_t normalized = *scale; @@ -476,10 +519,10 @@ _compute_transform (ft_font_transform_t *sf, * 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_matrix_t *scale) +_cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, + cairo_matrix_t *scale) { - ft_font_transform_t sf; + cairo_ft_font_transform_t sf; FT_Matrix mat; FT_UInt pixel_width, pixel_height; FT_Error error; @@ -528,7 +571,11 @@ _ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled, pixel_width = pixel_height = 0; for (i = 0; i < unscaled->face->num_fixed_sizes; i++) { +#if HAVE_FT_BITMAP_SIZE_Y_PPEM double size = unscaled->face->available_sizes[i].y_ppem / 64.; +#else + double size = unscaled->face->available_sizes[i].height; +#endif double distance = fabs (size - sf.y_scale); if (distance <= min_distance) { @@ -536,11 +583,13 @@ _ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled, best_i = i; } } +#if HAVE_FT_BITMAP_SIZE_Y_PPEM error = FT_Set_Char_Size (unscaled->face, unscaled->face->available_sizes[best_i].x_ppem, unscaled->face->available_sizes[best_i].y_ppem, 0, 0); - if (error ) + if (error) +#endif error = FT_Set_Pixel_Sizes (unscaled->face, unscaled->face->available_sizes[best_i].width, unscaled->face->available_sizes[best_i].height); @@ -552,7 +601,7 @@ _ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled, static void _cairo_ft_unscaled_font_destroy (void *abstract_font) { - ft_unscaled_font_t *unscaled = abstract_font; + cairo_ft_unscaled_font_t *unscaled = abstract_font; if (unscaled == NULL) return; @@ -990,7 +1039,7 @@ _render_glyph_bitmap (FT_Face face, static cairo_status_t _transform_glyph_bitmap (cairo_image_glyph_cache_entry_t *val) { - ft_font_transform_t sf; + cairo_ft_font_transform_t sf; cairo_matrix_t original_to_transformed; cairo_matrix_t transformed_to_original; cairo_image_surface_t *old_image; @@ -1110,21 +1159,21 @@ static cairo_status_t _cairo_ft_unscaled_font_create_glyph (void *abstract_font, cairo_image_glyph_cache_entry_t *val) { - ft_unscaled_font_t *unscaled = abstract_font; + cairo_ft_unscaled_font_t *unscaled = abstract_font; FT_GlyphSlot glyphslot; FT_Face face; FT_Glyph_Metrics *metrics; cairo_status_t status = CAIRO_STATUS_SUCCESS; double x_factor, y_factor; - face = _ft_unscaled_font_lock_face (unscaled); + face = _cairo_ft_unscaled_font_lock_face (unscaled); if (!face) return CAIRO_STATUS_NO_MEMORY; glyphslot = face->glyph; metrics = &glyphslot->metrics; - _ft_unscaled_font_set_scale (unscaled, &val->key.scale); + _cairo_ft_unscaled_font_set_scale (unscaled, &val->key.scale); if (FT_Load_Glyph (face, val->key.index, val->key.flags & ~PRIVATE_FLAGS_MASK) != 0) { status = CAIRO_STATUS_NO_MEMORY; @@ -1203,7 +1252,7 @@ _cairo_ft_unscaled_font_create_glyph (void *abstract_ val->image = NULL; } - _ft_unscaled_font_unlock_face (unscaled); + _cairo_ft_unscaled_font_unlock_face (unscaled); return status; } @@ -1215,11 +1264,10 @@ const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = { /* cairo_ft_scaled_font_t */ -typedef struct { +typedef struct _cairo_ft_scaled_font { cairo_scaled_font_t base; int load_flags; - cairo_font_options_t options; - ft_unscaled_font_t *unscaled; + cairo_ft_unscaled_font_t *unscaled; } cairo_ft_scaled_font_t; const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend; @@ -1370,31 +1418,31 @@ _get_options_load_flags (const cairo_font_options_t *options) } static cairo_scaled_font_t * -_ft_scaled_font_create (ft_unscaled_font_t *unscaled, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - int load_flags) +_cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + int load_flags) { - cairo_ft_scaled_font_t *f = NULL; + cairo_ft_scaled_font_t *scaled_font = NULL; - f = malloc (sizeof(cairo_ft_scaled_font_t)); - if (f == NULL) + scaled_font = malloc (sizeof(cairo_ft_scaled_font_t)); + if (scaled_font == NULL) return NULL; - f->unscaled = unscaled; + scaled_font->unscaled = unscaled; _cairo_unscaled_font_reference (&unscaled->base); - f->options = *options; - if (options->hint_metrics != CAIRO_HINT_METRICS_OFF) load_flags |= PRIVATE_FLAG_HINT_METRICS; - f->load_flags = load_flags; + scaled_font->load_flags = load_flags; - _cairo_scaled_font_init (&f->base, font_matrix, ctm, &cairo_ft_scaled_font_backend); + _cairo_scaled_font_init (&scaled_font->base, + font_matrix, ctm, options, + &cairo_ft_scaled_font_backend); - return (cairo_scaled_font_t *)f; + return (cairo_scaled_font_t*) scaled_font; } cairo_bool_t @@ -1404,28 +1452,28 @@ _cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font) } static cairo_status_t -_cairo_ft_scaled_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **font) +_cairo_ft_scaled_font_create_toy (const cairo_toy_font_face_t *toy_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font) { FcPattern *pattern, *resolved; - ft_unscaled_font_t *unscaled; + cairo_ft_unscaled_font_t *unscaled; cairo_scaled_font_t *new_font; FcResult result; int fcslant; int fcweight; cairo_matrix_t scale; - ft_font_transform_t sf; + cairo_ft_font_transform_t sf; + int load_flags; + unsigned char *family = (unsigned char*) toy_face->family; pattern = FcPatternCreate (); if (!pattern) return CAIRO_STATUS_NO_MEMORY; - switch (weight) + switch (toy_face->weight) { case CAIRO_FONT_WEIGHT_BOLD: fcweight = FC_WEIGHT_BOLD; @@ -1436,7 +1484,7 @@ _cairo_ft_scaled_font_create (const char *family, break; } - switch (slant) + switch (toy_face->slant) { case CAIRO_FONT_SLANT_ITALIC: fcslant = FC_SLANT_ITALIC; @@ -1450,7 +1498,7 @@ _cairo_ft_scaled_font_create (const char *family, break; } - if (!FcPatternAddString (pattern, FC_FAMILY, (unsigned char *) family)) + if (!FcPatternAddString (pattern, FC_FAMILY, family)) goto FREE_PATTERN; if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) goto FREE_PATTERN; @@ -1470,13 +1518,15 @@ _cairo_ft_scaled_font_create (const char *family, if (!resolved) goto FREE_PATTERN; - unscaled = _ft_unscaled_font_get_for_pattern (resolved); + unscaled = _cairo_ft_unscaled_font_get_for_pattern (resolved); if (!unscaled) goto FREE_RESOLVED; - - new_font = _ft_scaled_font_create (unscaled, - font_matrix, ctm, - options, _get_pattern_load_flags (pattern)); + + load_flags = _get_pattern_load_flags (pattern); + new_font = _cairo_ft_scaled_font_create (unscaled, + font_matrix, ctm, + options, load_flags); + _cairo_unscaled_font_destroy (&unscaled->base); FcPatternDestroy (resolved); @@ -1499,7 +1549,7 @@ _cairo_ft_scaled_font_create (const char *family, } static void -_cairo_ft_scaled_font_destroy (void *abstract_font) +_cairo_ft_scaled_font_fini (void *abstract_font) { cairo_ft_scaled_font_t *scaled_font = abstract_font; @@ -1599,19 +1649,20 @@ _cairo_ft_scaled_font_font_extents (void *abstract_font, FT_Face face; FT_Size_Metrics *metrics; - face = _ft_unscaled_font_lock_face (scaled_font->unscaled); + face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled); if (!face) return CAIRO_STATUS_NO_MEMORY; metrics = &face->size->metrics; - _ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale); + _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, + &scaled_font->base.scale); /* * Get to unscaled metrics so that the upper level can get back to * user space */ - if (scaled_font->options.hint_metrics != CAIRO_HINT_METRICS_OFF) { + if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { double x_factor, y_factor; if (scaled_font->unscaled->x_scale == 0) @@ -1640,7 +1691,7 @@ _cairo_ft_scaled_font_font_extents (void *abstract_font, /* FIXME: this doesn't do vertical layout atm. */ extents->max_y_advance = 0.0; - _ft_unscaled_font_unlock_face (scaled_font->unscaled); + _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); return CAIRO_STATUS_SUCCESS; } @@ -1697,7 +1748,7 @@ _cairo_ft_scaled_font_glyph_extents (void *abstract_font, /* XXX: Need to add code here to check the font's FcPattern for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y instead. This will require that - cairo_ft_scaled_font_create_for_ft_face accept an + cairo_ft_font_face_create_for_ft_face accept an FcPattern. */ glyph_min.x = glyphs[i].x + img->extents.x_bearing; glyph_min.y = glyphs[i].y + img->extents.y_bearing; @@ -1793,6 +1844,26 @@ _cairo_ft_scaled_font_glyph_bbox (void *abstract_font, return CAIRO_STATUS_SUCCESS; } +static cairo_format_t +_select_text_mask_format (cairo_bool_t have_a1_glyphs, + cairo_bool_t have_a8_glyphs, + cairo_bool_t have_argb32_glyphs) +{ + if (have_a8_glyphs) + return CAIRO_FORMAT_A8; + + if (have_a1_glyphs && have_argb32_glyphs) + return CAIRO_FORMAT_A8; + + if (have_a1_glyphs) + return CAIRO_FORMAT_A1; + + if (have_argb32_glyphs) + return CAIRO_FORMAT_ARGB32; + + /* when there are no glyphs to draw, just pick something */ + return CAIRO_FORMAT_A8; +} static cairo_status_t _cairo_ft_scaled_font_show_glyphs (void *abstract_font, @@ -1808,12 +1879,16 @@ _cairo_ft_scaled_font_show_glyphs (void *abstract_font, const cairo_glyph_t *glyphs, int num_glyphs) { - cairo_image_glyph_cache_entry_t *img; + cairo_image_glyph_cache_entry_t **entries; cairo_cache_t *cache; cairo_glyph_cache_key_t key; cairo_ft_scaled_font_t *scaled_font = abstract_font; cairo_surface_pattern_t glyph_pattern; - cairo_status_t status; + cairo_surface_t *mask; + cairo_surface_pattern_t mask_pattern; + cairo_format_t mask_format = CAIRO_FORMAT_A1; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_bool_t have_a1_glyphs, have_a8_glyphs, have_argb32_glyphs; int x, y; int i; @@ -1833,44 +1908,98 @@ _cairo_ft_scaled_font_show_glyphs (void *abstract_font, key.scale = scaled_font->base.scale; key.flags = scaled_font->load_flags; + entries = malloc (num_glyphs * sizeof (cairo_image_glyph_cache_entry_t)); + if (!entries) + goto CLEANUP_CACHE; + + have_a1_glyphs = FALSE; + have_a8_glyphs = FALSE; + have_argb32_glyphs = FALSE; + for (i = 0; i < num_glyphs; i++) { - img = NULL; + entries[i] = NULL; key.index = glyphs[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL) - != CAIRO_STATUS_SUCCESS - || img == NULL - || img->image == NULL) + if (_cairo_cache_lookup (cache, &key, (void **) &entries[i], NULL) != CAIRO_STATUS_SUCCESS) + continue; + + switch (entries[i]->image->format) { + case CAIRO_FORMAT_A1: + have_a1_glyphs = TRUE; + break; + case CAIRO_FORMAT_A8: + have_a8_glyphs = TRUE; + break; + case CAIRO_FORMAT_ARGB32: + have_argb32_glyphs = TRUE; + break; + default: + break; + } + } + + mask_format = _select_text_mask_format (have_a1_glyphs, have_a8_glyphs, have_argb32_glyphs); + + mask = cairo_image_surface_create (mask_format, width, height); + if (!mask) + goto CLEANUP_ENTRIES; + + status = _cairo_surface_fill_rectangle (mask, CAIRO_OPERATOR_SOURCE, + CAIRO_COLOR_TRANSPARENT, + 0, 0, width, height); + if (status) + goto CLEANUP_MASK; + + for (i = 0; i < num_glyphs; i++) + { + if (entries[i] == NULL + || entries[i]->image == NULL) continue; x = (int) floor (glyphs[i].x + 0.5); y = (int) floor (glyphs[i].y + 0.5); - _cairo_pattern_init_for_surface (&glyph_pattern, &(img->image->base)); + _cairo_pattern_init_for_surface (&glyph_pattern, &(entries[i]->image->base)); - status = _cairo_surface_composite (operator, pattern, + status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, pattern, &glyph_pattern.base, - surface, - x + img->size.x, - y + img->size.y, + mask, + x + entries[i]->size.x, + y + entries[i]->size.y, 0, 0, - x + img->size.x, - y + img->size.y, - (double) img->size.width, - (double) img->size.height); + x + entries[i]->size.x - dest_x, + y + entries[i]->size.y - dest_y, + entries[i]->size.width, + entries[i]->size.height); _cairo_pattern_fini (&glyph_pattern.base); - if (status) { - _cairo_unlock_global_image_glyph_cache (); - return status; - } - } + if (status) + goto CLEANUP_MASK; + } + + _cairo_pattern_init_for_surface (&mask_pattern, mask); + + status = _cairo_surface_composite (operator, pattern, &mask_pattern.base, + surface, + source_x, source_y, + 0, 0, + dest_x, dest_y, + width, height); + + _cairo_pattern_fini (&mask_pattern.base); + + CLEANUP_MASK: + cairo_surface_destroy (mask); + + CLEANUP_ENTRIES: + free (entries); + CLEANUP_CACHE: _cairo_unlock_global_image_glyph_cache (); - return CAIRO_STATUS_SUCCESS; + return status; } @@ -2018,26 +2147,26 @@ _cairo_ft_scaled_font_glyph_path (void *abstract_font, } const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = { - _cairo_ft_scaled_font_create, - _cairo_ft_scaled_font_destroy, + _cairo_ft_scaled_font_create_toy, + _cairo_ft_scaled_font_fini, _cairo_ft_scaled_font_font_extents, _cairo_ft_scaled_font_text_to_glyphs, _cairo_ft_scaled_font_glyph_extents, _cairo_ft_scaled_font_glyph_bbox, _cairo_ft_scaled_font_show_glyphs, _cairo_ft_scaled_font_glyph_path, - _cairo_ft_scaled_font_get_glyph_cache_key, + _cairo_ft_scaled_font_get_glyph_cache_key }; /* ft_font_face_t */ static void -_ft_font_face_destroy (void *abstract_face) +_cairo_ft_font_face_destroy (void *abstract_face) { - ft_font_face_t *font_face = abstract_face; + cairo_ft_font_face_t *font_face = abstract_face; - ft_font_face_t *tmp_face = NULL; - ft_font_face_t *last_face = NULL; + cairo_ft_font_face_t *tmp_face = NULL; + cairo_ft_font_face_t *last_face = NULL; if (font_face == NULL) return; @@ -2069,12 +2198,15 @@ _ft_font_face_destroy (void *abstract_face) if (font_face->unscaled) { /* Remove face from linked list */ - for (tmp_face = font_face->unscaled->faces; tmp_face; tmp_face = tmp_face->next_face) { + for (tmp_face = font_face->unscaled->faces; + tmp_face; + tmp_face = tmp_face->next) + { if (tmp_face == font_face) { if (last_face) - last_face->next_face = tmp_face->next_face; + last_face->next = tmp_face->next; else - font_face->unscaled->faces = tmp_face->next_face; + font_face->unscaled->faces = tmp_face->next; } last_face = tmp_face; @@ -2086,13 +2218,13 @@ _ft_font_face_destroy (void *abstract_face) } static cairo_status_t -_ft_font_face_create_font (void *abstract_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **scaled_font) +_cairo_ft_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font) { - ft_font_face_t *font_face = abstract_face; + cairo_ft_font_face_t *font_face = abstract_face; int load_flags; /* The handling of font options is different depending on how the @@ -2109,36 +2241,37 @@ _ft_font_face_create_font (void *abstract_face, else load_flags = font_face->load_flags; - *scaled_font = _ft_scaled_font_create (font_face->unscaled, - font_matrix, ctm, - options, load_flags); + *scaled_font = _cairo_ft_scaled_font_create (font_face->unscaled, + font_matrix, ctm, + options, load_flags); if (*scaled_font) return CAIRO_STATUS_SUCCESS; else return CAIRO_STATUS_NO_MEMORY; } -static const cairo_font_face_backend_t _ft_font_face_backend = { - _ft_font_face_destroy, - _ft_font_face_create_font, +static const cairo_font_face_backend_t _cairo_ft_font_face_backend = { + _cairo_ft_font_face_destroy, + _cairo_ft_font_face_scaled_font_create }; static cairo_font_face_t * -_ft_font_face_create (ft_unscaled_font_t *unscaled, - int load_flags) +_cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled, + int load_flags) { - ft_font_face_t *font_face; + cairo_ft_font_face_t *font_face; /* Looked for an existing matching font face */ - for (font_face = unscaled->faces; font_face; font_face = font_face->next_face) { - if (font_face->load_flags == load_flags) { - cairo_font_face_reference (&font_face->base); - return &font_face->base; - } + for (font_face = unscaled->faces; + font_face; + font_face = font_face->next) + { + if (font_face->load_flags == load_flags) + return cairo_font_face_reference (&font_face->base); } /* No match found, create a new one */ - font_face = malloc (sizeof (ft_font_face_t)); + font_face = malloc (sizeof (cairo_ft_font_face_t)); if (!font_face) return NULL; @@ -2147,10 +2280,10 @@ _ft_font_face_create (ft_unscaled_font_t *unscaled, font_face->load_flags = load_flags; - font_face->next_face = unscaled->faces; + font_face->next = unscaled->faces; unscaled->faces = font_face; - _cairo_font_face_init (&font_face->base, &_ft_font_face_backend); + _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend); return &font_face->base; } @@ -2272,16 +2405,17 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options, cairo_font_face_t * cairo_ft_font_face_create_for_pattern (FcPattern *pattern) { - ft_unscaled_font_t *unscaled; + cairo_ft_unscaled_font_t *unscaled; cairo_font_face_t *font_face; - unscaled = _ft_unscaled_font_get_for_pattern (pattern); + unscaled = _cairo_ft_unscaled_font_get_for_pattern (pattern); if (unscaled == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_font_face_t *)&_cairo_font_face_nil; } - font_face = _ft_font_face_create (unscaled, _get_pattern_load_flags (pattern)); + font_face = _cairo_ft_font_face_create (unscaled, + _get_pattern_load_flags (pattern)); _cairo_unscaled_font_destroy (&unscaled->base); if (font_face) @@ -2321,16 +2455,16 @@ cairo_font_face_t * cairo_ft_font_face_create_for_ft_face (FT_Face face, int load_flags) { - ft_unscaled_font_t *unscaled; + cairo_ft_unscaled_font_t *unscaled; cairo_font_face_t *font_face; - unscaled = _ft_unscaled_font_create_from_face (face); + unscaled = _cairo_ft_unscaled_font_create_from_face (face); if (unscaled == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_font_face_t *)&_cairo_font_face_nil; } - font_face = _ft_font_face_create (unscaled, load_flags); + font_face = _cairo_ft_font_face_create (unscaled, load_flags); _cairo_unscaled_font_destroy (&unscaled->base); if (font_face) { @@ -2379,13 +2513,13 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font) if (scaled_font->base.status) return NULL; - face = _ft_unscaled_font_lock_face (scaled_font->unscaled); + face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled); if (face == NULL) { _cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY); return NULL; } - _ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale); + _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, &scaled_font->base.scale); return face; } @@ -2408,7 +2542,7 @@ cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font) if (scaled_font->base.status) return; - _ft_unscaled_font_unlock_face (scaled_font->unscaled); + _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); } /* We expose our unscaled font implementation internally for the the @@ -2423,17 +2557,15 @@ _cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *abstract_font) return &scaled_font->unscaled->base; } -/* 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) +_cairo_ft_font_reset_static_data (void) { - _ft_unscaled_font_unlock_face ((ft_unscaled_font_t *)unscaled_font); + _lock_global_ft_cache (); + if (_global_ft_cache) { + FT_Done_FreeType (_global_ft_cache->lib); + _global_ft_cache->lib = NULL; + } + _cairo_cache_destroy (&_global_ft_cache->base); + _global_ft_cache = NULL; + _unlock_global_ft_cache (); } diff --git a/src/cairo-ft-private.h b/src/cairo-ft-private.h index e92048b2..8bd43413 100644 --- a/src/cairo-ft-private.h +++ b/src/cairo-ft-private.h @@ -44,6 +44,8 @@ CAIRO_BEGIN_DECLS +typedef struct _cairo_ft_unscaled_font cairo_ft_unscaled_font_t; + cairo_bool_t _cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font); @@ -57,10 +59,10 @@ cairo_private cairo_unscaled_font_t * _cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *scaled_font); cairo_private FT_Face -_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font); +_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled); cairo_private void -_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font); +_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled); CAIRO_END_DECLS diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c index 96e92033..7e0f3387 100644 --- a/src/cairo-glitz-surface.c +++ b/src/cairo-glitz-surface.c @@ -349,8 +349,7 @@ _cairo_glitz_surface_clone_similar (void *abstract_surface, if (src->backend == surface->base.backend) { - *clone_out = src; - cairo_surface_reference (src); + *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } @@ -937,6 +936,7 @@ static cairo_int_status_t _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, diff --git a/src/cairo-gstate-private.h b/src/cairo-gstate-private.h index 0d4d499f..489afdba 100644 --- a/src/cairo-gstate-private.h +++ b/src/cairo-gstate-private.h @@ -36,51 +36,13 @@ #ifndef CAIRO_GSTATE_PRIVATE_H #define CAIRO_GSTATE_PRIVATE_H -#include "cairo-path-fixed-private.h" - -struct _cairo_clip_path { - unsigned int ref_count; - cairo_path_fixed_t path; - cairo_fill_rule_t fill_rule; - double tolerance; - cairo_clip_path_t *prev; -}; - -typedef struct _cairo_clip { - cairo_clip_mode_t mode; - - /* - * Mask-based clipping for cases where the backend - * clipping isn't sufficiently able. - * - * The rectangle here represents the - * portion of the destination surface that this - * clip surface maps to, it does not - * represent the extents of the clip region or - * clip paths - */ - cairo_surface_t *surface; - cairo_rectangle_t surface_rect; - /* - * Surface clip serial number to store - * in the surface when this clip is set - */ - unsigned int serial; - /* - * A clip region that can be placed in the surface - */ - pixman_region16_t *region; - /* - * If the surface supports path clipping, we store the list of - * clipping paths that has been set here as a linked list. - */ - cairo_clip_path_t *path; -} cairo_clip_t; +#include "cairo-clip-private.h" struct _cairo_gstate { cairo_operator_t operator; double tolerance; + cairo_antialias_t antialias; /* stroke style */ double line_width; @@ -103,6 +65,7 @@ struct _cairo_gstate { cairo_matrix_t ctm; cairo_matrix_t ctm_inverse; + cairo_matrix_t source_ctm_inverse; /* At the time ->source was set */ cairo_pen_t pen_regular; diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index ed3359b9..a657f15e 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -39,6 +39,7 @@ #include "cairoint.h" +#include "cairo-clip-private.h" #include "cairo-gstate-private.h" static cairo_status_t @@ -53,28 +54,16 @@ _cairo_gstate_fini (cairo_gstate_t *gstate); static cairo_status_t _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, - cairo_pattern_t *src, - cairo_operator_t operator, - cairo_surface_t *dst, - cairo_traps_t *traps); - -static cairo_status_t -_cairo_gstate_ensure_font (cairo_gstate_t *gstate); + cairo_traps_t *traps); static cairo_status_t _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate); -static void -_cairo_gstate_unset_font (cairo_gstate_t *gstate); - -static void -_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src); - -static void -_cairo_clip_path_reference (cairo_clip_path_t *clip_path); +static cairo_status_t +_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate); static void -_cairo_clip_path_destroy (cairo_clip_path_t *clip_path); +_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate); cairo_gstate_t * _cairo_gstate_create (cairo_surface_t *target) @@ -103,6 +92,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate, gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT; gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT; + gstate->antialias = CAIRO_ANTIALIAS_DEFAULT; gstate->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT; gstate->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT; @@ -124,18 +114,14 @@ _cairo_gstate_init (cairo_gstate_t *gstate, _cairo_font_options_init_default (&gstate->font_options); - gstate->clip.mode = _cairo_surface_get_clip_mode (target); - gstate->clip.region = NULL; - gstate->clip.surface = NULL; - gstate->clip.serial = 0; - gstate->clip.path = NULL; + _cairo_clip_init (&gstate->clip, target); _cairo_gstate_identity_matrix (gstate); + cairo_matrix_init_identity (&gstate->source_ctm_inverse); _cairo_pen_init_empty (&gstate->pen_regular); - gstate->target = target; - cairo_surface_reference (gstate->target); + gstate->target = cairo_surface_reference (target); gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK); if (gstate->source->status) @@ -165,10 +151,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double)); } - if (other->clip.region) { - gstate->clip.region = pixman_region_create (); - pixman_region_copy (gstate->clip.region, other->clip.region); - } + _cairo_clip_init_copy (&gstate->clip, &other->clip); if (gstate->font_face) cairo_font_face_reference (gstate->font_face); @@ -177,8 +160,6 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) cairo_scaled_font_reference (gstate->scaled_font); cairo_surface_reference (gstate->target); - cairo_surface_reference (gstate->clip.surface); - _cairo_clip_path_reference (gstate->clip.path); cairo_pattern_reference (gstate->source); @@ -212,18 +193,7 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) gstate->target = NULL; } - if (gstate->clip.surface) - cairo_surface_destroy (gstate->clip.surface); - gstate->clip.surface = NULL; - - if (gstate->clip.path) - _cairo_clip_path_destroy (gstate->clip.path); - gstate->clip.path = NULL; - - if (gstate->clip.region) - pixman_region_destroy (gstate->clip.region); - gstate->clip.region = NULL; - gstate->clip.serial = 0; + _cairo_clip_fini (&gstate->clip); cairo_pattern_destroy (gstate->source); @@ -343,61 +313,6 @@ _cairo_gstate_end_group (cairo_gstate_t *gstate) } */ -static cairo_status_t -_cairo_gstate_set_clip (cairo_gstate_t *gstate) -{ - cairo_surface_t *surface = gstate->target; - - if (!surface) - return CAIRO_STATUS_NULL_POINTER; - if (gstate->clip.serial == _cairo_surface_get_current_clip_serial (surface)) - return CAIRO_STATUS_SUCCESS; - - if (gstate->clip.path) - return _cairo_surface_set_clip_path (surface, - gstate->clip.path, - gstate->clip.serial); - - if (gstate->clip.region) - return _cairo_surface_set_clip_region (surface, - gstate->clip.region, - gstate->clip.serial); - - return _cairo_surface_reset_clip (surface); -} - -static cairo_status_t -_cairo_gstate_get_clip_extents (cairo_gstate_t *gstate, - cairo_rectangle_t *rectangle) -{ - cairo_status_t status; - - status = _cairo_surface_get_extents (gstate->target, rectangle); - if (status) - return status; - /* check path extents here */ - - if (gstate->clip.region) { - pixman_box16_t *clip_box; - cairo_rectangle_t clip_rect; - - /* get region extents as a box */ - clip_box = pixman_region_extents (gstate->clip.region); - /* convert to a rectangle */ - clip_rect.x = clip_box->x1; - clip_rect.width = clip_box->x2 - clip_box->x1; - clip_rect.y = clip_box->y1; - clip_rect.height = clip_box->y2 - clip_box->y1; - /* intersect with surface extents */ - _cairo_rectangle_intersect (rectangle, &clip_rect); - } - - if (gstate->clip.surface) - _cairo_rectangle_intersect (rectangle, &gstate->clip.surface_rect); - - return CAIRO_STATUS_SUCCESS; -} - cairo_surface_t * _cairo_gstate_get_target (cairo_gstate_t *gstate) { @@ -414,6 +329,7 @@ _cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_reference (source); cairo_pattern_destroy (gstate->source); gstate->source = source; + gstate->source_ctm_inverse = gstate->ctm_inverse; return CAIRO_STATUS_SUCCESS; } @@ -559,7 +475,7 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty) { cairo_matrix_t tmp; - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); cairo_matrix_init_translate (&tmp, tx, ty); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -578,7 +494,7 @@ _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_gstate_unset_scaled_font (gstate); cairo_matrix_init_scale (&tmp, sx, sy); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -594,7 +510,7 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle) { cairo_matrix_t tmp; - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); cairo_matrix_init_rotate (&tmp, angle); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -611,7 +527,7 @@ _cairo_gstate_transform (cairo_gstate_t *gstate, { cairo_matrix_t tmp; - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); tmp = *matrix; cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); @@ -628,7 +544,7 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate, { cairo_status_t status; - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); gstate->ctm = *matrix; @@ -643,7 +559,7 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate, cairo_status_t _cairo_gstate_identity_matrix (cairo_gstate_t *gstate) { - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); cairo_matrix_init_identity (&gstate->ctm); cairo_matrix_init_identity (&gstate->ctm_inverse); @@ -717,11 +633,15 @@ _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate) */ static void -_cairo_gstate_pattern_transform (cairo_gstate_t *gstate, - cairo_pattern_t *pattern) +_cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate, + cairo_pattern_t *pattern, + cairo_pattern_t *original, + cairo_matrix_t *ctm_inverse) { - cairo_matrix_t tmp_matrix = gstate->ctm_inverse; - + cairo_matrix_t tmp_matrix = *ctm_inverse; + + _cairo_pattern_init_copy (pattern, original); + if (gstate->target) cairo_matrix_translate (&tmp_matrix, - gstate->target->device_x_offset, @@ -730,6 +650,25 @@ _cairo_gstate_pattern_transform (cairo_gstate_t *gstate, _cairo_pattern_transform (pattern, &tmp_matrix); } +static void +_cairo_gstate_copy_transformed_source (cairo_gstate_t *gstate, + cairo_pattern_t *pattern) +{ + _cairo_gstate_copy_transformed_pattern (gstate, pattern, + gstate->source, + &gstate->source_ctm_inverse); +} + +static void +_cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate, + cairo_pattern_t *pattern, + cairo_pattern_t *mask) +{ + _cairo_gstate_copy_transformed_pattern (gstate, pattern, + mask, + &gstate->ctm_inverse); +} + cairo_status_t _cairo_gstate_paint (cairo_gstate_t *gstate) { @@ -741,11 +680,14 @@ _cairo_gstate_paint (cairo_gstate_t *gstate) if (gstate->source->status) return gstate->source->status; - status = _cairo_gstate_set_clip (gstate); + status = _cairo_surface_set_clip (gstate->target, &gstate->clip); if (status) return status; - status = _cairo_gstate_get_clip_extents (gstate, &rectangle); + status = _cairo_surface_get_extents (gstate->target, &rectangle); + if (status) + return status; + status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &rectangle); if (status) return status; @@ -757,119 +699,310 @@ _cairo_gstate_paint (cairo_gstate_t *gstate) if (status) return status; - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->target, - &traps); + _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps); _cairo_traps_fini (&traps); return CAIRO_STATUS_SUCCESS; } -/* Combines @gstate->clip_surface using the IN operator with - * the given intermediate surface, which corresponds to the - * rectangle of the destination space given by @extents. +/** + * _cairo_operator_bounded: + * @operator: a #cairo_operator_t + * + * A bounded operator is one where a source or mask pixel + * of zero results in no effect on the destination image. + * + * Unbounded operators often require special handling; if you, for + * example, draw trapezoids with an unbounded operator, the effect + * extends past the bounding box of the trapezoids. + * + * Return value: %TRUE if the operator is bounded + **/ +cairo_bool_t +_cairo_operator_bounded (cairo_operator_t operator) +{ + switch (operator) { + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + return TRUE; + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_ATOP: + return FALSE; + } + + ASSERT_NOT_REACHED; + return FALSE; +} + +typedef cairo_status_t (*cairo_draw_func_t) (void *closure, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents); + +/* Handles compositing with a clip surface when the operator allows + * us to combine the clip with the mask */ static cairo_status_t -_cairo_gstate_combine_clip_surface (cairo_gstate_t *gstate, - cairo_surface_t *intermediate, - cairo_rectangle_t *extents) +_cairo_gstate_clip_and_composite_with_mask (cairo_clip_t *clip, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_t *extents) { - cairo_pattern_union_t pattern; + cairo_surface_t *intermediate; + cairo_surface_pattern_t intermediate_pattern; cairo_status_t status; - _cairo_pattern_init_for_surface (&pattern.surface, - gstate->clip.surface); + intermediate = cairo_surface_create_similar (clip->surface, + CAIRO_CONTENT_ALPHA, + extents->width, + extents->height); + if (intermediate->status) + return CAIRO_STATUS_NO_MEMORY; + + status = (*draw_func) (draw_closure, CAIRO_OPERATOR_SOURCE, + NULL, intermediate, + extents->x, extents->y, + extents); + if (status) + goto CLEANUP_SURFACE; - status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - &pattern.base, - NULL, - intermediate, - extents->x - gstate->clip.surface_rect.x, - extents->y - gstate->clip.surface_rect.y, - 0, 0, - 0, 0, - extents->width, extents->height); + status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN, + intermediate, + extents->x, extents->y, + extents); + if (status) + goto CLEANUP_SURFACE; - _cairo_pattern_fini (&pattern.base); + _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); + + status = _cairo_surface_composite (operator, + src, &intermediate_pattern.base, dst, + extents->x, extents->y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + + _cairo_pattern_fini (&intermediate_pattern.base); + + CLEANUP_SURFACE: + cairo_surface_destroy (intermediate); return status; } -/* Creates a region from a cairo_rectangle_t */ +/* Handles compositing with a clip surface when the operator allows + * us to combine the clip with the mask + */ static cairo_status_t -_region_new_from_rect (cairo_rectangle_t *rect, - pixman_region16_t **region) -{ - *region = pixman_region_create (); - if (pixman_region_union_rect (*region, *region, - rect->x, rect->y, - rect->width, rect->height) != PIXMAN_REGION_STATUS_SUCCESS) { - pixman_region_destroy (*region); +_cairo_gstate_clip_and_composite_combine (cairo_clip_t *clip, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_t *extents) +{ + cairo_surface_t *intermediate; + cairo_surface_pattern_t dst_pattern; + cairo_surface_pattern_t intermediate_pattern; + cairo_status_t status; + + /* We'd be better off here creating a surface identical in format + * to dst, but we have no way of getting that information. + * A CAIRO_CONTENT_CLONE or something might be useful. + */ + intermediate = cairo_surface_create_similar (dst, + CAIRO_CONTENT_COLOR_ALPHA, + extents->width, + extents->height); + if (intermediate->status) return CAIRO_STATUS_NO_MEMORY; - } - return CAIRO_STATUS_SUCCESS; -} + /* Initialize the intermediate surface from the destination surface + */ + _cairo_pattern_init_for_surface (&dst_pattern, dst); -/* Gets the bounding box of a region as a cairo_rectangle_t */ -static void -_region_rect_extents (pixman_region16_t *region, - cairo_rectangle_t *rect) -{ - pixman_box16_t *region_extents = pixman_region_extents (region); + status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, + &dst_pattern.base, NULL, intermediate, + extents->x, extents->y, + 0, 0, + 0, 0, + extents->width, extents->height); - rect->x = region_extents->x1; - rect->y = region_extents->y1; - rect->width = region_extents->x2 - region_extents->x1; - rect->height = region_extents->y2 - region_extents->y1; -} + _cairo_pattern_fini (&dst_pattern.base); -/* Intersects @region with the clipping bounds (both region - * and surface) of @gstate - */ -static cairo_status_t -_cairo_gstate_intersect_clip (cairo_gstate_t *gstate, - pixman_region16_t *region) -{ - if (gstate->clip.region) - pixman_region_intersect (region, gstate->clip.region, region); + if (status) + goto CLEANUP_SURFACE; + + status = (*draw_func) (draw_closure, operator, + src, intermediate, + extents->x, extents->y, + extents); + if (status) + goto CLEANUP_SURFACE; + + /* Combine that with the clip + */ + status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_IN, + intermediate, + extents->x, extents->y, + extents); + if (status) + goto CLEANUP_SURFACE; + + /* Punch the clip out of the destination + */ + status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_OUT, + dst, + 0, 0, + extents); + if (status) + goto CLEANUP_SURFACE; - if (gstate->clip.surface) { - pixman_region16_t *clip_rect; - cairo_status_t status; + /* Now add the two results together + */ + _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); - status = _region_new_from_rect (&gstate->clip.surface_rect, &clip_rect); - if (status) - return status; - - if (pixman_region_intersect (region, - clip_rect, - region) != PIXMAN_REGION_STATUS_SUCCESS) - status = CAIRO_STATUS_NO_MEMORY; + status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, + &intermediate_pattern.base, NULL, dst, + 0, 0, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); - pixman_region_destroy (clip_rect); + _cairo_pattern_fini (&intermediate_pattern.base); + + CLEANUP_SURFACE: + cairo_surface_destroy (intermediate); - if (status) - return status; - } + return status; +} - return CAIRO_STATUS_SUCCESS; +static int +_cairo_rectangle_empty (const cairo_rectangle_t *rect) +{ + return rect->width == 0 || rect->height == 0; } +/** + * _cairo_gstate_clip_and_composite: + * @gstate: a #cairo_gstate_t + * @operator: the operator to draw with + * @src: source pattern + * @draw_func: function that can be called to draw with the mask onto a surface. + * @draw_closure: data to pass to @draw_func. + * @dst: destination surface + * @extents: rectangle holding a bounding box for the operation; this + * rectangle will be used as the size for the temporary + * surface. + * + * When there is a surface clip, we typically need to create an intermediate + * surface. This function handles the logic of creating a temporary surface + * drawing to it, then compositing the result onto the target surface. + * + * @draw_func is to called to draw the mask; it will be called no more + * than once. + * + * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded. + **/ +static cairo_status_t +_cairo_gstate_clip_and_composite (cairo_clip_t *clip, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_t *extents) +{ + if (_cairo_rectangle_empty (extents)) + /* Nothing to do */ + return CAIRO_STATUS_SUCCESS; + + if (clip->surface) + { + if (_cairo_operator_bounded (operator)) + return _cairo_gstate_clip_and_composite_with_mask (clip, operator, + src, + draw_func, draw_closure, + dst, extents); + else + return _cairo_gstate_clip_and_composite_combine (clip, operator, + src, + draw_func, draw_closure, + dst, extents); + } + else + { + return (*draw_func) (draw_closure, operator, + src, dst, + 0, 0, + extents); + } +} + + static cairo_status_t _get_mask_extents (cairo_gstate_t *gstate, cairo_pattern_t *mask, cairo_rectangle_t *extents) { + cairo_status_t status; + /* * XXX should take mask extents into account, but - * that involves checking the transform... For now, + * that involves checking the transform and + * _cairo_operator_bounded (operator)... For now, * be lazy and just use the destination extents */ - return _cairo_gstate_get_clip_extents (gstate, extents); + status = _cairo_surface_get_extents (gstate->target, extents); + if (status) + return status; + + return _cairo_clip_intersect_to_rectangle (&gstate->clip, extents); +} + +static cairo_status_t +_cairo_gstate_mask_draw_func (void *closure, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents) +{ + cairo_pattern_t *mask = closure; + + if (src) + return _cairo_surface_composite (operator, + src, mask, dst, + extents->x, extents->y, + extents->x, extents->y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + else + return _cairo_surface_composite (operator, + mask, NULL, dst, + extents->x, extents->y, + 0, 0, /* unused */ + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); } cairo_status_t @@ -877,11 +1010,8 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, cairo_pattern_t *mask) { cairo_rectangle_t extents; - cairo_pattern_union_t pattern; - cairo_surface_pattern_t intermediate_pattern; - cairo_pattern_t *effective_mask; + cairo_pattern_union_t source_pattern, mask_pattern; cairo_status_t status; - int mask_x, mask_y; if (mask->status) return mask->status; @@ -889,69 +1019,23 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, if (gstate->source->status) return gstate->source->status; - status = _cairo_gstate_set_clip (gstate); + status = _cairo_surface_set_clip (gstate->target, &gstate->clip); if (status) return status; - _get_mask_extents (gstate, mask, &extents); + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask); - if (gstate->clip.surface) { - /* When there is clip surface, we'll need to create a - * temporary surface that combines the clip and mask - */ - cairo_surface_t *intermediate; - - intermediate = cairo_surface_create_similar (gstate->clip.surface, - CAIRO_CONTENT_ALPHA, - extents.width, - extents.height); - if (intermediate->status) - return CAIRO_STATUS_NO_MEMORY; - - status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, - mask, NULL, intermediate, - extents.x, extents.y, - 0, 0, - 0, 0, - extents.width, extents.height); - if (status) { - cairo_surface_destroy (intermediate); - return status; - } - - status = _cairo_gstate_combine_clip_surface (gstate, intermediate, &extents); - if (status) { - cairo_surface_destroy (intermediate); - return status; - } - - _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); - cairo_surface_destroy (intermediate); - - effective_mask = &intermediate_pattern.base; - mask_x = extents.x; - mask_y = extents.y; - - } else { - effective_mask = mask; - mask_x = mask_y = 0; - } - - _cairo_pattern_init_copy (&pattern.base, gstate->source); - _cairo_gstate_pattern_transform (gstate, &pattern.base); - - status = _cairo_surface_composite (gstate->operator, - &pattern.base, - effective_mask, - gstate->target, - extents.x, extents.y, - extents.x - mask_x, extents.y - mask_y, - extents.x, extents.y, - extents.width, extents.height); + _get_mask_extents (gstate, &mask_pattern.base, &extents); + + status = _cairo_gstate_clip_and_composite (&gstate->clip, gstate->operator, + &source_pattern.base, + _cairo_gstate_mask_draw_func, &mask_pattern.base, + gstate->target, + &extents); - if (gstate->clip.surface) - _cairo_pattern_fini (&intermediate_pattern.base); - _cairo_pattern_fini (&pattern.base); + _cairo_pattern_fini (&source_pattern.base); + _cairo_pattern_fini (&mask_pattern.base); return status; } @@ -968,7 +1052,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) if (gstate->line_width <= 0.0) return CAIRO_STATUS_SUCCESS; - status = _cairo_gstate_set_clip (gstate); + status = _cairo_surface_set_clip (gstate->target, &gstate->clip); if (status) return status; @@ -982,11 +1066,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) return status; } - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->target, - &traps); + _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps); _cairo_traps_fini (&traps); @@ -1035,7 +1115,7 @@ BAIL: * _cairo_rectangle_fixed_round. */ -static void +void _cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle) { rectangle->x = _cairo_fixed_integer_floor (box->p1.x); @@ -1044,7 +1124,7 @@ _cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle) rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y; } -static void +void _cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src) { int x1, y1, x2, y2; @@ -1067,80 +1147,10 @@ _cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src) } } -static int -_cairo_rectangle_empty (cairo_rectangle_t *rect) -{ - return rect->width == 0 || rect->height == 0; -} - -/* Given a region representing a set of trapezoids that will be - * drawn, clip the region according to the gstate and compute - * the overall extents. - */ -static cairo_status_t -_clip_and_compute_extents_region (cairo_gstate_t *gstate, - pixman_region16_t *trap_region, - cairo_rectangle_t *extents) -{ - cairo_status_t status; - - status = _cairo_gstate_intersect_clip (gstate, trap_region); - if (status) - return status; - - _region_rect_extents (trap_region, extents); - - return CAIRO_STATUS_SUCCESS; -} - -/* Given a a set of trapezoids to draw, find a bounding box (non-exact) - * of the trapezoids clipped by the gstate - */ -static cairo_status_t -_clip_and_compute_extents_arbitrary (cairo_gstate_t *gstate, - cairo_traps_t *traps, - cairo_rectangle_t *extents) -{ - cairo_box_t trap_extents; - - _cairo_traps_extents (traps, &trap_extents); - _cairo_box_round_to_rectangle (&trap_extents, extents); - - if (gstate->clip.region) { - pixman_region16_t *intersection; - cairo_status_t status; - - status = _region_new_from_rect (extents, &intersection); - if (status) - return status; - - if (pixman_region_intersect (intersection, - gstate->clip.region, - intersection) == PIXMAN_REGION_STATUS_SUCCESS) - { - _region_rect_extents (intersection, extents); - } - else - { - status = CAIRO_STATUS_NO_MEMORY; - } - - pixman_region_destroy (intersection); - - if (status) - return status; - } - - if (gstate->clip.surface) - _cairo_rectangle_intersect (extents, &gstate->clip.surface_rect); - - return CAIRO_STATUS_SUCCESS; -} - /* Composites a region representing a set of trapezoids. */ static cairo_status_t -_composite_trap_region (cairo_gstate_t *gstate, +_composite_trap_region (cairo_clip_t *clip, cairo_pattern_t *src, cairo_operator_t operator, cairo_surface_t *dst, @@ -1148,7 +1158,6 @@ _composite_trap_region (cairo_gstate_t *gstate, cairo_rectangle_t *extents) { cairo_status_t status; - cairo_pattern_union_t pattern; cairo_pattern_union_t mask; int num_rects = pixman_region_num_rects (trap_region); unsigned int clip_serial; @@ -1157,146 +1166,42 @@ _composite_trap_region (cairo_gstate_t *gstate, return CAIRO_STATUS_SUCCESS; if (num_rects > 1) { - - if (gstate->clip.mode != CAIRO_CLIP_MODE_REGION) + if (clip->mode != CAIRO_CLIP_MODE_REGION) return CAIRO_INT_STATUS_UNSUPPORTED; - clip_serial = _cairo_surface_allocate_clip_serial (gstate->target); - status = _cairo_surface_set_clip_region (gstate->target, + clip_serial = _cairo_surface_allocate_clip_serial (dst); + status = _cairo_surface_set_clip_region (dst, trap_region, clip_serial); if (status) return status; } - _cairo_pattern_init_copy (&pattern.base, src); - _cairo_gstate_pattern_transform (gstate, &pattern.base); - - if (gstate->clip.surface) - _cairo_pattern_init_for_surface (&mask.surface, gstate->clip.surface); + if (clip->surface) + _cairo_pattern_init_for_surface (&mask.surface, clip->surface); - status = _cairo_surface_composite (gstate->operator, - &pattern.base, - gstate->clip.surface ? &mask.base : NULL, + status = _cairo_surface_composite (operator, + src, + clip->surface ? &mask.base : NULL, dst, extents->x, extents->y, - extents->x - (gstate->clip.surface ? gstate->clip.surface_rect.x : 0), - extents->y - (gstate->clip.surface ? gstate->clip.surface_rect.y : 0), + extents->x - (clip->surface ? clip->surface_rect.x : 0), + extents->y - (clip->surface ? clip->surface_rect.y : 0), extents->x, extents->y, extents->width, extents->height); - _cairo_pattern_fini (&pattern.base); - if (gstate->clip.surface) + if (clip->surface) _cairo_pattern_fini (&mask.base); return status; } -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; - } -} - -/* Composites a set of trapezoids in the case where we need to create - * an intermediate surface to handle gstate->clip.surface - * - * Warning: This call modifies the coordinates of traps - */ -static cairo_status_t -_composite_traps_intermediate_surface (cairo_gstate_t *gstate, - cairo_pattern_t *src, - cairo_operator_t operator, - cairo_surface_t *dst, - cairo_traps_t *traps, - cairo_rectangle_t *extents) -{ - cairo_pattern_union_t pattern; - cairo_surface_t *intermediate; - cairo_surface_pattern_t intermediate_pattern; - cairo_status_t status; - - translate_traps (traps, -extents->x, -extents->y); - - intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, - CAIRO_CONTENT_ALPHA, - extents->width, - extents->height, - CAIRO_COLOR_TRANSPARENT); - if (intermediate->status) - return CAIRO_STATUS_NO_MEMORY; - - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); - - status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD, - &pattern.base, - intermediate, - extents->x, extents->y, - 0, 0, - extents->width, - extents->height, - traps->traps, - traps->num_traps); - _cairo_pattern_fini (&pattern.base); - - if (status) - goto out; - - status = _cairo_gstate_combine_clip_surface (gstate, intermediate, extents); - if (status) - goto out; - - _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); - _cairo_pattern_init_copy (&pattern.base, src); - _cairo_gstate_pattern_transform (gstate, &pattern.base); - - status = _cairo_surface_composite (operator, - &pattern.base, - &intermediate_pattern.base, - dst, - extents->x, extents->y, - 0, 0, - extents->x, extents->y, - extents->width, extents->height); - - _cairo_pattern_fini (&pattern.base); - _cairo_pattern_fini (&intermediate_pattern.base); - - out: - cairo_surface_destroy (intermediate); - - return status; -} - /* Composites a region representing a set of trapezoids in the * case of a solid source (so we can use * _cairo_surface_fill_rectangles). */ static cairo_status_t -_composite_trap_region_solid (cairo_gstate_t *gstate, +_composite_trap_region_solid (cairo_clip_t *clip, cairo_solid_pattern_t *src, cairo_operator_t operator, cairo_surface_t *dst, @@ -1330,48 +1235,69 @@ _composite_trap_region_solid (cairo_gstate_t *gstate, return status; } -/* Composites a set of trapezoids in the general case where - gstate->clip.surface == NULL - */ +typedef struct { + cairo_traps_t *traps; + cairo_antialias_t antialias; +} cairo_composite_traps_info_t; + static cairo_status_t -_composite_traps (cairo_gstate_t *gstate, - cairo_pattern_t *src, - cairo_operator_t operator, - cairo_surface_t *dst, - cairo_traps_t *traps, - cairo_rectangle_t *extents) -{ +_composite_traps_draw_func (void *closure, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents) +{ + cairo_composite_traps_info_t *info = closure; cairo_pattern_union_t pattern; cairo_status_t status; - - _cairo_pattern_init_copy (&pattern.base, src); - _cairo_gstate_pattern_transform (gstate, &pattern.base); - status = _cairo_surface_composite_trapezoids (gstate->operator, - &pattern.base, dst, - extents->x, extents->y, - extents->x, extents->y, - extents->width, - extents->height, - traps->traps, - traps->num_traps); + if (dst_x != 0 || dst_y != 0) + _cairo_traps_translate (info->traps, - dst_x, - dst_y); + _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); + if (!src) + src = &pattern.base; + + status = _cairo_surface_composite_trapezoids (operator, + src, dst, info->antialias, + extents->x, extents->y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + info->traps->traps, + info->traps->num_traps); _cairo_pattern_fini (&pattern.base); return status; } +/* Gets the bounding box of a region as a cairo_rectangle_t */ +static void +_region_rect_extents (pixman_region16_t *region, + cairo_rectangle_t *rect) +{ + pixman_box16_t *region_extents = pixman_region_extents (region); + + rect->x = region_extents->x1; + rect->y = region_extents->y1; + rect->width = region_extents->x2 - region_extents->x1; + rect->height = region_extents->y2 - region_extents->y1; +} + /* Warning: This call modifies the coordinates of traps */ -static cairo_status_t -_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, - cairo_pattern_t *src, - cairo_operator_t operator, - cairo_surface_t *dst, - cairo_traps_t *traps) +cairo_status_t +_cairo_surface_clip_and_composite_trapezoids (cairo_pattern_t *src, + cairo_operator_t operator, + cairo_surface_t *dst, + cairo_traps_t *traps, + cairo_clip_t *clip, + cairo_antialias_t antialias) { cairo_status_t status; pixman_region16_t *trap_region; cairo_rectangle_t extents; + cairo_composite_traps_info_t traps_info; if (traps->num_traps == 0) return CAIRO_STATUS_SUCCESS; @@ -1380,60 +1306,65 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, if (status) return status; - if (trap_region) - status = _clip_and_compute_extents_region (gstate, trap_region, &extents); + if (_cairo_operator_bounded (operator)) + { + if (trap_region) { + status = _cairo_clip_intersect_to_region (clip, trap_region); + _region_rect_extents (trap_region, &extents); + } else { + cairo_box_t trap_extents; + _cairo_traps_extents (traps, &trap_extents); + _cairo_box_round_to_rectangle (&trap_extents, &extents); + status = _cairo_clip_intersect_to_rectangle (clip, &extents); + } + } else - status = _clip_and_compute_extents_arbitrary (gstate, traps, &extents); + { + status = _cairo_surface_get_extents (dst, &extents); + if (status) + return status; + status = _cairo_clip_intersect_to_rectangle (clip, &extents); + if (status) + return status; + } if (status) goto out; - if (_cairo_rectangle_empty (&extents)) - /* Nothing to do */ - goto out; - - if (gstate->clip.surface) { - if (trap_region) { - /* If we are compositing a set of rectangles, we can set them as the - * clip region for the destination surface and use the clip surface - * as the mask. A clip region might not be supported, in which case - * we fall through to the next method - */ - status = _composite_trap_region (gstate, src, operator, dst, - trap_region, &extents); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto out; - } - - /* Handle a clip surface by creating an intermediate surface. */ - status = _composite_traps_intermediate_surface (gstate, src, operator, - dst, traps, &extents); - } else { - /* No clip surface */ - if (trap_region && src->type == CAIRO_PATTERN_SOLID) { - /* Solid rectangles are handled specially */ - status = _composite_trap_region_solid (gstate, (cairo_solid_pattern_t *)src, + if (trap_region && _cairo_operator_bounded (operator)) + { + if (src->type == CAIRO_PATTERN_SOLID && !clip->surface) + { + /* Solid rectangles special case */ + status = _composite_trap_region_solid (clip, (cairo_solid_pattern_t *)src, operator, dst, trap_region); - } else { - if (trap_region) { - /* For a simple rectangle, we can just use composite(), for more - * rectangles, we have to set a clip region. The cost of rasterizing - * trapezoids is pretty high for most backends currently, so it's - * worthwhile even if a region is needed. - */ - status = _composite_trap_region (gstate, src, operator, dst, - trap_region, &extents); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto out; - - /* If a clip regions aren't supported, fall through */ - } - - status = _composite_traps (gstate, src, operator, - dst, traps, &extents); + goto out; } + + /* For a simple rectangle, we can just use composite(), for more + * rectangles, we have to set a clip region. The cost of rasterizing + * trapezoids is pretty high for most backends currently, so it's + * worthwhile even if a region is needed. + * + * If we have a clip surface, we set it as the mask. + * + * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has + * more than rectangle and the destination doesn't support clip + * regions. In that case, we fall through. + */ + status = _composite_trap_region (clip, src, operator, dst, + trap_region, &extents); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto out; } + traps_info.traps = traps; + traps_info.antialias = antialias; + + status = _cairo_gstate_clip_and_composite (clip, operator, src, + _composite_traps_draw_func, &traps_info, + dst, &extents); + out: if (trap_region) pixman_region_destroy (trap_region); @@ -1441,6 +1372,28 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, return status; } +/* Warning: This call modifies the coordinates of traps */ +static cairo_status_t +_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, + cairo_traps_t *traps) +{ + cairo_pattern_union_t pattern; + cairo_status_t status; + + _cairo_gstate_copy_transformed_source (gstate, &pattern.base); + + status = _cairo_surface_clip_and_composite_trapezoids (&pattern.base, + gstate->operator, + gstate->target, + traps, + &gstate->clip, + gstate->antialias); + + _cairo_pattern_fini (&pattern.base); + + return status; +} + cairo_status_t _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { @@ -1450,7 +1403,7 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) if (gstate->source->status) return gstate->source->status; - status = _cairo_gstate_set_clip (gstate); + status = _cairo_surface_set_clip (gstate->target, &gstate->clip); if (status) return status; @@ -1466,17 +1419,16 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps); + status = _cairo_path_fixed_fill_to_traps (path, + gstate->fill_rule, + gstate->tolerance, + &traps); if (status) { _cairo_traps_fini (&traps); return status; } - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->target, - &traps); + _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps); _cairo_traps_fini (&traps); @@ -1497,7 +1449,10 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate, _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps); + status = _cairo_path_fixed_fill_to_traps (path, + gstate->fill_rule, + gstate->tolerance, + &traps); if (status) goto BAIL; @@ -1567,7 +1522,10 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate, _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps); + status = _cairo_path_fixed_fill_to_traps (path, + gstate->fill_rule, + gstate->tolerance, + &traps); if (status) goto BAIL; @@ -1590,226 +1548,19 @@ BAIL: cairo_status_t _cairo_gstate_reset_clip (cairo_gstate_t *gstate) { - /* destroy any existing clip-region artifacts */ - if (gstate->clip.surface) - cairo_surface_destroy (gstate->clip.surface); - gstate->clip.surface = NULL; - - if (gstate->clip.region) - pixman_region_destroy (gstate->clip.region); - gstate->clip.region = NULL; - - if (gstate->clip.path) - _cairo_clip_path_destroy (gstate->clip.path); - gstate->clip.path = NULL; - - gstate->clip.serial = 0; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_gstate_intersect_clip_path (cairo_gstate_t *gstate, - cairo_path_fixed_t *path) -{ - cairo_clip_path_t *clip_path; - cairo_status_t status; - - if (gstate->clip.mode != CAIRO_CLIP_MODE_PATH) - return CAIRO_INT_STATUS_UNSUPPORTED; - - clip_path = malloc (sizeof (cairo_clip_path_t)); - if (clip_path == NULL) - return CAIRO_STATUS_NO_MEMORY; - - status = _cairo_path_fixed_init_copy (&clip_path->path, path); - if (status) - return status; - - clip_path->ref_count = 1; - clip_path->fill_rule = gstate->fill_rule; - clip_path->tolerance = gstate->tolerance; - clip_path->prev = gstate->clip.path; - gstate->clip.path = clip_path; - gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target); - - return CAIRO_STATUS_SUCCESS; -} - -static void -_cairo_clip_path_reference (cairo_clip_path_t *clip_path) -{ - if (clip_path == NULL) - return; - - clip_path->ref_count++; -} - -static void -_cairo_clip_path_destroy (cairo_clip_path_t *clip_path) -{ - if (clip_path == NULL) - return; - - clip_path->ref_count--; - if (clip_path->ref_count) - return; - - _cairo_path_fixed_fini (&clip_path->path); - _cairo_clip_path_destroy (clip_path->prev); - free (clip_path); -} - -static cairo_status_t -_cairo_gstate_intersect_clip_region (cairo_gstate_t *gstate, - cairo_traps_t *traps) -{ - pixman_region16_t *region; - cairo_status_t status; - - if (gstate->clip.mode != CAIRO_CLIP_MODE_REGION) - return CAIRO_INT_STATUS_UNSUPPORTED; - - status = _cairo_traps_extract_region (traps, ®ion); - if (status) - return status; - - if (region == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; - - status = CAIRO_STATUS_SUCCESS; - if (gstate->clip.region == NULL) { - gstate->clip.region = region; - } else { - pixman_region16_t *intersection = pixman_region_create(); - - if (pixman_region_intersect (intersection, - gstate->clip.region, region) - == PIXMAN_REGION_STATUS_SUCCESS) { - pixman_region_destroy (gstate->clip.region); - gstate->clip.region = intersection; - } else { - status = CAIRO_STATUS_NO_MEMORY; - } - pixman_region_destroy (region); - } - gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target); - return status; -} - -static cairo_status_t -_cairo_gstate_intersect_clip_mask (cairo_gstate_t *gstate, - cairo_traps_t *traps) -{ - cairo_pattern_union_t pattern; - cairo_box_t extents; - cairo_rectangle_t surface_rect; - cairo_surface_t *surface; - cairo_status_t status; - - /* Represent the clip as a mask surface. We create a new surface - * the size of the intersection of the old mask surface and the - * extents of the new clip path. */ - - _cairo_traps_extents (traps, &extents); - _cairo_box_round_to_rectangle (&extents, &surface_rect); - - if (gstate->clip.surface != NULL) - _cairo_rectangle_intersect (&surface_rect, &gstate->clip.surface_rect); - - surface = _cairo_surface_create_similar_solid (gstate->target, - CAIRO_CONTENT_ALPHA, - surface_rect.width, - surface_rect.height, - CAIRO_COLOR_WHITE); - if (surface->status) - return CAIRO_STATUS_NO_MEMORY; - - /* Render the new clipping path into the new mask surface. */ - - translate_traps (traps, -surface_rect.x, -surface_rect.y); - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); - - status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN, - &pattern.base, - surface, - 0, 0, - 0, 0, - surface_rect.width, - surface_rect.height, - traps->traps, - traps->num_traps); - - _cairo_pattern_fini (&pattern.base); - - if (status) { - cairo_surface_destroy (surface); - return status; - } - - /* If there was a clip surface already, combine it with the new - * mask surface using the IN operator, so we get the intersection - * of the old and new clipping paths. */ - - if (gstate->clip.surface != NULL) { - _cairo_pattern_init_for_surface (&pattern.surface, gstate->clip.surface); - - status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - &pattern.base, - NULL, - surface, - surface_rect.x - gstate->clip.surface_rect.x, - surface_rect.y - gstate->clip.surface_rect.y, - 0, 0, - 0, 0, - surface_rect.width, - surface_rect.height); - - _cairo_pattern_fini (&pattern.base); - - if (status) { - cairo_surface_destroy (surface); - return status; - } - - cairo_surface_destroy (gstate->clip.surface); - } - - gstate->clip.surface = surface; - gstate->clip.surface_rect = surface_rect; - - return status; + return _cairo_clip_reset (&gstate->clip); } cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { - cairo_status_t status; - cairo_traps_t traps; - - status = _cairo_gstate_intersect_clip_path (gstate, path); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; - - _cairo_traps_init (&traps); - status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps); - if (status) - goto bail; - - status = _cairo_gstate_intersect_clip_region (gstate, &traps); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto bail; - - status = _cairo_gstate_intersect_clip_mask (gstate, &traps); - - bail: - _cairo_traps_fini (&traps); - - return status; + return _cairo_clip_clip (&gstate->clip, + path, gstate->fill_rule, gstate->tolerance, + gstate->antialias, gstate->target); } static void -_cairo_gstate_unset_font (cairo_gstate_t *gstate) +_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate) { if (gstate->scaled_font) { cairo_scaled_font_destroy (gstate->scaled_font); @@ -1825,7 +1576,7 @@ _cairo_gstate_select_font_face (cairo_gstate_t *gstate, { cairo_font_face_t *font_face; - font_face = _cairo_simple_font_face_create (family, slant, weight); + font_face = _cairo_toy_font_face_create (family, slant, weight); if (font_face->status) return font_face->status; @@ -1839,7 +1590,7 @@ cairo_status_t _cairo_gstate_set_font_size (cairo_gstate_t *gstate, double size) { - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); cairo_matrix_init_scale (&gstate->font_matrix, size, size); @@ -1850,7 +1601,7 @@ cairo_status_t _cairo_gstate_set_font_matrix (cairo_gstate_t *gstate, const cairo_matrix_t *matrix) { - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); gstate->font_matrix = *matrix; @@ -1868,7 +1619,7 @@ cairo_status_t _cairo_gstate_set_font_options (cairo_gstate_t *gstate, const cairo_font_options_t *options) { - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); gstate->font_options = *options; @@ -1979,9 +1730,9 @@ _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate) if (!gstate->font_face) { cairo_font_face_t *font_face; - font_face = _cairo_simple_font_face_create (CAIRO_FONT_FAMILY_DEFAULT, - CAIRO_FONT_SLANT_DEFAULT, - CAIRO_FONT_WEIGHT_DEFAULT); + font_face = _cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT, + CAIRO_FONT_SLANT_DEFAULT, + CAIRO_FONT_WEIGHT_DEFAULT); if (font_face->status) return font_face->status; else @@ -1992,7 +1743,7 @@ _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate) } static cairo_status_t -_cairo_gstate_ensure_font (cairo_gstate_t *gstate) +_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate) { cairo_status_t status; cairo_font_options_t options; @@ -2022,7 +1773,7 @@ cairo_status_t _cairo_gstate_get_font_extents (cairo_gstate_t *gstate, cairo_font_extents_t *extents) { - cairo_status_t status = _cairo_gstate_ensure_font (gstate); + cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate); if (status) return status; @@ -2042,7 +1793,7 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, cairo_status_t status; int i; - status = _cairo_gstate_ensure_font (gstate); + status = _cairo_gstate_ensure_scaled_font (gstate); if (status) return status; @@ -2071,18 +1822,15 @@ cairo_status_t _cairo_gstate_set_font_face (cairo_gstate_t *gstate, cairo_font_face_t *font_face) { - if (font_face->status) + if (font_face && font_face->status) return font_face->status; if (font_face != gstate->font_face) { - if (gstate->font_face) - cairo_font_face_destroy (gstate->font_face); - gstate->font_face = font_face; - if (gstate->font_face) - cairo_font_face_reference (gstate->font_face); + cairo_font_face_destroy (gstate->font_face); + gstate->font_face = cairo_font_face_reference (font_face); } - _cairo_gstate_unset_font (gstate); + _cairo_gstate_unset_scaled_font (gstate); return CAIRO_STATUS_SUCCESS; } @@ -2095,7 +1843,7 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, { cairo_status_t status; - status = _cairo_gstate_ensure_font (gstate); + status = _cairo_gstate_ensure_scaled_font (gstate); if (status) return status; @@ -2106,6 +1854,58 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, return CAIRO_STATUS_SUCCESS; } +typedef struct { + cairo_scaled_font_t *font; + cairo_glyph_t *glyphs; + int num_glyphs; +} cairo_show_glyphs_info_t; + +static cairo_status_t +_cairo_gstate_show_glyphs_draw_func (void *closure, + cairo_operator_t operator, + cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_t *extents) +{ + cairo_show_glyphs_info_t *glyph_info = closure; + cairo_pattern_union_t pattern; + cairo_status_t status; + + /* Modifying the glyph array is fine because we know that this function + * will be called only once, and we've already made a copy of the + * glyphs in the wrapper. + */ + if (dst_x != 0 || dst_y != 0) { + int i; + + for (i = 0; i < glyph_info->num_glyphs; ++i) + { + glyph_info->glyphs[i].x -= dst_x; + glyph_info->glyphs[i].y -= dst_y; + } + } + + _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); + if (!src) + src = &pattern.base; + + status = _cairo_scaled_font_show_glyphs (glyph_info->font, + operator, + src, dst, + extents->x, extents->y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + glyph_info->glyphs, + glyph_info->num_glyphs); + + if (src == &pattern.base) + _cairo_pattern_fini (&pattern.base); + + return status; +} + cairo_status_t _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, @@ -2117,15 +1917,16 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_pattern_union_t pattern; cairo_box_t bbox; cairo_rectangle_t extents; + cairo_show_glyphs_info_t glyph_info; if (gstate->source->status) return gstate->source->status; - status = _cairo_gstate_set_clip (gstate); + status = _cairo_surface_set_clip (gstate->target, &gstate->clip); if (status) return status; - status = _cairo_gstate_ensure_font (gstate); + status = _cairo_gstate_ensure_scaled_font (gstate); if (status) return status; @@ -2140,113 +1941,41 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, &transformed_glyphs[i].x, &transformed_glyphs[i].y); } - - status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font, - transformed_glyphs, num_glyphs, - &bbox); - _cairo_box_round_to_rectangle (&bbox, &extents); - if (status) - goto CLEANUP_GLYPHS; - - if (gstate->clip.surface) + if (_cairo_operator_bounded (gstate->operator)) { - cairo_surface_t *intermediate; - cairo_surface_pattern_t intermediate_pattern; - - _cairo_rectangle_intersect (&extents, &gstate->clip.surface_rect); - - /* Shortcut if empty */ - if (_cairo_rectangle_empty (&extents)) { - status = CAIRO_STATUS_SUCCESS; - goto BAIL1; - } - - intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface, - CAIRO_CONTENT_ALPHA, - extents.width, - extents.height, - CAIRO_COLOR_TRANSPARENT); - if (intermediate->status) { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL1; - } - - /* move the glyphs again, from dev space to intermediate space */ - for (i = 0; i < num_glyphs; ++i) - { - transformed_glyphs[i].x -= extents.x; - transformed_glyphs[i].y -= extents.y; - } - - _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); - - status = _cairo_scaled_font_show_glyphs (gstate->scaled_font, - CAIRO_OPERATOR_ADD, - &pattern.base, intermediate, - extents.x, extents.y, - 0, 0, - extents.width, extents.height, - transformed_glyphs, num_glyphs); - - _cairo_pattern_fini (&pattern.base); - + status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font, + transformed_glyphs, num_glyphs, + &bbox); if (status) - goto BAIL2; - - _cairo_pattern_init_for_surface (&pattern.surface, - gstate->clip.surface); - - status = _cairo_surface_composite (CAIRO_OPERATOR_IN, - &pattern.base, - NULL, - intermediate, - extents.x - gstate->clip.surface_rect.x, - extents.y - gstate->clip.surface_rect.y, - 0, 0, - 0, 0, - extents.width, extents.height); - - _cairo_pattern_fini (&pattern.base); - - if (status) - goto BAIL2; - - _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); - _cairo_pattern_init_copy (&pattern.base, gstate->source); - _cairo_gstate_pattern_transform (gstate, &pattern.base); - - status = _cairo_surface_composite (gstate->operator, - &pattern.base, - &intermediate_pattern.base, - gstate->target, - extents.x, extents.y, - 0, 0, - extents.x, extents.y, - extents.width, extents.height); - _cairo_pattern_fini (&pattern.base); - _cairo_pattern_fini (&intermediate_pattern.base); - - BAIL2: - cairo_surface_destroy (intermediate); - BAIL1: - ; + goto CLEANUP_GLYPHS; + + _cairo_box_round_to_rectangle (&bbox, &extents); } else { - _cairo_pattern_init_copy (&pattern.base, gstate->source); - _cairo_gstate_pattern_transform (gstate, &pattern.base); + status = _cairo_surface_get_extents (gstate->target, &extents); + if (status) + goto CLEANUP_GLYPHS; + } + + status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents); + if (status) + goto CLEANUP_GLYPHS; + + _cairo_gstate_copy_transformed_source (gstate, &pattern.base); - status = _cairo_scaled_font_show_glyphs (gstate->scaled_font, - gstate->operator, &pattern.base, - gstate->target, - extents.x, extents.y, - extents.x, extents.y, - extents.width, extents.height, - transformed_glyphs, num_glyphs); + glyph_info.font = gstate->scaled_font; + glyph_info.glyphs = transformed_glyphs; + glyph_info.num_glyphs = num_glyphs; + + status = _cairo_gstate_clip_and_composite (&gstate->clip, gstate->operator, + &pattern.base, + _cairo_gstate_show_glyphs_draw_func, &glyph_info, + gstate->target, + &extents); - _cairo_pattern_fini (&pattern.base); - } + _cairo_pattern_fini (&pattern.base); CLEANUP_GLYPHS: free (transformed_glyphs); @@ -2264,7 +1993,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, int i; cairo_glyph_t *transformed_glyphs = NULL; - status = _cairo_gstate_ensure_font (gstate); + status = _cairo_gstate_ensure_scaled_font (gstate); if (status) return status; @@ -2287,3 +2016,19 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, free (transformed_glyphs); return status; } + +cairo_private cairo_status_t +_cairo_gstate_set_antialias (cairo_gstate_t *gstate, + cairo_antialias_t antialias) +{ + gstate->antialias = antialias; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_private cairo_antialias_t +_cairo_gstate_get_antialias (cairo_gstate_t *gstate) +{ + return gstate->antialias; +} + diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index b21cf122..f7dbc8cf 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -69,7 +69,8 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, surface->format = format; surface->data = (unsigned char *) pixman_image_get_data (pixman_image); - surface->owns_data = 0; + surface->owns_data = FALSE; + surface->has_clip = FALSE; surface->width = pixman_image_get_width (pixman_image); surface->height = pixman_image_get_height (pixman_image); @@ -408,8 +409,7 @@ _cairo_image_surface_clone_similar (void *abstract_surface, cairo_image_surface_t *surface = abstract_surface; if (src->backend == surface->base.backend) { - *clone_out = src; - cairo_surface_reference (src); + *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } @@ -614,6 +614,16 @@ _cairo_image_surface_composite (cairo_operator_t operator, } } + if (!_cairo_operator_bounded (operator)) + _cairo_surface_composite_fixup_unbounded (&dst->base, + &src_attr, src->width, src->height, + mask ? &mask_attr : NULL, + mask ? mask->width : 0, + mask ? mask->height : 0, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, width, height); + if (mask) _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr); @@ -645,10 +655,25 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +static cairo_bool_t +_cairo_image_surface_is_alpha_only (cairo_image_surface_t *surface) +{ + int bpp, alpha, red, green, blue; + + if (surface->format != (cairo_format_t) -1) + return surface->format == CAIRO_FORMAT_A1 || surface->format == CAIRO_FORMAT_A8; + + pixman_format_get_masks (pixman_image_get_format (surface->pixman_image), + &bpp, &alpha, &red, &green, &blue); + + return red == 0 && blue == 0 && green == 0; +} + static cairo_int_status_t _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -662,8 +687,35 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, 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; + pixman_image_t *mask; + pixman_format_t *format; + pixman_bits_t *mask_data; + int mask_stride; + int mask_bpp; + + /* Special case adding trapezoids onto a mask surface; we want to avoid + * creating an intermediate temporary mask unecessarily. + * + * We make the assumption here that the portion of the trapezoids + * contained within the surface is bounded by [dst_x,dst_y,width,height]; + * the Cairo core code passes bounds based on the trapezoid extents. + * + * Currently the check surface->has_clip is needed for correct + * functioning, since pixman_add_trapezoids() doesn't obey the + * surface clip, which is a libpixman bug , but there's no harm in + * falling through to the general case when the surface is clipped + * since libpixman would have to generate an intermediate mask anyways. + */ + if (operator == CAIRO_OPERATOR_ADD && + _cairo_pattern_is_opaque_solid (pattern) && + _cairo_image_surface_is_alpha_only (dst) && + !dst->has_clip && + antialias != CAIRO_ANTIALIAS_NONE) + { + pixman_add_trapezoids (dst->pixman_image, 0, 0, + (pixman_trapezoid_t *) traps, num_traps); + return CAIRO_STATUS_SUCCESS; + } status = _cairo_pattern_acquire_surface (pattern, &dst->base, src_x, src_y, width, height, @@ -672,28 +724,64 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, 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); + status = _cairo_image_surface_set_attributes (src, &attributes); + if (status) + goto CLEANUP_SOURCE; + + switch (antialias) { + case CAIRO_ANTIALIAS_NONE: + format = pixman_format_create (PIXMAN_FORMAT_NAME_A1); + mask_stride = (width + 31)/8; + mask_bpp = 1; + break; + default: + format = pixman_format_create (PIXMAN_FORMAT_NAME_A8); + mask_stride = (width + 3) & ~3; + mask_bpp = 8; + break; + } + if (!format) { + status = CAIRO_STATUS_NO_MEMORY; + goto CLEANUP_SOURCE; + } + + /* The image must be initially transparent */ + mask_data = calloc (1, mask_stride * height); + if (!mask_data) { + status = CAIRO_STATUS_NO_MEMORY; + pixman_format_destroy (format); + goto CLEANUP_SOURCE; } - render_src_x = src_x + render_reference_x - dst_x; - render_src_y = src_y + render_reference_y - dst_y; + mask = pixman_image_create_for_data (mask_data, format, width, height, + mask_bpp, mask_stride); + pixman_format_destroy (format); + if (!mask) { + status = CAIRO_STATUS_NO_MEMORY; + goto CLEANUP_IMAGE_DATA; + } /* XXX: The pixman_trapezoid_t cast is evil and needs to go away * somehow. */ - status = _cairo_image_surface_set_attributes (src, &attributes); - if (status == CAIRO_STATUS_SUCCESS) - pixman_composite_trapezoids (_pixman_operator (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); - + pixman_add_trapezoids (mask, - dst_x, - dst_y, + (pixman_trapezoid_t *) traps, num_traps); + + pixman_composite (_pixman_operator (operator), + src->pixman_image, + mask, + dst->pixman_image, + src_x + attributes.x_offset, + src_y + attributes.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + + pixman_image_destroy (mask); + + CLEANUP_IMAGE_DATA: + free (mask_data); + + CLEANUP_SOURCE: _cairo_pattern_release_surface (pattern, &src->base, &attributes); return status; @@ -714,6 +802,8 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, { pixman_image_set_clip_region (surface->pixman_image, region); + surface->has_clip = region != NULL; + return CAIRO_STATUS_SUCCESS; } diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index 98feb571..7596b084 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -36,7 +36,6 @@ #define _GNU_SOURCE #include <stdlib.h> -#include <math.h> #include "cairoint.h" diff --git a/src/cairo-meta-surface-private.h b/src/cairo-meta-surface-private.h index 234c6ccf..f37a8916 100644 --- a/src/cairo-meta-surface-private.h +++ b/src/cairo-meta-surface-private.h @@ -77,6 +77,7 @@ typedef struct _cairo_command_composite_trapezoids { cairo_command_type_t type; cairo_operator_t operator; cairo_pattern_union_t pattern; + cairo_antialias_t antialias; int x_src; int y_src; int x_dst; @@ -99,6 +100,7 @@ typedef struct _cairo_command_intersect_clip_path { cairo_path_fixed_t path; cairo_fill_rule_t fill_rule; double tolerance; + cairo_antialias_t antialias; } cairo_command_intersect_clip_path_t; typedef struct _cairo_command_show_glyphs { @@ -123,6 +125,7 @@ typedef struct _cairo_command_fill_path { cairo_path_fixed_t path; cairo_fill_rule_t fill_rule; double tolerance; + cairo_antialias_t antialias; } cairo_command_fill_path_t; typedef union _cairo_command { diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c index 8a893d66..f218ae24 100644 --- a/src/cairo-meta-surface.c +++ b/src/cairo-meta-surface.c @@ -35,15 +35,7 @@ #include "cairoint.h" #include "cairo-meta-surface-private.h" - -/* - * Notes: - * - * Can't use cairo_surface_* calls since we often don't want - * fallbacks. For example, when determining the font subsets or the - * fallback areas. Hmm... but maybe those passes could be integrated - * into the delegation wrappers and the ps output pass, respectively. - */ +#include "cairo-gstate-private.h" static const cairo_surface_backend_t cairo_meta_surface_backend; @@ -106,10 +98,6 @@ _cairo_meta_surface_finish (void *abstract_surface) free (command); break; - case CAIRO_COMMAND_SET_CLIP_REGION: - free (command); - break; - case CAIRO_COMMAND_INTERSECT_CLIP_PATH: if (command->intersect_clip_path.path_pointer) _cairo_path_fixed_fini (&command->intersect_clip_path.path); @@ -229,6 +217,7 @@ static cairo_int_status_t _cairo_meta_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_surface, + cairo_antialias_t antialias, int x_src, int y_src, int x_dst, @@ -248,6 +237,7 @@ _cairo_meta_surface_composite_trapezoids (cairo_operator_t operator, command->type = CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS; command->operator = operator; _cairo_pattern_init_copy (&command->pattern.base, pattern); + command->antialias = antialias; command->x_src = x_src; command->y_src = y_src; command->x_dst = x_dst; @@ -276,42 +266,11 @@ _cairo_meta_surface_composite_trapezoids (cairo_operator_t operator, } static cairo_int_status_t -_cairo_meta_surface_set_clip_region (void *abstract_surface, - pixman_region16_t *region) -{ - cairo_meta_surface_t *meta = abstract_surface; - cairo_command_set_clip_region_t *command; - - command = malloc (sizeof (cairo_command_set_clip_region_t)); - if (command == NULL) - return CAIRO_STATUS_NO_MEMORY; - - command->type = CAIRO_COMMAND_SET_CLIP_REGION; - - if (region) { - command->region = pixman_region_create (); - pixman_region_copy (command->region, region); - } else { - command->region = NULL; - } - - command->serial = meta->base.current_clip_serial; - - if (_cairo_array_append (&meta->commands, &command, 1) == NULL) { - if (command->region) - pixman_region_destroy (command->region); - free (command); - return CAIRO_STATUS_NO_MEMORY; - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t _cairo_meta_surface_intersect_clip_path (void *dst, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, - double tolerance) + double tolerance, + cairo_antialias_t antialias) { cairo_meta_surface_t *meta = dst; cairo_command_intersect_clip_path_t *command; @@ -335,6 +294,7 @@ _cairo_meta_surface_intersect_clip_path (void *dst, } command->fill_rule = fill_rule; command->tolerance = tolerance; + command->antialias = antialias; if (_cairo_array_append (&meta->commands, &command, 1) == NULL) { if (path) @@ -387,8 +347,7 @@ _cairo_meta_surface_show_glyphs (cairo_scaled_font_t *scaled_font, return CAIRO_STATUS_NO_MEMORY; command->type = CAIRO_COMMAND_SHOW_GLYPHS; - command->scaled_font = scaled_font; - cairo_scaled_font_reference (scaled_font); + command->scaled_font = cairo_scaled_font_reference (scaled_font); command->operator = operator; _cairo_pattern_init_copy (&command->pattern.base, pattern); command->source_x = source_x; @@ -469,7 +428,7 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = { _cairo_meta_surface_composite_trapezoids, NULL, /* copy_page */ NULL, /* show_page */ - _cairo_meta_surface_set_clip_region, + NULL, /* set_clip_region */ _cairo_meta_surface_intersect_clip_path, _cairo_meta_surface_get_extents, _cairo_meta_surface_show_glyphs, @@ -484,16 +443,24 @@ _cairo_meta_surface_replay (cairo_surface_t *surface, cairo_command_t *command, **elements; int i, num_elements; cairo_int_status_t status; + cairo_traps_t traps; + cairo_clip_t clip; meta = (cairo_meta_surface_t *) surface; status = CAIRO_STATUS_SUCCESS; + _cairo_clip_init (&clip, target); + num_elements = meta->commands.num_elements; elements = (cairo_command_t **) meta->commands.elements; for (i = 0; i < num_elements; i++) { command = elements[i]; switch (command->type) { case CAIRO_COMMAND_COMPOSITE: + status = _cairo_surface_set_clip (target, &clip); + if (status) + break; + status = _cairo_surface_composite (command->composite.operator, &command->composite.src_pattern.base, @@ -510,6 +477,10 @@ _cairo_meta_surface_replay (cairo_surface_t *surface, break; case CAIRO_COMMAND_FILL_RECTANGLES: + status = _cairo_surface_set_clip (target, &clip); + if (status) + break; + status = _cairo_surface_fill_rectangles (target, command->fill_rectangles.operator, @@ -519,10 +490,15 @@ _cairo_meta_surface_replay (cairo_surface_t *surface, break; case CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS: + status = _cairo_surface_set_clip (target, &clip); + if (status) + break; + status = _cairo_surface_composite_trapezoids (command->composite_trapezoids.operator, &command->composite_trapezoids.pattern.base, target, + command->composite_trapezoids.antialias, command->composite_trapezoids.x_src, command->composite_trapezoids.y_src, command->composite_trapezoids.x_dst, @@ -533,27 +509,25 @@ _cairo_meta_surface_replay (cairo_surface_t *surface, command->composite_trapezoids.num_traps); break; - case CAIRO_COMMAND_SET_CLIP_REGION: - status = _cairo_surface_set_clip_region - (target, - command->set_clip_region.region, - command->set_clip_region.serial); - break; - case CAIRO_COMMAND_INTERSECT_CLIP_PATH: /* XXX Meta surface clipping is broken and requires some * cairo-gstate.c rewriting. Work around it for now. */ - if (target->backend->intersect_clip_path == NULL) - break; - - status = _cairo_surface_intersect_clip_path - (target, - command->intersect_clip_path.path_pointer, - command->intersect_clip_path.fill_rule, - command->intersect_clip_path.tolerance); + if (command->intersect_clip_path.path_pointer == NULL) + status = _cairo_clip_reset (&clip); + else + status = _cairo_clip_clip (&clip, + command->intersect_clip_path.path_pointer, + command->intersect_clip_path.fill_rule, + command->intersect_clip_path.tolerance, + command->intersect_clip_path.antialias, + target); break; case CAIRO_COMMAND_SHOW_GLYPHS: + status = _cairo_surface_set_clip (target, &clip); + if (status) + break; + status = _cairo_surface_show_glyphs (command->show_glyphs.scaled_font, command->show_glyphs.operator, @@ -570,18 +544,38 @@ _cairo_meta_surface_replay (cairo_surface_t *surface, break; case CAIRO_COMMAND_FILL_PATH: - /* XXX Meta surface fill_path is broken and requires some - * cairo-gstate.c rewriting. Work around it for now. */ - if (target->backend->fill_path == NULL) + status = _cairo_surface_set_clip (target, &clip); + if (status) break; - status = _cairo_surface_fill_path - (command->fill_path.operator, - &command->fill_path.pattern.base, - target, - &command->fill_path.path, - command->fill_path.fill_rule, - command->fill_path.tolerance); + status = _cairo_surface_fill_path (command->fill_path.operator, + &command->fill_path.pattern.base, + target, + &command->fill_path.path, + command->fill_path.fill_rule, + command->fill_path.tolerance); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + break; + + _cairo_traps_init (&traps); + + status = _cairo_path_fixed_fill_to_traps (&command->fill_path.path, + command->fill_path.fill_rule, + command->fill_path.tolerance, + &traps); + if (status) { + _cairo_traps_fini (&traps); + break; + } + + status = _cairo_surface_clip_and_composite_trapezoids (&command->fill_path.pattern.base, + command->fill_path.operator, + target, + &traps, + &clip, + command->fill_path.antialias); + + _cairo_traps_fini (&traps); break; default: @@ -592,5 +586,7 @@ _cairo_meta_surface_replay (cairo_surface_t *surface, break; } + _cairo_clip_fini (&clip); + return status; } diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c index 17ef7e2c..afb4d428 100644 --- a/src/cairo-output-stream.c +++ b/src/cairo-output-stream.c @@ -39,6 +39,10 @@ #include <ctype.h> #include "cairoint.h" +#ifdef _MSC_VER +#define snprintf _snprintf +#endif /* _MSC_VER */ + struct _cairo_output_stream { cairo_write_func_t write_data; void *closure; diff --git a/src/cairo-path-data-private.h b/src/cairo-path-data-private.h index d680f901..06ab187d 100644 --- a/src/cairo-path-data-private.h +++ b/src/cairo-path-data-private.h @@ -38,7 +38,7 @@ #include "cairoint.h" -extern cairo_path_t cairo_path_nil; +extern cairo_private const cairo_path_t _cairo_path_nil; cairo_private cairo_path_t * _cairo_path_data_create (cairo_path_fixed_t *path, diff --git a/src/cairo-path-data.c b/src/cairo-path-data.c index b3bd3123..11a0d0f0 100644 --- a/src/cairo-path-data.c +++ b/src/cairo-path-data.c @@ -37,7 +37,7 @@ #include "cairo-path-fixed-private.h" #include "cairo-gstate-private.h" -cairo_path_t cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 }; +const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 }; /* Closure for path interpretation. */ typedef struct cairo_path_data_count { @@ -346,7 +346,7 @@ _cairo_path_data_create_real (cairo_path_fixed_t *path_fixed, path = malloc (sizeof (cairo_path_t)); if (path == NULL) - return &cairo_path_nil; + return (cairo_path_t*) &_cairo_path_nil; path->num_data = _cairo_path_data_count (path, path_fixed, gstate->tolerance, flatten); @@ -354,7 +354,7 @@ _cairo_path_data_create_real (cairo_path_fixed_t *path_fixed, path->data = malloc (path->num_data * sizeof (cairo_path_data_t)); if (path->data == NULL) { free (path); - return &cairo_path_nil; + return (cairo_path_t*) &_cairo_path_nil; } path->status = CAIRO_STATUS_SUCCESS; @@ -382,7 +382,7 @@ _cairo_path_data_create_real (cairo_path_fixed_t *path_fixed, void cairo_path_destroy (cairo_path_t *path) { - if (path == NULL || path == &cairo_path_nil) + if (path == NULL || path == &_cairo_path_nil) return; free (path->data); diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index c0015fc9..31b83ade 100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -36,10 +36,8 @@ #include "cairoint.h" -#include "cairo-gstate-private.h" - typedef struct cairo_filler { - cairo_gstate_t *gstate; + double tolerance; cairo_traps_t *traps; cairo_point_t current_point; @@ -48,7 +46,7 @@ typedef struct cairo_filler { } cairo_filler_t; static void -_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps); +_cairo_filler_init (cairo_filler_t *filler, double tolerance, cairo_traps_t *traps); static void _cairo_filler_fini (cairo_filler_t *filler); @@ -69,9 +67,9 @@ static cairo_status_t _cairo_filler_close_path (void *closure); static void -_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps) +_cairo_filler_init (cairo_filler_t *filler, double tolerance, cairo_traps_t *traps) { - filler->gstate = gstate; + filler->tolerance = tolerance; filler->traps = traps; filler->current_point.x = 0; @@ -132,7 +130,6 @@ _cairo_filler_curve_to (void *closure, cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_filler_t *filler = closure; cairo_polygon_t *polygon = &filler->polygon; - cairo_gstate_t *gstate = filler->gstate; cairo_spline_t spline; status = _cairo_spline_init (&spline, &filler->current_point, b, c, d); @@ -140,7 +137,7 @@ _cairo_filler_curve_to (void *closure, if (status == CAIRO_INT_STATUS_DEGENERATE) return CAIRO_STATUS_SUCCESS; - _cairo_spline_decompose (&spline, gstate->tolerance); + _cairo_spline_decompose (&spline, filler->tolerance); if (status) goto CLEANUP_SPLINE; @@ -174,13 +171,14 @@ _cairo_filler_close_path (void *closure) cairo_status_t _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, - cairo_gstate_t *gstate, + cairo_fill_rule_t fill_rule, + double tolerance, cairo_traps_t *traps) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_filler_t filler; - _cairo_filler_init (&filler, gstate, traps); + _cairo_filler_init (&filler, tolerance, traps); status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, @@ -198,7 +196,7 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, status = _cairo_traps_tessellate_polygon (filler.traps, &filler.polygon, - filler.gstate->fill_rule); + fill_rule); if (status) goto BAIL; diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 1fb17217..ca93dde4 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -236,8 +236,7 @@ _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern, { _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SURFACE); - pattern->surface = surface; - cairo_surface_reference (surface); + pattern->surface = cairo_surface_reference (surface); } static void @@ -489,17 +488,21 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, * Increases the reference count on @pattern by one. This prevents * @pattern from being destroyed until a matching call to * cairo_pattern_destroy() is made. + * + * Return value: the referenced #cairo_pattern_t. **/ -void +cairo_pattern_t * cairo_pattern_reference (cairo_pattern_t *pattern) { if (pattern == NULL) - return; + return NULL; if (pattern->ref_count == (unsigned int)-1) - return; + return pattern; pattern->ref_count++; + + return pattern; } /** diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 485c1a0e..6b863721 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -159,7 +159,7 @@ _cairo_pdf_document_destroy (cairo_pdf_document_t *document); static cairo_status_t _cairo_pdf_document_finish (cairo_pdf_document_t *document); -static void +static cairo_pdf_document_t * _cairo_pdf_document_reference (cairo_pdf_document_t *document); static unsigned int @@ -365,8 +365,7 @@ _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document, surface->width = width; surface->height = height; - _cairo_pdf_document_reference (document); - surface->document = document; + surface->document = _cairo_pdf_document_reference (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)); @@ -1152,6 +1151,7 @@ static cairo_int_status_t _cairo_pdf_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int x_src, int y_src, int x_dst, @@ -1335,7 +1335,8 @@ static cairo_int_status_t _cairo_pdf_surface_intersect_clip_path (void *dst, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, - double tolerance) + double tolerance, + cairo_antialias_t antialias) { cairo_pdf_surface_t *surface = dst; cairo_pdf_document_t *document = surface->document; @@ -1658,10 +1659,12 @@ _cairo_pdf_document_write_xref (cairo_pdf_document_t *document) return offset; } -static void +static cairo_pdf_document_t * _cairo_pdf_document_reference (cairo_pdf_document_t *document) { document->ref_count++; + + return document; } static void diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 0b2962c2..a897ed0e 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -272,6 +272,7 @@ static cairo_int_status_t _cairo_ps_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int x_src, int y_src, int x_dst, @@ -286,6 +287,7 @@ _cairo_ps_surface_composite_trapezoids (cairo_operator_t operator, return _cairo_surface_composite_trapezoids (operator, pattern, surface->current_page, + antialias, x_src, y_src, x_dst, @@ -324,14 +326,16 @@ static cairo_int_status_t _cairo_ps_surface_intersect_clip_path (void *dst, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, - double tolerance) + double tolerance, + cairo_antialias_t antialias) { cairo_ps_surface_t *surface = dst; return _cairo_surface_intersect_clip_path (surface->current_page, path, fill_rule, - tolerance); + tolerance, + antialias); } static cairo_int_status_t @@ -929,6 +933,7 @@ static cairo_int_status_t _ps_output_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int x_src, int y_src, int x_dst, @@ -1054,7 +1059,8 @@ static cairo_int_status_t _ps_output_intersect_clip_path (void *abstract_surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, - double tolerance) + double tolerance, + cairo_antialias_t antialias) { ps_output_surface_t *surface = abstract_surface; cairo_output_stream_t *stream = surface->parent->stream; diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index af92c010..70f408a3 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -152,7 +152,8 @@ _cairo_quartz_surface_acquire_dest_image(void *abstract_surface, image_rect->height = surface->image->height; *image_out = surface->image; - *image_extra = NULL; + if (image_extra) + *image_extra = NULL; return CAIRO_STATUS_SUCCESS; } @@ -233,7 +234,7 @@ cairo_surface_t *cairo_quartz_surface_create(CGContextRef context, surface = malloc(sizeof(cairo_quartz_surface_t)); if (surface == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); - return &_cairo_surface_nil; + return (cairo_surface_t*) &_cairo_surface_nil; } _cairo_surface_init(&surface->base, &cairo_quartz_surface_backend); diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 11fbc609..8353d329 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -245,18 +245,38 @@ _cairo_surface_get_clip_mode (cairo_surface_t *surface) return CAIRO_CLIP_MODE_MASK; } -void +/** + * cairo_surface_reference: + * @surface: a #cairo_surface_t + * + * Increases the reference count on @surface by one. This prevents + * @surface from being destroyed until a matching call to + * cairo_surface_destroy() is made. + * + * Return value: the referenced #cairo_surface_t. + **/ +cairo_surface_t * cairo_surface_reference (cairo_surface_t *surface) { if (surface == NULL) - return; + return NULL; if (surface->ref_count == (unsigned int)-1) - return; + return surface; surface->ref_count++; + + return surface; } +/** + * cairo_surface_destroy: + * @surface: a #cairo_t + * + * Decreases the reference count on @surface by one. If the result is + * zero, then @surface and all associated resources are freed. See + * cairo_surface_reference(). + **/ void cairo_surface_destroy (cairo_surface_t *surface) { @@ -310,7 +330,15 @@ cairo_surface_finish (cairo_surface_t *surface) surface->finished = TRUE; return; } - + + if (!surface->status && surface->backend->flush) { + status = surface->backend->flush (surface); + if (status) { + _cairo_surface_set_error (surface, status); + return; + } + } + status = surface->backend->finish (surface); if (status) { _cairo_surface_set_error (surface, status); @@ -393,6 +421,93 @@ cairo_surface_get_font_options (cairo_surface_t *surface, } /** + * cairo_surface_flush: + * @surface: a #cairo_surface_t + * + * Do any pending drawing for the surface and also restore any + * temporary modification's cairo has made to the surface's + * state. This function must be called before switching from + * drawing on the surface with cairo to drawing on it directly + * with native APIs. If the surface doesn't support direct access, + * then this function does nothing. + **/ +void +cairo_surface_flush (cairo_surface_t *surface) +{ + if (surface->status) { + _cairo_surface_set_error (surface, surface->status); + return; + } + + if (surface->finished) { + _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + return; + } + + if (surface->backend->flush) { + cairo_status_t status; + + status = surface->backend->flush (surface); + + if (status) + _cairo_surface_set_error (surface, status); + } +} + +/** + * cairo_surface_mark_dirty: + * @surface: a #cairo_surface_t + * + * Tells cairo that drawing has been done to surface using means other + * than cairo, and that cairo should reread any cached areas. Note + * that you must call cairo_surface_flush() before doing such drawing. + */ +void +cairo_surface_mark_dirty (cairo_surface_t *surface) +{ + cairo_surface_mark_dirty_rectangle (surface, 0, 0, -1, -1); +} + +/** + * cairo_surface_mark_dirty_rectangle: + * @surface: a #cairo_surface_t + * @x: X coordinate of dirty rectangle + * @y: Y coordinate of dirty rectangle + * @width: width of dirty rectangle + * @height: height of dirty rectangle + * + * Like cairo_surface_mark_dirty(), but drawing has been done only to + * the specified rectangle, so that cairo can retain cached contents + * for other parts of the surface. + */ +void +cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, + int x, + int y, + int width, + int height) +{ + if (surface->status) { + _cairo_surface_set_error (surface, surface->status); + return; + } + + if (surface->finished) { + _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + return; + } + + if (surface->backend->mark_dirty_rectangle) { + cairo_status_t status; + + status = surface->backend->mark_dirty_rectangle (surface, x, y, width, height); + + if (status) + _cairo_surface_set_error (surface, status); + } +} + +/** * cairo_surface_set_device_offset: * @surface: a #cairo_surface_t * @x_offset: the offset in the X direction, in device units @@ -876,6 +991,7 @@ static cairo_status_t _fallback_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, cairo_surface_t *dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -928,6 +1044,7 @@ _fallback_composite_trapezoids (cairo_operator_t operator, state.image->base.backend->composite_trapezoids (operator, pattern, &state.image->base, + antialias, src_x, src_y, dst_x - state.image_rect.x, dst_y - state.image_rect.y, @@ -945,6 +1062,7 @@ cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, cairo_surface_t *dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -965,6 +1083,7 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, if (dst->backend->composite_trapezoids) { status = dst->backend->composite_trapezoids (operator, pattern, dst, + antialias, src_x, src_y, dst_x, dst_y, width, height, @@ -974,6 +1093,7 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, } return _fallback_composite_trapezoids (operator, pattern, dst, + antialias, src_x, src_y, dst_x, dst_y, width, height, @@ -1076,7 +1196,8 @@ _cairo_surface_reset_clip (cairo_surface_t *surface) status = surface->backend->intersect_clip_path (surface, NULL, CAIRO_FILL_RULE_WINDING, - 0); + 0, + CAIRO_ANTIALIAS_DEFAULT); if (status) return status; } @@ -1122,7 +1243,8 @@ cairo_int_status_t _cairo_surface_intersect_clip_path (cairo_surface_t *surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, - double tolerance) + double tolerance, + cairo_antialias_t antialias) { if (surface->status) return surface->status; @@ -1135,7 +1257,8 @@ _cairo_surface_intersect_clip_path (cairo_surface_t *surface, return surface->backend->intersect_clip_path (surface, path, fill_rule, - tolerance); + tolerance, + antialias); } static cairo_status_t @@ -1154,21 +1277,20 @@ _cairo_surface_set_clip_path_recursive (cairo_surface_t *surface, return surface->backend->intersect_clip_path (surface, &clip_path->path, clip_path->fill_rule, - clip_path->tolerance); + clip_path->tolerance, + clip_path->antialias); } /** * _cairo_surface_set_clip_path: - * @surface: the #cairo_surface_t to reset the clip on - * @path: the path to intersect against the current clipping path - * @fill_rule: fill rule to use for clipping - * @tolerance: tesselation to use for tesselating clipping path - * @serial: the clip serial number associated with the region + * @surface: the #cairo_surface_t to set the clip on + * @clip_path: the clip path to set + * @serial: the clip serial number associated with the clip path * - * Sets the clipping path to be the intersection of the current - * clipping path of the surface and the given path. + * Sets the given clipping path for the surface and assigns the + * clipping serial to the surface. **/ -cairo_status_t +static cairo_status_t _cairo_surface_set_clip_path (cairo_surface_t *surface, cairo_clip_path_t *clip_path, unsigned int serial) @@ -1186,7 +1308,8 @@ _cairo_surface_set_clip_path (cairo_surface_t *surface, status = surface->backend->intersect_clip_path (surface, NULL, CAIRO_FILL_RULE_WINDING, - 0); + 0, + CAIRO_ANTIALIAS_DEFAULT); if (status) return status; @@ -1199,6 +1322,27 @@ _cairo_surface_set_clip_path (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +cairo_status_t +_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip) +{ + if (!surface) + return CAIRO_STATUS_NULL_POINTER; + if (clip->serial == _cairo_surface_get_current_clip_serial (surface)) + return CAIRO_STATUS_SUCCESS; + + if (clip->path) + return _cairo_surface_set_clip_path (surface, + clip->path, + clip->serial); + + if (clip->region) + return _cairo_surface_set_clip_region (surface, + clip->region, + clip->serial); + + return _cairo_surface_reset_clip (surface); +} + /** * _cairo_surface_get_extents: * @surface: the #cairo_surface_t to fetch extents for @@ -1260,3 +1404,154 @@ _cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font, return status; } + +/** + * _cairo_surface_composite_fixup_unbounded: + * @dst: the destination surface + * @src_attr: source surface attributes (from _cairo_pattern_acquire_surface()) + * @src_width: width of source surface + * @src_height: height of source surface + * @mask_attr: mask surface attributes or %NULL if no mask + * @mask_width: width of mask surface + * @mask_height: height of mask surface + * @src_x: @src_x from _cairo_surface_composite() + * @src_y: @src_y from _cairo_surface_composite() + * @mask_x: @mask_x from _cairo_surface_composite() + * @mask_y: @mask_y from _cairo_surface_composite() + * @dst_x: @dst_x from _cairo_surface_composite() + * @dst_y: @dst_y from _cairo_surface_composite() + * @width: @width from _cairo_surface_composite() + * @height: @height_x from _cairo_surface_composite() + * + * Eeek! Too many parameters! This is a helper function to take care of fixing + * up for bugs in libpixman and RENDER where, when asked to composite an + * untransformed surface with an unbounded operator (like CLEAR or SOURCE) + * only the region inside both the source and the mask is affected. + * This function clears the region that should have been drawn but was wasn't. + **/ +void +_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, + cairo_surface_attributes_t *src_attr, + int src_width, + int src_height, + cairo_surface_attributes_t *mask_attr, + int mask_width, + int mask_height, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_bool_t have_src = TRUE; + cairo_bool_t have_mask = mask_attr != NULL; + cairo_rectangle_t dst_rectangle; + cairo_rectangle_t drawn_rectangle; + cairo_rectangle_t rects[4]; + int num_rects = 0; + + /* The RENDER/libpixman operators are clipped to the bounds of the untransformed, + * non-repeating sources and masks. Other sources and masks can be ignored. + */ + if (!_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) || + src_attr->extend != CAIRO_EXTEND_NONE) + have_src = FALSE; + + if (have_mask && + (!_cairo_matrix_is_integer_translation (&mask_attr->matrix, NULL, NULL) || + mask_attr->extend != CAIRO_EXTEND_NONE)) + have_mask = FALSE; + + /* The area that was drawn is the area in the destination rectangle but not within + * the source or the mask. + */ + dst_rectangle.x = dst_x; + dst_rectangle.y = dst_y; + dst_rectangle.width = width; + dst_rectangle.height = height; + + drawn_rectangle = dst_rectangle; + + if (have_src) { + cairo_rectangle_t src_rectangle; + + src_rectangle.x = (dst_x - (src_x + src_attr->x_offset)); + src_rectangle.y = (dst_y - (src_y + src_attr->y_offset)); + src_rectangle.width = src_width; + src_rectangle.height = src_height; + + _cairo_rectangle_intersect (&drawn_rectangle, &src_rectangle); + } + + if (have_mask) { + cairo_rectangle_t mask_rectangle; + + mask_rectangle.x = (dst_x - (mask_x + mask_attr->x_offset)); + mask_rectangle.y = (dst_y - (mask_y + mask_attr->y_offset)); + mask_rectangle.width = mask_width; + mask_rectangle.height = mask_height; + + _cairo_rectangle_intersect (&drawn_rectangle, &mask_rectangle); + } + + /* Now compute the area that is in dst_rectangle but not in drawn_rectangle; + * this is the area we must clear; This computation could be done with + * regions, but the clumsiness of the libpixman API makes this easier. + */ + if (drawn_rectangle.width == 0 || drawn_rectangle.height == 0) + { + rects[num_rects].x = dst_rectangle.x; + rects[num_rects].y = dst_rectangle.y; + rects[num_rects].width = dst_rectangle.width; + rects[num_rects].height = dst_rectangle.height; + + num_rects++; + } + else + { + if (dst_rectangle.y < drawn_rectangle.y) { + rects[num_rects].x = dst_rectangle.x; + rects[num_rects].y = dst_rectangle.y; + rects[num_rects].width = dst_rectangle.width; + rects[num_rects].height = drawn_rectangle.y - dst_rectangle.y; + + num_rects++; + } + + if (dst_rectangle.x < drawn_rectangle.x) { + rects[num_rects].x = dst_rectangle.x; + rects[num_rects].y = drawn_rectangle.y; + rects[num_rects].width = drawn_rectangle.x - dst_rectangle.x; + rects[num_rects].height = drawn_rectangle.height; + + num_rects++; + } + + if (dst_rectangle.x + dst_rectangle.width > drawn_rectangle.x + drawn_rectangle.width) { + rects[num_rects].x = drawn_rectangle.x + drawn_rectangle.width; + rects[num_rects].y = drawn_rectangle.y; + rects[num_rects].width = (dst_rectangle.x + dst_rectangle.width) - (drawn_rectangle.x + drawn_rectangle.width); + rects[num_rects].height = drawn_rectangle.height; + + num_rects++; + } + + if (dst_rectangle.y + dst_rectangle.height > drawn_rectangle.y + drawn_rectangle.height) { + rects[num_rects].x = dst_rectangle.x; + rects[num_rects].y = drawn_rectangle.y + drawn_rectangle.height; + rects[num_rects].width = dst_rectangle.width; + rects[num_rects].height = (dst_rectangle.y + dst_rectangle.height) - (drawn_rectangle.y + drawn_rectangle.height); + + num_rects++; + } + } + + if (num_rects > 0) { + _cairo_surface_fill_rectangles (dst, CAIRO_OPERATOR_SOURCE, CAIRO_COLOR_TRANSPARENT, + rects, num_rects); + } +} + diff --git a/src/cairo-traps.c b/src/cairo-traps.c index a97d5848..18b944c1 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -229,6 +229,35 @@ _compare_point_fixed_by_y (const void *av, const void *bv) return ret; } +void +_cairo_traps_translate (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; + } +} + cairo_status_t _cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3]) { diff --git a/src/cairo-wideint.c b/src/cairo-wideint.c index 60946d90..9e4914e6 100644 --- a/src/cairo-wideint.c +++ b/src/cairo-wideint.c @@ -1,5 +1,5 @@ /* - * $Id: cairo-wideint.c,v 1.5 2005-06-03 21:51:57 cworth Exp $ + * $Id: cairo-wideint.c,v 1.6 2005-07-30 19:57:54 keithp Exp $ * * Copyright © 2004 Keith Packard * @@ -36,22 +36,6 @@ #include "cairoint.h" -#if !HAVE_UINT64_T || !HAVE_UINT128_T - -static const unsigned char top_bit[256] = -{ - 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, -}; - -#endif - #if HAVE_UINT64_T #define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l)) @@ -157,7 +141,8 @@ _cairo_uint32x32_64_mul (uint32_t a, uint32_t b) cairo_int64_t _cairo_int32x32_64_mul (int32_t a, int32_t b) { - s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t b)); + cairo_int64_t s; + s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t) b); if (a < 0) s.hi -= b; if (b < 0) @@ -270,200 +255,38 @@ _cairo_uint64_negate (cairo_uint64_t a) } /* - * The design of this algorithm comes from GCC, - * but the actual implementation is new + * Simple bit-at-a-time divide. */ - -static const int -_cairo_leading_zeros32 (uint32_t i) -{ - int top; - - if (i < 0x100) - top = 0; - else if (i < 0x10000) - top = 8; - else if (i < 0x1000000) - top = 16; - else - top = 24; - top = top + top_bit [i >> top]; - return 32 - top; -} - -typedef struct _cairo_uquorem32_t { - uint32_t quo; - uint32_t rem; -} cairo_uquorem32_t; - -/* - * den >= num.hi - */ -static const cairo_uquorem32_t -_cairo_uint64x32_normalized_divrem (cairo_uint64_t num, uint32_t den) -{ - cairo_uquorem32_t qr; - uint32_t q0, q1, r0, r1; - uint16_t d0, d1; - uint32_t t; - - d0 = den & 0xffff; - d1 = den >> 16; - - q1 = num.hi / d1; - r1 = num.hi % d1; - - t = q1 * d0; - r1 = (r1 << 16) | (num.lo >> 16); - if (r1 < t) - { - q1--; - r1 += den; - if (r1 >= den && r1 < t) - { - q1--; - r1 += den; - } - } - - r1 -= t; - - q0 = r1 / d1; - r0 = r1 % d1; - t = q0 * d0; - r0 = (r0 << 16) | (num.lo & 0xffff); - if (r0 < t) - { - q0--; - r0 += den; - if (r0 >= den && r0 < t) - { - q0--; - r0 += den; - } - } - r0 -= t; - qr.quo = (q1 << 16) | q0; - qr.rem = r0; - return qr; -} - cairo_uquorem64_t _cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den) { - cairo_uquorem32_t qr32; cairo_uquorem64_t qr; - int norm; - uint32_t q1, q0, r1, r0; - - if (den.hi == 0) + cairo_uint64_t bit; + cairo_uint64_t quo; + + bit = _cairo_uint32_to_uint64 (1); + + /* normalize to make den >= num, but not overflow */ + while (_cairo_uint64_lt (den, num) && (den.hi & 0x80000000) == 0) { - if (den.lo > num.hi) - { - /* 0q = nn / 0d */ - - norm = _cairo_leading_zeros32 (den.lo); - if (norm) - { - den.lo <<= norm; - num = _cairo_uint64_lsl (num, norm); - } - q1 = 0; - } - else - { - /* qq = NN / 0d */ - - if (den.lo == 0) - den.lo = 1 / den.lo; - - norm = _cairo_leading_zeros32 (den.lo); - if (norm) - { - cairo_uint64_t num1; - den.lo <<= norm; - num1 = _cairo_uint64_rsl (num, 32 - norm); - qr32 = _cairo_uint64x32_normalized_divrem (num1, den.lo); - q1 = qr32.quo; - num.hi = qr32.rem; - num.lo <<= norm; - } - else - { - num.hi -= den.lo; - q1 = 1; - } - } - qr32 = _cairo_uint64x32_normalized_divrem (num, den.lo); - q0 = qr32.quo; - r1 = 0; - r0 = qr32.rem >> norm; + bit = _cairo_uint64_lsl (bit, 1); + den = _cairo_uint64_lsl (den, 1); } - else + quo = _cairo_uint32_to_uint64 (0); + + /* generate quotient, one bit at a time */ + while (bit.hi | bit.lo) { - if (den.hi > num.hi) - { - /* 00 = nn / DD */ - q0 = q1 = 0; - r0 = num.lo; - r1 = num.hi; - } - else + if (_cairo_uint64_le (den, num)) { - /* 0q = NN / dd */ - - norm = _cairo_leading_zeros32 (den.hi); - if (norm == 0) - { - if (num.hi > den.hi || num.lo >= den.lo) - { - q0 = 1; - num = _cairo_uint64_sub (num, den); - } - else - { - q0 = 0; - } - - q1 = 0; - r0 = num.lo; - r1 = num.hi; - } - else - { - cairo_uint64_t num1; - cairo_uint64_t part; - - num1 = _cairo_uint64_rsl (num, 32 - norm); - den = _cairo_uint64_lsl (den, norm); - - qr32 = _cairo_uint64x32_normalized_divrem (num1, den.hi); - part = _cairo_uint32x32_64_mul (qr32.quo, den.lo); - - q0 = qr32.quo; - - num.lo <<= norm; - num.hi = qr32.rem; - - if (_cairo_uint64_gt (part, num)) - { - q0--; - part = _cairo_uint64_sub (part, den); - } - - q1 = 0; - - num = _cairo_uint64_sub (num, part); - num = _cairo_uint64_rsl (num, norm); - r0 = num.lo; - r1 = num.hi; - } + num = _cairo_uint64_sub (num, den); + quo = _cairo_uint64_add (quo, bit); } + bit = _cairo_uint64_rsl (bit, 1); + den = _cairo_uint64_rsl (den, 1); } - qr.quo.lo = q0; - qr.quo.hi = q1; - qr.rem.lo = r0; - qr.rem.hi = r1; + qr.quo = quo; + qr.rem = num; return qr; } @@ -754,234 +577,42 @@ _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b) _cairo_uint64_eq (a.lo, b.lo)); } -/* - * The design of this algorithm comes from GCC, - * but the actual implementation is new - */ - -/* - * den >= num.hi - */ -static cairo_uquorem64_t -_cairo_uint128x64_normalized_divrem (cairo_uint128_t num, cairo_uint64_t den) -{ - cairo_uquorem64_t qr64; - cairo_uquorem64_t qr; - uint32_t q0, q1; - cairo_uint64_t r0, r1; - uint32_t d0, d1; - cairo_uint64_t t; - - d0 = uint64_lo32 (den); - d1 = uint64_hi32 (den); - - qr64 = _cairo_uint64_divrem (num.hi, _cairo_uint32_to_uint64 (d1)); - q1 = _cairo_uint64_to_uint32 (qr64.quo); - r1 = qr64.rem; - - t = _cairo_uint32x32_64_mul (q1, d0); - - r1 = _cairo_uint64_add (_cairo_uint64_lsl (r1, 32), - _cairo_uint64_rsl (num.lo, 32)); - - if (_cairo_uint64_lt (r1, t)) - { - q1--; - r1 = _cairo_uint64_add (r1, den); - if (_cairo_uint64_ge (r1, den) && _cairo_uint64_lt (r1, t)) - { - q1--; - r1 = _cairo_uint64_add (r1, den); - } - } - - r1 = _cairo_uint64_sub (r1, t); - - qr64 = _cairo_uint64_divrem (r1, _cairo_uint32_to_uint64 (d1)); - - q0 = _cairo_uint64_to_uint32 (qr64.quo); - r0 = qr64.rem; - - t = _cairo_uint32x32_64_mul (q0, d0); - - r0 = _cairo_uint64_add (_cairo_uint64_lsl (r0, 32), - _cairo_uint32_to_uint64 (_cairo_uint64_to_uint32 (num.lo))); - if (_cairo_uint64_lt (r0, t)) - { - q0--; - r0 = _cairo_uint64_add (r0, den); - if (_cairo_uint64_ge (r0, den) && _cairo_uint64_lt (r0, t)) - { - q0--; - r0 = _cairo_uint64_add (r0, den); - } - } - - r0 = _cairo_uint64_sub (r0, t); - - qr.quo = _cairo_uint32s_to_uint64 (q1, q0); - qr.rem = r0; - return qr; -} - #if HAVE_UINT64_T - -static int -_cairo_leading_zeros64 (cairo_uint64_t q) -{ - int top = 0; - - if (q >= (uint64_t) 0x10000 << 16) - { - top += 32; - q >>= 32; - } - if (q >= (uint64_t) 0x10000) - { - top += 16; - q >>= 16; - } - if (q >= (uint64_t) 0x100) - { - top += 8; - q >>= 8; - } - top += top_bit [q]; - return 64 - top; -} - +#define _cairo_msbset64(q) (q & ((uint64_t) 1 << 63)) #else - -static const int -_cairo_leading_zeros64 (cairo_uint64_t d) -{ - if (d.hi) - return _cairo_leading_zeros32 (d.hi); - else - return 32 + _cairo_leading_zeros32 (d.lo); -} - +#define _cairo_msbset64(q) (q.hi & ((uint32_t) 1 << 31)) #endif cairo_uquorem128_t _cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den) { - cairo_uquorem64_t qr64; cairo_uquorem128_t qr; - int norm; - cairo_uint64_t q1, q0, r1, r0; - - if (_cairo_uint64_eq (den.hi, _cairo_uint32_to_uint64 (0))) + cairo_uint128_t bit; + cairo_uint128_t quo; + + bit = _cairo_uint32_to_uint128 (1); + + /* normalize to make den >= num, but not overflow */ + while (_cairo_uint128_lt (den, num) && !_cairo_msbset64(den.hi)) { - if (_cairo_uint64_gt (den.lo, num.hi)) - { - /* 0q = nn / 0d */ - - norm = _cairo_leading_zeros64 (den.lo); - if (norm) - { - den.lo = _cairo_uint64_lsl (den.lo, norm); - num = _cairo_uint128_lsl (num, norm); - } - q1 = _cairo_uint32_to_uint64 (0); - } - else - { - /* qq = NN / 0d */ - - if (_cairo_uint64_eq (den.lo, _cairo_uint32_to_uint64 (0))) - den.lo = _cairo_uint64_divrem (_cairo_uint32_to_uint64 (1), - den.lo).quo; - - norm = _cairo_leading_zeros64 (den.lo); - if (norm) - { - cairo_uint128_t num1; - - den.lo = _cairo_uint64_lsl (den.lo, norm); - num1 = _cairo_uint128_rsl (num, 64 - norm); - qr64 = _cairo_uint128x64_normalized_divrem (num1, den.lo); - q1 = qr64.quo; - num.hi = qr64.rem; - num.lo = _cairo_uint64_lsl (num.lo, norm); - } - else - { - num.hi = _cairo_uint64_sub (num.hi, den.lo); - q1 = _cairo_uint32_to_uint64 (1); - } - } - qr64 = _cairo_uint128x64_normalized_divrem (num, den.lo); - q0 = qr64.quo; - r1 = _cairo_uint32_to_uint64 (0); - r0 = _cairo_uint64_rsl (qr64.rem, norm); + bit = _cairo_uint128_lsl (bit, 1); + den = _cairo_uint128_lsl (den, 1); } - else + quo = _cairo_uint32_to_uint128 (0); + + /* generate quotient, one bit at a time */ + while (_cairo_uint128_ne (bit, _cairo_uint32_to_uint128(0))) { - if (_cairo_uint64_gt (den.hi, num.hi)) - { - /* 00 = nn / DD */ - q0 = q1 = _cairo_uint32_to_uint64 (0); - r0 = num.lo; - r1 = num.hi; - } - else + if (_cairo_uint128_le (den, num)) { - /* 0q = NN / dd */ - - norm = _cairo_leading_zeros64 (den.hi); - if (norm == 0) - { - if (_cairo_uint64_gt (num.hi, den.hi) || - _cairo_uint64_ge (num.lo, den.lo)) - { - q0 = _cairo_uint32_to_uint64 (1); - num = _cairo_uint128_sub (num, den); - } - else - { - q0 = _cairo_uint32_to_uint64 (0); - } - - q1 = _cairo_uint32_to_uint64 (0); - r0 = num.lo; - r1 = num.hi; - } - else - { - cairo_uint128_t num1; - cairo_uint128_t part; - - num1 = _cairo_uint128_rsl (num, 64 - norm); - den = _cairo_uint128_lsl (den, norm); - - qr64 = _cairo_uint128x64_normalized_divrem (num1, den.hi); - part = _cairo_uint64x64_128_mul (qr64.quo, den.lo); - - q0 = qr64.quo; - - num.lo = _cairo_uint64_lsl (num.lo, norm); - num.hi = qr64.rem; - - if (_cairo_uint128_gt (part, num)) - { - q0 = _cairo_uint64_sub (q0, _cairo_uint32_to_uint64 (1)); - part = _cairo_uint128_sub (part, den); - } - - q1 = _cairo_uint32_to_uint64 (0); - - num = _cairo_uint128_sub (num, part); - num = _cairo_uint128_rsl (num, norm); - r0 = num.lo; - r1 = num.hi; - } + num = _cairo_uint128_sub (num, den); + quo = _cairo_uint128_add (quo, bit); } + bit = _cairo_uint128_rsl (bit, 1); + den = _cairo_uint128_rsl (den, 1); } - qr.quo.lo = q0; - qr.quo.hi = q1; - qr.rem.lo = r0; - qr.rem.hi = r1; + qr.quo = quo; + qr.rem = num; return qr; } diff --git a/src/cairo-wideint.h b/src/cairo-wideint.h index 3afea5a6..b008b5d5 100644 --- a/src/cairo-wideint.h +++ b/src/cairo-wideint.h @@ -1,5 +1,5 @@ /* - * $Id: cairo-wideint.h,v 1.10 2005-05-10 19:42:32 cworth Exp $ + * $Id: cairo-wideint.h,v 1.12 2005-08-05 14:48:19 cworth Exp $ * * Copyright © 2004 Keith Packard * @@ -44,6 +44,18 @@ # include <inttypes.h> #elif HAVE_SYS_INT_TYPES_H # include <sys/int_types.h> +#elif defined(_MSC_VER) + typedef __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +# ifndef HAVE_UINT64_T +# define HAVE_UINT64_T 1 +# endif #else #error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) #endif @@ -85,7 +97,7 @@ cairo_int64_t I _cairo_int32_to_int64(int32_t i); #define _cairo_int64_add(a,b) _cairo_uint64_add (a,b) #define _cairo_int64_sub(a,b) _cairo_uint64_sub (a,b) #define _cairo_int64_mul(a,b) _cairo_uint64_mul (a,b) -int I _cairo_int32x32_64_mul (int32_t a, int32_t b); +cairo_int64_t I _cairo_int32x32_64_mul (int32_t a, int32_t b); int I _cairo_int64_lt (cairo_uint64_t a, cairo_uint64_t b); #define _cairo_int64_eq(a,b) _cairo_uint64_eq (a,b) #define _cairo_int64_lsl(a,b) _cairo_uint64_lsl (a,b) @@ -208,7 +220,7 @@ cairo_int128_t I _cairo_int64_to_int128 (cairo_int64_t i); #define _cairo_int128_add(a,b) _cairo_uint128_add(a,b) #define _cairo_int128_sub(a,b) _cairo_uint128_sub(a,b) #define _cairo_int128_mul(a,b) _cairo_uint128_mul(a,b) -cairo_uint128_t I _cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b); +cairo_int128_t I _cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b); #define _cairo_int128_lsl(a,b) _cairo_uint128_lsl(a,b) #define _cairo_int128_rsl(a,b) _cairo_uint128_rsl(a,b) #define _cairo_int128_rsa(a,b) _cairo_uint128_rsa(a,b) diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c index 15dd96b3..4867fc0f 100644 --- a/src/cairo-win32-font.c +++ b/src/cairo-win32-font.c @@ -58,7 +58,6 @@ typedef struct { cairo_scaled_font_t base; LOGFONTW logfont; - cairo_font_options_t options; BYTE quality; @@ -227,7 +226,6 @@ _win32_scaled_font_create (LOGFONTW *logfont, return NULL; f->logfont = *logfont; - f->options = *options; /* We don't have any control over the hinting style or subpixel * order in the Win32 font API, so we ignore those parts of @@ -263,7 +261,7 @@ _win32_scaled_font_create (LOGFONTW *logfont, cairo_matrix_multiply (&scale, font_matrix, ctm); _compute_transform (f, &scale); - _cairo_scaled_font_init (&f->base, font_matrix, ctm, &cairo_win32_scaled_font_backend); + _cairo_scaled_font_init (&f->base, font_matrix, ctm, options, &cairo_win32_scaled_font_backend); return &f->base; } @@ -429,13 +427,11 @@ _cairo_win32_scaled_font_done_unscaled_font (cairo_scaled_font_t *scaled_font) /* implement the font backend interface */ static cairo_status_t -_cairo_win32_scaled_font_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **scaled_font_out) +_cairo_win32_scaled_font_create_toy (const cairo_toy_font_face_t *toy_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font_out) { LOGFONTW logfont; cairo_scaled_font_t *scaled_font; @@ -443,7 +439,8 @@ _cairo_win32_scaled_font_create (const char *family, int face_name_len; cairo_status_t status; - status = _cairo_utf8_to_utf16 (family, -1, &face_name, &face_name_len); + status = _cairo_utf8_to_utf16 (toy_face->family, -1, + &face_name, &face_name_len); if (status) return status; @@ -460,7 +457,7 @@ _cairo_win32_scaled_font_create (const char *family, logfont.lfEscapement = 0; /* filled in later */ logfont.lfOrientation = 0; /* filled in later */ - switch (weight) { + switch (toy_face->weight) { case CAIRO_FONT_WEIGHT_NORMAL: default: logfont.lfWeight = FW_NORMAL; @@ -470,7 +467,7 @@ _cairo_win32_scaled_font_create (const char *family, break; } - switch (slant) { + switch (toy_face->slant) { case CAIRO_FONT_SLANT_NORMAL: default: logfont.lfItalic = FALSE; @@ -506,7 +503,7 @@ _cairo_win32_scaled_font_create (const char *family, } static void -_cairo_win32_scaled_font_destroy (void *abstract_font) +_cairo_win32_scaled_font_fini (void *abstract_font) { cairo_win32_scaled_font_t *scaled_font = abstract_font; @@ -1059,7 +1056,6 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font, */ COLORREF new_color; - /* XXX Use the unpremultiplied or premultiplied color? */ new_color = RGB (((int)solid_pattern->color.red_short) >> 8, ((int)solid_pattern->color.green_short) >> 8, ((int)solid_pattern->color.blue_short) >> 8); @@ -1274,15 +1270,15 @@ FAIL: } const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend = { - _cairo_win32_scaled_font_create, - _cairo_win32_scaled_font_destroy, + _cairo_win32_scaled_font_create_toy, + _cairo_win32_scaled_font_fini, _cairo_win32_scaled_font_font_extents, _cairo_win32_scaled_font_text_to_glyphs, _cairo_win32_scaled_font_glyph_extents, _cairo_win32_scaled_font_glyph_bbox, _cairo_win32_scaled_font_show_glyphs, _cairo_win32_scaled_font_glyph_path, - _cairo_win32_scaled_font_get_glyph_cache_key, + _cairo_win32_scaled_font_get_glyph_cache_key }; /* cairo_win32_font_face_t */ @@ -1302,11 +1298,11 @@ _cairo_win32_font_face_destroy (void *abstract_face) } static cairo_status_t -_cairo_win32_font_face_create_font (void *abstract_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **font) +_cairo_win32_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font) { cairo_win32_font_face_t *font_face = abstract_face; @@ -1320,7 +1316,7 @@ _cairo_win32_font_face_create_font (void *abstract_face, static const cairo_font_face_backend_t _cairo_win32_font_face_backend = { _cairo_win32_font_face_destroy, - _cairo_win32_font_face_create_font, + _cairo_win32_font_face_scaled_font_create }; /** diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c index f9201245..95c37d99 100644 --- a/src/cairo-win32-surface.c +++ b/src/cairo-win32-surface.c @@ -340,8 +340,9 @@ _cairo_win32_surface_finish (void *abstract_surface) if (surface->image) cairo_surface_destroy (surface->image); - if (surface->saved_clip) + if (surface->saved_clip) { DeleteObject (surface->saved_clip); + } /* If we created the Bitmap and DC, destroy them */ if (surface->bitmap) { @@ -792,7 +793,6 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface, surface->set_clip = 0; } - return CAIRO_STATUS_SUCCESS; } else { @@ -893,6 +893,12 @@ _cairo_win32_surface_get_extents (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +static cairo_status_t +_cairo_win32_surface_flush (void *abstract_surface) +{ + return _cairo_surface_reset_clip (abstract_surface); +} + cairo_surface_t * cairo_win32_surface_create (HDC hdc) { @@ -964,5 +970,9 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = { _cairo_win32_surface_set_clip_region, NULL, /* intersect_clip_path */ _cairo_win32_surface_get_extents, - NULL /* show_glyphs */ + NULL, /* show_glyphs */ + NULL, /* fill_path */ + NULL, /* get_font_options */ + _cairo_win32_surface_flush, + NULL /* mark_dirty_rectangle */ }; diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index b743cf4d..2a7395f6 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -643,8 +643,7 @@ _cairo_xcb_surface_clone_similar (void *abstract_surface, cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src; if (xcb_src->dpy == surface->dpy) { - *clone_out = src; - cairo_surface_reference (src); + *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } @@ -943,6 +942,7 @@ static cairo_int_status_t _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -981,9 +981,17 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, render_src_x = src_x + render_reference_x - dst_x; render_src_y = src_y + render_reference_y - dst_y; + switch (antialias) { + case CAIRO_ANTIALIAS_NONE: + render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A1), + break; + default: + render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A8), + break; + } + /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ /* XXX: _format_from_cairo is slow. should cache something. */ - render_format = _format_from_cairo (dst->dpy, CAIRO_FORMAT_A8), status = _cairo_xcb_surface_set_attributes (src, &attributes); if (status == CAIRO_STATUS_SUCCESS) XCBRenderTrapezoids (dst->dpy, diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c index 6a4efdbd..e71d10ec 100644 --- a/src/cairo-xlib-screen.c +++ b/src/cairo-xlib-screen.c @@ -245,34 +245,59 @@ _cairo_xlib_init_screen_font_options (cairo_xlib_screen_info_t *info) CAIRO_MUTEX_DECLARE(_xlib_screen_mutex); -static cairo_xlib_screen_info_t *_cairo_xlib_screen_list; +static cairo_xlib_screen_info_t *_cairo_xlib_screen_list = NULL; static int _cairo_xlib_close_display (Display *dpy, XExtCodes *codes) { - cairo_xlib_screen_info_t *info; - cairo_xlib_screen_info_t **prev; + cairo_xlib_screen_info_t *info, *prev; /* * Unhook from the global list */ CAIRO_MUTEX_LOCK (_xlib_screen_mutex); - for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next) { + prev = NULL; + for (info = _cairo_xlib_screen_list; info; info = info->next) { if (info->display == dpy) { - *prev = info->next; + if (prev) + prev->next = info->next; + else + _cairo_xlib_screen_list = info->next; free (info); - if (!*prev) - break; + break; } + prev = info; } CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); - + + /* Return value in accordance with requirements of + * XESetCloseDisplay */ return 0; } +static void +_cairo_xlib_screen_info_reset (void) +{ + cairo_xlib_screen_info_t *info, *next; + + /* + * Delete everything in the list. + */ + CAIRO_MUTEX_LOCK (_xlib_screen_mutex); + + for (info = _cairo_xlib_screen_list; info; info = next) { + next = info->next; + free (info); + } + + _cairo_xlib_screen_list = NULL; + + CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex); + +} -cairo_private cairo_xlib_screen_info_t * +cairo_xlib_screen_info_t * _cairo_xlib_screen_info_get (Display *dpy, Screen *screen) { cairo_xlib_screen_info_t *info; @@ -344,3 +369,13 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen) return info; } +void +_cairo_xlib_screen_reset_static_data (void) +{ + _cairo_xlib_screen_info_reset (); + +#if HAVE_XRMFINALIZE + XrmFinalize (); +#endif + +} diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 5f26a2f4..7f4b8489 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -91,6 +91,14 @@ struct _cairo_xlib_surface { * * We can't test for this because it depends on whether the * picture is in video memory or not. + * + * We also use this variable as a guard against a second + * independent bug with transformed repeating pictures: + * + * http://lists.freedesktop.org/archives/cairo/2004-September/001839.html + * + * Both are fixed in xorg >= 6.9 and hopefully in > 6.8.2, so + * we can reuse the test for now. */ cairo_bool_t buggy_repeat; @@ -662,8 +670,7 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface, cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src; if (_cairo_xlib_surface_same_screen (surface, xlib_src)) { - *clone_out = src; - cairo_surface_reference (src); + *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } @@ -878,11 +885,13 @@ _operator_needs_alpha_composite (cairo_operator_t operator, return TRUE; } -/* There is a bug in most older X servers with compositing using a repeating - * source pattern when the source is in off-screen video memory. When that - * bug could be triggered, we need a fallback: in the common case where we have no - * transformation and the source and destination have the same format/visual, - * we can do the operation using the core protocol, otherwise, we need +/* There is a bug in most older X servers with compositing using a + * untransformed repeating source pattern when the source is in off-screen + * video memory, and another with repeated transformed images using a + * general tranform matrix. When these bugs could be triggered, we need a + * fallback: in the common case where we have no transformation and the + * source and destination have the same format/visual, we can do the + * operation using the core protocol for the first bug, otherwise, we need * a software fallback. * * We can also often optimize a compositing operation by calling XCopyArea @@ -896,9 +905,11 @@ typedef enum { DO_UNSUPPORTED /* software fallback */ } composite_operation_t; -/* Initial check for the bug; we need to recheck after we turn - * patterns into surfaces, since that may introduce a repeating - * pattern for gradient patterns. +/* Initial check for the render bugs; we need to recheck for the + * offscreen-memory bug after we turn patterns into surfaces, since that + * may introduce a repeating pattern for gradient patterns. We don't need + * to check for the repeat+transform bug because gradient surfaces aren't + * transformed. * * All we do here is reject cases where we *know* are going to * hit the bug and won't be able to use a core protocol fallback. @@ -920,8 +931,10 @@ _categorize_composite_operation (cairo_xlib_surface_t *dst, if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) && src_pattern->extend == CAIRO_EXTEND_REPEAT) { - /* This is the case where we have a bug; reject some cases where a - * core protocol fallback is impossible. + /* This is the case where we have the bug involving + * untransformed repeating source patterns with off-screen + * video memory; reject some cases where a core protocol + * fallback is impossible. */ if (have_mask || !(operator == CAIRO_OPERATOR_SOURCE || operator == CAIRO_OPERATOR_OVER)) @@ -942,6 +955,12 @@ _categorize_composite_operation (cairo_xlib_surface_t *dst, return DO_UNSUPPORTED; } } + + /* Check for the other bug involving repeat patterns with general + * transforms. */ + if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) && + src_pattern->extend == CAIRO_EXTEND_REPEAT) + return DO_UNSUPPORTED; } return DO_RENDER; @@ -1118,6 +1137,16 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, dst_x, dst_y, width, height); } + + if (!_cairo_operator_bounded (operator)) + _cairo_surface_composite_fixup_unbounded (&dst->base, + &src_attr, src->width, src->height, + mask ? &mask_attr : NULL, + mask ? mask->width : 0, + mask ? mask->height : 0, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, width, height); break; case DO_XCOPYAREA: @@ -1195,10 +1224,101 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +/* Creates an A8 picture of size @width x @height, initialized with @color + */ +static Picture +_create_a8_picture (cairo_xlib_surface_t *surface, + XRenderColor *color, + int width, + int height, + cairo_bool_t repeat) +{ + XRenderPictureAttributes pa; + unsigned long mask = 0; + + Pixmap pixmap = XCreatePixmap (surface->dpy, surface->drawable, + width, height, + 8); + Picture picture; + + if (repeat) { + pa.repeat = TRUE; + mask = CPRepeat; + } + + picture = XRenderCreatePicture (surface->dpy, pixmap, + XRenderFindStandardFormat (surface->dpy, PictStandardA8), + mask, &pa); + XRenderFillRectangle (surface->dpy, PictOpSrc, picture, color, + 0, 0, width, height); + XFreePixmap (surface->dpy, pixmap); + + return picture; +} + +/* Creates a temporary mask for the trapezoids covering the area + * [@dst_x, @dst_y, @width, @height] of the destination surface. + */ +static Picture +_create_trapezoid_mask (cairo_xlib_surface_t *dst, + cairo_trapezoid_t *traps, + int num_traps, + int dst_x, + int dst_y, + int width, + int height, + XRenderPictFormat *pict_format) +{ + XRenderColor transparent = { 0, 0, 0, 0 }; + XRenderColor solid = { 0xffff, 0xffff, 0xffff, 0xffff }; + Picture mask_picture, solid_picture; + XTrapezoid *offset_traps; + int i; + + /* This would be considerably simpler using XRenderAddTraps(), but since + * we are only using this in the unbounded-operator case, we stick with + * XRenderCompositeTrapezoids, which is available on older versions + * of RENDER rather than conditionalizing. We should still hit an + * optimization that avoids creating another intermediate surface on + * the servers that have XRenderAddTraps(). + */ + mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE); + solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE); + + offset_traps = malloc (sizeof (XTrapezoid) * num_traps); + if (!offset_traps) + return None; + + for (i = 0; i < num_traps; i++) { + offset_traps[i].top = traps[i].top - 0x10000 * dst_y; + offset_traps[i].bottom = traps[i].bottom - 0x10000 * dst_y; + offset_traps[i].left.p1.x = traps[i].left.p1.x - 0x10000 * dst_x; + offset_traps[i].left.p1.y = traps[i].left.p1.y - 0x10000 * dst_y; + offset_traps[i].left.p2.x = traps[i].left.p2.x - 0x10000 * dst_x; + offset_traps[i].left.p2.y = traps[i].left.p2.y - 0x10000 * dst_y; + offset_traps[i].right.p1.x = traps[i].right.p1.x - 0x10000 * dst_x; + offset_traps[i].right.p1.y = traps[i].right.p1.y - 0x10000 * dst_y; + offset_traps[i].right.p2.x = traps[i].right.p2.x - 0x10000 * dst_x; + offset_traps[i].right.p2.y = traps[i].right.p2.y - 0x10000 * dst_y; + } + + XRenderCompositeTrapezoids (dst->dpy, PictOpAdd, + solid_picture, mask_picture, + pict_format, + 0, 0, + offset_traps, num_traps); + + XRenderFreePicture (dst->dpy, solid_picture); + free (offset_traps); + + return mask_picture; +} + static cairo_int_status_t _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -1215,6 +1335,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, composite_operation_t operation; int render_reference_x, render_reference_y; int render_src_x, render_src_y; + XRenderPictFormat *pict_format; if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1235,6 +1356,15 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, status = CAIRO_INT_STATUS_UNSUPPORTED; goto FAIL; } + + switch (antialias) { + case CAIRO_ANTIALIAS_NONE: + pict_format = XRenderFindStandardFormat (dst->dpy, PictStandardA1); + break; + default: + pict_format = XRenderFindStandardFormat (dst->dpy, PictStandardA8); + break; + } if (traps[0].left.p1.y < traps[0].left.p2.y) { render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); @@ -1247,17 +1377,52 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, render_src_x = src_x + render_reference_x - dst_x; render_src_y = src_y + render_reference_y - dst_y; - /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ _cairo_xlib_surface_ensure_dst_picture (dst); status = _cairo_xlib_surface_set_attributes (src, &attributes); - if (status == CAIRO_STATUS_SUCCESS) + if (status) + goto FAIL; + + if (!_cairo_operator_bounded (operator)) { + /* XRenderCompositeTrapezoids() creates a mask only large enough for the + * trapezoids themselves, but if the operator is unbounded, then we need + * to actually composite all the way out to the bounds, so we create + * the mask and composite ourselves. There actually would + * be benefit to doing this in all cases, since RENDER implementations + * will frequently create a too temporary big mask, ignoring destination + * bounds and clip. (XRenderAddTraps() could be used to make creating + * the mask somewhat cheaper.) + */ + Picture mask_picture = _create_trapezoid_mask (dst, traps, num_traps, + dst_x, dst_y, width, height, + pict_format); + if (!mask_picture) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } + + XRenderComposite (dst->dpy, + _render_operator (operator), + src->src_picture, + mask_picture, + dst->dst_picture, + src_x + attributes.x_offset, + src_y + attributes.y_offset, + 0, 0, + dst_x, dst_y, + width, height); + + XRenderFreePicture (dst->dpy, mask_picture); + + } else { + /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ XRenderCompositeTrapezoids (dst->dpy, _render_operator (operator), src->src_picture, dst->dst_picture, - XRenderFindStandardFormat (dst->dpy, PictStandardA8), + pict_format, render_src_x + attributes.x_offset, render_src_y + attributes.y_offset, (XTrapezoid *) traps, num_traps); + } FAIL: _cairo_pattern_release_surface (pattern, &src->base, &attributes); @@ -1716,6 +1881,7 @@ typedef struct { cairo_glyph_cache_key_t key; GlyphSet glyphset; Glyph glyph; + cairo_glyph_size_t size; } glyphset_cache_entry_t; static Glyph @@ -1770,6 +1936,7 @@ _xlib_glyphset_cache_create_entry (void *abstract_cache, entry->glyph = None; entry->glyphset = None; entry->key.base.memory = 0; + entry->size.x = entry->size.y = entry->size.width = entry->size.height = 0; goto out; } @@ -1778,6 +1945,8 @@ _xlib_glyphset_cache_create_entry (void *abstract_cache, data = im->image->data; + entry->size = im->size; + glyph_info.width = im->size.width; glyph_info.height = im->size.height; @@ -1916,8 +2085,9 @@ _xlib_glyphset_cache_destroy_entry (void *abstract_cache, glyphset_cache_entry_t *entry = abstract_entry; _cairo_unscaled_font_destroy (entry->key.unscaled); - XRenderFreeGlyphs (cache->display, entry->glyphset, - &(entry->glyph), 1); + if (entry->glyph) + XRenderFreeGlyphs (cache->display, entry->glyphset, + &(entry->glyph), 1); free (entry); } @@ -1943,8 +2113,10 @@ _lock_xlib_glyphset_caches (void) static void _unlock_xlib_glyphset_caches (glyphset_cache_t *cache) { - _cairo_cache_shrink_to (&cache->base, - CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT); + if (cache) { + _cairo_cache_shrink_to (&cache->base, + CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT); + } CAIRO_MUTEX_UNLOCK(_xlib_glyphset_caches_mutex); } @@ -2102,7 +2274,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font, _render_operator (operator), src->src_picture, self->dst_picture, - cache->a8_pict_format, + mask_format, source_x, source_y, 0, 0, elts, count); @@ -2330,7 +2502,70 @@ _cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font, return CAIRO_STATUS_NO_MEMORY; } +/* Handles clearing the regions that are outside of the temporary + * mask created by XRenderCompositeText[N] but should be affected + * by an unbounded operator like CAIRO_OPERATOR_SOURCE. + */ +static void +_show_glyphs_fixup_unbounded (cairo_xlib_surface_t *self, + cairo_surface_attributes_t *src_attr, + cairo_xlib_surface_t *src, + const cairo_glyph_t *glyphs, + glyphset_cache_entry_t **entries, + int num_glyphs, + int src_x, + int src_y, + int dst_x, + int dst_y, + int width, + int height) +{ + cairo_surface_attributes_t mask_attr; + int x1 = INT_MAX; + int x2 = INT_MIN; + int y1 = INT_MAX; + int y2 = INT_MIN; + int i; + + /* Compute the size of the glyph mask as the bounding box + * of all the glyphs. + */ + for (i = 0; i < num_glyphs; ++i) { + int thisX, thisY; + + if (entries[i] == NULL || !entries[i]->glyph) + continue; + + thisX = (int) floor (glyphs[i].x + 0.5); + thisY = (int) floor (glyphs[i].y + 0.5); + + if (thisX + entries[i]->size.x < x1) + x1 = thisX + entries[i]->size.x; + if (thisX + entries[i]->size.x + entries[i]->size.width > x2) + x2 = thisX + entries[i]->size.x + entries[i]->size.width; + if (thisY + entries[i]->size.y < y1) + y1 = thisY + entries[i]->size.y; + if (thisY + entries[i]->size.y + entries[i]->size.height > y2) + y2 = thisY + entries[i]->size.y + entries[i]->size.height; + } + if (x1 >= x2 || y1 >= y2) + x1 = x2 = y1 = y2 = 0; + + cairo_matrix_init_identity (&mask_attr.matrix); + mask_attr.extend = CAIRO_EXTEND_NONE; + mask_attr.filter = CAIRO_FILTER_NEAREST; + mask_attr.x_offset = 0; + mask_attr.y_offset = 0; + + _cairo_surface_composite_fixup_unbounded (&self->base, + src_attr, src->width, src->height, + &mask_attr, x2 - x1, y2 - y1, + src_x, src_y, + dst_x - x1, dst_y - y1, + dst_x, dst_y, width, height); +} + static cairo_int_status_t _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, @@ -2441,6 +2676,13 @@ _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, glyphs, entries, num_glyphs); } + if (!_cairo_operator_bounded (operator)) + _show_glyphs_fixup_unbounded (self, + &attributes, src, + glyphs, entries, num_glyphs, + source_x, source_y, + dest_x, dest_y, width, height); + UNLOCK: _unlock_xlib_glyphset_caches (cache); @@ -2452,3 +2694,23 @@ _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, return status; } + +static void +_destroy_glyphset_cache_recurse (glyphset_cache_t *cache) +{ + if (cache == NULL) + return; + + _destroy_glyphset_cache_recurse (cache->next); + _cairo_cache_destroy (&cache->base); + free (cache); +} + +void +_cairo_xlib_surface_reset_static_data (void) +{ + _lock_xlib_glyphset_caches (); + _destroy_glyphset_cache_recurse (_xlib_glyphset_caches); + _xlib_glyphset_caches = NULL; + _unlock_xlib_glyphset_caches (NULL); +} diff --git a/src/cairo.c b/src/cairo.c index b4fc5464..4c4b03eb 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -178,14 +178,18 @@ cairo_create (cairo_surface_t *target) * Increases the reference count on @cr by one. This prevents * @cr from being destroyed until a matching call to cairo_destroy() * is made. + * + * Return value: the referenced #cairo_t. **/ -void +cairo_t * cairo_reference (cairo_t *cr) { if (cr->ref_count == (unsigned int)-1) - return; + return cr; cr->ref_count++; + + return cr; } /** @@ -532,6 +536,32 @@ cairo_set_tolerance (cairo_t *cr, double tolerance) } /** + * cairo_set_antialias: + * @cr: a #cairo_t + * @antialias: the new antialiasing mode + * + * Set the antialiasing mode of the rasterizer used for drawing shapes. + * This value is a hint, and a particular backend may or may not support + * a particular value. At the current time, no backend supports + * %CAIRO_ANTIALIAS_SUBPIXEL when drawing shapes. + * + * Note that this option does not affect text rendering, instead see + * cairo_font_options_set_antialias(). + **/ +void +cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias) +{ + if (cr->status) { + _cairo_set_error (cr, cr->status); + return; + } + + cr->status = _cairo_gstate_set_antialias (cr->gstate, antialias); + if (cr->status) + _cairo_set_error (cr, cr->status); +} + +/** * cairo_set_fill_rule: * @cr: a #cairo_t * @fill_rule: a fill rule, specified as a #cairo_fill_rule_t @@ -1401,8 +1431,9 @@ slim_hidden_def(cairo_stroke_preserve); * @cr: a cairo context * * A drawing operator that fills the current path according to the - * current fill rule. After cairo_fill, the current path will be - * cleared from the cairo context. See cairo_set_fill_rule() and + * current fill rule, (each sub-path is implicitly closed before being + * filled). After cairo_fill, the current path will be cleared from + * the cairo context. See cairo_set_fill_rule() and * cairo_fill_preserve(). **/ void @@ -1418,8 +1449,9 @@ cairo_fill (cairo_t *cr) * @cr: a cairo context * * A drawing operator that fills the current path according to the - * current fill rule. Unlike cairo_fill(), cairo_fill_preserve - * preserves the path within the cairo context. + * current fill rule, (each sub-path is implicitly closed before being + * filled). Unlike cairo_fill(), cairo_fill_preserve preserves the + * path within the cairo context. * * See cairo_set_fill_rule() and cairo_fill(). **/ @@ -1645,7 +1677,7 @@ cairo_reset_clip (cairo_t *cr) * for operations such as listing all available fonts on the system, * and it is expected that most applications will need to use a more * comprehensive font handling and text layout library in addition to - * Cairo. + * cairo. **/ void cairo_select_font_face (cairo_t *cr, @@ -1681,16 +1713,13 @@ cairo_get_font_face (cairo_t *cr) if (cr->status) { _cairo_set_error (cr, cr->status); - return NULL; + return (cairo_font_face_t*) &_cairo_font_face_nil; } cr->status = _cairo_gstate_get_font_face (cr->gstate, &font_face); if (cr->status) { _cairo_set_error (cr, cr->status); - /* XXX: When available: - return _cairo_font_face_nil; - */ - return NULL; + return (cairo_font_face_t*) &_cairo_font_face_nil; } return font_face; @@ -2079,6 +2108,20 @@ cairo_get_tolerance (cairo_t *cr) } /** + * cairo_get_antialias: + * @cr: a cairo context + * + * Gets the current shape antialiasing mode, as set by cairo_set_shape_antialias(). + * + * Return value: the current shape antialiasing mode. + **/ +cairo_antialias_t +cairo_get_antialias (cairo_t *cr) +{ + return _cairo_gstate_get_antialias (cr->gstate); +} + +/** * cairo_get_current_point: * @cr: a cairo context * @x: return value for X coordinate of the current point @@ -2257,7 +2300,7 @@ cairo_path_t * cairo_copy_path (cairo_t *cr) { if (cr->status) - return &cairo_path_nil; + return (cairo_path_t*) &_cairo_path_nil; return _cairo_path_data_create (&cr->path, cr->gstate); } @@ -2296,7 +2339,7 @@ cairo_path_t * cairo_copy_path_flat (cairo_t *cr) { if (cr->status) - return &cairo_path_nil; + return (cairo_path_t*) &_cairo_path_nil; else return _cairo_path_data_create_flat (&cr->path, cr->gstate); } diff --git a/src/cairo.h b/src/cairo.h index ba899981..1d871c81 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -38,14 +38,6 @@ #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> CAIRO_BEGIN_DECLS @@ -230,7 +222,7 @@ typedef cairo_status_t (*cairo_read_func_t) (void *closure, cairo_t * cairo_create (cairo_surface_t *target); -void +cairo_t * cairo_reference (cairo_t *cr); void @@ -296,6 +288,29 @@ void cairo_set_tolerance (cairo_t *cr, double tolerance); /** + * cairo_antialias_t: + * @CAIRO_ANTIALIAS_DEFAULT: Use the default antialiasing for + * the subsystem and target device + * @CAIRO_ANTIALIAS_NONE: Use a bilevel alpha mask + * @CAIRO_ANTIALIAS_GRAY: Perform single-color antialiasing (using + * shades of gray for black text on a white background, for example). + * @CAIRO_ANTIALIAS_SUBPIXEL: Perform antialiasing by taking + * advantage of the order of subpixel elements on devices + * such as LCD panels + * + * Specifies the type of antialiasing to do when rendering text or shapes. + **/ +typedef enum _cairo_antialias { + CAIRO_ANTIALIAS_DEFAULT, + CAIRO_ANTIALIAS_NONE, + CAIRO_ANTIALIAS_GRAY, + CAIRO_ANTIALIAS_SUBPIXEL +} cairo_antialias_t; + +void +cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias); + +/** * 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 @@ -668,26 +683,6 @@ typedef enum _cairo_font_weight { } cairo_font_weight_t; /** - * cairo_antialias_t: - * @CAIRO_ANTIALIAS_DEFAULT: Use the default antialiasing for - * the font subsystem and target device - * @CAIRO_ANTIALIAS_NONE: Do no antialiasing of fonts; use bilevel text - * @CAIRO_ANTIALIAS_GRAY: Perform single-color antialiasing (using - * shades of gray for black text on a white background, for example). - * @CAIRO_ANTIALIAS_SUBPIXEL: Perform antialiasing by taking - * advantage of the order of subpixel elements on devices - * such as LCD panels - * - * Specifies the type of antialiasing to do when rendering text. - **/ -typedef enum _cairo_antialias { - CAIRO_ANTIALIAS_DEFAULT, - CAIRO_ANTIALIAS_NONE, - CAIRO_ANTIALIAS_GRAY, - CAIRO_ANTIALIAS_SUBPIXEL -} cairo_antialias_t; - -/** * cairo_subpixel_order_t: * @CAIRO_SUBPIXEL_ORDER_DEFAULT: Use the default subpixel order for * for the target device @@ -871,7 +866,7 @@ cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs); /* Generic identifier for a font style */ -void +cairo_font_face_t * cairo_font_face_reference (cairo_font_face_t *font_face); void @@ -898,7 +893,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, const cairo_matrix_t *ctm, const cairo_font_options_t *options); -void +cairo_scaled_font_t * cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font); void @@ -928,6 +923,9 @@ cairo_get_source (cairo_t *cr); double cairo_get_tolerance (cairo_t *cr); +cairo_antialias_t +cairo_get_antialias (cairo_t *cr); + void cairo_get_current_point (cairo_t *cr, double *x, double *y); @@ -1109,7 +1107,7 @@ cairo_surface_create_similar (cairo_surface_t *other, int width, int height); -void +cairo_surface_t * cairo_surface_reference (cairo_surface_t *surface); void @@ -1149,6 +1147,19 @@ cairo_surface_get_font_options (cairo_surface_t *surface, cairo_font_options_t *options); void +cairo_surface_flush (cairo_surface_t *surface); + +void +cairo_surface_mark_dirty (cairo_surface_t *surface); + +void +cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, + int x, + int y, + int width, + int height); + +void cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, double y_offset); @@ -1236,7 +1247,7 @@ cairo_pattern_t * cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1); -void +cairo_pattern_t * cairo_pattern_reference (cairo_pattern_t *pattern); void diff --git a/src/cairoint.h b/src/cairoint.h index 45747838..2a5f45e3 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -63,6 +63,7 @@ #include <stdio.h> #include "cairo.h" +#include "cairo-debug.h" #include <pixman.h> #if __GNUC__ >= 3 && defined(__ELF__) @@ -188,6 +189,8 @@ typedef cairo_fixed_16_16_t cairo_fixed_t; #define CAIRO_ALPHA_IS_OPAQUE(alpha) ((alpha) >= ((double)0xff00 / (double)0xffff)) +#include "cairo-hash-private.h" + typedef struct _cairo_point { cairo_fixed_t x; cairo_fixed_t y; @@ -239,6 +242,9 @@ typedef enum cairo_direction { } cairo_direction_t; typedef struct _cairo_path_fixed cairo_path_fixed_t; +typedef enum _cairo_clip_mode cairo_clip_mode_t; +typedef struct _cairo_clip_path cairo_clip_path_t; +typedef struct _cairo_clip cairo_clip_t; typedef struct _cairo_edge { cairo_line_t edge; @@ -288,6 +294,13 @@ typedef struct _cairo_pen { typedef struct _cairo_color cairo_color_t; typedef struct _cairo_image_surface cairo_image_surface_t; +cairo_private void +_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle); + +cairo_private void +_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src); + + /* cairo_array.c structures and functions */ typedef struct _cairo_array cairo_array_t; @@ -443,8 +456,6 @@ _cairo_hash_string (const char *c); #define CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT 0x100000 #define CAIRO_XLIB_GLYPH_CACHE_MEMORY_DEFAULT 0x100000 -typedef struct _cairo_unscaled_font cairo_unscaled_font_t; - typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t; typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t; typedef struct _cairo_font_face_backend cairo_font_face_backend_t; @@ -453,9 +464,16 @@ typedef struct _cairo_font_face_backend cairo_font_face_backend_t; * A cairo_unscaled_font_t is just an opaque handle we use in the * glyph cache. */ -struct _cairo_unscaled_font { +typedef struct _cairo_unscaled_font { int ref_count; const cairo_unscaled_font_backend_t *backend; +} cairo_unscaled_font_t; + +struct _cairo_font_options { + cairo_antialias_t antialias; + cairo_subpixel_order_t subpixel_order; + cairo_hint_style_t hint_style; + cairo_hint_metrics_t hint_metrics; }; struct _cairo_scaled_font { @@ -464,7 +482,9 @@ struct _cairo_scaled_font { cairo_matrix_t font_matrix; /* font space => user space */ cairo_matrix_t ctm; /* user space => device space */ cairo_matrix_t scale; /* font space => device space */ + cairo_font_options_t options; cairo_font_face_t *font_face; /* may be NULL */ + const cairo_scaled_font_backend_t *backend; }; @@ -475,13 +495,6 @@ struct _cairo_font_face { const cairo_font_face_backend_t *backend; }; -struct _cairo_font_options { - cairo_antialias_t antialias; - cairo_subpixel_order_t subpixel_order; - cairo_hint_style_t hint_style; - cairo_hint_metrics_t hint_metrics; -}; - /* cairo_font.c is responsible for a global glyph cache: * * - glyph entries: [[[base], cairo_unscaled_font_t, scale, flags, index], @@ -516,6 +529,18 @@ _cairo_unlock_global_image_glyph_cache (void); cairo_private cairo_cache_t * _cairo_get_global_image_glyph_cache (void); +cairo_private void +_cairo_font_reset_static_data (void); + +cairo_private void +_cairo_ft_font_reset_static_data (void); + +cairo_private void +_cairo_xlib_surface_reset_static_data (void); + +cairo_private void +_cairo_xlib_screen_reset_static_data (void); + /* Some glyph cache functions you can reuse. */ cairo_private unsigned long @@ -534,66 +559,88 @@ struct _cairo_unscaled_font_backend { cairo_image_glyph_cache_entry_t *entry); }; +/* cairo_toy_font_face_t - simple family/slant/weight font faces used for + * the built-in font API + */ + +typedef struct _cairo_toy_font_face { + cairo_font_face_t base; + char *family; + cairo_font_slant_t slant; + cairo_font_weight_t weight; +} cairo_toy_font_face_t; + struct _cairo_scaled_font_backend { - cairo_status_t (*create) (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **font); - - void (*destroy) (void *font); + cairo_status_t + (*create_toy) (const cairo_toy_font_face_t *toy_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font); + + void + (*fini) (void *scaled_font); - cairo_status_t (*font_extents) (void *font, - cairo_font_extents_t *extents); + cairo_status_t + (*font_extents) (void *scaled_font, + cairo_font_extents_t *extents); - cairo_status_t (*text_to_glyphs) (void *font, - const char *utf8, - cairo_glyph_t **glyphs, - int *num_glyphs); + cairo_status_t + (*text_to_glyphs) (void *scaled_font, + const char *utf8, + cairo_glyph_t **glyphs, + int *num_glyphs); - cairo_status_t (*glyph_extents) (void *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents); + cairo_status_t + (*glyph_extents) (void *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents); - cairo_status_t (*glyph_bbox) (void *font, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_box_t *bbox); - - cairo_status_t (*show_glyphs) (void *font, - cairo_operator_t operator, - cairo_pattern_t *pattern, - cairo_surface_t *surface, - int source_x, - int source_y, - int dest_x, - int dest_y, - unsigned int width, - unsigned int height, - const cairo_glyph_t *glyphs, - int num_glyphs); + cairo_status_t + (*glyph_bbox) (void *scaled_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox); + + cairo_status_t + (*show_glyphs) (void *scaled_font, + cairo_operator_t operator, + cairo_pattern_t *pattern, + cairo_surface_t *surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + const cairo_glyph_t *glyphs, + int num_glyphs); - cairo_status_t (*glyph_path) (void *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_fixed_t *path); - void (*get_glyph_cache_key) (void *font, - cairo_glyph_cache_key_t *key); + cairo_status_t + (*glyph_path) (void *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_fixed_t *path); + + void + (*get_glyph_cache_key) (void *scaled_font, + cairo_glyph_cache_key_t *key); }; struct _cairo_font_face_backend { /* The destroy() function is allowed to resurrect the font face * by re-referencing. This is needed for the FreeType backend. */ - void (*destroy) (void *font_face); - cairo_status_t (*create_font) (void *font_face, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_font_options_t *options, - cairo_scaled_font_t **scaled_font); + void + (*destroy) (void *font_face); + + cairo_status_t + (*scaled_font_create) (void *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font); }; /* concrete font backends */ @@ -681,6 +728,7 @@ typedef struct _cairo_surface_backend { (*composite_trapezoids) (cairo_operator_t operator, cairo_pattern_t *pattern, void *dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -731,7 +779,8 @@ typedef struct _cairo_surface_backend { (*intersect_clip_path) (void *dst, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, - double tolerance); + double tolerance, + cairo_antialias_t antialias); /* Get the extents of the current surface. For many surface types * this will be as simple as { x=0, y=0, width=surface->width, @@ -777,6 +826,17 @@ typedef struct _cairo_surface_backend { void (*get_font_options) (void *surface, cairo_font_options_t *options); + + cairo_status_t + (*flush) (void *surface); + + cairo_status_t + (*mark_dirty_rectangle) (void *surface, + int x, + int y, + int width, + int height); + } cairo_surface_backend_t; typedef struct _cairo_format_masks { @@ -787,12 +847,6 @@ typedef struct _cairo_format_masks { unsigned long blue_mask; } cairo_format_masks_t; -typedef enum _cairo_clip_mode { - CAIRO_CLIP_MODE_PATH, - CAIRO_CLIP_MODE_REGION, - CAIRO_CLIP_MODE_MASK -} cairo_clip_mode_t; - struct _cairo_surface { const cairo_surface_backend_t *backend; @@ -827,7 +881,9 @@ struct _cairo_image_surface { /* libic-specific fields */ cairo_format_t format; unsigned char *data; - int owns_data; + cairo_bool_t owns_data; + cairo_bool_t has_clip; + int width; int height; @@ -1260,6 +1316,8 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, int num_glyphs, cairo_path_fixed_t *path); +cairo_bool_t +_cairo_operator_bounded (cairo_operator_t operator); /* cairo_color.c */ cairo_private const cairo_color_t * @@ -1312,26 +1370,27 @@ _cairo_font_face_init (cairo_font_face_t *font_face, const cairo_font_face_backend_t *backend); cairo_private cairo_font_face_t * -_cairo_simple_font_face_create (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight); - -cairo_private void -_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, - const cairo_matrix_t *font_matrix, - const cairo_matrix_t *ctm, - const cairo_scaled_font_backend_t *backend); +_cairo_toy_font_face_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight); cairo_private void _cairo_unscaled_font_init (cairo_unscaled_font_t *font, const cairo_unscaled_font_backend_t *backend); -cairo_private void +cairo_private cairo_unscaled_font_t * _cairo_unscaled_font_reference (cairo_unscaled_font_t *font); cairo_private void _cairo_unscaled_font_destroy (cairo_unscaled_font_t *font); +cairo_private void +_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + const cairo_scaled_font_backend_t *backend); + cairo_private cairo_status_t _cairo_scaled_font_font_extents (cairo_scaled_font_t *scaled_font, cairo_font_extents_t *extents); @@ -1472,7 +1531,8 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path, /* cairo_path_fill.c */ cairo_private cairo_status_t _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, - cairo_gstate_t *gstate, + cairo_fill_rule_t fill_rule, + double tolerance, cairo_traps_t *traps); /* cairo_path_stroke.c */ @@ -1549,6 +1609,7 @@ cairo_private cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, cairo_surface_t *dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -1558,6 +1619,14 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, cairo_trapezoid_t *traps, int ntraps); +cairo_status_t +_cairo_surface_clip_and_composite_trapezoids (cairo_pattern_t *src, + cairo_operator_t operator, + cairo_surface_t *dst, + cairo_traps_t *traps, + cairo_clip_t *clip, + cairo_antialias_t antialias); + cairo_private cairo_status_t _cairo_surface_copy_page (cairo_surface_t *surface); @@ -1611,14 +1680,11 @@ cairo_private cairo_int_status_t _cairo_surface_intersect_clip_path (cairo_surface_t *surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, - double tolerance); - -typedef struct _cairo_clip_path cairo_clip_path_t; + double tolerance, + cairo_antialias_t antialias); cairo_private cairo_status_t -_cairo_surface_set_clip_path (cairo_surface_t *surface, - cairo_clip_path_t *clip_path, - unsigned int serial); +_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip); cairo_private cairo_status_t _cairo_surface_get_extents (cairo_surface_t *surface, @@ -1638,6 +1704,23 @@ _cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font, const cairo_glyph_t *glyphs, int num_glyphs); +void +_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, + cairo_surface_attributes_t *src_attr, + int src_width, + int src_height, + cairo_surface_attributes_t *mask_attr, + int mask_width, + int mask_height, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height); + /* cairo_image_surface.c */ cairo_private cairo_format_t @@ -1773,6 +1856,9 @@ _cairo_traps_init_box (cairo_traps_t *traps, cairo_private void _cairo_traps_fini (cairo_traps_t *traps); +cairo_private void +_cairo_traps_translate (cairo_traps_t *traps, int x, int y); + cairo_private cairo_status_t _cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3]); @@ -1873,6 +1959,13 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src, cairo_surface_attributes_t *src_attributes, cairo_surface_attributes_t *mask_attributes); +cairo_private cairo_status_t +_cairo_gstate_set_antialias (cairo_gstate_t *gstate, + cairo_antialias_t antialias); + +cairo_private cairo_antialias_t +_cairo_gstate_get_antialias (cairo_gstate_t *gstate); + /* cairo_unicode.c */ diff --git a/test/.cvsignore b/test/.cvsignore index 1d037fa0..c1895986 100644 --- a/test/.cvsignore +++ b/test/.cvsignore @@ -2,7 +2,9 @@ .libs Makefile Makefile.in +a8-mask clip-nesting +clip-operator clip-twice composite-integer-translate-source composite-integer-translate-over @@ -20,6 +22,8 @@ leaky-polygon line-width linear-gradient mask +mask-ctm +mask-surface-ctm move-to-show-surface paint paint-with-alpha @@ -49,6 +53,7 @@ text-rotate transforms translate-show-surface trap-clip +unbounded-operator user-data xlib-surface *-image-out.png diff --git a/test/Makefile.am b/test/Makefile.am index 649c4012..e630b66b 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,8 @@ # All test cases go here TESTS = \ +a8-mask \ clip-nesting \ +clip-operator \ clip-twice \ composite-integer-translate-source \ composite-integer-translate-over \ @@ -16,6 +18,8 @@ leaky-polygon \ line-width \ linear-gradient \ mask \ +mask-ctm \ +mask-surface-ctm \ move-to-show-surface \ paint \ paint-with-alpha \ @@ -38,6 +42,8 @@ text-rotate \ transforms \ translate-show-surface \ trap-clip \ +unantialiased-shapes \ +unbounded-operator \ user-data \ rel-path @@ -57,7 +63,9 @@ endif # 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 = \ +a8-mask-ref.png \ clip-nesting-ref.png \ +clip-operator-ref.png \ clip-twice-ref.png \ composite-integer-translate-source-ref.png \ composite-integer-translate-over-ref.png \ @@ -72,6 +80,8 @@ leaky-polygon-ref.png \ line-width-ref.png \ linear-gradient-ref.png \ mask-ref.png \ +mask-ctm-ref.png \ +mask-surface-ctm-ref.png \ move-to-show-surface-ref.png \ paint-ref.png \ paint-with-alpha-ref.png \ @@ -90,6 +100,8 @@ text-antialias-none-ref.png \ transforms-ref.png \ translate-show-surface-ref.png \ trap-clip-ref.png \ +unantialiased-shapes-ref.png \ +unbounded-operator-ref.png \ rel-path-ref.png # Any test for which the code committed to CVS is expected to fail @@ -106,10 +118,10 @@ rel-path-ref.png # Also, any test listed here should call cairo_test_expect_failure and # provide an explanation for the expected failure. XFAIL_TESTS = \ +a8-mask \ filter-nearest-offset \ pixman-rotate \ self-intersecting \ -source-surface-scale-paint \ text-antialias-subpixel \ text-rotate @@ -145,7 +157,9 @@ LDADDS = libcairotest.la $(top_builddir)/src/libcairo.la # ARGH! I have to repeat the list of tests a third time. Maybe it's # time to break down and auto-generate the Makefile.am or something # from autogen.sh. My, but this is painful... +a8_mask_LDADD = $(LDADDS) clip_nesting_LDADD = $(LDADDS) +clip_operator_LDADD = $(LDADDS) clip_twice_LDADD = $(LDADDS) composite_integer_translate_source_LDADD = $(LDADDS) composite_integer_translate_over_LDADD = $(LDADDS) @@ -161,6 +175,8 @@ leaky_polygon_LDADD = $(LDADDS) line_width_LDADD = $(LDADDS) linear_gradient_LDADD = $(LDADDS) mask_LDADD = $(LDADDS) +mask_ctm_LDADD = $(LDADDS) +mask_surface_ctm_LDADD = $(LDADDS) move_to_show_surface_LDADD = $(LDADDS) paint_LDADD = $(LDADDS) paint_with_alpha_LDADD = $(LDADDS) @@ -186,6 +202,8 @@ text_rotate_LDADD = $(LDADDS) transforms_LDADD = $(LDADDS) translate_show_surface_LDADD = $(LDADDS) trap_clip_LDADD = $(LDADDS) +unantialiased_shapes_LDADD = $(LDADDS) +unbounded_operator_LDADD = $(LDADDS) user_data_LDADD = $(LDADDS) rel_path_LDADD = $(LDADDS) xlib_surface_LDADD = $(LDADDS) diff --git a/test/a8-mask-ref.png b/test/a8-mask-ref.png Binary files differnew file mode 100644 index 00000000..38556156 --- /dev/null +++ b/test/a8-mask-ref.png diff --git a/test/a8-mask.c b/test/a8-mask.c new file mode 100644 index 00000000..e547ecce --- /dev/null +++ b/test/a8-mask.c @@ -0,0 +1,72 @@ +/* + * Copyright © Jeff Muizelaar + * + * 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. + * + * JEFF MUIZELAAR 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: Jeff Muizelaar <jeff@infidigm.net> + */ + +#include "cairo-test.h" + +cairo_test_t test = { + "a8-mask", + "test masks of CAIRO_FORMAT_A8", + 8, 8 +}; + +static unsigned char mask[] = { + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0 +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_pattern_t *pattern; + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + surface = cairo_image_surface_create_for_data (mask, CAIRO_FORMAT_A8, + 7, 8, 7); + pattern = cairo_pattern_create_for_surface (surface); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_mask (cr, pattern); + + cairo_pattern_destroy (pattern); + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + return cairo_test_expect_failure (&test, draw, + "image backend fails because libpixman only handles (stride % sizeof(pixman_bits) == 0)"); +} diff --git a/test/buffer-diff.c b/test/buffer-diff.c index e5ba513a..78284efc 100644 --- a/test/buffer-diff.c +++ b/test/buffer-diff.c @@ -23,10 +23,17 @@ * * Author: Richard D. Worth <richard@theworths.org> */ +#if HAVE_CONFIG_H +#include "config.h" +#endif + #include <stdio.h> +#ifdef HAVE_UNISTD_H #include <unistd.h> +#endif #include <errno.h> #include <string.h> +#include <pixman.h> #include "cairo-test.h" @@ -45,18 +52,27 @@ xunlink (const char *pathname) } } -int -buffer_diff (unsigned char *buf_a, - unsigned char *buf_b, - unsigned char *buf_diff, - int width, - int height, - int stride) + +/* This function should be rewritten to compare all formats supported by + * cairo_format_t instead of taking a mask as a parameter. + */ +static int +buffer_diff_core (unsigned char *_buf_a, + unsigned char *_buf_b, + unsigned char *_buf_diff, + int width, + int height, + int stride, + pixman_bits_t mask) { int x, y; - unsigned char *row_a, *row_b, *row; + pixman_bits_t *row_a, *row_b, *row; int pixels_changed = 0; + pixman_bits_t *buf_a = (pixman_bits_t*)_buf_a; + pixman_bits_t *buf_b = (pixman_bits_t*)_buf_b; + pixman_bits_t *buf_diff = (pixman_bits_t*)_buf_diff; + stride /= sizeof(pixman_bits_t); for (y = 0; y < height; y++) { row_a = buf_a + y * stride; @@ -64,33 +80,54 @@ buffer_diff (unsigned char *buf_a, row = buf_diff + y * stride; for (x = 0; x < width; x++) { - int channel; - unsigned char value_a, value_b; - int pixel_differs = 0; - for (channel = 0; channel < 4; channel++) - { - double diff; - value_a = row_a[x * 4 + channel]; - value_b = row_b[x * 4 + channel]; - if (value_a != value_b) - pixel_differs = 1; - diff = value_a - value_b; - row[x * 4 + channel] = 128 + diff / 3.0; - } - if (pixel_differs) { + /* check if the pixels are the same */ + if ((row_a[x] & mask) != (row_b[x] & mask)) { + int channel; + pixman_bits_t diff_pixel = 0; + + /* calculate a difference value for all 4 channels */ + for (channel = 0; channel < 4; channel++) { + unsigned char value_a = (row_a[x] >> (channel*8)); + unsigned char value_b = (row_b[x] >> (channel*8)); + double diff; + diff = value_a - value_b; + diff_pixel |= (unsigned char)(128 + diff / 3.0) << (channel*8); + } + pixels_changed++; + row[x] = diff_pixel; } else { - row[x*4+0] = 0; - row[x*4+1] = 0; - row[x*4+2] = 0; + row[x] = 0; } - row[x * 4 + 3] = 0xff; /* Set ALPHA to 100% (opaque) */ + row[x] |= 0xff000000; /* Set ALPHA to 100% (opaque) */ } } return pixels_changed; } +int +buffer_diff (unsigned char *buf_a, + unsigned char *buf_b, + unsigned char *buf_diff, + int width, + int height, + int stride) +{ + return buffer_diff_core(buf_a, buf_b, buf_diff, width, height, stride, 0xffffffff); +} + +int +buffer_diff_noalpha (unsigned char *buf_a, + unsigned char *buf_b, + unsigned char *buf_diff, + int width, + int height, + int stride) +{ + return buffer_diff_core(buf_a, buf_b, buf_diff, width, height, stride, 0x00ffffff); +} + /* Image comparison code courtesy of Richard Worth <richard@theworths.org> * Returns number of pixels changed, (or -1 on error). * Also saves a "diff" image intended to visually show where the diff --git a/test/buffer-diff.h b/test/buffer-diff.h index a02834f3..2734713a 100644 --- a/test/buffer-diff.h +++ b/test/buffer-diff.h @@ -26,7 +26,7 @@ #ifndef BUFFER_DIFF_H #define BUFFER_DIFF_H -/* Returns number of pixels changed, (or -1 on error). +/* Returns number of pixels changed. * Also fills in a "diff" buffer intended to visually show where the * images differ. */ @@ -38,6 +38,18 @@ buffer_diff (unsigned char *buf_a, int height, int stride); +/* Returns number of pixels changed ignoring the alpha channel. + * Also fills in a "diff" buffer intended to visually show where the + * images differ. + */ +int +buffer_diff_noalpha (unsigned char *buf_a, + unsigned char *buf_b, + unsigned char *buf_diff, + int width, + int height, + int stride); + /* Returns number of pixels changed, (or -1 on error). * Also saves a "diff" image intended to visually show where the * images differ. diff --git a/test/cairo-test.c b/test/cairo-test.c index 456d7d85..6759c849 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -1,5 +1,5 @@ /* - * Copyright 2004 Red Hat, Inc. + * Copyright © 2004 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without @@ -23,12 +23,19 @@ * Author: Carl D. Worth <cworth@cworth.org> */ +#if HAVE_CONFIG_H +#include "config.h" +#endif + #include <stdio.h> #include <stdlib.h> #include <stdarg.h> +#ifdef HAVE_UNISTD_H #include <unistd.h> +#endif #include <errno.h> #include <string.h> +#include <fontconfig/fontconfig.h> #include "cairo-test.h" @@ -37,6 +44,10 @@ #include "write-png.h" #include "xmalloc.h" +#ifdef _MSC_VER +#define vsnprintf _vsnprintf +#endif + #define CAIRO_TEST_LOG_SUFFIX ".log" #define CAIRO_TEST_PNG_SUFFIX "-out.png" #define CAIRO_TEST_REF_SUFFIX "-ref.png" @@ -469,6 +480,9 @@ cairo_test_for_target (cairo_test_t *test, UNWIND_CAIRO: cairo_destroy (cr); cairo_surface_destroy (surface); + + cairo_debug_reset_static_data (); + target->cleanup_target (target->closure); UNWIND_STRINGS: @@ -557,6 +571,10 @@ cairo_test_expecting (cairo_test_t *test, cairo_test_draw_function_t draw, fclose (cairo_test_log_file); +#if HAVE_FCFINI + FcFini (); +#endif + return ret; } diff --git a/test/cairo-test.h b/test/cairo-test.h index beabc6a5..d35faab8 100644 --- a/test/cairo-test.h +++ b/test/cairo-test.h @@ -28,6 +28,7 @@ #include <math.h> #include <cairo.h> +#include <cairo-debug.h> typedef enum cairo_test_status { CAIRO_TEST_SUCCESS = 0, diff --git a/test/clip-operator-ref.png b/test/clip-operator-ref.png Binary files differnew file mode 100644 index 00000000..551d13f7 --- /dev/null +++ b/test/clip-operator-ref.png diff --git a/test/clip-operator.c b/test/clip-operator.c new file mode 100644 index 00000000..6cc5216c --- /dev/null +++ b/test/clip-operator.c @@ -0,0 +1,205 @@ +/* + * 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" +#include <stdio.h> + +#define WIDTH 64 +#define HEIGHT 64 +#define PAD 10 + +const char png_filename[] = "romedalen.png"; + +static void +draw_mask (cairo_t *cr, int x, int y) +{ + cairo_surface_t *mask_surface; + cairo_t *cr2; + + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + mask_surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask_surface); + + cairo_save (cr2); + cairo_set_source_rgba (cr2, 0, 0, 0, 0); /* transparent */ + cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr2); + cairo_restore (cr2); + + cairo_set_source_rgb (cr2, 1, 1, 1); /* white */ + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.45 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_destroy (cr2); + + cairo_mask_surface (cr, mask_surface, x, y); + + cairo_surface_destroy (mask_surface); +} + +static void +draw_glyphs (cairo_t *cr, int x, int y) +{ + cairo_text_extents_t extents; + + cairo_set_font_size (cr, 0.8 * HEIGHT); + + cairo_text_extents (cr, "FG", &extents); + cairo_move_to (cr, + x + (WIDTH - extents.width) / 2 - extents.x_bearing, + y + (HEIGHT - extents.height) / 2 - extents.y_bearing); + cairo_show_text (cr, "FG"); +} + +static void +draw_polygon (cairo_t *cr, int x, int y) +{ + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + 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 +draw_rects (cairo_t *cr, int x, int y) +{ + double block_width = (int)(0.33 * WIDTH + 0.5); + double block_height = (int)(0.33 * HEIGHT + 0.5); + int i, j; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if ((i + j) % 2 == 0) + cairo_rectangle (cr, + x + block_width * i, y + block_height * j, + block_width, block_height); + + cairo_fill (cr); +} + +static void (*draw_funcs[])(cairo_t *cr, int x, int y) = { + draw_mask, + draw_glyphs, + draw_polygon, + draw_rects +}; + +#define N_OPERATORS (1 + CAIRO_OPERATOR_SATURATE - CAIRO_OPERATOR_CLEAR) + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) +#define IMAGE_WIDTH (N_OPERATORS * (WIDTH + PAD) + PAD) +#define IMAGE_HEIGHT (ARRAY_SIZE (draw_funcs) * (HEIGHT + PAD) + PAD) + +static cairo_test_t test = { + "clip-operator", + "Surface clipping with different operators", + IMAGE_WIDTH, IMAGE_HEIGHT +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int j, x, y; + cairo_operator_t op; + cairo_font_options_t *font_options; + cairo_pattern_t *pattern; + + cairo_select_font_face (cr, "Bitstream Vera Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, 0.9 * HEIGHT); + + font_options = cairo_font_options_create (); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY); + + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + for (j = 0; j < ARRAY_SIZE (draw_funcs); j++) { + for (op = CAIRO_OPERATOR_CLEAR; op <= CAIRO_OPERATOR_SATURATE; op++) { + x = op * (WIDTH + PAD) + PAD; + y = j * (HEIGHT + PAD) + PAD; + + cairo_save (cr); + + pattern = cairo_pattern_create_linear (x + WIDTH, y, + x, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0.2, + 0.0, 0.0, 1.0, 1.0); /* Solid blue */ + cairo_pattern_add_color_stop_rgba (pattern, 0.8, + 0.0, 0.0, 1.0, 0.0); /* Transparent blue */ + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + cairo_rectangle (cr, x, y, WIDTH, HEIGHT); + cairo_fill (cr); + + cairo_set_operator (cr, op); + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + + cairo_move_to (cr, x, y); + cairo_line_to (cr, x + WIDTH, y); + cairo_line_to (cr, x, y + HEIGHT); + cairo_clip (cr); + + draw_funcs[j] (cr, x, y); + if (cairo_status (cr)) + cairo_test_log ("%d %d HERE!\n", op, j); + + cairo_restore (cr); + } + } + + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) + cairo_test_log ("%d %d .HERE!\n", op, j); + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/composite-integer-translate-over-repeat.c b/test/composite-integer-translate-over-repeat.c index ed55f63a..61a0ea71 100644 --- a/test/composite-integer-translate-over-repeat.c +++ b/test/composite-integer-translate-over-repeat.c @@ -44,7 +44,7 @@ draw (cairo_t *cr, int width, int height) cairo_fill (cr); cairo_translate (cr, OFFSET, OFFSET); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_source (cr, pat); cairo_rectangle (cr, 0, 0, SIZE - OFFSET, SIZE - OFFSET); cairo_fill (cr); diff --git a/test/mask-ctm-ref.png b/test/mask-ctm-ref.png Binary files differnew file mode 100644 index 00000000..88a0402c --- /dev/null +++ b/test/mask-ctm-ref.png diff --git a/test/mask-ctm.c b/test/mask-ctm.c new file mode 100644 index 00000000..1fd48285 --- /dev/null +++ b/test/mask-ctm.c @@ -0,0 +1,82 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth <cworth@cworth.org> + */ + +#include "cairo-test.h" + +cairo_test_t test = { + "mask-ctm", + "Test that cairo_mask is affected properly by the CTM", + 10, 10 +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *mask_surface; + cairo_pattern_t *mask; + unsigned long data[] = { + 0x80000000, 0x80000000, + 0x80000000, 0x80000000, + }; + cairo_matrix_t matrix; + + mask_surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_ARGB32, 2, 2, 8); + mask = cairo_pattern_create_for_surface (mask_surface); + cairo_surface_destroy (mask_surface); + + cairo_set_source_rgb (cr, 1.0, 0, 0); + + /* We can translate with the CTM, with the pattern matrix, or with + * both. */ + + /* 1. CTM alone. */ + cairo_save (cr); + { + cairo_translate (cr, 2, 2); + cairo_mask (cr, mask); + } + cairo_restore (cr); + + /* 2. Pattern matrix alone. */ + cairo_matrix_init_translate (&matrix, -4, -4); + cairo_pattern_set_matrix (mask, &matrix); + + cairo_mask (cr, mask); + + /* 3. CTM + pattern matrix */ + cairo_translate (cr, 2, 2); + cairo_mask (cr, mask); + + cairo_pattern_destroy (mask); + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/mask-surface-ctm-ref.png b/test/mask-surface-ctm-ref.png Binary files differnew file mode 100644 index 00000000..744b1dd3 --- /dev/null +++ b/test/mask-surface-ctm-ref.png diff --git a/test/mask-surface-ctm.c b/test/mask-surface-ctm.c new file mode 100644 index 00000000..6eb2bf26 --- /dev/null +++ b/test/mask-surface-ctm.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth <cworth@cworth.org> + */ + +#include "cairo-test.h" + +cairo_test_t test = { + "mask-surface-ctm", + "Test that cairo_mask_surface is affected properly by the CTM", + 10, 10 +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *mask; + unsigned long data[] = { + 0x80000000, 0x80000000, + 0x80000000, 0x80000000, + }; + + mask = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_ARGB32, 2, 2, 8); + + cairo_set_source_rgb (cr, 1.0, 0, 0); + + /* We can translate with the CTM, with the mask_surface offset, or + * with both. */ + + /* 1. CTM alone. */ + cairo_save (cr); + { + cairo_translate (cr, 2, 2); + cairo_mask_surface (cr, mask, 0, 0); + } + cairo_restore (cr); + + /* 2. Offset alone. */ + cairo_mask_surface (cr, mask, 4, 4); + + /* 3. CTM + offset */ + cairo_translate (cr, 2, 2); + cairo_mask_surface (cr, mask, 4, 4); + + cairo_surface_destroy (mask); + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/read-png.c b/test/read-png.c index 96259dfe..ff311c28 100644 --- a/test/read-png.c +++ b/test/read-png.c @@ -35,6 +35,18 @@ # include <inttypes.h> #elif HAVE_SYS_INT_TYPES_H # include <sys/int_types.h> +#elif defined(_MSC_VER) + typedef __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +# ifndef HAVE_UINT64_T +# define HAVE_UINT64_T 1 +# endif #else #error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) #endif @@ -79,7 +91,7 @@ read_png_argb32 (const char *filename, { int i; FILE *file; - static const int PNG_SIG_SIZE = 8; +#define PNG_SIG_SIZE 8 unsigned char png_sig[PNG_SIG_SIZE]; int sig_bytes; png_struct *png; diff --git a/test/source-surface-scale-paint-ref.png b/test/source-surface-scale-paint-ref.png Binary files differindex ec3c059f..a81f93d9 100644 --- a/test/source-surface-scale-paint-ref.png +++ b/test/source-surface-scale-paint-ref.png diff --git a/test/source-surface-scale-paint.c b/test/source-surface-scale-paint.c index 9862ba59..1af972f2 100644 --- a/test/source-surface-scale-paint.c +++ b/test/source-surface-scale-paint.c @@ -28,7 +28,7 @@ cairo_test_t test = { "source-surface-scale-paint", "Test call sequence: cairo_set_source_surface; cairo_scale; cairo_paint", - 12, 12 + 8, 8 }; static cairo_test_status_t @@ -59,6 +59,5 @@ draw (cairo_t *cr, int width, int height) int main (void) { - return cairo_test_expect_failure (&test, draw, - "cairo_set_source needs user space locking semantics"); + return cairo_test (&test, draw); } diff --git a/test/surface-finish-twice.c b/test/surface-finish-twice.c index ce4f0659..ad6c0e94 100644 --- a/test/surface-finish-twice.c +++ b/test/surface-finish-twice.c @@ -52,7 +52,6 @@ static cairo_test_status_t draw (cairo_t *cr, int width, int height) { cairo_surface_t *surface; - cairo_status_t status; surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); diff --git a/test/text-cache-crash.c b/test/text-cache-crash.c index 547e2a34..08e85739 100644 --- a/test/text-cache-crash.c +++ b/test/text-cache-crash.c @@ -118,20 +118,6 @@ main (void) ret = cairo_test (&test, draw); - /* It's convenient to be able to free all memory (including - * statically allocated memory). This makes it quite easy to use - * tools such as valgrind to verify that there are no memory leaks - * whatsoever. - * - * But I'm not sure what would be a sensible cairo API function - * for this. The cairo_destroy_caches call below is just something - * I made as a local modification to cairo. - */ - /* - cairo_destroy_caches (); - FcFini (); - */ - return ret; } diff --git a/test/unantialiased-shapes-ref.png b/test/unantialiased-shapes-ref.png Binary files differnew file mode 100644 index 00000000..b9485922 --- /dev/null +++ b/test/unantialiased-shapes-ref.png diff --git a/test/unantialiased-shapes.c b/test/unantialiased-shapes.c new file mode 100644 index 00000000..eaadf417 --- /dev/null +++ b/test/unantialiased-shapes.c @@ -0,0 +1,103 @@ +/* + * Copyright © 2005 Billy Biggs + * + * 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 + * Billy Biggs not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Billy Biggs makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * BILLY BIGGS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL BILLY BIGGS 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: Billy Biggs <vektor@dumbterm.net> + */ + +#include "cairo-test.h" + +cairo_test_t test = { + "unantialiased-shapes", + "Test shape drawing without antialiasing", + 320, 240 +}; + +/* The star shape from the SVG test suite, from the fill rule test */ +static void +big_star_path (cairo_t *cr) +{ + cairo_move_to (cr, 40, 0); + cairo_rel_line_to (cr, 25, 80); + cairo_rel_line_to (cr, -65, -50); + cairo_rel_line_to (cr, 80, 0); + cairo_rel_line_to (cr, -65, 50); + cairo_close_path (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + /* Try a circle */ + cairo_arc (cr, 40, 40, 20, 0, 2 * M_PI); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + + /* Try using clipping to draw a circle */ + cairo_arc (cr, 100, 40, 20, 0, 2 * M_PI); + cairo_clip (cr); + cairo_rectangle (cr, 80, 20, 40, 40); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill (cr); + + /* Reset the clipping */ + cairo_reset_clip (cr); + + /* Draw a bunch of lines */ + cairo_set_line_width (cr, 1.0); + cairo_set_source_rgb (cr, 0, 1, 0); + for (i = 0; i < 10; i++) { + cairo_move_to (cr, 10, 70 + (i * 4)); + cairo_line_to (cr, 120, 70 + (i * 18)); + cairo_stroke (cr); + } + + /* Try filling a poly */ + cairo_translate (cr, 160, 120); + cairo_set_source_rgb (cr, 1, 1, 0); + big_star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill (cr); + cairo_translate (cr, -160, -120); + + /* How about some curves? */ + cairo_set_source_rgb (cr, 1, 0, 1); + for (i = 0; i < 10; i++) { + cairo_move_to (cr, 150, 50 + (i * 5)); + cairo_curve_to (cr, 250, 50, 200, (i * 10), 300, 50 + (i * 10)); + cairo_stroke (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/unbounded-operator-ref.png b/test/unbounded-operator-ref.png Binary files differnew file mode 100644 index 00000000..7e3b3a07 --- /dev/null +++ b/test/unbounded-operator-ref.png diff --git a/test/unbounded-operator.c b/test/unbounded-operator.c new file mode 100644 index 00000000..45535b97 --- /dev/null +++ b/test/unbounded-operator.c @@ -0,0 +1,201 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Kristian Høgsberg <krh@redhat.com> + * Owen Taylor <otaylor@redhat.com> + */ + +#include <math.h> +#include "cairo-test.h" +#include <stdio.h> + +#define WIDTH 64 +#define HEIGHT 64 +#define PAD 10 + +static void +draw_mask (cairo_t *cr, int x, int y) +{ + cairo_surface_t *mask_surface; + cairo_t *cr2; + + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + mask_surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask_surface); + + cairo_save (cr2); + cairo_set_source_rgba (cr2, 0, 0, 0, 0); /* transparent */ + cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr2); + cairo_restore (cr2); + + cairo_set_source_rgb (cr2, 1, 1, 1); /* white */ + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.45 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_destroy (cr2); + + cairo_mask_surface (cr, mask_surface, x, y); + + cairo_surface_destroy (mask_surface); +} + +static void +draw_glyphs (cairo_t *cr, int x, int y) +{ + cairo_text_extents_t extents; + + cairo_set_font_size (cr, 0.8 * HEIGHT); + + cairo_text_extents (cr, "FG", &extents); + cairo_move_to (cr, + x + (WIDTH - extents.width) / 2 - extents.x_bearing, + y + (HEIGHT - extents.height) / 2 - extents.y_bearing); + cairo_show_text (cr, "FG"); +} + +static void +draw_polygon (cairo_t *cr, int x, int y) +{ + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + 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 +draw_rects (cairo_t *cr, int x, int y) +{ + double block_width = (int)(0.33 * WIDTH + 0.5); + double block_height = (int)(0.33 * HEIGHT + 0.5); + int i, j; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if ((i + j) % 2 == 0) + cairo_rectangle (cr, + x + block_width * i, y + block_height * j, + block_width, block_height); + + cairo_fill (cr); +} + +static void (*draw_funcs[])(cairo_t *cr, int x, int y) = { + draw_mask, + draw_glyphs, + draw_polygon, + draw_rects +}; + +static cairo_operator_t operators[] = { + CAIRO_OPERATOR_CLEAR, CAIRO_OPERATOR_SOURCE, CAIRO_OPERATOR_IN, + CAIRO_OPERATOR_OUT, CAIRO_OPERATOR_DEST_IN, CAIRO_OPERATOR_DEST_ATOP +}; + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) +#define IMAGE_WIDTH (ARRAY_SIZE (operators) * (WIDTH + PAD) + PAD) +#define IMAGE_HEIGHT (ARRAY_SIZE (draw_funcs) * (HEIGHT + PAD) + PAD) + +static cairo_test_t test = { + "unbounded-operator", + "Operators with an effect for transparent source/mask", + IMAGE_WIDTH, IMAGE_HEIGHT +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i, j, x, y; + cairo_font_options_t *font_options; + cairo_pattern_t *pattern; + + cairo_select_font_face (cr, "Bitstream Vera Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + font_options = cairo_font_options_create (); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY); + + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + for (j = 0; j < ARRAY_SIZE (draw_funcs); j++) { + for (i = 0; i < ARRAY_SIZE (operators); i++) { + x = i * (WIDTH + PAD) + PAD; + y = j * (HEIGHT + PAD) + PAD; + + cairo_save (cr); + + pattern = cairo_pattern_create_linear (x + WIDTH, y, + x, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0.2, + 0.0, 0.0, 1.0, 1.0); /* Solid blue */ + cairo_pattern_add_color_stop_rgba (pattern, 0.8, + 0.0, 0.0, 1.0, 0.0); /* Transparent blue */ + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + cairo_rectangle (cr, x, y, WIDTH, HEIGHT); + cairo_fill_preserve (cr); + cairo_clip (cr); + + cairo_set_operator (cr, operators[i]); + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + + draw_funcs[j] (cr, x, y); + if (cairo_status (cr)) + cairo_test_log ("%d %d HERE!\n", i, j); + + cairo_restore (cr); + } + } + + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) + cairo_test_log ("%d %d .HERE!\n", i, j); + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/xlib-surface.c b/test/xlib-surface.c index 2921eb85..0df5514f 100644 --- a/test/xlib-surface.c +++ b/test/xlib-surface.c @@ -155,19 +155,19 @@ do_test (Display *dpy, if (offscreen) { size_t offset = 4 * (SIZE * OFFSCREEN_OFFSET + OFFSCREEN_OFFSET); - result = !buffer_diff (reference_data + offset, - test_data + offset, - diff_data + offset, - SIZE - OFFSCREEN_OFFSET, - SIZE - OFFSCREEN_OFFSET, - 4 * SIZE); + result = !buffer_diff_noalpha (reference_data + offset, + test_data + offset, + diff_data + offset, + SIZE - OFFSCREEN_OFFSET, + SIZE - OFFSCREEN_OFFSET, + 4 * SIZE); } else { - result = !buffer_diff (reference_data, - test_data, - diff_data, - SIZE, - SIZE, - 4 * SIZE); + result = !buffer_diff_noalpha (reference_data, + test_data, + diff_data, + SIZE, + SIZE, + 4 * SIZE); } fprintf (log_file, "xlib-surface: %s, %s, %s%s: %s\n", @@ -267,6 +267,8 @@ main (void) XCloseDisplay (dpy); + cairo_debug_reset_static_data (); + fclose (log_file); return result; |