diff options
73 files changed, 9706 insertions, 2243 deletions
@@ -1 +1,18 @@ -Carl D. Worth <cworth@isi.edu> +Olivier Andrieu <oliv__a@users.sourceforge.net> PNG backend +Dave Beckett <dave.beckett@bristol.ac.uk> Track rename of libpixman, build fixes +Andrew Chant <andrew.chant@utoronto.ca> Adding const where needed +John Ellson <ellson@research.att.com> First font/glyph extents functions +Richard Henderson <rth@twiddle.net> "slim" macros for better shared libraries +James Henstridge <james@daa.com.au> Build fixes related to freetype +Graydon Hoare <graydon@redhat.com> Support for non-render X server, first real text support +Thomas Hunger <info@teh-web.de> Initial version of cairo_in_stroke/fill +Jordi Mas <jordi@ximian.com> Bug fix for cairo_show_text +Keith Packard <keithp@keithp.com> Original concept, polygon tessellation, dashing +Christof Petig <christof@petig-baender.de> Build fixes related to freetype +Jamey Sharp <jamey@minilop.net> Surface/font backend virtualization, XCB backend +Bill Spitzak <spitzak@d2.com> Build fix to find Xrender.h without xrender.pc +Sasha Vasko <sasha@aftercode.net> Build fix to compile without xlib backend +Carl Worth <cworth@isi.edu> Original library, support for paths, images +Richard D. Worth <richard@theworths.org> Build fixes for cygwin + +(please let us know if we have missed anyone) @@ -1,5 +1,7 @@ Splines are not dashed. +-- + The polygon tessellation routine has problems. It appears that the following paper has the right answers: @@ -9,8 +11,45 @@ following paper has the right answers: Finite Precision Output, Computation Geometry Theory and Applications, 13(4), 1999. +-- + Stroking a self-intersecting path generates the wrong answer, (in mostly subtle ways). The fix is to tessellate a giant polygon for the entire stroke outline rather than incrementally generating trapezoids. +-- + +Cairo is crashing Xnest with the following message: + +X Error of failed request: BadMatch (invalid parameter attributes) + Major opcode of failed request: 72 (X_PutImage) + Serial number of failed request: 28 + Current serial number in output stream: 29 + +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. + +-- +Caps are added only to the last subpath in a complex path. @@ -1,3 +1,631 @@ +2004-04-06 Carl Worth <cworth@isi.edu> + + * NEWS: Added notes for snapshot 0.1.20. + + * RELEASING: Added new RELEASING file. + +2004-04-04 David Reveman <c99drn@cs.umu.se> + + * src/cairoint.h: Added create_pattern backend function and pattern + prototypes. + + * src/cairo_xlib_surface.c: Added _cairo_xlib_surface_create_pattern. + + * src/cairo_xcb_surface.c: Added _cairo_xcb_surface_create_pattern. + + * src/cairo_traps.c: Added _cairo_trap_extents and + _cairo_traps_extents. + + * src/cairo_surface.c: Added _cairo_surface_create_pattern. + + * src/cairo_ps_surface.c: Added _cairo_ps_surface_create_pattern. + + * src/cairo_png_surface.c: Added _cairo_png_surface_create_pattern. + + * src/cairo_pattern.c (added): All functions needed for the new + pattern API. + + * src/cairo_image_surface.c: Added + _cairo_image_abstract_surface_create_pattern. + + * src/cairo_gstate.c (_cairo_gstate_init): Create solid pattern + and set alpha to 0.0. + (_cairo_gstate_init_copy): Increment pattern references. + (_cairo_gstate_fini): Destroy pattern. + (_cairo_gstate_set_pattern): Destroy current pattern, + increment references to the new pattern and update pattern + offset with the current point. + (_cairo_gstate_set_rgb_color): Destroy current pattern and + create a new solid pattern. + (_cairo_gstate_current_rgb_color): Get RGB from current pattern. + (_cairo_gstate_set_alpha): Set gstate->alpha without modifying + the current pattern. + (_cairo_gstate_stroke): + (_cairo_gstate_fill): Removed surface matrix computations as + they are now handled by _cairo_gstate_create_pattern. + (_cairo_gstate_clip_and_composite_trapezoids): Create a + possibly backend accelerated pattern source and use it for + compositing trapezoids. + (_cairo_gstate_clip): Allow backends to not support rectangular + clipping regions. Use solid pattern for creating clip surface. + (_cairo_gstate_show_surface): Use solid pattern for alpha mask. + (_cairo_gstate_show_text): + (_cairo_gstate_show_glyphs): Use current pattern when compositing + glyphs. + + Added _cairo_gstate_current_pattern and _cairo_gstate_create_pattern, + _cairo_gstate_stroke_extents, _cairo_gstate_fill_extents. + Removed restore_text_rendering_context, setup_text_rendering_context, + _cairo_gstate_ensure_source. + + * src/cairo_ft_font.c (_cairo_ft_font_show_glyphs): Advance + source offset. + + * src/cairo.h: Added cairo_current_pattern, + cairo_pattern_create_for_surface, cairo_pattern_create_linear, + cairo_pattern_create_radial, cairo_pattern_reference, + cairo_pattern_destroy, cairo_pattern_add_color_stop, + cairo_pattern_set_matrix, cairo_pattern_get_matrix, + cairo_pattern_set_extend, cairo_pattern_get_extend, + cairo_pattern_set_filter, cairo_pattern_get_filter. cairo_set_pattern + now takes a cairo_pattern_t pointer instead of a cairo_surface_t + pointer. Added CAIRO_FILTER_GAUSSIAN filter type. Added cairo_extend_t + enum. + + * src/cairo.c: _cairo_restrict_value declared not static as it's + used in cairo_pattern.c. Added rectangular extents functions + cairo_stroke_extents and cairo_fill_extents. cairo_set_pattern now + takes a cairo_pattern_t pointer instead of a cairo_surface_t + pointer. Added cairo_current_pattern function. + + * src/Makefile.am (libcairo_la_LIBADD): Removed -lz and added PS_LIBS. + + * configure.in: Bump version to 0.1.20. Includes new pattern + API. Removed an extra AC_SUBST(XRENDER_LIBS). + PS_SURFACE_LIBS -> PS_LIBS. + + * cairo.pc.in: PS_SURFACE_LIBS -> PS_LIBS. + +2004-04-02 Carl Worth <cworth@east.isi.edu> + + * src/cairo.h: Move weight after slant to match the order in + cairo_select_font. + + * TODO: Added notes on DPI for image-based backends and on + proposal for new cairo_text_glyphs function. + + * BUGS: Added BUG about cairo_show_text not advancing the current + point. + +2004-03-30 Carl Worth <cworth@isi.edu> + + * src/Makefile.am (libcairo_la_LIBADD): Add -lz. + +2004-03-30 Carl Worth <cworth@isi.edu> + + * configure.in: Add checks for Xrender.h in xrender.pc is not + found. Remove AC_HELP_STRING to be compatible with older versions + of autoconf (thanks to Bill Spitzak <spitzak@d2.com>). + + * src/cairo_xlib_surface.c (_cairo_xlib_surface_set_clip_region): + Add question on semantics with empty region. Fix missing return + value. + + * src/cairo_image_surface.c + (_cairo_image_surface_set_clip_region): Export for internal use. + (_cairo_image_abstract_surface_set_clip_region): Add silly wrapper + to match the backend interface. + + * src/cairo_gstate.c (_cairo_gstate_init_clip): Remove unused + variables. + + * src/cairo.h: Add proposal for cairo_xlib_surface_set_size. + + * BUGS: Added note about problem with cairo_scale_font. + +2004-03-23 Olivier Andrieu <oliv__a@users.sourceforge.net> + + * src/cairo_ps_surface.c (_cairo_ps_surface_set_clip_region) + * src/cairo_png_surface.c (_cairo_png_surface_set_clip_region): + Implement _set_clip_region by delegating it to the image backend. + + * src/cairo_xcb_surface.c (_cairo_xcb_surface_set_clip_region): + Add a stub. + + * src/cairo.h: Add missing (?) cairo_init_clip + +2004-03-20 Dave Beckett <Dave.Beckett@bristol.ac.uk> + + * configure.in: Move the PNG_CFLAGS/_LIBS substitutes outside + the conditional, to match what is already done for XCB. + Do the same for XRENDER_CFLAGS/LIBS. + + * configure.in: Substitute PNG_CFLAGS, PNG_LIBS on + the configure path when use_png is not enabled to prevent + the substituions being undefined. + +2004-03-19 Graydon Hoare <graydon@redhat.com> + + * src/cairo.c (cairo_init_clip): Add. + * src/cairo_gstate.c: + Initialize, finalize and copy clip.region. + Detect rectangular clips and push down to backend. + + * src/cairoint.h + (cairo_surface_backend_t): Add set_clip_region slot. + (cairo_clip_rec_t): Add region slot. + (_cairo_gstate_init_clip) + (_cairo_surface_set_clip_region): Prototype. + + * src/cairo_surface.c + (_cairo_surface_set_clip_region): Add. + + * src/cairo_xlib_surface.c + (_cairo_xlib_surface_set_clip_region): Add. + + * src/cairo_image_surface.c + (_cairo_image_surface_set_clip_region): Add. + + * src/cairo_ps_surface.c + (_cairo_ps_surface_set_clip_region): Stub, not implemented. + +2004-03-16 Jamey Sharp <jamey@minilop.net> + + * src/cairo.h: + * src/cairo_xcb_surface.c: + Updated for XCB typename renaming. The Xlib and XCB surfaces can + be compiled in the same library now. + + * src/cairo_surface.c: + Initialize the surface's filter value. + +2004-02-26 Carl Worth <cworth@isi.edu> + + * AUTHORS: Add Jordi and Olivier to the AUTHORS file. + + * src/cairo_ft_font.c (_utf8_to_ucs4): Fix broken return value for + nchars (thanks to Jordi Mas <jordi@ximian.com>). + +2004-02-24 Olivier Andrieu <oliv__a@users.sourceforge.net> + + * src/cairo.h: + * src/cairo-features.h.in: + * src/cairo_png_surface.c: Add PNG backend (cairo_set_target_png + and cairo_png_surface_create). + + * cairo.pc.in: + * configure.in: autoconf support for the PNG backend. Bump version + to 0.1.19. + + * src/Makefile.am: PNG backend support, removed references to + X_LIBS and X_CFLAGS. + +2004-02-24 Carl Worth <cworth@isi.edu> + + * AUTHORS: Add attribution for many people who have made generous + contributions to cairo. This list was generated by sifting through + the ChangeLog. Please let me know if I have missed anyone. + + * NEWS: Add some historical notes on cairo development, prior to + when we began to maintain this NEWS file. + + * README (http): Add pointer to cairographics.org. Fix to use + "cairo" rather than "Cairo" when not at the beginning of a + sentence. + + * TODO: Remove cairo_current_path, cairo_current_path_flat, + cairo_text_extents, cairo_glyph_extents, cairo_text_path, and + cairo_glyph_path from the TODO list as they have all been + implemented now. + +2004-02-17 Carl Worth <cworth@isi.edu> + + * src/cairo.h: Add comment indication cairo_copy will be going + away at some point. Some indentation fixes. + + * configure.in: Bump version to 0.1.18. Includes new functions + cairo_current_path, cairo_current_path_flat, + cairo_surface_get_filter. Support for XCB backend. Fixes for + building in cygwin. Adds cairo_surface_get_filter. + + * src/cairo.h: + * src/cairo.c (cairo_current_path): + (cairo_current_path_flat): Add new path query functions. + + * src/cairo_gstate.c (_gpi_move_to): + (_gpi_line_to): + (_gpi_curve_to): + (_gpi_close_path): + (_cairo_gstate_interpret_path): Implement support for + cairo_current_path and cairo_current_path_flat. These functions + just provide an interface to _cairo_path_interpret and take care + of mapping from device space back to user space. + +2004-02-13 Carl Worth <cworth@east.isi.edu> + + * TODO: Add some notes from JG's TODO list on the wiki: + http://cairographics.org/CairoToDoList. (Also testing automated + mailing to cairo-commit list). + +2004-02-12 Carl Worth <cworth@isi.edu> + + * src/cairo.h: Add typedefs for new callbacks to be used by + cairo_current_path: cairo_move_to_func, cairo_line_to_func, + cairo_curve_to_func, and cairo_close_path_func. + + * src/cairoint.h: cairo_path.last_move_point and + cairo_path.current_point are now fixed-point not doubles for + consistency. + + * src/cairo_path.c (_cairo_path_interpret): Now accept 4 explicit + function pointers rather than a structure. Eliminate unnecessary + done_path callback. + + * src/cairo_path_bounds.c (_cairo_path_bounds): + * src/cairo_path_stroke.c (_cairo_path_stroke_to_traps): + * src/cairo_path_fill.c (_cairo_path_fill_to_traps): Track change + in _cairo_path_interpret. Code previously in done_path callback is + now here immediately after call to _cairo_path_interpret. + + * src/cairo_path.c (_cairo_path_move_to): + (_cairo_path_rel_move_to): + (_cairo_path_line_to): + (_cairo_path_rel_line_to): + (_cairo_path_curve_to): + (_cairo_path_rel_curve_to): + (_cairo_path_current_point): Internal _cairo_path API modified to + accept fixed-point data everywhere. Much cleaner this way. + + * src/cairo_gstate.c (_cairo_gstate_move_to): + (_cairo_gstate_line_to): + (_cairo_gstate_curve_to): + (_cairo_gstate_rel_move_to): + (_cairo_gstate_rel_line_to): + (_cairo_gstate_rel_curve_to): + (_cairo_gstate_current_point): + (_cairo_gstate_show_text): + (_cairo_gstate_text_path): Have to convert doubles to fixed-point + to track changes in _cairo_path API. + + * src/cairo_ft_font.c (_move_to, _line_to, _conic_to, _cubic_to): + Keep data in fixed-point rather than going through intermediate + doubles. Track changes in _cairo_path API. + + * src/cairo_fixed.c (_cairo_fixed_from_26_6): New function to help + when working with freetype. + +2004-02-02 Jamey Sharp <jamey@minilop.net> + + * configure.in: + * src/Makefile.am: + * src/cairo-features.h.in: + * src/cairo.h: + * src/cairo_xcb_surface.c (added): + Ported the Xlib surface backend to XCB. + +2004-02-02 Graydon Hoare <graydon@redhat.com> + + * src/cairo_xlib_surface.c + (CAIRO_SURFACE_RENDER_HAS_FILTERS): New predicate. + (_cairo_xlib_surface_set_filter): Skip filterless servers. + (_cairo_xlib_surface_clone_similar): Fix typo. + +2004-01-27 Graydon Hoare <graydon@redhat.com> + + * src/cairoint.h (cairo_surface): New "filter" field. + * src/cairo_surface.c + (cairo_surface_get_filter): New function. + (cairo_surface_set_filter): Store filter in surface. + * src/cairo.h (cairo_surface_get_filter): Declare. + * src/cairo_xlib_surface.c + (_cairo_xlib_surface_clone_similar): Copy filter setting. + (_cairo_xlib_surface_set_filter): Use constants from Xrender.h + +2004-01-24 Carl Worth <cworth@isi.edu> + + * src/cairo_path_stroke.c (_cairo_stroker_add_sub_edge): Fix to + use tessellate_polygon instead of tessellate_rectangle as the + matrix may have skewed the coordinates into a non-rectangular + shape. + + * src/cairo_xlib_surface.c (_cairo_xlib_surface_set_filter): Add + missing break statements to switch. + +2004-01-22 Richard D. Worth <richard@theworths.org> + + * src/Makefile.am: Add '-no-undefined' to end of + libcairo_la_LDFLAGS to enable building shared library under + cygwin. + + * src/cairo.h: Remove all 'extern ' and ' __external_linkage' + (macro for __declspec(dllexport) and __declspec(dllimport)) + from function declarations. These are no longer needed for cygwin. + + * src/cairo_traps.c: Changed type of _line_segs_intersect_ceil + from 'static cairo_fixed_t' to 'static int' to match definition. + This was necessary to compile under cygwin. + +2003-12-17 Carl Worth <cworth@east.isi.edu> + + * src/cairo.h: Remove trailing commas from enums, (some compilers + like to complain about them). + +2003-12-16 Dave Beckett <Dave.Beckett@bristol.ac.uk> + + * README: Do not require libpixregion, libic. + +2003-12-16 Carl Worth <cworth@east.isi.edu> + + * NEWS: Add more notes culled from the ChangeLog. + +2003-12-16 Carl Worth <cworth@isi.edu> + + * NEWS: Begin maintaining NEWS file. Add notes on 0.1.17. + + * configure.in: Bump version to 0.1.17 for new functions: + cairo_text_extents, cairo_glyph_extents, cairo_text_path, + cairo_glyph_path. + + * src/cairo.h: + * src/cairo.c (cairo_text_path): + (cairo_glyph_path): Re-enable cairo_text_path and cairo_glyph_path. + + * src/cairo_gstate.c (_cairo_gstate_glyph_path): Add missing + transformation. + + * src/cairo_ft_font.c (_move_to): + (_line_to): + (_conic_to): + (_cubic_to): + (_cairo_ft_font_glyph_path): Initial implementation of glyph_path. + +2003-12-16 Carl Worth <cworth@isi.edu> + + * src/cairoint.h: Move all current_point state fields from + cairo_gstate_t to cairo_path_t. + + * src/cairo_path.c (_cairo_path_init): + (_cairo_path_init_copy): + (_cairo_path_fini): + (_cairo_path_move_to): + (_cairo_path_line_to): + (_cairo_path_curve_to): + (_cairo_path_close_path): Add current_point state. + (_cairo_path_current_point): New function. + (_cairo_path_rel_move_to): + (_cairo_path_rel_line_to): + (_cairo_path_rel_curve_to): New functions. + + * src/cairo_gstate.c (_cairo_gstate_init): + (_cairo_gstate_new_path): + (_cairo_gstate_move_to): + (_cairo_gstate_line_to): + (_cairo_gstate_curve_to): + (_cairo_gstate_rel_move_to): + (_cairo_gstate_rel_line_to): + (_cairo_gstate_rel_curve_to): + (_cairo_gstate_close_path): + (_cairo_gstate_current_point): Eliminate current_point state. + (_cairo_gstate_show_text): + (_cairo_gstate_text_path): Use new _cairo_path_current_point. + +2003-12-16 Carl Worth <cworth@isi.edu> + + + * src/cairo_ft_font.c (_cairo_ft_font_glyph_path): + (_cairo_ft_font_text_path): A couple of changes missed in the last + batch of commits (reordering so that path is final argument). + + * src/cairoint.h: Change cairo_font_backend_t to use a void * for + the abstract font. Put create, copy, and destroy as the first + functions in the list. Fix text_path and glyph_path so that the + path to be returned is the last argument. Add x,y arguments to + text_path. + + * src/cairo_gstate.c (_cairo_gstate_text_path): Compute x,y now + needed by cairo_font_text_path. + (_cairo_gstate_glyph_path): Track change in + cairo_font_text/glyph_path (path argument is now last). + + * src/cairo_ft_font.c: Switch to new macro-based mechanism for + including freetype headers. + (cairo_ft_font_face): + (cairo_ft_font_pattern): Minor cleanup. + (_cairo_ft_font_copy): + (_cairo_ft_font_destroy): + (_utf8_to_glyphs): + (_cairo_ft_font_font_extents): + (_cairo_ft_font_glyph_extents): + (_cairo_ft_font_text_extents): + (_cairo_ft_font_show_glyphs): + (_cairo_ft_font_show_text): Track changes to cairo_font_backend_t + interface. + + * src/cairo_font.c (_cairo_font_text_path): + (_cairo_font_glyph_path): Track changes to cairo_font_backend_t + interface. + +2003-12-16 Carl Worth <cworth@isi.edu> + + * TODO: Change instances of Cairo to cairo where necessary. Add + note about broken dashing on splines. + +2003-12-15 Carl Worth <cworth@isi.edu> + + * src/cairo_gstate.c (_cairo_gstate_text_extents): + (_cairo_gstate_glyph_extents): + * src/cairo_ft_font.c (_cairo_ft_font_glyph_extents): + (_cairo_ft_font_glyph_extents): + * src/cairo.h: Rename cairo_text_exextents_t fields: + left_side_bearing -> x_bearing + ascent -> y_bearing + right_side_bearing (replaced by) width + descent (replaced by) height + +2003-12-15 Carl Worth <cworth@isi.edu> + + * src/cairo_gstate.c (_cairo_gstate_text_extents): + (_cairo_gstate_glyph_extents): Need to divide out the scale factor + to return user-space extents. + (_cairo_gstate_glyph_extents): Don't transform glyph locations as + they're not relevant to extents. + + * src/cairo_ft_font.c (_cairo_ft_font_font_extents): Clean up + implementation. + (_cairo_ft_font_glyph_extents): Initial implementation. Thanks to + John Ellson <ellson@research.att.com> for most of the work on this + function. + (_cairo_ft_font_show_text): Clean to use num_glyphs not nglyphs. + + * src/cairo.h: + * src/cairo.c (cairo_text_extents): + (cairo_glyph_extents): Re-enable cairo_text/glyph_extents. + +2003-12-15 Carl Worth <cworth@isi.edu> + + * src/cairo_matrix.c (_cairo_matrix_compute_scale_factors): Move + this function from cairo_ft_font.c (_get_scale_factors). + + * src/cairo_ft_font.c (DOUBLE_TO_16_16): Fix minor errors in + fixed/floating-point conversion. + + * src/cairoint.h: font->show_glyphs no longer accepts an offset + point. + + * src/cairo_ft_font.c (_utf8_to_glyphs): + (_cairo_ft_font_text_extents): + (_cairo_ft_font_show_text): + (_cairo_ft_font_text_path): _utf8_to_glyphs now accepts a point by + which each glyph should be offset. + (cairo_ft_font_backend): Remove evil void * casts on function + pointers. + + * src/cairo_font.c (_cairo_font_show_glyphs): Fix to not require a + current point. + + * src/cairo_gstate.c (_cairo_gstate_show_text): + (setup_text_rendering_context): Move initialization of current + device-space point from setup_text_rendering_context to + _cairo_gstate_show_text. + (_cairo_gstate_show_glyphs): Fix to not reference current point. + +2003-12-12 Dave Beckett <Dave.Beckett@bristol.ac.uk> + + * src/Makefile.am: Add compatibility defines FONTCONFIG_LIBS, + X_LIBS, XRENDER_LIBS to keep automake happy - they look like + automake variable names. + +2003-12-12 Carl Worth <cworth@east.isi.edu> + + * src/cairo_font.c (_cairo_font_create): Add comment about + building in a font. + + * src/cairo_ft_font.c (_cairo_ft_font_create): Check for NULL + return value from cairo_ft_font_create. + + * src/cairo.h: + * src/cairo-features.h.in: + * src/Makefile.am (libcairo_ps_sources): Add conditionals for + ps_surface functions, etc. + + * configure.in: Get rid of AC_PATH_XTRA. Instead, find X + includes/libraries only via pkg-config xrender. + Switch option from --without-x to --disable-xlib + Add option --disable-ps + + * cairo.pc.in (Libs): Add -lz only if ps_surface backend is compiled. + + * src/cairo.h (__external_linkage): Add missing definitions from + slim_import.h. + +2003-12-11 Carl Worth <cworth@isi.edu> + + * src/cairoint.h: Rename surface->ic_image to + surface->pixman_image. + + * src/cairo_image_surface.c + (_cairo_image_surface_create_for_pixman_image): + (_cairo_image_surface_create_with_masks): + (_create_pixman_format): + (cairo_image_surface_create): + (cairo_image_surface_create_for_data): + (_cairo_image_abstract_surface_destroy): + (_cairo_image_surface_set_matrix): + (_cairo_image_surface_set_filter): + (_cairo_image_surface_set_repeat): + (_pixman_operator): + (_cairo_image_surface_fill_rectangles): + (_cairo_image_surface_composite_trapezoids): Rename functions and + indentifiers with ic_ in the name that were missed by the recent + renaming. Fix indentation problems left by the recent renaming. + + * Shift everything over from libic/libpixregion/slim to + libpixman. Many thanks to Dave Beckett + <dave.beckett@bristol.ac.uk> for all of the heavy lifting with + this renaming effort. + + * src/cairoint.h (slim_hidden_proto1): Directly fold in slim stuff + rather than depending on it from an external package. + + * src/cairo_ps_surface.c (_cairo_ps_surface_copy_page): + * src/cairo_image_surface.c: Switch from libic to libpixman. + + * src/cairo.h: Include pixman.h not ic.h. + (__external_linkage): Directly fold in slim stuff rather than + depending on it from an external package. + + * configure.in (PKG_CHECK_MODULES): + * cairo.pc.in (Requires): Look for libpixman instead of libic and + slim. + +2003-12-11 Andrew Chant <andrew.chant@utoronto.ca> + + * cairo_select_font: + _cairo_font_create: + _cairo_ft_font_create: + _cairo_gstate_select_font: + change char * family to const char * family + +2003-12-11 Carl Worth <cworth@isi.edu> + + * src/cairo_xlib_surface.c (_cairo_xlib_surface_set_image): + Replace mysterious image->depth == 32 ? 24 : image->depth with + simply image->depth. + +2003-12-11 Carl Worth <cworth@east.isi.edu> + + * cairo.pc.in (Requires): + * configure.in: Add xrender to cairo.pc Renders line if needed. + +2003-12-11 Carl Worth <cworth@east.isi.edu> + + * src/cairo_ps_surface.c (_cairo_ps_surface_copy_page): Fix to use + shifts and masks for endianness-correct PS image + generation. Rename bgr to rgb now that the byte order issues are + clear. + +2003-12-08 Carl Worth <cworth@isi.edu> + + * src/cairo_path_bounds.c (_cairo_path_bounder_move_to): + (_cairo_path_bounder_line_to): + (_cairo_path_bounder_curve_to): + (_cairo_path_bounder_close_path): Track change in + cairo_path_callbacks interface. + + * src/cairoint.h: + * src/cairo_path_stroke.c: + * src/cairo_path_fill.c: + * src/cairo_path.c: Clean up cairo_path_callbacks to have move_to, + line_to, curve_to, abd close_path instead of add_edge, add_spline, + and done_sub_path. Much, much nicer. + + * src/cairo_polygon.c (_cairo_polygon_move_to): Provide + cairo_polygon_move_to and cairo_polygon_line_to instead of + cairo_polygon_add_point. + + * src/cairo_pen.c (_cairo_pen_stroke_spline_half): Track change in + cairo_polygon interface. + 2003-12-08 Carl Worth <cworth@isi.edu> * configure.in: Bump version to 0.1.16 since it actually has a @@ -0,0 +1,151 @@ +Snapshot 0.1.20 (2004-04-06 Carl Worth <cworth@isi.edu>) +======================================================== +New pattern API +--------------- +David Reveman has contributed a new pattern API which enable linear +and radial gradient patterns in addition to the original surface-based +patterns. The significant new top-level functions are: + + cairo_pattern_create_linear + cairo_pattern_create_radial + cairo_pattern_create_for_surface + cairo_pattern_add_color_stop + cairo_set_pattern + +Any code using the old cairo_set_pattern, (which accepted a +cairo_surface_t rather than a cairo_pattern_t), will need to be +updated. + +Update to XCB backend +--------------------- +The XCB backend is now enabled by default, (use ./configure +--disable-xcb to turn it off). + +Faster clipping +--------------- +Graydon Hoare has added optimizations that make cairo_clip much faster +when the path is a pixel-aligned, rectangular region. + +Bug fixes. + +Snapshot 0.1.19 (2004-02-24 Carl Worth <cworth@isi.edu>) +======================================================== +New PNG backend +--------------- +Olivier Andrieu contributed a new PNG backend. It builds on the +existing image backend to make it easy to render "directly" to a +.png file. The user never needs to deal with the actual image +buffer. The significant new functions are: + + cairo_set_target_png + cairo_png_surface_create + +The PNG backend is not enabled by default so that by default there is +not a new dependency on libpng. Use ./configure --enable-png to enable +this backend. + +Snapshot 0.1.18 (2004-02-17 Carl Worth <cworth@isi.edu>) +======================================================== +Path query functionality +------------------------ +It's now possible to query the current path. The two new functions +are: + + cairo_current_path + cairo_current_path_flat + +Each function accepts a number of callback functions that will be +called for each element in the path (move_to, line_to, curve_to, +close_path). The cairo_current_path_flat function does not accept a +curve_to callback. Instead, all curved portions of the path will be +converted to line segments, (within the current tolerance value). This +can be handy for doing things like text-on-path without having to +manually interpolate bezier splines. + +New XCB backend +--------------- +Jamey Sharp has contributed a second X backend that uses the new, lean +XCB library rather than Xlib. It cannot currently be compiled at the +same time as the Xlib backend. See ./configure --enable-xcb. + +Build fixes for cygwin. + +Bug fixes. + +Snapshot 0.1.17 (2003-12-16 Carl Worth <cworth@isi.edu>) +======================================================== + +Better text support +------------------- +This snapshot provides much better text support by implementing the +following four functions: + + cairo_text_extents + cairo_glyph_extents + cairo_text_path + cairo_glyph_path + +The text/glyph_extents functions can be used to determine the bounding +box (and advance) for text as if drawn by show_text/glyphs. + +The text/glyph_path objects functions place text shapes on the current +path, where they can be subsequently manipulated. For example, +following these functions with cairo_stroke allows outline text to be +drawn. Calling cairo_clip allows clipping to a text-shaped region. + +Combined dependencies +--------------------- +The cairo core now depends only on the libpixman library. This single +library replaces the three previous libraries libic, libpixregion, and +slim. Thanks to Dave Beckett <dave.beckett@bristol.ac.uk> for all of +the heavy lifting with this renaming effort. + +Conditional compilation of backends +----------------------------------- +Cairo now allows optional beckends to be disabled at compile time. The +following options may now be passed to the configure script: + + --disable-xlib + --disable-ps + +Note that the first option is a change from the old --without-x option +which will no longer have any effect. + +OS X supported - several byte-order issues resolved +--------------------------------------------------- +Cairo has now been successfully compiled under OS X. Testing revealed +that there were some byte-order problems in the PostScript backend and +the PNG generation in the demos. These have now been resolved. + +2003-10 +======= +Graydon Hoare <graydon@redhat.com> implemented the first real text +support using Freetype/fontconfig, (previous versions of cairo used +Xft and could only draw text when using an X backend). + +2003-09 +======= +Graydon Hoare <graydon@redhat.com> added the first real support for +running cairo with a non-render-aware X server. + +Jamey Sharp <jamey@minilop.net> virtualized the backend font and +surface interfaces in September, 2003. + +2003-06 +======= +Xr is renamed cairo to avoid confusion since it no longer had a strict +dependence on X. + +2003-05 +======= +A new image surface backend is added to Xr. Keith Packard +<keithp@keithp.com> wrote the image compositing code in libic that is +used for the image_surface backend. This code was originally written +as the software fallback for the render extension within the X +server. + +2002-06 +======= +Carl Worth <cworth@isi.edu> wrote the first lines of Xr, after Keith +Packard <keithp@keithp.com> proposed the plan for a stateful drawing +library in C providing a PostScript-like rendering model. @@ -1,4 +1,5 @@ Cairo - Multi-platform 2D graphics library +http://cairographics.org Compiling --------- @@ -25,10 +26,7 @@ Dependencies ------------ Cairo currently requires the following supporting libraries: - slim - libpixregion - libic - + libpixman Xft2 fontconfig freetype2 @@ -39,19 +37,19 @@ There's not much documentation yet apart from the cairo.h header file. We'll be correcting that shortly. In the meantime, the cairo-demo module in CVS provides a few example -programs using Cairo. These may be helpful to a programmer just -beginning with Cairo. Also, familiarity with the PostScript imaging -model will help in understanding Cairo. +programs using cairo. These may be helpful to a programmer just +beginning with cairo. Also, familiarity with the PostScript imaging +model will help in understanding cairo. History ------- -Cairo was developed by Carl Worth <cworth@isi.edu> and Keith Packard -<keithp@keithp.com>. Many thanks are due to Lyle Ramshaw without whose -patient help our ignorance would be much more apparent. +Cairo was originally developed by Carl Worth <cworth@isi.edu> and +Keith Packard <keithp@keithp.com>. Many thanks are due to Lyle Ramshaw +without whose patient help our ignorance would be much more apparent. Mailing List ------------ -If you have trouble with Cairo or you have some ideas for how it could be +If you have trouble with cairo or you have some ideas for how it could be improved, please feel free to send a message to cairo@cairographics.org Cairo is still under active development and all discussion happens on diff --git a/RELEASING b/RELEASING new file mode 100644 index 000000000..6ebcb8ee0 --- /dev/null +++ b/RELEASING @@ -0,0 +1,67 @@ +So far, cairo hasn't reached an initial release. But we can still form +good habits now by practicing the release process with the current +snapshots. + +10 easy steps to creating a new cairo snapshot +============================================== + +1) Commit code with a significant new feature or backwards + incompatibility. + + Either of these events triggers the need for a new snapshot. + Users of cairo snapshots need to be able to specify snapshot + version numbers in order to get access to a specific set of + features. + +2) Verify that the code passes "make distcheck" + + Running "make distcheck" should result in no warnings or + errors and end with a message of the form: + + ============================================= + cairo-X.Y.Z.tar.gz is ready for distribution + ============================================= + + (But the tar file isn't actually ready yet, as we still have + some more steps to follow). + +3) Fill out an entry in the NEWS file + + Sift through the information in ChangeLog since the last + snapshot. Summarize major changes briefly in a style similar + to other entries in NEWS. + +4) Increment CAIRO_VERSION in configure.in + + Right now, in its pre-release form, we are incrementing + CAIRO_VERSION for each snapshot but we are not changing the + libtool shared library version information. Until now, we've + only incremented the sub-minor version. We'll invent rules for + incrementing major and minor numbers when the time is right. + +5) Commit the changes to NEWS and configure.in + + Don't forget to fill out the ChangeLog just like with any + other commit. It's especially important to mention the new + version number in the ChangeLog. + +6) Run "make distcheck" to generate the final tar file with the + correct version number. + +7) Copy the resulting tar file to the cairo snapshots distribution + directory: + + scp cairo-X.Y.Z-tar.gz cairographics.org:/home/www/cairo/snapshots + +8) Tag the entire source tree with a tag of the form SNAPSHOT_X_Y_Z: + + cvs tag SNAPSHOT_X_Y_Z + +9) Send a message to cairo-announce@cairographics.org to announce the + new snapshot. + + This is as simple as cutting and pasting the new section of + the NEWS file into the body of the message. + +10) Sit back and relax in confidence, (or brace yourself for a flood + of new bug reports). It's up to you! @@ -1,3 +1,12 @@ +* Clean up the API in preparation for freezing and release. + +* Implement a PDF backend. + +* Make a more interesting PS backend, (other than the current +"giant-image for every page" approach). + +* Figure out what to do with DPI for image/png backends. + * Change stroke code to go through one giant polygon. This will fix problems with stroking self-intersecting paths. @@ -7,14 +16,39 @@ is done). * Fix the intersection problem, (see reference to Hobby's paper mentioned in cairo_traps.c). -* Implement support for programmatic patterns. - -* Implement cairo_text_extents, cairo_glyph_extents, cairo_text_path, -cairo_glyph_path, and cairo_stroke_path, cairo_arc_to. - -* Investigate what needs to be done so that old X servers aren't -swamped with image transport. This may involve adding one or more of -the following functions: +* Add a new cairo_text_glyphs function (a sort of bridge between the +toy and the real text API): + + > void + > cairo_text_glyphs (cairo_t *cr, const unsigned char *utf8, + > cairo_glyph_t *glyphs, int *num_glyphs); + > + > with num_glyphs as an input-output parameter. The behavior of this + > function would be such that calling: + > + > cairo_text_glyphs (cr, string, glyphs, &num_glyphs); + > cairo_show_glyphs (cr, glyphs, num_glyphs); + > + > would be equivalent too: + > + > cairo_show_text (cr, string); + > + > as long as the original size of glyphs/num_glyphs was large + > enough. + +* Implement dashing for cairo_curve_to. + +* Implement support for programmatic patterns, (ie. figure out how to +do gradients the Right Way). + +* Implement cairo_arc_to. + +* Fix support for old X servers so that it is not swamped with image +transport. The key idea is to assume that nothing external to cairo +will be drawing to the same drawable after it is handed to +cairo. Beyond that, we might actually provide support for cooperating +with external entities by adding one or more of the following +functions: cairo_flush cairo_erase @@ -32,108 +66,108 @@ A comparison with PostScript ============================ Here's a list of several classes of PostScript operators indicating -which operators have rough equivalents in Cairo and which do not. In -general, the name of a Cairo function corresponding to a PostScript +which operators have rough equivalents in cairo and which do not. In +general, the name of a cairo function corresponding to a PostScript operator can be obtained by inserting a '_' between each word and prefixing it with "cairo_". For example, "cairo_move_to" corresponds to the PostScript "moveto". -In cases where the name of the Cairo function deviates from this -convention, or when the behavior of the Cairo function is +In cases where the name of the cairo function deviates from this +convention, or when the behavior of the cairo function is significantly different, the change is noted in parentheses below. This list is not exhaustive, (there are definitely some minor (major?) semantic deviations that are not noted below). Also, this list is -almost certainly out of date with respect to the current Cairo +almost certainly out of date with respect to the current cairo implementation. Caveat lector. -Oerators that are not yet in Cairo, but probably should be: arcto, +Operators that are not yet in cairo, but probably should be: arcto, strokepath, rectclip?, clipsave/restore?, setstrokeadjust?, currentdash, grestoreall?, initgraphics?, currentgstate?, setgstate?, erasepage?, setsmoothness? Painting operators ------------------ -in Cairo: stroke, fill, eofill (set_fill_rule/fill), image +in cairo: stroke, fill, eofill (set_fill_rule/fill), image (show_surface) -not in Cairo: erasepage, rectstroke, rectfill, shfill, colorimage, +not in cairo: erasepage, rectstroke, rectfill, shfill, colorimage, imagemask Path construction operators --------------------------- -in Cairo: arc, arcn (arc_negative), newpath, moveto, rmoveto +in cairo: arc, arcn (arc_negative), newpath, moveto, rmoveto (rel_move_to), lineto, rlineto (rel_line_to), curveto, rcurveto -(rel_curve_to), closepath, currentpoint, charpath (text_path) +(rel_curve_to), closepath, currentpoint, charpath (text_path), +pathforall (current_path), flattenpath (current_path_flat) -not in Cairo: arct, arcto, flattenpath, reversepath, strokepath, -clippath, pathbbox, pathforall +not in cairo: arct, arcto, reversepath, strokepath, clippath, pathbbox Clipping -------- -in Cairo: clip, eoclip (set_fill_rule/clip) +in cairo: clip, eoclip (set_fill_rule/clip) -not in Cairo: initclip, rectclip, clipsave, cliprestore +not in cairo: initclip, rectclip, clipsave, cliprestore Graphics state operators ------------------------ -in Cairo: setlinewidth, currentlinewidth, setlinecap, currentlinecap, +in cairo: setlinewidth, currentlinewidth, setlinecap, currentlinecap, setlinejoin, currentlinejoin, setmiterlimit, currentmiterlimit, setdash -not in Cairo: setstrokeadjust, currentstrokeadjust, currentdash +not in cairo: setstrokeadjust, currentstrokeadjust, currentdash Color specification operators ----------------------------- -in Cairo: setrgbcolor, currentcolor +in cairo: setrgbcolor, currentcolor -not in Cairo: setcolor, setgray, currentgray, currentrgbcolor, +not in cairo: setcolor, setgray, currentgray, currentrgbcolor, sethsbcolor, currenthsbcolor, setcmykcolor, currentcmykcolor, setcolorspace, currentcolorspace Form and pattern operators -------------------------- -in Cairo: setpattern, makepattern (lock_pattern) +in cairo: setpattern, makepattern (lock_pattern) -not in Cairo: execform +not in cairo: execform Whole-state manipulation ------------------------ -in Cairo: gsave (save), grestore (restore) +in cairo: gsave (save), grestore (restore) -not in Cairo: grestoreall, initgraphics, gstate, currentgstate, +not in cairo: grestoreall, initgraphics, gstate, currentgstate, setgstate Coordinate system and matrix operators -------------------------------------- -in Cairo: identmatrix (identity_matrix), initmatrix (default_matrix), +in cairo: identmatrix (identity_matrix), initmatrix (default_matrix), setmatrix, translate, scale, rotate, concatmatrix, currentmatrix, transform (transform_point), dtransform (transform_distance) -not in Cairo: matrix, defaultmatrix, concat, itransform, idtransform, +not in cairo: matrix, defaultmatrix, concat, itransform, idtransform, invertmatrix Insideness testing ------------------ -in Cairo: infill, instroke, ineofill (set_fill_rule/in_fill) +in cairo: infill, instroke, ineofill (set_fill_rule/in_fill) -not in Cairo: inufill, inustroke, inueofill +not in cairo: inufill, inustroke, inueofill Device setup ------------ -in Cairo: showpage, copypage +in cairo: showpage, copypage -not in Cairo: setpagedevice, currentpagedevice, nulldevice +not in cairo: setpagedevice, currentpagedevice, nulldevice Glyph and font operators ------------------------ -in Cairo: currentfont, definefont (font_create_for_ft_face), +in cairo: currentfont, definefont (font_create_for_ft_face), undefine_font (font_destroy), findfont (font_create), makefont (transform_font), setfont, scalefont, selectfont, show (show_text), stringwidth (x/y in text_extents), xyshow (glyph_show -- but ignoring current_point and using absolute positions) -not in Cairo, (and likely not needed): composefont, rootfont, ashow, +not in cairo, (and likely not needed): composefont, rootfont, ashow, widthshow, awidthshow, xshow, xyshow, yshow, glyphshow, cshow, kshow, FontDirectory, GlobalFontDirectory, StandardEncoding, ISOLatin1Encoding, findencoding, setcachedevice, setcachedevice2, @@ -141,16 +175,16 @@ setcharwidth Graphics state operators (device-dependent) ------------------------------------------- -in Cairo: setflat (set_tolerance), currentflat (current_tolerance) +in cairo: setflat (set_tolerance), currentflat (current_tolerance) -not in Cairo: sethalftone, currenthalftone, setscreen, currentscreen, +not in cairo: sethalftone, currenthalftone, setscreen, currentscreen, setcolorscreen, currentcolorscreen, settransfer, currenttransfer, setcolortransfer, currentcolortransfer, setblackgeneration, currentblackgeneration, setundercolorremoval, currentundercolorremoval, setcolorrendering, currentcolorrendering, setoverprint, currentoverprint, setsmoothness, currentsmoothness -PostScript operators never to be in Cairo +PostScript operators never to be in cairo ----------------------------------------- Operator Stack Manipulation Operators, Arithmetic and Math Operators, Array Operators, Packed Array Operators, Dictionary Operators, String diff --git a/cairo.pc.in b/cairo.pc.in index 4996450e7..316e6f337 100644 --- a/cairo.pc.in +++ b/cairo.pc.in @@ -7,7 +7,7 @@ Name: cairo Description: Multi-platform 2D graphics library Version: @VERSION@ -Requires: fontconfig libic slim -Libs: -L${libdir} -lcairo -lm -lz @FREETYPE_LIBS@ +Requires: fontconfig libpixman @XRENDER_REQUIRES@ @PNG_REQUIRES@ +Libs: -L${libdir} -lcairo -lm @XRENDER_LIBS@ @PS_LIBS@ @FREETYPE_LIBS@ Cflags: -I${includedir} @FREETYPE_CFLAGS@ diff --git a/configure.in b/configure.in index 63a154ea6..a2df768ad 100644 --- a/configure.in +++ b/configure.in @@ -3,7 +3,7 @@ AC_INIT(src/cairo.h) dnl =========================================================================== # Package version number, (as distinct from shared library version) -CAIRO_VERSION=0.1.16 +CAIRO_VERSION=0.1.20 # libtool shared library version @@ -36,25 +36,94 @@ AC_STDC_HEADERS dnl =========================================================================== -AC_PATH_XTRA +AC_ARG_ENABLE(xlib, + [ --disable-xlib Disable cairo's Xlib backend], + [use_xlib=$enableval], [use_xlib=yes]) -if test "x$have_x" != "xyes"; then +if test "x$use_xlib" != "xyes"; then XLIB_SURFACE_FEATURE=CAIRO_HAS_NO_XLIB_SURFACE + AM_CONDITIONAL(CAIRO_HAS_XLIB_SURFACE, false) else XLIB_SURFACE_FEATURE=CAIRO_HAS_XLIB_SURFACE - PKG_CHECK_MODULES(XRENDER, xrender >= 0.6) + dnl Check for Xrender header files if the Xrender package is not installed: + PKG_CHECK_MODULES(XRENDER, xrender >= 0.6,[ + XRENDER_REQUIRES=xrender],[ + AC_CHECK_HEADER(X11/extensions/Xrender.h,[ + AC_PATH_XTRA + XRENDER_LIBS="$X_LIBS -lXrender -lXext -lX11 $X_EXTRA_LIBS"],[ + AC_MSG_ERROR(Xrender not found perhaps use --disable-xlib?)])]) + AM_CONDITIONAL(CAIRO_HAS_XLIB_SURFACE, true) fi AC_SUBST(XLIB_SURFACE_FEATURE) +AC_SUBST(XRENDER_CFLAGS) +AC_SUBST(XRENDER_LIBS) +AC_SUBST(XRENDER_REQUIRES) -dnl This is needed for conditional compilation of xlib code in Makefile.am : -dnl XXX: I'd prefer to have only one test of $have_x, would that be easy? -AM_CONDITIONAL(CAIRO_HAS_XLIB_SURFACE, test x$have_x = xyes) +dnl =========================================================================== + +AC_ARG_ENABLE(xcb, + [ --disable-xcb Disable cairo's XCB backend], + [use_xcb=$enableval], [use_xcb=no]) + +if test "x$use_xcb" != "xyes"; then + XCB_SURFACE_FEATURE=CAIRO_HAS_NO_XCB_SURFACE + AM_CONDITIONAL(CAIRO_HAS_XCB_SURFACE, false) +else + XCB_SURFACE_FEATURE=CAIRO_HAS_XCB_SURFACE + PKG_CHECK_MODULES(XCB, xcb) + AM_CONDITIONAL(CAIRO_HAS_XCB_SURFACE, true) +fi + +AC_SUBST(XCB_SURFACE_FEATURE) +AC_SUBST(XCB_CFLAGS) +AC_SUBST(XCB_LIBS) + +dnl =========================================================================== + +AC_ARG_ENABLE(ps, + [ --disable-ps Disable cairo's PostScript backend], + [use_ps=$enableval], [use_ps=yes]) + +if test "x$use_ps" != "xyes"; then + PS_SURFACE_FEATURE=CAIRO_HAS_NO_PS_SURFACE + AM_CONDITIONAL(CAIRO_HAS_PS_SURFACE, false) +else + PS_SURFACE_FEATURE=CAIRO_HAS_PS_SURFACE + PS_LIBS=-lz + AM_CONDITIONAL(CAIRO_HAS_PS_SURFACE, true) +fi + +AC_SUBST(PS_SURFACE_FEATURE) +AC_SUBST(PS_LIBS) + +dnl =========================================================================== + +AC_ARG_ENABLE(png, + [ --enable-png Enable cairo's PNG backend], + [use_png=$enableval], [use_png=no]) + +if test "x$use_png" != "xyes"; then + PNG_SURFACE_FEATURE=CAIRO_HAS_NO_PNG_SURFACE + AM_CONDITIONAL(CAIRO_HAS_PNG_SURFACE, false) +else + PNG_SURFACE_FEATURE=CAIRO_HAS_PNG_SURFACE + PKG_CHECK_MODULES(PNG, libpng12, + [PNG_REQUIRES=libpng12],[ + PKG_CHECK_MODULES(PNG, libpng10, + [PNG_REQUIRES=libpng10])]) + AM_CONDITIONAL(CAIRO_HAS_PNG_SURFACE, true) +fi + +AC_SUBST(PNG_SURFACE_FEATURE) +AC_SUBST(PNG_CFLAGS) +AC_SUBST(PNG_LIBS) +AC_SUBST(PNG_REQUIRES) dnl =========================================================================== PKG_CHECK_MODULES(FONTCONFIG, fontconfig) -PKG_CHECK_MODULES(CAIRO, slim >= 0.2.0 libic >= 0.1.3) +PKG_CHECK_MODULES(CAIRO, libpixman >= 0.1.0) # Test for freetype2 separate from pkg-config since at least up to # 2003-06-07, there was no freetype2.pc in the release. diff --git a/doc/reference/doc.xml b/doc/reference/doc.xml index 10dcd6258..1530ec957 100644 --- a/doc/reference/doc.xml +++ b/doc/reference/doc.xml @@ -11,6 +11,10 @@ <!ENTITY cairo_pop_group SYSTEM "xml/cairo_pop_group.xml"> <!ENTITY cairo_set_target_surface SYSTEM "xml/cairo_set_target_surface.xml"> <!ENTITY cairo_set_target_image SYSTEM "xml/cairo_set_target_image.xml"> +<!ENTITY cairo_set_target_ps SYSTEM "xml/cairo_set_target_ps.xml"> +<!ENTITY cairo_set_target_drawable SYSTEM "xml/cairo_set_target_drawable.xml"> +<!ENTITY cairo_set_target_xcb SYSTEM "xml/cairo_set_target_xcb.xml"> +<!ENTITY cairo_set_target_png SYSTEM "xml/cairo_set_target_png.xml"> <!ENTITY cairo_set_operator SYSTEM "xml/cairo_set_operator.xml"> <!ENTITY cairo_set_rgb_color SYSTEM "xml/cairo_set_rgb_color.xml"> <!ENTITY cairo_set_alpha SYSTEM "xml/cairo_set_alpha.xml"> @@ -34,8 +38,12 @@ <!ENTITY cairo_new_path SYSTEM "xml/cairo_new_path.xml"> <!ENTITY cairo_move_to SYSTEM "xml/cairo_move_to.xml"> <!ENTITY cairo_line_to SYSTEM "xml/cairo_line_to.xml"> +<!ENTITY cairo_arc SYSTEM "xml/cairo_arc.xml"> +<!ENTITY cairo_arc_negative SYSTEM "xml/cairo_arc_negative.xml"> <!ENTITY cairo_rel_move_to SYSTEM "xml/cairo_rel_move_to.xml"> <!ENTITY cairo_rel_line_to SYSTEM "xml/cairo_rel_line_to.xml"> +<!ENTITY cairo_rectangle SYSTEM "xml/cairo_rectangle.xml"> +<!ENTITY cairo_curve_to SYSTEM "xml/cairo_curve_to.xml"> <!ENTITY cairo_stroke_path SYSTEM "xml/cairo_stroke_path.xml"> <!ENTITY cairo_close_path SYSTEM "xml/cairo_close_path.xml"> <!ENTITY cairo_stroke SYSTEM "xml/cairo_stroke.xml"> @@ -44,6 +52,7 @@ <!ENTITY cairo_select_font SYSTEM "xml/cairo_select_font.xml"> <!ENTITY cairo_scale_font SYSTEM "xml/cairo_scale_font.xml"> <!ENTITY cairo_show_text SYSTEM "xml/cairo_show_text.xml"> +<!ENTITY cairo_text_extents SYSTEM "xml/cairo_text_extents.xml"> <!ENTITY cairo_current_operator SYSTEM "xml/cairo_current_operator.xml"> <!ENTITY cairo_current_rgb_color SYSTEM "xml/cairo_current_rgb_color.xml"> <!ENTITY cairo_current_alpha SYSTEM "xml/cairo_current_alpha.xml"> @@ -80,6 +89,10 @@ <!ENTITY cairo_matrix_t SYSTEM "xml/cairo_matrix_t.xml"> <!ENTITY cairo_surface_t SYSTEM "xml/cairo_surface_t.xml"> <!ENTITY cairo_format_t SYSTEM "xml/cairo_format_t.xml"> +<!ENTITY cairo_operator_t SYSTEM "xml/cairo_operator_t.xml"> +<!ENTITY cairo_fill_rule_t SYSTEM "xml/cairo_fill_rule_t.xml"> +<!ENTITY cairo_line_cap_t SYSTEM "xml/cairo_line_cap_t.xml"> +<!ENTITY cairo_text_extents_t SYSTEM "xml/cairo_text_extents_t.xml"> ]> <book lang="en"> <title>Cairo: A Vector Graphics Library</title> @@ -97,6 +110,10 @@ &cairo_pop_group; &cairo_set_target_surface; &cairo_set_target_image; +&cairo_set_target_ps; +&cairo_set_target_png; +&cairo_set_target_drawable; +&cairo_set_target_xcb; &cairo_set_operator; &cairo_set_rgb_color; &cairo_set_alpha; @@ -120,8 +137,12 @@ &cairo_new_path; &cairo_move_to; &cairo_line_to; +&cairo_arc; +&cairo_arc_negative; &cairo_rel_move_to; &cairo_rel_line_to; +&cairo_rectangle; +&cairo_curve_to; &cairo_stroke_path; &cairo_close_path; &cairo_stroke; @@ -130,6 +151,7 @@ &cairo_select_font; &cairo_scale_font; &cairo_show_text; +&cairo_text_extents; &cairo_current_operator; &cairo_current_rgb_color; &cairo_current_alpha; @@ -169,6 +191,10 @@ &cairo_matrix_t; &cairo_surface_t; &cairo_format_t; +&cairo_operator_t; +&cairo_fill_rule_t; +&cairo_line_cap_t; +&cairo_text_extents_t; </reference> </book> diff --git a/doc/reference/xml/cairo_arc.xml b/doc/reference/xml/cairo_arc.xml new file mode 100644 index 000000000..b8a391f9d --- /dev/null +++ b/doc/reference/xml/cairo_arc.xml @@ -0,0 +1,40 @@ +<refentry id="cairo_arc"> + <refmeta> + <refentrytitle>cairo_arc</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_arc</refname> + <refpurpose>some description</refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> + void cairo_arc (<link linkend="cairo_t">cairo_t</link> *cr, double xc, double yc, double radius, double angle1, double angle2);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>xc, yc</parameter> :</term> + <listitem> + <simpara>center of arc (a full arc makes a circle)</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_arc</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_arc_negative.xml b/doc/reference/xml/cairo_arc_negative.xml new file mode 100644 index 000000000..ece1af7f5 --- /dev/null +++ b/doc/reference/xml/cairo_arc_negative.xml @@ -0,0 +1,40 @@ +<refentry id="cairo_arc_negative"> + <refmeta> + <refentrytitle>cairo_arc_negative</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_arc_negative</refname> + <refpurpose>some description</refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> + void cairo_arc_negative (<link linkend="cairo_t">cairo_t</link> *cr, double xc, double yc, double radius, double angle1, double angle2);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>xc, yc</parameter> :</term> + <listitem> + <simpara>center of the arc</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_arc_negative</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_current_font.xml b/doc/reference/xml/cairo_current_font.xml new file mode 100644 index 000000000..3503b6db7 --- /dev/null +++ b/doc/reference/xml/cairo_current_font.xml @@ -0,0 +1,37 @@ + +<refentry id="cairo_current_font"> + <refmeta> + <refentrytitle>cairo_current_font</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_current_font</refname> + <refpurpose>some description</refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> + cairo_font_t * + cairo_current_font (<link linkend="cairo_t">cairo_t</link> *cr)</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_current_font</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + returns pointer to the current cairo_font_t object in the <link linkend="cairo_t">cairo_t</link> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_current_font_extents.xml b/doc/reference/xml/cairo_current_font_extents.xml new file mode 100644 index 000000000..822cd4049 --- /dev/null +++ b/doc/reference/xml/cairo_current_font_extents.xml @@ -0,0 +1,40 @@ +<refentry id="cairo_current_font_extents"> + <refmeta> + <refentrytitle>cairo_current_font_extents</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_current_font_extents</refname> + <refpurpose>some description</refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> +void cairo_current_font_extents (<link linkend="cairo_t">cairo_t</link> *cr, cairo_font_extents_t *extents)</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>extents</parameter> :</term> + <listitem> + <simpara>fills in a provided cairo_font_extents_t object</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_current_font_extents</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_curve_to.xml b/doc/reference/xml/cairo_curve_to.xml new file mode 100644 index 000000000..330ed3629 --- /dev/null +++ b/doc/reference/xml/cairo_curve_to.xml @@ -0,0 +1,70 @@ +<refentry id="cairo_curve_to"> + <refmeta> + <refentrytitle>cairo_curve_to</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_curve_to</refname> + <refpurpose>some description</refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> + void cairo_curve_to (<link linkend="cairo_t">cairo_t</link> *cr, double x1, double y1, double x2, double y2, double x3, double y3);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>x1</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>y1</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>x2</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>y2</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>x3</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>y3</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_curve_to</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_operator_t.xml b/doc/reference/xml/cairo_operator_t.xml index d8baf1708..b659bb9b2 100644 --- a/doc/reference/xml/cairo_operator_t.xml +++ b/doc/reference/xml/cairo_operator_t.xml @@ -14,46 +14,20 @@ <indexterm><primary>enums</primary> <secondary>cairo_operator_t</secondary></indexterm> <programlisting>typedef enum cairo_operator { - CAIRO_OPERATOR_CLEAR = PictOpClear, - CAIRO_OPERATOR_SRC = PictOpSrc, - CAIRO_OPERATOR_DST = PictOpDst, - CAIRO_OPERATOR_OVER = PictOpOver, - CAIRO_OPERATOR_OVER_REVERSE = PictOpOverReverse, - CAIRO_OPERATOR_IN = PictOpIn, - CAIRO_OPERATOR_IN_REVERSE = PictOpInReverse, - CAIRO_OPERATOR_OUT = PictOpOut, - CAIRO_OPERATOR_OUT_REVERSE = PictOpOutReverse, - CAIRO_OPERATOR_ATOP = PictOpAtop, - CAIRO_OPERATOR_ATOP_REVERSE = PictOpAtopReverse, - CAIRO_OPERATOR_XOR = PictOpXor, - CAIRO_OPERATOR_ADD = PictOpAdd, - CAIRO_OPERATOR_SATURATE = PictOpSaturate, - - CAIRO_OPERATOR_DISJOINT_CLEAR = PictOpDisjointClear, - CAIRO_OPERATOR_DISJOINT_SRC = PictOpDisjointSrc, - CAIRO_OPERATOR_DISJOINT_DST = PictOpDisjointDst, - CAIRO_OPERATOR_DISJOINT_OVER = PictOpDisjointOver, - CAIRO_OPERATOR_DISJOINT_OVER_REVERSE = PictOpDisjointOverReverse, - CAIRO_OPERATOR_DISJOINT_IN = PictOpDisjointIn, - CAIRO_OPERATOR_DISJOINT_IN_REVERSE = PictOpDisjointInReverse, - CAIRO_OPERATOR_DISJOINT_OUT = PictOpDisjointOut, - CAIRO_OPERATOR_DISJOINT_OUT_REVERSE = PictOpDisjointOutReverse, - CAIRO_OPERATOR_DISJOINT_ATOP = PictOpDisjointAtop, - CAIRO_OPERATOR_DISJOINT_ATOP_REVERSE = PictOpDisjointAtopReverse, - CAIRO_OPERATOR_DISJOINT_XOR = PictOpDisjointXor, - - CAIRO_OPERATOR_CONJOINT_CLEAR = PictOpConjointClear, - CAIRO_OPERATOR_CONJOINT_SRC = PictOpConjointSrc, - CAIRO_OPERATOR_CONJOINT_DST = PictOpConjointDst, - CAIRO_OPERATOR_CONJOINT_OVER = PictOpConjointOver, - CAIRO_OPERATOR_CONJOINT_OVER_REVERSE = PictOpConjointOverReverse, - CAIRO_OPERATOR_CONJOINT_IN = PictOpConjointIn, - CAIRO_OPERATOR_CONJOINT_IN_REVERSE = PictOpConjointInReverse, - CAIRO_OPERATOR_CONJOINT_OUT = PictOpConjointOut, - CAIRO_OPERATOR_CONJOINT_OUT_REVERSE = PictOpConjointOutReverse, - CAIRO_OPERATOR_CONJOINT_ATOP = PictOpConjointAtop, - CAIRO_OPERATOR_CONJOINT_ATOP_REVERSE = PictOpConjointAtopReverse, - CAIRO_OPERATOR_CONJOINT_XOR = PictOpConjointXor + CAIRO_OPERATOR_CLEAR, + CAIRO_OPERATOR_SRC, + CAIRO_OPERATOR_DST, + CAIRO_OPERATOR_OVER, + CAIRO_OPERATOR_OVER_REVERSE, + CAIRO_OPERATOR_IN, + CAIRO_OPERATOR_IN_REVERSE, + CAIRO_OPERATOR_OUT, + CAIRO_OPERATOR_OUT_REVERSE, + CAIRO_OPERATOR_ATOP, + CAIRO_OPERATOR_ATOP_REVERSE, + CAIRO_OPERATOR_XOR, + CAIRO_OPERATOR_ADD, + CAIRO_OPERATOR_SATURATE } cairo_operator_t; </programlisting> <para> diff --git a/doc/reference/xml/cairo_rectangle.xml b/doc/reference/xml/cairo_rectangle.xml new file mode 100644 index 000000000..bab307f32 --- /dev/null +++ b/doc/reference/xml/cairo_rectangle.xml @@ -0,0 +1,47 @@ +<refentry id="cairo_rectangle"> + <refmeta> + <refentrytitle>cairo_rectangle</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_rectangle</refname> + <refpurpose>some description</refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> + void cairo_rectangle (<link linkend="cairo_t">cairo_t</link> *cr, double x, double y, double width, double height);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>x, y</parameter> :</term> + <listitem> + <simpara>coordinates of the left top corner</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>width, height</parameter> :</term> + <listitem> + <simpara>width and height of the rectangle</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_rectangle</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + The current line style applies to the lines of the rectangle. + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_rel_curve_to.xml b/doc/reference/xml/cairo_rel_curve_to.xml new file mode 100644 index 000000000..c16f85ff2 --- /dev/null +++ b/doc/reference/xml/cairo_rel_curve_to.xml @@ -0,0 +1,70 @@ +<refentry id="cairo_curve_to"> + <refmeta> + <refentrytitle><link linkend="cairo_curve_to">cairo_curve_to</link></refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname><link linkend="cairo_curve_to">cairo_curve_to</link></refname> + <refpurpose>some description</refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> + void <link linkend="cairo_curve_to">cairo_curve_to</link> (<link linkend="cairo_t">cairo_t</link> *cr, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>dx1</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>dy1</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>dx2</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>dy2</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>dx3</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>dy3</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary><link linkend="cairo_curve_to">cairo_curve_to</link></secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_select_font.xml b/doc/reference/xml/cairo_select_font.xml index 09d55925f..36bd782f8 100644 --- a/doc/reference/xml/cairo_select_font.xml +++ b/doc/reference/xml/cairo_select_font.xml @@ -10,7 +10,7 @@ </refnamediv> <refsynopsisdiv> <programlisting> -void cairo_select_font (<link linkend="cairo_t">cairo_t</link> *cr, const char *key)</programlisting> +void cairo_select_font (<link linkend="cairo_t">cairo_t</link> *cr, const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight);</programlisting> <variablelist role="params"> <varlistentry> <term><parameter>cr</parameter> :</term> @@ -19,9 +19,21 @@ void cairo_select_font (<link linkend="cairo_t">cairo_t</link> *cr, const char * </listitem> </varlistentry> <varlistentry> - <term><parameter>key</parameter> :</term> + <term><parameter>family</parameter> :</term> <listitem> - <simpara>description</simpara> + <simpara>name for the font family (e.g. XXX)</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>slant</parameter> :</term> + <listitem> + <simpara>see cairo_font_slant_t for valid values</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>weight</parameter> :</term> + <listitem> + <simpara>see cairo_font_weight_t for valid values</simpara> </listitem> </varlistentry> </variablelist> diff --git a/doc/reference/xml/cairo_set_font.xml b/doc/reference/xml/cairo_set_font.xml new file mode 100644 index 000000000..31661494e --- /dev/null +++ b/doc/reference/xml/cairo_set_font.xml @@ -0,0 +1,40 @@ +<refentry id="cairo_set_font"> + <refmeta> + <refentrytitle>cairo_set_font</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_set_font</refname> + <refpurpose>replace the font in the current state</refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> +void cairo_set_font (<link linkend="cairo_t">cairo_t</link> *cr, cairo_font_t *font)</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>font</parameter> :</term> + <listitem> + <simpara>replaces the current cairo_font_t object in the <link linkend="cairo_t">cairo_t</link> with font. The replaced font in the <link linkend="cairo_t">cairo_t</link> will be destroyed if there are no other references to it.</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_set_font</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_set_target_drawable.xml b/doc/reference/xml/cairo_set_target_drawable.xml new file mode 100644 index 000000000..febabb554 --- /dev/null +++ b/doc/reference/xml/cairo_set_target_drawable.xml @@ -0,0 +1,45 @@ +<refentry id="cairo_set_target_drawable"> + <refmeta> + <refentrytitle>cairo_set_target_drawable</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_set_target_drawable</refname> + <refpurpose>set surface for painting operations </refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting>void cairo_set_target_drawable (<link linkend="cairo_t">cairo_t</link> *cr, Display *dpy, Drawable drawable);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>dpy</parameter> :</term> + <listitem> + <simpara>X Display</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>drawable</parameter> :</term> + <listitem> + <simpara>an X onscreen or offscreen drawable</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_set_target_drawable</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_set_target_image.xml b/doc/reference/xml/cairo_set_target_image.xml new file mode 100644 index 000000000..b96a5fbdc --- /dev/null +++ b/doc/reference/xml/cairo_set_target_image.xml @@ -0,0 +1,58 @@ +<refentry id="cairo_set_target_image"> + <refmeta> + <refentrytitle>cairo_set_target_image</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_set_target_image</refname> + <refpurpose>set image for painting operations </refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> +void cairo_set_target_image (<link linkend="cairo_t">cairo_t</link> *cr,char *data, <link linkend="cairo_format_t">cairo_format_t</link> format, int width, int height, int stride)</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>data</parameter> :</term> + <listitem> + <simpara>pointer to an user-allocated buffer of appropriate size</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>format</parameter> :</term> + <listitem> + <simpara>select color-format of image</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>width, height</parameter></term> + <listitem> + <simpara>width and height describe the visibles image size.</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>stride</parameter></term> + <listitem> + <simpara>stride is the actual with of the image and can be larger than with. It is requiered even if stride is equal to with.</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_set_target_image</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_set_target_png.xml b/doc/reference/xml/cairo_set_target_png.xml new file mode 100644 index 000000000..8577fa160 --- /dev/null +++ b/doc/reference/xml/cairo_set_target_png.xml @@ -0,0 +1,51 @@ +<refentry id="cairo_set_target_png"> + <refmeta> + <refentrytitle>cairo_set_target_png</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_set_target_png</refname> + <refpurpose>set surface for painting operations </refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting>void cairo_set_target_png (<link linkend="cairo_t">cairo_t</link> *cr, FILE *file, <link linkend="cairo_format_t">cairo_format_t</link> format, int width, int height);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>FILE</parameter> :</term> + <listitem> + <simpara>an open, writeable file</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter><link linkend="cairo_format_t">cairo_format_t</link></parameter> :</term> + <listitem> + <simpara>determines the color-depth of the resulting png image</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>width, height</parameter> :</term> + <listitem> + <simpara>sets width and height of resulting png image </simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_set_target_png</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_set_target_ps.xml b/doc/reference/xml/cairo_set_target_ps.xml new file mode 100644 index 000000000..b1211a9d8 --- /dev/null +++ b/doc/reference/xml/cairo_set_target_ps.xml @@ -0,0 +1,52 @@ +<refentry id="cairo_set_target_ps"> + <refmeta> + <refentrytitle>cairo_set_target_ps</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_set_target_ps</refname> + <refpurpose>set surface for painting operations </refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> +void cairo_set_target_ps (<link linkend="cairo_t">cairo_t</link> *cr,FILE *file, double width_inches, double height_inches, double x_pixels_per_inch, double y_pixels_per_inch);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>FILE</parameter> :</term> + <listitem> + <simpara>an open, writeable file</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>width_inches, height_inches</parameter> :</term> + <listitem> + <simpara>width and height of an output page in inches</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>x_pixels_per_inch, y_pixels_per_inch</parameter> :</term> + <listitem> + <simpara>Resolution of the postscript file. Right now cairo dumps an entire image on every page, so this parameters define the resolution of the resulting image.</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_set_target_ps</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_set_target_surface.xml b/doc/reference/xml/cairo_set_target_surface.xml index 1619b40c0..473df3fe9 100644 --- a/doc/reference/xml/cairo_set_target_surface.xml +++ b/doc/reference/xml/cairo_set_target_surface.xml @@ -35,7 +35,7 @@ void cairo_set_target_surface (<link linkend="cairo_t">cairo_t</link> *cr, <link <indexterm> <primary/> </indexterm> -Selects <varname>surfacee</varname> as the surface to draw on. If there already is a surface set, it will be substituted by <varname>surface</varname>. It references <varname>surface</varname>e to ensure that it will be calid at least until another surface was selected or the <link linkend="cairo_t">cairo_t</link> is destroyed. +Selects <varname>surface</varname> as the surface to draw on. If there already is a surface set, it will be substituted by <varname>surface</varname>. It references <varname>surface</varname>e to ensure that it will be valid at least until another surface was selected or the <link linkend="cairo_t">cairo_t</link> is destroyed. </para> </refsect1> </refentry> diff --git a/doc/reference/xml/cairo_set_target_xcb.xml b/doc/reference/xml/cairo_set_target_xcb.xml new file mode 100644 index 000000000..d7bd2b05f --- /dev/null +++ b/doc/reference/xml/cairo_set_target_xcb.xml @@ -0,0 +1,58 @@ +<refentry id="cairo_set_target_xcb"> + <refmeta> + <refentrytitle>cairo_set_target_xcb</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_set_target_xcb</refname> + <refpurpose>set surface for painting operations </refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting>void +cairo_set_target_xcb (<link linkend="cairo_t">cairo_t</link> *cr, XCBConnection *dpy, DRAWABLE drawable, VISUALTYPE *visual, <link linkend="cairo_format_t">cairo_format_t</link> format);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>dpy</parameter> :</term> + <listitem> + <simpara>...</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>drawable</parameter> :</term> + <listitem> + <simpara>an X onscreen or offscreen drawable</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>visual</parameter> :</term> + <listitem> + <simpara>...</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>format</parameter> :</term> + <listitem> + <simpara>...</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_set_target_xcb</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_show_glyphs.xml b/doc/reference/xml/cairo_show_glyphs.xml new file mode 100644 index 000000000..aab0de1de --- /dev/null +++ b/doc/reference/xml/cairo_show_glyphs.xml @@ -0,0 +1,46 @@ +<refentry id="cairo_show_glyphs"> + <refmeta> + <refentrytitle>cairo_show_glyphs</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_show_glyphs</refname> + <refpurpose>some description</refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> +void cairo_show_glyphs (<link linkend="cairo_t">cairo_t</link> *cr, cairo_glyph_t *glyphs, int num_glyphs);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>glyphs</parameter> :</term> + <listitem> + <simpara></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>num_glyphs</parameter> :</term> + <listitem> + <simpara></simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_show_glyphs</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_show_text.xml b/doc/reference/xml/cairo_show_text.xml index 22eaef4d0..db16c9704 100644 --- a/doc/reference/xml/cairo_show_text.xml +++ b/doc/reference/xml/cairo_show_text.xml @@ -15,13 +15,13 @@ void cairo_show_text (<link linkend="cairo_t">cairo_t</link> *cr, const unsigned <varlistentry> <term><parameter>cr</parameter> :</term> <listitem> - <simpara>description</simpara> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> </listitem> </varlistentry> <varlistentry> <term><parameter>utf8</parameter> :</term> <listitem> - <simpara>description</simpara> + <simpara>text to show</simpara> </listitem> </varlistentry> </variablelist> diff --git a/doc/reference/xml/cairo_text_extents.xml b/doc/reference/xml/cairo_text_extents.xml new file mode 100644 index 000000000..fcb359304 --- /dev/null +++ b/doc/reference/xml/cairo_text_extents.xml @@ -0,0 +1,47 @@ + +<refentry id="cairo_text_extents"> + <refmeta> + <refentrytitle>cairo_text_extents</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_text_extents</refname> + <refpurpose>determine extents of a utf8 string</refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting>void cairo_text_extents (<link linkend="cairo_t">cairo_t</link> *ct, const unsigned char *utf8, <link linkend="cairo_text_extents_t">cairo_text_extents_t</link> *extents);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_t">cairo_t</link></simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>utf8</parameter> :</term> + <listitem> + <simpara>utf8 encoded string</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>extents</parameter> :</term> + <listitem> + <simpara>a <link linkend="cairo_text_extents_t">cairo_text_extents_t</link> structure</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_text_extents</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_text_extents_t.xml b/doc/reference/xml/cairo_text_extents_t.xml new file mode 100644 index 000000000..80e8534d5 --- /dev/null +++ b/doc/reference/xml/cairo_text_extents_t.xml @@ -0,0 +1,29 @@ + +<refentry id="cairo_text_extents_t"> + <refmeta> + <refentrytitle>cairo_text_extents_t</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_text_extents_t</refname> + <refpurpose>struct to store extents of a string</refpurpose> + </refnamediv> + <refsect1> + <title>Description</title> + <para><indexterm><primary>types</primary><secondary>cairo_text_extents_t</secondary></indexterm><indexterm><primary/></indexterm> + <programlisting> + typedef struct { + double x_bearing; + double y_bearing; + double width; + double height; + double x_advance; + double y_advance; + } cairo_text_extents_t; + </programlisting> + </para> + <para> + XXX. not sure what the status is right know. + </para> + </refsect1> +</refentry> diff --git a/doc/reference/xml/cairo_transform_font.xml b/doc/reference/xml/cairo_transform_font.xml new file mode 100644 index 000000000..d348d9b54 --- /dev/null +++ b/doc/reference/xml/cairo_transform_font.xml @@ -0,0 +1,41 @@ + +<refentry id="cairo_transform_font"> + <refmeta> + <refentrytitle>cairo_transform_font</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + <refnamediv> + <refname>cairo_transform_font</refname> + <refpurpose>set transformation matrix for individual glyphs</refpurpose> + </refnamediv> + <refsynopsisdiv> + <programlisting> + void cairo_transform_font (<link linkend="cairo_t">cairo_t</link> *cr, <link linkend="cairo_matrix_t">cairo_matrix_t</link> *matrix);</programlisting> + <variablelist role="params"> + <varlistentry> + <term><parameter>cr</parameter> :</term> + <listitem> + <simpara>description</simpara> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>matrix</parameter> :</term> + <listitem> + <simpara>an affine transformation matrix</simpara> + </listitem> + </varlistentry> + </variablelist> + </refsynopsisdiv> + <refsect1> + <title>Description</title> + <para> + <indexterm> + <primary>functions</primary> + <secondary>cairo_transform_font</secondary> + </indexterm> + <indexterm> + <primary/> + </indexterm> + </para> + </refsect1> +</refentry> diff --git a/src/Makefile.am b/src/Makefile.am index 2ed7341b5..518e69f21 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,12 +1,29 @@ lib_LTLIBRARIES = libcairo.la include_HEADERS = cairo.h cairo-features.h +if CAIRO_HAS_PS_SURFACE +libcairo_ps_sources = cairo_ps_surface.c +endif + +if CAIRO_HAS_PNG_SURFACE +libcairo_png_sources = cairo_png_surface.c +endif + if CAIRO_HAS_XLIB_SURFACE libcairo_xlib_sources = cairo_xlib_surface.c -else -libcairo_xlib_sources = endif +if CAIRO_HAS_XCB_SURFACE +libcairo_xcb_sources = cairo_xcb_surface.c +endif + +# These names match automake style variable definition conventions so +# without these lines, automake will complain during the handling of +# the libcairo_la_LIBADD below. (The INCLUDES is an autoconf only +# term and automake does not care about it) +FONTCONFIG_LIBS=@FONTCONFIG_LIBS@ +XRENDER_LIBS=@XRENDER_LIBS@ + libcairo_la_SOURCES = \ cairo.c \ cairo.h \ @@ -24,16 +41,19 @@ libcairo_la_SOURCES = \ cairo_path_stroke.c \ cairo_pen.c \ cairo_polygon.c \ - cairo_ps_surface.c \ cairo_slope.c \ cairo_spline.c \ cairo_surface.c \ cairo_traps.c \ + cairo_pattern.c \ + $(libcairo_ps_sources) \ + $(libcairo_png_sources) \ $(libcairo_xlib_sources)\ + $(libcairo_xcb_sources) \ cairoint.h -libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ +libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined -INCLUDES = $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(X_CFLAGS) +INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(XCB_CFLAGS) $(PNG_CFLAGS) -libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(X_LIBS) -lm +libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(XCB_LIBS) $(PS_LIBS) $(PNG_LIBS) -lm diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in index 9d83d0705..e9dacad51 100644 --- a/src/cairo-features.h.in +++ b/src/cairo-features.h.in @@ -28,6 +28,12 @@ #ifndef _CAIRO_CONFIG_H_ #define _CAIRO_CONFIG_H_ +#define @PS_SURFACE_FEATURE@ + +#define @PNG_SURFACE_FEATURE@ + #define @XLIB_SURFACE_FEATURE@ +#define @XCB_SURFACE_FEATURE@ + #endif diff --git a/src/cairo-fixed.c b/src/cairo-fixed.c index 330885467..9a7e7bc47 100644 --- a/src/cairo-fixed.c +++ b/src/cairo-fixed.c @@ -39,8 +39,15 @@ _cairo_fixed_from_double (double d) return (cairo_fixed_t) (d * 65536); } +cairo_fixed_t +_cairo_fixed_from_26_6 (uint32_t i) +{ + return i << 10; +} + double _cairo_fixed_to_double (cairo_fixed_t f) { return ((double) f) / 65536.0; } + diff --git a/src/cairo-font.c b/src/cairo-font.c index f6bf390a9..157ebedbe 100644 --- a/src/cairo-font.c +++ b/src/cairo-font.c @@ -28,12 +28,18 @@ #include "cairoint.h" cairo_font_t * -_cairo_font_create (char *family, +_cairo_font_create (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT; + /* XXX: The current freetype backend may return NULL, (for example + * if no fonts are installed), but I would like to guarantee that + * the toy API always returns at least *some* font, so I would + * like to build in some sort fo font here, (even a really lame, + * ugly one if necessary). */ + return backend->create (family, slant, weight); } @@ -118,31 +124,30 @@ _cairo_font_show_glyphs (cairo_font_t *font, cairo_operator_t operator, cairo_surface_t *source, cairo_surface_t *surface, - double x, - double y, cairo_glyph_t *glyphs, int num_glyphs) { return font->backend->show_glyphs(font, operator, source, - surface, x, y, glyphs, num_glyphs); + surface, glyphs, num_glyphs); } cairo_status_t _cairo_font_text_path (cairo_font_t *font, - cairo_path_t *path, - const unsigned char *utf8) + double x, + double y, + const unsigned char *utf8, + cairo_path_t *path) { - return font->backend->text_path(font, path, utf8); + return font->backend->text_path(font, x, y, utf8, path); } cairo_status_t _cairo_font_glyph_path (cairo_font_t *font, - cairo_path_t *path, cairo_glyph_t *glyphs, - int num_glyphs) + int num_glyphs, + cairo_path_t *path) { - return font->backend->glyph_path(font, path, - glyphs, num_glyphs); + return font->backend->glyph_path(font, glyphs, num_glyphs, path); } cairo_status_t diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index c3e4306d7..77cf59b0d 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -25,7 +25,10 @@ #include "cairoint.h" #include <fontconfig/fontconfig.h> #include <fontconfig/fcfreetype.h> -#include <freetype/freetype.h> + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_OUTLINE_H typedef struct { cairo_font_t base; @@ -39,13 +42,10 @@ typedef struct { FcPattern *pattern; } cairo_ft_font_t; - -#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 63.0)) -#define DOUBLE_FROM_26_6(t) (((double)((t) >> 6)) \ - + ((double)((t) & 0x3F) / 63.0)) -#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65535.0)) -#define DOUBLE_FROM_16_16(t) (((double)((t) >> 16)) \ - + ((double)((t) & 0xFFFF) / 65535.0)) +#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0)) +#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) +#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) +#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) /* implement the platform-specific interface */ @@ -101,29 +101,31 @@ cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern) } FT_Face -cairo_ft_font_face (cairo_font_t *font) +cairo_ft_font_face (cairo_font_t *abstract_font) { + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + if (font == NULL) return NULL; - return ((cairo_ft_font_t *) font)->face; + return font->face; } FcPattern * -cairo_ft_font_pattern (cairo_font_t *font) +cairo_ft_font_pattern (cairo_font_t *abstract_font) { + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + if (font == NULL) return NULL; - return ((cairo_ft_font_t *) font)->pattern; + return font->pattern; } - - /* implement the backend interface */ static cairo_font_t * -_cairo_ft_font_create (char *family, +_cairo_ft_font_create (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { @@ -175,6 +177,9 @@ _cairo_ft_font_create (char *family, } font = cairo_ft_font_create (ft_library, pat); + if (font == NULL) + return NULL; + ft_font = (cairo_ft_font_t *) font; ft_font->owns_ft_library = 1; @@ -188,45 +193,43 @@ _cairo_ft_font_create (char *family, return font; } - static cairo_font_t * -_cairo_ft_font_copy (cairo_font_t *font) +_cairo_ft_font_copy (void *abstract_font) { - cairo_ft_font_t * ft_font_new = NULL; - cairo_ft_font_t * ft_font = NULL; + cairo_ft_font_t * font_new = NULL; + cairo_ft_font_t * font = abstract_font; - ft_font = (cairo_ft_font_t *)font; + if (font->base.backend != &cairo_ft_font_backend) + return NULL; - ft_font_new = (cairo_ft_font_t *)cairo_ft_font_create_for_ft_face (ft_font->face); - if (ft_font_new == NULL) + font_new = (cairo_ft_font_t *) cairo_ft_font_create_for_ft_face (font->face); + if (font_new == NULL) return NULL; - if (ft_font_new != NULL && ft_font->pattern != NULL) - ft_font_new->pattern = FcPatternDuplicate (ft_font->pattern); + if (font_new != NULL && font->pattern != NULL) + font_new->pattern = FcPatternDuplicate (font->pattern); - return (cairo_font_t *)ft_font_new; + return (cairo_font_t *) font_new; } static void -_cairo_ft_font_destroy (cairo_font_t *font) +_cairo_ft_font_destroy (void *abstract_font) { - cairo_ft_font_t * ft_font = NULL; + cairo_ft_font_t * font = abstract_font; if (font == NULL) return; - ft_font = (cairo_ft_font_t *)font; - - if (ft_font->face != NULL && ft_font->owns_face) - FT_Done_Face (ft_font->face); + if (font->face != NULL && font->owns_face) + FT_Done_Face (font->face); - if (ft_font->pattern != NULL) - FcPatternDestroy (ft_font->pattern); + if (font->pattern != NULL) + FcPatternDestroy (font->pattern); - if (ft_font->ft_library && ft_font->owns_ft_library) - FT_Done_FreeType (ft_font->ft_library); + if (font->ft_library && font->owns_ft_library) + FT_Done_FreeType (font->ft_library); - free (ft_font); + free (font); } static void @@ -260,21 +263,7 @@ _utf8_to_ucs4 (char const *utf8, len -= step; utf8 += step; } - *nchars = alloc; -} - -static void -_get_scale_factors(cairo_matrix_t *matrix, double *sx, double *sy) -{ - double e0, e1; - e1 = 1.; e0 = 0.; - - cairo_matrix_transform_distance (matrix, &e1, &e0); - *sx = sqrt(e1*e1 + e0*e0); - - e1 = 1.; e0 = 0.; - cairo_matrix_transform_distance (matrix, &e0, &e1); - *sy = sqrt(e1*e1 + e0*e0); + *nchars = n; } static void @@ -292,7 +281,7 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face) * transformation. */ - _get_scale_factors(matrix, &scale_x, &scale_y); + _cairo_matrix_compute_scale_factors (matrix, &scale_x, &scale_y); cairo_matrix_copy (&normalized, matrix); @@ -314,23 +303,19 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face) 0, 0); } - static int -_utf8_to_glyphs (cairo_font_t *font, - const unsigned char *utf8, - cairo_glyph_t **glyphs, - size_t *nglyphs) +_utf8_to_glyphs (cairo_ft_font_t *font, + const unsigned char *utf8, + double x0, + double y0, + cairo_glyph_t **glyphs, + size_t *nglyphs) { - cairo_ft_font_t *ft; + FT_Face face = font->face; double x = 0., y = 0.; size_t i; FT_ULong *ucs4 = NULL; - if (font == NULL) - return 0; - - ft = (cairo_ft_font_t *)font; - _utf8_to_ucs4 (utf8, &ucs4, nglyphs); if (ucs4 == NULL) @@ -343,18 +328,18 @@ _utf8_to_glyphs (cairo_font_t *font, return 0; } - _install_font_matrix (&font->matrix, ft->face); + _install_font_matrix (&font->base.matrix, face); for (i = 0; i < *nglyphs; i++) { - (*glyphs)[i].index = FT_Get_Char_Index (ft->face, ucs4[i]); - (*glyphs)[i].x = x; - (*glyphs)[i].y = y; + (*glyphs)[i].index = FT_Get_Char_Index (face, ucs4[i]); + (*glyphs)[i].x = x0 + x; + (*glyphs)[i].y = y0 + y; - FT_Load_Glyph (ft->face, (*glyphs)[i].index, FT_LOAD_DEFAULT); + FT_Load_Glyph (face, (*glyphs)[i].index, FT_LOAD_DEFAULT); - x += DOUBLE_FROM_26_6 (ft->face->glyph->advance.x); - y -= DOUBLE_FROM_26_6 (ft->face->glyph->advance.y); + x += DOUBLE_FROM_26_6 (face->glyph->advance.x); + y -= DOUBLE_FROM_26_6 (face->glyph->advance.y); } free (ucs4); @@ -362,51 +347,114 @@ _utf8_to_glyphs (cairo_font_t *font, } static cairo_status_t -_cairo_ft_font_font_extents (cairo_font_t *font, - cairo_font_extents_t *extents) +_cairo_ft_font_font_extents (void *abstract_font, + cairo_font_extents_t *extents) { + cairo_ft_font_t *font = abstract_font; + FT_Face face = font->face; double scale_x, scale_y; - cairo_ft_font_t *ft = (cairo_ft_font_t *)font; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - _get_scale_factors(&font->matrix, &scale_x, &scale_y); + double upm = face->units_per_EM; -#define FONT_UNIT_TO_DEV(x) ((double)(x) / (double)(ft->face->units_per_EM)) + _cairo_matrix_compute_scale_factors (&font->base.matrix, &scale_x, &scale_y); - extents->ascent = FONT_UNIT_TO_DEV(ft->face->ascender) * scale_y; - extents->descent = FONT_UNIT_TO_DEV(ft->face->descender) * scale_y; - extents->height = FONT_UNIT_TO_DEV(ft->face->height) * scale_y; - extents->max_x_advance = FONT_UNIT_TO_DEV(ft->face->max_advance_width) * scale_x; - extents->max_y_advance = FONT_UNIT_TO_DEV(ft->face->max_advance_height) * scale_y; - return status; + extents->ascent = face->ascender / upm * scale_y; + extents->descent = face->descender / upm * scale_y; + extents->height = face->height / upm * scale_y; + extents->max_x_advance = face->max_advance_width / upm * scale_x; + extents->max_y_advance = face->max_advance_height / upm * scale_y; + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_ft_font_glyph_extents (cairo_font_t *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents) +_cairo_ft_font_glyph_extents (void *abstract_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) { - cairo_ft_font_t *ft; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + int i; + cairo_ft_font_t *font = abstract_font; + cairo_point_double_t origin; + cairo_point_double_t glyph_min, glyph_max; + cairo_point_double_t total_min, total_max; + FT_Error error; + FT_Face face = font->face; + FT_GlyphSlot glyph = face->glyph; + FT_Glyph_Metrics *metrics = &glyph->metrics; - ft = (cairo_ft_font_t *)font; + if (num_glyphs == 0) + { + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + extents->x_advance = 0.0; + extents->y_advance = 0.0; + + return CAIRO_STATUS_SUCCESS; + } - /* FIXME: lift code from xft to do this */ + origin.x = glyphs[0].x; + origin.y = glyphs[0].y; - return status; + _install_font_matrix (&font->base.matrix, face); + + for (i = 0; i < num_glyphs; i++) + { + error = FT_Load_Glyph (face, glyphs[i].index, FT_LOAD_DEFAULT); + /* XXX: What to do in this error case? */ + if (error) + continue; + + /* XXX: Need to add code here to check the font's FcPattern + for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y + instead. This will require that + cairo_ft_font_create_for_ft_face accept an + FcPattern. */ + glyph_min.x = glyphs[i].x + DOUBLE_FROM_26_6 (metrics->horiBearingX); + glyph_min.y = glyphs[i].y - DOUBLE_FROM_26_6 (metrics->horiBearingY); + glyph_max.x = glyph_min.x + DOUBLE_FROM_26_6 (metrics->width); + glyph_max.y = glyph_min.y + DOUBLE_FROM_26_6 (metrics->height); + + if (i==0) { + total_min = glyph_min; + total_max = glyph_max; + } else { + if (glyph_min.x < total_min.x) + total_min.x = glyph_min.x; + if (glyph_min.y < total_min.y) + total_min.y = glyph_min.y; + + if (glyph_max.x > total_max.x) + total_max.x = glyph_max.x; + if (glyph_max.y > total_max.y) + total_max.y = glyph_max.y; + } + } + + extents->x_bearing = total_min.x - origin.x; + extents->y_bearing = total_min.y - origin.y; + extents->width = total_max.x - total_min.x; + extents->height = total_max.y - total_min.y; + extents->x_advance = glyphs[i-1].x + DOUBLE_FROM_26_6 (metrics->horiAdvance) - origin.x; + extents->y_advance = glyphs[i-1].y + 0 - origin.y; + + return CAIRO_STATUS_SUCCESS; } + static cairo_status_t -_cairo_ft_font_text_extents (cairo_font_t *font, - const unsigned char *utf8, - cairo_text_extents_t *extents) +_cairo_ft_font_text_extents (void *abstract_font, + const unsigned char *utf8, + cairo_text_extents_t *extents) { + cairo_ft_font_t *font = abstract_font; cairo_glyph_t *glyphs; size_t nglyphs; cairo_status_t status = CAIRO_STATUS_SUCCESS; - if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs)) + if (_utf8_to_glyphs (font, utf8, 0, 0, &glyphs, &nglyphs)) { status = _cairo_ft_font_glyph_extents (font, glyphs, nglyphs, extents); @@ -414,24 +462,22 @@ _cairo_ft_font_text_extents (cairo_font_t *font, } return status; } - - static cairo_status_t -_cairo_ft_font_show_glyphs (cairo_font_t *font, +_cairo_ft_font_show_glyphs (void *abstract_font, cairo_operator_t operator, cairo_surface_t *source, cairo_surface_t *surface, - double x0, - double y0, const cairo_glyph_t *glyphs, int num_glyphs) { + cairo_ft_font_t *font = abstract_font; cairo_status_t status; int i; cairo_ft_font_t *ft = NULL; FT_GlyphSlot glyphslot; cairo_surface_t *mask = NULL; + cairo_point_double_t origin; double x, y; int width, height, stride; @@ -444,22 +490,27 @@ _cairo_ft_font_show_glyphs (cairo_font_t *font, ft = (cairo_ft_font_t *)font; glyphslot = ft->face->glyph; - _install_font_matrix (&font->matrix, ft->face); + _install_font_matrix (&font->base.matrix, ft->face); for (i = 0; i < num_glyphs; i++) { unsigned char *bitmap; FT_Load_Glyph (ft->face, glyphs[i].index, FT_LOAD_DEFAULT); - FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL); + FT_Render_Glyph (glyphslot, ft_render_mode_normal); width = glyphslot->bitmap.width; height = glyphslot->bitmap.rows; stride = glyphslot->bitmap.pitch; bitmap = glyphslot->bitmap.buffer; - x = x0 + glyphs[i].x; - y = y0 + glyphs[i].y; + x = glyphs[i].x; + y = glyphs[i].y; + + if (i == 0) { + origin.x = x; + origin.y = y; + } /* X gets upset with zero-sized images (such as whitespace) */ if (width * height == 0) @@ -502,11 +553,14 @@ _cairo_ft_font_show_glyphs (cairo_font_t *font, return CAIRO_STATUS_NO_MEMORY; } - status = _cairo_surface_composite (operator, source, mask, surface, - 0, 0, 0, 0, - x + glyphslot->bitmap_left, - y - glyphslot->bitmap_top, - (double)width, (double)height); + status = + _cairo_surface_composite (operator, source, mask, surface, + -origin.x + x + glyphslot->bitmap_left, + -origin.y + y - glyphslot->bitmap_top, + 0, 0, + x + glyphslot->bitmap_left, + y - glyphslot->bitmap_top, + (double) width, (double) height); cairo_surface_destroy (mask); if (bitmap != glyphslot->bitmap.buffer) @@ -519,7 +573,7 @@ _cairo_ft_font_show_glyphs (cairo_font_t *font, } static cairo_status_t -_cairo_ft_font_show_text (cairo_font_t *font, +_cairo_ft_font_show_text (void *abstract_font, cairo_operator_t operator, cairo_surface_t *source, cairo_surface_t *surface, @@ -527,15 +581,16 @@ _cairo_ft_font_show_text (cairo_font_t *font, double y0, const unsigned char *utf8) { + cairo_ft_font_t *font = abstract_font; cairo_glyph_t *glyphs; - size_t nglyphs; + int num_glyphs; - if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs)) + if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) { cairo_status_t res; res = _cairo_ft_font_show_glyphs (font, operator, - source, surface, x0, y0, - glyphs, nglyphs); + source, surface, + glyphs, num_glyphs); free (glyphs); return res; } @@ -543,35 +598,147 @@ _cairo_ft_font_show_text (cairo_font_t *font, return CAIRO_STATUS_NO_MEMORY; } +static int +_move_to (FT_Vector *to, void *closure) +{ + cairo_path_t *path = closure; + cairo_point_t point; + + point.x = _cairo_fixed_from_26_6 (to->x); + point.y = _cairo_fixed_from_26_6 (to->y); + + _cairo_path_close_path (path); + _cairo_path_move_to (path, &point); + + return 0; +} + +static int +_line_to (FT_Vector *to, void *closure) +{ + cairo_path_t *path = closure; + cairo_point_t point; + + point.x = _cairo_fixed_from_26_6 (to->x); + point.y = _cairo_fixed_from_26_6 (to->y); + + _cairo_path_line_to (path, &point); + + return 0; +} + +static int +_conic_to (FT_Vector *control, FT_Vector *to, void *closure) +{ + cairo_path_t *path = closure; + + cairo_point_t p0, p1, p2, p3; + cairo_point_t conic; + + _cairo_path_current_point (path, &p0); + + conic.x = _cairo_fixed_from_26_6 (control->x); + conic.y = _cairo_fixed_from_26_6 (control->y); + + p3.x = _cairo_fixed_from_26_6 (to->x); + p3.y = _cairo_fixed_from_26_6 (to->y); + + p1.x = p0.x + 2.0/3.0 * (conic.x - p0.x); + p1.y = p0.y + 2.0/3.0 * (conic.y - p0.y); + + p2.x = p3.x + 2.0/3.0 * (conic.x - p3.x); + p2.y = p3.y + 2.0/3.0 * (conic.y - p3.y); + + _cairo_path_curve_to (path, + &p1, &p2, &p3); + + return 0; +} + +static int +_cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closure) +{ + cairo_path_t *path = closure; + cairo_point_t p0, p1, p2; + + p0.x = _cairo_fixed_from_26_6 (control1->x); + p0.y = _cairo_fixed_from_26_6 (control1->y); + + p1.x = _cairo_fixed_from_26_6 (control2->x); + p1.y = _cairo_fixed_from_26_6 (control2->y); + + p2.x = _cairo_fixed_from_26_6 (to->x); + p2.y = _cairo_fixed_from_26_6 (to->y); + + _cairo_path_curve_to (path, &p0, &p1, &p2); + + return 0; +} static cairo_status_t -_cairo_ft_font_glyph_path (cairo_font_t *font, - cairo_path_t *path, - cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_ft_font_glyph_path (void *abstract_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_ft_font_t *ft; - - ft = (cairo_ft_font_t *)font; - - /* FIXME: lift code from xft to do this */ + int i; + cairo_ft_font_t *font = abstract_font; + FT_GlyphSlot glyph; + FT_Error error; + FT_Outline_Funcs outline_funcs = { + _move_to, + _line_to, + _conic_to, + _cubic_to, + 0, /* shift */ + 0, /* delta */ + }; + + glyph = font->face->glyph; + _install_font_matrix (&font->base.matrix, font->face); + + for (i = 0; i < num_glyphs; i++) + { + FT_Matrix invert_y = { + DOUBLE_TO_16_16 (1.0), 0, + 0, DOUBLE_TO_16_16 (-1.0), + }; + + error = FT_Load_Glyph (font->face, glyphs[i].index, FT_LOAD_DEFAULT); + /* XXX: What to do in this error case? */ + if (error) + continue; + /* XXX: Do we want to support bitmap fonts here? */ + if (glyph->format == ft_glyph_format_bitmap) + continue; + + /* Font glyphs have an inverted Y axis compared to cairo. */ + FT_Outline_Transform (&glyph->outline, &invert_y); + FT_Outline_Translate (&glyph->outline, + DOUBLE_TO_26_6(glyphs[i].x), + DOUBLE_TO_26_6(glyphs[i].y)); + FT_Outline_Decompose (&glyph->outline, &outline_funcs, path); + } + _cairo_path_close_path (path); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_ft_font_text_path (cairo_font_t *font, - cairo_path_t *path, - const unsigned char *utf8) +_cairo_ft_font_text_path (void *abstract_font, + double x, + double y, + const unsigned char *utf8, + cairo_path_t *path) { + cairo_ft_font_t *font = abstract_font; cairo_glyph_t *glyphs; size_t nglyphs; - if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs)) + if (_utf8_to_glyphs (font, utf8, x, y, &glyphs, &nglyphs)) { cairo_status_t res; - res = _cairo_ft_font_glyph_path (font, path, glyphs, nglyphs); + res = _cairo_ft_font_glyph_path (font, glyphs, nglyphs, path); free (glyphs); return res; } @@ -579,7 +746,6 @@ _cairo_ft_font_text_path (cairo_font_t *font, return CAIRO_STATUS_NO_MEMORY; } - cairo_font_t * cairo_ft_font_create_for_ft_face (FT_Face face) { @@ -602,16 +768,15 @@ cairo_ft_font_create_for_ft_face (FT_Face face) return (cairo_font_t *) f; } - const struct cairo_font_backend cairo_ft_font_backend = { - font_extents: (void *) _cairo_ft_font_font_extents, - text_extents: (void *) _cairo_ft_font_text_extents, - glyph_extents: (void *) _cairo_ft_font_glyph_extents, - show_text: (void *) _cairo_ft_font_show_text, - show_glyphs: (void *) _cairo_ft_font_show_glyphs, - text_path: (void *) _cairo_ft_font_text_path, - glyph_path: (void *) _cairo_ft_font_glyph_path, - create: (void *) _cairo_ft_font_create, - copy: (void *) _cairo_ft_font_copy, - destroy: (void *) _cairo_ft_font_destroy + _cairo_ft_font_create, + _cairo_ft_font_copy, + _cairo_ft_font_destroy, + _cairo_ft_font_font_extents, + _cairo_ft_font_text_extents, + _cairo_ft_font_glyph_extents, + _cairo_ft_font_show_text, + _cairo_ft_font_show_glyphs, + _cairo_ft_font_text_path, + _cairo_ft_font_glyph_path, }; diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 8bc6e704a..ed8c8a1a8 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -30,15 +30,9 @@ #include "cairoint.h" -static void -_cairo_gstate_set_current_point (cairo_gstate_t *gstate, double x, double y); - -static cairo_status_t -_cairo_gstate_ensure_source (cairo_gstate_t *gstate); - static cairo_status_t _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, - cairo_surface_t *src, + cairo_pattern_t *src, cairo_operator_t operator, cairo_surface_t *dst, cairo_traps_t *traps); @@ -79,25 +73,20 @@ _cairo_gstate_init (cairo_gstate_t *gstate) CAIRO_FONT_WEIGHT_DEFAULT); gstate->surface = NULL; - gstate->source = NULL; - gstate->source_offset.x = 0.0; - gstate->source_offset.y = 0.0; - gstate->source_is_solid = 1; + gstate->clip.region = NULL; gstate->clip.surface = NULL; - + + gstate->pattern = _cairo_pattern_create_solid (1.0, 1.0, 1.0); + gstate->pattern_offset.x = 0.0; + gstate->pattern_offset.y = 0.0; gstate->alpha = 1.0; - _cairo_color_init (&gstate->color); gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT; _cairo_gstate_default_matrix (gstate); _cairo_path_init (&gstate->path); - gstate->current_point.x = 0.0; - gstate->current_point.y = 0.0; - gstate->has_current_point = 0; - _cairo_pen_init_empty (&gstate->pen_regular); gstate->next = NULL; @@ -130,9 +119,16 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) } } + if (other->clip.region) + { + gstate->clip.region = pixman_region_create (); + pixman_region_copy (gstate->clip.region, other->clip.region); + } + cairo_surface_reference (gstate->surface); - cairo_surface_reference (gstate->source); cairo_surface_reference (gstate->clip.surface); + + cairo_pattern_reference (gstate->pattern); status = _cairo_path_init_copy (&gstate->path, &other->path); if (status) @@ -164,16 +160,15 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) cairo_surface_destroy (gstate->surface); gstate->surface = NULL; - if (gstate->source) - cairo_surface_destroy (gstate->source); - gstate->source = NULL; - gstate->source_is_solid = 1; - if (gstate->clip.surface) cairo_surface_destroy (gstate->clip.surface); gstate->clip.surface = NULL; - _cairo_color_fini (&gstate->color); + if (gstate->clip.region) + pixman_region_destroy (gstate->clip.region); + gstate->clip.region = NULL; + + cairo_pattern_destroy (gstate->pattern); _cairo_matrix_fini (&gstate->ctm); _cairo_matrix_fini (&gstate->ctm_inverse); @@ -358,22 +353,37 @@ _cairo_gstate_current_target_surface (cairo_gstate_t *gstate) } cairo_status_t -_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_surface_t *pattern) +_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern) { - cairo_surface_destroy (gstate->source); - - gstate->source = pattern; - gstate->source_is_solid = 0; + if (pattern == NULL) + return CAIRO_STATUS_NULL_POINTER; - cairo_surface_reference (gstate->source); + if (gstate->pattern) + cairo_pattern_destroy (gstate->pattern); + + gstate->pattern = pattern; + cairo_pattern_reference (pattern); _cairo_gstate_current_point (gstate, - &gstate->source_offset.x, - &gstate->source_offset.y); - + &gstate->pattern_offset.x, + &gstate->pattern_offset.y); + return CAIRO_STATUS_SUCCESS; } +cairo_pattern_t * +_cairo_gstate_current_pattern (cairo_gstate_t *gstate) +{ + if (gstate == NULL) + return NULL; + +/* XXX: Do we want this? + cairo_pattern_reference (gstate->pattern); +*/ + + return gstate->pattern; +} + cairo_status_t _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator) { @@ -391,25 +401,19 @@ _cairo_gstate_current_operator (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue) { - _cairo_color_set_rgb (&gstate->color, red, green, blue); - - if (gstate->source) - cairo_surface_destroy (gstate->source); - - gstate->source = NULL; - gstate->source_offset.x = 0; - gstate->source_offset.y = 0; - gstate->source_is_solid = 1; - + cairo_pattern_destroy (gstate->pattern); + + gstate->pattern = _cairo_pattern_create_solid (red, green, blue); + gstate->pattern_offset.x = 0.0; + gstate->pattern_offset.y = 0.0; + return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_gstate_current_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue) { - _cairo_color_get_rgb (&gstate->color, red, green, blue); - - return CAIRO_STATUS_SUCCESS; + return _cairo_pattern_get_rgb (gstate->pattern, red, green, blue); } cairo_status_t @@ -426,20 +430,11 @@ _cairo_gstate_current_tolerance (cairo_gstate_t *gstate) return gstate->tolerance; } -/* XXX: Need to fix this so it does the right thing after set_pattern. */ cairo_status_t _cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha) { gstate->alpha = alpha; - _cairo_color_set_alpha (&gstate->color, alpha); - - cairo_surface_destroy (gstate->source); - - gstate->source = NULL; - gstate->source_offset.x = 0; - gstate->source_offset.y = 0; - return CAIRO_STATUS_SUCCESS; } @@ -680,20 +675,10 @@ _cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, do return CAIRO_STATUS_SUCCESS; } -static void -_cairo_gstate_set_current_point (cairo_gstate_t *gstate, double x, double y) -{ - gstate->current_point.x = x; - gstate->current_point.y = y; - - gstate->has_current_point = 1; -} - cairo_status_t _cairo_gstate_new_path (cairo_gstate_t *gstate) { _cairo_path_fini (&gstate->path); - gstate->has_current_point = 0; return CAIRO_STATUS_SUCCESS; } @@ -701,53 +686,51 @@ _cairo_gstate_new_path (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y) { - cairo_status_t status; + cairo_point_t point; cairo_matrix_transform_point (&gstate->ctm, &x, &y); - status = _cairo_path_move_to (&gstate->path, x, y); - - _cairo_gstate_set_current_point (gstate, x, y); - - gstate->last_move_point = gstate->current_point; + point.x = _cairo_fixed_from_double (x); + point.y = _cairo_fixed_from_double (y); - return status; + return _cairo_path_move_to (&gstate->path, &point); } cairo_status_t _cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y) { - cairo_status_t status; + cairo_point_t point; cairo_matrix_transform_point (&gstate->ctm, &x, &y); - status = _cairo_path_line_to (&gstate->path, x, y); - - _cairo_gstate_set_current_point (gstate, x, y); + point.x = _cairo_fixed_from_double (x); + point.y = _cairo_fixed_from_double (y); - return status; + return _cairo_path_line_to (&gstate->path, &point); } cairo_status_t _cairo_gstate_curve_to (cairo_gstate_t *gstate, + double x0, double y0, double x1, double y1, - double x2, double y2, - double x3, double y3) + double x2, double y2) { - cairo_status_t status; + cairo_point_t p0, p1, p2; + cairo_matrix_transform_point (&gstate->ctm, &x0, &y0); cairo_matrix_transform_point (&gstate->ctm, &x1, &y1); cairo_matrix_transform_point (&gstate->ctm, &x2, &y2); - cairo_matrix_transform_point (&gstate->ctm, &x3, &y3); - status = _cairo_path_curve_to (&gstate->path, - x1, y1, - x2, y2, - x3, y3); + p0.x = _cairo_fixed_from_double (x0); + p0.y = _cairo_fixed_from_double (y0); - _cairo_gstate_set_current_point (gstate, x3, y3); + p1.x = _cairo_fixed_from_double (x1); + p1.y = _cairo_fixed_from_double (y1); - return status; + p2.x = _cairo_fixed_from_double (x2); + p2.y = _cairo_fixed_from_double (y2); + + return _cairo_path_curve_to (&gstate->path, &p0, &p1, &p2); } /* Spline deviation from the circle in radius would be given by: @@ -1025,63 +1008,54 @@ _cairo_gstate_arc_to (cairo_gstate_t *gstate, cairo_status_t _cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy) { - cairo_status_t status; - double x, y; + cairo_distance_t distance; cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy); - x = gstate->current_point.x + dx; - y = gstate->current_point.y + dy; - - status = _cairo_path_move_to (&gstate->path, x, y); - - _cairo_gstate_set_current_point (gstate, x, y); + distance.dx = _cairo_fixed_from_double (dx); + distance.dy = _cairo_fixed_from_double (dy); - gstate->last_move_point = gstate->current_point; - - return status; + return _cairo_path_rel_move_to (&gstate->path, &distance); } cairo_status_t _cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy) { - cairo_status_t status; - double x, y; + cairo_distance_t distance; cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy); - x = gstate->current_point.x + dx; - y = gstate->current_point.y + dy; - - status = _cairo_path_line_to (&gstate->path, x, y); - - _cairo_gstate_set_current_point (gstate, x, y); + distance.dx = _cairo_fixed_from_double (dx); + distance.dy = _cairo_fixed_from_double (dy); - return status; + return _cairo_path_rel_line_to (&gstate->path, &distance); } cairo_status_t _cairo_gstate_rel_curve_to (cairo_gstate_t *gstate, + double dx0, double dy0, double dx1, double dy1, - double dx2, double dy2, - double dx3, double dy3) + double dx2, double dy2) { - cairo_status_t status; + cairo_distance_t distance[3]; + cairo_matrix_transform_distance (&gstate->ctm, &dx0, &dy0); cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1); cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2); - cairo_matrix_transform_distance (&gstate->ctm, &dx3, &dy3); - status = _cairo_path_curve_to (&gstate->path, - gstate->current_point.x + dx1, gstate->current_point.y + dy1, - gstate->current_point.x + dx2, gstate->current_point.y + dy2, - gstate->current_point.x + dx3, gstate->current_point.y + dy3); + distance[0].dx = _cairo_fixed_from_double (dx0); + distance[0].dy = _cairo_fixed_from_double (dy0); - _cairo_gstate_set_current_point (gstate, - gstate->current_point.x + dx3, - gstate->current_point.y + dy3); + distance[1].dx = _cairo_fixed_from_double (dx1); + distance[1].dy = _cairo_fixed_from_double (dy1); - return status; + distance[2].dx = _cairo_fixed_from_double (dx2); + distance[2].dy = _cairo_fixed_from_double (dy2); + + return _cairo_path_rel_curve_to (&gstate->path, + &distance[0], + &distance[1], + &distance[2]); } /* XXX: NYI @@ -1098,29 +1072,24 @@ _cairo_gstate_stroke_path (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_close_path (cairo_gstate_t *gstate) { - cairo_status_t status; - - status = _cairo_path_close_path (&gstate->path); - - _cairo_gstate_set_current_point (gstate, - gstate->last_move_point.x, - gstate->last_move_point.y); - - return status; + return _cairo_path_close_path (&gstate->path); } cairo_status_t _cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_ret) { + cairo_status_t status; + cairo_point_t point; double x, y; - if (gstate->has_current_point) { - x = gstate->current_point.x; - y = gstate->current_point.y; - cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y); - } else { + status = _cairo_path_current_point (&gstate->path, &point); + if (status == CAIRO_STATUS_NO_CURRENT_POINT) { x = 0.0; y = 0.0; + } else { + x = _cairo_fixed_to_double (point.x); + y = _cairo_fixed_to_double (point.y); + cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y); } *x_ret = x; @@ -1129,24 +1098,201 @@ _cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_re return CAIRO_STATUS_SUCCESS; } +typedef struct gstate_path_interpreter { + cairo_matrix_t ctm_inverse; + double tolerance; + cairo_point_t current_point; + + cairo_move_to_func_t *move_to; + cairo_line_to_func_t *line_to; + cairo_curve_to_func_t *curve_to; + cairo_close_path_func_t *close_path; + + void *closure; +} gpi_t; + static cairo_status_t -_cairo_gstate_ensure_source (cairo_gstate_t *gstate) +_gpi_move_to (void *closure, cairo_point_t *point) { - if (gstate->source) - return CAIRO_STATUS_SUCCESS; + gpi_t *gpi = closure; + double x, y; - if (gstate->surface == NULL) + x = _cairo_fixed_to_double (point->x); + y = _cairo_fixed_to_double (point->y); + + cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y); + + gpi->move_to (gpi->closure, x, y); + gpi->current_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_gpi_line_to (void *closure, cairo_point_t *point) +{ + gpi_t *gpi = closure; + double x, y; + + x = _cairo_fixed_to_double (point->x); + y = _cairo_fixed_to_double (point->y); + + cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y); + + gpi->line_to (gpi->closure, x, y); + gpi->current_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_gpi_curve_to (void *closure, + cairo_point_t *p1, + cairo_point_t *p2, + cairo_point_t *p3) +{ + gpi_t *gpi = closure; + cairo_status_t status; + cairo_spline_t spline; + double x1, y1, x2, y2, x3, y3; + + if (gpi->curve_to) { + x1 = _cairo_fixed_to_double (p1->x); + y1 = _cairo_fixed_to_double (p1->y); + cairo_matrix_transform_point (&gpi->ctm_inverse, &x1, &y1); + + x2 = _cairo_fixed_to_double (p2->x); + y2 = _cairo_fixed_to_double (p2->y); + cairo_matrix_transform_point (&gpi->ctm_inverse, &x2, &y2); + + x3 = _cairo_fixed_to_double (p3->x); + y3 = _cairo_fixed_to_double (p3->y); + cairo_matrix_transform_point (&gpi->ctm_inverse, &x3, &y3); + + gpi->curve_to (gpi->closure, x1, y1, x2, y2, x3, y3); + } else { + cairo_point_t *p0 = &gpi->current_point; + int i; + double x, y; + + status = _cairo_spline_init (&spline, p0, p1, p2, p3); + if (status == CAIRO_INT_STATUS_DEGENERATE) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_spline_decompose (&spline, gpi->tolerance); + if (status) + return status; + + for (i=1; i < spline.num_points; i++) { + x = _cairo_fixed_to_double (spline.points[i].x); + y = _cairo_fixed_to_double (spline.points[i].y); + + cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y); + + gpi->line_to (gpi->closure, x, y); + } + } + + gpi->current_point = *p3; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_gpi_close_path (void *closure) +{ + gpi_t *gpi = closure; + + gpi->close_path (gpi->closure); + + gpi->current_point.x = 0; + gpi->current_point.y = 0; + + return CAIRO_STATUS_SUCCESS; +} + +/* It's OK for curve_path to be NULL. In that case, all curves in the + path will be decomposed into one or more calls to the line_to + function, (according to the current tolerance). */ +cairo_status_t +_cairo_gstate_interpret_path (cairo_gstate_t *gstate, + cairo_move_to_func_t *move_to, + cairo_line_to_func_t *line_to, + cairo_curve_to_func_t *curve_to, + cairo_close_path_func_t *close_path, + void *closure) +{ + cairo_path_t path; + gpi_t gpi; + + /* Anything we want from gstate must be copied. We must not retain + pointers into gstate. */ + _cairo_path_init_copy (&path, &gstate->path); + + cairo_matrix_copy (&gpi.ctm_inverse, &gstate->ctm_inverse); + gpi.tolerance = gstate->tolerance; + + gpi.move_to = move_to; + gpi.line_to = line_to; + gpi.curve_to = curve_to; + gpi.close_path = close_path; + gpi.closure = closure; + + gpi.current_point.x = 0; + gpi.current_point.y = 0; + + return _cairo_path_interpret (&path, + CAIRO_DIRECTION_FORWARD, + _gpi_move_to, + _gpi_line_to, + _gpi_curve_to, + _gpi_close_path, + &gpi); +} + +/* This function modifies the pattern and the state of the pattern surface it + may contain. The pattern surface will be restored to its orignal state + when the pattern is destroyed. The appropriate way is to pass a copy of + the original pattern to this function just before the pattern should be + used and destroy the copy when done. */ +static cairo_status_t +_cairo_gstate_create_pattern (cairo_gstate_t *gstate, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + cairo_int_status_t status; + + if (gstate->surface == NULL) { + _cairo_pattern_fini (pattern); return CAIRO_STATUS_NO_TARGET_SURFACE; + } - gstate->source = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_ARGB32, - 1, 1, - &gstate->color); - if (gstate->source == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (pattern->type == CAIRO_PATTERN_LINEAR || + pattern->type == CAIRO_PATTERN_RADIAL) { + if (pattern->n_stops < 2) { + pattern->type = CAIRO_PATTERN_SOLID; + + if (pattern->n_stops) + pattern->color = pattern->stops->color; + } + } + + _cairo_pattern_set_alpha (pattern, gstate->alpha); + _cairo_pattern_transform (pattern, &gstate->ctm, &gstate->ctm_inverse); - cairo_surface_set_repeat (gstate->source, 1); + status = _cairo_surface_create_pattern (gstate->surface, pattern, extents); + if (status) { + _cairo_pattern_fini (pattern); + return status; + } + + if (pattern->type == CAIRO_PATTERN_SURFACE) + _cairo_pattern_prepare_surface (pattern); + _cairo_pattern_add_source_offset (pattern, + gstate->pattern_offset.x, + gstate->pattern_offset.y); + return CAIRO_STATUS_SUCCESS; } @@ -1155,15 +1301,10 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate) { cairo_status_t status; cairo_traps_t traps; - cairo_matrix_t user_to_source, device_to_source; if (gstate->line_width <= 0.0) return CAIRO_STATUS_SUCCESS; - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; - _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); _cairo_traps_init (&traps); @@ -1174,21 +1315,11 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate) return status; } - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, &user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, &user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->surface, - &traps); - - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, &user_to_source); + gstate->pattern, + gstate->operator, + gstate->surface, + &traps); _cairo_traps_fini (&traps); @@ -1227,12 +1358,14 @@ BAIL: /* Warning: This call modifies the coordinates of traps */ static cairo_status_t _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, - cairo_surface_t *src, + cairo_pattern_t *src, cairo_operator_t operator, cairo_surface_t *dst, cairo_traps_t *traps) { cairo_status_t status; + cairo_pattern_t pattern; + cairo_box_t extents; if (traps->num_traps == 0) return CAIRO_STATUS_SUCCESS; @@ -1241,19 +1374,8 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, cairo_fixed_t xoff, yoff; cairo_trapezoid_t *t; int i; - - cairo_surface_t *white, *intermediate; - cairo_color_t white_color, empty_color; - - _cairo_color_init (&white_color); - white = _cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, - 1, 1, - &white_color); - if (white == NULL) { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; - } - cairo_surface_set_repeat (white, 1); + cairo_surface_t *intermediate; + cairo_color_t empty_color; _cairo_color_init (&empty_color); _cairo_color_set_alpha (&empty_color, 0.); @@ -1261,10 +1383,10 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, CAIRO_FORMAT_A8, gstate->clip.width, gstate->clip.height, - &empty_color); + &empty_color); if (intermediate == NULL) { status = CAIRO_STATUS_NO_MEMORY; - goto BAIL1; + goto BAIL0; } /* Ugh. The cairo_composite/(Render) interface doesn't allow @@ -1286,8 +1408,16 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, t->right.p2.y -= yoff; } + _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&pattern, 1.0); + + _cairo_traps_extents (traps, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + goto BAIL1; + status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD, - white, intermediate, + pattern.source, intermediate, 0, 0, traps->traps, traps->num_traps); @@ -1302,9 +1432,23 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, gstate->clip.width, gstate->clip.height); if (status) goto BAIL2; + + _cairo_pattern_fini (&pattern); + + _cairo_pattern_init_copy (&pattern, src); + + extents.p1.x = _cairo_fixed_from_int (gstate->clip.x); + extents.p1.y = _cairo_fixed_from_int (gstate->clip.y); + extents.p2.x = + _cairo_fixed_from_int (gstate->clip.x + gstate->clip.width); + extents.p2.y = + _cairo_fixed_from_int (gstate->clip.y + gstate->clip.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + goto BAIL2; status = _cairo_surface_composite (operator, - src, intermediate, dst, + pattern.source, intermediate, dst, 0, 0, 0, 0, gstate->clip.x, @@ -1315,11 +1459,12 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, BAIL2: cairo_surface_destroy (intermediate); BAIL1: - cairo_surface_destroy (white); + _cairo_pattern_fini (&pattern); BAIL0: + if (status) return status; - + } else { int xoff, yoff; @@ -1331,16 +1476,26 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, yoff = _cairo_fixed_to_double (traps->traps[0].left.p2.y); } + _cairo_pattern_init_copy (&pattern, src); + + _cairo_traps_extents (traps, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_surface_composite_trapezoids (gstate->operator, - src, dst, - xoff - gstate->source_offset.x, - yoff - gstate->source_offset.y, + pattern.source, dst, + xoff - pattern.source_offset.x, + yoff - pattern.source_offset.y, traps->traps, traps->num_traps); + + _cairo_pattern_fini (&pattern); + if (status) return status; } - + return CAIRO_STATUS_SUCCESS; } @@ -1349,11 +1504,6 @@ _cairo_gstate_fill (cairo_gstate_t *gstate) { cairo_status_t status; cairo_traps_t traps; - cairo_matrix_t user_to_source, device_to_source; - - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; _cairo_traps_init (&traps); @@ -1363,21 +1513,11 @@ _cairo_gstate_fill (cairo_gstate_t *gstate) return status; } - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, &user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, &user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->surface, - &traps); - - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, &user_to_source); + gstate->pattern, + gstate->operator, + gstate->surface, + &traps); _cairo_traps_fini (&traps); @@ -1404,7 +1544,7 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate, goto BAIL; *inside_ret = _cairo_traps_contain (&traps, x, y); - + BAIL: _cairo_traps_fini (&traps); @@ -1430,39 +1570,137 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate) } cairo_status_t -_cairo_gstate_clip (cairo_gstate_t *gstate) +_cairo_gstate_stroke_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2) { cairo_status_t status; - cairo_surface_t *alpha_one; cairo_traps_t traps; - cairo_color_t white_color; + cairo_box_t extents; + + _cairo_traps_init (&traps); + + status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps); + if (status) + goto BAIL; - _cairo_color_init (&white_color); + _cairo_traps_extents (&traps, &extents); - if (gstate->clip.surface == NULL) { - double x1, y1, x2, y2; - _cairo_path_bounds (&gstate->path, - &x1, &y1, &x2, &y2); - gstate->clip.x = floor (x1); - gstate->clip.y = floor (y1); - gstate->clip.width = ceil (x2 - gstate->clip.x); - gstate->clip.height = ceil (y2 - gstate->clip.y); - gstate->clip.surface = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_A8, - gstate->clip.width, - gstate->clip.height, - &white_color); - if (gstate->clip.surface == NULL) - return CAIRO_STATUS_NO_MEMORY; + *x1 = _cairo_fixed_to_double (extents.p1.x); + *y1 = _cairo_fixed_to_double (extents.p1.y); + *x2 = _cairo_fixed_to_double (extents.p2.x); + *y2 = _cairo_fixed_to_double (extents.p2.y); + + cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); + cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + +BAIL: + _cairo_traps_fini (&traps); + + return status; +} + +cairo_status_t +_cairo_gstate_fill_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2) +{ + cairo_status_t status; + cairo_traps_t traps; + cairo_box_t extents; + + _cairo_traps_init (&traps); + + status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps); + if (status) + goto BAIL; + + _cairo_traps_extents (&traps, &extents); + + *x1 = _cairo_fixed_to_double (extents.p1.x); + *y1 = _cairo_fixed_to_double (extents.p1.y); + *x2 = _cairo_fixed_to_double (extents.p2.x); + *y2 = _cairo_fixed_to_double (extents.p2.y); + + cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); + cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + +BAIL: + _cairo_traps_fini (&traps); + + return status; +} + +cairo_status_t +_cairo_gstate_init_clip (cairo_gstate_t *gstate) +{ + /* destroy any existing clip-region artifacts */ + if (gstate->clip.surface) + cairo_surface_destroy (gstate->clip.surface); + gstate->clip.surface = NULL; + + if (gstate->clip.region) + pixman_region_destroy (gstate->clip.region); + gstate->clip.region = NULL; + + /* reset the surface's clip to the whole surface */ + _cairo_surface_set_clip_region (gstate->surface, + gstate->clip.region); + + return CAIRO_STATUS_SUCCESS; +} + +static int +extract_transformed_rectangle(cairo_matrix_t *mat, + cairo_traps_t *tr, + pixman_box16_t *box) +{ +#define CAIRO_FIXED_IS_INTEGER(x) (((x) & 0xFFFF) == 0) +#define CAIRO_FIXED_INTEGER_PART(x) ((x) >> 16) + + double a, b, c, d, tx, ty; + cairo_status_t st; + + st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty); + if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.)) + return 0; + + if (tr->num_traps == 1 + && tr->traps[0].left.p1.x == tr->traps[0].left.p2.x + && tr->traps[0].right.p1.x == tr->traps[0].right.p2.x + && tr->traps[0].left.p1.y == tr->traps[0].right.p1.y + && tr->traps[0].left.p2.y == tr->traps[0].right.p2.y + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.x) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.y) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.x) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.y) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.x) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.y) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.x) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.y)) { + + box->x1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.x); + box->x2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].right.p1.x); + box->y1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.y); + box->y2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p2.y); + return 1; } + return 0; - alpha_one = _cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, - 1, 1, - &white_color); - if (alpha_one == NULL) - return CAIRO_STATUS_NO_MEMORY; +#undef CAIRO_FIXED_IS_INTEGER +#undef CAIRO_FIXED_INTEGER_PART +} - cairo_surface_set_repeat (alpha_one, 1); +cairo_status_t +_cairo_gstate_clip (cairo_gstate_t *gstate) +{ + cairo_status_t status; + cairo_pattern_t pattern; + cairo_traps_t traps; + cairo_color_t white_color; + pixman_box16_t box; + + /* Fill the clip region as traps. */ _cairo_traps_init (&traps); status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps); @@ -1471,16 +1709,82 @@ _cairo_gstate_clip (cairo_gstate_t *gstate) return status; } + /* Check to see if we can represent these traps as a PixRegion. */ + + if (extract_transformed_rectangle (&gstate->ctm, &traps, &box)) { + + pixman_region16_t *rect = NULL; + pixman_region16_t *intersection = NULL; + + status = CAIRO_STATUS_SUCCESS; + rect = pixman_region_create_simple (&box); + + if (rect == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + + } else { + + if (gstate->clip.region == NULL) { + gstate->clip.region = rect; + } else { + intersection = pixman_region_create(); + if (pixman_region_intersect (intersection, + gstate->clip.region, rect) + == PIXMAN_REGION_STATUS_SUCCESS) { + pixman_region_destroy (gstate->clip.region); + gstate->clip.region = intersection; + } else { + status = CAIRO_STATUS_NO_MEMORY; + } + pixman_region_destroy (rect); + } + + if (!status) + status = _cairo_surface_set_clip_region (gstate->surface, + gstate->clip.region); + } + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + _cairo_traps_fini (&traps); + return status; + } + } + + /* Otherwise represent the clip as a mask surface. */ + + _cairo_color_init (&white_color); + + if (gstate->clip.surface == NULL) { + double x1, y1, x2, y2; + _cairo_path_bounds (&gstate->path, + &x1, &y1, &x2, &y2); + gstate->clip.x = floor (x1); + gstate->clip.y = floor (y1); + gstate->clip.width = ceil (x2 - gstate->clip.x); + gstate->clip.height = ceil (y2 - gstate->clip.y); + gstate->clip.surface = + _cairo_surface_create_similar_solid (gstate->surface, + CAIRO_FORMAT_A8, + gstate->clip.width, + gstate->clip.height, + &white_color); + if (gstate->clip.surface == NULL) + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&pattern, 1.0); + _cairo_gstate_clip_and_composite_trapezoids (gstate, - alpha_one, + &pattern, CAIRO_OPERATOR_IN, gstate->clip.surface, &traps); - + + _cairo_pattern_fini (&pattern); + _cairo_traps_fini (&traps); - cairo_surface_destroy (alpha_one); - return status; } @@ -1491,27 +1795,12 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, int height) { cairo_status_t status; - cairo_surface_t *mask; cairo_matrix_t user_to_image, image_to_user; cairo_matrix_t image_to_device, device_to_image; double device_x, device_y; double device_width, device_height; - cairo_color_t alpha_color; - - if (gstate->alpha != 1.0) { - _cairo_color_init (&alpha_color); - _cairo_color_set_alpha (&alpha_color, gstate->alpha); - mask = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_A8, - 1, 1, - &alpha_color); - if (mask == NULL) - return CAIRO_STATUS_NO_MEMORY; - - cairo_surface_set_repeat (mask, 1); - } else { - mask = NULL; - } + cairo_pattern_t pattern; + cairo_box_t extents; cairo_surface_get_matrix (surface, &user_to_image); cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image); @@ -1527,32 +1816,47 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, _cairo_matrix_transform_bounding_box (&image_to_device, &device_x, &device_y, &device_width, &device_height); + + _cairo_pattern_init (&pattern); + + if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) || + (gstate->alpha != 1.0)) { + /* I'm allowing any type of pattern for the mask right now. + Maybe this is bad. Will allow for some cool effects though. */ + _cairo_pattern_init_copy (&pattern, gstate->pattern); + extents.p1.x = _cairo_fixed_from_double (device_x); + extents.p1.y = _cairo_fixed_from_double (device_y); + extents.p2.x = _cairo_fixed_from_double (device_x + device_width); + extents.p2.y = _cairo_fixed_from_double (device_y + device_height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + } /* XXX: The rendered size is sometimes 1 or 2 pixels short from what I expect. Need to fix this. */ status = _cairo_surface_composite (gstate->operator, - surface, mask, gstate->surface, + surface, pattern.source, gstate->surface, device_x, device_y, 0, 0, device_x, device_y, device_width, device_height); - - if (mask) - cairo_surface_destroy (mask); - if (status) - return status; + _cairo_pattern_fini (&pattern); /* restore the matrix originally in the surface */ cairo_surface_set_matrix (surface, &user_to_image); + + if (status) + return status; return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_gstate_select_font (cairo_gstate_t *gstate, - char *family, + const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { @@ -1600,6 +1904,7 @@ _cairo_gstate_current_font_extents (cairo_gstate_t *gstate, status = _cairo_font_font_extents (gstate->font, extents); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + return status; } @@ -1622,14 +1927,24 @@ _cairo_gstate_text_extents (cairo_gstate_t *gstate, { cairo_matrix_t saved_font_matrix; cairo_status_t status; + double scale_x, scale_y; cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y); + cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y); status = _cairo_font_text_extents (gstate->font, utf8, extents); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + + extents->x_bearing /= scale_x; + extents->y_bearing /= scale_y; + extents->width /= scale_x; + extents->height /= scale_y; + extents->x_advance /= scale_x; + extents->y_advance /= scale_y; + return status; } @@ -1640,120 +1955,91 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, cairo_text_extents_t *extents) { cairo_status_t status; - int i; - cairo_glyph_t *transformed_glyphs = NULL; cairo_matrix_t saved_font_matrix; - - transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); - if (transformed_glyphs == NULL) - return CAIRO_STATUS_NO_MEMORY; - - for (i = 0; i < num_glyphs; ++i) - { - transformed_glyphs[i] = glyphs[i]; - cairo_matrix_transform_point (&gstate->ctm, - &(transformed_glyphs[i].x), - &(transformed_glyphs[i].y)); - } + double scale_x, scale_y; cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y); + cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y); status = _cairo_font_glyph_extents (gstate->font, - transformed_glyphs, num_glyphs, + glyphs, num_glyphs, extents); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - free (transformed_glyphs); - return status; -} - + extents->x_bearing /= scale_x; + extents->y_bearing /= scale_y; + extents->width /= scale_x; + extents->height /= scale_y; + extents->x_advance /= scale_x; + extents->y_advance /= scale_y; -static cairo_status_t -setup_text_rendering_context(cairo_gstate_t *gstate, - double *x, double *y, - cairo_matrix_t *user_to_source) -{ - cairo_status_t status; - cairo_matrix_t device_to_source; - - /* XXX: I believe this is correct, but it would be much more clear - to have some explicit current_point accesor functions, (one for - user- and one for device-space). */ - - if (gstate->has_current_point) { - *x = gstate->current_point.x; - *y = gstate->current_point.y; - } else { - *x = 0; - *y = 0; - cairo_matrix_transform_point (&gstate->ctm, x, y); - } - - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; - - /* XXX: This same source matrix manipulation code shows up in - about 3 or 4 places. We should move that into a shared function - or two. */ - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - return CAIRO_STATUS_SUCCESS; -} - -static void -restore_text_rendering_context(cairo_gstate_t *gstate, - cairo_matrix_t *user_to_source) -{ - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, user_to_source); + return status; } - cairo_status_t _cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8) { cairo_status_t status; + cairo_point_t point; double x, y; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; - - status = setup_text_rendering_context(gstate, &x, &y, &user_to_source); - if (status) - return status; + cairo_pattern_t pattern; + cairo_text_extents_t text_extents; + cairo_box_t extents; + + status = _cairo_path_current_point (&gstate->path, &point); + if (status == CAIRO_STATUS_NO_CURRENT_POINT) { + x = 0; + y = 0; + cairo_matrix_transform_point (&gstate->ctm, &x, &y); + } else { + x = _cairo_fixed_to_double (point.x); + y = _cairo_fixed_to_double (point.y); + } cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_pattern_init_copy (&pattern, gstate->pattern); + + status = _cairo_gstate_text_extents (gstate, utf8, &text_extents); + if (status) + return status; + + extents.p1.x = _cairo_fixed_from_double (x); + extents.p1.y = _cairo_fixed_from_double (y); + extents.p2.x = _cairo_fixed_from_double (x + text_extents.width); + extents.p2.y = _cairo_fixed_from_double (y + text_extents.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_font_show_text (gstate->font, - gstate->operator, gstate->source, + gstate->operator, pattern.source, gstate->surface, x, y, utf8); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); + + _cairo_pattern_fini (&pattern); return status; } - cairo_status_t _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, int num_glyphs) { cairo_status_t status; - double x, y; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; int i; cairo_glyph_t *transformed_glyphs = NULL; + cairo_pattern_t pattern; + cairo_text_extents_t text_extents; + cairo_box_t extents; transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) @@ -1767,25 +2053,37 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, &(transformed_glyphs[i].y)); } - status = setup_text_rendering_context (gstate, &x, &y, &user_to_source); - if (status) - return status; - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_pattern_init_copy (&pattern, gstate->pattern); + _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs, + &text_extents); + if (status) + return status; + + extents.p1.x = _cairo_fixed_from_double (transformed_glyphs[0].x); + extents.p1.y = _cairo_fixed_from_double (transformed_glyphs[0].y); + extents.p2.x = _cairo_fixed_from_double (transformed_glyphs[0].x + + text_extents.width); + extents.p2.y = _cairo_fixed_from_double (transformed_glyphs[0].y + + text_extents.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_font_show_glyphs (gstate->font, - gstate->operator, gstate->source, - gstate->surface, x, y, + gstate->operator, pattern.source, + gstate->surface, transformed_glyphs, num_glyphs); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); + + _cairo_pattern_fini (&pattern); free (transformed_glyphs); return status; - } @@ -1795,21 +2093,35 @@ _cairo_gstate_text_path (cairo_gstate_t *gstate, { cairo_status_t status; cairo_matrix_t saved_font_matrix; + cairo_point_t point; + double x, y; + + status = _cairo_path_current_point (&gstate->path, &point); + if (status == CAIRO_STATUS_NO_CURRENT_POINT) { + x = 0; + y = 0; + cairo_matrix_transform_point (&gstate->ctm, &x, &y); + } else { + x = _cairo_fixed_to_double (point.x); + y = _cairo_fixed_to_double (point.y); + } cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); status = _cairo_font_text_path (gstate->font, - &gstate->path, - utf8); + x, y, + utf8, + &gstate->path); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + return status; } cairo_status_t -_cairo_gstate_glyph_path (cairo_gstate_t *gstate, +_cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, int num_glyphs) { @@ -1834,11 +2146,11 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); status = _cairo_font_glyph_path (gstate->font, - &gstate->path, - transformed_glyphs, num_glyphs); + transformed_glyphs, num_glyphs, + &gstate->path); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - + free (transformed_glyphs); return status; } diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index efa54d26a..a11a07eed 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -45,7 +45,7 @@ _cairo_format_bpp (cairo_format_t format) } static cairo_image_surface_t * -_cairo_image_surface_create_for_ic_image (IcImage *ic_image) +_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image) { cairo_image_surface_t *surface; @@ -55,15 +55,15 @@ _cairo_image_surface_create_for_ic_image (IcImage *ic_image) _cairo_surface_init (&surface->base, &cairo_image_surface_backend); - surface->ic_image = ic_image; + surface->pixman_image = pixman_image; - surface->data = (char *) IcImageGetData (ic_image); + surface->data = (char *) pixman_image_get_data (pixman_image); surface->owns_data = 0; - surface->width = IcImageGetWidth (ic_image); - surface->height = IcImageGetHeight (ic_image); - surface->stride = IcImageGetStride (ic_image); - surface->depth = IcImageGetDepth (ic_image); + surface->width = pixman_image_get_width (pixman_image); + surface->height = pixman_image_get_height (pixman_image); + surface->stride = pixman_image_get_stride (pixman_image); + surface->depth = pixman_image_get_depth (pixman_image); return surface; } @@ -76,47 +76,47 @@ _cairo_image_surface_create_with_masks (char *data, int stride) { cairo_image_surface_t *surface; - IcFormat *ic_format; - IcImage *ic_image; + pixman_format_t *pixman_format; + pixman_image_t *pixman_image; - ic_format = IcFormatCreateMasks (format->bpp, - format->alpha_mask, - format->red_mask, - format->green_mask, - format->blue_mask); + pixman_format = pixman_format_create_masks (format->bpp, + format->alpha_mask, + format->red_mask, + format->green_mask, + format->blue_mask); - if (ic_format == NULL) + if (pixman_format == NULL) return NULL; - ic_image = IcImageCreateForData ((IcBits *) data, ic_format, - width, height, format->bpp, stride); + pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format, + width, height, format->bpp, stride); - IcFormatDestroy (ic_format); + pixman_format_destroy (pixman_format); - if (ic_image == NULL) + if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_ic_image (ic_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image); return surface; } -static IcFormat * -_create_ic_format (cairo_format_t format) +static pixman_format_t * +_create_pixman_format (cairo_format_t format) { switch (format) { case CAIRO_FORMAT_A1: - return IcFormatCreate (IcFormatNameA1); + return pixman_format_create (PIXMAN_FORMAT_NAME_A1); break; case CAIRO_FORMAT_A8: - return IcFormatCreate (IcFormatNameA8); + return pixman_format_create (PIXMAN_FORMAT_NAME_A8); break; case CAIRO_FORMAT_RGB24: - return IcFormatCreate (IcFormatNameRGB24); + return pixman_format_create (PIXMAN_FORMAT_NAME_RG_B24); break; case CAIRO_FORMAT_ARGB32: default: - return IcFormatCreate (IcFormatNameARGB32); + return pixman_format_create (PIXMAN_FORMAT_NAME_AR_GB32); break; } } @@ -127,21 +127,21 @@ cairo_image_surface_create (cairo_format_t format, int height) { cairo_image_surface_t *surface; - IcFormat *ic_format; - IcImage *ic_image; + pixman_format_t *pixman_format; + pixman_image_t *pixman_image; - ic_format = _create_ic_format (format); - if (ic_format == NULL) + pixman_format = _create_pixman_format (format); + if (pixman_format == NULL) return NULL; - ic_image = IcImageCreate (ic_format, width, height); + pixman_image = pixman_image_create (pixman_format, width, height); - IcFormatDestroy (ic_format); + pixman_format_destroy (pixman_format); - if (ic_image == NULL) + if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_ic_image (ic_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image); return &surface->base; } @@ -154,24 +154,24 @@ cairo_image_surface_create_for_data (char *data, int stride) { cairo_image_surface_t *surface; - IcFormat *ic_format; - IcImage *ic_image; + pixman_format_t *pixman_format; + pixman_image_t *pixman_image; - ic_format = _create_ic_format (format); - if (ic_format == NULL) + pixman_format = _create_pixman_format (format); + if (pixman_format == NULL) return NULL; - ic_image = IcImageCreateForData ((IcBits *) data, ic_format, - width, height, - _cairo_format_bpp (format), - stride); + pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format, + width, height, + _cairo_format_bpp (format), + stride); - IcFormatDestroy (ic_format); + pixman_format_destroy (pixman_format); - if (ic_image == NULL) + if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_ic_image (ic_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image); return &surface->base; } @@ -190,8 +190,8 @@ _cairo_image_abstract_surface_destroy (void *abstract_surface) { cairo_image_surface_t *surface = abstract_surface; - if (surface->ic_image) - IcImageDestroy (surface->ic_image); + if (surface->pixman_image) + pixman_image_destroy (surface->pixman_image); if (surface->owns_data) { free (surface->data); @@ -247,21 +247,21 @@ cairo_status_t _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, cairo_matrix_t *matrix) { - IcTransform ic_transform; + pixman_transform_t pixman_transform; - ic_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); - ic_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); - ic_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); + pixman_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); + pixman_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); + pixman_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); - ic_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); - ic_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); - ic_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); + pixman_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); + pixman_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); + pixman_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); - ic_transform.matrix[2][0] = 0; - ic_transform.matrix[2][1] = 0; - ic_transform.matrix[2][2] = _cairo_fixed_from_double (1); + pixman_transform.matrix[2][0] = 0; + pixman_transform.matrix[2][1] = 0; + pixman_transform.matrix[2][2] = _cairo_fixed_from_double (1); - IcImageSetTransform (surface->ic_image, &ic_transform); + pixman_image_set_transform (surface->pixman_image, &pixman_transform); return CAIRO_STATUS_SUCCESS; } @@ -277,29 +277,29 @@ _cairo_image_abstract_surface_set_filter (void *abstract_surface, cairo_filter_t cairo_status_t _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter) { - IcFilter ic_filter; + pixman_filter_t pixman_filter; switch (filter) { case CAIRO_FILTER_FAST: - ic_filter = IcFilterFast; + pixman_filter = PIXMAN_FILTER_FAST; break; case CAIRO_FILTER_GOOD: - ic_filter = IcFilterGood; + pixman_filter = PIXMAN_FILTER_GOOD; break; case CAIRO_FILTER_BEST: - ic_filter = IcFilterBest; + pixman_filter = PIXMAN_FILTER_BEST; break; case CAIRO_FILTER_NEAREST: - ic_filter = IcFilterNearest; + pixman_filter = PIXMAN_FILTER_NEAREST; break; case CAIRO_FILTER_BILINEAR: - ic_filter = IcFilterBilinear; + pixman_filter = PIXMAN_FILTER_BILINEAR; break; default: - ic_filter = IcFilterBest; + pixman_filter = PIXMAN_FILTER_BEST; } - IcImageSetFilter (surface->ic_image, ic_filter); + pixman_image_set_filter (surface->pixman_image, pixman_filter); return CAIRO_STATUS_SUCCESS; } @@ -314,45 +314,45 @@ _cairo_image_abstract_surface_set_repeat (void *abstract_surface, int repeat) cairo_status_t _cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat) { - IcImageSetRepeat (surface->ic_image, repeat); + pixman_image_set_repeat (surface->pixman_image, repeat); return CAIRO_STATUS_SUCCESS; } -static IcOperator -_ic_operator (cairo_operator_t operator) +static pixman_operator_t +_pixman_operator (cairo_operator_t operator) { switch (operator) { case CAIRO_OPERATOR_CLEAR: - return IcOperatorClear; + return PIXMAN_OPERATOR_CLEAR; case CAIRO_OPERATOR_SRC: - return IcOperatorSrc; + return PIXMAN_OPERATOR_SRC; case CAIRO_OPERATOR_DST: - return IcOperatorDst; + return PIXMAN_OPERATOR_DST; case CAIRO_OPERATOR_OVER: - return IcOperatorOver; + return PIXMAN_OPERATOR_OVER; case CAIRO_OPERATOR_OVER_REVERSE: - return IcOperatorOverReverse; + return PIXMAN_OPERATOR_OVER_REVERSE; case CAIRO_OPERATOR_IN: - return IcOperatorIn; + return PIXMAN_OPERATOR_IN; case CAIRO_OPERATOR_IN_REVERSE: - return IcOperatorInReverse; + return PIXMAN_OPERATOR_IN_REVERSE; case CAIRO_OPERATOR_OUT: - return IcOperatorOut; + return PIXMAN_OPERATOR_OUT; case CAIRO_OPERATOR_OUT_REVERSE: - return IcOperatorOutReverse; + return PIXMAN_OPERATOR_OUT_REVERSE; case CAIRO_OPERATOR_ATOP: - return IcOperatorAtop; + return PIXMAN_OPERATOR_ATOP; case CAIRO_OPERATOR_ATOP_REVERSE: - return IcOperatorAtopReverse; + return PIXMAN_OPERATOR_ATOP_REVERSE; case CAIRO_OPERATOR_XOR: - return IcOperatorXor; + return PIXMAN_OPERATOR_XOR; case CAIRO_OPERATOR_ADD: - return IcOperatorAdd; + return PIXMAN_OPERATOR_ADD; case CAIRO_OPERATOR_SATURATE: - return IcOperatorSaturate; + return PIXMAN_OPERATOR_SATURATE; default: - return IcOperatorOver; + return PIXMAN_OPERATOR_OVER; } } @@ -380,14 +380,14 @@ _cairo_image_surface_composite (cairo_operator_t operator, return CAIRO_INT_STATUS_UNSUPPORTED; } - IcComposite (_ic_operator (operator), - src->ic_image, - mask ? mask->ic_image : NULL, - dst->ic_image, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); + pixman_composite (_pixman_operator (operator), + src->pixman_image, + mask ? mask->pixman_image : NULL, + dst->pixman_image, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); return CAIRO_STATUS_SUCCESS; } @@ -401,16 +401,16 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, { cairo_image_surface_t *surface = abstract_surface; - IcColor ic_color; + pixman_color_t pixman_color; - ic_color.red = color->red_short; - ic_color.green = color->green_short; - ic_color.blue = color->blue_short; - ic_color.alpha = color->alpha_short; + pixman_color.red = color->red_short; + pixman_color.green = color->green_short; + pixman_color.blue = color->blue_short; + pixman_color.alpha = color->alpha_short; - /* XXX: The IcRectangle cast is evil... it needs to go away somehow. */ - IcFillRectangles (_ic_operator(operator), surface->ic_image, - &ic_color, (IcRectangle *) rects, num_rects); + /* XXX: The pixman_rectangle_t cast is evil... it needs to go away somehow. */ + pixman_fill_rectangles (_pixman_operator(operator), surface->pixman_image, + &pixman_color, (pixman_rectangle_t *) rects, num_rects); return CAIRO_STATUS_SUCCESS; } @@ -430,9 +430,9 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, if (generic_src->backend != dst->base.backend) return CAIRO_INT_STATUS_UNSUPPORTED; - /* XXX: The IcTrapezoid cast is evil and needs to go away somehow. */ - IcCompositeTrapezoids (operator, src->ic_image, dst->ic_image, - x_src, y_src, (IcTrapezoid *) traps, num_traps); + /* XXX: The pixman_trapezoid_t cast is evil and needs to go away somehow. */ + pixman_composite_trapezoids (operator, src->pixman_image, dst->pixman_image, + x_src, y_src, (pixman_trapezoid_t *) traps, num_traps); return CAIRO_STATUS_SUCCESS; } @@ -449,6 +449,44 @@ _cairo_image_surface_show_page (void *abstract_surface) return CAIRO_INT_STATUS_UNSUPPORTED; } +static cairo_int_status_t +_cairo_image_abstract_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface; + + return _cairo_image_surface_set_clip_region (surface, region); +} + +cairo_int_status_t +_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, + pixman_region16_t *region) +{ + pixman_image_set_clip_region (surface->pixman_image, region); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_image_abstract_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_image_surface_t *image; + + /* Fall back to general pattern creation for surface patterns. */ + if (pattern->type == CAIRO_PATTERN_SURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + image = _cairo_pattern_get_image (pattern, box); + if (image) { + pattern->source = &image->base; + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; +} + static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_create_similar, _cairo_image_abstract_surface_destroy, @@ -462,5 +500,7 @@ static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_fill_rectangles, _cairo_image_surface_composite_trapezoids, _cairo_image_surface_copy_page, - _cairo_image_surface_show_page + _cairo_image_surface_show_page, + _cairo_image_abstract_surface_set_clip_region, + _cairo_image_abstract_surface_create_pattern }; diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index 655bcde83..de89c0fd5 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -386,3 +386,22 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou return CAIRO_STATUS_SUCCESS; } + +/* Compute the amount that each basis vector is scaled by. */ +cairo_status_t +_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy) +{ + double x, y; + + x = 1.0; + y = 0.0; + cairo_matrix_transform_distance (matrix, &x, &y); + *sx = sqrt(x*x + y*y); + + x = 0.0; + y = 1.0; + cairo_matrix_transform_distance (matrix, &x, &y); + *sy = sqrt(x*x + y*y); + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c index 40b64c3d6..6a02b9ac0 100644 --- a/src/cairo-path-bounds.c +++ b/src/cairo-path-bounds.c @@ -46,18 +46,19 @@ static cairo_status_t _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point); static cairo_status_t -_cairo_path_bounder_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2); +_cairo_path_bounder_move_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_path_bounder_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d); +_cairo_path_bounder_line_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done_t done); +_cairo_path_bounder_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d); static cairo_status_t -_cairo_path_bounder_done_path (void *closure); +_cairo_path_bounder_close_path (void *closure); static void _cairo_path_bounder_init (cairo_path_bounder_t *bounder) @@ -99,39 +100,42 @@ _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *poi } static cairo_status_t -_cairo_path_bounder_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2) +_cairo_path_bounder_move_to (void *closure, cairo_point_t *point) { cairo_path_bounder_t *bounder = closure; - _cairo_path_bounder_add_point (bounder, p1); - _cairo_path_bounder_add_point (bounder, p2); + _cairo_path_bounder_add_point (bounder, point); return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_path_bounder_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d) +_cairo_path_bounder_line_to (void *closure, cairo_point_t *point) { cairo_path_bounder_t *bounder = closure; - _cairo_path_bounder_add_point (bounder, a); - _cairo_path_bounder_add_point (bounder, b); - _cairo_path_bounder_add_point (bounder, c); - _cairo_path_bounder_add_point (bounder, d); + _cairo_path_bounder_add_point (bounder, point); return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done_t done) +_cairo_path_bounder_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d) { + cairo_path_bounder_t *bounder = closure; + + _cairo_path_bounder_add_point (bounder, b); + _cairo_path_bounder_add_point (bounder, c); + _cairo_path_bounder_add_point (bounder, d); + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_path_bounder_done_path (void *closure) +_cairo_path_bounder_close_path (void *closure) { return CAIRO_STATUS_SUCCESS; } @@ -141,18 +145,17 @@ cairo_status_t _cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2) { cairo_status_t status; - static cairo_path_callbacks_t const cb = { - _cairo_path_bounder_add_edge, - _cairo_path_bounder_add_spline, - _cairo_path_bounder_done_sub_path, - _cairo_path_bounder_done_path - }; cairo_path_bounder_t bounder; _cairo_path_bounder_init (&bounder); - status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD, &cb, &bounder); + status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD, + _cairo_path_bounder_move_to, + _cairo_path_bounder_line_to, + _cairo_path_bounder_curve_to, + _cairo_path_bounder_close_path, + &bounder); if (status) { *x1 = *y1 = *x2 = *y2 = 0.0; _cairo_path_bounder_fini (&bounder); diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index 8f34af854..fba5bb090 100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -31,6 +31,8 @@ typedef struct cairo_filler { cairo_gstate_t *gstate; cairo_traps_t *traps; + cairo_point_t current_point; + cairo_polygon_t polygon; } cairo_filler_t; @@ -41,18 +43,19 @@ static void _cairo_filler_fini (cairo_filler_t *filler); static cairo_status_t -_cairo_filler_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2); +_cairo_filler_move_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_filler_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d); +_cairo_filler_line_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done_t done); +_cairo_filler_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d); static cairo_status_t -_cairo_filler_done_path (void *closure); +_cairo_filler_close_path (void *closure); static void _cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps) @@ -60,6 +63,9 @@ _cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_ filler->gstate = gstate; filler->traps = traps; + filler->current_point.x = 0; + filler->current_point.y = 0; + _cairo_polygon_init (&filler->polygon); } @@ -70,18 +76,46 @@ _cairo_filler_fini (cairo_filler_t *filler) } static cairo_status_t -_cairo_filler_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2) +_cairo_filler_move_to (void *closure, cairo_point_t *point) { + cairo_status_t status; cairo_filler_t *filler = closure; cairo_polygon_t *polygon = &filler->polygon; - return _cairo_polygon_add_edge (polygon, p1, p2); + status = _cairo_polygon_close (polygon); + if (status) + return status; + + status = _cairo_polygon_move_to (polygon, point); + if (status) + return status; + + filler->current_point = *point; + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_filler_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d) +_cairo_filler_line_to (void *closure, cairo_point_t *point) +{ + cairo_status_t status; + cairo_filler_t *filler = closure; + cairo_polygon_t *polygon = &filler->polygon; + + status = _cairo_polygon_line_to (polygon, point); + if (status) + return status; + + filler->current_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_filler_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d) { int i; cairo_status_t status = CAIRO_STATUS_SUCCESS; @@ -90,7 +124,8 @@ _cairo_filler_add_spline (void *closure, cairo_gstate_t *gstate = filler->gstate; cairo_spline_t spline; - status = _cairo_spline_init (&spline, a, b, c, d); + status = _cairo_spline_init (&spline, &filler->current_point, b, c, d); + if (status == CAIRO_INT_STATUS_DEGENERATE) return CAIRO_STATUS_SUCCESS; @@ -98,65 +133,65 @@ _cairo_filler_add_spline (void *closure, if (status) goto CLEANUP_SPLINE; - for (i = 0; i < spline.num_points - 1; i++) { - status = _cairo_polygon_add_edge (polygon, &spline.points[i], &spline.points[i+1]); + for (i = 1; i < spline.num_points; i++) { + status = _cairo_polygon_line_to (polygon, &spline.points[i]); if (status) - goto CLEANUP_SPLINE; + break; } CLEANUP_SPLINE: _cairo_spline_fini (&spline); + filler->current_point = *d; + return status; } static cairo_status_t -_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done_t done) +_cairo_filler_close_path (void *closure) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_status_t status; cairo_filler_t *filler = closure; cairo_polygon_t *polygon = &filler->polygon; - _cairo_polygon_close (polygon); - - return status; -} - -static cairo_status_t -_cairo_filler_done_path (void *closure) -{ - cairo_filler_t *filler = closure; + status = _cairo_polygon_close (polygon); + if (status) + return status; - return _cairo_traps_tessellate_polygon (filler->traps, - &filler->polygon, - filler->gstate->fill_rule); + return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps) { - static const cairo_path_callbacks_t filler_callbacks = { - _cairo_filler_add_edge, - _cairo_filler_add_spline, - _cairo_filler_done_sub_path, - _cairo_filler_done_path - }; - - cairo_status_t status; + cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_filler_t filler; _cairo_filler_init (&filler, gstate, traps); status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD, - &filler_callbacks, &filler); - if (status) { - _cairo_filler_fini (&filler); - return status; - } + _cairo_filler_move_to, + _cairo_filler_line_to, + _cairo_filler_curve_to, + _cairo_filler_close_path, + &filler); + if (status) + goto BAIL; + status = _cairo_polygon_close (&filler.polygon); + if (status) + goto BAIL; + + status = _cairo_traps_tessellate_polygon (filler.traps, + &filler.polygon, + filler.gstate->fill_rule); + if (status) + goto BAIL; + +BAIL: _cairo_filler_fini (&filler); - return CAIRO_STATUS_SUCCESS; + return status; } diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index 35e7b1b70..c2412579a 100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -31,11 +31,17 @@ typedef struct cairo_stroker { cairo_gstate_t *gstate; cairo_traps_t *traps; - int have_prev; - int have_first; - int is_first; - cairo_stroke_face_t prev; - cairo_stroke_face_t first; + int has_current_point; + cairo_point_t current_point; + cairo_point_t first_point; + + int has_current_face; + cairo_stroke_face_t current_face; + + int has_first_face; + cairo_stroke_face_t first_face; + + int dashed; int dash_index; int dash_on; double dash_remain; @@ -49,21 +55,22 @@ static void _cairo_stroker_fini (cairo_stroker_t *stroker); static cairo_status_t -_cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2); +_cairo_stroker_move_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t *p2); +_cairo_stroker_line_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_stroker_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d); +_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done_t done); +_cairo_stroker_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d); static cairo_status_t -_cairo_stroker_done_path (void *closure); +_cairo_stroker_close_path (void *closure); static void _translate_point (cairo_point_t *point, cairo_point_t *offset); @@ -89,6 +96,7 @@ _cairo_stroker_start_dash (cairo_stroker_t *stroker) if (++i == gstate->num_dashes) i = 0; } + stroker->dashed = 1; stroker->dash_index = i; stroker->dash_on = on; stroker->dash_remain = gstate->dash[i] - offset; @@ -113,11 +121,15 @@ _cairo_stroker_init (cairo_stroker_t *stroker, cairo_gstate_t *gstate, cairo_tra { stroker->gstate = gstate; stroker->traps = traps; - stroker->have_prev = 0; - stroker->have_first = 0; - stroker->is_first = 1; + + stroker->has_current_point = 0; + stroker->has_current_face = 0; + stroker->has_first_face = 0; + if (gstate->dash) _cairo_stroker_start_dash (stroker); + else + stroker->dashed = 0; } static void @@ -286,10 +298,11 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st outer.x = _cairo_fixed_from_double (mx); outer.y = _cairo_fixed_from_double (my); _cairo_polygon_init (&polygon); - _cairo_polygon_add_edge (&polygon, &in->point, inpt); - _cairo_polygon_add_edge (&polygon, inpt, &outer); - _cairo_polygon_add_edge (&polygon, &outer, outpt); - _cairo_polygon_add_edge (&polygon, outpt, &in->point); + _cairo_polygon_move_to (&polygon, &in->point); + _cairo_polygon_line_to (&polygon, inpt); + _cairo_polygon_line_to (&polygon, &outer); + _cairo_polygon_line_to (&polygon, outpt); + _cairo_polygon_close (&polygon); status = _cairo_traps_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING); @@ -351,8 +364,6 @@ _cairo_stroker_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f) cairo_point_t occw, ocw; cairo_polygon_t polygon; - _cairo_polygon_init (&polygon); - dx = f->usr_vector.x; dy = f->usr_vector.y; dx *= gstate->line_width / 2.0; @@ -365,10 +376,12 @@ _cairo_stroker_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f) ocw.x = f->cw.x + fvector.dx; ocw.y = f->cw.y + fvector.dy; - _cairo_polygon_add_edge (&polygon, &f->cw, &ocw); - _cairo_polygon_add_edge (&polygon, &ocw, &occw); - _cairo_polygon_add_edge (&polygon, &occw, &f->ccw); - _cairo_polygon_add_edge (&polygon, &f->ccw, &f->cw); + _cairo_polygon_init (&polygon); + _cairo_polygon_move_to (&polygon, &f->cw); + _cairo_polygon_line_to (&polygon, &ocw); + _cairo_polygon_line_to (&polygon, &occw); + _cairo_polygon_line_to (&polygon, &f->ccw); + _cairo_polygon_close (&polygon); status = _cairo_traps_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING); _cairo_polygon_fini (&polygon); @@ -454,8 +467,9 @@ static cairo_status_t _cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, cairo_point_t *p1, cairo_point_t *p2, cairo_stroke_face_t *start, cairo_stroke_face_t *end) { + cairo_status_t status; cairo_gstate_t *gstate = stroker->gstate; - cairo_point_t quad[4]; + cairo_polygon_t polygon; cairo_slope_t slope; if (p1->x == p2->x && p1->y == p2->y) { @@ -473,20 +487,58 @@ _cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, cairo_point_t *p1, cairo_ fields from start. */ _compute_face (p2, &slope, gstate, end); - quad[0] = start->cw; - quad[1] = start->ccw; - quad[2] = end->ccw; - quad[3] = end->cw; + /* XXX: I should really check the return value of the + move_to/line_to functions here to catch out of memory + conditions. But since that would be ugly, I'd prefer to add a + status flag to the polygon object that I could check only once + at then end of this sequence, (like we do with cairo_t + already). */ + _cairo_polygon_init (&polygon); + _cairo_polygon_move_to (&polygon, &start->cw); + _cairo_polygon_line_to (&polygon, &start->ccw); + _cairo_polygon_line_to (&polygon, &end->ccw); + _cairo_polygon_line_to (&polygon, &end->cw); + _cairo_polygon_close (&polygon); + + /* XXX: We can't use tessellate_rectangle as the matrix may have + skewed this into a non-rectangular shape. Perhaps it would be + worth checking the matrix for skew so that the common case + could use the faster tessellate_rectangle rather than + tessellate_polygon? */ + status = _cairo_traps_tessellate_polygon (stroker->traps, + &polygon, CAIRO_FILL_RULE_WINDING); + + _cairo_polygon_fini (&polygon); - return _cairo_traps_tessellate_rectangle (stroker->traps, quad); + return status; } static cairo_status_t -_cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2) +_cairo_stroker_move_to (void *closure, cairo_point_t *point) +{ + cairo_stroker_t *stroker = closure; + + stroker->first_point = *point; + stroker->current_point = *point; + stroker->has_current_point = 1; + + stroker->has_first_face = 0; + stroker->has_current_face = 0; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_stroker_line_to (void *closure, cairo_point_t *point) { cairo_status_t status; cairo_stroker_t *stroker = closure; cairo_stroke_face_t start, end; + cairo_point_t *p1 = &stroker->current_point; + cairo_point_t *p2 = point; + + if (!stroker->has_current_point) + return _cairo_stroker_move_to (stroker, point); if (p1->x == p2->x && p1->y == p2->y) { /* XXX: Need to rethink how this case should be handled, (both @@ -500,19 +552,20 @@ _cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2) if (status) return status; - if (stroker->have_prev) { - status = _cairo_stroker_join (stroker, &stroker->prev, &start); + if (stroker->has_current_face) { + status = _cairo_stroker_join (stroker, &stroker->current_face, &start); if (status) return status; } else { - stroker->have_prev = 1; - if (stroker->is_first) { - stroker->have_first = 1; - stroker->first = start; + if (!stroker->has_first_face) { + stroker->first_face = start; + stroker->has_first_face = 1; } } - stroker->prev = end; - stroker->is_first = 0; + stroker->current_face = end; + stroker->has_current_face = 1; + + stroker->current_point = *point; return CAIRO_STATUS_SUCCESS; } @@ -521,7 +574,7 @@ _cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2) * Dashed lines. Cap each dash end, join around turns when on */ static cairo_status_t -_cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t *p2) +_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t *stroker = closure; @@ -532,6 +585,11 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t cairo_point_t fd1, fd2; int first = 1; cairo_stroke_face_t sub_start, sub_end; + cairo_point_t *p1 = &stroker->current_point; + cairo_point_t *p2 = point; + + if (!stroker->has_current_point) + return _cairo_stroker_move_to (stroker, point); dx = _cairo_fixed_to_double (p2->x - p1->x); dy = _cairo_fixed_to_double (p2->y - p1->y); @@ -569,18 +627,18 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t return status; } else { /* - * First in this segment, join to any prev, else + * First in this segment, join to any current_face, else * if at start of sub-path, mark position, else * cap */ - if (stroker->have_prev) { - status = _cairo_stroker_join (stroker, &stroker->prev, &sub_start); + if (stroker->has_current_face) { + status = _cairo_stroker_join (stroker, &stroker->current_face, &sub_start); if (status) return status; } else { - if (stroker->is_first) { - stroker->have_first = 1; - stroker->first = sub_start; + if (!stroker->has_first_face) { + stroker->first_face = sub_start; + stroker->has_first_face = 1; } else { status = _cairo_stroker_cap (stroker, &sub_start); if (status) @@ -600,8 +658,8 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t * Mark previous line face and fix up next time * through */ - stroker->prev = sub_end; - stroker->have_prev = 1; + stroker->current_face = sub_end; + stroker->has_current_face = 1; } } else { /* @@ -609,27 +667,30 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t * and cap if necessary */ if (first) { - if (stroker->have_prev) { - status = _cairo_stroker_cap (stroker, &stroker->prev); + if (stroker->has_current_face) { + status = _cairo_stroker_cap (stroker, &stroker->current_face); if (status) return status; } } if (!remain) - stroker->have_prev = 0; + stroker->has_current_face = 0; } _cairo_stroker_step_dash (stroker, tmp); fd1 = fd2; first = 0; } - stroker->is_first = 0; + + stroker->current_point = *point; + return status; } static cairo_status_t -_cairo_stroker_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d) +_cairo_stroker_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t *stroker = closure; @@ -638,6 +699,7 @@ _cairo_stroker_add_spline (void *closure, cairo_pen_t pen; cairo_stroke_face_t start, end; cairo_point_t extra_points[4]; + cairo_point_t *a = &stroker->current_point; status = _cairo_spline_init (&spline, a, b, c, d); if (status == CAIRO_INT_STATUS_DEGENERATE) @@ -650,19 +712,18 @@ _cairo_stroker_add_spline (void *closure, _compute_face (a, &spline.initial_slope, gstate, &start); _compute_face (d, &spline.final_slope, gstate, &end); - if (stroker->have_prev) { - status = _cairo_stroker_join (stroker, &stroker->prev, &start); + if (stroker->has_current_face) { + status = _cairo_stroker_join (stroker, &stroker->current_face, &start); if (status) return status; } else { - stroker->have_prev = 1; - if (stroker->is_first) { - stroker->have_first = 1; - stroker->first = start; + if (!stroker->has_first_face) { + stroker->first_face = start; + stroker->has_first_face = 1; } } - stroker->prev = end; - stroker->is_first = 0; + stroker->current_face = end; + stroker->has_current_face = 1; extra_points[0] = start.cw; extra_points[0].x -= start.point.x; @@ -690,91 +751,89 @@ _cairo_stroker_add_spline (void *closure, CLEANUP_SPLINE: _cairo_spline_fini (&spline); + stroker->current_point = *d; + return status; } static cairo_status_t -_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done_t done) +_cairo_stroker_close_path (void *closure) { cairo_status_t status; cairo_stroker_t *stroker = closure; - switch (done) { - case CAIRO_SUB_PATH_DONE_JOIN: - if (stroker->have_first && stroker->have_prev) { - status = _cairo_stroker_join (stroker, &stroker->prev, &stroker->first); - if (status) - return status; - break; - } - /* fall through... */ - case CAIRO_SUB_PATH_DONE_CAP: - if (stroker->have_first) { - cairo_point_t t; - /* The initial cap needs an outward facing vector. Reverse everything */ - stroker->first.usr_vector.x = -stroker->first.usr_vector.x; - stroker->first.usr_vector.y = -stroker->first.usr_vector.y; - stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx; - stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy; - t = stroker->first.cw; - stroker->first.cw = stroker->first.ccw; - stroker->first.ccw = t; - status = _cairo_stroker_cap (stroker, &stroker->first); - if (status) - return status; - } - if (stroker->have_prev) { - status = _cairo_stroker_cap (stroker, &stroker->prev); - if (status) - return status; - } - break; + if (stroker->has_current_point) { + if (stroker->dashed) + status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point); + else + status = _cairo_stroker_line_to (stroker, &stroker->first_point); + if (status) + return status; } - stroker->have_prev = 0; - stroker->have_first = 0; - stroker->is_first = 1; + if (stroker->has_first_face && stroker->has_current_face) { + status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face); + if (status) + return status; + } - return CAIRO_STATUS_SUCCESS; -} + stroker->has_first_face = 0; + stroker->has_current_face = 0; + stroker->has_current_point = 0; -static cairo_status_t -_cairo_stroker_done_path (void *closure) -{ return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps) { - static const cairo_path_callbacks_t stroker_solid_cb = { - _cairo_stroker_add_edge, - _cairo_stroker_add_spline, - _cairo_stroker_done_sub_path, - _cairo_stroker_done_path - }; - static const cairo_path_callbacks_t stroker_dashed_cb = { - _cairo_stroker_add_edge_dashed, - _cairo_stroker_add_spline, - _cairo_stroker_done_sub_path, - _cairo_stroker_done_path - }; - const cairo_path_callbacks_t *callbacks = gstate->dash ? &stroker_dashed_cb : &stroker_solid_cb; - - cairo_status_t status; + cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t stroker; _cairo_stroker_init (&stroker, gstate, traps); - status = _cairo_path_interpret (path, - CAIRO_DIRECTION_FORWARD, - callbacks, &stroker); - if (status) { - _cairo_stroker_fini (&stroker); - return status; + if (gstate->dash) + status = _cairo_path_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cairo_stroker_move_to, + _cairo_stroker_line_to_dashed, + _cairo_stroker_curve_to, + _cairo_stroker_close_path, + &stroker); + else + status = _cairo_path_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cairo_stroker_move_to, + _cairo_stroker_line_to, + _cairo_stroker_curve_to, + _cairo_stroker_close_path, + &stroker); + if (status) + goto BAIL; + + if (stroker.has_first_face) { + cairo_point_t t; + /* The initial cap needs an outward facing vector. Reverse everything */ + stroker.first_face.usr_vector.x = -stroker.first_face.usr_vector.x; + stroker.first_face.usr_vector.y = -stroker.first_face.usr_vector.y; + stroker.first_face.dev_vector.dx = -stroker.first_face.dev_vector.dx; + stroker.first_face.dev_vector.dy = -stroker.first_face.dev_vector.dy; + t = stroker.first_face.cw; + stroker.first_face.cw = stroker.first_face.ccw; + stroker.first_face.ccw = t; + status = _cairo_stroker_cap (&stroker, &stroker.first_face); + if (status) + goto BAIL; } + if (stroker.has_current_face) { + status = _cairo_stroker_cap (&stroker, &stroker.current_face); + if (status) + goto BAIL; + } + +BAIL: _cairo_stroker_fini (&stroker); - return CAIRO_STATUS_SUCCESS; + return status; } diff --git a/src/cairo-path.c b/src/cairo-path.c index 9366394d5..91142c8ff 100644 --- a/src/cairo-path.c +++ b/src/cairo-path.c @@ -70,6 +70,11 @@ _cairo_path_init (cairo_path_t *path) path->arg_head = NULL; path->arg_tail = NULL; + + path->current_point.x = 0; + path->current_point.y = 0; + path->has_current_point = 0; + path->last_move_point = path->current_point; } cairo_status_t @@ -79,6 +84,9 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other) cairo_path_arg_buf_t *arg, *other_arg; _cairo_path_init (path); + path->current_point = other->current_point; + path->has_current_point = other->has_current_point; + path->last_move_point = other->last_move_point; for (other_op = other->op_head; other_op; other_op = other_op->next) { op = _cairo_path_op_buf_create (); @@ -120,54 +128,131 @@ _cairo_path_fini (cairo_path_t *path) _cairo_path_arg_buf_destroy (arg); } path->arg_tail = NULL; + + path->has_current_point = 0; +} + +cairo_status_t +_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point) +{ + cairo_status_t status; + + status = _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, point, 1); + if (status) + return status; + + path->current_point = *point; + path->has_current_point = 1; + path->last_move_point = path->current_point; + + return CAIRO_STATUS_SUCCESS; } cairo_status_t -_cairo_path_move_to (cairo_path_t *path, double x, double y) +_cairo_path_rel_move_to (cairo_path_t *path, cairo_distance_t *distance) { cairo_point_t point; - point.x = _cairo_fixed_from_double (x); - point.y = _cairo_fixed_from_double (y); + point.x = path->current_point.x + distance->dx; + point.y = path->current_point.y + distance->dy; + + return _cairo_path_move_to (path, &point); +} + +cairo_status_t +_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point) +{ + cairo_status_t status; + + status = _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, point, 1); + if (status) + return status; - return _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1); + path->current_point = *point; + path->has_current_point = 1; + + return CAIRO_STATUS_SUCCESS; } cairo_status_t -_cairo_path_line_to (cairo_path_t *path, double x, double y) +_cairo_path_rel_line_to (cairo_path_t *path, cairo_distance_t *distance) { cairo_point_t point; - point.x = _cairo_fixed_from_double (x); - point.y = _cairo_fixed_from_double (y); + point.x = path->current_point.x + distance->dx; + point.y = path->current_point.y + distance->dy; - return _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1); + return _cairo_path_line_to (path, &point); } cairo_status_t _cairo_path_curve_to (cairo_path_t *path, - double x1, double y1, - double x2, double y2, - double x3, double y3) + cairo_point_t *p0, + cairo_point_t *p1, + cairo_point_t *p2) { + cairo_status_t status; cairo_point_t point[3]; - point[0].x = _cairo_fixed_from_double (x1); - point[0].y = _cairo_fixed_from_double (y1); + point[0] = *p0; + point[1] = *p1; + point[2] = *p2; - point[1].x = _cairo_fixed_from_double (x2); - point[1].y = _cairo_fixed_from_double (y2); + status = _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3); + if (status) + return status; - point[2].x = _cairo_fixed_from_double (x3); - point[2].y = _cairo_fixed_from_double (y3); + path->current_point = *p2; + path->has_current_point = 1; - return _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3); + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_path_rel_curve_to (cairo_path_t *path, + cairo_distance_t *d0, + cairo_distance_t *d1, + cairo_distance_t *d2) +{ + cairo_point_t p0, p1, p2; + + p0.x = path->current_point.x + d0->dx; + p0.y = path->current_point.y + d0->dy; + + p1.x = path->current_point.x + d1->dx; + p1.y = path->current_point.y + d1->dy; + + p2.x = path->current_point.x + d2->dx; + p2.y = path->current_point.y + d2->dy; + + return _cairo_path_curve_to (path, &p0, &p1, &p2); } cairo_status_t _cairo_path_close_path (cairo_path_t *path) { - return _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0); + cairo_status_t status; + + status = _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0); + if (status) + return status; + + path->current_point.x = path->last_move_point.x; + path->current_point.y = path->last_move_point.y; + path->has_current_point = 1; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point) +{ + if (! path->has_current_point) + return CAIRO_STATUS_NO_CURRENT_POINT; + + *point = path->current_point; + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -320,7 +405,13 @@ static int const num_args[] = }; cairo_status_t -_cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_path_callbacks_t *cb, void *closure) +_cairo_path_interpret (cairo_path_t *path, + cairo_direction_t dir, + cairo_path_move_to_func_t *move_to, + cairo_path_line_to_func_t *line_to, + cairo_path_curve_to_func_t *curve_to, + cairo_path_close_path_func_t *close_path, + void *closure) { cairo_status_t status; int i, arg; @@ -329,10 +420,6 @@ _cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_pa cairo_path_arg_buf_t *arg_buf = path->arg_head; int buf_i = 0; cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS]; - cairo_point_t current = {0, 0}; - cairo_point_t first = {0, 0}; - int has_current = 0; - int has_edge = 0; int step = (dir == CAIRO_DIRECTION_FORWARD) ? 1 : -1; for (op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? path->op_head : path->op_tail; @@ -374,62 +461,24 @@ _cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_pa switch (op) { case CAIRO_PATH_OP_MOVE_TO: - if (has_edge) { - status = (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_CAP); - if (status) - return status; - } - first = point[0]; - current = point[0]; - has_current = 1; - has_edge = 0; + status = (*move_to) (closure, &point[0]); break; case CAIRO_PATH_OP_LINE_TO: - if (has_current) { - status = (*cb->add_edge) (closure, ¤t, &point[0]); - if (status) - return status; - current = point[0]; - has_edge = 1; - } else { - first = point[0]; - current = point[0]; - has_current = 1; - has_edge = 0; - } + status = (*line_to) (closure, &point[0]); break; case CAIRO_PATH_OP_CURVE_TO: - if (has_current) { - status = (*cb->add_spline) (closure, ¤t, &point[0], &point[1], &point[2]); - if (status) - return status; - current = point[2]; - has_edge = 1; - } else { - first = point[2]; - current = point[2]; - has_current = 1; - has_edge = 0; - } + status = (*curve_to) (closure, &point[0], &point[1], &point[2]); break; case CAIRO_PATH_OP_CLOSE_PATH: - if (has_edge) { - (*cb->add_edge) (closure, ¤t, &first); - (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_JOIN); - } - current.x = 0; - current.y = 0; - first.x = 0; - first.y = 0; - has_current = 0; - has_edge = 0; + default: + status = (*close_path) (closure); break; } + if (status) + return status; } } - if (has_edge) - (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_CAP); - return (*cb->done_path) (closure); + return CAIRO_STATUS_SUCCESS; } diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c new file mode 100644 index 000000000..dcdb1566a --- /dev/null +++ b/src/cairo-pattern.c @@ -0,0 +1,716 @@ +/* + * Copyright © 2002 University of Southern California + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <c99drn@cs.umu.se> + */ + +#include "cairoint.h" + +void +_cairo_pattern_init (cairo_pattern_t *pattern) +{ + pattern->ref_count = 1; + + pattern->extend = CAIRO_EXTEND_DEFAULT; + pattern->filter = CAIRO_FILTER_DEFAULT; + + _cairo_color_init (&pattern->color); + + _cairo_matrix_init (&pattern->matrix); + + pattern->stops = NULL; + pattern->n_stops = 0; + + pattern->type = CAIRO_PATTERN_SOLID; + + pattern->source = NULL; + pattern->source_offset.x = 0.0; + pattern->source_offset.y = 0.0; +} + +cairo_status_t +_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other) +{ + *pattern = *other; + + pattern->ref_count = 1; + + if (pattern->n_stops) { + pattern->stops = + malloc (sizeof (cairo_color_stop_t) * pattern->n_stops); + if (pattern->stops == NULL) + return CAIRO_STATUS_NO_MEMORY; + memcpy (pattern->stops, other->stops, + sizeof (cairo_color_stop_t) * other->n_stops); + } + + if (pattern->source) + cairo_surface_reference (other->source); + + if (pattern->type == CAIRO_PATTERN_SURFACE) + cairo_surface_reference (other->u.surface.surface); + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_pattern_fini (cairo_pattern_t *pattern) +{ + if (pattern->n_stops) + free (pattern->stops); + + if (pattern->type == CAIRO_PATTERN_SURFACE) { + /* show_surface require us to restore surface matrix, repeat + attribute, filter type */ + if (pattern->source) { + cairo_surface_set_matrix (pattern->source, + &pattern->u.surface.save_matrix); + cairo_surface_set_repeat (pattern->source, + pattern->u.surface.save_repeat); + cairo_surface_set_filter (pattern->source, + pattern->u.surface.save_filter); + } + cairo_surface_destroy (pattern->u.surface.surface); + } + + if (pattern->source) + cairo_surface_destroy (pattern->source); +} + +void +_cairo_pattern_init_solid (cairo_pattern_t *pattern, + double red, double green, double blue) +{ + _cairo_pattern_init (pattern); + + pattern->type = CAIRO_PATTERN_SOLID; + _cairo_color_set_rgb (&pattern->color, red, green, blue); +} + +cairo_pattern_t * +_cairo_pattern_create_solid (double red, double green, double blue) +{ + cairo_pattern_t *pattern; + + pattern = malloc (sizeof (cairo_pattern_t)); + if (pattern == NULL) + return NULL; + + _cairo_pattern_init_solid (pattern, red, green, blue); + + return pattern; +} + +cairo_pattern_t * +cairo_pattern_create_for_surface (cairo_surface_t *surface) +{ + cairo_pattern_t *pattern; + + pattern = malloc (sizeof (cairo_pattern_t)); + if (pattern == NULL) + return NULL; + + _cairo_pattern_init (pattern); + + pattern->type = CAIRO_PATTERN_SURFACE; + pattern->u.surface.surface = surface; + cairo_surface_reference (surface); + + return pattern; +} + +cairo_pattern_t * +cairo_pattern_create_linear (double x0, double y0, double x1, double y1) +{ + cairo_pattern_t *pattern; + + pattern = malloc (sizeof (cairo_pattern_t)); + if (pattern == NULL) + return NULL; + + _cairo_pattern_init (pattern); + + pattern->type = CAIRO_PATTERN_LINEAR; + pattern->u.linear.point0.x = x0; + pattern->u.linear.point0.y = y0; + pattern->u.linear.point1.x = x1; + pattern->u.linear.point1.y = y1; + + return pattern; +} + +cairo_pattern_t * +cairo_pattern_create_radial (double cx0, double cy0, double radius0, + double cx1, double cy1, double radius1) +{ + cairo_pattern_t *pattern; + + pattern = malloc (sizeof (cairo_pattern_t)); + if (pattern == NULL) + return NULL; + + _cairo_pattern_init (pattern); + + pattern->type = CAIRO_PATTERN_RADIAL; + pattern->u.radial.center0.x = cx0; + pattern->u.radial.center0.y = cy0; + pattern->u.radial.radius0.dx = radius0; + pattern->u.radial.radius0.dy = radius0; + pattern->u.radial.center1.x = cx1; + pattern->u.radial.center1.y = cy1; + pattern->u.radial.radius1.dx = radius1; + pattern->u.radial.radius1.dy = radius1; + + return pattern; +} + +void +cairo_pattern_reference (cairo_pattern_t *pattern) +{ + if (pattern == NULL) + return; + + pattern->ref_count++; +} + +void +cairo_pattern_destroy (cairo_pattern_t *pattern) +{ + if (pattern == NULL) + return; + + pattern->ref_count--; + if (pattern->ref_count) + return; + + _cairo_pattern_fini (pattern); + free (pattern); +} + +static int +_cairo_pattern_stop_compare (const void *elem1, const void *elem2) +{ + return + (((cairo_color_stop_t *) elem1)->offset == + ((cairo_color_stop_t *) elem2)->offset) ? + /* equal offsets, sort on id */ + ((((cairo_color_stop_t *) elem1)->id < + ((cairo_color_stop_t *) elem2)->id) ? -1 : 1) : + /* sort on offset */ + ((((cairo_color_stop_t *) elem1)->offset < + ((cairo_color_stop_t *) elem2)->offset) ? -1 : 1); +} + +cairo_status_t +cairo_pattern_add_color_stop (cairo_pattern_t *pattern, + double offset, + double red, double green, double blue, + double alpha) +{ + cairo_color_stop_t *stop; + + _cairo_restrict_value (&offset, 0.0, 1.0); + _cairo_restrict_value (&red, 0.0, 1.0); + _cairo_restrict_value (&green, 0.0, 1.0); + _cairo_restrict_value (&blue, 0.0, 1.0); + + pattern->n_stops++; + pattern->stops = realloc (pattern->stops, + sizeof (cairo_color_stop_t) * pattern->n_stops); + if (pattern->stops == NULL) { + pattern->n_stops = 0; + + return CAIRO_STATUS_NO_MEMORY; + } + + stop = &pattern->stops[pattern->n_stops - 1]; + + stop->offset = offset; + stop->id = pattern->n_stops; + _cairo_color_init (&stop->color); + _cairo_color_set_rgb (&stop->color, red, green, blue); + _cairo_color_set_alpha (&stop->color, alpha); + stop->color_char[0] = stop->color.red_short / 256; + stop->color_char[1] = stop->color.green_short / 256; + stop->color_char[2] = stop->color.blue_short / 256; + stop->color_char[3] = stop->color.alpha_short / 256; + + /* sort stops in ascending order */ + qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t), + _cairo_pattern_stop_compare); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) +{ + cairo_matrix_copy (&pattern->matrix, matrix); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) +{ + cairo_matrix_copy (matrix, &pattern->matrix); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) +{ + pattern->filter = filter; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_filter_t +cairo_pattern_get_filter (cairo_pattern_t *pattern) +{ + return pattern->filter; +} + +cairo_status_t +cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend) +{ + pattern->extend = extend; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_extend_t +cairo_pattern_get_extend (cairo_pattern_t *pattern) +{ + return pattern->extend; +} + +cairo_status_t +_cairo_pattern_get_rgb (cairo_pattern_t *pattern, + double *red, double *green, double *blue) +{ + _cairo_color_get_rgb (&pattern->color, red, green, blue); + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha) +{ + int i; + + _cairo_color_set_alpha (&pattern->color, alpha); + + for (i = 0; i < pattern->n_stops; i++) { + cairo_color_stop_t *stop = &pattern->stops[i]; + + _cairo_color_set_alpha (&stop->color, stop->color.alpha * alpha); + + stop->color_char[0] = stop->color.red_short / 256; + stop->color_char[1] = stop->color.green_short / 256; + stop->color_char[2] = stop->color.blue_short / 256; + stop->color_char[3] = stop->color.alpha_short / 256; + } +} + +void +_cairo_pattern_add_source_offset (cairo_pattern_t *pattern, + double x, double y) +{ + pattern->source_offset.x += x; + pattern->source_offset.y += y; +} + +void +_cairo_pattern_transform (cairo_pattern_t *pattern, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse) +{ + cairo_matrix_t matrix; + + switch (pattern->type) { + case CAIRO_PATTERN_SURFACE: + /* hmm, maybe we should instead multiply with the inverse of the + pattern matrix here? */ + cairo_matrix_multiply (&pattern->matrix, ctm_inverse, + &pattern->matrix); + break; + case CAIRO_PATTERN_LINEAR: + cairo_matrix_multiply (&matrix, &pattern->matrix, ctm); + cairo_matrix_transform_point (&matrix, + &pattern->u.linear.point0.x, + &pattern->u.linear.point0.y); + cairo_matrix_transform_point (&matrix, + &pattern->u.linear.point1.x, + &pattern->u.linear.point1.y); + break; + case CAIRO_PATTERN_RADIAL: + cairo_matrix_multiply (&matrix, &pattern->matrix, ctm); + cairo_matrix_transform_point (&matrix, + &pattern->u.radial.center0.x, + &pattern->u.radial.center0.y); + cairo_matrix_transform_distance (&matrix, + &pattern->u.radial.radius0.dx, + &pattern->u.radial.radius0.dy); + cairo_matrix_transform_point (&matrix, + &pattern->u.radial.center1.x, + &pattern->u.radial.center1.y); + cairo_matrix_transform_distance (&matrix, + &pattern->u.radial.radius1.dx, + &pattern->u.radial.radius1.dy); + break; + case CAIRO_PATTERN_SOLID: + break; + } +} + +void +_cairo_pattern_prepare_surface (cairo_pattern_t *pattern) +{ + cairo_matrix_t device_to_source; + cairo_matrix_t user_to_source; + + /* should the surface matrix interface be remove from the API? + for now we multiple the surface matrix with the pattern matrix */ + cairo_surface_get_matrix (pattern->u.surface.surface, &user_to_source); + cairo_matrix_multiply (&device_to_source, &pattern->matrix, + &user_to_source); + cairo_surface_set_matrix (pattern->source, &device_to_source); + + /* storing original surface matrix in pattern */ + pattern->u.surface.save_matrix = user_to_source; + + /* storing original surface repeat mode in pattern */ + pattern->u.surface.save_repeat = pattern->source->repeat; + + /* what do we do with extend types pad and reflect? */ + if (pattern->extend == CAIRO_EXTEND_REPEAT + || pattern->source->repeat == 1) + cairo_surface_set_repeat (pattern->source, 1); + else + cairo_surface_set_repeat (pattern->source, 0); + + /* storing original surface filter in pattern */ + pattern->u.surface.save_filter = + cairo_surface_get_filter (pattern->source); + + cairo_surface_set_filter (pattern->source, pattern->filter); +} + +typedef void (*cairo_shader_function_t) (unsigned char *color0, + unsigned char *color1, + double factor, + unsigned char *result_color); + +#define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \ + ((unsigned char) ((factor < 0.5)? c1: c2)) + +static void +_cairo_pattern_shader_nearest (unsigned char *color0, + unsigned char *color1, + double factor, + unsigned char *result_color) +{ + result_color[0] = INTERPOLATE_COLOR_NEAREST (color0[0], color1[0], factor); + result_color[1] = INTERPOLATE_COLOR_NEAREST (color0[1], color1[1], factor); + result_color[2] = INTERPOLATE_COLOR_NEAREST (color0[2], color1[2], factor); + result_color[3] = INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor); +} + +#undef INTERPOLATE_COLOR_NEAREST + +#define INTERPOLATE_COLOR_LINEAR(c1, c2, factor) \ + ((unsigned char) ((c2 * factor) + (c1 * (1.0 - factor)))) + +static void +_cairo_pattern_shader_linear (unsigned char *color0, + unsigned char *color1, + double factor, + unsigned char *result_color) +{ + result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor); + result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor); + result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor); + result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor); +} + +static void +_cairo_pattern_shader_gaussian (unsigned char *color0, + unsigned char *color1, + double factor, + unsigned char *result_color) +{ + factor = (exp (factor * factor) - 1.0) / (M_E - 1.0); + + result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor); + result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor); + result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor); + result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor); +} + +#undef INTERPOLATE_COLOR_LINEAR + +void +_cairo_pattern_calc_color_at_pixel (cairo_pattern_t *pattern, + double factor, + int *pixel) +{ + int p, colorstop; + double factorscale; + unsigned char result_color[4]; + cairo_shader_function_t shader_function; + + switch (pattern->filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + shader_function = _cairo_pattern_shader_nearest; + break; + case CAIRO_FILTER_GAUSSIAN: + shader_function = _cairo_pattern_shader_gaussian; + break; + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + shader_function = _cairo_pattern_shader_linear; + break; + } + + if (factor > 1.0 || factor < 0.0) { + switch (pattern->extend) { + case CAIRO_EXTEND_REPEAT: + factor -= floor (factor); + break; + case CAIRO_EXTEND_REFLECT: + if (factor >= 0.0) { + if (((int) factor) % 2) + factor = 1.0 - (factor - floor (factor)); + else + factor -= floor (factor); + } else { + if (((int) factor) % 2) + factor -= floor (factor); + else + factor = 1.0 - (factor - floor (factor)); + } + break; + case CAIRO_EXTEND_NONE: + break; + } + } + + if (factor < pattern->stops[0].offset) + factor = pattern->stops[0].offset; + + if (factor > pattern->stops[pattern->n_stops - 1].offset) + factor = pattern->stops[pattern->n_stops - 1].offset; + + for (colorstop = 0; colorstop < pattern->n_stops - 1; colorstop++) { + if (factor <= pattern->stops[colorstop + 1].offset) { + factorscale = fabs (pattern->stops[colorstop].offset - + pattern->stops[colorstop + 1].offset); + + /* abrubt change, difference between two offsets == 0.0 */ + if (factorscale == 0) + break; + + factor -= pattern->stops[colorstop].offset; + + /* take offset as new 0 of coordinate system */ + factor /= factorscale; + + shader_function (pattern->stops[colorstop].color_char, + pattern->stops[colorstop + 1].color_char, + factor, result_color); + + p = ((result_color[3] << 24) | + (result_color[0] << 16) | + (result_color[1] << 8) | (result_color[2] << 0)); + *pixel = p; + break; + } + } +} + +static void +_cairo_image_data_set_linear (cairo_pattern_t *pattern, + double offset_x, + double offset_y, + char *data, + int width, + int height) +{ + int x, y; + cairo_point_double_t point0, point1, angle; + double a, length, start, end; + double factor; + + point0.x = pattern->u.linear.point0.x - offset_x; + point0.y = pattern->u.linear.point0.y - offset_y; + point1.x = pattern->u.linear.point1.x - offset_x; + point1.y = pattern->u.linear.point1.y - offset_y; + + length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) + + (point1.y - point0.y) * (point1.y - point0.y)); + length = (length) ? 1.0 / length : INT_MAX; + + a = -atan2 (point1.y - point0.y, point1.x - point0.x); + angle.x = cos (a); + angle.y = -sin (a); + + start = angle.x * point0.x; + start += angle.y * point0.y; + + end = angle.x * point1.x; + end += angle.y * point1.y; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + + factor = angle.x * (double) x; + factor += angle.y * (double) y; + + factor = factor - start; + factor *= length; + + _cairo_pattern_calc_color_at_pixel (pattern, factor, (int *) + &data[y * width * 4 + x * 4]); + } + } +} + +/* TODO: Inner circle is currently ignored. */ +static void +_cairo_image_data_set_radial (cairo_pattern_t *pattern, + double offset_x, + double offset_y, + char *data, + int width, + int height) +{ + int x, y; + cairo_point_double_t center1, pos; + cairo_distance_double_t length; + double factor; + double min_length; + + center1.x = pattern->u.radial.center1.x - offset_x; + center1.y = pattern->u.radial.center1.y - offset_y; + + min_length = + fabs ((pattern->u.radial.radius1.dx < pattern->u.radial.radius1.dy) ? + pattern->u.radial.radius1.dx : pattern->u.radial.radius1.dy); + + /* ugly */ + if (min_length == 0.0) + min_length = 0.000001; + + length.dx = min_length / pattern->u.radial.radius1.dx; + length.dy = min_length / pattern->u.radial.radius1.dy; + + min_length = 1.0 / min_length; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + pos.x = x - center1.x; + pos.y = y - center1.y; + + pos.x *= length.dx; + pos.y *= length.dy; + + factor = sqrt (pos.x * pos.x + pos.y * pos.y) * min_length; + + _cairo_pattern_calc_color_at_pixel (pattern, factor, (int *) + &data[y * width * 4 + x * 4]); + } + } +} + +cairo_image_surface_t * +_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box) +{ + cairo_surface_t *surface; + + switch (pattern->type) { + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + char *data; + int width = ceil (_cairo_fixed_to_double (box->p2.x) - + _cairo_fixed_to_double (box->p1.x)); + int height = ceil (_cairo_fixed_to_double (box->p2.y) - + _cairo_fixed_to_double (box->p1.y)); + + data = malloc (width * height * 4); + if (!data) + return NULL; + + _cairo_pattern_add_source_offset (pattern, + _cairo_fixed_to_double (box->p1.x), + _cairo_fixed_to_double (box->p1.y)); + + if (pattern->type == CAIRO_PATTERN_RADIAL) + _cairo_image_data_set_radial (pattern, + pattern->source_offset.x, + pattern->source_offset.y, + data, width, height); + else + _cairo_image_data_set_linear (pattern, + pattern->source_offset.x, + pattern->source_offset.y, + data, width, height); + + surface = cairo_image_surface_create_for_data (data, + CAIRO_FORMAT_ARGB32, + width, height, + width * 4); + + if (surface) + _cairo_image_surface_assume_ownership_of_data ( + (cairo_image_surface_t *) surface); + } + break; + case CAIRO_PATTERN_SOLID: + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + if (surface) { + _cairo_surface_fill_rectangle (surface, + CAIRO_OPERATOR_SRC, + &pattern->color, 0, 0, 1, 1); + cairo_surface_set_repeat (surface, 1); + } + break; + case CAIRO_PATTERN_SURFACE: { + cairo_image_surface_t *image; + + image = _cairo_surface_get_image (pattern->u.surface.surface); + if (image) + surface = &image->base; + else + surface = NULL; + + } + break; + } + + return (cairo_image_surface_t *) surface; +} diff --git a/src/cairo-pen.c b/src/cairo-pen.c index dd054372d..0bb5debd9 100644 --- a/src/cairo-pen.c +++ b/src/cairo-pen.c @@ -288,7 +288,7 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen, while (i != stop) { hull_point.x = point[i].x + pen->vertices[active].point.x; hull_point.y = point[i].y + pen->vertices[active].point.y; - status = _cairo_polygon_add_point (polygon, &hull_point); + status = _cairo_polygon_line_to (polygon, &hull_point); if (status) return status; diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c index 97f074a33..fbda73211 100644 --- a/src/cairo-polygon.c +++ b/src/cairo-polygon.c @@ -35,9 +35,6 @@ static cairo_status_t _cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional); -static void -_cairo_polygon_set_last_point (cairo_polygon_t *polygon, cairo_point_t *point); - void _cairo_polygon_init (cairo_polygon_t *polygon) { @@ -46,10 +43,7 @@ _cairo_polygon_init (cairo_polygon_t *polygon) polygon->edges_size = 0; polygon->edges = NULL; - polygon->first_point_defined = 0; - polygon->last_point_defined = 0; - - polygon->closed = 0; + polygon->has_current_point = 0; } void @@ -62,10 +56,7 @@ _cairo_polygon_fini (cairo_polygon_t *polygon) polygon->num_edges = 0; } - polygon->first_point_defined = 0; - polygon->last_point_defined = 0; - - polygon->closed = 0; + polygon->has_current_point = 0; } static cairo_status_t @@ -92,25 +83,12 @@ _cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional) return CAIRO_STATUS_SUCCESS; } -static void -_cairo_polygon_set_last_point (cairo_polygon_t *polygon, cairo_point_t *point) -{ - polygon->last_point = *point; - polygon->last_point_defined = 1; -} - cairo_status_t _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2) { cairo_status_t status; cairo_edge_t *edge; - if (! polygon->first_point_defined) { - polygon->first_point = *p1; - polygon->first_point_defined = 1; - polygon->closed = 0; - } - /* drop horizontal edges */ if (p1->y == p2->y) { goto DONE; @@ -137,20 +115,31 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_poin polygon->num_edges++; DONE: - _cairo_polygon_set_last_point (polygon, p2); + _cairo_polygon_move_to (polygon, p2); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point) +{ + if (! polygon->has_current_point) + polygon->first_point = *point; + polygon->current_point = *point; + polygon->has_current_point = 1; return CAIRO_STATUS_SUCCESS; } cairo_status_t -_cairo_polygon_add_point (cairo_polygon_t *polygon, cairo_point_t *point) +_cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point) { cairo_status_t status = CAIRO_STATUS_SUCCESS; - if (polygon->last_point_defined) { - status = _cairo_polygon_add_edge (polygon, &polygon->last_point, point); + if (polygon->has_current_point) { + status = _cairo_polygon_add_edge (polygon, &polygon->current_point, point); } else { - _cairo_polygon_set_last_point (polygon, point); + _cairo_polygon_move_to (polygon, point); } return status; @@ -161,13 +150,14 @@ _cairo_polygon_close (cairo_polygon_t *polygon) { cairo_status_t status; - if (polygon->closed == 0 && polygon->last_point_defined) { - status = _cairo_polygon_add_edge (polygon, &polygon->last_point, &polygon->first_point); + if (polygon->has_current_point) { + status = _cairo_polygon_add_edge (polygon, + &polygon->current_point, + &polygon->first_point); if (status) return status; - polygon->closed = 1; - polygon->first_point_defined = 0; + polygon->has_current_point = 0; } return CAIRO_STATUS_SUCCESS; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index c66b70987..98d34e44d 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -286,19 +286,19 @@ _cairo_ps_surface_copy_page (void *abstract_surface) int i, x, y; cairo_surface_t *white_surface; - char *bgr, *compressed; - long bgr_size, compressed_size; + char *rgb, *compressed; + long rgb_size, compressed_size; cairo_color_t white; - bgr_size = 3 * width * height; - bgr = malloc (bgr_size); - if (bgr == NULL) { + rgb_size = 3 * width * height; + rgb = malloc (rgb_size); + if (rgb == NULL) { status = CAIRO_STATUS_NO_MEMORY; goto BAIL0; } - compressed_size = (int) (1.0 + 1.1 * bgr_size); + compressed_size = (int) (1.0 + 1.1 * rgb_size); compressed = malloc (compressed_size); if (compressed == NULL) { status = CAIRO_STATUS_NO_MEMORY; @@ -330,16 +330,15 @@ _cairo_ps_surface_copy_page (void *abstract_surface) i = 0; for (y = 0; y < height; y++) { - char *line = surface->image->data + y * surface->image->stride; - for (x = 0; x < width; x++) { - unsigned char *pixel = (unsigned char *) line + x * 4; - bgr[i++] = *(pixel+2); - bgr[i++] = *(pixel+1); - bgr[i++] = *(pixel); + pixman_bits_t *pixel = (pixman_bits_t *) (surface->image->data + y * surface->image->stride); + for (x = 0; x < width; x++, pixel++) { + rgb[i++] = (*pixel & 0x00ff0000) >> 16; + rgb[i++] = (*pixel & 0x0000ff00) >> 8; + rgb[i++] = (*pixel & 0x000000ff) >> 0; } } - compress (compressed, &compressed_size, bgr, bgr_size); + compress (compressed, &compressed_size, rgb, rgb_size); /* Page header */ fprintf (file, "%%%%Page: %d\n", ++surface->pages); @@ -375,7 +374,7 @@ _cairo_ps_surface_copy_page (void *abstract_surface) BAIL2: free (compressed); BAIL1: - free (bgr); + free (rgb); BAIL0: return status; } @@ -395,6 +394,23 @@ _cairo_ps_surface_show_page (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_ps_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + cairo_ps_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_clip_region (surface->image, region); +} + +static cairo_int_status_t +_cairo_ps_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_create_similar, _cairo_ps_surface_destroy, @@ -408,5 +424,7 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_fill_rectangles, _cairo_ps_surface_composite_trapezoids, _cairo_ps_surface_copy_page, - _cairo_ps_surface_show_page + _cairo_ps_surface_show_page, + _cairo_ps_surface_set_clip_region, + _cairo_ps_surface_create_pattern }; diff --git a/src/cairo-surface.c b/src/cairo-surface.c index ff4f39c1f..91ab8aba4 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -38,6 +38,7 @@ _cairo_surface_init (cairo_surface_t *surface, surface->ref_count = 1; _cairo_matrix_init (&surface->matrix); + surface->filter = CAIRO_FILTER_NEAREST; surface->repeat = 0; } @@ -165,9 +166,16 @@ cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter) if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; + surface->filter = filter; return surface->backend->set_filter (surface, filter); } +cairo_filter_t +cairo_surface_get_filter (cairo_surface_t *surface) +{ + return surface->filter; +} + /* XXX: NYI cairo_status_t cairo_surface_clip_rectangle (cairo_surface_t *surface, @@ -364,3 +372,116 @@ _cairo_surface_show_page (cairo_surface_t *surface) return CAIRO_STATUS_SUCCESS; } +cairo_status_t +_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region) +{ + return surface->backend->set_clip_region (surface, region); +} + +cairo_status_t +_cairo_surface_create_pattern (cairo_surface_t *surface, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_int_status_t status; + + status = surface->backend->create_pattern (surface, pattern, box); + + /* The backend cannot accelerate this pattern, lets create an + unaccelerated source instead. */ + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + + status = CAIRO_STATUS_SUCCESS; + switch (pattern->type) { + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_image_surface_t *image; + + image = _cairo_pattern_get_image (pattern, box); + if (image) { + pattern->source = &image->base; + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; + + } break; + case CAIRO_PATTERN_SOLID: + pattern->source = + _cairo_surface_create_similar_solid (surface, + CAIRO_FORMAT_ARGB32, + 1, 1, + &pattern->color); + if (pattern->source) { + cairo_surface_set_repeat (pattern->source, 1); + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; + break; + case CAIRO_PATTERN_SURFACE: + status = CAIRO_INT_STATUS_UNSUPPORTED; + + /* handle pattern opacity */ + if (pattern->color.alpha != 1.0) { + int width = ceil (_cairo_fixed_to_double (box->p2.x) - + _cairo_fixed_to_double (box->p1.x)); + int height = ceil (_cairo_fixed_to_double (box->p2.y) - + _cairo_fixed_to_double (box->p1.y)); + cairo_pattern_t alpha; + + pattern->source = + cairo_surface_create_similar (surface, + CAIRO_FORMAT_ARGB32, + width, height); + if (pattern->source) { + _cairo_pattern_init_solid (&alpha, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&alpha, pattern->color.alpha); + + status = _cairo_surface_create_pattern (pattern->source, + &alpha, box); + + if (status == CAIRO_STATUS_SUCCESS) { + int save_repeat = pattern->u.surface.surface->repeat; + + if (pattern->extend == CAIRO_EXTEND_REPEAT || + pattern->u.surface.surface->repeat == 1) + cairo_surface_set_repeat (pattern->u.surface.surface, 1); + else + cairo_surface_set_repeat (pattern->u.surface.surface, 0); + + status = + _cairo_surface_composite (CAIRO_OPERATOR_OVER, + pattern->u.surface.surface, + alpha.source, + pattern->source, + 0, 0, 0, 0, 0, 0, + width, height); + + cairo_surface_set_repeat (pattern->u.surface.surface, + save_repeat); + + if (status == CAIRO_STATUS_SUCCESS) { + _cairo_pattern_add_source_offset (pattern, + _cairo_fixed_to_double (box->p1.x), + _cairo_fixed_to_double (box->p1.y)); + } else + cairo_surface_destroy (pattern->source); + } + + _cairo_pattern_fini (&alpha); + } + } + + if (status != CAIRO_STATUS_SUCCESS) { + pattern->source = pattern->u.surface.surface; + cairo_surface_reference (pattern->u.surface.surface); + + return CAIRO_STATUS_SUCCESS; + } + break; + } + } + + return status; +} diff --git a/src/cairo-traps.c b/src/cairo-traps.c index 63df3ea45..9b44d38ea 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -58,7 +58,7 @@ _compute_inverse_slope (cairo_line_t *l); static double _compute_x_intercept (cairo_line_t *l, double inverse_slope); -static cairo_fixed_t +static int _line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret); void @@ -490,7 +490,7 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ */ cairo_status_t _cairo_traps_tessellate_polygon (cairo_traps_t *traps, - cairo_polygon_t *poly, + cairo_polygon_t *poly, cairo_fill_rule_t fill_rule) { cairo_status_t status; @@ -608,3 +608,40 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y) return 0; } + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +static void +_cairo_trap_extents (cairo_trapezoid_t *t, cairo_box_t *extents) +{ + cairo_fixed_t x; + + if (t->top < extents->p1.y) + extents->p1.y = t->top; + + if (t->bottom > extents->p2.y) + extents->p2.y = t->bottom; + + x = MIN (_compute_x (&t->left, t->top), + _compute_x (&t->left, t->bottom)); + if (x < extents->p1.x) + extents->p1.x = x; + + x = MAX (_compute_x (&t->right, t->top), + _compute_x (&t->right, t->bottom)); + if (x > extents->p2.x) + extents->p2.x = x; +} + +void +_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents) +{ + int i; + + extents->p1.x = extents->p1.y = SHRT_MAX << 16; + extents->p2.x = extents->p2.y = SHRT_MIN << 16; + + for (i = 0; i < traps->num_traps; i++) + _cairo_trap_extents (&traps->traps[i], extents); +} diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c new file mode 100644 index 000000000..ea1f72e16 --- /dev/null +++ b/src/cairo-xcb-surface.c @@ -0,0 +1,799 @@ +/* + * Copyright © 2002 University of Southern California + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth <cworth@isi.edu> + */ + +#include "cairoint.h" + +cairo_surface_t * +cairo_xcb_surface_create (XCBConnection *dpy, + XCBDRAWABLE drawable, + XCBVISUALTYPE *visual, + cairo_format_t format); + +#define AllPlanes ((unsigned long)~0L) + +static XCBRenderPICTFORMAT +format_from_visual(XCBConnection *c, XCBVISUALID visual) +{ + static const XCBRenderPICTFORMAT nil = { 0 }; + XCBRenderQueryPictFormatsRep *r; + XCBRenderPICTSCREENIter si; + XCBRenderPICTDEPTHIter di; + XCBRenderPICTVISUALIter vi; + + r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0); + if(!r) + return nil; + + for(si = XCBRenderQueryPictFormatsScreens(r); si.rem; XCBRenderPICTSCREENNext(&si)) + for(di = XCBRenderPICTSCREENDepths(si.data); di.rem; XCBRenderPICTDEPTHNext(&di)) + for(vi = XCBRenderPICTDEPTHVisuals(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi)) + if(vi.data->visual.id == visual.id) + { + XCBRenderPICTFORMAT ret = vi.data->format; + free(r); + return ret; + } + + return nil; +} + +static XCBRenderPICTFORMAT +format_from_cairo(XCBConnection *c, cairo_format_t fmt) +{ + XCBRenderPICTFORMAT ret = { 0 }; + struct tmpl_t { + XCBRenderDIRECTFORMAT direct; + CARD8 depth; + }; + static const struct tmpl_t templates[] = { + /* CAIRO_FORMAT_ARGB32 */ + { + { + 16, 0xff, + 8, 0xff, + 0, 0xff, + 24, 0xff + }, + 32 + }, + /* CAIRO_FORMAT_RGB24 */ + { + { + 16, 0xff, + 8, 0xff, + 0, 0xff, + 0, 0x00 + }, + 24 + }, + /* CAIRO_FORMAT_A8 */ + { + { + 0, 0x00, + 0, 0x00, + 0, 0x00, + 0, 0xff + }, + 8 + }, + /* CAIRO_FORMAT_A1 */ + { + { + 0, 0x00, + 0, 0x00, + 0, 0x00, + 0, 0x01 + }, + 1 + }, + }; + const struct tmpl_t *tmpl; + XCBRenderQueryPictFormatsRep *r; + XCBRenderPICTFORMINFOIter fi; + + if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates))) + return ret; + tmpl = templates + fmt; + + r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0); + if(!r) + return ret; + + for(fi = XCBRenderQueryPictFormatsFormats(r); fi.rem; XCBRenderPICTFORMINFONext(&fi)) + { + const XCBRenderDIRECTFORMAT *t, *f; + if(fi.data->type != XCBRenderPictTypeDirect) + continue; + if(fi.data->depth != tmpl->depth) + continue; + t = &tmpl->direct; + f = &fi.data->direct; + if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift)) + continue; + if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift)) + continue; + if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift)) + continue; + if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift)) + continue; + + ret = fi.data->id; + } + + free(r); + return ret; +} + +void +cairo_set_target_xcb (cairo_t *cr, + XCBConnection *dpy, + XCBDRAWABLE drawable, + XCBVISUALTYPE *visual, + cairo_format_t format) +{ + cairo_surface_t *surface; + + if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE) + return; + + surface = cairo_xcb_surface_create (dpy, drawable, visual, format); + if (surface == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + cairo_set_target_surface (cr, surface); + + /* cairo_set_target_surface takes a reference, so we must destroy ours */ + cairo_surface_destroy (surface); +} + +typedef struct cairo_xcb_surface { + cairo_surface_t base; + + XCBConnection *dpy; + XCBGCONTEXT gc; + XCBDRAWABLE drawable; + int owns_pixmap; + XCBVISUALTYPE *visual; + cairo_format_t format; + + int render_major; + int render_minor; + + int width; + int height; + + XCBRenderPICTURE picture; +} cairo_xcb_surface_t; + +#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \ + (((surface)->render_major > major) || \ + (((surface)->render_major == major) && ((surface)->render_minor >= minor))) + +#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) +#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) + +#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1) +#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1) + +#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2) +#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2) + +#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) +#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) +#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) +#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) + +#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) +#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) + +static int +_CAIRO_FORMAT_DEPTH (cairo_format_t format) +{ + switch (format) { + case CAIRO_FORMAT_A1: + return 1; + case CAIRO_FORMAT_A8: + return 8; + case CAIRO_FORMAT_RGB24: + return 24; + case CAIRO_FORMAT_ARGB32: + default: + return 32; + } +} + +static cairo_surface_t * +_cairo_xcb_surface_create_similar (void *abstract_src, + cairo_format_t format, + int width, + int height) +{ + cairo_xcb_surface_t *src = abstract_src; + XCBConnection *dpy = src->dpy; + XCBDRAWABLE d; + cairo_xcb_surface_t *surface; + + /* XXX: There's a pretty lame heuristic here. This assumes that + * all non-Render X servers do not support depth-32 pixmaps, (and + * that they do support depths 1, 8, and 24). Obviously, it would + * be much better to check the depths that are actually + * supported. */ + if (!dpy + || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src) + && format == CAIRO_FORMAT_ARGB32)) + { + return NULL; + } + + d.pixmap = XCBPIXMAPNew (dpy); + XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format), + d.pixmap, src->drawable, + width, height); + + surface = (cairo_xcb_surface_t *) + cairo_xcb_surface_create (dpy, d, NULL, format); + surface->owns_pixmap = 1; + + surface->width = width; + surface->height = height; + + return &surface->base; +} + +static void +_cairo_xcb_surface_destroy (void *abstract_surface) +{ + cairo_xcb_surface_t *surface = abstract_surface; + if (surface->picture.xid) + XCBRenderFreePicture (surface->dpy, surface->picture); + + if (surface->owns_pixmap) + XCBFreePixmap (surface->dpy, surface->drawable.pixmap); + + if (surface->gc.xid) + XCBFreeGC (surface->dpy, surface->gc); + + surface->dpy = 0; + + free (surface); +} + +static double +_cairo_xcb_surface_pixels_per_inch (void *abstract_surface) +{ + /* XXX: We should really get this value from somewhere like Xft.dpy */ + return 96.0; +} + +static int +bits_per_pixel(XCBConnection *c, int depth) +{ + XCBFORMAT *fmt = XCBConnSetupSuccessRepPixmapFormats(XCBGetSetup(c)); + XCBFORMAT *fmtend = fmt + XCBConnSetupSuccessRepPixmapFormatsLength(XCBGetSetup(c)); + + for(; fmt != fmtend; ++fmt) + if(fmt->depth == depth) + return fmt->bits_per_pixel; + + if(depth <= 4) + return 4; + if(depth <= 8) + return 8; + if(depth <= 16) + return 16; + return 32; +} + +static int +bytes_per_line(XCBConnection *c, int width, int bpp) +{ + int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad; + return (bpp * width + bitmap_pad - 1) & -bitmap_pad; +} + +static cairo_image_surface_t * +_cairo_xcb_surface_get_image (void *abstract_surface) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + XCBGetGeometryRep *geomrep; + XCBGetImageRep *imagerep; + int bpp; + + geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0); + if(!geomrep) + return 0; + + surface->width = geomrep->width; + surface->height = geomrep->height; + free(geomrep); + + imagerep = XCBGetImageReply(surface->dpy, + XCBGetImage(surface->dpy, ZPixmap, + surface->drawable, + 0, 0, + surface->width, surface->height, + AllPlanes), 0); + if(!imagerep) + return 0; + + bpp = bits_per_pixel(surface->dpy, imagerep->depth); + + if (surface->visual) { + cairo_format_masks_t masks; + + /* XXX: Add support here for pictures with external alpha? */ + + masks.bpp = bpp; + masks.alpha_mask = 0; + masks.red_mask = surface->visual->red_mask; + masks.green_mask = surface->visual->green_mask; + masks.blue_mask = surface->visual->blue_mask; + + image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep), + &masks, + surface->width, + surface->height, + bytes_per_line(surface->dpy, surface->width, bpp)); + } else { + image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (XCBGetImageData(imagerep), + surface->format, + surface->width, + surface->height, + bytes_per_line(surface->dpy, surface->width, bpp)); + } + + /* Let the surface take ownership of the data */ + /* XXX: Can probably come up with a cleaner API here. */ + _cairo_image_surface_assume_ownership_of_data (image); + /* FIXME: imagerep can't be freed correctly, I think. must copy. :-( */ + + _cairo_image_surface_set_repeat (image, surface->base.repeat); + _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); + + return image; +} + +static void +_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface) +{ + if (surface->gc.xid) + return; + + surface->gc = XCBGCONTEXTNew(surface->dpy); + XCBCreateGC (surface->dpy, surface->gc, surface->drawable, 0, 0); +} + +static cairo_status_t +_cairo_xcb_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_xcb_surface_t *surface = abstract_surface; + int bpp, data_len; + + _cairo_xcb_surface_ensure_gc (surface); + bpp = bits_per_pixel(surface->dpy, image->depth); + data_len = bytes_per_line(surface->dpy, surface->width, bpp) * surface->height; + XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc, + image->width, + image->height, + /* dst_x */ 0, /* dst_y */ 0, + /* left_pad */ 0, image->depth, + data_len, image->data); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) +{ + cairo_xcb_surface_t *surface = abstract_surface; + XCBRenderTRANSFORM xtransform; + + if (!surface->picture.xid) + return CAIRO_STATUS_SUCCESS; + + xtransform.matrix11 = _cairo_fixed_from_double (matrix->m[0][0]); + xtransform.matrix12 = _cairo_fixed_from_double (matrix->m[1][0]); + xtransform.matrix13 = _cairo_fixed_from_double (matrix->m[2][0]); + + xtransform.matrix21 = _cairo_fixed_from_double (matrix->m[0][1]); + xtransform.matrix22 = _cairo_fixed_from_double (matrix->m[1][1]); + xtransform.matrix23 = _cairo_fixed_from_double (matrix->m[2][1]); + + xtransform.matrix31 = 0; + xtransform.matrix32 = 0; + xtransform.matrix33 = _cairo_fixed_from_double (1); + + if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) + { + XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform); + } else { + /* XXX: Need support here if using an old RENDER without support + for SetPictureTransform */ + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +{ + cairo_xcb_surface_t *surface = abstract_surface; + char *render_filter; + + if (!(surface->picture.xid + && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface))) + return CAIRO_STATUS_SUCCESS; + + switch (filter) { + case CAIRO_FILTER_FAST: + render_filter = "fast"; + break; + case CAIRO_FILTER_GOOD: + render_filter = "good"; + break; + case CAIRO_FILTER_BEST: + render_filter = "best"; + break; + case CAIRO_FILTER_NEAREST: + render_filter = "nearest"; + break; + case CAIRO_FILTER_BILINEAR: + render_filter = "bilinear"; + break; + default: + render_filter = "best"; + break; + } + + XCBRenderSetPictureFilter(surface->dpy, surface->picture, + strlen(render_filter), 0, render_filter, NULL); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat) +{ + cairo_xcb_surface_t *surface = abstract_surface; + + CARD32 mask = XCBRenderCPRepeat; + CARD32 pa[] = { repeat }; + + if (!surface->picture.xid) + return CAIRO_STATUS_SUCCESS; + + XCBRenderChangePicture (surface->dpy, surface->picture, mask, pa); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_xcb_surface_t * +_cairo_xcb_surface_clone_similar (cairo_surface_t *src, + cairo_xcb_surface_t *template, + cairo_format_t format, + int depth) +{ + cairo_xcb_surface_t *clone; + cairo_image_surface_t *src_image; + + src_image = _cairo_surface_get_image (src); + + clone = (cairo_xcb_surface_t *) + _cairo_xcb_surface_create_similar (template, format, + src_image->width, + src_image->height); + if (clone == NULL) + return NULL; + + _cairo_xcb_surface_set_filter (clone, cairo_surface_get_filter(src)); + + _cairo_xcb_surface_set_image (clone, src_image); + + _cairo_xcb_surface_set_matrix (clone, &(src_image->base.matrix)); + + cairo_surface_destroy (&src_image->base); + + return clone; +} + +static int +_render_operator (cairo_operator_t operator) +{ + switch (operator) { + case CAIRO_OPERATOR_CLEAR: + return XCBRenderPictOpClear; + case CAIRO_OPERATOR_SRC: + return XCBRenderPictOpSrc; + case CAIRO_OPERATOR_DST: + return XCBRenderPictOpDst; + case CAIRO_OPERATOR_OVER: + return XCBRenderPictOpOver; + case CAIRO_OPERATOR_OVER_REVERSE: + return XCBRenderPictOpOverReverse; + case CAIRO_OPERATOR_IN: + return XCBRenderPictOpIn; + case CAIRO_OPERATOR_IN_REVERSE: + return XCBRenderPictOpInReverse; + case CAIRO_OPERATOR_OUT: + return XCBRenderPictOpOut; + case CAIRO_OPERATOR_OUT_REVERSE: + return XCBRenderPictOpOutReverse; + case CAIRO_OPERATOR_ATOP: + return XCBRenderPictOpAtop; + case CAIRO_OPERATOR_ATOP_REVERSE: + return XCBRenderPictOpAtopReverse; + case CAIRO_OPERATOR_XOR: + return XCBRenderPictOpXor; + case CAIRO_OPERATOR_ADD: + return XCBRenderPictOpAdd; + case CAIRO_OPERATOR_SATURATE: + return XCBRenderPictOpSaturate; + default: + return XCBRenderPictOpOver; + } +} + +static cairo_int_status_t +_cairo_xcb_surface_composite (cairo_operator_t operator, + cairo_surface_t *generic_src, + cairo_surface_t *generic_mask, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_xcb_surface_t *dst = abstract_dst; + cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src; + cairo_xcb_surface_t *mask = (cairo_xcb_surface_t *) generic_mask; + cairo_xcb_surface_t *src_clone = NULL; + cairo_xcb_surface_t *mask_clone = NULL; + XCBRenderPICTURE maskpict = { 0 }; + + + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { + src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst, + CAIRO_FORMAT_ARGB32, 32); + if (!src_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + src = src_clone; + } + if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) { + mask_clone = _cairo_xcb_surface_clone_similar (generic_mask, dst, + CAIRO_FORMAT_A8, 8); + if (!mask_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + mask = mask_clone; + } + + if(mask) + maskpict = mask->picture; + + XCBRenderComposite (dst->dpy, + _render_operator (operator), + src->picture, + maskpict, + dst->picture, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + + /* XXX: This is messed up. If I can xcb_surface_create, then I + should be able to xcb_surface_destroy. */ + if (src_clone) + cairo_surface_destroy (&src_clone->base); + if (mask_clone) + cairo_surface_destroy (&mask_clone->base); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_xcb_surface_fill_rectangles (void *abstract_surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + cairo_xcb_surface_t *surface = abstract_surface; + XCBRenderCOLOR render_color; + + if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + render_color.red = color->red_short; + render_color.green = color->green_short; + render_color.blue = color->blue_short; + render_color.alpha = color->alpha_short; + + /* XXX: This XCBRECTANGLE cast is evil... it needs to go away somehow. */ + XCBRenderFillRectangles (surface->dpy, + _render_operator (operator), + surface->picture, + render_color, num_rects, (XCBRECTANGLE *) rects); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, + cairo_surface_t *generic_src, + void *abstract_dst, + int xSrc, + int ySrc, + cairo_trapezoid_t *traps, + int num_traps) +{ + cairo_xcb_surface_t *dst = abstract_dst; + cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src; + cairo_xcb_surface_t *src_clone = NULL; + + if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { + src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst, + CAIRO_FORMAT_ARGB32, 32); + if (!src_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + src = src_clone; + } + + /* XXX: The XCBRenderTRAP cast is evil and needs to go away somehow. */ + /* XXX: format_from_cairo is slow. should cache something. */ + XCBRenderTrapezoids (dst->dpy, + _render_operator (operator), + src->picture, dst->picture, + format_from_cairo (dst->dpy, CAIRO_FORMAT_A8), + xSrc, ySrc, num_traps, (XCBRenderTRAP *) traps); + + /* XXX: This is messed up. If I can xcb_surface_create, then I + should be able to xcb_surface_destroy. */ + if (src_clone) + cairo_surface_destroy (&src_clone->base); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_xcb_surface_copy_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_xcb_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_xcb_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + /* FIXME */ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_xcb_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static const struct cairo_surface_backend cairo_xcb_surface_backend = { + _cairo_xcb_surface_create_similar, + _cairo_xcb_surface_destroy, + _cairo_xcb_surface_pixels_per_inch, + _cairo_xcb_surface_get_image, + _cairo_xcb_surface_set_image, + _cairo_xcb_surface_set_matrix, + _cairo_xcb_surface_set_filter, + _cairo_xcb_surface_set_repeat, + _cairo_xcb_surface_composite, + _cairo_xcb_surface_fill_rectangles, + _cairo_xcb_surface_composite_trapezoids, + _cairo_xcb_surface_copy_page, + _cairo_xcb_surface_show_page, + _cairo_xcb_surface_set_clip_region, + _cairo_xcb_surface_create_pattern +}; + +static void +query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface) +{ + XCBRenderQueryVersionRep *r; + + surface->render_major = -1; + surface->render_minor = -1; + + if (!XCBRenderInit(c)) + return; + + r = XCBRenderQueryVersionReply(c, XCBRenderQueryVersion(c, 0, 6), 0); + if (!r) + return; + + surface->render_major = r->major_version; + surface->render_minor = r->minor_version; + free(r); +} + +cairo_surface_t * +cairo_xcb_surface_create (XCBConnection *dpy, + XCBDRAWABLE drawable, + XCBVISUALTYPE *visual, + cairo_format_t format) +{ + cairo_xcb_surface_t *surface; + + surface = malloc (sizeof (cairo_xcb_surface_t)); + if (surface == NULL) + return NULL; + + _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend); + + surface->dpy = dpy; + surface->gc.xid = 0; + surface->drawable = drawable; + surface->owns_pixmap = 0; + surface->visual = visual; + surface->format = format; + + query_render_version(dpy, surface); + + if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) + { + XCBRenderPICTFORMAT fmt; + if(visual) + fmt = format_from_visual (dpy, visual->visual_id); + else + fmt = format_from_cairo (dpy, format); + surface->picture = XCBRenderPICTURENew(dpy); + XCBRenderCreatePicture (dpy, surface->picture, drawable, + fmt, 0, NULL); + } + else + surface->picture.xid = 0; + + return (cairo_surface_t *) surface; +} diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 49abdb56e..19dfde503 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -90,6 +90,7 @@ typedef struct cairo_xlib_surface { #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) +#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) static int _CAIRO_FORMAT_DEPTH (cairo_format_t format) @@ -257,7 +258,7 @@ _cairo_xlib_surface_set_image (void *abstract_surface, ximage = XCreateImage (surface->dpy, DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)), - image->depth == 32 ? 24 : image->depth, + image->depth, ZPixmap, 0, image->data, @@ -320,26 +321,29 @@ _cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter) cairo_xlib_surface_t *surface = abstract_surface; char *render_filter; - if (!surface->picture) + if (!(surface->picture + && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface))) return CAIRO_STATUS_SUCCESS; - - /* XXX: The Render specification has capitalized versions of these - strings. However, the current implementation is - case-sensitive and expects lowercase versions. - */ + switch (filter) { case CAIRO_FILTER_FAST: - render_filter = "fast"; + render_filter = FilterFast; + break; case CAIRO_FILTER_GOOD: - render_filter = "good"; + render_filter = FilterGood; + break; case CAIRO_FILTER_BEST: - render_filter = "best"; + render_filter = FilterBest; + break; case CAIRO_FILTER_NEAREST: - render_filter = "nearest"; + render_filter = FilterNearest; + break; case CAIRO_FILTER_BILINEAR: - render_filter = "bilinear"; + render_filter = FilterBilinear; + break; default: - render_filter = "best"; + render_filter = FilterBest; + break; } XRenderSetPictureFilter (surface->dpy, surface->picture, @@ -384,6 +388,8 @@ _cairo_xlib_surface_clone_similar (cairo_surface_t *src, if (clone == NULL) return NULL; + _cairo_xlib_surface_set_filter (clone, cairo_surface_get_filter(src)); + _cairo_xlib_surface_set_image (clone, src_image); _cairo_xlib_surface_set_matrix (clone, &(src_image->base.matrix)); @@ -567,6 +573,60 @@ _cairo_xlib_surface_show_page (void *abstract_surface) return CAIRO_INT_STATUS_UNSUPPORTED; } +static cairo_int_status_t +_cairo_xlib_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + Region xregion; + XRectangle xr; + pixman_box16_t *box; + cairo_xlib_surface_t *surf; + int n, m; + + surf = (cairo_xlib_surface_t *) abstract_surface; + + if (region == NULL) { + /* NULL region == reset the clip */ + xregion = XCreateRegion(); + xr.x = 0; + xr.y = 0; + xr.width = surf->width; + xr.height = surf->height; + XUnionRectWithRegion (&xr, xregion, xregion); + } else { + n = pixman_region_num_rects (region); + /* XXX: Are we sure these are the semantics we want for an + * empty, (not null) region? */ + if (n == 0) + return CAIRO_STATUS_SUCCESS; + + box = pixman_region_rects (region); + xregion = XCreateRegion(); + + m = n; + for (; n > 0; --n, ++box) { + xr.x = (short) box->x1; + xr.y = (short) box->y1; + xr.width = (unsigned short) (box->x2 - box->x1); + xr.height = (unsigned short) (box->y2 - box->y1); + XUnionRectWithRegion (&xr, xregion, xregion); + } + } + + XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion); + XDestroyRegion(xregion); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_xlib_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, _cairo_xlib_surface_destroy, @@ -580,7 +640,9 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_fill_rectangles, _cairo_xlib_surface_composite_trapezoids, _cairo_xlib_surface_copy_page, - _cairo_xlib_surface_show_page + _cairo_xlib_surface_show_page, + _cairo_xlib_surface_set_clip_region, + _cairo_xlib_surface_create_pattern }; cairo_surface_t * diff --git a/src/cairo.c b/src/cairo.c index 1149337b5..d173ca767 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -29,9 +29,6 @@ #define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */ -static void -_cairo_restrict_value (double *value, double min, double max); - cairo_t * cairo_create (void) { @@ -220,7 +217,7 @@ cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue) } void -cairo_set_pattern (cairo_t *cr, cairo_surface_t *pattern) +cairo_set_pattern (cairo_t *cr, cairo_pattern_t *pattern) { if (cr->status) return; @@ -228,6 +225,12 @@ cairo_set_pattern (cairo_t *cr, cairo_surface_t *pattern) cr->status = _cairo_gstate_set_pattern (cr->gstate, pattern); } +cairo_pattern_t * +cairo_current_pattern (cairo_t *cr) +{ + return _cairo_gstate_current_pattern (cr->gstate); +} + void cairo_set_tolerance (cairo_t *cr, double tolerance) { @@ -636,6 +639,35 @@ cairo_in_fill (cairo_t *cr, double x, double y) } void +cairo_stroke_extents (cairo_t *cr, + double *x1, double *y1, double *x2, double *y2) +{ + if (cr->status) + return; + + cr->status = _cairo_gstate_stroke_extents (cr->gstate, x1, y1, x2, y2); +} + +void +cairo_fill_extents (cairo_t *cr, + double *x1, double *y1, double *x2, double *y2) +{ + if (cr->status) + return; + + cr->status = _cairo_gstate_fill_extents (cr->gstate, x1, y1, x2, y2); +} + +void +cairo_init_clip (cairo_t *cr) +{ + if (cr->status) + return; + + cr->status = _cairo_gstate_init_clip (cr->gstate); +} + +void cairo_clip (cairo_t *cr) { if (cr->status) @@ -646,7 +678,7 @@ cairo_clip (cairo_t *cr) void cairo_select_font (cairo_t *cr, - char *family, + const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { @@ -706,8 +738,6 @@ cairo_transform_font (cairo_t *cr, cairo_matrix_t *matrix) cr->status = _cairo_gstate_transform_font (cr->gstate, matrix); } - -/* XXX: NYI void cairo_text_extents (cairo_t *cr, const unsigned char *utf8, @@ -731,7 +761,6 @@ cairo_glyph_extents (cairo_t *cr, cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, extents); } -*/ void cairo_show_text (cairo_t *cr, const unsigned char *utf8) @@ -751,7 +780,6 @@ cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs) cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs); } -/* XXX: NYI void cairo_text_path (cairo_t *cr, const unsigned char *utf8) { @@ -769,7 +797,6 @@ cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs) cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs); } -*/ void cairo_show_surface (cairo_t *cr, @@ -868,6 +895,43 @@ cairo_current_target_surface (cairo_t *cr) } DEPRECATE (cairo_get_target_surface, cairo_current_target_surface); +void +cairo_current_path (cairo_t *cr, + cairo_move_to_func_t *move_to, + cairo_line_to_func_t *line_to, + cairo_curve_to_func_t *curve_to, + cairo_close_path_func_t *close_path, + void *closure) +{ + if (cr->status) + return; + + cr->status = _cairo_gstate_interpret_path (cr->gstate, + move_to, + line_to, + curve_to, + close_path, + closure); +} + +void +cairo_current_path_flat (cairo_t *cr, + cairo_move_to_func_t *move_to, + cairo_line_to_func_t *line_to, + cairo_close_path_func_t *close_path, + void *closure) +{ + if (cr->status) + return; + + cr->status = _cairo_gstate_interpret_path (cr->gstate, + move_to, + line_to, + NULL, + close_path, + closure); +} + cairo_status_t cairo_status (cairo_t *cr) { @@ -901,7 +965,7 @@ cairo_status_string (cairo_t *cr) } DEPRECATE (cairo_get_status_string, cairo_status_string); -static void +void _cairo_restrict_value (double *value, double min, double max) { if (*value < min) diff --git a/src/cairo.h b/src/cairo.h index 6df5f8cf4..ab3c80e82 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -30,52 +30,48 @@ #include <cairo-features.h> -#include <ic.h> +#include <pixman.h> #include <stdio.h> -#ifdef _CAIROINT_H_ -#include <slim_export.h> -#else -#include <slim_import.h> -#endif - typedef struct cairo cairo_t; typedef struct cairo_surface cairo_surface_t; typedef struct cairo_matrix cairo_matrix_t; +typedef struct cairo_pattern cairo_pattern_t; #ifdef __cplusplus extern "C" { #endif /* Functions for manipulating state objects */ -extern cairo_t * __external_linkage +cairo_t * cairo_create (void); -extern void __external_linkage +void cairo_reference (cairo_t *cr); -extern void __external_linkage +void cairo_destroy (cairo_t *cr); -extern void __external_linkage +void cairo_save (cairo_t *cr); -extern void __external_linkage +void cairo_restore (cairo_t *cr); -extern void __external_linkage +/* XXX: Replace with cairo_current_gstate/cairo_set_gstate */ +void cairo_copy (cairo_t *dest, cairo_t *src); /* XXX: I want to rethink this API -extern void __external_linkage +void cairo_push_group (cairo_t *cr); -extern void __external_linkage +void cairo_pop_group (cairo_t *cr); */ /* Modify state */ -extern void __external_linkage +void cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface); typedef enum cairo_format { @@ -85,7 +81,7 @@ typedef enum cairo_format { CAIRO_FORMAT_A1 } cairo_format_t; -extern void __external_linkage +void cairo_set_target_image (cairo_t *cr, char *data, cairo_format_t format, @@ -93,7 +89,11 @@ cairo_set_target_image (cairo_t *cr, int height, int stride); -extern void __external_linkage +#ifdef CAIRO_HAS_PS_SURFACE + +#include <stdio.h> + +void cairo_set_target_ps (cairo_t *cr, FILE *file, double width_inches, @@ -101,18 +101,46 @@ cairo_set_target_ps (cairo_t *cr, double x_pixels_per_inch, double y_pixels_per_inch); +#endif /* CAIRO_HAS_PS_SURFACE */ + +#ifdef CAIRO_HAS_PNG_SURFACE + +#include <stdio.h> + +void +cairo_set_target_png (cairo_t *cr, + FILE *file, + cairo_format_t format, + int width, + int height); + +#endif /* CAIRO_HAS_PNG_SURFACE */ + #ifdef CAIRO_HAS_XLIB_SURFACE #include <X11/extensions/Xrender.h> /* XXX: This shold be renamed to cairo_set_target_xlib to match the * other backends */ -extern void __external_linkage +void cairo_set_target_drawable (cairo_t *cr, Display *dpy, Drawable drawable); #endif /* CAIRO_HAS_XLIB_SURFACE */ +#ifdef CAIRO_HAS_XCB_SURFACE + +#include <X11/XCB/xcb.h> +#include <X11/XCB/render.h> + +void +cairo_set_target_xcb (cairo_t *cr, + XCBConnection *dpy, + XCBDRAWABLE drawable, + XCBVISUALTYPE *visual, + cairo_format_t format); +#endif /* CAIRO_HAS_XCB_SURFACE */ + typedef enum cairo_operator { CAIRO_OPERATOR_CLEAR, CAIRO_OPERATOR_SRC, @@ -127,10 +155,10 @@ typedef enum cairo_operator { CAIRO_OPERATOR_ATOP_REVERSE, CAIRO_OPERATOR_XOR, CAIRO_OPERATOR_ADD, - CAIRO_OPERATOR_SATURATE, + CAIRO_OPERATOR_SATURATE } cairo_operator_t; -extern void __external_linkage +void cairo_set_operator (cairo_t *cr, cairo_operator_t op); /* XXX: Probably want to bite the bullet and expose a cairo_color_t object */ @@ -150,16 +178,20 @@ cairo_set_operator (cairo_t *cr, cairo_operator_t op); the behavior of cairo_show_surface. */ -extern void __external_linkage +void cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue); -extern void __external_linkage -cairo_set_alpha (cairo_t *cr, double alpha); +void +cairo_set_pattern (cairo_t *cr, cairo_pattern_t *pattern); -extern void __external_linkage -cairo_set_pattern (cairo_t *cr, cairo_surface_t *pattern); +void +cairo_set_alpha (cairo_t *cr, double alpha); -extern void __external_linkage +/* XXX: Currently, the tolerance value is specified by the user in + terms of device-space units. If I'm not mistaken, this is the only + value in this API that is not expressed in user-space units. I + should think whether this value should be user-space instead. */ +void cairo_set_tolerance (cairo_t *cr, double tolerance); typedef enum cairo_fill_rule { @@ -167,10 +199,10 @@ typedef enum cairo_fill_rule { CAIRO_FILL_RULE_EVEN_ODD } cairo_fill_rule_t; -extern void __external_linkage +void cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule); -extern void __external_linkage +void cairo_set_line_width (cairo_t *cr, double width); typedef enum cairo_line_cap { @@ -179,7 +211,7 @@ typedef enum cairo_line_cap { CAIRO_LINE_CAP_SQUARE } cairo_line_cap_t; -extern void __external_linkage +void cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap); typedef enum cairo_line_join { @@ -188,101 +220,101 @@ typedef enum cairo_line_join { CAIRO_LINE_JOIN_BEVEL } cairo_line_join_t; -extern void __external_linkage +void cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join); -extern void __external_linkage +void cairo_set_dash (cairo_t *cr, double *dashes, int ndash, double offset); -extern void __external_linkage +void cairo_set_miter_limit (cairo_t *cr, double limit); -extern void __external_linkage +void cairo_translate (cairo_t *cr, double tx, double ty); -extern void __external_linkage +void cairo_scale (cairo_t *cr, double sx, double sy); -extern void __external_linkage +void cairo_rotate (cairo_t *cr, double angle); -extern void __external_linkage +void cairo_concat_matrix (cairo_t *cr, - cairo_matrix_t *matrix); + cairo_matrix_t *matrix); -extern void __external_linkage +void cairo_set_matrix (cairo_t *cr, - cairo_matrix_t *matrix); + cairo_matrix_t *matrix); -extern void __external_linkage +void cairo_default_matrix (cairo_t *cr); /* XXX: There's been a proposal to add cairo_default_matrix_exact */ -extern void __external_linkage +void cairo_identity_matrix (cairo_t *cr); -extern void __external_linkage +void cairo_transform_point (cairo_t *cr, double *x, double *y); -extern void __external_linkage +void cairo_transform_distance (cairo_t *cr, double *dx, double *dy); -extern void __external_linkage +void cairo_inverse_transform_point (cairo_t *cr, double *x, double *y); -extern void __external_linkage +void cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy); /* Path creation functions */ -extern void __external_linkage +void cairo_new_path (cairo_t *cr); -extern void __external_linkage +void cairo_move_to (cairo_t *cr, double x, double y); -extern void __external_linkage +void cairo_line_to (cairo_t *cr, double x, double y); -extern void __external_linkage +void cairo_curve_to (cairo_t *cr, - double x1, double y1, - double x2, double y2, - double x3, double y3); + double x1, double y1, + double x2, double y2, + double x3, double y3); -extern void __external_linkage +void cairo_arc (cairo_t *cr, double xc, double yc, double radius, double angle1, double angle2); -extern void __external_linkage +void cairo_arc_negative (cairo_t *cr, double xc, double yc, double radius, double angle1, double angle2); /* XXX: NYI -extern void __external_linkage +void cairo_arc_to (cairo_t *cr, double x1, double y1, double x2, double y2, double radius); */ -extern void __external_linkage +void cairo_rel_move_to (cairo_t *cr, double dx, double dy); -extern void __external_linkage +void cairo_rel_line_to (cairo_t *cr, double dx, double dy); -extern void __external_linkage +void cairo_rel_curve_to (cairo_t *cr, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3); -extern void __external_linkage +void cairo_rectangle (cairo_t *cr, double x, double y, double width, double height); @@ -295,35 +327,49 @@ cairo_rectangle (cairo_t *cr, Maybe we could use something like "cairo_outline_path (cairo_t *)"? */ /* XXX: NYI -extern void __external_linkage +void cairo_stroke_path (cairo_t *cr); */ -extern void __external_linkage +void cairo_close_path (cairo_t *cr); /* Painting functions */ -extern void __external_linkage +void cairo_stroke (cairo_t *cr); -extern void __external_linkage +void cairo_fill (cairo_t *cr); -extern void __external_linkage +void cairo_copy_page (cairo_t *cr); -extern void __external_linkage +void cairo_show_page (cairo_t *cr); /* Insideness testing */ -extern int __external_linkage +int cairo_in_stroke (cairo_t *cr, double x, double y); -extern int __external_linkage +int cairo_in_fill (cairo_t *cr, double x, double y); +/* Rectangular extents */ +void +cairo_stroke_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2); + +void +cairo_fill_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2); + /* Clipping */ -extern void __external_linkage +void +cairo_init_clip (cairo_t *cr); + +void cairo_clip (cairo_t *cr); /* Font/Text functions */ @@ -337,10 +383,10 @@ typedef struct { } cairo_glyph_t; typedef struct { - double left_side_bearing; - double right_side_bearing; - double ascent; - double descent; + double x_bearing; + double y_bearing; + double width; + double height; double x_advance; double y_advance; } cairo_text_extents_t; @@ -353,115 +399,106 @@ typedef struct { double max_y_advance; } cairo_font_extents_t; -typedef enum cairo_font_weight { - CAIRO_FONT_WEIGHT_NORMAL, - CAIRO_FONT_WEIGHT_BOLD -} cairo_font_weight_t; - typedef enum cairo_font_slant { CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_SLANT_ITALIC, CAIRO_FONT_SLANT_OBLIQUE } cairo_font_slant_t; - +typedef enum cairo_font_weight { + CAIRO_FONT_WEIGHT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD +} cairo_font_weight_t; + /* This interface is for dealing with text as text, not caring about the font object inside the the cairo_t. */ -extern void __external_linkage +void cairo_select_font (cairo_t *ct, - char *family, + const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight); -extern void __external_linkage +void cairo_scale_font (cairo_t *cr, double scale); -extern void __external_linkage +void cairo_transform_font (cairo_t *cr, cairo_matrix_t *matrix); -extern void __external_linkage +void cairo_show_text (cairo_t *ct, const unsigned char *utf8); -extern void __external_linkage +void cairo_show_glyphs (cairo_t *ct, cairo_glyph_t *glyphs, int num_glyphs); -extern cairo_font_t * __external_linkage +cairo_font_t * cairo_current_font (cairo_t *ct); -extern void __external_linkage +void cairo_current_font_extents (cairo_t *ct, cairo_font_extents_t *extents); -extern void __external_linkage +void cairo_set_font (cairo_t *ct, cairo_font_t *font); - -/* XXX: NYI - -extern void __external_linkage +void cairo_text_extents (cairo_t *ct, const unsigned char *utf8, cairo_text_extents_t *extents); -extern void __external_linkage +void cairo_glyph_extents (cairo_t *ct, cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents); -extern void __external_linkage +void cairo_text_path (cairo_t *ct, const unsigned char *utf8); -extern void __external_linkage +void cairo_glyph_path (cairo_t *ct, cairo_glyph_t *glyphs, int num_glyphs); -*/ - - /* Portable interface to general font features. */ -extern void __external_linkage +void cairo_font_reference (cairo_font_t *font); -extern void __external_linkage +void cairo_font_destroy (cairo_font_t *font); -extern void __external_linkage +void cairo_font_set_transform (cairo_font_t *font, cairo_matrix_t *matrix); -extern void __external_linkage +void cairo_font_current_transform (cairo_font_t *font, cairo_matrix_t *matrix); - /* Fontconfig/Freetype platform-specific font interface */ #include <fontconfig/fontconfig.h> #include <ft2build.h> #include FT_FREETYPE_H -extern cairo_font_t * __external_linkage +cairo_font_t * cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern); -extern cairo_font_t * __external_linkage +cairo_font_t * cairo_ft_font_create_for_ft_face (FT_Face face); -extern void __external_linkage +void cairo_ft_font_destroy (cairo_font_t *ft_font); -extern FT_Face __external_linkage +FT_Face cairo_ft_font_face (cairo_font_t *ft_font); -extern FcPattern * __external_linkage +FcPattern * cairo_ft_font_pattern (cairo_font_t *ft_font); - - /* Image functions */ -extern void __external_linkage +/* XXX: Eliminate width/height here */ +void cairo_show_surface (cairo_t *cr, cairo_surface_t *surface, int width, @@ -475,48 +512,78 @@ cairo_show_surface (cairo_t *cr, into one file and be done with it. For now, I've got a little more typing than that. */ -extern cairo_operator_t __external_linkage +cairo_operator_t cairo_current_operator (cairo_t *cr); -extern void __external_linkage +void cairo_current_rgb_color (cairo_t *cr, double *red, double *green, double *blue); +cairo_pattern_t * +cairo_current_pattern (cairo_t *cr); -extern double __external_linkage +double cairo_current_alpha (cairo_t *cr); /* XXX: Do we want cairo_current_pattern as well? */ -extern double __external_linkage +double cairo_current_tolerance (cairo_t *cr); -extern void __external_linkage +void cairo_current_point (cairo_t *cr, double *x, double *y); -extern cairo_fill_rule_t __external_linkage +cairo_fill_rule_t cairo_current_fill_rule (cairo_t *cr); -extern double __external_linkage +double cairo_current_line_width (cairo_t *cr); -extern cairo_line_cap_t __external_linkage +cairo_line_cap_t cairo_current_line_cap (cairo_t *cr); -extern cairo_line_join_t __external_linkage +cairo_line_join_t cairo_current_line_join (cairo_t *cr); -extern double __external_linkage +double cairo_current_miter_limit (cairo_t *cr); /* XXX: How to do cairo_current_dash??? Do we want to switch to a cairo_dash object? */ -extern void __external_linkage +void cairo_current_matrix (cairo_t *cr, cairo_matrix_t *matrix); /* XXX: Need to decide the memory mangement semantics of this function. Should it reference the surface again? */ -extern cairo_surface_t * __external_linkage +cairo_surface_t * cairo_current_target_surface (cairo_t *cr); +typedef void (cairo_move_to_func_t) (void *closure, + double x, double y); + +typedef void (cairo_line_to_func_t) (void *closure, + double x, double y); + +typedef void (cairo_curve_to_func_t) (void *closure, + double x1, double y1, + double x2, double y2, + double x3, double y3); + +typedef void (cairo_close_path_func_t) (void *closure); + +extern void +cairo_current_path (cairo_t *cr, + cairo_move_to_func_t *move_to, + cairo_line_to_func_t *line_to, + cairo_curve_to_func_t *curve_to, + cairo_close_path_func_t *close_path, + void *closure); + +extern void +cairo_current_path_flat (cairo_t *cr, + cairo_move_to_func_t *move_to, + cairo_line_to_func_t *line_to, + cairo_close_path_func_t *close_path, + void *closure); + /* Error status queries */ typedef enum cairo_status { @@ -530,16 +597,16 @@ typedef enum cairo_status { CAIRO_STATUS_NULL_POINTER } cairo_status_t; -extern cairo_status_t __external_linkage +cairo_status_t cairo_status (cairo_t *cr); -extern const char * __external_linkage +const char * cairo_status_string (cairo_t *cr); /* Surface manipulation */ /* XXX: We may want to rename this function in light of the new virtualized surface backends... */ -extern cairo_surface_t * __external_linkage +cairo_surface_t * cairo_surface_create_for_image (char *data, cairo_format_t format, int width, @@ -548,26 +615,26 @@ cairo_surface_create_for_image (char *data, /* XXX: I want to remove this function, (replace with cairo_set_target_scratch or similar). */ -extern cairo_surface_t * __external_linkage +cairo_surface_t * cairo_surface_create_similar (cairo_surface_t *other, cairo_format_t format, int width, int height); -extern void __external_linkage +void cairo_surface_reference (cairo_surface_t *surface); -extern void __external_linkage +void cairo_surface_destroy (cairo_surface_t *surface); /* XXX: NYI -extern cairo_status_t __external_linkage +cairo_status_t cairo_surface_clip_restore (cairo_surface_t *surface); -extern cairo_status_t __external_linkage +cairo_status_t cairo_surface_clip_begin (cairo_surface_t *surface); -extern cairo_status_t __external_linkage +cairo_status_t cairo_surface_clip_rectangle (cairo_surface_t *surface, int x, int y, int width, int height); @@ -576,52 +643,120 @@ cairo_surface_clip_rectangle (cairo_surface_t *surface, /* XXX: Note: The current Render/Ic implementations don't do the right thing with repeat when the surface has a non-identity matrix. */ /* XXX: Rework this as a cairo function with an enum: cairo_set_pattern_extend */ -extern cairo_status_t __external_linkage +cairo_status_t cairo_surface_set_repeat (cairo_surface_t *surface, int repeat); /* XXX: Rework this as a cairo function: cairo_set_pattern_transform */ -extern cairo_status_t __external_linkage +cairo_status_t cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix); /* XXX: Rework this as a cairo function: cairo_current_pattern_transform */ -extern cairo_status_t __external_linkage +cairo_status_t cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix); -typedef enum cairo_filter { +typedef enum { CAIRO_FILTER_FAST, CAIRO_FILTER_GOOD, CAIRO_FILTER_BEST, CAIRO_FILTER_NEAREST, CAIRO_FILTER_BILINEAR, + CAIRO_FILTER_GAUSSIAN } cairo_filter_t; - + /* XXX: Rework this as a cairo function: cairo_set_pattern_filter */ -extern cairo_status_t __external_linkage +cairo_status_t cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter); +cairo_filter_t +cairo_surface_get_filter (cairo_surface_t *surface); + /* Image-surface functions */ -extern cairo_surface_t * __external_linkage +cairo_surface_t * cairo_image_surface_create (cairo_format_t format, int width, int height); -extern cairo_surface_t * __external_linkage +cairo_surface_t * cairo_image_surface_create_for_data (char *data, cairo_format_t format, int width, int height, int stride); +/* Pattern creation functions */ +cairo_pattern_t * +cairo_pattern_create_for_surface (cairo_surface_t *surface); + +cairo_pattern_t * +cairo_pattern_create_linear (double x0, double y0, + double x1, double y1); + +cairo_pattern_t * +cairo_pattern_create_radial (double cx0, double cy0, double radius0, + double cx1, double cy1, double radius1); + +void +cairo_pattern_reference (cairo_pattern_t *pattern); + +void +cairo_pattern_destroy (cairo_pattern_t *pattern); + +cairo_status_t +cairo_pattern_add_color_stop (cairo_pattern_t *pattern, + double offset, + double red, double green, double blue, + double alpha); + +cairo_status_t +cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix); + +cairo_status_t +cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix); + +typedef enum { + CAIRO_EXTEND_NONE, + CAIRO_EXTEND_REPEAT, + CAIRO_EXTEND_REFLECT +} cairo_extend_t; + +cairo_status_t +cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend); + +cairo_extend_t +cairo_pattern_get_extend (cairo_pattern_t *pattern); + +cairo_status_t +cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter); + +cairo_filter_t +cairo_pattern_get_filter (cairo_pattern_t *pattern); + +#ifdef CAIRO_HAS_PS_SURFACE + /* PS-surface functions */ -extern cairo_surface_t * __external_linkage +cairo_surface_t * cairo_ps_surface_create (FILE *file, double width_inches, double height_inches, double x_pixels_per_inch, double y_pixels_per_inch); +#endif /* CAIRO_HAS_PS_SURFACE */ + +#ifdef CAIRO_HAS_PNG_SURFACE + +/* PNG-surface functions */ + +cairo_surface_t * +cairo_png_surface_create (FILE *file, + cairo_format_t format, + int width, + int height); + +#endif /* CAIRO_HAS_PNG_SURFACE */ + #ifdef CAIRO_HAS_XLIB_SURFACE /* XXX: This is a mess from the user's POV. Should the Visual or the @@ -629,12 +764,17 @@ cairo_ps_surface_create (FILE *file, cairo_surface_create_for_window with a visual, and cairo_surface_create_for_pixmap with a cairo_format_t. Would that work? */ -extern cairo_surface_t * __external_linkage +cairo_surface_t * cairo_xlib_surface_create (Display *dpy, Drawable drawable, Visual *visual, cairo_format_t format, Colormap colormap); + +/* XXX: This has been proposed +cairo_status_t +cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height); +*/ #endif /* CAIRO_HAS_XLIB_SURFACE */ @@ -642,49 +782,49 @@ cairo_xlib_surface_create (Display *dpy, /* XXX: Rename all of these to cairo_transform_t */ -extern cairo_matrix_t * __external_linkage +cairo_matrix_t * cairo_matrix_create (void); -extern void __external_linkage +void cairo_matrix_destroy (cairo_matrix_t *matrix); -extern cairo_status_t __external_linkage +cairo_status_t cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other); -extern cairo_status_t __external_linkage +cairo_status_t cairo_matrix_set_identity (cairo_matrix_t *matrix); -extern cairo_status_t __external_linkage +cairo_status_t cairo_matrix_set_affine (cairo_matrix_t *cr, double a, double b, double c, double d, double tx, double ty); -extern cairo_status_t __external_linkage +cairo_status_t cairo_matrix_get_affine (cairo_matrix_t *matrix, double *a, double *b, double *c, double *d, double *tx, double *ty); -extern cairo_status_t __external_linkage +cairo_status_t cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty); -extern cairo_status_t __external_linkage +cairo_status_t cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy); -extern cairo_status_t __external_linkage +cairo_status_t cairo_matrix_rotate (cairo_matrix_t *matrix, double radians); -extern cairo_status_t __external_linkage +cairo_status_t cairo_matrix_invert (cairo_matrix_t *matrix); -extern cairo_status_t __external_linkage +cairo_status_t cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b); -extern cairo_status_t __external_linkage +cairo_status_t cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy); -extern cairo_status_t __external_linkage +cairo_status_t cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y); /* Deprecated functions. We've made some effort to allow the @@ -712,6 +852,4 @@ cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y); } #endif -#undef __external_linkage - #endif diff --git a/src/cairo_fixed.c b/src/cairo_fixed.c index 330885467..9a7e7bc47 100644 --- a/src/cairo_fixed.c +++ b/src/cairo_fixed.c @@ -39,8 +39,15 @@ _cairo_fixed_from_double (double d) return (cairo_fixed_t) (d * 65536); } +cairo_fixed_t +_cairo_fixed_from_26_6 (uint32_t i) +{ + return i << 10; +} + double _cairo_fixed_to_double (cairo_fixed_t f) { return ((double) f) / 65536.0; } + diff --git a/src/cairo_font.c b/src/cairo_font.c index f6bf390a9..157ebedbe 100644 --- a/src/cairo_font.c +++ b/src/cairo_font.c @@ -28,12 +28,18 @@ #include "cairoint.h" cairo_font_t * -_cairo_font_create (char *family, +_cairo_font_create (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT; + /* XXX: The current freetype backend may return NULL, (for example + * if no fonts are installed), but I would like to guarantee that + * the toy API always returns at least *some* font, so I would + * like to build in some sort fo font here, (even a really lame, + * ugly one if necessary). */ + return backend->create (family, slant, weight); } @@ -118,31 +124,30 @@ _cairo_font_show_glyphs (cairo_font_t *font, cairo_operator_t operator, cairo_surface_t *source, cairo_surface_t *surface, - double x, - double y, cairo_glyph_t *glyphs, int num_glyphs) { return font->backend->show_glyphs(font, operator, source, - surface, x, y, glyphs, num_glyphs); + surface, glyphs, num_glyphs); } cairo_status_t _cairo_font_text_path (cairo_font_t *font, - cairo_path_t *path, - const unsigned char *utf8) + double x, + double y, + const unsigned char *utf8, + cairo_path_t *path) { - return font->backend->text_path(font, path, utf8); + return font->backend->text_path(font, x, y, utf8, path); } cairo_status_t _cairo_font_glyph_path (cairo_font_t *font, - cairo_path_t *path, cairo_glyph_t *glyphs, - int num_glyphs) + int num_glyphs, + cairo_path_t *path) { - return font->backend->glyph_path(font, path, - glyphs, num_glyphs); + return font->backend->glyph_path(font, glyphs, num_glyphs, path); } cairo_status_t diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c index c3e4306d7..77cf59b0d 100644 --- a/src/cairo_ft_font.c +++ b/src/cairo_ft_font.c @@ -25,7 +25,10 @@ #include "cairoint.h" #include <fontconfig/fontconfig.h> #include <fontconfig/fcfreetype.h> -#include <freetype/freetype.h> + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_OUTLINE_H typedef struct { cairo_font_t base; @@ -39,13 +42,10 @@ typedef struct { FcPattern *pattern; } cairo_ft_font_t; - -#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 63.0)) -#define DOUBLE_FROM_26_6(t) (((double)((t) >> 6)) \ - + ((double)((t) & 0x3F) / 63.0)) -#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65535.0)) -#define DOUBLE_FROM_16_16(t) (((double)((t) >> 16)) \ - + ((double)((t) & 0xFFFF) / 65535.0)) +#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0)) +#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) +#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) +#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) /* implement the platform-specific interface */ @@ -101,29 +101,31 @@ cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern) } FT_Face -cairo_ft_font_face (cairo_font_t *font) +cairo_ft_font_face (cairo_font_t *abstract_font) { + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + if (font == NULL) return NULL; - return ((cairo_ft_font_t *) font)->face; + return font->face; } FcPattern * -cairo_ft_font_pattern (cairo_font_t *font) +cairo_ft_font_pattern (cairo_font_t *abstract_font) { + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + if (font == NULL) return NULL; - return ((cairo_ft_font_t *) font)->pattern; + return font->pattern; } - - /* implement the backend interface */ static cairo_font_t * -_cairo_ft_font_create (char *family, +_cairo_ft_font_create (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { @@ -175,6 +177,9 @@ _cairo_ft_font_create (char *family, } font = cairo_ft_font_create (ft_library, pat); + if (font == NULL) + return NULL; + ft_font = (cairo_ft_font_t *) font; ft_font->owns_ft_library = 1; @@ -188,45 +193,43 @@ _cairo_ft_font_create (char *family, return font; } - static cairo_font_t * -_cairo_ft_font_copy (cairo_font_t *font) +_cairo_ft_font_copy (void *abstract_font) { - cairo_ft_font_t * ft_font_new = NULL; - cairo_ft_font_t * ft_font = NULL; + cairo_ft_font_t * font_new = NULL; + cairo_ft_font_t * font = abstract_font; - ft_font = (cairo_ft_font_t *)font; + if (font->base.backend != &cairo_ft_font_backend) + return NULL; - ft_font_new = (cairo_ft_font_t *)cairo_ft_font_create_for_ft_face (ft_font->face); - if (ft_font_new == NULL) + font_new = (cairo_ft_font_t *) cairo_ft_font_create_for_ft_face (font->face); + if (font_new == NULL) return NULL; - if (ft_font_new != NULL && ft_font->pattern != NULL) - ft_font_new->pattern = FcPatternDuplicate (ft_font->pattern); + if (font_new != NULL && font->pattern != NULL) + font_new->pattern = FcPatternDuplicate (font->pattern); - return (cairo_font_t *)ft_font_new; + return (cairo_font_t *) font_new; } static void -_cairo_ft_font_destroy (cairo_font_t *font) +_cairo_ft_font_destroy (void *abstract_font) { - cairo_ft_font_t * ft_font = NULL; + cairo_ft_font_t * font = abstract_font; if (font == NULL) return; - ft_font = (cairo_ft_font_t *)font; - - if (ft_font->face != NULL && ft_font->owns_face) - FT_Done_Face (ft_font->face); + if (font->face != NULL && font->owns_face) + FT_Done_Face (font->face); - if (ft_font->pattern != NULL) - FcPatternDestroy (ft_font->pattern); + if (font->pattern != NULL) + FcPatternDestroy (font->pattern); - if (ft_font->ft_library && ft_font->owns_ft_library) - FT_Done_FreeType (ft_font->ft_library); + if (font->ft_library && font->owns_ft_library) + FT_Done_FreeType (font->ft_library); - free (ft_font); + free (font); } static void @@ -260,21 +263,7 @@ _utf8_to_ucs4 (char const *utf8, len -= step; utf8 += step; } - *nchars = alloc; -} - -static void -_get_scale_factors(cairo_matrix_t *matrix, double *sx, double *sy) -{ - double e0, e1; - e1 = 1.; e0 = 0.; - - cairo_matrix_transform_distance (matrix, &e1, &e0); - *sx = sqrt(e1*e1 + e0*e0); - - e1 = 1.; e0 = 0.; - cairo_matrix_transform_distance (matrix, &e0, &e1); - *sy = sqrt(e1*e1 + e0*e0); + *nchars = n; } static void @@ -292,7 +281,7 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face) * transformation. */ - _get_scale_factors(matrix, &scale_x, &scale_y); + _cairo_matrix_compute_scale_factors (matrix, &scale_x, &scale_y); cairo_matrix_copy (&normalized, matrix); @@ -314,23 +303,19 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face) 0, 0); } - static int -_utf8_to_glyphs (cairo_font_t *font, - const unsigned char *utf8, - cairo_glyph_t **glyphs, - size_t *nglyphs) +_utf8_to_glyphs (cairo_ft_font_t *font, + const unsigned char *utf8, + double x0, + double y0, + cairo_glyph_t **glyphs, + size_t *nglyphs) { - cairo_ft_font_t *ft; + FT_Face face = font->face; double x = 0., y = 0.; size_t i; FT_ULong *ucs4 = NULL; - if (font == NULL) - return 0; - - ft = (cairo_ft_font_t *)font; - _utf8_to_ucs4 (utf8, &ucs4, nglyphs); if (ucs4 == NULL) @@ -343,18 +328,18 @@ _utf8_to_glyphs (cairo_font_t *font, return 0; } - _install_font_matrix (&font->matrix, ft->face); + _install_font_matrix (&font->base.matrix, face); for (i = 0; i < *nglyphs; i++) { - (*glyphs)[i].index = FT_Get_Char_Index (ft->face, ucs4[i]); - (*glyphs)[i].x = x; - (*glyphs)[i].y = y; + (*glyphs)[i].index = FT_Get_Char_Index (face, ucs4[i]); + (*glyphs)[i].x = x0 + x; + (*glyphs)[i].y = y0 + y; - FT_Load_Glyph (ft->face, (*glyphs)[i].index, FT_LOAD_DEFAULT); + FT_Load_Glyph (face, (*glyphs)[i].index, FT_LOAD_DEFAULT); - x += DOUBLE_FROM_26_6 (ft->face->glyph->advance.x); - y -= DOUBLE_FROM_26_6 (ft->face->glyph->advance.y); + x += DOUBLE_FROM_26_6 (face->glyph->advance.x); + y -= DOUBLE_FROM_26_6 (face->glyph->advance.y); } free (ucs4); @@ -362,51 +347,114 @@ _utf8_to_glyphs (cairo_font_t *font, } static cairo_status_t -_cairo_ft_font_font_extents (cairo_font_t *font, - cairo_font_extents_t *extents) +_cairo_ft_font_font_extents (void *abstract_font, + cairo_font_extents_t *extents) { + cairo_ft_font_t *font = abstract_font; + FT_Face face = font->face; double scale_x, scale_y; - cairo_ft_font_t *ft = (cairo_ft_font_t *)font; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - _get_scale_factors(&font->matrix, &scale_x, &scale_y); + double upm = face->units_per_EM; -#define FONT_UNIT_TO_DEV(x) ((double)(x) / (double)(ft->face->units_per_EM)) + _cairo_matrix_compute_scale_factors (&font->base.matrix, &scale_x, &scale_y); - extents->ascent = FONT_UNIT_TO_DEV(ft->face->ascender) * scale_y; - extents->descent = FONT_UNIT_TO_DEV(ft->face->descender) * scale_y; - extents->height = FONT_UNIT_TO_DEV(ft->face->height) * scale_y; - extents->max_x_advance = FONT_UNIT_TO_DEV(ft->face->max_advance_width) * scale_x; - extents->max_y_advance = FONT_UNIT_TO_DEV(ft->face->max_advance_height) * scale_y; - return status; + extents->ascent = face->ascender / upm * scale_y; + extents->descent = face->descender / upm * scale_y; + extents->height = face->height / upm * scale_y; + extents->max_x_advance = face->max_advance_width / upm * scale_x; + extents->max_y_advance = face->max_advance_height / upm * scale_y; + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_ft_font_glyph_extents (cairo_font_t *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents) +_cairo_ft_font_glyph_extents (void *abstract_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) { - cairo_ft_font_t *ft; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + int i; + cairo_ft_font_t *font = abstract_font; + cairo_point_double_t origin; + cairo_point_double_t glyph_min, glyph_max; + cairo_point_double_t total_min, total_max; + FT_Error error; + FT_Face face = font->face; + FT_GlyphSlot glyph = face->glyph; + FT_Glyph_Metrics *metrics = &glyph->metrics; - ft = (cairo_ft_font_t *)font; + if (num_glyphs == 0) + { + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + extents->x_advance = 0.0; + extents->y_advance = 0.0; + + return CAIRO_STATUS_SUCCESS; + } - /* FIXME: lift code from xft to do this */ + origin.x = glyphs[0].x; + origin.y = glyphs[0].y; - return status; + _install_font_matrix (&font->base.matrix, face); + + for (i = 0; i < num_glyphs; i++) + { + error = FT_Load_Glyph (face, glyphs[i].index, FT_LOAD_DEFAULT); + /* XXX: What to do in this error case? */ + if (error) + continue; + + /* XXX: Need to add code here to check the font's FcPattern + for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y + instead. This will require that + cairo_ft_font_create_for_ft_face accept an + FcPattern. */ + glyph_min.x = glyphs[i].x + DOUBLE_FROM_26_6 (metrics->horiBearingX); + glyph_min.y = glyphs[i].y - DOUBLE_FROM_26_6 (metrics->horiBearingY); + glyph_max.x = glyph_min.x + DOUBLE_FROM_26_6 (metrics->width); + glyph_max.y = glyph_min.y + DOUBLE_FROM_26_6 (metrics->height); + + if (i==0) { + total_min = glyph_min; + total_max = glyph_max; + } else { + if (glyph_min.x < total_min.x) + total_min.x = glyph_min.x; + if (glyph_min.y < total_min.y) + total_min.y = glyph_min.y; + + if (glyph_max.x > total_max.x) + total_max.x = glyph_max.x; + if (glyph_max.y > total_max.y) + total_max.y = glyph_max.y; + } + } + + extents->x_bearing = total_min.x - origin.x; + extents->y_bearing = total_min.y - origin.y; + extents->width = total_max.x - total_min.x; + extents->height = total_max.y - total_min.y; + extents->x_advance = glyphs[i-1].x + DOUBLE_FROM_26_6 (metrics->horiAdvance) - origin.x; + extents->y_advance = glyphs[i-1].y + 0 - origin.y; + + return CAIRO_STATUS_SUCCESS; } + static cairo_status_t -_cairo_ft_font_text_extents (cairo_font_t *font, - const unsigned char *utf8, - cairo_text_extents_t *extents) +_cairo_ft_font_text_extents (void *abstract_font, + const unsigned char *utf8, + cairo_text_extents_t *extents) { + cairo_ft_font_t *font = abstract_font; cairo_glyph_t *glyphs; size_t nglyphs; cairo_status_t status = CAIRO_STATUS_SUCCESS; - if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs)) + if (_utf8_to_glyphs (font, utf8, 0, 0, &glyphs, &nglyphs)) { status = _cairo_ft_font_glyph_extents (font, glyphs, nglyphs, extents); @@ -414,24 +462,22 @@ _cairo_ft_font_text_extents (cairo_font_t *font, } return status; } - - static cairo_status_t -_cairo_ft_font_show_glyphs (cairo_font_t *font, +_cairo_ft_font_show_glyphs (void *abstract_font, cairo_operator_t operator, cairo_surface_t *source, cairo_surface_t *surface, - double x0, - double y0, const cairo_glyph_t *glyphs, int num_glyphs) { + cairo_ft_font_t *font = abstract_font; cairo_status_t status; int i; cairo_ft_font_t *ft = NULL; FT_GlyphSlot glyphslot; cairo_surface_t *mask = NULL; + cairo_point_double_t origin; double x, y; int width, height, stride; @@ -444,22 +490,27 @@ _cairo_ft_font_show_glyphs (cairo_font_t *font, ft = (cairo_ft_font_t *)font; glyphslot = ft->face->glyph; - _install_font_matrix (&font->matrix, ft->face); + _install_font_matrix (&font->base.matrix, ft->face); for (i = 0; i < num_glyphs; i++) { unsigned char *bitmap; FT_Load_Glyph (ft->face, glyphs[i].index, FT_LOAD_DEFAULT); - FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL); + FT_Render_Glyph (glyphslot, ft_render_mode_normal); width = glyphslot->bitmap.width; height = glyphslot->bitmap.rows; stride = glyphslot->bitmap.pitch; bitmap = glyphslot->bitmap.buffer; - x = x0 + glyphs[i].x; - y = y0 + glyphs[i].y; + x = glyphs[i].x; + y = glyphs[i].y; + + if (i == 0) { + origin.x = x; + origin.y = y; + } /* X gets upset with zero-sized images (such as whitespace) */ if (width * height == 0) @@ -502,11 +553,14 @@ _cairo_ft_font_show_glyphs (cairo_font_t *font, return CAIRO_STATUS_NO_MEMORY; } - status = _cairo_surface_composite (operator, source, mask, surface, - 0, 0, 0, 0, - x + glyphslot->bitmap_left, - y - glyphslot->bitmap_top, - (double)width, (double)height); + status = + _cairo_surface_composite (operator, source, mask, surface, + -origin.x + x + glyphslot->bitmap_left, + -origin.y + y - glyphslot->bitmap_top, + 0, 0, + x + glyphslot->bitmap_left, + y - glyphslot->bitmap_top, + (double) width, (double) height); cairo_surface_destroy (mask); if (bitmap != glyphslot->bitmap.buffer) @@ -519,7 +573,7 @@ _cairo_ft_font_show_glyphs (cairo_font_t *font, } static cairo_status_t -_cairo_ft_font_show_text (cairo_font_t *font, +_cairo_ft_font_show_text (void *abstract_font, cairo_operator_t operator, cairo_surface_t *source, cairo_surface_t *surface, @@ -527,15 +581,16 @@ _cairo_ft_font_show_text (cairo_font_t *font, double y0, const unsigned char *utf8) { + cairo_ft_font_t *font = abstract_font; cairo_glyph_t *glyphs; - size_t nglyphs; + int num_glyphs; - if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs)) + if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs)) { cairo_status_t res; res = _cairo_ft_font_show_glyphs (font, operator, - source, surface, x0, y0, - glyphs, nglyphs); + source, surface, + glyphs, num_glyphs); free (glyphs); return res; } @@ -543,35 +598,147 @@ _cairo_ft_font_show_text (cairo_font_t *font, return CAIRO_STATUS_NO_MEMORY; } +static int +_move_to (FT_Vector *to, void *closure) +{ + cairo_path_t *path = closure; + cairo_point_t point; + + point.x = _cairo_fixed_from_26_6 (to->x); + point.y = _cairo_fixed_from_26_6 (to->y); + + _cairo_path_close_path (path); + _cairo_path_move_to (path, &point); + + return 0; +} + +static int +_line_to (FT_Vector *to, void *closure) +{ + cairo_path_t *path = closure; + cairo_point_t point; + + point.x = _cairo_fixed_from_26_6 (to->x); + point.y = _cairo_fixed_from_26_6 (to->y); + + _cairo_path_line_to (path, &point); + + return 0; +} + +static int +_conic_to (FT_Vector *control, FT_Vector *to, void *closure) +{ + cairo_path_t *path = closure; + + cairo_point_t p0, p1, p2, p3; + cairo_point_t conic; + + _cairo_path_current_point (path, &p0); + + conic.x = _cairo_fixed_from_26_6 (control->x); + conic.y = _cairo_fixed_from_26_6 (control->y); + + p3.x = _cairo_fixed_from_26_6 (to->x); + p3.y = _cairo_fixed_from_26_6 (to->y); + + p1.x = p0.x + 2.0/3.0 * (conic.x - p0.x); + p1.y = p0.y + 2.0/3.0 * (conic.y - p0.y); + + p2.x = p3.x + 2.0/3.0 * (conic.x - p3.x); + p2.y = p3.y + 2.0/3.0 * (conic.y - p3.y); + + _cairo_path_curve_to (path, + &p1, &p2, &p3); + + return 0; +} + +static int +_cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closure) +{ + cairo_path_t *path = closure; + cairo_point_t p0, p1, p2; + + p0.x = _cairo_fixed_from_26_6 (control1->x); + p0.y = _cairo_fixed_from_26_6 (control1->y); + + p1.x = _cairo_fixed_from_26_6 (control2->x); + p1.y = _cairo_fixed_from_26_6 (control2->y); + + p2.x = _cairo_fixed_from_26_6 (to->x); + p2.y = _cairo_fixed_from_26_6 (to->y); + + _cairo_path_curve_to (path, &p0, &p1, &p2); + + return 0; +} static cairo_status_t -_cairo_ft_font_glyph_path (cairo_font_t *font, - cairo_path_t *path, - cairo_glyph_t *glyphs, - int num_glyphs) +_cairo_ft_font_glyph_path (void *abstract_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_ft_font_t *ft; - - ft = (cairo_ft_font_t *)font; - - /* FIXME: lift code from xft to do this */ + int i; + cairo_ft_font_t *font = abstract_font; + FT_GlyphSlot glyph; + FT_Error error; + FT_Outline_Funcs outline_funcs = { + _move_to, + _line_to, + _conic_to, + _cubic_to, + 0, /* shift */ + 0, /* delta */ + }; + + glyph = font->face->glyph; + _install_font_matrix (&font->base.matrix, font->face); + + for (i = 0; i < num_glyphs; i++) + { + FT_Matrix invert_y = { + DOUBLE_TO_16_16 (1.0), 0, + 0, DOUBLE_TO_16_16 (-1.0), + }; + + error = FT_Load_Glyph (font->face, glyphs[i].index, FT_LOAD_DEFAULT); + /* XXX: What to do in this error case? */ + if (error) + continue; + /* XXX: Do we want to support bitmap fonts here? */ + if (glyph->format == ft_glyph_format_bitmap) + continue; + + /* Font glyphs have an inverted Y axis compared to cairo. */ + FT_Outline_Transform (&glyph->outline, &invert_y); + FT_Outline_Translate (&glyph->outline, + DOUBLE_TO_26_6(glyphs[i].x), + DOUBLE_TO_26_6(glyphs[i].y)); + FT_Outline_Decompose (&glyph->outline, &outline_funcs, path); + } + _cairo_path_close_path (path); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_ft_font_text_path (cairo_font_t *font, - cairo_path_t *path, - const unsigned char *utf8) +_cairo_ft_font_text_path (void *abstract_font, + double x, + double y, + const unsigned char *utf8, + cairo_path_t *path) { + cairo_ft_font_t *font = abstract_font; cairo_glyph_t *glyphs; size_t nglyphs; - if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs)) + if (_utf8_to_glyphs (font, utf8, x, y, &glyphs, &nglyphs)) { cairo_status_t res; - res = _cairo_ft_font_glyph_path (font, path, glyphs, nglyphs); + res = _cairo_ft_font_glyph_path (font, glyphs, nglyphs, path); free (glyphs); return res; } @@ -579,7 +746,6 @@ _cairo_ft_font_text_path (cairo_font_t *font, return CAIRO_STATUS_NO_MEMORY; } - cairo_font_t * cairo_ft_font_create_for_ft_face (FT_Face face) { @@ -602,16 +768,15 @@ cairo_ft_font_create_for_ft_face (FT_Face face) return (cairo_font_t *) f; } - const struct cairo_font_backend cairo_ft_font_backend = { - font_extents: (void *) _cairo_ft_font_font_extents, - text_extents: (void *) _cairo_ft_font_text_extents, - glyph_extents: (void *) _cairo_ft_font_glyph_extents, - show_text: (void *) _cairo_ft_font_show_text, - show_glyphs: (void *) _cairo_ft_font_show_glyphs, - text_path: (void *) _cairo_ft_font_text_path, - glyph_path: (void *) _cairo_ft_font_glyph_path, - create: (void *) _cairo_ft_font_create, - copy: (void *) _cairo_ft_font_copy, - destroy: (void *) _cairo_ft_font_destroy + _cairo_ft_font_create, + _cairo_ft_font_copy, + _cairo_ft_font_destroy, + _cairo_ft_font_font_extents, + _cairo_ft_font_text_extents, + _cairo_ft_font_glyph_extents, + _cairo_ft_font_show_text, + _cairo_ft_font_show_glyphs, + _cairo_ft_font_text_path, + _cairo_ft_font_glyph_path, }; diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c index 8bc6e704a..ed8c8a1a8 100644 --- a/src/cairo_gstate.c +++ b/src/cairo_gstate.c @@ -30,15 +30,9 @@ #include "cairoint.h" -static void -_cairo_gstate_set_current_point (cairo_gstate_t *gstate, double x, double y); - -static cairo_status_t -_cairo_gstate_ensure_source (cairo_gstate_t *gstate); - static cairo_status_t _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, - cairo_surface_t *src, + cairo_pattern_t *src, cairo_operator_t operator, cairo_surface_t *dst, cairo_traps_t *traps); @@ -79,25 +73,20 @@ _cairo_gstate_init (cairo_gstate_t *gstate) CAIRO_FONT_WEIGHT_DEFAULT); gstate->surface = NULL; - gstate->source = NULL; - gstate->source_offset.x = 0.0; - gstate->source_offset.y = 0.0; - gstate->source_is_solid = 1; + gstate->clip.region = NULL; gstate->clip.surface = NULL; - + + gstate->pattern = _cairo_pattern_create_solid (1.0, 1.0, 1.0); + gstate->pattern_offset.x = 0.0; + gstate->pattern_offset.y = 0.0; gstate->alpha = 1.0; - _cairo_color_init (&gstate->color); gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT; _cairo_gstate_default_matrix (gstate); _cairo_path_init (&gstate->path); - gstate->current_point.x = 0.0; - gstate->current_point.y = 0.0; - gstate->has_current_point = 0; - _cairo_pen_init_empty (&gstate->pen_regular); gstate->next = NULL; @@ -130,9 +119,16 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) } } + if (other->clip.region) + { + gstate->clip.region = pixman_region_create (); + pixman_region_copy (gstate->clip.region, other->clip.region); + } + cairo_surface_reference (gstate->surface); - cairo_surface_reference (gstate->source); cairo_surface_reference (gstate->clip.surface); + + cairo_pattern_reference (gstate->pattern); status = _cairo_path_init_copy (&gstate->path, &other->path); if (status) @@ -164,16 +160,15 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) cairo_surface_destroy (gstate->surface); gstate->surface = NULL; - if (gstate->source) - cairo_surface_destroy (gstate->source); - gstate->source = NULL; - gstate->source_is_solid = 1; - if (gstate->clip.surface) cairo_surface_destroy (gstate->clip.surface); gstate->clip.surface = NULL; - _cairo_color_fini (&gstate->color); + if (gstate->clip.region) + pixman_region_destroy (gstate->clip.region); + gstate->clip.region = NULL; + + cairo_pattern_destroy (gstate->pattern); _cairo_matrix_fini (&gstate->ctm); _cairo_matrix_fini (&gstate->ctm_inverse); @@ -358,22 +353,37 @@ _cairo_gstate_current_target_surface (cairo_gstate_t *gstate) } cairo_status_t -_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_surface_t *pattern) +_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern) { - cairo_surface_destroy (gstate->source); - - gstate->source = pattern; - gstate->source_is_solid = 0; + if (pattern == NULL) + return CAIRO_STATUS_NULL_POINTER; - cairo_surface_reference (gstate->source); + if (gstate->pattern) + cairo_pattern_destroy (gstate->pattern); + + gstate->pattern = pattern; + cairo_pattern_reference (pattern); _cairo_gstate_current_point (gstate, - &gstate->source_offset.x, - &gstate->source_offset.y); - + &gstate->pattern_offset.x, + &gstate->pattern_offset.y); + return CAIRO_STATUS_SUCCESS; } +cairo_pattern_t * +_cairo_gstate_current_pattern (cairo_gstate_t *gstate) +{ + if (gstate == NULL) + return NULL; + +/* XXX: Do we want this? + cairo_pattern_reference (gstate->pattern); +*/ + + return gstate->pattern; +} + cairo_status_t _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator) { @@ -391,25 +401,19 @@ _cairo_gstate_current_operator (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue) { - _cairo_color_set_rgb (&gstate->color, red, green, blue); - - if (gstate->source) - cairo_surface_destroy (gstate->source); - - gstate->source = NULL; - gstate->source_offset.x = 0; - gstate->source_offset.y = 0; - gstate->source_is_solid = 1; - + cairo_pattern_destroy (gstate->pattern); + + gstate->pattern = _cairo_pattern_create_solid (red, green, blue); + gstate->pattern_offset.x = 0.0; + gstate->pattern_offset.y = 0.0; + return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_gstate_current_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue) { - _cairo_color_get_rgb (&gstate->color, red, green, blue); - - return CAIRO_STATUS_SUCCESS; + return _cairo_pattern_get_rgb (gstate->pattern, red, green, blue); } cairo_status_t @@ -426,20 +430,11 @@ _cairo_gstate_current_tolerance (cairo_gstate_t *gstate) return gstate->tolerance; } -/* XXX: Need to fix this so it does the right thing after set_pattern. */ cairo_status_t _cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha) { gstate->alpha = alpha; - _cairo_color_set_alpha (&gstate->color, alpha); - - cairo_surface_destroy (gstate->source); - - gstate->source = NULL; - gstate->source_offset.x = 0; - gstate->source_offset.y = 0; - return CAIRO_STATUS_SUCCESS; } @@ -680,20 +675,10 @@ _cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, do return CAIRO_STATUS_SUCCESS; } -static void -_cairo_gstate_set_current_point (cairo_gstate_t *gstate, double x, double y) -{ - gstate->current_point.x = x; - gstate->current_point.y = y; - - gstate->has_current_point = 1; -} - cairo_status_t _cairo_gstate_new_path (cairo_gstate_t *gstate) { _cairo_path_fini (&gstate->path); - gstate->has_current_point = 0; return CAIRO_STATUS_SUCCESS; } @@ -701,53 +686,51 @@ _cairo_gstate_new_path (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y) { - cairo_status_t status; + cairo_point_t point; cairo_matrix_transform_point (&gstate->ctm, &x, &y); - status = _cairo_path_move_to (&gstate->path, x, y); - - _cairo_gstate_set_current_point (gstate, x, y); - - gstate->last_move_point = gstate->current_point; + point.x = _cairo_fixed_from_double (x); + point.y = _cairo_fixed_from_double (y); - return status; + return _cairo_path_move_to (&gstate->path, &point); } cairo_status_t _cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y) { - cairo_status_t status; + cairo_point_t point; cairo_matrix_transform_point (&gstate->ctm, &x, &y); - status = _cairo_path_line_to (&gstate->path, x, y); - - _cairo_gstate_set_current_point (gstate, x, y); + point.x = _cairo_fixed_from_double (x); + point.y = _cairo_fixed_from_double (y); - return status; + return _cairo_path_line_to (&gstate->path, &point); } cairo_status_t _cairo_gstate_curve_to (cairo_gstate_t *gstate, + double x0, double y0, double x1, double y1, - double x2, double y2, - double x3, double y3) + double x2, double y2) { - cairo_status_t status; + cairo_point_t p0, p1, p2; + cairo_matrix_transform_point (&gstate->ctm, &x0, &y0); cairo_matrix_transform_point (&gstate->ctm, &x1, &y1); cairo_matrix_transform_point (&gstate->ctm, &x2, &y2); - cairo_matrix_transform_point (&gstate->ctm, &x3, &y3); - status = _cairo_path_curve_to (&gstate->path, - x1, y1, - x2, y2, - x3, y3); + p0.x = _cairo_fixed_from_double (x0); + p0.y = _cairo_fixed_from_double (y0); - _cairo_gstate_set_current_point (gstate, x3, y3); + p1.x = _cairo_fixed_from_double (x1); + p1.y = _cairo_fixed_from_double (y1); - return status; + p2.x = _cairo_fixed_from_double (x2); + p2.y = _cairo_fixed_from_double (y2); + + return _cairo_path_curve_to (&gstate->path, &p0, &p1, &p2); } /* Spline deviation from the circle in radius would be given by: @@ -1025,63 +1008,54 @@ _cairo_gstate_arc_to (cairo_gstate_t *gstate, cairo_status_t _cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy) { - cairo_status_t status; - double x, y; + cairo_distance_t distance; cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy); - x = gstate->current_point.x + dx; - y = gstate->current_point.y + dy; - - status = _cairo_path_move_to (&gstate->path, x, y); - - _cairo_gstate_set_current_point (gstate, x, y); + distance.dx = _cairo_fixed_from_double (dx); + distance.dy = _cairo_fixed_from_double (dy); - gstate->last_move_point = gstate->current_point; - - return status; + return _cairo_path_rel_move_to (&gstate->path, &distance); } cairo_status_t _cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy) { - cairo_status_t status; - double x, y; + cairo_distance_t distance; cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy); - x = gstate->current_point.x + dx; - y = gstate->current_point.y + dy; - - status = _cairo_path_line_to (&gstate->path, x, y); - - _cairo_gstate_set_current_point (gstate, x, y); + distance.dx = _cairo_fixed_from_double (dx); + distance.dy = _cairo_fixed_from_double (dy); - return status; + return _cairo_path_rel_line_to (&gstate->path, &distance); } cairo_status_t _cairo_gstate_rel_curve_to (cairo_gstate_t *gstate, + double dx0, double dy0, double dx1, double dy1, - double dx2, double dy2, - double dx3, double dy3) + double dx2, double dy2) { - cairo_status_t status; + cairo_distance_t distance[3]; + cairo_matrix_transform_distance (&gstate->ctm, &dx0, &dy0); cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1); cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2); - cairo_matrix_transform_distance (&gstate->ctm, &dx3, &dy3); - status = _cairo_path_curve_to (&gstate->path, - gstate->current_point.x + dx1, gstate->current_point.y + dy1, - gstate->current_point.x + dx2, gstate->current_point.y + dy2, - gstate->current_point.x + dx3, gstate->current_point.y + dy3); + distance[0].dx = _cairo_fixed_from_double (dx0); + distance[0].dy = _cairo_fixed_from_double (dy0); - _cairo_gstate_set_current_point (gstate, - gstate->current_point.x + dx3, - gstate->current_point.y + dy3); + distance[1].dx = _cairo_fixed_from_double (dx1); + distance[1].dy = _cairo_fixed_from_double (dy1); - return status; + distance[2].dx = _cairo_fixed_from_double (dx2); + distance[2].dy = _cairo_fixed_from_double (dy2); + + return _cairo_path_rel_curve_to (&gstate->path, + &distance[0], + &distance[1], + &distance[2]); } /* XXX: NYI @@ -1098,29 +1072,24 @@ _cairo_gstate_stroke_path (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_close_path (cairo_gstate_t *gstate) { - cairo_status_t status; - - status = _cairo_path_close_path (&gstate->path); - - _cairo_gstate_set_current_point (gstate, - gstate->last_move_point.x, - gstate->last_move_point.y); - - return status; + return _cairo_path_close_path (&gstate->path); } cairo_status_t _cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_ret) { + cairo_status_t status; + cairo_point_t point; double x, y; - if (gstate->has_current_point) { - x = gstate->current_point.x; - y = gstate->current_point.y; - cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y); - } else { + status = _cairo_path_current_point (&gstate->path, &point); + if (status == CAIRO_STATUS_NO_CURRENT_POINT) { x = 0.0; y = 0.0; + } else { + x = _cairo_fixed_to_double (point.x); + y = _cairo_fixed_to_double (point.y); + cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y); } *x_ret = x; @@ -1129,24 +1098,201 @@ _cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_re return CAIRO_STATUS_SUCCESS; } +typedef struct gstate_path_interpreter { + cairo_matrix_t ctm_inverse; + double tolerance; + cairo_point_t current_point; + + cairo_move_to_func_t *move_to; + cairo_line_to_func_t *line_to; + cairo_curve_to_func_t *curve_to; + cairo_close_path_func_t *close_path; + + void *closure; +} gpi_t; + static cairo_status_t -_cairo_gstate_ensure_source (cairo_gstate_t *gstate) +_gpi_move_to (void *closure, cairo_point_t *point) { - if (gstate->source) - return CAIRO_STATUS_SUCCESS; + gpi_t *gpi = closure; + double x, y; - if (gstate->surface == NULL) + x = _cairo_fixed_to_double (point->x); + y = _cairo_fixed_to_double (point->y); + + cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y); + + gpi->move_to (gpi->closure, x, y); + gpi->current_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_gpi_line_to (void *closure, cairo_point_t *point) +{ + gpi_t *gpi = closure; + double x, y; + + x = _cairo_fixed_to_double (point->x); + y = _cairo_fixed_to_double (point->y); + + cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y); + + gpi->line_to (gpi->closure, x, y); + gpi->current_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_gpi_curve_to (void *closure, + cairo_point_t *p1, + cairo_point_t *p2, + cairo_point_t *p3) +{ + gpi_t *gpi = closure; + cairo_status_t status; + cairo_spline_t spline; + double x1, y1, x2, y2, x3, y3; + + if (gpi->curve_to) { + x1 = _cairo_fixed_to_double (p1->x); + y1 = _cairo_fixed_to_double (p1->y); + cairo_matrix_transform_point (&gpi->ctm_inverse, &x1, &y1); + + x2 = _cairo_fixed_to_double (p2->x); + y2 = _cairo_fixed_to_double (p2->y); + cairo_matrix_transform_point (&gpi->ctm_inverse, &x2, &y2); + + x3 = _cairo_fixed_to_double (p3->x); + y3 = _cairo_fixed_to_double (p3->y); + cairo_matrix_transform_point (&gpi->ctm_inverse, &x3, &y3); + + gpi->curve_to (gpi->closure, x1, y1, x2, y2, x3, y3); + } else { + cairo_point_t *p0 = &gpi->current_point; + int i; + double x, y; + + status = _cairo_spline_init (&spline, p0, p1, p2, p3); + if (status == CAIRO_INT_STATUS_DEGENERATE) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_spline_decompose (&spline, gpi->tolerance); + if (status) + return status; + + for (i=1; i < spline.num_points; i++) { + x = _cairo_fixed_to_double (spline.points[i].x); + y = _cairo_fixed_to_double (spline.points[i].y); + + cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y); + + gpi->line_to (gpi->closure, x, y); + } + } + + gpi->current_point = *p3; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_gpi_close_path (void *closure) +{ + gpi_t *gpi = closure; + + gpi->close_path (gpi->closure); + + gpi->current_point.x = 0; + gpi->current_point.y = 0; + + return CAIRO_STATUS_SUCCESS; +} + +/* It's OK for curve_path to be NULL. In that case, all curves in the + path will be decomposed into one or more calls to the line_to + function, (according to the current tolerance). */ +cairo_status_t +_cairo_gstate_interpret_path (cairo_gstate_t *gstate, + cairo_move_to_func_t *move_to, + cairo_line_to_func_t *line_to, + cairo_curve_to_func_t *curve_to, + cairo_close_path_func_t *close_path, + void *closure) +{ + cairo_path_t path; + gpi_t gpi; + + /* Anything we want from gstate must be copied. We must not retain + pointers into gstate. */ + _cairo_path_init_copy (&path, &gstate->path); + + cairo_matrix_copy (&gpi.ctm_inverse, &gstate->ctm_inverse); + gpi.tolerance = gstate->tolerance; + + gpi.move_to = move_to; + gpi.line_to = line_to; + gpi.curve_to = curve_to; + gpi.close_path = close_path; + gpi.closure = closure; + + gpi.current_point.x = 0; + gpi.current_point.y = 0; + + return _cairo_path_interpret (&path, + CAIRO_DIRECTION_FORWARD, + _gpi_move_to, + _gpi_line_to, + _gpi_curve_to, + _gpi_close_path, + &gpi); +} + +/* This function modifies the pattern and the state of the pattern surface it + may contain. The pattern surface will be restored to its orignal state + when the pattern is destroyed. The appropriate way is to pass a copy of + the original pattern to this function just before the pattern should be + used and destroy the copy when done. */ +static cairo_status_t +_cairo_gstate_create_pattern (cairo_gstate_t *gstate, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + cairo_int_status_t status; + + if (gstate->surface == NULL) { + _cairo_pattern_fini (pattern); return CAIRO_STATUS_NO_TARGET_SURFACE; + } - gstate->source = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_ARGB32, - 1, 1, - &gstate->color); - if (gstate->source == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (pattern->type == CAIRO_PATTERN_LINEAR || + pattern->type == CAIRO_PATTERN_RADIAL) { + if (pattern->n_stops < 2) { + pattern->type = CAIRO_PATTERN_SOLID; + + if (pattern->n_stops) + pattern->color = pattern->stops->color; + } + } + + _cairo_pattern_set_alpha (pattern, gstate->alpha); + _cairo_pattern_transform (pattern, &gstate->ctm, &gstate->ctm_inverse); - cairo_surface_set_repeat (gstate->source, 1); + status = _cairo_surface_create_pattern (gstate->surface, pattern, extents); + if (status) { + _cairo_pattern_fini (pattern); + return status; + } + + if (pattern->type == CAIRO_PATTERN_SURFACE) + _cairo_pattern_prepare_surface (pattern); + _cairo_pattern_add_source_offset (pattern, + gstate->pattern_offset.x, + gstate->pattern_offset.y); + return CAIRO_STATUS_SUCCESS; } @@ -1155,15 +1301,10 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate) { cairo_status_t status; cairo_traps_t traps; - cairo_matrix_t user_to_source, device_to_source; if (gstate->line_width <= 0.0) return CAIRO_STATUS_SUCCESS; - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; - _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); _cairo_traps_init (&traps); @@ -1174,21 +1315,11 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate) return status; } - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, &user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, &user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->surface, - &traps); - - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, &user_to_source); + gstate->pattern, + gstate->operator, + gstate->surface, + &traps); _cairo_traps_fini (&traps); @@ -1227,12 +1358,14 @@ BAIL: /* Warning: This call modifies the coordinates of traps */ static cairo_status_t _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, - cairo_surface_t *src, + cairo_pattern_t *src, cairo_operator_t operator, cairo_surface_t *dst, cairo_traps_t *traps) { cairo_status_t status; + cairo_pattern_t pattern; + cairo_box_t extents; if (traps->num_traps == 0) return CAIRO_STATUS_SUCCESS; @@ -1241,19 +1374,8 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, cairo_fixed_t xoff, yoff; cairo_trapezoid_t *t; int i; - - cairo_surface_t *white, *intermediate; - cairo_color_t white_color, empty_color; - - _cairo_color_init (&white_color); - white = _cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, - 1, 1, - &white_color); - if (white == NULL) { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; - } - cairo_surface_set_repeat (white, 1); + cairo_surface_t *intermediate; + cairo_color_t empty_color; _cairo_color_init (&empty_color); _cairo_color_set_alpha (&empty_color, 0.); @@ -1261,10 +1383,10 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, CAIRO_FORMAT_A8, gstate->clip.width, gstate->clip.height, - &empty_color); + &empty_color); if (intermediate == NULL) { status = CAIRO_STATUS_NO_MEMORY; - goto BAIL1; + goto BAIL0; } /* Ugh. The cairo_composite/(Render) interface doesn't allow @@ -1286,8 +1408,16 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, t->right.p2.y -= yoff; } + _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&pattern, 1.0); + + _cairo_traps_extents (traps, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + goto BAIL1; + status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD, - white, intermediate, + pattern.source, intermediate, 0, 0, traps->traps, traps->num_traps); @@ -1302,9 +1432,23 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, gstate->clip.width, gstate->clip.height); if (status) goto BAIL2; + + _cairo_pattern_fini (&pattern); + + _cairo_pattern_init_copy (&pattern, src); + + extents.p1.x = _cairo_fixed_from_int (gstate->clip.x); + extents.p1.y = _cairo_fixed_from_int (gstate->clip.y); + extents.p2.x = + _cairo_fixed_from_int (gstate->clip.x + gstate->clip.width); + extents.p2.y = + _cairo_fixed_from_int (gstate->clip.y + gstate->clip.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + goto BAIL2; status = _cairo_surface_composite (operator, - src, intermediate, dst, + pattern.source, intermediate, dst, 0, 0, 0, 0, gstate->clip.x, @@ -1315,11 +1459,12 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, BAIL2: cairo_surface_destroy (intermediate); BAIL1: - cairo_surface_destroy (white); + _cairo_pattern_fini (&pattern); BAIL0: + if (status) return status; - + } else { int xoff, yoff; @@ -1331,16 +1476,26 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, yoff = _cairo_fixed_to_double (traps->traps[0].left.p2.y); } + _cairo_pattern_init_copy (&pattern, src); + + _cairo_traps_extents (traps, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_surface_composite_trapezoids (gstate->operator, - src, dst, - xoff - gstate->source_offset.x, - yoff - gstate->source_offset.y, + pattern.source, dst, + xoff - pattern.source_offset.x, + yoff - pattern.source_offset.y, traps->traps, traps->num_traps); + + _cairo_pattern_fini (&pattern); + if (status) return status; } - + return CAIRO_STATUS_SUCCESS; } @@ -1349,11 +1504,6 @@ _cairo_gstate_fill (cairo_gstate_t *gstate) { cairo_status_t status; cairo_traps_t traps; - cairo_matrix_t user_to_source, device_to_source; - - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; _cairo_traps_init (&traps); @@ -1363,21 +1513,11 @@ _cairo_gstate_fill (cairo_gstate_t *gstate) return status; } - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, &user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, &user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->surface, - &traps); - - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, &user_to_source); + gstate->pattern, + gstate->operator, + gstate->surface, + &traps); _cairo_traps_fini (&traps); @@ -1404,7 +1544,7 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate, goto BAIL; *inside_ret = _cairo_traps_contain (&traps, x, y); - + BAIL: _cairo_traps_fini (&traps); @@ -1430,39 +1570,137 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate) } cairo_status_t -_cairo_gstate_clip (cairo_gstate_t *gstate) +_cairo_gstate_stroke_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2) { cairo_status_t status; - cairo_surface_t *alpha_one; cairo_traps_t traps; - cairo_color_t white_color; + cairo_box_t extents; + + _cairo_traps_init (&traps); + + status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps); + if (status) + goto BAIL; - _cairo_color_init (&white_color); + _cairo_traps_extents (&traps, &extents); - if (gstate->clip.surface == NULL) { - double x1, y1, x2, y2; - _cairo_path_bounds (&gstate->path, - &x1, &y1, &x2, &y2); - gstate->clip.x = floor (x1); - gstate->clip.y = floor (y1); - gstate->clip.width = ceil (x2 - gstate->clip.x); - gstate->clip.height = ceil (y2 - gstate->clip.y); - gstate->clip.surface = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_A8, - gstate->clip.width, - gstate->clip.height, - &white_color); - if (gstate->clip.surface == NULL) - return CAIRO_STATUS_NO_MEMORY; + *x1 = _cairo_fixed_to_double (extents.p1.x); + *y1 = _cairo_fixed_to_double (extents.p1.y); + *x2 = _cairo_fixed_to_double (extents.p2.x); + *y2 = _cairo_fixed_to_double (extents.p2.y); + + cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); + cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + +BAIL: + _cairo_traps_fini (&traps); + + return status; +} + +cairo_status_t +_cairo_gstate_fill_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2) +{ + cairo_status_t status; + cairo_traps_t traps; + cairo_box_t extents; + + _cairo_traps_init (&traps); + + status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps); + if (status) + goto BAIL; + + _cairo_traps_extents (&traps, &extents); + + *x1 = _cairo_fixed_to_double (extents.p1.x); + *y1 = _cairo_fixed_to_double (extents.p1.y); + *x2 = _cairo_fixed_to_double (extents.p2.x); + *y2 = _cairo_fixed_to_double (extents.p2.y); + + cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); + cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + +BAIL: + _cairo_traps_fini (&traps); + + return status; +} + +cairo_status_t +_cairo_gstate_init_clip (cairo_gstate_t *gstate) +{ + /* destroy any existing clip-region artifacts */ + if (gstate->clip.surface) + cairo_surface_destroy (gstate->clip.surface); + gstate->clip.surface = NULL; + + if (gstate->clip.region) + pixman_region_destroy (gstate->clip.region); + gstate->clip.region = NULL; + + /* reset the surface's clip to the whole surface */ + _cairo_surface_set_clip_region (gstate->surface, + gstate->clip.region); + + return CAIRO_STATUS_SUCCESS; +} + +static int +extract_transformed_rectangle(cairo_matrix_t *mat, + cairo_traps_t *tr, + pixman_box16_t *box) +{ +#define CAIRO_FIXED_IS_INTEGER(x) (((x) & 0xFFFF) == 0) +#define CAIRO_FIXED_INTEGER_PART(x) ((x) >> 16) + + double a, b, c, d, tx, ty; + cairo_status_t st; + + st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty); + if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.)) + return 0; + + if (tr->num_traps == 1 + && tr->traps[0].left.p1.x == tr->traps[0].left.p2.x + && tr->traps[0].right.p1.x == tr->traps[0].right.p2.x + && tr->traps[0].left.p1.y == tr->traps[0].right.p1.y + && tr->traps[0].left.p2.y == tr->traps[0].right.p2.y + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.x) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.y) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.x) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.y) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.x) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.y) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.x) + && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.y)) { + + box->x1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.x); + box->x2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].right.p1.x); + box->y1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.y); + box->y2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p2.y); + return 1; } + return 0; - alpha_one = _cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, - 1, 1, - &white_color); - if (alpha_one == NULL) - return CAIRO_STATUS_NO_MEMORY; +#undef CAIRO_FIXED_IS_INTEGER +#undef CAIRO_FIXED_INTEGER_PART +} - cairo_surface_set_repeat (alpha_one, 1); +cairo_status_t +_cairo_gstate_clip (cairo_gstate_t *gstate) +{ + cairo_status_t status; + cairo_pattern_t pattern; + cairo_traps_t traps; + cairo_color_t white_color; + pixman_box16_t box; + + /* Fill the clip region as traps. */ _cairo_traps_init (&traps); status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps); @@ -1471,16 +1709,82 @@ _cairo_gstate_clip (cairo_gstate_t *gstate) return status; } + /* Check to see if we can represent these traps as a PixRegion. */ + + if (extract_transformed_rectangle (&gstate->ctm, &traps, &box)) { + + pixman_region16_t *rect = NULL; + pixman_region16_t *intersection = NULL; + + status = CAIRO_STATUS_SUCCESS; + rect = pixman_region_create_simple (&box); + + if (rect == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + + } else { + + if (gstate->clip.region == NULL) { + gstate->clip.region = rect; + } else { + intersection = pixman_region_create(); + if (pixman_region_intersect (intersection, + gstate->clip.region, rect) + == PIXMAN_REGION_STATUS_SUCCESS) { + pixman_region_destroy (gstate->clip.region); + gstate->clip.region = intersection; + } else { + status = CAIRO_STATUS_NO_MEMORY; + } + pixman_region_destroy (rect); + } + + if (!status) + status = _cairo_surface_set_clip_region (gstate->surface, + gstate->clip.region); + } + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + _cairo_traps_fini (&traps); + return status; + } + } + + /* Otherwise represent the clip as a mask surface. */ + + _cairo_color_init (&white_color); + + if (gstate->clip.surface == NULL) { + double x1, y1, x2, y2; + _cairo_path_bounds (&gstate->path, + &x1, &y1, &x2, &y2); + gstate->clip.x = floor (x1); + gstate->clip.y = floor (y1); + gstate->clip.width = ceil (x2 - gstate->clip.x); + gstate->clip.height = ceil (y2 - gstate->clip.y); + gstate->clip.surface = + _cairo_surface_create_similar_solid (gstate->surface, + CAIRO_FORMAT_A8, + gstate->clip.width, + gstate->clip.height, + &white_color); + if (gstate->clip.surface == NULL) + return CAIRO_STATUS_NO_MEMORY; + } + + _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&pattern, 1.0); + _cairo_gstate_clip_and_composite_trapezoids (gstate, - alpha_one, + &pattern, CAIRO_OPERATOR_IN, gstate->clip.surface, &traps); - + + _cairo_pattern_fini (&pattern); + _cairo_traps_fini (&traps); - cairo_surface_destroy (alpha_one); - return status; } @@ -1491,27 +1795,12 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, int height) { cairo_status_t status; - cairo_surface_t *mask; cairo_matrix_t user_to_image, image_to_user; cairo_matrix_t image_to_device, device_to_image; double device_x, device_y; double device_width, device_height; - cairo_color_t alpha_color; - - if (gstate->alpha != 1.0) { - _cairo_color_init (&alpha_color); - _cairo_color_set_alpha (&alpha_color, gstate->alpha); - mask = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_A8, - 1, 1, - &alpha_color); - if (mask == NULL) - return CAIRO_STATUS_NO_MEMORY; - - cairo_surface_set_repeat (mask, 1); - } else { - mask = NULL; - } + cairo_pattern_t pattern; + cairo_box_t extents; cairo_surface_get_matrix (surface, &user_to_image); cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image); @@ -1527,32 +1816,47 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, _cairo_matrix_transform_bounding_box (&image_to_device, &device_x, &device_y, &device_width, &device_height); + + _cairo_pattern_init (&pattern); + + if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) || + (gstate->alpha != 1.0)) { + /* I'm allowing any type of pattern for the mask right now. + Maybe this is bad. Will allow for some cool effects though. */ + _cairo_pattern_init_copy (&pattern, gstate->pattern); + extents.p1.x = _cairo_fixed_from_double (device_x); + extents.p1.y = _cairo_fixed_from_double (device_y); + extents.p2.x = _cairo_fixed_from_double (device_x + device_width); + extents.p2.y = _cairo_fixed_from_double (device_y + device_height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + } /* XXX: The rendered size is sometimes 1 or 2 pixels short from what I expect. Need to fix this. */ status = _cairo_surface_composite (gstate->operator, - surface, mask, gstate->surface, + surface, pattern.source, gstate->surface, device_x, device_y, 0, 0, device_x, device_y, device_width, device_height); - - if (mask) - cairo_surface_destroy (mask); - if (status) - return status; + _cairo_pattern_fini (&pattern); /* restore the matrix originally in the surface */ cairo_surface_set_matrix (surface, &user_to_image); + + if (status) + return status; return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_gstate_select_font (cairo_gstate_t *gstate, - char *family, + const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) { @@ -1600,6 +1904,7 @@ _cairo_gstate_current_font_extents (cairo_gstate_t *gstate, status = _cairo_font_font_extents (gstate->font, extents); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + return status; } @@ -1622,14 +1927,24 @@ _cairo_gstate_text_extents (cairo_gstate_t *gstate, { cairo_matrix_t saved_font_matrix; cairo_status_t status; + double scale_x, scale_y; cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y); + cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y); status = _cairo_font_text_extents (gstate->font, utf8, extents); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + + extents->x_bearing /= scale_x; + extents->y_bearing /= scale_y; + extents->width /= scale_x; + extents->height /= scale_y; + extents->x_advance /= scale_x; + extents->y_advance /= scale_y; + return status; } @@ -1640,120 +1955,91 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, cairo_text_extents_t *extents) { cairo_status_t status; - int i; - cairo_glyph_t *transformed_glyphs = NULL; cairo_matrix_t saved_font_matrix; - - transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); - if (transformed_glyphs == NULL) - return CAIRO_STATUS_NO_MEMORY; - - for (i = 0; i < num_glyphs; ++i) - { - transformed_glyphs[i] = glyphs[i]; - cairo_matrix_transform_point (&gstate->ctm, - &(transformed_glyphs[i].x), - &(transformed_glyphs[i].y)); - } + double scale_x, scale_y; cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); - cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y); + cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y); status = _cairo_font_glyph_extents (gstate->font, - transformed_glyphs, num_glyphs, + glyphs, num_glyphs, extents); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - free (transformed_glyphs); - return status; -} - + extents->x_bearing /= scale_x; + extents->y_bearing /= scale_y; + extents->width /= scale_x; + extents->height /= scale_y; + extents->x_advance /= scale_x; + extents->y_advance /= scale_y; -static cairo_status_t -setup_text_rendering_context(cairo_gstate_t *gstate, - double *x, double *y, - cairo_matrix_t *user_to_source) -{ - cairo_status_t status; - cairo_matrix_t device_to_source; - - /* XXX: I believe this is correct, but it would be much more clear - to have some explicit current_point accesor functions, (one for - user- and one for device-space). */ - - if (gstate->has_current_point) { - *x = gstate->current_point.x; - *y = gstate->current_point.y; - } else { - *x = 0; - *y = 0; - cairo_matrix_transform_point (&gstate->ctm, x, y); - } - - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; - - /* XXX: This same source matrix manipulation code shows up in - about 3 or 4 places. We should move that into a shared function - or two. */ - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - return CAIRO_STATUS_SUCCESS; -} - -static void -restore_text_rendering_context(cairo_gstate_t *gstate, - cairo_matrix_t *user_to_source) -{ - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, user_to_source); + return status; } - cairo_status_t _cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8) { cairo_status_t status; + cairo_point_t point; double x, y; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; - - status = setup_text_rendering_context(gstate, &x, &y, &user_to_source); - if (status) - return status; + cairo_pattern_t pattern; + cairo_text_extents_t text_extents; + cairo_box_t extents; + + status = _cairo_path_current_point (&gstate->path, &point); + if (status == CAIRO_STATUS_NO_CURRENT_POINT) { + x = 0; + y = 0; + cairo_matrix_transform_point (&gstate->ctm, &x, &y); + } else { + x = _cairo_fixed_to_double (point.x); + y = _cairo_fixed_to_double (point.y); + } cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_pattern_init_copy (&pattern, gstate->pattern); + + status = _cairo_gstate_text_extents (gstate, utf8, &text_extents); + if (status) + return status; + + extents.p1.x = _cairo_fixed_from_double (x); + extents.p1.y = _cairo_fixed_from_double (y); + extents.p2.x = _cairo_fixed_from_double (x + text_extents.width); + extents.p2.y = _cairo_fixed_from_double (y + text_extents.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_font_show_text (gstate->font, - gstate->operator, gstate->source, + gstate->operator, pattern.source, gstate->surface, x, y, utf8); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); + + _cairo_pattern_fini (&pattern); return status; } - cairo_status_t _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, int num_glyphs) { cairo_status_t status; - double x, y; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; int i; cairo_glyph_t *transformed_glyphs = NULL; + cairo_pattern_t pattern; + cairo_text_extents_t text_extents; + cairo_box_t extents; transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) @@ -1767,25 +2053,37 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, &(transformed_glyphs[i].y)); } - status = setup_text_rendering_context (gstate, &x, &y, &user_to_source); - if (status) - return status; - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_pattern_init_copy (&pattern, gstate->pattern); + _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs, + &text_extents); + if (status) + return status; + + extents.p1.x = _cairo_fixed_from_double (transformed_glyphs[0].x); + extents.p1.y = _cairo_fixed_from_double (transformed_glyphs[0].y); + extents.p2.x = _cairo_fixed_from_double (transformed_glyphs[0].x + + text_extents.width); + extents.p2.y = _cairo_fixed_from_double (transformed_glyphs[0].y + + text_extents.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_font_show_glyphs (gstate->font, - gstate->operator, gstate->source, - gstate->surface, x, y, + gstate->operator, pattern.source, + gstate->surface, transformed_glyphs, num_glyphs); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); + + _cairo_pattern_fini (&pattern); free (transformed_glyphs); return status; - } @@ -1795,21 +2093,35 @@ _cairo_gstate_text_path (cairo_gstate_t *gstate, { cairo_status_t status; cairo_matrix_t saved_font_matrix; + cairo_point_t point; + double x, y; + + status = _cairo_path_current_point (&gstate->path, &point); + if (status == CAIRO_STATUS_NO_CURRENT_POINT) { + x = 0; + y = 0; + cairo_matrix_transform_point (&gstate->ctm, &x, &y); + } else { + x = _cairo_fixed_to_double (point.x); + y = _cairo_fixed_to_double (point.y); + } cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); status = _cairo_font_text_path (gstate->font, - &gstate->path, - utf8); + x, y, + utf8, + &gstate->path); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); + return status; } cairo_status_t -_cairo_gstate_glyph_path (cairo_gstate_t *gstate, +_cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, int num_glyphs) { @@ -1834,11 +2146,11 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); status = _cairo_font_glyph_path (gstate->font, - &gstate->path, - transformed_glyphs, num_glyphs); + transformed_glyphs, num_glyphs, + &gstate->path); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - + free (transformed_glyphs); return status; } diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c index efa54d26a..a11a07eed 100644 --- a/src/cairo_image_surface.c +++ b/src/cairo_image_surface.c @@ -45,7 +45,7 @@ _cairo_format_bpp (cairo_format_t format) } static cairo_image_surface_t * -_cairo_image_surface_create_for_ic_image (IcImage *ic_image) +_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image) { cairo_image_surface_t *surface; @@ -55,15 +55,15 @@ _cairo_image_surface_create_for_ic_image (IcImage *ic_image) _cairo_surface_init (&surface->base, &cairo_image_surface_backend); - surface->ic_image = ic_image; + surface->pixman_image = pixman_image; - surface->data = (char *) IcImageGetData (ic_image); + surface->data = (char *) pixman_image_get_data (pixman_image); surface->owns_data = 0; - surface->width = IcImageGetWidth (ic_image); - surface->height = IcImageGetHeight (ic_image); - surface->stride = IcImageGetStride (ic_image); - surface->depth = IcImageGetDepth (ic_image); + surface->width = pixman_image_get_width (pixman_image); + surface->height = pixman_image_get_height (pixman_image); + surface->stride = pixman_image_get_stride (pixman_image); + surface->depth = pixman_image_get_depth (pixman_image); return surface; } @@ -76,47 +76,47 @@ _cairo_image_surface_create_with_masks (char *data, int stride) { cairo_image_surface_t *surface; - IcFormat *ic_format; - IcImage *ic_image; + pixman_format_t *pixman_format; + pixman_image_t *pixman_image; - ic_format = IcFormatCreateMasks (format->bpp, - format->alpha_mask, - format->red_mask, - format->green_mask, - format->blue_mask); + pixman_format = pixman_format_create_masks (format->bpp, + format->alpha_mask, + format->red_mask, + format->green_mask, + format->blue_mask); - if (ic_format == NULL) + if (pixman_format == NULL) return NULL; - ic_image = IcImageCreateForData ((IcBits *) data, ic_format, - width, height, format->bpp, stride); + pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format, + width, height, format->bpp, stride); - IcFormatDestroy (ic_format); + pixman_format_destroy (pixman_format); - if (ic_image == NULL) + if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_ic_image (ic_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image); return surface; } -static IcFormat * -_create_ic_format (cairo_format_t format) +static pixman_format_t * +_create_pixman_format (cairo_format_t format) { switch (format) { case CAIRO_FORMAT_A1: - return IcFormatCreate (IcFormatNameA1); + return pixman_format_create (PIXMAN_FORMAT_NAME_A1); break; case CAIRO_FORMAT_A8: - return IcFormatCreate (IcFormatNameA8); + return pixman_format_create (PIXMAN_FORMAT_NAME_A8); break; case CAIRO_FORMAT_RGB24: - return IcFormatCreate (IcFormatNameRGB24); + return pixman_format_create (PIXMAN_FORMAT_NAME_RG_B24); break; case CAIRO_FORMAT_ARGB32: default: - return IcFormatCreate (IcFormatNameARGB32); + return pixman_format_create (PIXMAN_FORMAT_NAME_AR_GB32); break; } } @@ -127,21 +127,21 @@ cairo_image_surface_create (cairo_format_t format, int height) { cairo_image_surface_t *surface; - IcFormat *ic_format; - IcImage *ic_image; + pixman_format_t *pixman_format; + pixman_image_t *pixman_image; - ic_format = _create_ic_format (format); - if (ic_format == NULL) + pixman_format = _create_pixman_format (format); + if (pixman_format == NULL) return NULL; - ic_image = IcImageCreate (ic_format, width, height); + pixman_image = pixman_image_create (pixman_format, width, height); - IcFormatDestroy (ic_format); + pixman_format_destroy (pixman_format); - if (ic_image == NULL) + if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_ic_image (ic_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image); return &surface->base; } @@ -154,24 +154,24 @@ cairo_image_surface_create_for_data (char *data, int stride) { cairo_image_surface_t *surface; - IcFormat *ic_format; - IcImage *ic_image; + pixman_format_t *pixman_format; + pixman_image_t *pixman_image; - ic_format = _create_ic_format (format); - if (ic_format == NULL) + pixman_format = _create_pixman_format (format); + if (pixman_format == NULL) return NULL; - ic_image = IcImageCreateForData ((IcBits *) data, ic_format, - width, height, - _cairo_format_bpp (format), - stride); + pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format, + width, height, + _cairo_format_bpp (format), + stride); - IcFormatDestroy (ic_format); + pixman_format_destroy (pixman_format); - if (ic_image == NULL) + if (pixman_image == NULL) return NULL; - surface = _cairo_image_surface_create_for_ic_image (ic_image); + surface = _cairo_image_surface_create_for_pixman_image (pixman_image); return &surface->base; } @@ -190,8 +190,8 @@ _cairo_image_abstract_surface_destroy (void *abstract_surface) { cairo_image_surface_t *surface = abstract_surface; - if (surface->ic_image) - IcImageDestroy (surface->ic_image); + if (surface->pixman_image) + pixman_image_destroy (surface->pixman_image); if (surface->owns_data) { free (surface->data); @@ -247,21 +247,21 @@ cairo_status_t _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, cairo_matrix_t *matrix) { - IcTransform ic_transform; + pixman_transform_t pixman_transform; - ic_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); - ic_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); - ic_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); + pixman_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); + pixman_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); + pixman_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); - ic_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); - ic_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); - ic_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); + pixman_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); + pixman_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); + pixman_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); - ic_transform.matrix[2][0] = 0; - ic_transform.matrix[2][1] = 0; - ic_transform.matrix[2][2] = _cairo_fixed_from_double (1); + pixman_transform.matrix[2][0] = 0; + pixman_transform.matrix[2][1] = 0; + pixman_transform.matrix[2][2] = _cairo_fixed_from_double (1); - IcImageSetTransform (surface->ic_image, &ic_transform); + pixman_image_set_transform (surface->pixman_image, &pixman_transform); return CAIRO_STATUS_SUCCESS; } @@ -277,29 +277,29 @@ _cairo_image_abstract_surface_set_filter (void *abstract_surface, cairo_filter_t cairo_status_t _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter) { - IcFilter ic_filter; + pixman_filter_t pixman_filter; switch (filter) { case CAIRO_FILTER_FAST: - ic_filter = IcFilterFast; + pixman_filter = PIXMAN_FILTER_FAST; break; case CAIRO_FILTER_GOOD: - ic_filter = IcFilterGood; + pixman_filter = PIXMAN_FILTER_GOOD; break; case CAIRO_FILTER_BEST: - ic_filter = IcFilterBest; + pixman_filter = PIXMAN_FILTER_BEST; break; case CAIRO_FILTER_NEAREST: - ic_filter = IcFilterNearest; + pixman_filter = PIXMAN_FILTER_NEAREST; break; case CAIRO_FILTER_BILINEAR: - ic_filter = IcFilterBilinear; + pixman_filter = PIXMAN_FILTER_BILINEAR; break; default: - ic_filter = IcFilterBest; + pixman_filter = PIXMAN_FILTER_BEST; } - IcImageSetFilter (surface->ic_image, ic_filter); + pixman_image_set_filter (surface->pixman_image, pixman_filter); return CAIRO_STATUS_SUCCESS; } @@ -314,45 +314,45 @@ _cairo_image_abstract_surface_set_repeat (void *abstract_surface, int repeat) cairo_status_t _cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat) { - IcImageSetRepeat (surface->ic_image, repeat); + pixman_image_set_repeat (surface->pixman_image, repeat); return CAIRO_STATUS_SUCCESS; } -static IcOperator -_ic_operator (cairo_operator_t operator) +static pixman_operator_t +_pixman_operator (cairo_operator_t operator) { switch (operator) { case CAIRO_OPERATOR_CLEAR: - return IcOperatorClear; + return PIXMAN_OPERATOR_CLEAR; case CAIRO_OPERATOR_SRC: - return IcOperatorSrc; + return PIXMAN_OPERATOR_SRC; case CAIRO_OPERATOR_DST: - return IcOperatorDst; + return PIXMAN_OPERATOR_DST; case CAIRO_OPERATOR_OVER: - return IcOperatorOver; + return PIXMAN_OPERATOR_OVER; case CAIRO_OPERATOR_OVER_REVERSE: - return IcOperatorOverReverse; + return PIXMAN_OPERATOR_OVER_REVERSE; case CAIRO_OPERATOR_IN: - return IcOperatorIn; + return PIXMAN_OPERATOR_IN; case CAIRO_OPERATOR_IN_REVERSE: - return IcOperatorInReverse; + return PIXMAN_OPERATOR_IN_REVERSE; case CAIRO_OPERATOR_OUT: - return IcOperatorOut; + return PIXMAN_OPERATOR_OUT; case CAIRO_OPERATOR_OUT_REVERSE: - return IcOperatorOutReverse; + return PIXMAN_OPERATOR_OUT_REVERSE; case CAIRO_OPERATOR_ATOP: - return IcOperatorAtop; + return PIXMAN_OPERATOR_ATOP; case CAIRO_OPERATOR_ATOP_REVERSE: - return IcOperatorAtopReverse; + return PIXMAN_OPERATOR_ATOP_REVERSE; case CAIRO_OPERATOR_XOR: - return IcOperatorXor; + return PIXMAN_OPERATOR_XOR; case CAIRO_OPERATOR_ADD: - return IcOperatorAdd; + return PIXMAN_OPERATOR_ADD; case CAIRO_OPERATOR_SATURATE: - return IcOperatorSaturate; + return PIXMAN_OPERATOR_SATURATE; default: - return IcOperatorOver; + return PIXMAN_OPERATOR_OVER; } } @@ -380,14 +380,14 @@ _cairo_image_surface_composite (cairo_operator_t operator, return CAIRO_INT_STATUS_UNSUPPORTED; } - IcComposite (_ic_operator (operator), - src->ic_image, - mask ? mask->ic_image : NULL, - dst->ic_image, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, - width, height); + pixman_composite (_pixman_operator (operator), + src->pixman_image, + mask ? mask->pixman_image : NULL, + dst->pixman_image, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); return CAIRO_STATUS_SUCCESS; } @@ -401,16 +401,16 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, { cairo_image_surface_t *surface = abstract_surface; - IcColor ic_color; + pixman_color_t pixman_color; - ic_color.red = color->red_short; - ic_color.green = color->green_short; - ic_color.blue = color->blue_short; - ic_color.alpha = color->alpha_short; + pixman_color.red = color->red_short; + pixman_color.green = color->green_short; + pixman_color.blue = color->blue_short; + pixman_color.alpha = color->alpha_short; - /* XXX: The IcRectangle cast is evil... it needs to go away somehow. */ - IcFillRectangles (_ic_operator(operator), surface->ic_image, - &ic_color, (IcRectangle *) rects, num_rects); + /* XXX: The pixman_rectangle_t cast is evil... it needs to go away somehow. */ + pixman_fill_rectangles (_pixman_operator(operator), surface->pixman_image, + &pixman_color, (pixman_rectangle_t *) rects, num_rects); return CAIRO_STATUS_SUCCESS; } @@ -430,9 +430,9 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator, if (generic_src->backend != dst->base.backend) return CAIRO_INT_STATUS_UNSUPPORTED; - /* XXX: The IcTrapezoid cast is evil and needs to go away somehow. */ - IcCompositeTrapezoids (operator, src->ic_image, dst->ic_image, - x_src, y_src, (IcTrapezoid *) traps, num_traps); + /* XXX: The pixman_trapezoid_t cast is evil and needs to go away somehow. */ + pixman_composite_trapezoids (operator, src->pixman_image, dst->pixman_image, + x_src, y_src, (pixman_trapezoid_t *) traps, num_traps); return CAIRO_STATUS_SUCCESS; } @@ -449,6 +449,44 @@ _cairo_image_surface_show_page (void *abstract_surface) return CAIRO_INT_STATUS_UNSUPPORTED; } +static cairo_int_status_t +_cairo_image_abstract_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface; + + return _cairo_image_surface_set_clip_region (surface, region); +} + +cairo_int_status_t +_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, + pixman_region16_t *region) +{ + pixman_image_set_clip_region (surface->pixman_image, region); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_image_abstract_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_image_surface_t *image; + + /* Fall back to general pattern creation for surface patterns. */ + if (pattern->type == CAIRO_PATTERN_SURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + image = _cairo_pattern_get_image (pattern, box); + if (image) { + pattern->source = &image->base; + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; +} + static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_create_similar, _cairo_image_abstract_surface_destroy, @@ -462,5 +500,7 @@ static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_fill_rectangles, _cairo_image_surface_composite_trapezoids, _cairo_image_surface_copy_page, - _cairo_image_surface_show_page + _cairo_image_surface_show_page, + _cairo_image_abstract_surface_set_clip_region, + _cairo_image_abstract_surface_create_pattern }; diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c index 655bcde83..de89c0fd5 100644 --- a/src/cairo_matrix.c +++ b/src/cairo_matrix.c @@ -386,3 +386,22 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou return CAIRO_STATUS_SUCCESS; } + +/* Compute the amount that each basis vector is scaled by. */ +cairo_status_t +_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy) +{ + double x, y; + + x = 1.0; + y = 0.0; + cairo_matrix_transform_distance (matrix, &x, &y); + *sx = sqrt(x*x + y*y); + + x = 0.0; + y = 1.0; + cairo_matrix_transform_distance (matrix, &x, &y); + *sy = sqrt(x*x + y*y); + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo_path.c b/src/cairo_path.c index 9366394d5..91142c8ff 100644 --- a/src/cairo_path.c +++ b/src/cairo_path.c @@ -70,6 +70,11 @@ _cairo_path_init (cairo_path_t *path) path->arg_head = NULL; path->arg_tail = NULL; + + path->current_point.x = 0; + path->current_point.y = 0; + path->has_current_point = 0; + path->last_move_point = path->current_point; } cairo_status_t @@ -79,6 +84,9 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other) cairo_path_arg_buf_t *arg, *other_arg; _cairo_path_init (path); + path->current_point = other->current_point; + path->has_current_point = other->has_current_point; + path->last_move_point = other->last_move_point; for (other_op = other->op_head; other_op; other_op = other_op->next) { op = _cairo_path_op_buf_create (); @@ -120,54 +128,131 @@ _cairo_path_fini (cairo_path_t *path) _cairo_path_arg_buf_destroy (arg); } path->arg_tail = NULL; + + path->has_current_point = 0; +} + +cairo_status_t +_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point) +{ + cairo_status_t status; + + status = _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, point, 1); + if (status) + return status; + + path->current_point = *point; + path->has_current_point = 1; + path->last_move_point = path->current_point; + + return CAIRO_STATUS_SUCCESS; } cairo_status_t -_cairo_path_move_to (cairo_path_t *path, double x, double y) +_cairo_path_rel_move_to (cairo_path_t *path, cairo_distance_t *distance) { cairo_point_t point; - point.x = _cairo_fixed_from_double (x); - point.y = _cairo_fixed_from_double (y); + point.x = path->current_point.x + distance->dx; + point.y = path->current_point.y + distance->dy; + + return _cairo_path_move_to (path, &point); +} + +cairo_status_t +_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point) +{ + cairo_status_t status; + + status = _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, point, 1); + if (status) + return status; - return _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1); + path->current_point = *point; + path->has_current_point = 1; + + return CAIRO_STATUS_SUCCESS; } cairo_status_t -_cairo_path_line_to (cairo_path_t *path, double x, double y) +_cairo_path_rel_line_to (cairo_path_t *path, cairo_distance_t *distance) { cairo_point_t point; - point.x = _cairo_fixed_from_double (x); - point.y = _cairo_fixed_from_double (y); + point.x = path->current_point.x + distance->dx; + point.y = path->current_point.y + distance->dy; - return _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1); + return _cairo_path_line_to (path, &point); } cairo_status_t _cairo_path_curve_to (cairo_path_t *path, - double x1, double y1, - double x2, double y2, - double x3, double y3) + cairo_point_t *p0, + cairo_point_t *p1, + cairo_point_t *p2) { + cairo_status_t status; cairo_point_t point[3]; - point[0].x = _cairo_fixed_from_double (x1); - point[0].y = _cairo_fixed_from_double (y1); + point[0] = *p0; + point[1] = *p1; + point[2] = *p2; - point[1].x = _cairo_fixed_from_double (x2); - point[1].y = _cairo_fixed_from_double (y2); + status = _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3); + if (status) + return status; - point[2].x = _cairo_fixed_from_double (x3); - point[2].y = _cairo_fixed_from_double (y3); + path->current_point = *p2; + path->has_current_point = 1; - return _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3); + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_path_rel_curve_to (cairo_path_t *path, + cairo_distance_t *d0, + cairo_distance_t *d1, + cairo_distance_t *d2) +{ + cairo_point_t p0, p1, p2; + + p0.x = path->current_point.x + d0->dx; + p0.y = path->current_point.y + d0->dy; + + p1.x = path->current_point.x + d1->dx; + p1.y = path->current_point.y + d1->dy; + + p2.x = path->current_point.x + d2->dx; + p2.y = path->current_point.y + d2->dy; + + return _cairo_path_curve_to (path, &p0, &p1, &p2); } cairo_status_t _cairo_path_close_path (cairo_path_t *path) { - return _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0); + cairo_status_t status; + + status = _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0); + if (status) + return status; + + path->current_point.x = path->last_move_point.x; + path->current_point.y = path->last_move_point.y; + path->has_current_point = 1; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point) +{ + if (! path->has_current_point) + return CAIRO_STATUS_NO_CURRENT_POINT; + + *point = path->current_point; + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -320,7 +405,13 @@ static int const num_args[] = }; cairo_status_t -_cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_path_callbacks_t *cb, void *closure) +_cairo_path_interpret (cairo_path_t *path, + cairo_direction_t dir, + cairo_path_move_to_func_t *move_to, + cairo_path_line_to_func_t *line_to, + cairo_path_curve_to_func_t *curve_to, + cairo_path_close_path_func_t *close_path, + void *closure) { cairo_status_t status; int i, arg; @@ -329,10 +420,6 @@ _cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_pa cairo_path_arg_buf_t *arg_buf = path->arg_head; int buf_i = 0; cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS]; - cairo_point_t current = {0, 0}; - cairo_point_t first = {0, 0}; - int has_current = 0; - int has_edge = 0; int step = (dir == CAIRO_DIRECTION_FORWARD) ? 1 : -1; for (op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? path->op_head : path->op_tail; @@ -374,62 +461,24 @@ _cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_pa switch (op) { case CAIRO_PATH_OP_MOVE_TO: - if (has_edge) { - status = (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_CAP); - if (status) - return status; - } - first = point[0]; - current = point[0]; - has_current = 1; - has_edge = 0; + status = (*move_to) (closure, &point[0]); break; case CAIRO_PATH_OP_LINE_TO: - if (has_current) { - status = (*cb->add_edge) (closure, ¤t, &point[0]); - if (status) - return status; - current = point[0]; - has_edge = 1; - } else { - first = point[0]; - current = point[0]; - has_current = 1; - has_edge = 0; - } + status = (*line_to) (closure, &point[0]); break; case CAIRO_PATH_OP_CURVE_TO: - if (has_current) { - status = (*cb->add_spline) (closure, ¤t, &point[0], &point[1], &point[2]); - if (status) - return status; - current = point[2]; - has_edge = 1; - } else { - first = point[2]; - current = point[2]; - has_current = 1; - has_edge = 0; - } + status = (*curve_to) (closure, &point[0], &point[1], &point[2]); break; case CAIRO_PATH_OP_CLOSE_PATH: - if (has_edge) { - (*cb->add_edge) (closure, ¤t, &first); - (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_JOIN); - } - current.x = 0; - current.y = 0; - first.x = 0; - first.y = 0; - has_current = 0; - has_edge = 0; + default: + status = (*close_path) (closure); break; } + if (status) + return status; } } - if (has_edge) - (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_CAP); - return (*cb->done_path) (closure); + return CAIRO_STATUS_SUCCESS; } diff --git a/src/cairo_path_bounds.c b/src/cairo_path_bounds.c index 40b64c3d6..6a02b9ac0 100644 --- a/src/cairo_path_bounds.c +++ b/src/cairo_path_bounds.c @@ -46,18 +46,19 @@ static cairo_status_t _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point); static cairo_status_t -_cairo_path_bounder_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2); +_cairo_path_bounder_move_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_path_bounder_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d); +_cairo_path_bounder_line_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done_t done); +_cairo_path_bounder_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d); static cairo_status_t -_cairo_path_bounder_done_path (void *closure); +_cairo_path_bounder_close_path (void *closure); static void _cairo_path_bounder_init (cairo_path_bounder_t *bounder) @@ -99,39 +100,42 @@ _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *poi } static cairo_status_t -_cairo_path_bounder_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2) +_cairo_path_bounder_move_to (void *closure, cairo_point_t *point) { cairo_path_bounder_t *bounder = closure; - _cairo_path_bounder_add_point (bounder, p1); - _cairo_path_bounder_add_point (bounder, p2); + _cairo_path_bounder_add_point (bounder, point); return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_path_bounder_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d) +_cairo_path_bounder_line_to (void *closure, cairo_point_t *point) { cairo_path_bounder_t *bounder = closure; - _cairo_path_bounder_add_point (bounder, a); - _cairo_path_bounder_add_point (bounder, b); - _cairo_path_bounder_add_point (bounder, c); - _cairo_path_bounder_add_point (bounder, d); + _cairo_path_bounder_add_point (bounder, point); return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done_t done) +_cairo_path_bounder_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d) { + cairo_path_bounder_t *bounder = closure; + + _cairo_path_bounder_add_point (bounder, b); + _cairo_path_bounder_add_point (bounder, c); + _cairo_path_bounder_add_point (bounder, d); + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_path_bounder_done_path (void *closure) +_cairo_path_bounder_close_path (void *closure) { return CAIRO_STATUS_SUCCESS; } @@ -141,18 +145,17 @@ cairo_status_t _cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2) { cairo_status_t status; - static cairo_path_callbacks_t const cb = { - _cairo_path_bounder_add_edge, - _cairo_path_bounder_add_spline, - _cairo_path_bounder_done_sub_path, - _cairo_path_bounder_done_path - }; cairo_path_bounder_t bounder; _cairo_path_bounder_init (&bounder); - status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD, &cb, &bounder); + status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD, + _cairo_path_bounder_move_to, + _cairo_path_bounder_line_to, + _cairo_path_bounder_curve_to, + _cairo_path_bounder_close_path, + &bounder); if (status) { *x1 = *y1 = *x2 = *y2 = 0.0; _cairo_path_bounder_fini (&bounder); diff --git a/src/cairo_path_fill.c b/src/cairo_path_fill.c index 8f34af854..fba5bb090 100644 --- a/src/cairo_path_fill.c +++ b/src/cairo_path_fill.c @@ -31,6 +31,8 @@ typedef struct cairo_filler { cairo_gstate_t *gstate; cairo_traps_t *traps; + cairo_point_t current_point; + cairo_polygon_t polygon; } cairo_filler_t; @@ -41,18 +43,19 @@ static void _cairo_filler_fini (cairo_filler_t *filler); static cairo_status_t -_cairo_filler_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2); +_cairo_filler_move_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_filler_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d); +_cairo_filler_line_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done_t done); +_cairo_filler_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d); static cairo_status_t -_cairo_filler_done_path (void *closure); +_cairo_filler_close_path (void *closure); static void _cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps) @@ -60,6 +63,9 @@ _cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_ filler->gstate = gstate; filler->traps = traps; + filler->current_point.x = 0; + filler->current_point.y = 0; + _cairo_polygon_init (&filler->polygon); } @@ -70,18 +76,46 @@ _cairo_filler_fini (cairo_filler_t *filler) } static cairo_status_t -_cairo_filler_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2) +_cairo_filler_move_to (void *closure, cairo_point_t *point) { + cairo_status_t status; cairo_filler_t *filler = closure; cairo_polygon_t *polygon = &filler->polygon; - return _cairo_polygon_add_edge (polygon, p1, p2); + status = _cairo_polygon_close (polygon); + if (status) + return status; + + status = _cairo_polygon_move_to (polygon, point); + if (status) + return status; + + filler->current_point = *point; + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_filler_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d) +_cairo_filler_line_to (void *closure, cairo_point_t *point) +{ + cairo_status_t status; + cairo_filler_t *filler = closure; + cairo_polygon_t *polygon = &filler->polygon; + + status = _cairo_polygon_line_to (polygon, point); + if (status) + return status; + + filler->current_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_filler_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d) { int i; cairo_status_t status = CAIRO_STATUS_SUCCESS; @@ -90,7 +124,8 @@ _cairo_filler_add_spline (void *closure, cairo_gstate_t *gstate = filler->gstate; cairo_spline_t spline; - status = _cairo_spline_init (&spline, a, b, c, d); + status = _cairo_spline_init (&spline, &filler->current_point, b, c, d); + if (status == CAIRO_INT_STATUS_DEGENERATE) return CAIRO_STATUS_SUCCESS; @@ -98,65 +133,65 @@ _cairo_filler_add_spline (void *closure, if (status) goto CLEANUP_SPLINE; - for (i = 0; i < spline.num_points - 1; i++) { - status = _cairo_polygon_add_edge (polygon, &spline.points[i], &spline.points[i+1]); + for (i = 1; i < spline.num_points; i++) { + status = _cairo_polygon_line_to (polygon, &spline.points[i]); if (status) - goto CLEANUP_SPLINE; + break; } CLEANUP_SPLINE: _cairo_spline_fini (&spline); + filler->current_point = *d; + return status; } static cairo_status_t -_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done_t done) +_cairo_filler_close_path (void *closure) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_status_t status; cairo_filler_t *filler = closure; cairo_polygon_t *polygon = &filler->polygon; - _cairo_polygon_close (polygon); - - return status; -} - -static cairo_status_t -_cairo_filler_done_path (void *closure) -{ - cairo_filler_t *filler = closure; + status = _cairo_polygon_close (polygon); + if (status) + return status; - return _cairo_traps_tessellate_polygon (filler->traps, - &filler->polygon, - filler->gstate->fill_rule); + return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps) { - static const cairo_path_callbacks_t filler_callbacks = { - _cairo_filler_add_edge, - _cairo_filler_add_spline, - _cairo_filler_done_sub_path, - _cairo_filler_done_path - }; - - cairo_status_t status; + cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_filler_t filler; _cairo_filler_init (&filler, gstate, traps); status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD, - &filler_callbacks, &filler); - if (status) { - _cairo_filler_fini (&filler); - return status; - } + _cairo_filler_move_to, + _cairo_filler_line_to, + _cairo_filler_curve_to, + _cairo_filler_close_path, + &filler); + if (status) + goto BAIL; + status = _cairo_polygon_close (&filler.polygon); + if (status) + goto BAIL; + + status = _cairo_traps_tessellate_polygon (filler.traps, + &filler.polygon, + filler.gstate->fill_rule); + if (status) + goto BAIL; + +BAIL: _cairo_filler_fini (&filler); - return CAIRO_STATUS_SUCCESS; + return status; } diff --git a/src/cairo_path_stroke.c b/src/cairo_path_stroke.c index 35e7b1b70..c2412579a 100644 --- a/src/cairo_path_stroke.c +++ b/src/cairo_path_stroke.c @@ -31,11 +31,17 @@ typedef struct cairo_stroker { cairo_gstate_t *gstate; cairo_traps_t *traps; - int have_prev; - int have_first; - int is_first; - cairo_stroke_face_t prev; - cairo_stroke_face_t first; + int has_current_point; + cairo_point_t current_point; + cairo_point_t first_point; + + int has_current_face; + cairo_stroke_face_t current_face; + + int has_first_face; + cairo_stroke_face_t first_face; + + int dashed; int dash_index; int dash_on; double dash_remain; @@ -49,21 +55,22 @@ static void _cairo_stroker_fini (cairo_stroker_t *stroker); static cairo_status_t -_cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2); +_cairo_stroker_move_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t *p2); +_cairo_stroker_line_to (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_stroker_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d); +_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point); static cairo_status_t -_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done_t done); +_cairo_stroker_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d); static cairo_status_t -_cairo_stroker_done_path (void *closure); +_cairo_stroker_close_path (void *closure); static void _translate_point (cairo_point_t *point, cairo_point_t *offset); @@ -89,6 +96,7 @@ _cairo_stroker_start_dash (cairo_stroker_t *stroker) if (++i == gstate->num_dashes) i = 0; } + stroker->dashed = 1; stroker->dash_index = i; stroker->dash_on = on; stroker->dash_remain = gstate->dash[i] - offset; @@ -113,11 +121,15 @@ _cairo_stroker_init (cairo_stroker_t *stroker, cairo_gstate_t *gstate, cairo_tra { stroker->gstate = gstate; stroker->traps = traps; - stroker->have_prev = 0; - stroker->have_first = 0; - stroker->is_first = 1; + + stroker->has_current_point = 0; + stroker->has_current_face = 0; + stroker->has_first_face = 0; + if (gstate->dash) _cairo_stroker_start_dash (stroker); + else + stroker->dashed = 0; } static void @@ -286,10 +298,11 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st outer.x = _cairo_fixed_from_double (mx); outer.y = _cairo_fixed_from_double (my); _cairo_polygon_init (&polygon); - _cairo_polygon_add_edge (&polygon, &in->point, inpt); - _cairo_polygon_add_edge (&polygon, inpt, &outer); - _cairo_polygon_add_edge (&polygon, &outer, outpt); - _cairo_polygon_add_edge (&polygon, outpt, &in->point); + _cairo_polygon_move_to (&polygon, &in->point); + _cairo_polygon_line_to (&polygon, inpt); + _cairo_polygon_line_to (&polygon, &outer); + _cairo_polygon_line_to (&polygon, outpt); + _cairo_polygon_close (&polygon); status = _cairo_traps_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING); @@ -351,8 +364,6 @@ _cairo_stroker_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f) cairo_point_t occw, ocw; cairo_polygon_t polygon; - _cairo_polygon_init (&polygon); - dx = f->usr_vector.x; dy = f->usr_vector.y; dx *= gstate->line_width / 2.0; @@ -365,10 +376,12 @@ _cairo_stroker_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f) ocw.x = f->cw.x + fvector.dx; ocw.y = f->cw.y + fvector.dy; - _cairo_polygon_add_edge (&polygon, &f->cw, &ocw); - _cairo_polygon_add_edge (&polygon, &ocw, &occw); - _cairo_polygon_add_edge (&polygon, &occw, &f->ccw); - _cairo_polygon_add_edge (&polygon, &f->ccw, &f->cw); + _cairo_polygon_init (&polygon); + _cairo_polygon_move_to (&polygon, &f->cw); + _cairo_polygon_line_to (&polygon, &ocw); + _cairo_polygon_line_to (&polygon, &occw); + _cairo_polygon_line_to (&polygon, &f->ccw); + _cairo_polygon_close (&polygon); status = _cairo_traps_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING); _cairo_polygon_fini (&polygon); @@ -454,8 +467,9 @@ static cairo_status_t _cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, cairo_point_t *p1, cairo_point_t *p2, cairo_stroke_face_t *start, cairo_stroke_face_t *end) { + cairo_status_t status; cairo_gstate_t *gstate = stroker->gstate; - cairo_point_t quad[4]; + cairo_polygon_t polygon; cairo_slope_t slope; if (p1->x == p2->x && p1->y == p2->y) { @@ -473,20 +487,58 @@ _cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, cairo_point_t *p1, cairo_ fields from start. */ _compute_face (p2, &slope, gstate, end); - quad[0] = start->cw; - quad[1] = start->ccw; - quad[2] = end->ccw; - quad[3] = end->cw; + /* XXX: I should really check the return value of the + move_to/line_to functions here to catch out of memory + conditions. But since that would be ugly, I'd prefer to add a + status flag to the polygon object that I could check only once + at then end of this sequence, (like we do with cairo_t + already). */ + _cairo_polygon_init (&polygon); + _cairo_polygon_move_to (&polygon, &start->cw); + _cairo_polygon_line_to (&polygon, &start->ccw); + _cairo_polygon_line_to (&polygon, &end->ccw); + _cairo_polygon_line_to (&polygon, &end->cw); + _cairo_polygon_close (&polygon); + + /* XXX: We can't use tessellate_rectangle as the matrix may have + skewed this into a non-rectangular shape. Perhaps it would be + worth checking the matrix for skew so that the common case + could use the faster tessellate_rectangle rather than + tessellate_polygon? */ + status = _cairo_traps_tessellate_polygon (stroker->traps, + &polygon, CAIRO_FILL_RULE_WINDING); + + _cairo_polygon_fini (&polygon); - return _cairo_traps_tessellate_rectangle (stroker->traps, quad); + return status; } static cairo_status_t -_cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2) +_cairo_stroker_move_to (void *closure, cairo_point_t *point) +{ + cairo_stroker_t *stroker = closure; + + stroker->first_point = *point; + stroker->current_point = *point; + stroker->has_current_point = 1; + + stroker->has_first_face = 0; + stroker->has_current_face = 0; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_stroker_line_to (void *closure, cairo_point_t *point) { cairo_status_t status; cairo_stroker_t *stroker = closure; cairo_stroke_face_t start, end; + cairo_point_t *p1 = &stroker->current_point; + cairo_point_t *p2 = point; + + if (!stroker->has_current_point) + return _cairo_stroker_move_to (stroker, point); if (p1->x == p2->x && p1->y == p2->y) { /* XXX: Need to rethink how this case should be handled, (both @@ -500,19 +552,20 @@ _cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2) if (status) return status; - if (stroker->have_prev) { - status = _cairo_stroker_join (stroker, &stroker->prev, &start); + if (stroker->has_current_face) { + status = _cairo_stroker_join (stroker, &stroker->current_face, &start); if (status) return status; } else { - stroker->have_prev = 1; - if (stroker->is_first) { - stroker->have_first = 1; - stroker->first = start; + if (!stroker->has_first_face) { + stroker->first_face = start; + stroker->has_first_face = 1; } } - stroker->prev = end; - stroker->is_first = 0; + stroker->current_face = end; + stroker->has_current_face = 1; + + stroker->current_point = *point; return CAIRO_STATUS_SUCCESS; } @@ -521,7 +574,7 @@ _cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2) * Dashed lines. Cap each dash end, join around turns when on */ static cairo_status_t -_cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t *p2) +_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t *stroker = closure; @@ -532,6 +585,11 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t cairo_point_t fd1, fd2; int first = 1; cairo_stroke_face_t sub_start, sub_end; + cairo_point_t *p1 = &stroker->current_point; + cairo_point_t *p2 = point; + + if (!stroker->has_current_point) + return _cairo_stroker_move_to (stroker, point); dx = _cairo_fixed_to_double (p2->x - p1->x); dy = _cairo_fixed_to_double (p2->y - p1->y); @@ -569,18 +627,18 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t return status; } else { /* - * First in this segment, join to any prev, else + * First in this segment, join to any current_face, else * if at start of sub-path, mark position, else * cap */ - if (stroker->have_prev) { - status = _cairo_stroker_join (stroker, &stroker->prev, &sub_start); + if (stroker->has_current_face) { + status = _cairo_stroker_join (stroker, &stroker->current_face, &sub_start); if (status) return status; } else { - if (stroker->is_first) { - stroker->have_first = 1; - stroker->first = sub_start; + if (!stroker->has_first_face) { + stroker->first_face = sub_start; + stroker->has_first_face = 1; } else { status = _cairo_stroker_cap (stroker, &sub_start); if (status) @@ -600,8 +658,8 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t * Mark previous line face and fix up next time * through */ - stroker->prev = sub_end; - stroker->have_prev = 1; + stroker->current_face = sub_end; + stroker->has_current_face = 1; } } else { /* @@ -609,27 +667,30 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t * and cap if necessary */ if (first) { - if (stroker->have_prev) { - status = _cairo_stroker_cap (stroker, &stroker->prev); + if (stroker->has_current_face) { + status = _cairo_stroker_cap (stroker, &stroker->current_face); if (status) return status; } } if (!remain) - stroker->have_prev = 0; + stroker->has_current_face = 0; } _cairo_stroker_step_dash (stroker, tmp); fd1 = fd2; first = 0; } - stroker->is_first = 0; + + stroker->current_point = *point; + return status; } static cairo_status_t -_cairo_stroker_add_spline (void *closure, - cairo_point_t *a, cairo_point_t *b, - cairo_point_t *c, cairo_point_t *d) +_cairo_stroker_curve_to (void *closure, + cairo_point_t *b, + cairo_point_t *c, + cairo_point_t *d) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t *stroker = closure; @@ -638,6 +699,7 @@ _cairo_stroker_add_spline (void *closure, cairo_pen_t pen; cairo_stroke_face_t start, end; cairo_point_t extra_points[4]; + cairo_point_t *a = &stroker->current_point; status = _cairo_spline_init (&spline, a, b, c, d); if (status == CAIRO_INT_STATUS_DEGENERATE) @@ -650,19 +712,18 @@ _cairo_stroker_add_spline (void *closure, _compute_face (a, &spline.initial_slope, gstate, &start); _compute_face (d, &spline.final_slope, gstate, &end); - if (stroker->have_prev) { - status = _cairo_stroker_join (stroker, &stroker->prev, &start); + if (stroker->has_current_face) { + status = _cairo_stroker_join (stroker, &stroker->current_face, &start); if (status) return status; } else { - stroker->have_prev = 1; - if (stroker->is_first) { - stroker->have_first = 1; - stroker->first = start; + if (!stroker->has_first_face) { + stroker->first_face = start; + stroker->has_first_face = 1; } } - stroker->prev = end; - stroker->is_first = 0; + stroker->current_face = end; + stroker->has_current_face = 1; extra_points[0] = start.cw; extra_points[0].x -= start.point.x; @@ -690,91 +751,89 @@ _cairo_stroker_add_spline (void *closure, CLEANUP_SPLINE: _cairo_spline_fini (&spline); + stroker->current_point = *d; + return status; } static cairo_status_t -_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done_t done) +_cairo_stroker_close_path (void *closure) { cairo_status_t status; cairo_stroker_t *stroker = closure; - switch (done) { - case CAIRO_SUB_PATH_DONE_JOIN: - if (stroker->have_first && stroker->have_prev) { - status = _cairo_stroker_join (stroker, &stroker->prev, &stroker->first); - if (status) - return status; - break; - } - /* fall through... */ - case CAIRO_SUB_PATH_DONE_CAP: - if (stroker->have_first) { - cairo_point_t t; - /* The initial cap needs an outward facing vector. Reverse everything */ - stroker->first.usr_vector.x = -stroker->first.usr_vector.x; - stroker->first.usr_vector.y = -stroker->first.usr_vector.y; - stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx; - stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy; - t = stroker->first.cw; - stroker->first.cw = stroker->first.ccw; - stroker->first.ccw = t; - status = _cairo_stroker_cap (stroker, &stroker->first); - if (status) - return status; - } - if (stroker->have_prev) { - status = _cairo_stroker_cap (stroker, &stroker->prev); - if (status) - return status; - } - break; + if (stroker->has_current_point) { + if (stroker->dashed) + status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point); + else + status = _cairo_stroker_line_to (stroker, &stroker->first_point); + if (status) + return status; } - stroker->have_prev = 0; - stroker->have_first = 0; - stroker->is_first = 1; + if (stroker->has_first_face && stroker->has_current_face) { + status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face); + if (status) + return status; + } - return CAIRO_STATUS_SUCCESS; -} + stroker->has_first_face = 0; + stroker->has_current_face = 0; + stroker->has_current_point = 0; -static cairo_status_t -_cairo_stroker_done_path (void *closure) -{ return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps) { - static const cairo_path_callbacks_t stroker_solid_cb = { - _cairo_stroker_add_edge, - _cairo_stroker_add_spline, - _cairo_stroker_done_sub_path, - _cairo_stroker_done_path - }; - static const cairo_path_callbacks_t stroker_dashed_cb = { - _cairo_stroker_add_edge_dashed, - _cairo_stroker_add_spline, - _cairo_stroker_done_sub_path, - _cairo_stroker_done_path - }; - const cairo_path_callbacks_t *callbacks = gstate->dash ? &stroker_dashed_cb : &stroker_solid_cb; - - cairo_status_t status; + cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t stroker; _cairo_stroker_init (&stroker, gstate, traps); - status = _cairo_path_interpret (path, - CAIRO_DIRECTION_FORWARD, - callbacks, &stroker); - if (status) { - _cairo_stroker_fini (&stroker); - return status; + if (gstate->dash) + status = _cairo_path_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cairo_stroker_move_to, + _cairo_stroker_line_to_dashed, + _cairo_stroker_curve_to, + _cairo_stroker_close_path, + &stroker); + else + status = _cairo_path_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cairo_stroker_move_to, + _cairo_stroker_line_to, + _cairo_stroker_curve_to, + _cairo_stroker_close_path, + &stroker); + if (status) + goto BAIL; + + if (stroker.has_first_face) { + cairo_point_t t; + /* The initial cap needs an outward facing vector. Reverse everything */ + stroker.first_face.usr_vector.x = -stroker.first_face.usr_vector.x; + stroker.first_face.usr_vector.y = -stroker.first_face.usr_vector.y; + stroker.first_face.dev_vector.dx = -stroker.first_face.dev_vector.dx; + stroker.first_face.dev_vector.dy = -stroker.first_face.dev_vector.dy; + t = stroker.first_face.cw; + stroker.first_face.cw = stroker.first_face.ccw; + stroker.first_face.ccw = t; + status = _cairo_stroker_cap (&stroker, &stroker.first_face); + if (status) + goto BAIL; } + if (stroker.has_current_face) { + status = _cairo_stroker_cap (&stroker, &stroker.current_face); + if (status) + goto BAIL; + } + +BAIL: _cairo_stroker_fini (&stroker); - return CAIRO_STATUS_SUCCESS; + return status; } diff --git a/src/cairo_pattern.c b/src/cairo_pattern.c new file mode 100644 index 000000000..dcdb1566a --- /dev/null +++ b/src/cairo_pattern.c @@ -0,0 +1,716 @@ +/* + * Copyright © 2002 University of Southern California + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <c99drn@cs.umu.se> + */ + +#include "cairoint.h" + +void +_cairo_pattern_init (cairo_pattern_t *pattern) +{ + pattern->ref_count = 1; + + pattern->extend = CAIRO_EXTEND_DEFAULT; + pattern->filter = CAIRO_FILTER_DEFAULT; + + _cairo_color_init (&pattern->color); + + _cairo_matrix_init (&pattern->matrix); + + pattern->stops = NULL; + pattern->n_stops = 0; + + pattern->type = CAIRO_PATTERN_SOLID; + + pattern->source = NULL; + pattern->source_offset.x = 0.0; + pattern->source_offset.y = 0.0; +} + +cairo_status_t +_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other) +{ + *pattern = *other; + + pattern->ref_count = 1; + + if (pattern->n_stops) { + pattern->stops = + malloc (sizeof (cairo_color_stop_t) * pattern->n_stops); + if (pattern->stops == NULL) + return CAIRO_STATUS_NO_MEMORY; + memcpy (pattern->stops, other->stops, + sizeof (cairo_color_stop_t) * other->n_stops); + } + + if (pattern->source) + cairo_surface_reference (other->source); + + if (pattern->type == CAIRO_PATTERN_SURFACE) + cairo_surface_reference (other->u.surface.surface); + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_pattern_fini (cairo_pattern_t *pattern) +{ + if (pattern->n_stops) + free (pattern->stops); + + if (pattern->type == CAIRO_PATTERN_SURFACE) { + /* show_surface require us to restore surface matrix, repeat + attribute, filter type */ + if (pattern->source) { + cairo_surface_set_matrix (pattern->source, + &pattern->u.surface.save_matrix); + cairo_surface_set_repeat (pattern->source, + pattern->u.surface.save_repeat); + cairo_surface_set_filter (pattern->source, + pattern->u.surface.save_filter); + } + cairo_surface_destroy (pattern->u.surface.surface); + } + + if (pattern->source) + cairo_surface_destroy (pattern->source); +} + +void +_cairo_pattern_init_solid (cairo_pattern_t *pattern, + double red, double green, double blue) +{ + _cairo_pattern_init (pattern); + + pattern->type = CAIRO_PATTERN_SOLID; + _cairo_color_set_rgb (&pattern->color, red, green, blue); +} + +cairo_pattern_t * +_cairo_pattern_create_solid (double red, double green, double blue) +{ + cairo_pattern_t *pattern; + + pattern = malloc (sizeof (cairo_pattern_t)); + if (pattern == NULL) + return NULL; + + _cairo_pattern_init_solid (pattern, red, green, blue); + + return pattern; +} + +cairo_pattern_t * +cairo_pattern_create_for_surface (cairo_surface_t *surface) +{ + cairo_pattern_t *pattern; + + pattern = malloc (sizeof (cairo_pattern_t)); + if (pattern == NULL) + return NULL; + + _cairo_pattern_init (pattern); + + pattern->type = CAIRO_PATTERN_SURFACE; + pattern->u.surface.surface = surface; + cairo_surface_reference (surface); + + return pattern; +} + +cairo_pattern_t * +cairo_pattern_create_linear (double x0, double y0, double x1, double y1) +{ + cairo_pattern_t *pattern; + + pattern = malloc (sizeof (cairo_pattern_t)); + if (pattern == NULL) + return NULL; + + _cairo_pattern_init (pattern); + + pattern->type = CAIRO_PATTERN_LINEAR; + pattern->u.linear.point0.x = x0; + pattern->u.linear.point0.y = y0; + pattern->u.linear.point1.x = x1; + pattern->u.linear.point1.y = y1; + + return pattern; +} + +cairo_pattern_t * +cairo_pattern_create_radial (double cx0, double cy0, double radius0, + double cx1, double cy1, double radius1) +{ + cairo_pattern_t *pattern; + + pattern = malloc (sizeof (cairo_pattern_t)); + if (pattern == NULL) + return NULL; + + _cairo_pattern_init (pattern); + + pattern->type = CAIRO_PATTERN_RADIAL; + pattern->u.radial.center0.x = cx0; + pattern->u.radial.center0.y = cy0; + pattern->u.radial.radius0.dx = radius0; + pattern->u.radial.radius0.dy = radius0; + pattern->u.radial.center1.x = cx1; + pattern->u.radial.center1.y = cy1; + pattern->u.radial.radius1.dx = radius1; + pattern->u.radial.radius1.dy = radius1; + + return pattern; +} + +void +cairo_pattern_reference (cairo_pattern_t *pattern) +{ + if (pattern == NULL) + return; + + pattern->ref_count++; +} + +void +cairo_pattern_destroy (cairo_pattern_t *pattern) +{ + if (pattern == NULL) + return; + + pattern->ref_count--; + if (pattern->ref_count) + return; + + _cairo_pattern_fini (pattern); + free (pattern); +} + +static int +_cairo_pattern_stop_compare (const void *elem1, const void *elem2) +{ + return + (((cairo_color_stop_t *) elem1)->offset == + ((cairo_color_stop_t *) elem2)->offset) ? + /* equal offsets, sort on id */ + ((((cairo_color_stop_t *) elem1)->id < + ((cairo_color_stop_t *) elem2)->id) ? -1 : 1) : + /* sort on offset */ + ((((cairo_color_stop_t *) elem1)->offset < + ((cairo_color_stop_t *) elem2)->offset) ? -1 : 1); +} + +cairo_status_t +cairo_pattern_add_color_stop (cairo_pattern_t *pattern, + double offset, + double red, double green, double blue, + double alpha) +{ + cairo_color_stop_t *stop; + + _cairo_restrict_value (&offset, 0.0, 1.0); + _cairo_restrict_value (&red, 0.0, 1.0); + _cairo_restrict_value (&green, 0.0, 1.0); + _cairo_restrict_value (&blue, 0.0, 1.0); + + pattern->n_stops++; + pattern->stops = realloc (pattern->stops, + sizeof (cairo_color_stop_t) * pattern->n_stops); + if (pattern->stops == NULL) { + pattern->n_stops = 0; + + return CAIRO_STATUS_NO_MEMORY; + } + + stop = &pattern->stops[pattern->n_stops - 1]; + + stop->offset = offset; + stop->id = pattern->n_stops; + _cairo_color_init (&stop->color); + _cairo_color_set_rgb (&stop->color, red, green, blue); + _cairo_color_set_alpha (&stop->color, alpha); + stop->color_char[0] = stop->color.red_short / 256; + stop->color_char[1] = stop->color.green_short / 256; + stop->color_char[2] = stop->color.blue_short / 256; + stop->color_char[3] = stop->color.alpha_short / 256; + + /* sort stops in ascending order */ + qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t), + _cairo_pattern_stop_compare); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) +{ + cairo_matrix_copy (&pattern->matrix, matrix); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) +{ + cairo_matrix_copy (matrix, &pattern->matrix); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) +{ + pattern->filter = filter; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_filter_t +cairo_pattern_get_filter (cairo_pattern_t *pattern) +{ + return pattern->filter; +} + +cairo_status_t +cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend) +{ + pattern->extend = extend; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_extend_t +cairo_pattern_get_extend (cairo_pattern_t *pattern) +{ + return pattern->extend; +} + +cairo_status_t +_cairo_pattern_get_rgb (cairo_pattern_t *pattern, + double *red, double *green, double *blue) +{ + _cairo_color_get_rgb (&pattern->color, red, green, blue); + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha) +{ + int i; + + _cairo_color_set_alpha (&pattern->color, alpha); + + for (i = 0; i < pattern->n_stops; i++) { + cairo_color_stop_t *stop = &pattern->stops[i]; + + _cairo_color_set_alpha (&stop->color, stop->color.alpha * alpha); + + stop->color_char[0] = stop->color.red_short / 256; + stop->color_char[1] = stop->color.green_short / 256; + stop->color_char[2] = stop->color.blue_short / 256; + stop->color_char[3] = stop->color.alpha_short / 256; + } +} + +void +_cairo_pattern_add_source_offset (cairo_pattern_t *pattern, + double x, double y) +{ + pattern->source_offset.x += x; + pattern->source_offset.y += y; +} + +void +_cairo_pattern_transform (cairo_pattern_t *pattern, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse) +{ + cairo_matrix_t matrix; + + switch (pattern->type) { + case CAIRO_PATTERN_SURFACE: + /* hmm, maybe we should instead multiply with the inverse of the + pattern matrix here? */ + cairo_matrix_multiply (&pattern->matrix, ctm_inverse, + &pattern->matrix); + break; + case CAIRO_PATTERN_LINEAR: + cairo_matrix_multiply (&matrix, &pattern->matrix, ctm); + cairo_matrix_transform_point (&matrix, + &pattern->u.linear.point0.x, + &pattern->u.linear.point0.y); + cairo_matrix_transform_point (&matrix, + &pattern->u.linear.point1.x, + &pattern->u.linear.point1.y); + break; + case CAIRO_PATTERN_RADIAL: + cairo_matrix_multiply (&matrix, &pattern->matrix, ctm); + cairo_matrix_transform_point (&matrix, + &pattern->u.radial.center0.x, + &pattern->u.radial.center0.y); + cairo_matrix_transform_distance (&matrix, + &pattern->u.radial.radius0.dx, + &pattern->u.radial.radius0.dy); + cairo_matrix_transform_point (&matrix, + &pattern->u.radial.center1.x, + &pattern->u.radial.center1.y); + cairo_matrix_transform_distance (&matrix, + &pattern->u.radial.radius1.dx, + &pattern->u.radial.radius1.dy); + break; + case CAIRO_PATTERN_SOLID: + break; + } +} + +void +_cairo_pattern_prepare_surface (cairo_pattern_t *pattern) +{ + cairo_matrix_t device_to_source; + cairo_matrix_t user_to_source; + + /* should the surface matrix interface be remove from the API? + for now we multiple the surface matrix with the pattern matrix */ + cairo_surface_get_matrix (pattern->u.surface.surface, &user_to_source); + cairo_matrix_multiply (&device_to_source, &pattern->matrix, + &user_to_source); + cairo_surface_set_matrix (pattern->source, &device_to_source); + + /* storing original surface matrix in pattern */ + pattern->u.surface.save_matrix = user_to_source; + + /* storing original surface repeat mode in pattern */ + pattern->u.surface.save_repeat = pattern->source->repeat; + + /* what do we do with extend types pad and reflect? */ + if (pattern->extend == CAIRO_EXTEND_REPEAT + || pattern->source->repeat == 1) + cairo_surface_set_repeat (pattern->source, 1); + else + cairo_surface_set_repeat (pattern->source, 0); + + /* storing original surface filter in pattern */ + pattern->u.surface.save_filter = + cairo_surface_get_filter (pattern->source); + + cairo_surface_set_filter (pattern->source, pattern->filter); +} + +typedef void (*cairo_shader_function_t) (unsigned char *color0, + unsigned char *color1, + double factor, + unsigned char *result_color); + +#define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \ + ((unsigned char) ((factor < 0.5)? c1: c2)) + +static void +_cairo_pattern_shader_nearest (unsigned char *color0, + unsigned char *color1, + double factor, + unsigned char *result_color) +{ + result_color[0] = INTERPOLATE_COLOR_NEAREST (color0[0], color1[0], factor); + result_color[1] = INTERPOLATE_COLOR_NEAREST (color0[1], color1[1], factor); + result_color[2] = INTERPOLATE_COLOR_NEAREST (color0[2], color1[2], factor); + result_color[3] = INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor); +} + +#undef INTERPOLATE_COLOR_NEAREST + +#define INTERPOLATE_COLOR_LINEAR(c1, c2, factor) \ + ((unsigned char) ((c2 * factor) + (c1 * (1.0 - factor)))) + +static void +_cairo_pattern_shader_linear (unsigned char *color0, + unsigned char *color1, + double factor, + unsigned char *result_color) +{ + result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor); + result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor); + result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor); + result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor); +} + +static void +_cairo_pattern_shader_gaussian (unsigned char *color0, + unsigned char *color1, + double factor, + unsigned char *result_color) +{ + factor = (exp (factor * factor) - 1.0) / (M_E - 1.0); + + result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor); + result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor); + result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor); + result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor); +} + +#undef INTERPOLATE_COLOR_LINEAR + +void +_cairo_pattern_calc_color_at_pixel (cairo_pattern_t *pattern, + double factor, + int *pixel) +{ + int p, colorstop; + double factorscale; + unsigned char result_color[4]; + cairo_shader_function_t shader_function; + + switch (pattern->filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + shader_function = _cairo_pattern_shader_nearest; + break; + case CAIRO_FILTER_GAUSSIAN: + shader_function = _cairo_pattern_shader_gaussian; + break; + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + shader_function = _cairo_pattern_shader_linear; + break; + } + + if (factor > 1.0 || factor < 0.0) { + switch (pattern->extend) { + case CAIRO_EXTEND_REPEAT: + factor -= floor (factor); + break; + case CAIRO_EXTEND_REFLECT: + if (factor >= 0.0) { + if (((int) factor) % 2) + factor = 1.0 - (factor - floor (factor)); + else + factor -= floor (factor); + } else { + if (((int) factor) % 2) + factor -= floor (factor); + else + factor = 1.0 - (factor - floor (factor)); + } + break; + case CAIRO_EXTEND_NONE: + break; + } + } + + if (factor < pattern->stops[0].offset) + factor = pattern->stops[0].offset; + + if (factor > pattern->stops[pattern->n_stops - 1].offset) + factor = pattern->stops[pattern->n_stops - 1].offset; + + for (colorstop = 0; colorstop < pattern->n_stops - 1; colorstop++) { + if (factor <= pattern->stops[colorstop + 1].offset) { + factorscale = fabs (pattern->stops[colorstop].offset - + pattern->stops[colorstop + 1].offset); + + /* abrubt change, difference between two offsets == 0.0 */ + if (factorscale == 0) + break; + + factor -= pattern->stops[colorstop].offset; + + /* take offset as new 0 of coordinate system */ + factor /= factorscale; + + shader_function (pattern->stops[colorstop].color_char, + pattern->stops[colorstop + 1].color_char, + factor, result_color); + + p = ((result_color[3] << 24) | + (result_color[0] << 16) | + (result_color[1] << 8) | (result_color[2] << 0)); + *pixel = p; + break; + } + } +} + +static void +_cairo_image_data_set_linear (cairo_pattern_t *pattern, + double offset_x, + double offset_y, + char *data, + int width, + int height) +{ + int x, y; + cairo_point_double_t point0, point1, angle; + double a, length, start, end; + double factor; + + point0.x = pattern->u.linear.point0.x - offset_x; + point0.y = pattern->u.linear.point0.y - offset_y; + point1.x = pattern->u.linear.point1.x - offset_x; + point1.y = pattern->u.linear.point1.y - offset_y; + + length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) + + (point1.y - point0.y) * (point1.y - point0.y)); + length = (length) ? 1.0 / length : INT_MAX; + + a = -atan2 (point1.y - point0.y, point1.x - point0.x); + angle.x = cos (a); + angle.y = -sin (a); + + start = angle.x * point0.x; + start += angle.y * point0.y; + + end = angle.x * point1.x; + end += angle.y * point1.y; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + + factor = angle.x * (double) x; + factor += angle.y * (double) y; + + factor = factor - start; + factor *= length; + + _cairo_pattern_calc_color_at_pixel (pattern, factor, (int *) + &data[y * width * 4 + x * 4]); + } + } +} + +/* TODO: Inner circle is currently ignored. */ +static void +_cairo_image_data_set_radial (cairo_pattern_t *pattern, + double offset_x, + double offset_y, + char *data, + int width, + int height) +{ + int x, y; + cairo_point_double_t center1, pos; + cairo_distance_double_t length; + double factor; + double min_length; + + center1.x = pattern->u.radial.center1.x - offset_x; + center1.y = pattern->u.radial.center1.y - offset_y; + + min_length = + fabs ((pattern->u.radial.radius1.dx < pattern->u.radial.radius1.dy) ? + pattern->u.radial.radius1.dx : pattern->u.radial.radius1.dy); + + /* ugly */ + if (min_length == 0.0) + min_length = 0.000001; + + length.dx = min_length / pattern->u.radial.radius1.dx; + length.dy = min_length / pattern->u.radial.radius1.dy; + + min_length = 1.0 / min_length; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + pos.x = x - center1.x; + pos.y = y - center1.y; + + pos.x *= length.dx; + pos.y *= length.dy; + + factor = sqrt (pos.x * pos.x + pos.y * pos.y) * min_length; + + _cairo_pattern_calc_color_at_pixel (pattern, factor, (int *) + &data[y * width * 4 + x * 4]); + } + } +} + +cairo_image_surface_t * +_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box) +{ + cairo_surface_t *surface; + + switch (pattern->type) { + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + char *data; + int width = ceil (_cairo_fixed_to_double (box->p2.x) - + _cairo_fixed_to_double (box->p1.x)); + int height = ceil (_cairo_fixed_to_double (box->p2.y) - + _cairo_fixed_to_double (box->p1.y)); + + data = malloc (width * height * 4); + if (!data) + return NULL; + + _cairo_pattern_add_source_offset (pattern, + _cairo_fixed_to_double (box->p1.x), + _cairo_fixed_to_double (box->p1.y)); + + if (pattern->type == CAIRO_PATTERN_RADIAL) + _cairo_image_data_set_radial (pattern, + pattern->source_offset.x, + pattern->source_offset.y, + data, width, height); + else + _cairo_image_data_set_linear (pattern, + pattern->source_offset.x, + pattern->source_offset.y, + data, width, height); + + surface = cairo_image_surface_create_for_data (data, + CAIRO_FORMAT_ARGB32, + width, height, + width * 4); + + if (surface) + _cairo_image_surface_assume_ownership_of_data ( + (cairo_image_surface_t *) surface); + } + break; + case CAIRO_PATTERN_SOLID: + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + if (surface) { + _cairo_surface_fill_rectangle (surface, + CAIRO_OPERATOR_SRC, + &pattern->color, 0, 0, 1, 1); + cairo_surface_set_repeat (surface, 1); + } + break; + case CAIRO_PATTERN_SURFACE: { + cairo_image_surface_t *image; + + image = _cairo_surface_get_image (pattern->u.surface.surface); + if (image) + surface = &image->base; + else + surface = NULL; + + } + break; + } + + return (cairo_image_surface_t *) surface; +} diff --git a/src/cairo_pen.c b/src/cairo_pen.c index dd054372d..0bb5debd9 100644 --- a/src/cairo_pen.c +++ b/src/cairo_pen.c @@ -288,7 +288,7 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen, while (i != stop) { hull_point.x = point[i].x + pen->vertices[active].point.x; hull_point.y = point[i].y + pen->vertices[active].point.y; - status = _cairo_polygon_add_point (polygon, &hull_point); + status = _cairo_polygon_line_to (polygon, &hull_point); if (status) return status; diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c new file mode 100644 index 000000000..ed7bb039e --- /dev/null +++ b/src/cairo_png_surface.c @@ -0,0 +1,333 @@ +#include <png.h> + +#include "cairoint.h" + +static const cairo_surface_backend_t cairo_png_surface_backend; + +void +cairo_set_target_png (cairo_t *cr, + FILE *file, + cairo_format_t format, + int width, + int height) +{ + cairo_surface_t *surface; + + surface = cairo_png_surface_create (file, format, + width, height); + + if (surface == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + cairo_set_target_surface (cr, surface); + + /* cairo_set_target_surface takes a reference, so we must destroy ours */ + cairo_surface_destroy (surface); +} + +typedef struct cairo_png_surface { + cairo_surface_t base; + + /* PNG-specific fields */ + FILE *file; + + png_structp png_w; + png_infop png_i; + + cairo_image_surface_t *image; +} cairo_png_surface_t; + + +static void +_cairo_png_surface_erase (cairo_png_surface_t *surface); + +cairo_surface_t * +cairo_png_surface_create (FILE *file, + cairo_format_t format, + int width, + int height) +{ + cairo_png_surface_t *surface; + time_t now = time (NULL); + png_time png_time; + + if (format == CAIRO_FORMAT_A8 || + format == CAIRO_FORMAT_A1 || + file == NULL) + return NULL; + + surface = malloc (sizeof (cairo_png_surface_t)); + if (surface == NULL) + goto failure; + + _cairo_surface_init (&surface->base, &cairo_png_surface_backend); + surface->png_w = NULL; + surface->png_i = NULL; + + surface->image = (cairo_image_surface_t *) + cairo_image_surface_create (format, width, height); + if (surface->image == NULL) + goto failure; + + _cairo_png_surface_erase (surface); + + surface->file = file; + + surface->png_w = png_create_write_struct (PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + if (surface->png_w == NULL) + goto failure; + surface->png_i = png_create_info_struct (surface->png_w); + if (surface->png_i == NULL) + goto failure; + + if (setjmp (png_jmpbuf (surface->png_w))) + goto failure; + + png_init_io (surface->png_w, surface->file); + + switch (format) { + case CAIRO_FORMAT_ARGB32: + png_set_IHDR (surface->png_w, surface->png_i, + width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + break; + case CAIRO_FORMAT_RGB24: + png_set_IHDR (surface->png_w, surface->png_i, + width, height, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + break; + } + + png_convert_from_time_t (&png_time, now); + png_set_tIME (surface->png_w, surface->png_i, &png_time); + + png_write_info (surface->png_w, surface->png_i); + + switch (format) { + case CAIRO_FORMAT_ARGB32: + png_set_bgr (surface->png_w); + break; + case CAIRO_FORMAT_RGB24: + png_set_filler (surface->png_w, 0, PNG_FILLER_AFTER); + png_set_bgr (surface->png_w); + break; + } + + return &surface->base; + + + failure: + if (surface) { + if (surface->image) + cairo_surface_destroy (&surface->image->base); + if (surface->png_i) + png_destroy_write_struct (&surface->png_w, &surface->png_i); + else if (surface->png_w) + png_destroy_write_struct (&surface->png_w, NULL); + free (surface); + } + return NULL; +} + + +static cairo_surface_t * +_cairo_png_surface_create_similar (void *abstract_src, + cairo_format_t format, + int width, + int height) +{ + return NULL; +} + +static void +_cairo_png_surface_destroy (void *abstract_surface) +{ + cairo_png_surface_t *surface = abstract_surface; + int i; + png_byte *row; + + if (setjmp (png_jmpbuf (surface->png_w))) + goto failure; + + row = surface->image->data; + for (i=0; i < surface->image->height; i++) { + png_write_row (surface->png_w, row); + row += surface->image->stride; + } + + png_write_end (surface->png_w, surface->png_i); + + failure: + png_destroy_write_struct (&surface->png_w, &surface->png_i); + + cairo_surface_destroy (&surface->image->base); + + free (surface); +} + +static void +_cairo_png_surface_erase (cairo_png_surface_t *surface) +{ + cairo_color_t transparent; + + _cairo_color_init (&transparent); + _cairo_color_set_rgb (&transparent, 0., 0., 0.); + _cairo_color_set_alpha (&transparent, 0.); + _cairo_surface_fill_rectangle (&surface->image->base, + CAIRO_OPERATOR_SRC, + &transparent, + 0, 0, + surface->image->width, + surface->image->height); +} + +static double +_cairo_png_surface_pixels_per_inch (void *abstract_surface) +{ + return 96.0; +} + +static cairo_image_surface_t * +_cairo_png_surface_get_image (void *abstract_surface) +{ + cairo_png_surface_t *surface = abstract_surface; + + cairo_surface_reference (&surface->image->base); + + return surface->image; +} + +static cairo_status_t +_cairo_png_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_png_surface_t *surface = abstract_surface; + + if (image == surface->image) + return CAIRO_STATUS_SUCCESS; + + /* XXX: Need to call _cairo_image_surface_set_image here, but it's + not implemented yet. */ + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_cairo_png_surface_set_matrix (void *abstract_surface, + cairo_matrix_t *matrix) +{ + cairo_png_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_matrix (surface->image, matrix); +} + +static cairo_status_t +_cairo_png_surface_set_filter (void *abstract_surface, + cairo_filter_t filter) +{ + cairo_png_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_filter (surface->image, filter); +} + +static cairo_status_t +_cairo_png_surface_set_repeat (void *abstract_surface, + int repeat) +{ + cairo_png_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_repeat (surface->image, repeat); +} + +static cairo_int_status_t +_cairo_png_surface_composite (cairo_operator_t operator, + cairo_surface_t *generic_src, + cairo_surface_t *generic_mask, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_png_surface_fill_rectangles (void *abstract_surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_png_surface_composite_trapezoids (cairo_operator_t operator, + cairo_surface_t *generic_src, + void *abstract_dst, + int x_src, + int y_src, + cairo_trapezoid_t *traps, + int num_traps) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_png_surface_copy_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_png_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_png_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + cairo_png_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_clip_region (surface->image, region); +} + +static cairo_int_status_t +_cairo_png_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static const cairo_surface_backend_t cairo_png_surface_backend = { + _cairo_png_surface_create_similar, + _cairo_png_surface_destroy, + _cairo_png_surface_pixels_per_inch, + _cairo_png_surface_get_image, + _cairo_png_surface_set_image, + _cairo_png_surface_set_matrix, + _cairo_png_surface_set_filter, + _cairo_png_surface_set_repeat, + _cairo_png_surface_composite, + _cairo_png_surface_fill_rectangles, + _cairo_png_surface_composite_trapezoids, + _cairo_png_surface_copy_page, + _cairo_png_surface_show_page, + _cairo_png_surface_set_clip_region, + _cairo_png_surface_create_pattern +}; diff --git a/src/cairo_polygon.c b/src/cairo_polygon.c index 97f074a33..fbda73211 100644 --- a/src/cairo_polygon.c +++ b/src/cairo_polygon.c @@ -35,9 +35,6 @@ static cairo_status_t _cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional); -static void -_cairo_polygon_set_last_point (cairo_polygon_t *polygon, cairo_point_t *point); - void _cairo_polygon_init (cairo_polygon_t *polygon) { @@ -46,10 +43,7 @@ _cairo_polygon_init (cairo_polygon_t *polygon) polygon->edges_size = 0; polygon->edges = NULL; - polygon->first_point_defined = 0; - polygon->last_point_defined = 0; - - polygon->closed = 0; + polygon->has_current_point = 0; } void @@ -62,10 +56,7 @@ _cairo_polygon_fini (cairo_polygon_t *polygon) polygon->num_edges = 0; } - polygon->first_point_defined = 0; - polygon->last_point_defined = 0; - - polygon->closed = 0; + polygon->has_current_point = 0; } static cairo_status_t @@ -92,25 +83,12 @@ _cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional) return CAIRO_STATUS_SUCCESS; } -static void -_cairo_polygon_set_last_point (cairo_polygon_t *polygon, cairo_point_t *point) -{ - polygon->last_point = *point; - polygon->last_point_defined = 1; -} - cairo_status_t _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2) { cairo_status_t status; cairo_edge_t *edge; - if (! polygon->first_point_defined) { - polygon->first_point = *p1; - polygon->first_point_defined = 1; - polygon->closed = 0; - } - /* drop horizontal edges */ if (p1->y == p2->y) { goto DONE; @@ -137,20 +115,31 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_poin polygon->num_edges++; DONE: - _cairo_polygon_set_last_point (polygon, p2); + _cairo_polygon_move_to (polygon, p2); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point) +{ + if (! polygon->has_current_point) + polygon->first_point = *point; + polygon->current_point = *point; + polygon->has_current_point = 1; return CAIRO_STATUS_SUCCESS; } cairo_status_t -_cairo_polygon_add_point (cairo_polygon_t *polygon, cairo_point_t *point) +_cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point) { cairo_status_t status = CAIRO_STATUS_SUCCESS; - if (polygon->last_point_defined) { - status = _cairo_polygon_add_edge (polygon, &polygon->last_point, point); + if (polygon->has_current_point) { + status = _cairo_polygon_add_edge (polygon, &polygon->current_point, point); } else { - _cairo_polygon_set_last_point (polygon, point); + _cairo_polygon_move_to (polygon, point); } return status; @@ -161,13 +150,14 @@ _cairo_polygon_close (cairo_polygon_t *polygon) { cairo_status_t status; - if (polygon->closed == 0 && polygon->last_point_defined) { - status = _cairo_polygon_add_edge (polygon, &polygon->last_point, &polygon->first_point); + if (polygon->has_current_point) { + status = _cairo_polygon_add_edge (polygon, + &polygon->current_point, + &polygon->first_point); if (status) return status; - polygon->closed = 1; - polygon->first_point_defined = 0; + polygon->has_current_point = 0; } return CAIRO_STATUS_SUCCESS; diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c index c66b70987..98d34e44d 100644 --- a/src/cairo_ps_surface.c +++ b/src/cairo_ps_surface.c @@ -286,19 +286,19 @@ _cairo_ps_surface_copy_page (void *abstract_surface) int i, x, y; cairo_surface_t *white_surface; - char *bgr, *compressed; - long bgr_size, compressed_size; + char *rgb, *compressed; + long rgb_size, compressed_size; cairo_color_t white; - bgr_size = 3 * width * height; - bgr = malloc (bgr_size); - if (bgr == NULL) { + rgb_size = 3 * width * height; + rgb = malloc (rgb_size); + if (rgb == NULL) { status = CAIRO_STATUS_NO_MEMORY; goto BAIL0; } - compressed_size = (int) (1.0 + 1.1 * bgr_size); + compressed_size = (int) (1.0 + 1.1 * rgb_size); compressed = malloc (compressed_size); if (compressed == NULL) { status = CAIRO_STATUS_NO_MEMORY; @@ -330,16 +330,15 @@ _cairo_ps_surface_copy_page (void *abstract_surface) i = 0; for (y = 0; y < height; y++) { - char *line = surface->image->data + y * surface->image->stride; - for (x = 0; x < width; x++) { - unsigned char *pixel = (unsigned char *) line + x * 4; - bgr[i++] = *(pixel+2); - bgr[i++] = *(pixel+1); - bgr[i++] = *(pixel); + pixman_bits_t *pixel = (pixman_bits_t *) (surface->image->data + y * surface->image->stride); + for (x = 0; x < width; x++, pixel++) { + rgb[i++] = (*pixel & 0x00ff0000) >> 16; + rgb[i++] = (*pixel & 0x0000ff00) >> 8; + rgb[i++] = (*pixel & 0x000000ff) >> 0; } } - compress (compressed, &compressed_size, bgr, bgr_size); + compress (compressed, &compressed_size, rgb, rgb_size); /* Page header */ fprintf (file, "%%%%Page: %d\n", ++surface->pages); @@ -375,7 +374,7 @@ _cairo_ps_surface_copy_page (void *abstract_surface) BAIL2: free (compressed); BAIL1: - free (bgr); + free (rgb); BAIL0: return status; } @@ -395,6 +394,23 @@ _cairo_ps_surface_show_page (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_ps_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + cairo_ps_surface_t *surface = abstract_surface; + + return _cairo_image_surface_set_clip_region (surface->image, region); +} + +static cairo_int_status_t +_cairo_ps_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_create_similar, _cairo_ps_surface_destroy, @@ -408,5 +424,7 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_fill_rectangles, _cairo_ps_surface_composite_trapezoids, _cairo_ps_surface_copy_page, - _cairo_ps_surface_show_page + _cairo_ps_surface_show_page, + _cairo_ps_surface_set_clip_region, + _cairo_ps_surface_create_pattern }; diff --git a/src/cairo_surface.c b/src/cairo_surface.c index ff4f39c1f..91ab8aba4 100644 --- a/src/cairo_surface.c +++ b/src/cairo_surface.c @@ -38,6 +38,7 @@ _cairo_surface_init (cairo_surface_t *surface, surface->ref_count = 1; _cairo_matrix_init (&surface->matrix); + surface->filter = CAIRO_FILTER_NEAREST; surface->repeat = 0; } @@ -165,9 +166,16 @@ cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter) if (surface == NULL) return CAIRO_STATUS_NULL_POINTER; + surface->filter = filter; return surface->backend->set_filter (surface, filter); } +cairo_filter_t +cairo_surface_get_filter (cairo_surface_t *surface) +{ + return surface->filter; +} + /* XXX: NYI cairo_status_t cairo_surface_clip_rectangle (cairo_surface_t *surface, @@ -364,3 +372,116 @@ _cairo_surface_show_page (cairo_surface_t *surface) return CAIRO_STATUS_SUCCESS; } +cairo_status_t +_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region) +{ + return surface->backend->set_clip_region (surface, region); +} + +cairo_status_t +_cairo_surface_create_pattern (cairo_surface_t *surface, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_int_status_t status; + + status = surface->backend->create_pattern (surface, pattern, box); + + /* The backend cannot accelerate this pattern, lets create an + unaccelerated source instead. */ + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + + status = CAIRO_STATUS_SUCCESS; + switch (pattern->type) { + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_image_surface_t *image; + + image = _cairo_pattern_get_image (pattern, box); + if (image) { + pattern->source = &image->base; + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; + + } break; + case CAIRO_PATTERN_SOLID: + pattern->source = + _cairo_surface_create_similar_solid (surface, + CAIRO_FORMAT_ARGB32, + 1, 1, + &pattern->color); + if (pattern->source) { + cairo_surface_set_repeat (pattern->source, 1); + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; + break; + case CAIRO_PATTERN_SURFACE: + status = CAIRO_INT_STATUS_UNSUPPORTED; + + /* handle pattern opacity */ + if (pattern->color.alpha != 1.0) { + int width = ceil (_cairo_fixed_to_double (box->p2.x) - + _cairo_fixed_to_double (box->p1.x)); + int height = ceil (_cairo_fixed_to_double (box->p2.y) - + _cairo_fixed_to_double (box->p1.y)); + cairo_pattern_t alpha; + + pattern->source = + cairo_surface_create_similar (surface, + CAIRO_FORMAT_ARGB32, + width, height); + if (pattern->source) { + _cairo_pattern_init_solid (&alpha, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&alpha, pattern->color.alpha); + + status = _cairo_surface_create_pattern (pattern->source, + &alpha, box); + + if (status == CAIRO_STATUS_SUCCESS) { + int save_repeat = pattern->u.surface.surface->repeat; + + if (pattern->extend == CAIRO_EXTEND_REPEAT || + pattern->u.surface.surface->repeat == 1) + cairo_surface_set_repeat (pattern->u.surface.surface, 1); + else + cairo_surface_set_repeat (pattern->u.surface.surface, 0); + + status = + _cairo_surface_composite (CAIRO_OPERATOR_OVER, + pattern->u.surface.surface, + alpha.source, + pattern->source, + 0, 0, 0, 0, 0, 0, + width, height); + + cairo_surface_set_repeat (pattern->u.surface.surface, + save_repeat); + + if (status == CAIRO_STATUS_SUCCESS) { + _cairo_pattern_add_source_offset (pattern, + _cairo_fixed_to_double (box->p1.x), + _cairo_fixed_to_double (box->p1.y)); + } else + cairo_surface_destroy (pattern->source); + } + + _cairo_pattern_fini (&alpha); + } + } + + if (status != CAIRO_STATUS_SUCCESS) { + pattern->source = pattern->u.surface.surface; + cairo_surface_reference (pattern->u.surface.surface); + + return CAIRO_STATUS_SUCCESS; + } + break; + } + } + + return status; +} diff --git a/src/cairo_traps.c b/src/cairo_traps.c index 63df3ea45..9b44d38ea 100644 --- a/src/cairo_traps.c +++ b/src/cairo_traps.c @@ -58,7 +58,7 @@ _compute_inverse_slope (cairo_line_t *l); static double _compute_x_intercept (cairo_line_t *l, double inverse_slope); -static cairo_fixed_t +static int _line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret); void @@ -490,7 +490,7 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ */ cairo_status_t _cairo_traps_tessellate_polygon (cairo_traps_t *traps, - cairo_polygon_t *poly, + cairo_polygon_t *poly, cairo_fill_rule_t fill_rule) { cairo_status_t status; @@ -608,3 +608,40 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y) return 0; } + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +static void +_cairo_trap_extents (cairo_trapezoid_t *t, cairo_box_t *extents) +{ + cairo_fixed_t x; + + if (t->top < extents->p1.y) + extents->p1.y = t->top; + + if (t->bottom > extents->p2.y) + extents->p2.y = t->bottom; + + x = MIN (_compute_x (&t->left, t->top), + _compute_x (&t->left, t->bottom)); + if (x < extents->p1.x) + extents->p1.x = x; + + x = MAX (_compute_x (&t->right, t->top), + _compute_x (&t->right, t->bottom)); + if (x > extents->p2.x) + extents->p2.x = x; +} + +void +_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents) +{ + int i; + + extents->p1.x = extents->p1.y = SHRT_MAX << 16; + extents->p2.x = extents->p2.y = SHRT_MIN << 16; + + for (i = 0; i < traps->num_traps; i++) + _cairo_trap_extents (&traps->traps[i], extents); +} diff --git a/src/cairo_xcb_surface.c b/src/cairo_xcb_surface.c new file mode 100644 index 000000000..ea1f72e16 --- /dev/null +++ b/src/cairo_xcb_surface.c @@ -0,0 +1,799 @@ +/* + * Copyright © 2002 University of Southern California + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * University of Southern California not be used in advertising or + * publicity pertaining to distribution of the software without + * specific, written prior permission. The University of Southern + * California makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF + * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth <cworth@isi.edu> + */ + +#include "cairoint.h" + +cairo_surface_t * +cairo_xcb_surface_create (XCBConnection *dpy, + XCBDRAWABLE drawable, + XCBVISUALTYPE *visual, + cairo_format_t format); + +#define AllPlanes ((unsigned long)~0L) + +static XCBRenderPICTFORMAT +format_from_visual(XCBConnection *c, XCBVISUALID visual) +{ + static const XCBRenderPICTFORMAT nil = { 0 }; + XCBRenderQueryPictFormatsRep *r; + XCBRenderPICTSCREENIter si; + XCBRenderPICTDEPTHIter di; + XCBRenderPICTVISUALIter vi; + + r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0); + if(!r) + return nil; + + for(si = XCBRenderQueryPictFormatsScreens(r); si.rem; XCBRenderPICTSCREENNext(&si)) + for(di = XCBRenderPICTSCREENDepths(si.data); di.rem; XCBRenderPICTDEPTHNext(&di)) + for(vi = XCBRenderPICTDEPTHVisuals(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi)) + if(vi.data->visual.id == visual.id) + { + XCBRenderPICTFORMAT ret = vi.data->format; + free(r); + return ret; + } + + return nil; +} + +static XCBRenderPICTFORMAT +format_from_cairo(XCBConnection *c, cairo_format_t fmt) +{ + XCBRenderPICTFORMAT ret = { 0 }; + struct tmpl_t { + XCBRenderDIRECTFORMAT direct; + CARD8 depth; + }; + static const struct tmpl_t templates[] = { + /* CAIRO_FORMAT_ARGB32 */ + { + { + 16, 0xff, + 8, 0xff, + 0, 0xff, + 24, 0xff + }, + 32 + }, + /* CAIRO_FORMAT_RGB24 */ + { + { + 16, 0xff, + 8, 0xff, + 0, 0xff, + 0, 0x00 + }, + 24 + }, + /* CAIRO_FORMAT_A8 */ + { + { + 0, 0x00, + 0, 0x00, + 0, 0x00, + 0, 0xff + }, + 8 + }, + /* CAIRO_FORMAT_A1 */ + { + { + 0, 0x00, + 0, 0x00, + 0, 0x00, + 0, 0x01 + }, + 1 + }, + }; + const struct tmpl_t *tmpl; + XCBRenderQueryPictFormatsRep *r; + XCBRenderPICTFORMINFOIter fi; + + if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates))) + return ret; + tmpl = templates + fmt; + + r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0); + if(!r) + return ret; + + for(fi = XCBRenderQueryPictFormatsFormats(r); fi.rem; XCBRenderPICTFORMINFONext(&fi)) + { + const XCBRenderDIRECTFORMAT *t, *f; + if(fi.data->type != XCBRenderPictTypeDirect) + continue; + if(fi.data->depth != tmpl->depth) + continue; + t = &tmpl->direct; + f = &fi.data->direct; + if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift)) + continue; + if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift)) + continue; + if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift)) + continue; + if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift)) + continue; + + ret = fi.data->id; + } + + free(r); + return ret; +} + +void +cairo_set_target_xcb (cairo_t *cr, + XCBConnection *dpy, + XCBDRAWABLE drawable, + XCBVISUALTYPE *visual, + cairo_format_t format) +{ + cairo_surface_t *surface; + + if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE) + return; + + surface = cairo_xcb_surface_create (dpy, drawable, visual, format); + if (surface == NULL) { + cr->status = CAIRO_STATUS_NO_MEMORY; + return; + } + + cairo_set_target_surface (cr, surface); + + /* cairo_set_target_surface takes a reference, so we must destroy ours */ + cairo_surface_destroy (surface); +} + +typedef struct cairo_xcb_surface { + cairo_surface_t base; + + XCBConnection *dpy; + XCBGCONTEXT gc; + XCBDRAWABLE drawable; + int owns_pixmap; + XCBVISUALTYPE *visual; + cairo_format_t format; + + int render_major; + int render_minor; + + int width; + int height; + + XCBRenderPICTURE picture; +} cairo_xcb_surface_t; + +#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \ + (((surface)->render_major > major) || \ + (((surface)->render_major == major) && ((surface)->render_minor >= minor))) + +#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) +#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) + +#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1) +#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1) + +#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2) +#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2) + +#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) +#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) +#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) +#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) + +#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) +#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) + +static int +_CAIRO_FORMAT_DEPTH (cairo_format_t format) +{ + switch (format) { + case CAIRO_FORMAT_A1: + return 1; + case CAIRO_FORMAT_A8: + return 8; + case CAIRO_FORMAT_RGB24: + return 24; + case CAIRO_FORMAT_ARGB32: + default: + return 32; + } +} + +static cairo_surface_t * +_cairo_xcb_surface_create_similar (void *abstract_src, + cairo_format_t format, + int width, + int height) +{ + cairo_xcb_surface_t *src = abstract_src; + XCBConnection *dpy = src->dpy; + XCBDRAWABLE d; + cairo_xcb_surface_t *surface; + + /* XXX: There's a pretty lame heuristic here. This assumes that + * all non-Render X servers do not support depth-32 pixmaps, (and + * that they do support depths 1, 8, and 24). Obviously, it would + * be much better to check the depths that are actually + * supported. */ + if (!dpy + || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src) + && format == CAIRO_FORMAT_ARGB32)) + { + return NULL; + } + + d.pixmap = XCBPIXMAPNew (dpy); + XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format), + d.pixmap, src->drawable, + width, height); + + surface = (cairo_xcb_surface_t *) + cairo_xcb_surface_create (dpy, d, NULL, format); + surface->owns_pixmap = 1; + + surface->width = width; + surface->height = height; + + return &surface->base; +} + +static void +_cairo_xcb_surface_destroy (void *abstract_surface) +{ + cairo_xcb_surface_t *surface = abstract_surface; + if (surface->picture.xid) + XCBRenderFreePicture (surface->dpy, surface->picture); + + if (surface->owns_pixmap) + XCBFreePixmap (surface->dpy, surface->drawable.pixmap); + + if (surface->gc.xid) + XCBFreeGC (surface->dpy, surface->gc); + + surface->dpy = 0; + + free (surface); +} + +static double +_cairo_xcb_surface_pixels_per_inch (void *abstract_surface) +{ + /* XXX: We should really get this value from somewhere like Xft.dpy */ + return 96.0; +} + +static int +bits_per_pixel(XCBConnection *c, int depth) +{ + XCBFORMAT *fmt = XCBConnSetupSuccessRepPixmapFormats(XCBGetSetup(c)); + XCBFORMAT *fmtend = fmt + XCBConnSetupSuccessRepPixmapFormatsLength(XCBGetSetup(c)); + + for(; fmt != fmtend; ++fmt) + if(fmt->depth == depth) + return fmt->bits_per_pixel; + + if(depth <= 4) + return 4; + if(depth <= 8) + return 8; + if(depth <= 16) + return 16; + return 32; +} + +static int +bytes_per_line(XCBConnection *c, int width, int bpp) +{ + int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad; + return (bpp * width + bitmap_pad - 1) & -bitmap_pad; +} + +static cairo_image_surface_t * +_cairo_xcb_surface_get_image (void *abstract_surface) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_image_surface_t *image; + XCBGetGeometryRep *geomrep; + XCBGetImageRep *imagerep; + int bpp; + + geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0); + if(!geomrep) + return 0; + + surface->width = geomrep->width; + surface->height = geomrep->height; + free(geomrep); + + imagerep = XCBGetImageReply(surface->dpy, + XCBGetImage(surface->dpy, ZPixmap, + surface->drawable, + 0, 0, + surface->width, surface->height, + AllPlanes), 0); + if(!imagerep) + return 0; + + bpp = bits_per_pixel(surface->dpy, imagerep->depth); + + if (surface->visual) { + cairo_format_masks_t masks; + + /* XXX: Add support here for pictures with external alpha? */ + + masks.bpp = bpp; + masks.alpha_mask = 0; + masks.red_mask = surface->visual->red_mask; + masks.green_mask = surface->visual->green_mask; + masks.blue_mask = surface->visual->blue_mask; + + image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep), + &masks, + surface->width, + surface->height, + bytes_per_line(surface->dpy, surface->width, bpp)); + } else { + image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (XCBGetImageData(imagerep), + surface->format, + surface->width, + surface->height, + bytes_per_line(surface->dpy, surface->width, bpp)); + } + + /* Let the surface take ownership of the data */ + /* XXX: Can probably come up with a cleaner API here. */ + _cairo_image_surface_assume_ownership_of_data (image); + /* FIXME: imagerep can't be freed correctly, I think. must copy. :-( */ + + _cairo_image_surface_set_repeat (image, surface->base.repeat); + _cairo_image_surface_set_matrix (image, &(surface->base.matrix)); + + return image; +} + +static void +_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface) +{ + if (surface->gc.xid) + return; + + surface->gc = XCBGCONTEXTNew(surface->dpy); + XCBCreateGC (surface->dpy, surface->gc, surface->drawable, 0, 0); +} + +static cairo_status_t +_cairo_xcb_surface_set_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_xcb_surface_t *surface = abstract_surface; + int bpp, data_len; + + _cairo_xcb_surface_ensure_gc (surface); + bpp = bits_per_pixel(surface->dpy, image->depth); + data_len = bytes_per_line(surface->dpy, surface->width, bpp) * surface->height; + XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc, + image->width, + image->height, + /* dst_x */ 0, /* dst_y */ 0, + /* left_pad */ 0, image->depth, + data_len, image->data); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix) +{ + cairo_xcb_surface_t *surface = abstract_surface; + XCBRenderTRANSFORM xtransform; + + if (!surface->picture.xid) + return CAIRO_STATUS_SUCCESS; + + xtransform.matrix11 = _cairo_fixed_from_double (matrix->m[0][0]); + xtransform.matrix12 = _cairo_fixed_from_double (matrix->m[1][0]); + xtransform.matrix13 = _cairo_fixed_from_double (matrix->m[2][0]); + + xtransform.matrix21 = _cairo_fixed_from_double (matrix->m[0][1]); + xtransform.matrix22 = _cairo_fixed_from_double (matrix->m[1][1]); + xtransform.matrix23 = _cairo_fixed_from_double (matrix->m[2][1]); + + xtransform.matrix31 = 0; + xtransform.matrix32 = 0; + xtransform.matrix33 = _cairo_fixed_from_double (1); + + if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) + { + XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform); + } else { + /* XXX: Need support here if using an old RENDER without support + for SetPictureTransform */ + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter) +{ + cairo_xcb_surface_t *surface = abstract_surface; + char *render_filter; + + if (!(surface->picture.xid + && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface))) + return CAIRO_STATUS_SUCCESS; + + switch (filter) { + case CAIRO_FILTER_FAST: + render_filter = "fast"; + break; + case CAIRO_FILTER_GOOD: + render_filter = "good"; + break; + case CAIRO_FILTER_BEST: + render_filter = "best"; + break; + case CAIRO_FILTER_NEAREST: + render_filter = "nearest"; + break; + case CAIRO_FILTER_BILINEAR: + render_filter = "bilinear"; + break; + default: + render_filter = "best"; + break; + } + + XCBRenderSetPictureFilter(surface->dpy, surface->picture, + strlen(render_filter), 0, render_filter, NULL); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat) +{ + cairo_xcb_surface_t *surface = abstract_surface; + + CARD32 mask = XCBRenderCPRepeat; + CARD32 pa[] = { repeat }; + + if (!surface->picture.xid) + return CAIRO_STATUS_SUCCESS; + + XCBRenderChangePicture (surface->dpy, surface->picture, mask, pa); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_xcb_surface_t * +_cairo_xcb_surface_clone_similar (cairo_surface_t *src, + cairo_xcb_surface_t *template, + cairo_format_t format, + int depth) +{ + cairo_xcb_surface_t *clone; + cairo_image_surface_t *src_image; + + src_image = _cairo_surface_get_image (src); + + clone = (cairo_xcb_surface_t *) + _cairo_xcb_surface_create_similar (template, format, + src_image->width, + src_image->height); + if (clone == NULL) + return NULL; + + _cairo_xcb_surface_set_filter (clone, cairo_surface_get_filter(src)); + + _cairo_xcb_surface_set_image (clone, src_image); + + _cairo_xcb_surface_set_matrix (clone, &(src_image->base.matrix)); + + cairo_surface_destroy (&src_image->base); + + return clone; +} + +static int +_render_operator (cairo_operator_t operator) +{ + switch (operator) { + case CAIRO_OPERATOR_CLEAR: + return XCBRenderPictOpClear; + case CAIRO_OPERATOR_SRC: + return XCBRenderPictOpSrc; + case CAIRO_OPERATOR_DST: + return XCBRenderPictOpDst; + case CAIRO_OPERATOR_OVER: + return XCBRenderPictOpOver; + case CAIRO_OPERATOR_OVER_REVERSE: + return XCBRenderPictOpOverReverse; + case CAIRO_OPERATOR_IN: + return XCBRenderPictOpIn; + case CAIRO_OPERATOR_IN_REVERSE: + return XCBRenderPictOpInReverse; + case CAIRO_OPERATOR_OUT: + return XCBRenderPictOpOut; + case CAIRO_OPERATOR_OUT_REVERSE: + return XCBRenderPictOpOutReverse; + case CAIRO_OPERATOR_ATOP: + return XCBRenderPictOpAtop; + case CAIRO_OPERATOR_ATOP_REVERSE: + return XCBRenderPictOpAtopReverse; + case CAIRO_OPERATOR_XOR: + return XCBRenderPictOpXor; + case CAIRO_OPERATOR_ADD: + return XCBRenderPictOpAdd; + case CAIRO_OPERATOR_SATURATE: + return XCBRenderPictOpSaturate; + default: + return XCBRenderPictOpOver; + } +} + +static cairo_int_status_t +_cairo_xcb_surface_composite (cairo_operator_t operator, + cairo_surface_t *generic_src, + cairo_surface_t *generic_mask, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_xcb_surface_t *dst = abstract_dst; + cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src; + cairo_xcb_surface_t *mask = (cairo_xcb_surface_t *) generic_mask; + cairo_xcb_surface_t *src_clone = NULL; + cairo_xcb_surface_t *mask_clone = NULL; + XCBRenderPICTURE maskpict = { 0 }; + + + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { + src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst, + CAIRO_FORMAT_ARGB32, 32); + if (!src_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + src = src_clone; + } + if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) { + mask_clone = _cairo_xcb_surface_clone_similar (generic_mask, dst, + CAIRO_FORMAT_A8, 8); + if (!mask_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + mask = mask_clone; + } + + if(mask) + maskpict = mask->picture; + + XCBRenderComposite (dst->dpy, + _render_operator (operator), + src->picture, + maskpict, + dst->picture, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + + /* XXX: This is messed up. If I can xcb_surface_create, then I + should be able to xcb_surface_destroy. */ + if (src_clone) + cairo_surface_destroy (&src_clone->base); + if (mask_clone) + cairo_surface_destroy (&mask_clone->base); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_xcb_surface_fill_rectangles (void *abstract_surface, + cairo_operator_t operator, + const cairo_color_t *color, + cairo_rectangle_t *rects, + int num_rects) +{ + cairo_xcb_surface_t *surface = abstract_surface; + XCBRenderCOLOR render_color; + + if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + render_color.red = color->red_short; + render_color.green = color->green_short; + render_color.blue = color->blue_short; + render_color.alpha = color->alpha_short; + + /* XXX: This XCBRECTANGLE cast is evil... it needs to go away somehow. */ + XCBRenderFillRectangles (surface->dpy, + _render_operator (operator), + surface->picture, + render_color, num_rects, (XCBRECTANGLE *) rects); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator, + cairo_surface_t *generic_src, + void *abstract_dst, + int xSrc, + int ySrc, + cairo_trapezoid_t *traps, + int num_traps) +{ + cairo_xcb_surface_t *dst = abstract_dst; + cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src; + cairo_xcb_surface_t *src_clone = NULL; + + if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) { + src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst, + CAIRO_FORMAT_ARGB32, 32); + if (!src_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + src = src_clone; + } + + /* XXX: The XCBRenderTRAP cast is evil and needs to go away somehow. */ + /* XXX: format_from_cairo is slow. should cache something. */ + XCBRenderTrapezoids (dst->dpy, + _render_operator (operator), + src->picture, dst->picture, + format_from_cairo (dst->dpy, CAIRO_FORMAT_A8), + xSrc, ySrc, num_traps, (XCBRenderTRAP *) traps); + + /* XXX: This is messed up. If I can xcb_surface_create, then I + should be able to xcb_surface_destroy. */ + if (src_clone) + cairo_surface_destroy (&src_clone->base); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_xcb_surface_copy_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_xcb_surface_show_page (void *abstract_surface) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_xcb_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + /* FIXME */ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_xcb_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static const struct cairo_surface_backend cairo_xcb_surface_backend = { + _cairo_xcb_surface_create_similar, + _cairo_xcb_surface_destroy, + _cairo_xcb_surface_pixels_per_inch, + _cairo_xcb_surface_get_image, + _cairo_xcb_surface_set_image, + _cairo_xcb_surface_set_matrix, + _cairo_xcb_surface_set_filter, + _cairo_xcb_surface_set_repeat, + _cairo_xcb_surface_composite, + _cairo_xcb_surface_fill_rectangles, + _cairo_xcb_surface_composite_trapezoids, + _cairo_xcb_surface_copy_page, + _cairo_xcb_surface_show_page, + _cairo_xcb_surface_set_clip_region, + _cairo_xcb_surface_create_pattern +}; + +static void +query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface) +{ + XCBRenderQueryVersionRep *r; + + surface->render_major = -1; + surface->render_minor = -1; + + if (!XCBRenderInit(c)) + return; + + r = XCBRenderQueryVersionReply(c, XCBRenderQueryVersion(c, 0, 6), 0); + if (!r) + return; + + surface->render_major = r->major_version; + surface->render_minor = r->minor_version; + free(r); +} + +cairo_surface_t * +cairo_xcb_surface_create (XCBConnection *dpy, + XCBDRAWABLE drawable, + XCBVISUALTYPE *visual, + cairo_format_t format) +{ + cairo_xcb_surface_t *surface; + + surface = malloc (sizeof (cairo_xcb_surface_t)); + if (surface == NULL) + return NULL; + + _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend); + + surface->dpy = dpy; + surface->gc.xid = 0; + surface->drawable = drawable; + surface->owns_pixmap = 0; + surface->visual = visual; + surface->format = format; + + query_render_version(dpy, surface); + + if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) + { + XCBRenderPICTFORMAT fmt; + if(visual) + fmt = format_from_visual (dpy, visual->visual_id); + else + fmt = format_from_cairo (dpy, format); + surface->picture = XCBRenderPICTURENew(dpy); + XCBRenderCreatePicture (dpy, surface->picture, drawable, + fmt, 0, NULL); + } + else + surface->picture.xid = 0; + + return (cairo_surface_t *) surface; +} diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c index 49abdb56e..19dfde503 100644 --- a/src/cairo_xlib_surface.c +++ b/src/cairo_xlib_surface.c @@ -90,6 +90,7 @@ typedef struct cairo_xlib_surface { #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) +#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) static int _CAIRO_FORMAT_DEPTH (cairo_format_t format) @@ -257,7 +258,7 @@ _cairo_xlib_surface_set_image (void *abstract_surface, ximage = XCreateImage (surface->dpy, DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)), - image->depth == 32 ? 24 : image->depth, + image->depth, ZPixmap, 0, image->data, @@ -320,26 +321,29 @@ _cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter) cairo_xlib_surface_t *surface = abstract_surface; char *render_filter; - if (!surface->picture) + if (!(surface->picture + && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface))) return CAIRO_STATUS_SUCCESS; - - /* XXX: The Render specification has capitalized versions of these - strings. However, the current implementation is - case-sensitive and expects lowercase versions. - */ + switch (filter) { case CAIRO_FILTER_FAST: - render_filter = "fast"; + render_filter = FilterFast; + break; case CAIRO_FILTER_GOOD: - render_filter = "good"; + render_filter = FilterGood; + break; case CAIRO_FILTER_BEST: - render_filter = "best"; + render_filter = FilterBest; + break; case CAIRO_FILTER_NEAREST: - render_filter = "nearest"; + render_filter = FilterNearest; + break; case CAIRO_FILTER_BILINEAR: - render_filter = "bilinear"; + render_filter = FilterBilinear; + break; default: - render_filter = "best"; + render_filter = FilterBest; + break; } XRenderSetPictureFilter (surface->dpy, surface->picture, @@ -384,6 +388,8 @@ _cairo_xlib_surface_clone_similar (cairo_surface_t *src, if (clone == NULL) return NULL; + _cairo_xlib_surface_set_filter (clone, cairo_surface_get_filter(src)); + _cairo_xlib_surface_set_image (clone, src_image); _cairo_xlib_surface_set_matrix (clone, &(src_image->base.matrix)); @@ -567,6 +573,60 @@ _cairo_xlib_surface_show_page (void *abstract_surface) return CAIRO_INT_STATUS_UNSUPPORTED; } +static cairo_int_status_t +_cairo_xlib_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) +{ + Region xregion; + XRectangle xr; + pixman_box16_t *box; + cairo_xlib_surface_t *surf; + int n, m; + + surf = (cairo_xlib_surface_t *) abstract_surface; + + if (region == NULL) { + /* NULL region == reset the clip */ + xregion = XCreateRegion(); + xr.x = 0; + xr.y = 0; + xr.width = surf->width; + xr.height = surf->height; + XUnionRectWithRegion (&xr, xregion, xregion); + } else { + n = pixman_region_num_rects (region); + /* XXX: Are we sure these are the semantics we want for an + * empty, (not null) region? */ + if (n == 0) + return CAIRO_STATUS_SUCCESS; + + box = pixman_region_rects (region); + xregion = XCreateRegion(); + + m = n; + for (; n > 0; --n, ++box) { + xr.x = (short) box->x1; + xr.y = (short) box->y1; + xr.width = (unsigned short) (box->x2 - box->x1); + xr.height = (unsigned short) (box->y2 - box->y1); + XUnionRectWithRegion (&xr, xregion, xregion); + } + } + + XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion); + XDestroyRegion(xregion); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_xlib_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, _cairo_xlib_surface_destroy, @@ -580,7 +640,9 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_fill_rectangles, _cairo_xlib_surface_composite_trapezoids, _cairo_xlib_surface_copy_page, - _cairo_xlib_surface_show_page + _cairo_xlib_surface_show_page, + _cairo_xlib_surface_set_clip_region, + _cairo_xlib_surface_create_pattern }; cairo_surface_t * diff --git a/src/cairoint.h b/src/cairoint.h index 036bff212..5b4ccb56e 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -43,7 +43,33 @@ #include "cairo.h" -#include <slim_internal.h> +#if __GNUC__ >= 3 && defined(__ELF__) +# define slim_hidden_proto(name) slim_hidden_proto1(name, INT_##name) +# define slim_hidden_def(name) slim_hidden_def1(name, INT_##name) +# define slim_hidden_proto1(name, internal) \ + extern __typeof (name) name \ + __asm__ (slim_hidden_asmname (internal)) \ + __internal_linkage; +# define slim_hidden_def1(name, internal) \ + extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \ + __attribute__((__alias__(slim_hidden_asmname(internal)))) +# define slim_hidden_ulp slim_hidden_ulp1(__USER_LABEL_PREFIX__) +# define slim_hidden_ulp1(x) slim_hidden_ulp2(x) +# define slim_hidden_ulp2(x) #x +# define slim_hidden_asmname(name) slim_hidden_asmname1(name) +# define slim_hidden_asmname1(name) slim_hidden_ulp #name +#else +# define slim_hidden_proto(name) +# define slim_hidden_def(name) +#endif + +/* slim_internal.h */ +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) +#define __internal_linkage __attribute__((__visibility__("hidden"))) +#else +#define __internal_linkage +#endif + /* These macros allow us to deprecate a function by providing an alias for the old function name to the new function name. With this @@ -102,17 +128,22 @@ typedef struct cairo_slope { cairo_fixed_t dx; cairo_fixed_t dy; -} cairo_slope_t; +} cairo_slope_t, cairo_distance_t; typedef struct cairo_point_double { double x; double y; } cairo_point_double_t; +typedef struct cairo_distance_double { + double dx; + double dy; +} cairo_distance_double_t; + typedef struct cairo_line { cairo_point_t p1; cairo_point_t p2; -} cairo_line_t; +} cairo_line_t, cairo_box_t; typedef struct cairo_trapezoid { cairo_fixed_t top, bottom; @@ -144,18 +175,6 @@ typedef enum cairo_direction { CAIRO_DIRECTION_REVERSE } cairo_direction_t; -typedef enum cairo_sub_path_done { - CAIRO_SUB_PATH_DONE_CAP, - CAIRO_SUB_PATH_DONE_JOIN -} cairo_sub_path_done_t; - -typedef struct cairo_path_callbacks { - cairo_status_t (*add_edge) (void *closure, cairo_point_t *p1, cairo_point_t *p2); - cairo_status_t (*add_spline) (void *closure, cairo_point_t *a, cairo_point_t *b, cairo_point_t *c, cairo_point_t *d); - cairo_status_t (*done_sub_path) (void *closure, cairo_sub_path_done_t done); - cairo_status_t (*done_path) (void *closure); -} cairo_path_callbacks_t; - #define CAIRO_PATH_BUF_SZ 64 typedef struct cairo_path_op_buf { @@ -178,6 +197,10 @@ typedef struct cairo_path { cairo_path_arg_buf_t *arg_head; cairo_path_arg_buf_t *arg_tail; + + cairo_point_t last_move_point; + cairo_point_t current_point; + int has_current_point; } cairo_path_t; typedef struct cairo_edge { @@ -193,9 +216,8 @@ typedef struct cairo_polygon { cairo_edge_t *edges; cairo_point_t first_point; - int first_point_defined; - cairo_point_t last_point; - int last_point_defined; + cairo_point_t current_point; + int has_current_point; int closed; } cairo_polygon_t; @@ -229,53 +251,51 @@ typedef struct cairo_pen { typedef struct cairo_color cairo_color_t; typedef struct cairo_font_backend { + cairo_font_t *(*create) (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight); + + cairo_font_t *(*copy) (void *font); - cairo_status_t (*font_extents) (cairo_font_t *font, - cairo_font_extents_t *extents); + void (*destroy) (void *font); - cairo_status_t (*text_extents) (cairo_font_t *font, - const unsigned char *utf8, - cairo_text_extents_t *extents); - - cairo_status_t (*glyph_extents) (cairo_font_t *font, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents); + cairo_status_t (*font_extents) (void *font, + cairo_font_extents_t *extents); + + cairo_status_t (*text_extents) (void *font, + const unsigned char *utf8, + cairo_text_extents_t *extents); - cairo_status_t (*show_text) (cairo_font_t *font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - double x, - double y, - const unsigned char *utf8); - - cairo_status_t (*show_glyphs) (cairo_font_t *font, - cairo_operator_t operator, - cairo_surface_t *source, - cairo_surface_t *surface, - double x, - double y, - const 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 (*text_path) (cairo_font_t *font, - cairo_path_t *path, - const unsigned char *utf8); - - cairo_status_t (*glyph_path) (cairo_font_t *font, - cairo_path_t *path, - cairo_glyph_t *glyphs, - int num_glyphs); - - cairo_font_t *(*create) (const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight); - - cairo_font_t *(*copy) (cairo_font_t *other); - - void (*destroy) (cairo_font_t *font); + cairo_status_t (*show_text) (void *font, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + double x, + double y, + const unsigned char *utf8); + + cairo_status_t (*show_glyphs) (void *font, + cairo_operator_t operator, + cairo_surface_t *source, + cairo_surface_t *surface, + const cairo_glyph_t *glyphs, + int num_glyphs); + cairo_status_t (*text_path) (void *font, + double x, + double y, + const unsigned char *utf8, + cairo_path_t *path); + + cairo_status_t (*glyph_path) (void *font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_t *path); } cairo_font_backend_t; /* concrete font backends */ @@ -357,6 +377,14 @@ typedef struct cairo_surface_backend { cairo_int_status_t (*show_page) (void *surface); + + cairo_int_status_t + (*set_clip_region) (void *surface, + pixman_region16_t *region); + cairo_int_status_t + (*create_pattern) (void *surface, + cairo_pattern_t *pattern, + cairo_box_t *extents); } cairo_surface_backend_t; struct cairo_matrix { @@ -377,6 +405,7 @@ struct cairo_surface { unsigned int ref_count; cairo_matrix_t matrix; + cairo_filter_t filter; int repeat; }; @@ -392,7 +421,7 @@ struct cairo_image_surface { int stride; int depth; - IcImage *ic_image; + pixman_image_t *pixman_image; }; /* XXX: Right now, the cairo_color structure puts unpremultiplied @@ -413,6 +442,59 @@ struct cairo_color { unsigned short alpha_short; }; +#define CAIRO_EXTEND_DEFAULT CAIRO_EXTEND_NONE +#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_NEAREST + +typedef enum { + CAIRO_PATTERN_SOLID, + CAIRO_PATTERN_SURFACE, + CAIRO_PATTERN_LINEAR, + CAIRO_PATTERN_RADIAL +} cairo_pattern_type_t; + +typedef struct cairo_color_stop { + double offset; + int id; + cairo_color_t color; + unsigned char color_char[4]; +} cairo_color_stop_t; + +struct cairo_pattern { + unsigned int ref_count; + + cairo_extend_t extend; + cairo_filter_t filter; + cairo_matrix_t matrix; + + cairo_color_stop_t *stops; + int n_stops; + + cairo_color_t color; + + cairo_surface_t *source; + cairo_point_double_t source_offset; + + cairo_pattern_type_t type; + union { + struct { + cairo_surface_t *surface; + cairo_matrix_t save_matrix; + int save_repeat; + cairo_filter_t save_filter; + } surface; + struct { + cairo_point_double_t point0; + cairo_point_double_t point1; + } linear; + struct { + cairo_point_double_t center0; + cairo_point_double_t center1; + cairo_distance_double_t radius0; + cairo_distance_double_t radius1; + } radial; + } u; +}; + typedef struct cairo_traps { cairo_trapezoid_t *traps; int num_traps; @@ -447,6 +529,7 @@ typedef struct cairo_clip_rec { int y; int width; int height; + pixman_region16_t *region; cairo_surface_t *surface; } cairo_clip_rec_t; @@ -471,25 +554,18 @@ typedef struct cairo_gstate { cairo_surface_t *surface; - cairo_surface_t *source; - cairo_point_double_t source_offset; - int source_is_solid; + cairo_pattern_t *pattern; + cairo_point_double_t pattern_offset; + double alpha; cairo_clip_rec_t clip; - double alpha; - cairo_color_t color; - double pixels_per_inch; cairo_matrix_t ctm; cairo_matrix_t ctm_inverse; cairo_path_t path; - cairo_point_double_t last_move_point; - cairo_point_double_t current_point; - int has_current_point; - cairo_pen_t pen_regular; struct cairo_gstate *next; @@ -509,6 +585,10 @@ typedef struct cairo_stroke_face { cairo_point_double_t usr_vector; } cairo_stroke_face_t; +/* cairo.c */ +extern void __internal_linkage +_cairo_restrict_value (double *value, double min, double max); + /* cairo_fixed.c */ extern cairo_fixed_t __internal_linkage _cairo_fixed_from_int (int i); @@ -516,6 +596,9 @@ _cairo_fixed_from_int (int i); extern cairo_fixed_t _cairo_fixed_from_double (double d); +cairo_fixed_t +_cairo_fixed_from_26_6 (uint32_t i); + extern double _cairo_fixed_to_double (cairo_fixed_t f); @@ -554,7 +637,10 @@ extern cairo_surface_t * __internal_linkage _cairo_gstate_current_target_surface (cairo_gstate_t *gstate); extern cairo_status_t __internal_linkage -_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_surface_t *pattern); +_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern); + +extern cairo_pattern_t *__internal_linkage +_cairo_gstate_current_pattern (cairo_gstate_t *gstate); extern cairo_status_t __internal_linkage _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator); @@ -705,6 +791,14 @@ extern cairo_status_t __internal_linkage _cairo_gstate_current_point (cairo_gstate_t *gstate, double *x, double *y); extern cairo_status_t __internal_linkage +_cairo_gstate_interpret_path (cairo_gstate_t *gstate, + cairo_move_to_func_t *move_to, + cairo_line_to_func_t *line_to, + cairo_curve_to_func_t *curve_to, + cairo_close_path_func_t *close_path, + void *closure); + +extern cairo_status_t __internal_linkage _cairo_gstate_stroke (cairo_gstate_t *gstate); extern cairo_status_t __internal_linkage @@ -717,6 +811,16 @@ extern cairo_status_t __internal_linkage _cairo_gstate_show_page (cairo_gstate_t *gstate); extern cairo_status_t __internal_linkage +_cairo_gstate_stroke_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2); + +extern cairo_status_t __internal_linkage +_cairo_gstate_fill_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2); + +extern cairo_status_t __internal_linkage _cairo_gstate_in_stroke (cairo_gstate_t *gstate, double x, double y, @@ -729,6 +833,9 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate, int *inside_ret); extern cairo_status_t __internal_linkage +_cairo_gstate_init_clip (cairo_gstate_t *gstate); + +extern cairo_status_t __internal_linkage _cairo_gstate_clip (cairo_gstate_t *gstate); extern cairo_status_t __internal_linkage @@ -739,7 +846,7 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, extern cairo_status_t __internal_linkage _cairo_gstate_select_font (cairo_gstate_t *gstate, - char *family, + const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight); @@ -813,7 +920,7 @@ _cairo_color_set_alpha (cairo_color_t *color, double alpha); /* cairo_font.c */ extern cairo_font_t * __internal_linkage -_cairo_font_create (char *family, +_cairo_font_create (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight); @@ -860,23 +967,22 @@ _cairo_font_show_glyphs (cairo_font_t *font, cairo_operator_t operator, cairo_surface_t *source, cairo_surface_t *surface, - double x, - double y, cairo_glyph_t *glyphs, int num_glyphs); extern cairo_int_status_t __internal_linkage _cairo_font_text_path (cairo_font_t *font, - cairo_path_t *path, - const unsigned char *utf8); + double x, + double y, + const unsigned char *utf8, + cairo_path_t *path); extern cairo_int_status_t __internal_linkage _cairo_font_glyph_path (cairo_font_t *font, - cairo_path_t *path, cairo_glyph_t *glyphs, - int num_glyphs); - + int num_glyphs, + cairo_path_t *path); /* cairo_hull.c */ extern cairo_status_t @@ -893,25 +999,56 @@ extern void __internal_linkage _cairo_path_fini (cairo_path_t *path); extern cairo_status_t __internal_linkage -_cairo_path_move_to (cairo_path_t *path, double x, double y); +_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point); + +extern cairo_status_t __internal_linkage +_cairo_path_rel_move_to (cairo_path_t *path, cairo_slope_t *slope); extern cairo_status_t __internal_linkage -_cairo_path_line_to (cairo_path_t *path, double x, double y); +_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point); + +extern cairo_status_t __internal_linkage +_cairo_path_rel_line_to (cairo_path_t *path, cairo_slope_t *slope); extern cairo_status_t __internal_linkage _cairo_path_curve_to (cairo_path_t *path, - double x1, double y1, - double x2, double y2, - double x3, double y3); + cairo_point_t *p0, + cairo_point_t *p1, + cairo_point_t *p2); + +extern cairo_status_t __internal_linkage +_cairo_path_rel_curve_to (cairo_path_t *path, + cairo_slope_t *s0, + cairo_slope_t *s1, + cairo_slope_t *s2); extern cairo_status_t __internal_linkage _cairo_path_close_path (cairo_path_t *path); extern cairo_status_t __internal_linkage -_cairo_path_interpret (cairo_path_t *path, - cairo_direction_t dir, - const cairo_path_callbacks_t *cb, - void *closure); +_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point); + +typedef cairo_status_t (cairo_path_move_to_func_t) (void *closure, + cairo_point_t *point); + +typedef cairo_status_t (cairo_path_line_to_func_t) (void *closure, + cairo_point_t *point); + +typedef cairo_status_t (cairo_path_curve_to_func_t) (void *closure, + cairo_point_t *p0, + cairo_point_t *p1, + cairo_point_t *p2); + +typedef cairo_status_t (cairo_path_close_path_func_t) (void *closure); + +extern cairo_status_t __internal_linkage +_cairo_path_interpret (cairo_path_t *path, + cairo_direction_t dir, + cairo_path_move_to_func_t *move_to, + cairo_path_line_to_func_t *line_to, + cairo_path_curve_to_func_t *curve_to, + cairo_path_close_path_func_t *close_path, + void *closure); extern cairo_status_t __internal_linkage _cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2); @@ -991,6 +1128,14 @@ extern cairo_status_t __internal_linkage _cairo_surface_set_image (cairo_surface_t *surface, cairo_image_surface_t *image); +extern cairo_status_t __internal_linkage +_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region); + +extern cairo_status_t __internal_linkage +_cairo_surface_create_pattern (cairo_surface_t *surface, + cairo_pattern_t *pattern, + cairo_box_t *extents); + /* cairo_image_surface.c */ extern cairo_image_surface_t * __internal_linkage @@ -1007,7 +1152,7 @@ extern cairo_status_t __internal_linkage _cairo_image_surface_set_matrix (cairo_image_surface_t *surface, cairo_matrix_t *matrix); -cairo_status_t +extern cairo_status_t __internal_linkage _cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter); @@ -1015,6 +1160,10 @@ extern cairo_status_t __internal_linkage _cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat); +extern cairo_int_status_t __internal_linkage +_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, + pixman_region16_t *region); + /* cairo_pen.c */ extern cairo_status_t __internal_linkage _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate); @@ -1065,7 +1214,10 @@ extern cairo_status_t __internal_linkage _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2); extern cairo_status_t __internal_linkage -_cairo_polygon_add_point (cairo_polygon_t *polygon, cairo_point_t *point); +_cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point); + +extern cairo_status_t __internal_linkage +_cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point); extern cairo_status_t __internal_linkage _cairo_polygon_close (cairo_polygon_t *polygon); @@ -1114,6 +1266,9 @@ _cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det); extern cairo_status_t __internal_linkage _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2); +extern cairo_status_t __internal_linkage +_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy); + /* cairo_traps.c */ extern void __internal_linkage _cairo_traps_init (cairo_traps_t *traps); @@ -1135,6 +1290,9 @@ _cairo_traps_tessellate_polygon (cairo_traps_t *traps, extern int __internal_linkage _cairo_traps_contain (cairo_traps_t *traps, double x, double y); +extern void __internal_linkage +_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents); + /* cairo_slope.c */ extern void __internal_linkage _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b); @@ -1148,6 +1306,50 @@ _cairo_slope_clockwise (cairo_slope_t *a, cairo_slope_t *b); extern int __internal_linkage _cairo_slope_counter_clockwise (cairo_slope_t *a, cairo_slope_t *b); +/* cairo_pattern.c */ +extern void __internal_linkage +_cairo_pattern_init (cairo_pattern_t *pattern); + +extern cairo_status_t __internal_linkage +_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other); + +extern void __internal_linkage +_cairo_pattern_fini (cairo_pattern_t *pattern); + +extern void __internal_linkage +_cairo_pattern_init_solid (cairo_pattern_t *pattern, + double red, double green, double blue); + +extern cairo_pattern_t *__internal_linkage +_cairo_pattern_create_solid (double red, double green, double blue); + +extern cairo_status_t __internal_linkage +_cairo_pattern_get_rgb (cairo_pattern_t *pattern, + double *red, double *green, double *blue); + +extern void __internal_linkage +_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha); + +extern void __internal_linkage +_cairo_pattern_add_source_offset (cairo_pattern_t *pattern, + double x, double y); + +extern void __internal_linkage +_cairo_pattern_transform (cairo_pattern_t *pattern, + cairo_matrix_t *matrix, + cairo_matrix_t *matrix_inverse); + +extern void __internal_linkage +_cairo_pattern_prepare_surface (cairo_pattern_t *pattern); + +extern void __internal_linkage +_cairo_pattern_calc_color_at_pixel (cairo_pattern_t *pattern, + double factor, + int *pixel); + +extern cairo_image_surface_t *__internal_linkage +_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box); + /* Avoid unnecessary PLT entries. */ slim_hidden_proto(cairo_close_path) |