From f30c726d3a424659191823e6d1b0f26f2eb68882 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Thu, 10 Mar 2011 14:52:15 -0500 Subject: [PATCH] Bug 562746. Update cairo to 1.10. A lot of changes from upstream here that will hopefully be smoothed out a bit soon. --- configure.in | 2 + gfx/cairo/cairo/src/Makefile.in | 16 +- .../src/cairo-analysis-surface-private.h | 6 +- gfx/cairo/cairo/src/cairo-analysis-surface.c | 37 +- gfx/cairo/cairo/src/cairo-arc-private.h | 2 +- gfx/cairo/cairo/src/cairo-arc.c | 2 +- gfx/cairo/cairo/src/cairo-array.c | 5 +- gfx/cairo/cairo/src/cairo-atomic-private.h | 151 +- gfx/cairo/cairo/src/cairo-atomic.c | 31 +- gfx/cairo/cairo/src/cairo-base64-stream.c | 3 +- gfx/cairo/cairo/src/cairo-base85-stream.c | 3 +- .../src/cairo-bentley-ottmann-rectangular.c | 778 +-- .../src/cairo-bentley-ottmann-rectilinear.c | 125 +- gfx/cairo/cairo/src/cairo-bentley-ottmann.c | 11 +- gfx/cairo/cairo/src/cairo-beos.h | 2 +- .../cairo/src/cairo-botor-scan-converter.c | 2199 +++++++++ gfx/cairo/cairo/src/cairo-boxes-private.h | 84 + gfx/cairo/cairo/src/cairo-boxes.c | 300 ++ gfx/cairo/cairo/src/cairo-cache-private.h | 2 +- gfx/cairo/cairo/src/cairo-cache.c | 13 +- gfx/cairo/cairo/src/cairo-cff-subset.c | 39 +- gfx/cairo/cairo/src/cairo-clip-private.h | 28 +- gfx/cairo/cairo/src/cairo-clip.c | 591 +-- gfx/cairo/cairo/src/cairo-color.c | 54 +- gfx/cairo/cairo/src/cairo-combsort-private.h | 2 +- gfx/cairo/cairo/src/cairo-compiler-private.h | 63 +- .../src/cairo-composite-rectangles-private.h | 105 + .../cairo/src/cairo-composite-rectangles.c | 195 + gfx/cairo/cairo/src/cairo-d2d-private.h | 2 - gfx/cairo/cairo/src/cairo-d2d-surface.cpp | 112 +- gfx/cairo/cairo/src/cairo-debug.c | 16 +- gfx/cairo/cairo/src/cairo-deflate-stream.c | 3 +- gfx/cairo/cairo/src/cairo-deprecated.h | 17 +- gfx/cairo/cairo/src/cairo-device-private.h | 86 + gfx/cairo/cairo/src/cairo-device.c | 533 ++ gfx/cairo/cairo/src/cairo-directfb-surface.c | 23 +- gfx/cairo/cairo/src/cairo-directfb.h | 2 +- gfx/cairo/cairo/src/cairo-drm.h | 37 +- gfx/cairo/cairo/src/cairo-dwrite-font.cpp | 3 +- gfx/cairo/cairo/src/cairo-error-private.h | 60 + gfx/cairo/cairo/src/cairo-features.h.in | 2 + gfx/cairo/cairo/src/cairo-fixed-private.h | 62 +- .../cairo/src/cairo-fixed-type-private.h | 2 +- gfx/cairo/cairo/src/cairo-fixed.c | 2 +- gfx/cairo/cairo/src/cairo-font-face-twin.c | 3 +- gfx/cairo/cairo/src/cairo-font-face.c | 20 +- gfx/cairo/cairo/src/cairo-font-options.c | 115 +- .../cairo/src/cairo-fontconfig-private.h | 78 + .../cairo/src/cairo-freed-pool-private.h | 129 + gfx/cairo/cairo/src/cairo-freed-pool.c | 93 + gfx/cairo/cairo/src/cairo-freelist-private.h | 41 +- .../cairo/src/cairo-freelist-type-private.h | 54 + gfx/cairo/cairo/src/cairo-freelist.c | 46 +- gfx/cairo/cairo/src/cairo-ft-font.c | 741 ++- gfx/cairo/cairo/src/cairo-ft-private.h | 2 +- gfx/cairo/cairo/src/cairo-ft.h | 2 +- gfx/cairo/cairo/src/cairo-gl-glyphs.c | 504 +- gfx/cairo/cairo/src/cairo-gl-private.h | 383 +- gfx/cairo/cairo/src/cairo-gl-shaders.c | 1004 +++- gfx/cairo/cairo/src/cairo-gl-surface.c | 2394 +++------ gfx/cairo/cairo/src/cairo-gl.h | 64 +- gfx/cairo/cairo/src/cairo-glx-context.c | 91 +- gfx/cairo/cairo/src/cairo-gstate-private.h | 315 +- gfx/cairo/cairo/src/cairo-gstate.c | 355 +- gfx/cairo/cairo/src/cairo-hash-private.h | 2 +- gfx/cairo/cairo/src/cairo-hash.c | 3 +- gfx/cairo/cairo/src/cairo-hull.c | 10 +- .../cairo/src/cairo-image-info-private.h | 8 +- gfx/cairo/cairo/src/cairo-image-info.c | 6 +- gfx/cairo/cairo/src/cairo-image-surface.c | 4272 ++++++++++++++--- gfx/cairo/cairo/src/cairo-list-private.h | 40 +- gfx/cairo/cairo/src/cairo-lzw.c | 3 +- gfx/cairo/cairo/src/cairo-malloc-private.h | 2 +- gfx/cairo/cairo/src/cairo-matrix.c | 39 +- gfx/cairo/cairo/src/cairo-misc.c | 127 +- .../cairo/src/cairo-mutex-impl-private.h | 30 +- .../cairo/src/cairo-mutex-list-private.h | 9 +- gfx/cairo/cairo/src/cairo-mutex-private.h | 2 +- .../cairo/src/cairo-mutex-type-private.h | 11 +- gfx/cairo/cairo/src/cairo-mutex.c | 2 +- gfx/cairo/cairo/src/cairo-observer.c | 50 + gfx/cairo/cairo/src/cairo-os2-private.h | 2 +- gfx/cairo/cairo/src/cairo-os2-surface.c | 8 +- gfx/cairo/cairo/src/cairo-os2.h | 2 +- .../cairo/src/cairo-output-stream-private.h | 4 +- gfx/cairo/cairo/src/cairo-output-stream.c | 5 +- gfx/cairo/cairo/src/cairo-paginated-private.h | 2 +- .../src/cairo-paginated-surface-private.h | 3 +- gfx/cairo/cairo/src/cairo-paginated-surface.c | 97 +- gfx/cairo/cairo/src/cairo-path-bounds.c | 157 +- gfx/cairo/cairo/src/cairo-path-fill.c | 86 +- .../cairo/src/cairo-path-fixed-private.h | 9 +- gfx/cairo/cairo/src/cairo-path-fixed.c | 147 +- gfx/cairo/cairo/src/cairo-path-in-fill.c | 2 +- gfx/cairo/cairo/src/cairo-path-private.h | 2 +- gfx/cairo/cairo/src/cairo-path-stroke.c | 257 +- gfx/cairo/cairo/src/cairo-path.c | 12 +- gfx/cairo/cairo/src/cairo-pattern.c | 649 +-- .../cairo/src/cairo-pdf-operators-private.h | 27 +- gfx/cairo/cairo/src/cairo-pdf-operators.c | 63 +- .../cairo/src/cairo-pdf-surface-private.h | 13 +- gfx/cairo/cairo/src/cairo-pdf-surface.c | 553 ++- gfx/cairo/cairo/src/cairo-pdf.h | 2 +- gfx/cairo/cairo/src/cairo-pen.c | 3 +- gfx/cairo/cairo/src/cairo-png.c | 41 +- gfx/cairo/cairo/src/cairo-polygon.c | 33 +- gfx/cairo/cairo/src/cairo-private.h | 2 +- .../cairo/src/cairo-ps-surface-private.h | 2 +- gfx/cairo/cairo/src/cairo-ps-surface.c | 597 ++- gfx/cairo/cairo/src/cairo-ps.h | 2 +- gfx/cairo/cairo/src/cairo-qt-surface.cpp | 17 +- gfx/cairo/cairo/src/cairo-qt.h | 14 +- gfx/cairo/cairo/src/cairo-quartz-font.c | 180 +- .../cairo/src/cairo-quartz-image-surface.c | 5 +- gfx/cairo/cairo/src/cairo-quartz-image.h | 2 +- gfx/cairo/cairo/src/cairo-quartz-private.h | 8 +- gfx/cairo/cairo/src/cairo-quartz-surface.c | 975 ++-- gfx/cairo/cairo/src/cairo-quartz.h | 2 +- .../src/cairo-recording-surface-private.h | 4 +- gfx/cairo/cairo/src/cairo-recording-surface.c | 154 +- gfx/cairo/cairo/src/cairo-rectangle.c | 23 +- .../src/cairo-rectangular-scan-converter.c | 723 +++ .../cairo/src/cairo-reference-count-private.h | 3 +- gfx/cairo/cairo/src/cairo-region-private.h | 5 +- gfx/cairo/cairo/src/cairo-region.c | 200 +- gfx/cairo/cairo/src/cairo-rtree-private.h | 18 +- gfx/cairo/cairo/src/cairo-rtree.c | 51 +- .../cairo/src/cairo-scaled-font-private.h | 6 +- .../src/cairo-scaled-font-subsets-private.h | 14 +- .../cairo/src/cairo-scaled-font-subsets.c | 5 +- gfx/cairo/cairo/src/cairo-scaled-font.c | 461 +- gfx/cairo/cairo/src/cairo-script-surface.c | 940 ++-- gfx/cairo/cairo/src/cairo-script.h | 37 +- gfx/cairo/cairo/src/cairo-skia.h | 4 +- gfx/cairo/cairo/src/cairo-slope-private.h | 2 +- gfx/cairo/cairo/src/cairo-slope.c | 2 +- gfx/cairo/cairo/src/cairo-spans-private.h | 60 +- gfx/cairo/cairo/src/cairo-spans.c | 78 +- gfx/cairo/cairo/src/cairo-spline.c | 2 +- gfx/cairo/cairo/src/cairo-stroke-style.c | 81 +- .../cairo/src/cairo-supported-features.h | 6 +- .../cairo/src/cairo-surface-clipper-private.h | 2 +- gfx/cairo/cairo/src/cairo-surface-clipper.c | 7 +- .../src/cairo-surface-fallback-private.h | 8 +- gfx/cairo/cairo/src/cairo-surface-fallback.c | 726 +-- .../cairo/src/cairo-surface-offset-private.h | 95 + gfx/cairo/cairo/src/cairo-surface-offset.c | 342 ++ gfx/cairo/cairo/src/cairo-surface-private.h | 12 +- .../src/cairo-surface-snapshot-private.h | 48 + gfx/cairo/cairo/src/cairo-surface-snapshot.c | 255 + .../src/cairo-surface-subsurface-private.h | 49 + .../cairo/src/cairo-surface-subsurface.c | 552 +++ .../cairo/src/cairo-surface-wrapper-private.h | 21 +- gfx/cairo/cairo/src/cairo-surface-wrapper.c | 462 +- gfx/cairo/cairo/src/cairo-surface.c | 610 ++- .../cairo/src/cairo-svg-surface-private.h | 2 +- gfx/cairo/cairo/src/cairo-svg-surface.c | 195 +- gfx/cairo/cairo/src/cairo-svg.h | 2 +- gfx/cairo/cairo/src/cairo-system.c | 2 +- .../cairo/src/cairo-tee-surface-private.h | 2 +- gfx/cairo/cairo/src/cairo-tee-surface.c | 27 +- gfx/cairo/cairo/src/cairo-tee.h | 66 + .../cairo/src/cairo-tor-scan-converter.c | 151 +- gfx/cairo/cairo/src/cairo-toy-font-face.c | 3 +- gfx/cairo/cairo/src/cairo-traps.c | 44 +- .../cairo/src/cairo-truetype-subset-private.h | 2 +- gfx/cairo/cairo/src/cairo-truetype-subset.c | 3 +- gfx/cairo/cairo/src/cairo-type1-fallback.c | 19 +- gfx/cairo/cairo/src/cairo-type1-private.h | 2 +- gfx/cairo/cairo/src/cairo-type1-subset.c | 21 +- .../src/cairo-type3-glyph-surface-private.h | 2 +- .../cairo/src/cairo-type3-glyph-surface.c | 41 +- gfx/cairo/cairo/src/cairo-types-private.h | 128 +- gfx/cairo/cairo/src/cairo-unicode.c | 3 +- gfx/cairo/cairo/src/cairo-user-font-private.h | 2 +- gfx/cairo/cairo/src/cairo-user-font.c | 85 +- gfx/cairo/cairo/src/cairo-version.c | 158 +- gfx/cairo/cairo/src/cairo-vg-surface.c | 22 +- gfx/cairo/cairo/src/cairo-vg.h | 2 +- gfx/cairo/cairo/src/cairo-wideint-private.h | 2 +- .../cairo/src/cairo-wideint-type-private.h | 2 +- gfx/cairo/cairo/src/cairo-wideint.c | 4 +- gfx/cairo/cairo/src/cairo-win32-font.c | 22 +- .../cairo/src/cairo-win32-printing-surface.c | 42 +- gfx/cairo/cairo/src/cairo-win32-private.h | 8 +- gfx/cairo/cairo/src/cairo-win32-surface.c | 2029 +++++++- gfx/cairo/cairo/src/cairo-win32.h | 2 +- gfx/cairo/cairo/src/cairo-xcb-surface.c | 3598 +++++--------- gfx/cairo/cairo/src/cairo-xcb.h | 43 +- gfx/cairo/cairo/src/cairo-xlib-display.c | 372 +- gfx/cairo/cairo/src/cairo-xlib-private.h | 97 +- gfx/cairo/cairo/src/cairo-xlib-screen.c | 335 +- .../cairo/src/cairo-xlib-surface-private.h | 5 +- gfx/cairo/cairo/src/cairo-xlib-surface.c | 952 ++-- gfx/cairo/cairo/src/cairo-xlib-visual.c | 6 +- .../cairo/src/cairo-xlib-xrender-private.h | 16 +- gfx/cairo/cairo/src/cairo-xlib-xrender.h | 2 +- gfx/cairo/cairo/src/cairo-xlib.h | 2 +- gfx/cairo/cairo/src/cairo-xml-surface.c | 251 +- gfx/cairo/cairo/src/cairo-xml.h | 15 +- gfx/cairo/cairo/src/cairo.c | 298 +- gfx/cairo/cairo/src/cairo.h | 196 +- gfx/cairo/cairo/src/cairoint.h | 594 +-- gfx/cairo/cairo/src/test-fallback-surface.c | 7 +- gfx/cairo/cairo/src/test-fallback-surface.h | 2 +- gfx/cairo/cairo/src/test-paginated-surface.c | 13 +- gfx/cairo/cairo/src/test-paginated-surface.h | 2 +- gfx/thebes/gfxASurface.cpp | 1 + gfx/thebes/gfxASurface.h | 1 + gfx/thebes/gfxQPainterSurface.cpp | 6 +- gfx/thebes/gfxTeeSurface.cpp | 7 - layout/reftests/border-radius/reftest.list | 6 +- layout/reftests/counters/reftest.list | 2 +- .../reftests/generated-content/reftest.list | 2 +- 214 files changed, 25105 insertions(+), 11735 deletions(-) create mode 100644 gfx/cairo/cairo/src/cairo-botor-scan-converter.c create mode 100644 gfx/cairo/cairo/src/cairo-boxes-private.h create mode 100644 gfx/cairo/cairo/src/cairo-boxes.c create mode 100644 gfx/cairo/cairo/src/cairo-composite-rectangles-private.h create mode 100644 gfx/cairo/cairo/src/cairo-composite-rectangles.c create mode 100644 gfx/cairo/cairo/src/cairo-device-private.h create mode 100644 gfx/cairo/cairo/src/cairo-device.c create mode 100644 gfx/cairo/cairo/src/cairo-error-private.h create mode 100644 gfx/cairo/cairo/src/cairo-fontconfig-private.h create mode 100644 gfx/cairo/cairo/src/cairo-freed-pool-private.h create mode 100644 gfx/cairo/cairo/src/cairo-freed-pool.c create mode 100644 gfx/cairo/cairo/src/cairo-freelist-type-private.h create mode 100644 gfx/cairo/cairo/src/cairo-observer.c create mode 100644 gfx/cairo/cairo/src/cairo-rectangular-scan-converter.c create mode 100644 gfx/cairo/cairo/src/cairo-surface-offset-private.h create mode 100644 gfx/cairo/cairo/src/cairo-surface-offset.c create mode 100644 gfx/cairo/cairo/src/cairo-surface-snapshot-private.h create mode 100644 gfx/cairo/cairo/src/cairo-surface-snapshot.c create mode 100644 gfx/cairo/cairo/src/cairo-surface-subsurface-private.h create mode 100644 gfx/cairo/cairo/src/cairo-surface-subsurface.c create mode 100644 gfx/cairo/cairo/src/cairo-tee.h diff --git a/configure.in b/configure.in index 9541c45ef1dd..e0d7601014b5 100644 --- a/configure.in +++ b/configure.in @@ -8407,6 +8407,7 @@ if test "$MOZ_TREE_CAIRO"; then AC_DEFINE(HAVE_UINT64_T) # Define macros for cairo-features.h + TEE_SURFACE_FEATURE="#define CAIRO_HAS_TEE_SURFACE 1" if test "$MOZ_X11"; then XLIB_SURFACE_FEATURE="#define CAIRO_HAS_XLIB_SURFACE 1" XLIB_XRENDER_SURFACE_FEATURE="#define CAIRO_HAS_XLIB_XRENDER_SURFACE 1" @@ -8489,6 +8490,7 @@ if test "$MOZ_TREE_CAIRO"; then AC_SUBST(QUARTZ_FONT_FEATURE) AC_SUBST(PNG_FUNCTIONS_FEATURE) AC_SUBST(QT_SURFACE_FEATURE) + AC_SUBST(TEE_SURFACE_FEATURE) MOZ_CAIRO_LIBS='$(call EXPAND_LIBNAME_PATH,mozcairo,$(DEPTH)/gfx/cairo/cairo/src)'" $CAIRO_FT_LIBS" diff --git a/gfx/cairo/cairo/src/Makefile.in b/gfx/cairo/cairo/src/Makefile.in index 820dd783d659..915f1a7f7d6d 100644 --- a/gfx/cairo/cairo/src/Makefile.in +++ b/gfx/cairo/cairo/src/Makefile.in @@ -70,20 +70,25 @@ CSRCS = \ cairo-arc.c \ cairo-array.c \ cairo-atomic.c \ + cairo-base64-stream.c \ cairo-bentley-ottmann.c \ cairo-bentley-ottmann-rectilinear.c \ cairo-bentley-ottmann-rectangular.c \ - cairo-base64-stream.c \ + cairo-botor-scan-converter.c \ + cairo-boxes.c \ cairo-cache.c \ cairo-clip.c \ cairo-color.c \ + cairo-composite-rectangles.c \ cairo-debug.c \ cairo-deflate-stream.c \ + cairo-device.c \ cairo-fixed.c \ cairo-font-face.c \ cairo-font-face-twin.c \ cairo-font-face-twin-data.c \ cairo-font-options.c \ + cairo-freed-pool.c \ cairo-freelist.c \ cairo-gstate.c \ cairo-hash.c \ @@ -94,6 +99,7 @@ CSRCS = \ cairo-matrix.c \ cairo-misc.c \ cairo-mutex.c \ + cairo-observer.c \ cairo-output-stream.c \ cairo-paginated-surface.c \ cairo-path.c \ @@ -107,6 +113,7 @@ CSRCS = \ cairo-polygon.c \ cairo-recording-surface.c \ cairo-rectangle.c \ + cairo-rectangular-scan-converter.c \ cairo-region.c \ cairo-scaled-font.c \ cairo-scaled-font-subsets.c \ @@ -117,6 +124,9 @@ CSRCS = \ cairo-surface.c \ cairo-surface-clipper.c \ cairo-surface-fallback.c \ + cairo-surface-offset.c \ + cairo-surface-snapshot.c \ + cairo-surface-subsurface.c \ cairo-surface-wrapper.c \ cairo-tee-surface.c \ cairo-tor-scan-converter.c \ @@ -130,7 +140,7 @@ CSRCS = \ EXPORTS_NAMESPACES = cairo -EXPORTS_cairo = cairo.h cairo-version.h cairo-features.h cairo-platform.h cairo-deprecated.h cairo-rename.h +EXPORTS_cairo = cairo.h cairo-version.h cairo-features.h cairo-platform.h cairo-deprecated.h cairo-rename.h cairo-tee.h # cairo-type1-subset.c should be here, but it's only supported on freetype platforms @@ -153,6 +163,7 @@ PDF_EXPORTS = cairo-pdf.h PS_EXPORTS = cairo-ps.h ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +DEFINES += -DDISABLE_SOME_FLOATING_POINT CSRCS += cairo-win32-surface.c ifndef WINCE @@ -269,3 +280,4 @@ endif cairo-features.h: $(srcdir)/cairo-features.h.in $(GLOBAL_DEPS) $(PERL) $(AUTOCONF_TOOLS)/make-makefile -t $(topsrcdir) -d $(DEPTH) ./$@ + cat cairo-dwrite-font.i | gzip | python -c "import base64,sys; base64.encode(sys.stdin,sys.stdout)" diff --git a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h index f67caf904ef0..12c82f8892f4 100644 --- a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h @@ -11,7 +11,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,6 +37,8 @@ #include "cairoint.h" +CAIRO_BEGIN_DECLS + cairo_private cairo_surface_t * _cairo_analysis_surface_create (cairo_surface_t *target); @@ -71,4 +73,6 @@ _cairo_analysis_surface_merge_status (cairo_int_status_t status_a, cairo_private cairo_surface_t * _cairo_null_surface_create (cairo_content_t content); +CAIRO_END_DECLS + #endif /* CAIRO_ANALYSIS_SURFACE_H */ diff --git a/gfx/cairo/cairo/src/cairo-analysis-surface.c b/gfx/cairo/cairo/src/cairo-analysis-surface.c index 0ba667d4ae40..a61514903d43 100644 --- a/gfx/cairo/cairo/src/cairo-analysis-surface.c +++ b/gfx/cairo/cairo/src/cairo-analysis-surface.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,8 +37,10 @@ #include "cairoint.h" #include "cairo-analysis-surface-private.h" +#include "cairo-error-private.h" #include "cairo-paginated-private.h" #include "cairo-recording-surface-private.h" +#include "cairo-surface-subsurface-private.h" #include "cairo-region-private.h" typedef struct { @@ -99,10 +101,11 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, cairo_bool_t old_has_ctm; cairo_matrix_t old_ctm, p2d; cairo_status_t status; + cairo_surface_t *source; assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); surface_pattern = (const cairo_surface_pattern_t *) pattern; - assert (_cairo_surface_is_recording (surface_pattern->surface)); + assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING); old_ctm = surface->ctm; old_has_ctm = surface->has_ctm; @@ -114,8 +117,13 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm); surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm); - status = _cairo_recording_surface_replay_and_create_regions (surface_pattern->surface, - &surface->base); + source = surface_pattern->surface; + if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source; + source = sub->target; + } + + status = _cairo_recording_surface_replay_and_create_regions (source, &surface->base); surface->ctm = old_ctm; surface->has_ctm = old_has_ctm; @@ -396,9 +404,9 @@ _cairo_analysis_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) @@ -716,7 +724,9 @@ _cairo_analysis_surface_create (cairo_surface_t *target) /* I believe the content type here is truly arbitrary. I'm quite * sure nothing will ever use this value. */ - _cairo_surface_init (&surface->base, &cairo_analysis_surface_backend, + _cairo_surface_init (&surface->base, + &cairo_analysis_surface_backend, + NULL, /* device */ CAIRO_CONTENT_COLOR_ALPHA); cairo_matrix_init_identity (&surface->ctm); @@ -831,9 +841,9 @@ typedef cairo_int_status_t cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip); @@ -906,7 +916,10 @@ _cairo_null_surface_create (cairo_content_t content) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } - _cairo_surface_init (surface, &cairo_null_surface_backend, content); + _cairo_surface_init (surface, + &cairo_null_surface_backend, + NULL, /* device */ + content); return surface; } diff --git a/gfx/cairo/cairo/src/cairo-arc-private.h b/gfx/cairo/cairo/src/cairo-arc-private.h index 633fbfa5a3a2..018a14b4a711 100644 --- a/gfx/cairo/cairo/src/cairo-arc-private.h +++ b/gfx/cairo/cairo/src/cairo-arc-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-arc.c b/gfx/cairo/cairo/src/cairo-arc.c index e99c79b2da81..56d42f19eb77 100644 --- a/gfx/cairo/cairo/src/cairo-arc.c +++ b/gfx/cairo/cairo/src/cairo-arc.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-array.c b/gfx/cairo/cairo/src/cairo-array.c index fcd1246dc532..942c9b98ecd9 100644 --- a/gfx/cairo/cairo/src/cairo-array.c +++ b/gfx/cairo/cairo/src/cairo-array.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -36,6 +36,7 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" /** * _cairo_array_init: @@ -260,7 +261,7 @@ _cairo_array_append (cairo_array_t *array, } /** - * _cairo_array_append: + * _cairo_array_append_multiple: * @array: a #cairo_array_t * * Append one or more items onto the array by growing the array by diff --git a/gfx/cairo/cairo/src/cairo-atomic-private.h b/gfx/cairo/cairo/src/cairo-atomic-private.h index 8532f6212b44..8d02ec948cbb 100644 --- a/gfx/cairo/cairo/src/cairo-atomic-private.h +++ b/gfx/cairo/cairo/src/cairo-atomic-private.h @@ -1,6 +1,7 @@ /* cairo - a vector graphics library with display and print output * * Copyright © 2007 Chris Wilson + * Copyright © 2010 Andrea Canciani * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -12,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -32,6 +33,7 @@ * * Contributor(s): * Chris Wilson + * Andrea Canciani */ #ifndef CAIRO_ATOMIC_PRIVATE_H @@ -57,12 +59,29 @@ CAIRO_BEGIN_DECLS typedef int cairo_atomic_int_t; +#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER +static cairo_always_inline cairo_atomic_int_t +_cairo_atomic_int_get (cairo_atomic_int_t *x) +{ + __sync_synchronize (); + return *x; +} + +static cairo_always_inline void * +_cairo_atomic_ptr_get (void **x) +{ + __sync_synchronize (); + return *x; +} +#else # define _cairo_atomic_int_get(x) (*x) -# define _cairo_atomic_int_set(x, value) ((*x) = value) +# define _cairo_atomic_ptr_get(x) (*x) +#endif # define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1)) # define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1) -# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv) +# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_bool_compare_and_swap (x, oldv, newv) +# define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv) #if SIZEOF_VOID_P==SIZEOF_INT typedef int cairo_atomic_intptr_t; @@ -75,7 +94,10 @@ typedef long long cairo_atomic_intptr_t; #endif # define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \ - (void*)__sync_val_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv) + __sync_bool_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv) + +# define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) \ + _cairo_atomic_intptr_to_voidptr (__sync_val_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)) #endif @@ -87,11 +109,10 @@ typedef long long cairo_atomic_intptr_t; typedef AO_t cairo_atomic_int_t; # define _cairo_atomic_int_get(x) (AO_load_full (x)) -# define _cairo_atomic_int_set(x, value) (AO_store_full (x)) # define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x)) # define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1) -# define _cairo_atomic_int_cmpxchg(x, oldv, newv) ((cairo_atomic_int_t) AO_compare_and_swap_full(x, oldv, newv) ? oldv : *x) +# define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, oldv, newv) #if SIZEOF_VOID_P==SIZEOF_INT typedef unsigned int cairo_atomic_intptr_t; @@ -103,45 +124,129 @@ typedef unsigned long long cairo_atomic_intptr_t; #error No matching integer pointer type #endif +# define _cairo_atomic_ptr_get(x) _cairo_atomic_intptr_to_voidptr (AO_load_full (x)) # define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \ - (void*) (cairo_atomic_intptr_t) _cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv) + _cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv) #endif +#if HAVE_OS_ATOMIC_OPS +#include + +#define HAS_ATOMIC_OPS 1 + +typedef int32_t cairo_atomic_int_t; + +# define _cairo_atomic_int_get(x) (OSMemoryBarrier(), *(x)) + +# define _cairo_atomic_int_inc(x) ((void) OSAtomicIncrement32Barrier (x)) +# define _cairo_atomic_int_dec_and_test(x) (OSAtomicDecrement32Barrier (x) == 0) +# define _cairo_atomic_int_cmpxchg(x, oldv, newv) OSAtomicCompareAndSwap32Barrier(oldv, newv, x) + +#if SIZEOF_VOID_P==4 +typedef int32_t cairo_atomic_intptr_t; +# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \ + OSAtomicCompareAndSwap32Barrier((cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv, (cairo_atomic_intptr_t *)x) + +#elif SIZEOF_VOID_P==8 +typedef int64_t cairo_atomic_intptr_t; +# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \ + OSAtomicCompareAndSwap64Barrier((cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv, (cairo_atomic_intptr_t *)x) + +#else +#error No matching integer pointer type +#endif + +# define _cairo_atomic_ptr_get(x) (OSMemoryBarrier(), *(x)) + +#endif #ifndef HAS_ATOMIC_OPS -typedef int cairo_atomic_int_t; +#if SIZEOF_VOID_P==SIZEOF_INT +typedef unsigned int cairo_atomic_intptr_t; +#elif SIZEOF_VOID_P==SIZEOF_LONG +typedef unsigned long cairo_atomic_intptr_t; +#elif SIZEOF_VOID_P==SIZEOF_LONG_LONG +typedef unsigned long long cairo_atomic_intptr_t; +#else +#error No matching integer pointer type +#endif + +typedef cairo_atomic_intptr_t cairo_atomic_int_t; cairo_private void -_cairo_atomic_int_inc (int *x); +_cairo_atomic_int_inc (cairo_atomic_int_t *x); cairo_private cairo_bool_t -_cairo_atomic_int_dec_and_test (int *x); +_cairo_atomic_int_dec_and_test (cairo_atomic_int_t *x); -cairo_private int -_cairo_atomic_int_cmpxchg (int *x, int oldv, int newv); +cairo_private cairo_atomic_int_t +_cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv); cairo_private void * -_cairo_atomic_ptr_cmpxchg (void **x, void *oldv, void *newv); +_cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv); + +#define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_impl (x, oldv, newv) +#define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_impl (x, oldv, newv) #ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER - -# include "cairo-compiler-private.h" - -cairo_private int -_cairo_atomic_int_get (int *x); - -cairo_private void -_cairo_atomic_int_set (int *x, int value); +cairo_private cairo_atomic_int_t +_cairo_atomic_int_get (cairo_atomic_int_t *x); +# define _cairo_atomic_ptr_get(x) (void *) _cairo_atomic_int_get((cairo_atomic_int_t *) x) +#else +# define _cairo_atomic_int_get(x) (*x) +# define _cairo_atomic_ptr_get(x) (*x) +#endif #else -# define _cairo_atomic_int_get(x) (*x) -# define _cairo_atomic_int_set(x, value) ((*x) = value) +/* Workaround GCC complaining about casts */ +static cairo_always_inline void * +_cairo_atomic_intptr_to_voidptr (cairo_atomic_intptr_t x) +{ + return (void *) x; +} +static cairo_always_inline cairo_atomic_int_t +_cairo_atomic_int_cmpxchg_return_old_fallback(cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv) +{ + cairo_atomic_int_t curr; + + do { + curr = _cairo_atomic_int_get (x); + } while (curr == oldv && !_cairo_atomic_int_cmpxchg (x, oldv, newv)); + + return curr; +} + +static cairo_always_inline void * +_cairo_atomic_ptr_cmpxchg_return_old_fallback(void **x, void *oldv, void *newv) +{ + void *curr; + + do { + curr = _cairo_atomic_ptr_get (x); + } while (curr == oldv && !_cairo_atomic_ptr_cmpxchg (x, oldv, newv)); + + return curr; +} #endif +#ifndef _cairo_atomic_int_cmpxchg_return_old +#define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_fallback (x, oldv, newv) +#endif + +#ifndef _cairo_atomic_ptr_cmpxchg_return_old +#define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_fallback (x, oldv, newv) +#endif + +#ifndef _cairo_atomic_int_cmpxchg +#define _cairo_atomic_int_cmpxchg(x, oldv, newv) (_cairo_atomic_int_cmpxchg_return_old (x, oldv, newv) == oldv) +#endif + +#ifndef _cairo_atomic_ptr_cmpxchg +#define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) (_cairo_atomic_ptr_cmpxchg_return_old (x, oldv, newv) == oldv) #endif #define _cairo_atomic_uint_get(x) _cairo_atomic_int_get(x) diff --git a/gfx/cairo/cairo/src/cairo-atomic.c b/gfx/cairo/cairo/src/cairo-atomic.c index 146ad857d803..909cfea49254 100644 --- a/gfx/cairo/cairo/src/cairo-atomic.c +++ b/gfx/cairo/cairo/src/cairo-atomic.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -42,7 +42,7 @@ COMPILE_TIME_ASSERT(sizeof(void*) == sizeof(int) || sizeof(void*) == sizeof(long long)); #else void -_cairo_atomic_int_inc (int *x) +_cairo_atomic_int_inc (cairo_atomic_intptr_t *x) { CAIRO_MUTEX_LOCK (_cairo_atomic_mutex); *x += 1; @@ -50,7 +50,7 @@ _cairo_atomic_int_inc (int *x) } cairo_bool_t -_cairo_atomic_int_dec_and_test (int *x) +_cairo_atomic_int_dec_and_test (cairo_atomic_intptr_t *x) { cairo_bool_t ret; @@ -61,10 +61,10 @@ _cairo_atomic_int_dec_and_test (int *x) return ret; } -int -_cairo_atomic_int_cmpxchg (int *x, int oldv, int newv) +cairo_atomic_intptr_t +_cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_intptr_t *x, cairo_atomic_intptr_t oldv, cairo_atomic_intptr_t newv) { - int ret; + cairo_atomic_intptr_t ret; CAIRO_MUTEX_LOCK (_cairo_atomic_mutex); ret = *x; @@ -76,7 +76,7 @@ _cairo_atomic_int_cmpxchg (int *x, int oldv, int newv) } void * -_cairo_atomic_ptr_cmpxchg (void **x, void *oldv, void *newv) +_cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv) { void *ret; @@ -88,13 +88,12 @@ _cairo_atomic_ptr_cmpxchg (void **x, void *oldv, void *newv) return ret; } -#endif #ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER -int -_cairo_atomic_int_get (int *x) +cairo_atomic_intptr_t +_cairo_atomic_int_get (cairo_atomic_intptr_t *x) { - int ret; + cairo_atomic_intptr_t ret; CAIRO_MUTEX_LOCK (_cairo_atomic_mutex); ret = *x; @@ -102,12 +101,6 @@ _cairo_atomic_int_get (int *x) return ret; } - -void -_cairo_atomic_int_set (int *x, int value) -{ - CAIRO_MUTEX_LOCK (_cairo_atomic_mutex); - *x = value; - CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex); -} +#endif + #endif diff --git a/gfx/cairo/cairo/src/cairo-base64-stream.c b/gfx/cairo/cairo/src/cairo-base64-stream.c index 2b211ff0ce37..636431372b58 100644 --- a/gfx/cairo/cairo/src/cairo-base64-stream.c +++ b/gfx/cairo/cairo/src/cairo-base64-stream.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,6 +37,7 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-output-stream-private.h" typedef struct _cairo_base64_stream { diff --git a/gfx/cairo/cairo/src/cairo-base85-stream.c b/gfx/cairo/cairo/src/cairo-base85-stream.c index 791e80134032..f81affb49ea4 100644 --- a/gfx/cairo/cairo/src/cairo-base85-stream.c +++ b/gfx/cairo/cairo/src/cairo-base85-stream.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -35,6 +35,7 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-output-stream-private.h" typedef struct _cairo_base85_stream { diff --git a/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectangular.c b/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectangular.c index 9887b8242f29..f2f790e53be0 100644 --- a/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectangular.c +++ b/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectangular.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,30 +38,30 @@ /* Provide definitions for standalone compilation */ #include "cairoint.h" +#include "cairo-boxes-private.h" +#include "cairo-error-private.h" #include "cairo-combsort-private.h" #include "cairo-list-private.h" -typedef struct _cairo_bo_rectangle cairo_bo_rectangle_t; -typedef struct _cairo_bo_edge cairo_bo_edge_t; +#include -/* A deferred trapezoid of an edge */ -typedef struct _cairo_bo_trap { - cairo_bo_edge_t *right; - int32_t top; -} cairo_bo_trap_t; +typedef struct _rectangle rectangle_t; +typedef struct _edge edge_t; -struct _cairo_bo_edge { - int x; +struct _edge { + edge_t *next, *prev; + edge_t *right; + cairo_fixed_t x, top; int dir; - cairo_bo_trap_t deferred_trap; - cairo_list_t link; }; -struct _cairo_bo_rectangle { - cairo_bo_edge_t left, right; - int top, bottom; +struct _rectangle { + edge_t left, right; + int32_t top, bottom; }; +#define UNROLL3(x) x x x + /* the parent is always given by index/2 */ #define PQ_PARENT_INDEX(i) ((i) >> 1) #define PQ_FIRST_ENTRY 1 @@ -72,18 +72,22 @@ struct _cairo_bo_rectangle { typedef struct _pqueue { int size, max_size; - cairo_bo_rectangle_t **elements; - cairo_bo_rectangle_t *elements_embedded[1024]; + rectangle_t **elements; + rectangle_t *elements_embedded[1024]; } pqueue_t; -typedef struct _cairo_bo_sweep_line { - cairo_bo_rectangle_t **rectangles; - pqueue_t stop; - cairo_list_t sweep; - cairo_list_t *current_left, *current_right; +typedef struct _sweep_line { + rectangle_t **rectangles; + pqueue_t pq; + edge_t head, tail; + edge_t *insert_left, *insert_right; int32_t current_y; int32_t last_y; -} cairo_bo_sweep_line_t; + + cairo_fill_rule_t fill_rule; + + jmp_buf unwind; +} sweep_line_t; #define DEBUG_TRAPS 0 @@ -121,21 +125,21 @@ dump_traps (cairo_traps_t *traps, const char *filename) #endif static inline int -cairo_bo_rectangle_compare_start (const cairo_bo_rectangle_t *a, - const cairo_bo_rectangle_t *b) +rectangle_compare_start (const rectangle_t *a, + const rectangle_t *b) { return a->top - b->top; } static inline int -_cairo_bo_rectangle_compare_stop (const cairo_bo_rectangle_t *a, - const cairo_bo_rectangle_t *b) +rectangle_compare_stop (const rectangle_t *a, + const rectangle_t *b) { return a->bottom - b->bottom; } static inline void -_pqueue_init (pqueue_t *pq) +pqueue_init (pqueue_t *pq) { pq->max_size = ARRAY_LENGTH (pq->elements_embedded); pq->size = 0; @@ -145,73 +149,69 @@ _pqueue_init (pqueue_t *pq) } static inline void -_pqueue_fini (pqueue_t *pq) +pqueue_fini (pqueue_t *pq) { if (pq->elements != pq->elements_embedded) free (pq->elements); } -static cairo_status_t -_pqueue_grow (pqueue_t *pq) +static cairo_bool_t +pqueue_grow (pqueue_t *pq) { - cairo_bo_rectangle_t **new_elements; + rectangle_t **new_elements; pq->max_size *= 2; if (pq->elements == pq->elements_embedded) { new_elements = _cairo_malloc_ab (pq->max_size, - sizeof (cairo_bo_rectangle_t *)); + sizeof (rectangle_t *)); if (unlikely (new_elements == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + return FALSE; memcpy (new_elements, pq->elements_embedded, sizeof (pq->elements_embedded)); } else { new_elements = _cairo_realloc_ab (pq->elements, pq->max_size, - sizeof (cairo_bo_rectangle_t *)); + sizeof (rectangle_t *)); if (unlikely (new_elements == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + return FALSE; } pq->elements = new_elements; - return CAIRO_STATUS_SUCCESS; + return TRUE; } -static inline cairo_status_t -_pqueue_push (pqueue_t *pq, cairo_bo_rectangle_t *rectangle) +static inline void +pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle) { - cairo_bo_rectangle_t **elements; + rectangle_t **elements; int i, parent; - if (unlikely (pq->size + 1 == pq->max_size)) { - cairo_status_t status; - - status = _pqueue_grow (pq); - if (unlikely (status)) - return status; + if (unlikely (sweep->pq.size + 1 == sweep->pq.max_size)) { + if (unlikely (! pqueue_grow (&sweep->pq))) { + longjmp (sweep->unwind, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + } } - elements = pq->elements; - - for (i = ++pq->size; + elements = sweep->pq.elements; + for (i = ++sweep->pq.size; i != PQ_FIRST_ENTRY && - _cairo_bo_rectangle_compare_stop (rectangle, - elements[parent = PQ_PARENT_INDEX (i)]) < 0; + rectangle_compare_stop (rectangle, + elements[parent = PQ_PARENT_INDEX (i)]) < 0; i = parent) { elements[i] = elements[parent]; } elements[i] = rectangle; - - return CAIRO_STATUS_SUCCESS; } static inline void -_pqueue_pop (pqueue_t *pq) +pqueue_pop (pqueue_t *pq) { - cairo_bo_rectangle_t **elements = pq->elements; - cairo_bo_rectangle_t *tail; + rectangle_t **elements = pq->elements; + rectangle_t *tail; int child, i; tail = elements[pq->size--]; @@ -225,13 +225,13 @@ _pqueue_pop (pqueue_t *pq) i = child) { if (child != pq->size && - _cairo_bo_rectangle_compare_stop (elements[child+1], - elements[child]) < 0) + rectangle_compare_stop (elements[child+1], + elements[child]) < 0) { child++; } - if (_cairo_bo_rectangle_compare_stop (elements[child], tail) >= 0) + if (rectangle_compare_stop (elements[child], tail) >= 0) break; elements[i] = elements[child]; @@ -239,74 +239,94 @@ _pqueue_pop (pqueue_t *pq) elements[i] = tail; } -static inline cairo_bo_rectangle_t * -_cairo_bo_rectangle_pop_start (cairo_bo_sweep_line_t *sweep_line) +static inline rectangle_t * +rectangle_pop_start (sweep_line_t *sweep_line) { return *sweep_line->rectangles++; } -static inline cairo_bo_rectangle_t * -_cairo_bo_rectangle_peek_stop (cairo_bo_sweep_line_t *sweep_line) +static inline rectangle_t * +rectangle_peek_stop (sweep_line_t *sweep_line) { - return sweep_line->stop.elements[PQ_FIRST_ENTRY]; + return sweep_line->pq.elements[PQ_FIRST_ENTRY]; } -CAIRO_COMBSORT_DECLARE (_cairo_bo_rectangle_sort, - cairo_bo_rectangle_t *, - cairo_bo_rectangle_compare_start) +CAIRO_COMBSORT_DECLARE (_rectangle_sort, + rectangle_t *, + rectangle_compare_start) static void -_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line, - cairo_bo_rectangle_t **rectangles, - int num_rectangles) +sweep_line_init (sweep_line_t *sweep_line, + rectangle_t **rectangles, + int num_rectangles, + cairo_fill_rule_t fill_rule) { - _cairo_bo_rectangle_sort (rectangles, num_rectangles); + _rectangle_sort (rectangles, num_rectangles); rectangles[num_rectangles] = NULL; sweep_line->rectangles = rectangles; - cairo_list_init (&sweep_line->sweep); - sweep_line->current_left = &sweep_line->sweep; - sweep_line->current_right = &sweep_line->sweep; + sweep_line->head.x = INT32_MIN; + sweep_line->head.right = NULL; + sweep_line->head.dir = 0; + sweep_line->head.next = &sweep_line->tail; + sweep_line->tail.x = INT32_MAX; + sweep_line->tail.right = NULL; + sweep_line->tail.dir = 0; + sweep_line->tail.prev = &sweep_line->head; + + sweep_line->insert_left = &sweep_line->tail; + sweep_line->insert_right = &sweep_line->tail; + sweep_line->current_y = INT32_MIN; sweep_line->last_y = INT32_MIN; - _pqueue_init (&sweep_line->stop); + sweep_line->fill_rule = fill_rule; + + pqueue_init (&sweep_line->pq); } static void -_cairo_bo_sweep_line_fini (cairo_bo_sweep_line_t *sweep_line) +sweep_line_fini (sweep_line_t *sweep_line) { - _pqueue_fini (&sweep_line->stop); + pqueue_fini (&sweep_line->pq); } -static inline cairo_bo_edge_t * -link_to_edge (cairo_list_t *elt) +static void +edge_end_box (sweep_line_t *sweep_line, + edge_t *left, + int32_t bot, + cairo_bool_t do_traps, + void *container) { - return cairo_container_of (elt, cairo_bo_edge_t, link); -} - -static cairo_status_t -_cairo_bo_edge_end_trap (cairo_bo_edge_t *left, - int32_t bot, - cairo_traps_t *traps) -{ - cairo_bo_trap_t *trap = &left->deferred_trap; + cairo_status_t status = CAIRO_STATUS_SUCCESS; /* Only emit (trivial) non-degenerate trapezoids with positive height. */ - if (likely (trap->top < bot)) { - cairo_line_t _left = { - { left->x, trap->top }, - { left->x, bot }, - }, _right = { - { trap->right->x, trap->top }, - { trap->right->x, bot }, - }; - _cairo_traps_add_trap (traps, trap->top, bot, &_left, &_right); + if (likely (left->top < bot)) { + if (do_traps) { + cairo_line_t _left = { + { left->x, left->top }, + { left->x, bot }, + }, _right = { + { left->right->x, left->top }, + { left->right->x, bot }, + }; + _cairo_traps_add_trap (container, left->top, bot, &_left, &_right); + status = _cairo_traps_status ((cairo_traps_t *) container); + } else { + cairo_box_t box; + + box.p1.x = left->x; + box.p1.y = left->top; + box.p2.x = left->right->x; + box.p2.y = bot; + + status = _cairo_boxes_add (container, &box); + } } + if (unlikely (status)) + longjmp (sweep_line->unwind, status); - trap->right = NULL; - - return _cairo_traps_status (traps); + left->right = NULL; } /* Start a new trapezoid at the given top y coordinate, whose edges @@ -314,75 +334,78 @@ _cairo_bo_edge_end_trap (cairo_bo_edge_t *left, * then either add it to the traps in `traps', if the trapezoid's * right edge differs from `edge->next', or do nothing if the new * trapezoid would be a continuation of the existing one. */ -static inline cairo_status_t -_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left, - cairo_bo_edge_t *right, - int top, - cairo_traps_t *traps) +static inline void +edge_start_or_continue_box (sweep_line_t *sweep_line, + edge_t *left, + edge_t *right, + int top, + cairo_bool_t do_traps, + void *container) { - cairo_status_t status; + if (left->right == right) + return; - if (left->deferred_trap.right == right) - return CAIRO_STATUS_SUCCESS; - - if (left->deferred_trap.right != NULL) { - if (right != NULL && left->deferred_trap.right->x == right->x) { + if (left->right != NULL) { + if (right != NULL && left->right->x == right->x) { /* continuation on right, so just swap edges */ - left->deferred_trap.right = right; - return CAIRO_STATUS_SUCCESS; + left->right = right; + return; } - status = _cairo_bo_edge_end_trap (left, top, traps); - if (unlikely (status)) - return status; + edge_end_box (sweep_line, + left, top, do_traps, container); } if (right != NULL && left->x != right->x) { - left->deferred_trap.top = top; - left->deferred_trap.right = right; + left->top = top; + left->right = right; } - - return CAIRO_STATUS_SUCCESS; } -static inline cairo_status_t -_active_edges_to_traps (cairo_bo_sweep_line_t *sweep, - cairo_fill_rule_t fill_rule, - cairo_traps_t *traps) +static inline void +active_edges_to_traps (sweep_line_t *sweep, + cairo_bool_t do_traps, + void *container) { int top = sweep->current_y; - cairo_list_t *pos = &sweep->sweep; - cairo_status_t status; + edge_t *pos; if (sweep->last_y == sweep->current_y) - return CAIRO_STATUS_SUCCESS; + return; - if (fill_rule == CAIRO_FILL_RULE_WINDING) { + pos = sweep->head.next; + if (pos == &sweep->tail) + return; + + if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING) { do { - cairo_bo_edge_t *left, *right; - int in_out; + edge_t *left, *right; + int winding; - pos = pos->next; - if (pos == &sweep->sweep) - break; + left = pos; + winding = left->dir; - left = link_to_edge (pos); - in_out = left->dir; + right = left->next; /* Check if there is a co-linear edge with an existing trap */ - if (left->deferred_trap.right == NULL) { - right = link_to_edge (pos->next); + if (left->right == NULL) { while (unlikely (right->x == left->x)) { - if (right->deferred_trap.right != NULL) { + winding += right->dir; + if (right->right != NULL) { /* continuation on left */ - left->deferred_trap = right->deferred_trap; - right->deferred_trap.right = NULL; + left->top = right->top; + left->right = right->right; + right->right = NULL; + winding -= right->dir; break; } - if (right->link.next == &sweep->sweep) - break; - right = link_to_edge (right->link.next); + right = right->next; + } + + if (winding == 0) { + pos = right; + continue; } } @@ -390,277 +413,238 @@ _active_edges_to_traps (cairo_bo_sweep_line_t *sweep, * maximal span width with the minimal number of trapezoids. */ - right = link_to_edge (left->link.next); do { /* End all subsumed traps */ - if (right->deferred_trap.right != NULL) { - status = _cairo_bo_edge_end_trap (right, top, traps); - if (unlikely (status)) - return status; + if (unlikely (right->right != NULL)) { + edge_end_box (sweep, + right, top, do_traps, container); } - in_out += right->dir; - if (in_out == 0) { + winding += right->dir; + if (winding == 0) { /* skip co-linear edges */ - if (likely (right->link.next == &sweep->sweep || - right->x != link_to_edge (right->link.next)->x)) - { + if (likely (right->x != right->next->x)) break; - } } - right = link_to_edge (right->link.next); + right = right->next; } while (TRUE); - status = _cairo_bo_edge_start_or_continue_trap (left, right, - top, traps); - if (unlikely (status)) - return status; + edge_start_or_continue_box (sweep, + left, right, top, + do_traps, container); - pos = &right->link; - } while (TRUE); + pos = right->next; + } while (pos != &sweep->tail); } else { - cairo_bo_edge_t *left, *right; do { - int in_out = 0; + edge_t *right = pos->next; + int count = 0; - pos = pos->next; - if (pos == &sweep->sweep) - break; - - left = link_to_edge (pos); - - pos = pos->next; do { - right = link_to_edge (pos); - if (right->deferred_trap.right != NULL) { - status = _cairo_bo_edge_end_trap (right, top, traps); - if (unlikely (status)) - return status; + /* End all subsumed traps */ + if (unlikely (right->right != NULL)) { + edge_end_box (sweep, + right, top, do_traps, container); } - if ((in_out++ & 1) == 0) { - cairo_list_t *next; - cairo_bool_t skip = FALSE; - + if (++count & 1) { /* skip co-linear edges */ - next = pos->next; - if (next != &sweep->sweep) - skip = right->x == link_to_edge (next)->x; - - if (! skip) + if (likely (right->x != right->next->x)) break; } - pos = pos->next; + + right = right->next; } while (TRUE); - right = pos == &sweep->sweep ? NULL : link_to_edge (pos); - status = _cairo_bo_edge_start_or_continue_trap (left, right, - top, traps); - if (unlikely (status)) - return status; - } while (right != NULL); + edge_start_or_continue_box (sweep, + pos, right, top, + do_traps, container); + + pos = right->next; + } while (pos != &sweep->tail); } sweep->last_y = sweep->current_y; - return CAIRO_STATUS_SUCCESS; } -static inline cairo_status_t -_cairo_bo_sweep_line_delete_edge (cairo_bo_sweep_line_t *sweep_line, - cairo_bo_edge_t *edge, - cairo_traps_t *traps) +static inline void +sweep_line_delete_edge (sweep_line_t *sweep_line, + edge_t *edge, + cairo_bool_t do_traps, + void *container) { - if (edge->deferred_trap.right != NULL) { - cairo_bo_edge_t *next = link_to_edge (edge->link.next); - if (&next->link != &sweep_line->sweep && next->x == edge->x) { - next->deferred_trap = edge->deferred_trap; + if (edge->right != NULL) { + edge_t *next = edge->next; + if (next->x == edge->x) { + next->top = edge->top; + next->right = edge->right; } else { - cairo_status_t status; - - status = _cairo_bo_edge_end_trap (edge, - sweep_line->current_y, - traps); - if (unlikely (status)) - return status; + edge_end_box (sweep_line, + edge, + sweep_line->current_y, + do_traps, container); } } - if (sweep_line->current_left == &edge->link) - sweep_line->current_left = edge->link.prev; + if (sweep_line->insert_left == edge) + sweep_line->insert_left = edge->next; + if (sweep_line->insert_right == edge) + sweep_line->insert_right = edge->next; - if (sweep_line->current_right == &edge->link) - sweep_line->current_right = edge->link.next; - - cairo_list_del (&edge->link); - - return CAIRO_STATUS_SUCCESS; + edge->prev->next = edge->next; + edge->next->prev = edge->prev; } -static inline cairo_status_t -_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line, - cairo_bo_rectangle_t *rectangle, - cairo_fill_rule_t fill_rule, - cairo_traps_t *traps) +static inline cairo_bool_t +sweep_line_delete (sweep_line_t *sweep, + rectangle_t *rectangle, + cairo_bool_t do_traps, + void *container) { - cairo_status_t status; + cairo_bool_t update; - if (rectangle->bottom != sweep_line->current_y) { - status = _active_edges_to_traps (sweep_line, fill_rule, traps); - if (unlikely (status)) - return status; - - sweep_line->current_y = rectangle->bottom; + update = TRUE; + if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING && + rectangle->left.prev->dir == rectangle->left.dir) + { + update = rectangle->left.next != &rectangle->right; } - status = _cairo_bo_sweep_line_delete_edge (sweep_line, - &rectangle->left, - traps); - if (unlikely (status)) - return status; + sweep_line_delete_edge (sweep, + &rectangle->left, + do_traps, container); - status = _cairo_bo_sweep_line_delete_edge (sweep_line, - &rectangle->right, - traps); - if (unlikely (status)) - return status; + sweep_line_delete_edge (sweep, + &rectangle->right, + do_traps, container); - _pqueue_pop (&sweep_line->stop); - return CAIRO_STATUS_SUCCESS; + pqueue_pop (&sweep->pq); + return update; } -static cairo_bool_t -validate_sweep_line (cairo_bo_sweep_line_t *sweep_line) +static inline void +insert_edge (edge_t *edge, edge_t *pos) { - int32_t last_x = INT32_MIN; - cairo_bo_edge_t *edge; - cairo_list_foreach_entry (edge, cairo_bo_edge_t, &sweep_line->sweep, link) { - if (edge->x < last_x) - return FALSE; - last_x = edge->x; - } - return TRUE; -} -static inline cairo_status_t -_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line, - cairo_bo_rectangle_t *rectangle, - cairo_fill_rule_t fill_rule, - cairo_traps_t *traps) -{ - cairo_list_t *pos; - cairo_status_t status; - - if (rectangle->top != sweep_line->current_y) { - cairo_bo_rectangle_t *stop; - - stop = _cairo_bo_rectangle_peek_stop (sweep_line); - while (stop != NULL && stop->bottom < rectangle->top) { - status = _cairo_bo_sweep_line_delete (sweep_line, stop, - fill_rule, traps); - if (unlikely (status)) - return status; - - stop = _cairo_bo_rectangle_peek_stop (sweep_line); + if (pos->x != edge->x) { + if (pos->x > edge->x) { + do { + UNROLL3({ + if (pos->prev->x <= edge->x) + break; + pos = pos->prev; + }) + } while (TRUE); + } else { + do { + UNROLL3({ + pos = pos->next; + if (pos->x >= edge->x) + break; + }) + } while (TRUE); } - - status = _active_edges_to_traps (sweep_line, fill_rule, traps); - if (unlikely (status)) - return status; - - sweep_line->current_y = rectangle->top; } + pos->prev->next = edge; + edge->prev = pos->prev; + edge->next = pos; + pos->prev = edge; +} + +static inline cairo_bool_t +sweep_line_insert (sweep_line_t *sweep, + rectangle_t *rectangle) +{ + edge_t *pos; + /* right edge */ - pos = sweep_line->current_right; - if (pos == &sweep_line->sweep) - pos = sweep_line->sweep.prev; - if (pos != &sweep_line->sweep) { - int cmp; - - cmp = link_to_edge (pos)->x - rectangle->right.x; - if (cmp < 0) { - while (pos->next != &sweep_line->sweep && - link_to_edge (pos->next)->x - rectangle->right.x < 0) - { - pos = pos->next; - } - } else if (cmp > 0) { - do { - pos = pos->prev; - } while (pos != &sweep_line->sweep && - link_to_edge (pos)->x - rectangle->right.x > 0); - } - - cairo_list_add (&rectangle->right.link, pos); - } else { - cairo_list_add_tail (&rectangle->right.link, pos); - } - sweep_line->current_right = &rectangle->right.link; - assert (validate_sweep_line (sweep_line)); + pos = sweep->insert_right; + insert_edge (&rectangle->right, pos); + sweep->insert_right = &rectangle->right; /* left edge */ - pos = sweep_line->current_left; - if (pos == &sweep_line->sweep) - pos = sweep_line->sweep.next; - if (pos != &sweep_line->sweep) { - int cmp; + pos = sweep->insert_left; + if (pos->x > sweep->insert_right->x) + pos = sweep->insert_right->prev; + insert_edge (&rectangle->left, pos); + sweep->insert_left = &rectangle->left; - if (link_to_edge (pos)->x >= rectangle->right.x) { - pos = rectangle->right.link.prev; - if (pos == &sweep_line->sweep) - goto left_done; - } + pqueue_push (sweep, rectangle); - cmp = link_to_edge (pos)->x - rectangle->left.x; - if (cmp < 0) { - while (pos->next != &sweep_line->sweep && - link_to_edge (pos->next)->x - rectangle->left.x < 0) - { - pos = pos->next; - } - } else if (cmp > 0) { - do { - pos = pos->prev; - } while (pos != &sweep_line->sweep && - link_to_edge (pos)->x - rectangle->left.x > 0); - } + if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING && + rectangle->left.prev->dir == rectangle->left.dir) + { + return rectangle->left.next != &rectangle->right; } - left_done: - cairo_list_add (&rectangle->left.link, pos); - sweep_line->current_left = &rectangle->left.link; - assert (validate_sweep_line (sweep_line)); - return _pqueue_push (&sweep_line->stop, rectangle); + return TRUE; } static cairo_status_t -_cairo_bentley_ottmann_tessellate_rectangular (cairo_bo_rectangle_t **rectangles, +_cairo_bentley_ottmann_tessellate_rectangular (rectangle_t **rectangles, int num_rectangles, cairo_fill_rule_t fill_rule, - cairo_traps_t *traps) + cairo_bool_t do_traps, + void *container) { - cairo_bo_sweep_line_t sweep_line; - cairo_bo_rectangle_t *rectangle; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + sweep_line_t sweep_line; + rectangle_t *rectangle; + cairo_status_t status; + cairo_bool_t update = FALSE; - _cairo_bo_sweep_line_init (&sweep_line, rectangles, num_rectangles); + sweep_line_init (&sweep_line, rectangles, num_rectangles, fill_rule); + if ((status = setjmp (sweep_line.unwind))) + goto unwind; - while ((rectangle = _cairo_bo_rectangle_pop_start (&sweep_line)) != NULL) { - status = _cairo_bo_sweep_line_insert (&sweep_line, rectangle, - fill_rule, traps); - if (unlikely (status)) - goto BAIL; + rectangle = rectangle_pop_start (&sweep_line); + do { + if (rectangle->top != sweep_line.current_y) { + rectangle_t *stop; + + stop = rectangle_peek_stop (&sweep_line); + while (stop != NULL && stop->bottom < rectangle->top) { + if (stop->bottom != sweep_line.current_y) { + if (update) { + active_edges_to_traps (&sweep_line, + do_traps, container); + update = FALSE; + } + + sweep_line.current_y = stop->bottom; + } + + update |= sweep_line_delete (&sweep_line, stop, do_traps, container); + + stop = rectangle_peek_stop (&sweep_line); + } + + if (update) { + active_edges_to_traps (&sweep_line, do_traps, container); + update = FALSE; + } + + sweep_line.current_y = rectangle->top; + } + + update |= sweep_line_insert (&sweep_line, rectangle); + } while ((rectangle = rectangle_pop_start (&sweep_line)) != NULL); + + while ((rectangle = rectangle_peek_stop (&sweep_line)) != NULL) { + if (rectangle->bottom != sweep_line.current_y) { + if (update) { + active_edges_to_traps (&sweep_line, do_traps, container); + update = FALSE; + } + + sweep_line.current_y = rectangle->bottom; + } + + update |= sweep_line_delete (&sweep_line, rectangle, do_traps, container); } - while ((rectangle = _cairo_bo_rectangle_peek_stop (&sweep_line)) != NULL) { - status = _cairo_bo_sweep_line_delete (&sweep_line, rectangle, - fill_rule, traps); - if (unlikely (status)) - goto BAIL; - } - -BAIL: - _cairo_bo_sweep_line_fini (&sweep_line); +unwind: + sweep_line_fini (&sweep_line); return status; } @@ -668,14 +652,14 @@ cairo_status_t _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps, cairo_fill_rule_t fill_rule) { - cairo_bo_rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_rectangle_t)]; - cairo_bo_rectangle_t *rectangles; - cairo_bo_rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1]; - cairo_bo_rectangle_t **rectangles_ptrs; + rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)]; + rectangle_t *rectangles; + rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1]; + rectangle_t **rectangles_ptrs; cairo_status_t status; int i; - if (unlikely (traps->num_traps == 0)) + if (unlikely (traps->num_traps <= 1)) return CAIRO_STATUS_SUCCESS; assert (traps->is_rectangular); @@ -686,13 +670,13 @@ _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps, rectangles_ptrs = stack_rectangles_ptrs; if (traps->num_traps > ARRAY_LENGTH (stack_rectangles)) { rectangles = _cairo_malloc_ab_plus_c (traps->num_traps, - sizeof (cairo_bo_rectangle_t) + - sizeof (cairo_bo_rectangle_t *), - sizeof (cairo_bo_rectangle_t *)); + sizeof (rectangle_t) + + sizeof (rectangle_t *), + sizeof (rectangle_t *)); if (unlikely (rectangles == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - rectangles_ptrs = (cairo_bo_rectangle_t **) (rectangles + traps->num_traps); + rectangles_ptrs = (rectangle_t **) (rectangles + traps->num_traps); } for (i = 0; i < traps->num_traps; i++) { @@ -710,11 +694,8 @@ _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps, rectangles[i].left.dir = -1; } - rectangles[i].left.deferred_trap.right = NULL; - cairo_list_init (&rectangles[i].left.link); - - rectangles[i].right.deferred_trap.right = NULL; - cairo_list_init (&rectangles[i].right.link); + rectangles[i].left.right = NULL; + rectangles[i].right.right = NULL; rectangles[i].top = traps->traps[i].top; rectangles[i].bottom = traps->traps[i].bottom; @@ -725,7 +706,7 @@ _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps, _cairo_traps_clear (traps); status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, i, fill_rule, - traps); + TRUE, traps); traps->is_rectilinear = TRUE; traps->is_rectangular = TRUE; @@ -734,6 +715,73 @@ _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps, dump_traps (traps, "bo-rects-traps-out.txt"); + return status; +} + +cairo_status_t +_cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in, + cairo_fill_rule_t fill_rule, + cairo_boxes_t *out) +{ + rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)]; + rectangle_t *rectangles; + rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1]; + rectangle_t **rectangles_ptrs; + const struct _cairo_boxes_chunk *chunk; + cairo_status_t status; + int i, j; + + if (unlikely (in->num_boxes <= 1)) + return CAIRO_STATUS_SUCCESS; + + rectangles = stack_rectangles; + rectangles_ptrs = stack_rectangles_ptrs; + if (in->num_boxes > ARRAY_LENGTH (stack_rectangles)) { + rectangles = _cairo_malloc_ab_plus_c (in->num_boxes, + sizeof (rectangle_t) + + sizeof (rectangle_t *), + sizeof (rectangle_t *)); + if (unlikely (rectangles == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + rectangles_ptrs = (rectangle_t **) (rectangles + in->num_boxes); + } + + j = 0; + for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *box = chunk->base; + for (i = 0; i < chunk->count; i++) { + if (box[i].p1.x < box[i].p2.x) { + rectangles[j].left.x = box[i].p1.x; + rectangles[j].left.dir = 1; + + rectangles[j].right.x = box[i].p2.x; + rectangles[j].right.dir = -1; + } else { + rectangles[j].right.x = box[i].p1.x; + rectangles[j].right.dir = 1; + + rectangles[j].left.x = box[i].p2.x; + rectangles[j].left.dir = -1; + } + + rectangles[j].left.right = NULL; + rectangles[j].right.right = NULL; + + rectangles[j].top = box[i].p1.y; + rectangles[j].bottom = box[i].p2.y; + + rectangles_ptrs[j] = &rectangles[j]; + j++; + } + } + + _cairo_boxes_clear (out); + status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, j, + fill_rule, + FALSE, out); + if (rectangles != stack_rectangles) + free (rectangles); return status; } diff --git a/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectilinear.c b/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectilinear.c index c7e738b6f6a1..1696d9367b61 100644 --- a/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectilinear.c +++ b/gfx/cairo/cairo/src/cairo-bentley-ottmann-rectilinear.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,7 +38,9 @@ /* Provide definitions for standalone compilation */ #include "cairoint.h" +#include "cairo-boxes-private.h" #include "cairo-combsort-private.h" +#include "cairo-error-private.h" typedef struct _cairo_bo_edge cairo_bo_edge_t; typedef struct _cairo_bo_trap cairo_bo_trap_t; @@ -215,20 +217,33 @@ edges_collinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b) static cairo_status_t _cairo_bo_edge_end_trap (cairo_bo_edge_t *left, int32_t bot, - cairo_traps_t *traps) + cairo_bool_t do_traps, + void *container) { cairo_bo_trap_t *trap = &left->deferred_trap; + cairo_status_t status = CAIRO_STATUS_SUCCESS; /* Only emit (trivial) non-degenerate trapezoids with positive height. */ if (likely (trap->top < bot)) { - _cairo_traps_add_trap (traps, - trap->top, bot, - &left->edge.line, &trap->right->edge.line); + if (do_traps) { + _cairo_traps_add_trap (container, + trap->top, bot, + &left->edge.line, &trap->right->edge.line); + status = _cairo_traps_status ((cairo_traps_t *) container); + } else { + cairo_box_t box; + + box.p1.x = left->edge.line.p1.x; + box.p1.y = trap->top; + box.p2.x = trap->right->edge.line.p1.x; + box.p2.y = bot; + status = _cairo_boxes_add (container, &box); + } } trap->right = NULL; - return _cairo_traps_status (traps); + return status; } /* Start a new trapezoid at the given top y coordinate, whose edges @@ -240,7 +255,8 @@ static inline cairo_status_t _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left, cairo_bo_edge_t *right, int top, - cairo_traps_t *traps) + cairo_bool_t do_traps, + void *container) { cairo_status_t status; @@ -255,7 +271,7 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left, return CAIRO_STATUS_SUCCESS; } - status = _cairo_bo_edge_end_trap (left, top, traps); + status = _cairo_bo_edge_end_trap (left, top, do_traps, container); if (unlikely (status)) return status; } @@ -272,7 +288,8 @@ static inline cairo_status_t _active_edges_to_traps (cairo_bo_edge_t *left, int32_t top, cairo_fill_rule_t fill_rule, - cairo_traps_t *traps) + cairo_bool_t do_traps, + void *container) { cairo_bo_edge_t *right; cairo_status_t status; @@ -303,7 +320,7 @@ _active_edges_to_traps (cairo_bo_edge_t *left, right = left->next; while (right != NULL) { if (right->deferred_trap.right != NULL) { - status = _cairo_bo_edge_end_trap (right, top, traps); + status = _cairo_bo_edge_end_trap (right, top, do_traps, container); if (unlikely (status)) return status; } @@ -321,8 +338,8 @@ _active_edges_to_traps (cairo_bo_edge_t *left, right = right->next; } - status = _cairo_bo_edge_start_or_continue_trap (left, right, - top, traps); + status = _cairo_bo_edge_start_or_continue_trap (left, right, top, + do_traps, container); if (unlikely (status)) return status; @@ -337,7 +354,7 @@ _active_edges_to_traps (cairo_bo_edge_t *left, right = left->next; while (right != NULL) { if (right->deferred_trap.right != NULL) { - status = _cairo_bo_edge_end_trap (right, top, traps); + status = _cairo_bo_edge_end_trap (right, top, do_traps, container); if (unlikely (status)) return status; } @@ -358,8 +375,8 @@ _active_edges_to_traps (cairo_bo_edge_t *left, right = right->next; } - status = _cairo_bo_edge_start_or_continue_trap (left, right, - top, traps); + status = _cairo_bo_edge_start_or_continue_trap (left, right, top, + do_traps, container); if (unlikely (status)) return status; @@ -376,7 +393,8 @@ static cairo_status_t _cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events, int num_events, cairo_fill_rule_t fill_rule, - cairo_traps_t *traps) + cairo_bool_t do_traps, + void *container) { cairo_bo_sweep_line_t sweep_line; cairo_bo_event_t *event; @@ -388,7 +406,7 @@ _cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events if (event->point.y != sweep_line.current_y) { status = _active_edges_to_traps (sweep_line.head, sweep_line.current_y, - fill_rule, traps); + fill_rule, do_traps, container); if (unlikely (status)) return status; @@ -406,7 +424,7 @@ _cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events if (event->edge->deferred_trap.right != NULL) { status = _cairo_bo_edge_end_trap (event->edge, sweep_line.current_y, - traps); + do_traps, container); if (unlikely (status)) return status; } @@ -476,7 +494,8 @@ _cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps, } status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j, - fill_rule, traps); + fill_rule, + TRUE, traps); if (events != stack_events) free (events); @@ -485,6 +504,72 @@ _cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps, return status; } +cairo_status_t +_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_boxes_t *boxes) +{ + cairo_status_t status; + cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)]; + cairo_bo_event_t *events; + cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1]; + cairo_bo_event_t **event_ptrs; + cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)]; + cairo_bo_edge_t *edges; + int num_events; + int i, j; + + if (unlikely (polygon->num_edges == 0)) + return CAIRO_STATUS_SUCCESS; + + num_events = 2 * polygon->num_edges; + + events = stack_events; + event_ptrs = stack_event_ptrs; + edges = stack_edges; + if (num_events > ARRAY_LENGTH (stack_events)) { + events = _cairo_malloc_ab_plus_c (num_events, + sizeof (cairo_bo_event_t) + + sizeof (cairo_bo_edge_t) + + sizeof (cairo_bo_event_t *), + sizeof (cairo_bo_event_t *)); + if (unlikely (events == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + event_ptrs = (cairo_bo_event_t **) (events + num_events); + edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1); + } + + for (i = j = 0; i < polygon->num_edges; i++) { + edges[i].edge = polygon->edges[i]; + edges[i].deferred_trap.right = NULL; + edges[i].prev = NULL; + edges[i].next = NULL; + + event_ptrs[j] = &events[j]; + events[j].type = CAIRO_BO_EVENT_TYPE_START; + events[j].point.y = polygon->edges[i].top; + events[j].point.x = polygon->edges[i].line.p1.x; + events[j].edge = &edges[i]; + j++; + + event_ptrs[j] = &events[j]; + events[j].type = CAIRO_BO_EVENT_TYPE_STOP; + events[j].point.y = polygon->edges[i].bottom; + events[j].point.x = polygon->edges[i].line.p1.x; + events[j].edge = &edges[i]; + j++; + } + + status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j, + fill_rule, + FALSE, boxes); + if (events != stack_events) + free (events); + + return status; +} + cairo_status_t _cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps, cairo_fill_rule_t fill_rule) @@ -572,7 +657,7 @@ _cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps, _cairo_traps_clear (traps); status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j, fill_rule, - traps); + TRUE, traps); traps->is_rectilinear = TRUE; if (events != stack_events) diff --git a/gfx/cairo/cairo/src/cairo-bentley-ottmann.c b/gfx/cairo/cairo/src/cairo-bentley-ottmann.c index cb508f518fe4..b3819f2f7faf 100644 --- a/gfx/cairo/cairo/src/cairo-bentley-ottmann.c +++ b/gfx/cairo/cairo/src/cairo-bentley-ottmann.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,6 +38,7 @@ /* Provide definitions for standalone compilation */ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-freelist-private.h" #include "cairo-combsort-private.h" @@ -129,21 +130,25 @@ static void dump_traps (cairo_traps_t *traps, const char *filename) { FILE *file; + cairo_box_t extents; int n; if (getenv ("CAIRO_DEBUG_TRAPS") == NULL) return; +#if 0 if (traps->has_limits) { printf ("%s: limits=(%d, %d, %d, %d)\n", filename, traps->limits.p1.x, traps->limits.p1.y, traps->limits.p2.x, traps->limits.p2.y); } +#endif + _cairo_traps_extents (traps, &extents); printf ("%s: extents=(%d, %d, %d, %d)\n", filename, - traps->extents.p1.x, traps->extents.p1.y, - traps->extents.p2.x, traps->extents.p2.y); + extents.p1.x, extents.p1.y, + extents.p2.x, extents.p2.y); file = fopen (filename, "a"); if (file != NULL) { diff --git a/gfx/cairo/cairo/src/cairo-beos.h b/gfx/cairo/cairo/src/cairo-beos.h index f53be5a7ef6e..fdb89a6c4dc9 100644 --- a/gfx/cairo/cairo/src/cairo-beos.h +++ b/gfx/cairo/cairo/src/cairo-beos.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-botor-scan-converter.c b/gfx/cairo/cairo/src/cairo-botor-scan-converter.c new file mode 100644 index 000000000000..0778a5dcd9d9 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-botor-scan-converter.c @@ -0,0 +1,2199 @@ +/* + * Copyright © 2004 Carl Worth + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2007 David Turner + * Copyright © 2008 M Joonas Pihlaja + * Copyright © 2008 Chris Wilson + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Carl Worth + * + * Contributor(s): + * Carl D. Worth + * M Joonas Pihlaja + * Chris Wilson + */ + +/* Provide definitions for standalone compilation */ +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-list-private.h" +#include "cairo-freelist-private.h" +#include "cairo-combsort-private.h" + +#include + +#define STEP_X CAIRO_FIXED_ONE +#define STEP_Y CAIRO_FIXED_ONE +#define UNROLL3(x) x x x + +#define STEP_XY (2*STEP_X*STEP_Y) /* Unit area in the step. */ +#define AREA_TO_ALPHA(c) (((c)*255 + STEP_XY/2) / STEP_XY) + +typedef struct _cairo_bo_intersect_ordinate { + int32_t ordinate; + enum { EXACT, INEXACT } exactness; +} cairo_bo_intersect_ordinate_t; + +typedef struct _cairo_bo_intersect_point { + cairo_bo_intersect_ordinate_t x; + cairo_bo_intersect_ordinate_t y; +} cairo_bo_intersect_point_t; + +struct quorem { + cairo_fixed_t quo; + cairo_fixed_t rem; +}; + +struct run { + struct run *next; + int sign; + cairo_fixed_t y; +}; + +typedef struct edge { + cairo_list_t link; + + cairo_edge_t edge; + + /* Current x coordinate and advancement. + * Initialised to the x coordinate of the top of the + * edge. The quotient is in cairo_fixed_t units and the + * remainder is mod dy in cairo_fixed_t units. + */ + cairo_fixed_t dy; + struct quorem x; + struct quorem dxdy; + struct quorem dxdy_full; + + cairo_bool_t vertical; + unsigned int flags; + + int current_sign; + struct run *runs; +} edge_t; + +enum { + START = 0x1, + STOP = 0x2, +}; + +/* the parent is always given by index/2 */ +#define PQ_PARENT_INDEX(i) ((i) >> 1) +#define PQ_FIRST_ENTRY 1 + +/* left and right children are index * 2 and (index * 2) +1 respectively */ +#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1) + +typedef enum { + EVENT_TYPE_STOP, + EVENT_TYPE_INTERSECTION, + EVENT_TYPE_START +} event_type_t; + +typedef struct _event { + cairo_fixed_t y; + event_type_t type; +} event_t; + +typedef struct _start_event { + cairo_fixed_t y; + event_type_t type; + edge_t *edge; +} start_event_t; + +typedef struct _queue_event { + cairo_fixed_t y; + event_type_t type; + edge_t *e1; + edge_t *e2; +} queue_event_t; + +typedef struct _pqueue { + int size, max_size; + + event_t **elements; + event_t *elements_embedded[1024]; +} pqueue_t; + +struct cell { + struct cell *prev; + struct cell *next; + int x; + int uncovered_area; + int covered_height; +}; + +typedef struct _sweep_line { + cairo_list_t active; + cairo_list_t stopped; + cairo_list_t *insert_cursor; + cairo_bool_t is_vertical; + + cairo_fixed_t current_row; + cairo_fixed_t current_subrow; + + struct coverage { + struct cell head; + struct cell tail; + + struct cell *cursor; + int count; + + cairo_freepool_t pool; + } coverage; + + struct event_queue { + pqueue_t pq; + event_t **start_events; + + cairo_freepool_t pool; + } queue; + + cairo_freepool_t runs; + + jmp_buf unwind; +} sweep_line_t; + +cairo_always_inline static struct quorem +floored_divrem (int a, int b) +{ + struct quorem qr; + qr.quo = a/b; + qr.rem = a%b; + if ((a^b)<0 && qr.rem) { + qr.quo--; + qr.rem += b; + } + return qr; +} + +static struct quorem +floored_muldivrem(int x, int a, int b) +{ + struct quorem qr; + long long xa = (long long)x*a; + qr.quo = xa/b; + qr.rem = xa%b; + if ((xa>=0) != (b>=0) && qr.rem) { + qr.quo--; + qr.rem += b; + } + return qr; +} + +static cairo_fixed_t +line_compute_intersection_x_for_y (const cairo_line_t *line, + cairo_fixed_t y) +{ + cairo_fixed_t x, dy; + + if (y == line->p1.y) + return line->p1.x; + if (y == line->p2.y) + return line->p2.x; + + x = line->p1.x; + dy = line->p2.y - line->p1.y; + if (dy != 0) { + x += _cairo_fixed_mul_div_floor (y - line->p1.y, + line->p2.x - line->p1.x, + dy); + } + + return x; +} + +/* + * We need to compare the x-coordinates of a pair of lines for a particular y, + * without loss of precision. + * + * The x-coordinate along an edge for a given y is: + * X = A_x + (Y - A_y) * A_dx / A_dy + * + * So the inequality we wish to test is: + * A_x + (Y - A_y) * A_dx / A_dy ∘ B_x + (Y - B_y) * B_dx / B_dy, + * where ∘ is our inequality operator. + * + * By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are + * all positive, so we can rearrange it thus without causing a sign change: + * A_dy * B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx * A_dy + * - (Y - A_y) * A_dx * B_dy + * + * Given the assumption that all the deltas fit within 32 bits, we can compute + * this comparison directly using 128 bit arithmetic. For certain, but common, + * input we can reduce this down to a single 32 bit compare by inspecting the + * deltas. + * + * (And put the burden of the work on developing fast 128 bit ops, which are + * required throughout the tessellator.) + * + * See the similar discussion for _slope_compare(). + */ +static int +edges_compare_x_for_y_general (const cairo_edge_t *a, + const cairo_edge_t *b, + int32_t y) +{ + /* XXX: We're assuming here that dx and dy will still fit in 32 + * bits. That's not true in general as there could be overflow. We + * should prevent that before the tessellation algorithm + * begins. + */ + int32_t dx; + int32_t adx, ady; + int32_t bdx, bdy; + enum { + HAVE_NONE = 0x0, + HAVE_DX = 0x1, + HAVE_ADX = 0x2, + HAVE_DX_ADX = HAVE_DX | HAVE_ADX, + HAVE_BDX = 0x4, + HAVE_DX_BDX = HAVE_DX | HAVE_BDX, + HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX, + HAVE_ALL = HAVE_DX | HAVE_ADX | HAVE_BDX + } have_dx_adx_bdx = HAVE_ALL; + + /* don't bother solving for abscissa if the edges' bounding boxes + * can be used to order them. */ + { + int32_t amin, amax; + int32_t bmin, bmax; + if (a->line.p1.x < a->line.p2.x) { + amin = a->line.p1.x; + amax = a->line.p2.x; + } else { + amin = a->line.p2.x; + amax = a->line.p1.x; + } + if (b->line.p1.x < b->line.p2.x) { + bmin = b->line.p1.x; + bmax = b->line.p2.x; + } else { + bmin = b->line.p2.x; + bmax = b->line.p1.x; + } + if (amax < bmin) return -1; + if (amin > bmax) return +1; + } + + ady = a->line.p2.y - a->line.p1.y; + adx = a->line.p2.x - a->line.p1.x; + if (adx == 0) + have_dx_adx_bdx &= ~HAVE_ADX; + + bdy = b->line.p2.y - b->line.p1.y; + bdx = b->line.p2.x - b->line.p1.x; + if (bdx == 0) + have_dx_adx_bdx &= ~HAVE_BDX; + + dx = a->line.p1.x - b->line.p1.x; + if (dx == 0) + have_dx_adx_bdx &= ~HAVE_DX; + +#define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx) +#define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->line.p1.y) +#define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->line.p1.y) + switch (have_dx_adx_bdx) { + default: + case HAVE_NONE: + return 0; + case HAVE_DX: + /* A_dy * B_dy * (A_x - B_x) ∘ 0 */ + return dx; /* ady * bdy is positive definite */ + case HAVE_ADX: + /* 0 ∘ - (Y - A_y) * A_dx * B_dy */ + return adx; /* bdy * (y - a->top.y) is positive definite */ + case HAVE_BDX: + /* 0 ∘ (Y - B_y) * B_dx * A_dy */ + return -bdx; /* ady * (y - b->top.y) is positive definite */ + case HAVE_ADX_BDX: + /* 0 ∘ (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */ + if ((adx ^ bdx) < 0) { + return adx; + } else if (a->line.p1.y == b->line.p1.y) { /* common origin */ + cairo_int64_t adx_bdy, bdx_ady; + + /* ∴ A_dx * B_dy ∘ B_dx * A_dy */ + + adx_bdy = _cairo_int32x32_64_mul (adx, bdy); + bdx_ady = _cairo_int32x32_64_mul (bdx, ady); + + return _cairo_int64_cmp (adx_bdy, bdx_ady); + } else + return _cairo_int128_cmp (A, B); + case HAVE_DX_ADX: + /* A_dy * (A_x - B_x) ∘ - (Y - A_y) * A_dx */ + if ((-adx ^ dx) < 0) { + return dx; + } else { + cairo_int64_t ady_dx, dy_adx; + + ady_dx = _cairo_int32x32_64_mul (ady, dx); + dy_adx = _cairo_int32x32_64_mul (a->line.p1.y - y, adx); + + return _cairo_int64_cmp (ady_dx, dy_adx); + } + case HAVE_DX_BDX: + /* B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx */ + if ((bdx ^ dx) < 0) { + return dx; + } else { + cairo_int64_t bdy_dx, dy_bdx; + + bdy_dx = _cairo_int32x32_64_mul (bdy, dx); + dy_bdx = _cairo_int32x32_64_mul (y - b->line.p1.y, bdx); + + return _cairo_int64_cmp (bdy_dx, dy_bdx); + } + case HAVE_ALL: + /* XXX try comparing (a->line.p2.x - b->line.p2.x) et al */ + return _cairo_int128_cmp (L, _cairo_int128_sub (B, A)); + } +#undef B +#undef A +#undef L +} + +/* + * We need to compare the x-coordinate of a line for a particular y wrt to a + * given x, without loss of precision. + * + * The x-coordinate along an edge for a given y is: + * X = A_x + (Y - A_y) * A_dx / A_dy + * + * So the inequality we wish to test is: + * A_x + (Y - A_y) * A_dx / A_dy ∘ X + * where ∘ is our inequality operator. + * + * By construction, we know that A_dy (and (Y - A_y)) are + * all positive, so we can rearrange it thus without causing a sign change: + * (Y - A_y) * A_dx ∘ (X - A_x) * A_dy + * + * Given the assumption that all the deltas fit within 32 bits, we can compute + * this comparison directly using 64 bit arithmetic. + * + * See the similar discussion for _slope_compare() and + * edges_compare_x_for_y_general(). + */ +static int +edge_compare_for_y_against_x (const cairo_edge_t *a, + int32_t y, + int32_t x) +{ + int32_t adx, ady; + int32_t dx, dy; + cairo_int64_t L, R; + + if (a->line.p1.x <= a->line.p2.x) { + if (x < a->line.p1.x) + return 1; + if (x > a->line.p2.x) + return -1; + } else { + if (x < a->line.p2.x) + return 1; + if (x > a->line.p1.x) + return -1; + } + + adx = a->line.p2.x - a->line.p1.x; + dx = x - a->line.p1.x; + + if (adx == 0) + return -dx; + if (dx == 0 || (adx ^ dx) < 0) + return adx; + + dy = y - a->line.p1.y; + ady = a->line.p2.y - a->line.p1.y; + + L = _cairo_int32x32_64_mul (dy, adx); + R = _cairo_int32x32_64_mul (dx, ady); + + return _cairo_int64_cmp (L, R); +} + +static int +edges_compare_x_for_y (const cairo_edge_t *a, + const cairo_edge_t *b, + int32_t y) +{ + /* If the sweep-line is currently on an end-point of a line, + * then we know its precise x value (and considering that we often need to + * compare events at end-points, this happens frequently enough to warrant + * special casing). + */ + enum { + HAVE_NEITHER = 0x0, + HAVE_AX = 0x1, + HAVE_BX = 0x2, + HAVE_BOTH = HAVE_AX | HAVE_BX + } have_ax_bx = HAVE_BOTH; + int32_t ax, bx; + + /* XXX given we have x and dx? */ + + if (y == a->line.p1.y) + ax = a->line.p1.x; + else if (y == a->line.p2.y) + ax = a->line.p2.x; + else + have_ax_bx &= ~HAVE_AX; + + if (y == b->line.p1.y) + bx = b->line.p1.x; + else if (y == b->line.p2.y) + bx = b->line.p2.x; + else + have_ax_bx &= ~HAVE_BX; + + switch (have_ax_bx) { + default: + case HAVE_NEITHER: + return edges_compare_x_for_y_general (a, b, y); + case HAVE_AX: + return -edge_compare_for_y_against_x (b, y, ax); + case HAVE_BX: + return edge_compare_for_y_against_x (a, y, bx); + case HAVE_BOTH: + return ax - bx; + } +} + +static inline int +slope_compare (const edge_t *a, + const edge_t *b) +{ + cairo_int64_t L, R; + int cmp; + + cmp = a->dxdy.quo - b->dxdy.quo; + if (cmp) + return cmp; + + if (a->dxdy.rem == 0) + return -b->dxdy.rem; + if (b->dxdy.rem == 0) + return a->dxdy.rem; + + L = _cairo_int32x32_64_mul (b->dy, a->dxdy.rem); + R = _cairo_int32x32_64_mul (a->dy, b->dxdy.rem); + return _cairo_int64_cmp (L, R); +} + +static inline int +line_equal (const cairo_line_t *a, const cairo_line_t *b) +{ + return a->p1.x == b->p1.x && a->p1.y == b->p1.y && + a->p2.x == b->p2.x && a->p2.y == b->p2.y; +} + +static inline int +sweep_line_compare_edges (const edge_t *a, + const edge_t *b, + cairo_fixed_t y) +{ + int cmp; + + if (line_equal (&a->edge.line, &b->edge.line)) + return 0; + + cmp = edges_compare_x_for_y (&a->edge, &b->edge, y); + if (cmp) + return cmp; + + return slope_compare (a, b); +} + +static inline cairo_int64_t +det32_64 (int32_t a, int32_t b, + int32_t c, int32_t d) +{ + /* det = a * d - b * c */ + return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d), + _cairo_int32x32_64_mul (b, c)); +} + +static inline cairo_int128_t +det64x32_128 (cairo_int64_t a, int32_t b, + cairo_int64_t c, int32_t d) +{ + /* det = a * d - b * c */ + return _cairo_int128_sub (_cairo_int64x32_128_mul (a, d), + _cairo_int64x32_128_mul (c, b)); +} + +/* Compute the intersection of two lines as defined by two edges. The + * result is provided as a coordinate pair of 128-bit integers. + * + * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or + * %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel. + */ +static cairo_bool_t +intersect_lines (const edge_t *a, const edge_t *b, + cairo_bo_intersect_point_t *intersection) +{ + cairo_int64_t a_det, b_det; + + /* XXX: We're assuming here that dx and dy will still fit in 32 + * bits. That's not true in general as there could be overflow. We + * should prevent that before the tessellation algorithm begins. + * What we're doing to mitigate this is to perform clamping in + * cairo_bo_tessellate_polygon(). + */ + int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x; + int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y; + + int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x; + int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y; + + cairo_int64_t den_det; + cairo_int64_t R; + cairo_quorem64_t qr; + + den_det = det32_64 (dx1, dy1, dx2, dy2); + + /* Q: Can we determine that the lines do not intersect (within range) + * much more cheaply than computing the intersection point i.e. by + * avoiding the division? + * + * X = ax + t * adx = bx + s * bdx; + * Y = ay + t * ady = by + s * bdy; + * ∴ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx) + * => t * L = R + * + * Therefore we can reject any intersection (under the criteria for + * valid intersection events) if: + * L^R < 0 => t < 0, or + * L t > 1 + * + * (where top/bottom must at least extend to the line endpoints). + * + * A similar substitution can be performed for s, yielding: + * s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by) + */ + R = det32_64 (dx2, dy2, + b->edge.line.p1.x - a->edge.line.p1.x, + b->edge.line.p1.y - a->edge.line.p1.y); + if (_cairo_int64_negative (den_det)) { + if (_cairo_int64_ge (den_det, R)) + return FALSE; + } else { + if (_cairo_int64_le (den_det, R)) + return FALSE; + } + + R = det32_64 (dy1, dx1, + a->edge.line.p1.y - b->edge.line.p1.y, + a->edge.line.p1.x - b->edge.line.p1.x); + if (_cairo_int64_negative (den_det)) { + if (_cairo_int64_ge (den_det, R)) + return FALSE; + } else { + if (_cairo_int64_le (den_det, R)) + return FALSE; + } + + /* We now know that the two lines should intersect within range. */ + + a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y, + a->edge.line.p2.x, a->edge.line.p2.y); + b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y, + b->edge.line.p2.x, b->edge.line.p2.y); + + /* x = det (a_det, dx1, b_det, dx2) / den_det */ + qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1, + b_det, dx2), + den_det); + if (_cairo_int64_eq (qr.rem, den_det)) + return FALSE; +#if 0 + intersection->x.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT; +#else + intersection->x.exactness = EXACT; + if (! _cairo_int64_is_zero (qr.rem)) { + if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem)) + qr.rem = _cairo_int64_negate (qr.rem); + qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2)); + if (_cairo_int64_ge (qr.rem, den_det)) { + qr.quo = _cairo_int64_add (qr.quo, + _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1)); + } else + intersection->x.exactness = INEXACT; + } +#endif + intersection->x.ordinate = _cairo_int64_to_int32 (qr.quo); + + /* y = det (a_det, dy1, b_det, dy2) / den_det */ + qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1, + b_det, dy2), + den_det); + if (_cairo_int64_eq (qr.rem, den_det)) + return FALSE; +#if 0 + intersection->y.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT; +#else + intersection->y.exactness = EXACT; + if (! _cairo_int64_is_zero (qr.rem)) { + /* compute ceiling away from zero */ + qr.quo = _cairo_int64_add (qr.quo, + _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1)); + intersection->y.exactness = INEXACT; + } +#endif + intersection->y.ordinate = _cairo_int64_to_int32 (qr.quo); + + return TRUE; +} + +static int +bo_intersect_ordinate_32_compare (int32_t a, int32_t b, int exactness) +{ + int cmp; + + /* First compare the quotient */ + cmp = a - b; + if (cmp) + return cmp; + + /* With quotient identical, if remainder is 0 then compare equal */ + /* Otherwise, the non-zero remainder makes a > b */ + return -(INEXACT == exactness); +} + +/* Does the given edge contain the given point. The point must already + * be known to be contained within the line determined by the edge, + * (most likely the point results from an intersection of this edge + * with another). + * + * If we had exact arithmetic, then this function would simply be a + * matter of examining whether the y value of the point lies within + * the range of y values of the edge. But since intersection points + * are not exact due to being rounded to the nearest integer within + * the available precision, we must also examine the x value of the + * point. + * + * The definition of "contains" here is that the given intersection + * point will be seen by the sweep line after the start event for the + * given edge and before the stop event for the edge. See the comments + * in the implementation for more details. + */ +static cairo_bool_t +bo_edge_contains_intersect_point (const edge_t *edge, + cairo_bo_intersect_point_t *point) +{ + int cmp_top, cmp_bottom; + + /* XXX: When running the actual algorithm, we don't actually need to + * compare against edge->top at all here, since any intersection above + * top is eliminated early via a slope comparison. We're leaving these + * here for now only for the sake of the quadratic-time intersection + * finder which needs them. + */ + + cmp_top = bo_intersect_ordinate_32_compare (point->y.ordinate, + edge->edge.top, + point->y.exactness); + if (cmp_top < 0) + return FALSE; + + cmp_bottom = bo_intersect_ordinate_32_compare (point->y.ordinate, + edge->edge.bottom, + point->y.exactness); + if (cmp_bottom > 0) + return FALSE; + + if (cmp_top > 0 && cmp_bottom < 0) + return TRUE; + + /* At this stage, the point lies on the same y value as either + * edge->top or edge->bottom, so we have to examine the x value in + * order to properly determine containment. */ + + /* If the y value of the point is the same as the y value of the + * top of the edge, then the x value of the point must be greater + * to be considered as inside the edge. Similarly, if the y value + * of the point is the same as the y value of the bottom of the + * edge, then the x value of the point must be less to be + * considered as inside. */ + + if (cmp_top == 0) { + cairo_fixed_t top_x; + + top_x = line_compute_intersection_x_for_y (&edge->edge.line, + edge->edge.top); + return bo_intersect_ordinate_32_compare (top_x, point->x.ordinate, point->x.exactness) < 0; + } else { /* cmp_bottom == 0 */ + cairo_fixed_t bot_x; + + bot_x = line_compute_intersection_x_for_y (&edge->edge.line, + edge->edge.bottom); + return bo_intersect_ordinate_32_compare (point->x.ordinate, bot_x, point->x.exactness) < 0; + } +} + +static cairo_bool_t +edge_intersect (const edge_t *a, + const edge_t *b, + cairo_point_t *intersection) +{ + cairo_bo_intersect_point_t quorem; + + if (! intersect_lines (a, b, &quorem)) + return FALSE; + + if (a->edge.top != a->edge.line.p1.y || a->edge.bottom != a->edge.line.p2.y) { + if (! bo_edge_contains_intersect_point (a, &quorem)) + return FALSE; + } + + if (b->edge.top != b->edge.line.p1.y || b->edge.bottom != b->edge.line.p2.y) { + if (! bo_edge_contains_intersect_point (b, &quorem)) + return FALSE; + } + + /* Now that we've correctly compared the intersection point and + * determined that it lies within the edge, then we know that we + * no longer need any more bits of storage for the intersection + * than we do for our edge coordinates. We also no longer need the + * remainder from the division. */ + intersection->x = quorem.x.ordinate; + intersection->y = quorem.y.ordinate; + + return TRUE; +} + +static inline int +event_compare (const event_t *a, const event_t *b) +{ + return a->y - b->y; +} + +static void +pqueue_init (pqueue_t *pq) +{ + pq->max_size = ARRAY_LENGTH (pq->elements_embedded); + pq->size = 0; + + pq->elements = pq->elements_embedded; +} + +static void +pqueue_fini (pqueue_t *pq) +{ + if (pq->elements != pq->elements_embedded) + free (pq->elements); +} + +static cairo_bool_t +pqueue_grow (pqueue_t *pq) +{ + event_t **new_elements; + pq->max_size *= 2; + + if (pq->elements == pq->elements_embedded) { + new_elements = _cairo_malloc_ab (pq->max_size, + sizeof (event_t *)); + if (unlikely (new_elements == NULL)) + return FALSE; + + memcpy (new_elements, pq->elements_embedded, + sizeof (pq->elements_embedded)); + } else { + new_elements = _cairo_realloc_ab (pq->elements, + pq->max_size, + sizeof (event_t *)); + if (unlikely (new_elements == NULL)) + return FALSE; + } + + pq->elements = new_elements; + return TRUE; +} + +static inline void +pqueue_push (sweep_line_t *sweep_line, event_t *event) +{ + event_t **elements; + int i, parent; + + if (unlikely (sweep_line->queue.pq.size + 1 == sweep_line->queue.pq.max_size)) { + if (unlikely (! pqueue_grow (&sweep_line->queue.pq))) { + longjmp (sweep_line->unwind, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + } + + elements = sweep_line->queue.pq.elements; + for (i = ++sweep_line->queue.pq.size; + i != PQ_FIRST_ENTRY && + event_compare (event, + elements[parent = PQ_PARENT_INDEX (i)]) < 0; + i = parent) + { + elements[i] = elements[parent]; + } + + elements[i] = event; +} + +static inline void +pqueue_pop (pqueue_t *pq) +{ + event_t **elements = pq->elements; + event_t *tail; + int child, i; + + tail = elements[pq->size--]; + if (pq->size == 0) { + elements[PQ_FIRST_ENTRY] = NULL; + return; + } + + for (i = PQ_FIRST_ENTRY; + (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size; + i = child) + { + if (child != pq->size && + event_compare (elements[child+1], + elements[child]) < 0) + { + child++; + } + + if (event_compare (elements[child], tail) >= 0) + break; + + elements[i] = elements[child]; + } + elements[i] = tail; +} + +static inline void +event_insert (sweep_line_t *sweep_line, + event_type_t type, + edge_t *e1, + edge_t *e2, + cairo_fixed_t y) +{ + queue_event_t *event; + + event = _cairo_freepool_alloc (&sweep_line->queue.pool); + if (unlikely (event == NULL)) { + longjmp (sweep_line->unwind, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + event->y = y; + event->type = type; + event->e1 = e1; + event->e2 = e2; + + pqueue_push (sweep_line, (event_t *) event); +} + +static void +event_delete (sweep_line_t *sweep_line, + event_t *event) +{ + _cairo_freepool_free (&sweep_line->queue.pool, event); +} + +static inline event_t * +event_next (sweep_line_t *sweep_line) +{ + event_t *event, *cmp; + + event = sweep_line->queue.pq.elements[PQ_FIRST_ENTRY]; + cmp = *sweep_line->queue.start_events; + if (event == NULL || + (cmp != NULL && event_compare (cmp, event) < 0)) + { + event = cmp; + sweep_line->queue.start_events++; + } + else + { + pqueue_pop (&sweep_line->queue.pq); + } + + return event; +} + +CAIRO_COMBSORT_DECLARE (start_event_sort, event_t *, event_compare) + +static inline void +event_insert_stop (sweep_line_t *sweep_line, + edge_t *edge) +{ + event_insert (sweep_line, + EVENT_TYPE_STOP, + edge, NULL, + edge->edge.bottom); +} + +static inline void +event_insert_if_intersect_below_current_y (sweep_line_t *sweep_line, + edge_t *left, + edge_t *right) +{ + cairo_point_t intersection; + + /* start points intersect */ + if (left->edge.line.p1.x == right->edge.line.p1.x && + left->edge.line.p1.y == right->edge.line.p1.y) + { + return; + } + + /* end points intersect, process DELETE events first */ + if (left->edge.line.p2.x == right->edge.line.p2.x && + left->edge.line.p2.y == right->edge.line.p2.y) + { + return; + } + + if (slope_compare (left, right) <= 0) + return; + + if (! edge_intersect (left, right, &intersection)) + return; + + event_insert (sweep_line, + EVENT_TYPE_INTERSECTION, + left, right, + intersection.y); +} + +static inline edge_t * +link_to_edge (cairo_list_t *link) +{ + return (edge_t *) link; +} + +static void +sweep_line_insert (sweep_line_t *sweep_line, + edge_t *edge) +{ + cairo_list_t *pos; + cairo_fixed_t y = sweep_line->current_subrow; + + pos = sweep_line->insert_cursor; + if (pos == &sweep_line->active) + pos = sweep_line->active.next; + if (pos != &sweep_line->active) { + int cmp; + + cmp = sweep_line_compare_edges (link_to_edge (pos), + edge, + y); + if (cmp < 0) { + while (pos->next != &sweep_line->active && + sweep_line_compare_edges (link_to_edge (pos->next), + edge, + y) < 0) + { + pos = pos->next; + } + } else if (cmp > 0) { + do { + pos = pos->prev; + } while (pos != &sweep_line->active && + sweep_line_compare_edges (link_to_edge (pos), + edge, + y) > 0); + } + } + cairo_list_add (&edge->link, pos); + sweep_line->insert_cursor = &edge->link; +} + +inline static void +coverage_rewind (struct coverage *cells) +{ + cells->cursor = &cells->head; +} + +static void +coverage_init (struct coverage *cells) +{ + _cairo_freepool_init (&cells->pool, + sizeof (struct cell)); + cells->head.prev = NULL; + cells->head.next = &cells->tail; + cells->head.x = INT_MIN; + cells->tail.prev = &cells->head; + cells->tail.next = NULL; + cells->tail.x = INT_MAX; + cells->count = 0; + coverage_rewind (cells); +} + +static void +coverage_fini (struct coverage *cells) +{ + _cairo_freepool_fini (&cells->pool); +} + +inline static void +coverage_reset (struct coverage *cells) +{ + cells->head.next = &cells->tail; + cells->tail.prev = &cells->head; + cells->count = 0; + _cairo_freepool_reset (&cells->pool); + coverage_rewind (cells); +} + +inline static struct cell * +coverage_alloc (sweep_line_t *sweep_line, + struct cell *tail, + int x) +{ + struct cell *cell; + + cell = _cairo_freepool_alloc (&sweep_line->coverage.pool); + if (unlikely (NULL == cell)) { + longjmp (sweep_line->unwind, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + tail->prev->next = cell; + cell->prev = tail->prev; + cell->next = tail; + tail->prev = cell; + cell->x = x; + cell->uncovered_area = 0; + cell->covered_height = 0; + sweep_line->coverage.count++; + return cell; +} + +inline static struct cell * +coverage_find (sweep_line_t *sweep_line, int x) +{ + struct cell *cell; + + cell = sweep_line->coverage.cursor; + if (unlikely (cell->x > x)) { + do { + if (cell->prev->x < x) + break; + cell = cell->prev; + } while (TRUE); + } else { + if (cell->x == x) + return cell; + + do { + UNROLL3({ + cell = cell->next; + if (cell->x >= x) + break; + }); + } while (TRUE); + } + + if (cell->x != x) + cell = coverage_alloc (sweep_line, cell, x); + + return sweep_line->coverage.cursor = cell; +} + +static void +coverage_render_cells (sweep_line_t *sweep_line, + cairo_fixed_t left, cairo_fixed_t right, + cairo_fixed_t y1, cairo_fixed_t y2, + int sign) +{ + int fx1, fx2; + int ix1, ix2; + int dx, dy; + + /* Orient the edge left-to-right. */ + dx = right - left; + if (dx >= 0) { + ix1 = _cairo_fixed_integer_part (left); + fx1 = _cairo_fixed_fractional_part (left); + + ix2 = _cairo_fixed_integer_part (right); + fx2 = _cairo_fixed_fractional_part (right); + + dy = y2 - y1; + } else { + ix1 = _cairo_fixed_integer_part (right); + fx1 = _cairo_fixed_fractional_part (right); + + ix2 = _cairo_fixed_integer_part (left); + fx2 = _cairo_fixed_fractional_part (left); + + dx = -dx; + sign = -sign; + dy = y1 - y2; + y1 = y2 - dy; + y2 = y1 + dy; + } + + /* Add coverage for all pixels [ix1,ix2] on this row crossed + * by the edge. */ + { + struct quorem y = floored_divrem ((STEP_X - fx1)*dy, dx); + struct cell *cell; + + cell = sweep_line->coverage.cursor; + if (cell->x != ix1) { + if (unlikely (cell->x > ix1)) { + do { + if (cell->prev->x < ix1) + break; + cell = cell->prev; + } while (TRUE); + } else do { + UNROLL3({ + if (cell->x >= ix1) + break; + cell = cell->next; + }); + } while (TRUE); + + if (cell->x != ix1) + cell = coverage_alloc (sweep_line, cell, ix1); + } + + cell->uncovered_area += sign * y.quo * (STEP_X + fx1); + cell->covered_height += sign * y.quo; + y.quo += y1; + + cell = cell->next; + if (cell->x != ++ix1) + cell = coverage_alloc (sweep_line, cell, ix1); + if (ix1 < ix2) { + struct quorem dydx_full = floored_divrem (STEP_X*dy, dx); + + do { + cairo_fixed_t y_skip = dydx_full.quo; + y.rem += dydx_full.rem; + if (y.rem >= dx) { + ++y_skip; + y.rem -= dx; + } + + y.quo += y_skip; + + y_skip *= sign; + cell->covered_height += y_skip; + cell->uncovered_area += y_skip*STEP_X; + + cell = cell->next; + if (cell->x != ++ix1) + cell = coverage_alloc (sweep_line, cell, ix1); + } while (ix1 != ix2); + } + cell->uncovered_area += sign*(y2 - y.quo)*fx2; + cell->covered_height += sign*(y2 - y.quo); + sweep_line->coverage.cursor = cell; + } +} + +inline static void +full_inc_edge (edge_t *edge) +{ + edge->x.quo += edge->dxdy_full.quo; + edge->x.rem += edge->dxdy_full.rem; + if (edge->x.rem >= 0) { + ++edge->x.quo; + edge->x.rem -= edge->dy; + } +} + +static void +full_add_edge (sweep_line_t *sweep_line, edge_t *edge, int sign) +{ + struct cell *cell; + cairo_fixed_t x1, x2; + int ix1, ix2; + int frac; + + edge->current_sign = sign; + + ix1 = _cairo_fixed_integer_part (edge->x.quo); + + if (edge->vertical) { + frac = _cairo_fixed_fractional_part (edge->x.quo); + cell = coverage_find (sweep_line, ix1); + cell->covered_height += sign * STEP_Y; + cell->uncovered_area += sign * 2 * frac * STEP_Y; + return; + } + + x1 = edge->x.quo; + full_inc_edge (edge); + x2 = edge->x.quo; + + ix2 = _cairo_fixed_integer_part (edge->x.quo); + + /* Edge is entirely within a column? */ + if (likely (ix1 == ix2)) { + frac = _cairo_fixed_fractional_part (x1) + + _cairo_fixed_fractional_part (x2); + cell = coverage_find (sweep_line, ix1); + cell->covered_height += sign * STEP_Y; + cell->uncovered_area += sign * frac * STEP_Y; + return; + } + + coverage_render_cells (sweep_line, x1, x2, 0, STEP_Y, sign); +} + +static void +full_nonzero (sweep_line_t *sweep_line) +{ + cairo_list_t *pos; + + sweep_line->is_vertical = TRUE; + pos = sweep_line->active.next; + do { + edge_t *left = link_to_edge (pos), *right; + int winding = left->edge.dir; + + sweep_line->is_vertical &= left->vertical; + + pos = left->link.next; + do { + if (unlikely (pos == &sweep_line->active)) { + full_add_edge (sweep_line, left, +1); + return; + } + + right = link_to_edge (pos); + pos = pos->next; + sweep_line->is_vertical &= right->vertical; + + winding += right->edge.dir; + if (0 == winding) { + if (pos == &sweep_line->active || + link_to_edge (pos)->x.quo != right->x.quo) + { + break; + } + } + + if (! right->vertical) + full_inc_edge (right); + } while (TRUE); + + full_add_edge (sweep_line, left, +1); + full_add_edge (sweep_line, right, -1); + } while (pos != &sweep_line->active); +} + +static void +full_evenodd (sweep_line_t *sweep_line) +{ + cairo_list_t *pos; + + sweep_line->is_vertical = TRUE; + pos = sweep_line->active.next; + do { + edge_t *left = link_to_edge (pos), *right; + int winding = 0; + + sweep_line->is_vertical &= left->vertical; + + pos = left->link.next; + do { + if (pos == &sweep_line->active) { + full_add_edge (sweep_line, left, +1); + return; + } + + right = link_to_edge (pos); + pos = pos->next; + sweep_line->is_vertical &= right->vertical; + + if (++winding & 1) { + if (pos == &sweep_line->active || + link_to_edge (pos)->x.quo != right->x.quo) + { + break; + } + } + + if (! right->vertical) + full_inc_edge (right); + } while (TRUE); + + full_add_edge (sweep_line, left, +1); + full_add_edge (sweep_line, right, -1); + } while (pos != &sweep_line->active); +} + +static void +render_rows (cairo_botor_scan_converter_t *self, + sweep_line_t *sweep_line, + int y, int height, + cairo_span_renderer_t *renderer) +{ + cairo_half_open_span_t spans_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_half_open_span_t)]; + cairo_half_open_span_t *spans = spans_stack; + struct cell *cell; + int prev_x, cover; + int num_spans; + cairo_status_t status; + + if (unlikely (sweep_line->coverage.count == 0)) { + status = renderer->render_rows (renderer, y, height, NULL, 0); + if (unlikely (status)) + longjmp (sweep_line->unwind, status); + return; + } + + /* Allocate enough spans for the row. */ + + num_spans = 2*sweep_line->coverage.count+2; + if (unlikely (num_spans > ARRAY_LENGTH (spans_stack))) { + spans = _cairo_malloc_ab (num_spans, sizeof (cairo_half_open_span_t)); + if (unlikely (spans == NULL)) { + longjmp (sweep_line->unwind, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + } + + /* Form the spans from the coverage and areas. */ + num_spans = 0; + prev_x = self->xmin; + cover = 0; + cell = sweep_line->coverage.head.next; + do { + int x = cell->x; + int area; + + if (x > prev_x) { + spans[num_spans].x = prev_x; + spans[num_spans].coverage = AREA_TO_ALPHA (cover); + ++num_spans; + } + + cover += cell->covered_height*STEP_X*2; + area = cover - cell->uncovered_area; + + spans[num_spans].x = x; + spans[num_spans].coverage = AREA_TO_ALPHA (area); + ++num_spans; + + prev_x = x + 1; + } while ((cell = cell->next) != &sweep_line->coverage.tail); + + if (prev_x <= self->xmax) { + spans[num_spans].x = prev_x; + spans[num_spans].coverage = AREA_TO_ALPHA (cover); + ++num_spans; + } + + if (cover && prev_x < self->xmax) { + spans[num_spans].x = self->xmax; + spans[num_spans].coverage = 0; + ++num_spans; + } + + status = renderer->render_rows (renderer, y, height, spans, num_spans); + + if (unlikely (spans != spans_stack)) + free (spans); + + coverage_reset (&sweep_line->coverage); + + if (unlikely (status)) + longjmp (sweep_line->unwind, status); +} + +static void +full_repeat (sweep_line_t *sweep) +{ + edge_t *edge; + + cairo_list_foreach_entry (edge, edge_t, &sweep->active, link) { + if (edge->current_sign) + full_add_edge (sweep, edge, edge->current_sign); + else if (! edge->vertical) + full_inc_edge (edge); + } +} + +static void +full_reset (sweep_line_t *sweep) +{ + edge_t *edge; + + cairo_list_foreach_entry (edge, edge_t, &sweep->active, link) + edge->current_sign = 0; +} + +static void +full_step (cairo_botor_scan_converter_t *self, + sweep_line_t *sweep_line, + cairo_fixed_t row, + cairo_span_renderer_t *renderer) +{ + int top, bottom; + + top = _cairo_fixed_integer_part (sweep_line->current_row); + bottom = _cairo_fixed_integer_part (row); + if (cairo_list_is_empty (&sweep_line->active)) { + cairo_status_t status; + + status = renderer->render_rows (renderer, top, bottom - top, NULL, 0); + if (unlikely (status)) + longjmp (sweep_line->unwind, status); + + return; + } + + if (self->fill_rule == CAIRO_FILL_RULE_WINDING) + full_nonzero (sweep_line); + else + full_evenodd (sweep_line); + + if (sweep_line->is_vertical || bottom == top + 1) { + render_rows (self, sweep_line, top, bottom - top, renderer); + full_reset (sweep_line); + return; + } + + render_rows (self, sweep_line, top++, 1, renderer); + do { + full_repeat (sweep_line); + render_rows (self, sweep_line, top, 1, renderer); + } while (++top != bottom); + + full_reset (sweep_line); +} + +cairo_always_inline static void +sub_inc_edge (edge_t *edge, + cairo_fixed_t height) +{ + if (height == 1) { + edge->x.quo += edge->dxdy.quo; + edge->x.rem += edge->dxdy.rem; + if (edge->x.rem >= 0) { + ++edge->x.quo; + edge->x.rem -= edge->dy; + } + } else { + edge->x.quo += height * edge->dxdy.quo; + edge->x.rem += height * edge->dxdy.rem; + if (edge->x.rem >= 0) { + int carry = edge->x.rem / edge->dy + 1; + edge->x.quo += carry; + edge->x.rem -= carry * edge->dy; + } + } +} + +static void +sub_add_run (sweep_line_t *sweep_line, edge_t *edge, int y, int sign) +{ + struct run *run; + + run = _cairo_freepool_alloc (&sweep_line->runs); + if (unlikely (run == NULL)) + longjmp (sweep_line->unwind, _cairo_error (CAIRO_STATUS_NO_MEMORY)); + + run->y = y; + run->sign = sign; + run->next = edge->runs; + edge->runs = run; + + edge->current_sign = sign; +} + +inline static cairo_bool_t +edges_coincident (edge_t *left, edge_t *right, cairo_fixed_t y) +{ + /* XXX is compare_x_for_y() worth executing during sub steps? */ + return line_equal (&left->edge.line, &right->edge.line); + //edges_compare_x_for_y (&left->edge, &right->edge, y) >= 0; +} + +static void +sub_nonzero (sweep_line_t *sweep_line) +{ + cairo_fixed_t y = sweep_line->current_subrow; + cairo_fixed_t fy = _cairo_fixed_fractional_part (y); + cairo_list_t *pos; + + pos = sweep_line->active.next; + do { + edge_t *left = link_to_edge (pos), *right; + int winding = left->edge.dir; + + pos = left->link.next; + do { + if (unlikely (pos == &sweep_line->active)) { + if (left->current_sign != +1) + sub_add_run (sweep_line, left, fy, +1); + return; + } + + right = link_to_edge (pos); + pos = pos->next; + + winding += right->edge.dir; + if (0 == winding) { + if (pos == &sweep_line->active || + ! edges_coincident (right, link_to_edge (pos), y)) + { + break; + } + } + + if (right->current_sign) + sub_add_run (sweep_line, right, fy, 0); + } while (TRUE); + + if (left->current_sign != +1) + sub_add_run (sweep_line, left, fy, +1); + if (right->current_sign != -1) + sub_add_run (sweep_line, right, fy, -1); + } while (pos != &sweep_line->active); +} + +static void +sub_evenodd (sweep_line_t *sweep_line) +{ + cairo_fixed_t y = sweep_line->current_subrow; + cairo_fixed_t fy = _cairo_fixed_fractional_part (y); + cairo_list_t *pos; + + pos = sweep_line->active.next; + do { + edge_t *left = link_to_edge (pos), *right; + int winding = 0; + + pos = left->link.next; + do { + if (unlikely (pos == &sweep_line->active)) { + if (left->current_sign != +1) + sub_add_run (sweep_line, left, fy, +1); + return; + } + + right = link_to_edge (pos); + pos = pos->next; + + if (++winding & 1) { + if (pos == &sweep_line->active || + ! edges_coincident (right, link_to_edge (pos), y)) + { + break; + } + } + + if (right->current_sign) + sub_add_run (sweep_line, right, fy, 0); + } while (TRUE); + + if (left->current_sign != +1) + sub_add_run (sweep_line, left, fy, +1); + if (right->current_sign != -1) + sub_add_run (sweep_line, right, fy, -1); + } while (pos != &sweep_line->active); +} + +cairo_always_inline static void +sub_step (cairo_botor_scan_converter_t *self, + sweep_line_t *sweep_line) +{ + if (cairo_list_is_empty (&sweep_line->active)) + return; + + if (self->fill_rule == CAIRO_FILL_RULE_WINDING) + sub_nonzero (sweep_line); + else + sub_evenodd (sweep_line); +} + +static void +coverage_render_runs (sweep_line_t *sweep, edge_t *edge, + cairo_fixed_t y1, cairo_fixed_t y2) +{ + struct run tail; + struct run *run = &tail; + + tail.next = NULL; + tail.y = y2; + + /* Order the runs top->bottom */ + while (edge->runs) { + struct run *r; + + r = edge->runs; + edge->runs = r->next; + r->next = run; + run = r; + } + + if (run->y > y1) + sub_inc_edge (edge, run->y - y1); + + do { + cairo_fixed_t x1, x2; + + y1 = run->y; + y2 = run->next->y; + + x1 = edge->x.quo; + if (y2 - y1 == STEP_Y) + full_inc_edge (edge); + else + sub_inc_edge (edge, y2 - y1); + x2 = edge->x.quo; + + if (run->sign) { + int ix1, ix2; + + ix1 = _cairo_fixed_integer_part (x1); + ix2 = _cairo_fixed_integer_part (x2); + + /* Edge is entirely within a column? */ + if (likely (ix1 == ix2)) { + struct cell *cell; + int frac; + + frac = _cairo_fixed_fractional_part (x1) + + _cairo_fixed_fractional_part (x2); + cell = coverage_find (sweep, ix1); + cell->covered_height += run->sign * (y2 - y1); + cell->uncovered_area += run->sign * (y2 - y1) * frac; + } else { + coverage_render_cells (sweep, x1, x2, y1, y2, run->sign); + } + } + + run = run->next; + } while (run->next != NULL); +} + +static void +coverage_render_vertical_runs (sweep_line_t *sweep, edge_t *edge, cairo_fixed_t y2) +{ + struct cell *cell; + struct run *run; + int height = 0; + + for (run = edge->runs; run != NULL; run = run->next) { + if (run->sign) + height += run->sign * (y2 - run->y); + y2 = run->y; + } + + cell = coverage_find (sweep, _cairo_fixed_integer_part (edge->x.quo)); + cell->covered_height += height; + cell->uncovered_area += 2 * _cairo_fixed_fractional_part (edge->x.quo) * height; +} + +cairo_always_inline static void +sub_emit (cairo_botor_scan_converter_t *self, + sweep_line_t *sweep, + cairo_span_renderer_t *renderer) +{ + edge_t *edge; + + sub_step (self, sweep); + + /* convert the runs into coverages */ + + cairo_list_foreach_entry (edge, edge_t, &sweep->active, link) { + if (edge->runs == NULL) { + if (! edge->vertical) { + if (edge->flags & START) { + sub_inc_edge (edge, + STEP_Y - _cairo_fixed_fractional_part (edge->edge.top)); + edge->flags &= ~START; + } else + full_inc_edge (edge); + } + } else { + if (edge->vertical) { + coverage_render_vertical_runs (sweep, edge, STEP_Y); + } else { + int y1 = 0; + if (edge->flags & START) { + y1 = _cairo_fixed_fractional_part (edge->edge.top); + edge->flags &= ~START; + } + coverage_render_runs (sweep, edge, y1, STEP_Y); + } + } + edge->current_sign = 0; + edge->runs = NULL; + } + + cairo_list_foreach_entry (edge, edge_t, &sweep->stopped, link) { + int y2 = _cairo_fixed_fractional_part (edge->edge.bottom); + if (edge->vertical) { + coverage_render_vertical_runs (sweep, edge, y2); + } else { + int y1 = 0; + if (edge->flags & START) + y1 = _cairo_fixed_fractional_part (edge->edge.top); + coverage_render_runs (sweep, edge, y1, y2); + } + } + cairo_list_init (&sweep->stopped); + + _cairo_freepool_reset (&sweep->runs); + + render_rows (self, sweep, + _cairo_fixed_integer_part (sweep->current_row), 1, + renderer); +} + +static void +sweep_line_init (sweep_line_t *sweep_line, + event_t **start_events, + int num_events) +{ + cairo_list_init (&sweep_line->active); + cairo_list_init (&sweep_line->stopped); + sweep_line->insert_cursor = &sweep_line->active; + + sweep_line->current_row = INT32_MIN; + sweep_line->current_subrow = INT32_MIN; + + coverage_init (&sweep_line->coverage); + _cairo_freepool_init (&sweep_line->runs, sizeof (struct run)); + + start_event_sort (start_events, num_events); + start_events[num_events] = NULL; + + sweep_line->queue.start_events = start_events; + + _cairo_freepool_init (&sweep_line->queue.pool, + sizeof (queue_event_t)); + pqueue_init (&sweep_line->queue.pq); + sweep_line->queue.pq.elements[PQ_FIRST_ENTRY] = NULL; +} + +static void +sweep_line_delete (sweep_line_t *sweep_line, + edge_t *edge) +{ + if (sweep_line->insert_cursor == &edge->link) + sweep_line->insert_cursor = edge->link.prev; + + cairo_list_del (&edge->link); + if (edge->runs) + cairo_list_add_tail (&edge->link, &sweep_line->stopped); + edge->flags |= STOP; +} + +static void +sweep_line_swap (sweep_line_t *sweep_line, + edge_t *left, + edge_t *right) +{ + right->link.prev = left->link.prev; + left->link.next = right->link.next; + right->link.next = &left->link; + left->link.prev = &right->link; + left->link.next->prev = &left->link; + right->link.prev->next = &right->link; +} + +static void +sweep_line_fini (sweep_line_t *sweep_line) +{ + pqueue_fini (&sweep_line->queue.pq); + _cairo_freepool_fini (&sweep_line->queue.pool); + coverage_fini (&sweep_line->coverage); + _cairo_freepool_fini (&sweep_line->runs); +} + +static cairo_status_t +botor_generate (cairo_botor_scan_converter_t *self, + event_t **start_events, + cairo_span_renderer_t *renderer) +{ + cairo_status_t status; + sweep_line_t sweep_line; + cairo_fixed_t ybot; + event_t *event; + cairo_list_t *left, *right; + edge_t *e1, *e2; + int bottom; + + sweep_line_init (&sweep_line, start_events, self->num_edges); + if ((status = setjmp (sweep_line.unwind))) + goto unwind; + + ybot = self->extents.p2.y; + sweep_line.current_subrow = self->extents.p1.y; + sweep_line.current_row = _cairo_fixed_floor (self->extents.p1.y); + event = *sweep_line.queue.start_events++; + do { + /* Can we process a full step in one go? */ + if (event->y >= sweep_line.current_row + STEP_Y) { + bottom = _cairo_fixed_floor (event->y); + full_step (self, &sweep_line, bottom, renderer); + sweep_line.current_row = bottom; + sweep_line.current_subrow = bottom; + } + + do { + if (event->y > sweep_line.current_subrow) { + sub_step (self, &sweep_line); + sweep_line.current_subrow = event->y; + } + + do { + /* Update the active list using Bentley-Ottmann */ + switch (event->type) { + case EVENT_TYPE_START: + e1 = ((start_event_t *) event)->edge; + + sweep_line_insert (&sweep_line, e1); + event_insert_stop (&sweep_line, e1); + + left = e1->link.prev; + right = e1->link.next; + + if (left != &sweep_line.active) { + event_insert_if_intersect_below_current_y (&sweep_line, + link_to_edge (left), e1); + } + + if (right != &sweep_line.active) { + event_insert_if_intersect_below_current_y (&sweep_line, + e1, link_to_edge (right)); + } + + break; + + case EVENT_TYPE_STOP: + e1 = ((queue_event_t *) event)->e1; + event_delete (&sweep_line, event); + + left = e1->link.prev; + right = e1->link.next; + + sweep_line_delete (&sweep_line, e1); + + if (left != &sweep_line.active && + right != &sweep_line.active) + { + event_insert_if_intersect_below_current_y (&sweep_line, + link_to_edge (left), + link_to_edge (right)); + } + + break; + + case EVENT_TYPE_INTERSECTION: + e1 = ((queue_event_t *) event)->e1; + e2 = ((queue_event_t *) event)->e2; + + event_delete (&sweep_line, event); + if (e1->flags & STOP) + break; + if (e2->flags & STOP) + break; + + /* skip this intersection if its edges are not adjacent */ + if (&e2->link != e1->link.next) + break; + + left = e1->link.prev; + right = e2->link.next; + + sweep_line_swap (&sweep_line, e1, e2); + + /* after the swap e2 is left of e1 */ + if (left != &sweep_line.active) { + event_insert_if_intersect_below_current_y (&sweep_line, + link_to_edge (left), e2); + } + + if (right != &sweep_line.active) { + event_insert_if_intersect_below_current_y (&sweep_line, + e1, link_to_edge (right)); + } + + break; + } + + event = event_next (&sweep_line); + if (event == NULL) + goto end; + } while (event->y == sweep_line.current_subrow); + } while (event->y < sweep_line.current_row + STEP_Y); + + bottom = sweep_line.current_row + STEP_Y; + sub_emit (self, &sweep_line, renderer); + sweep_line.current_subrow = bottom; + sweep_line.current_row = sweep_line.current_subrow; + } while (TRUE); + + end: + /* flush any partial spans */ + if (sweep_line.current_subrow != sweep_line.current_row) { + sub_emit (self, &sweep_line, renderer); + sweep_line.current_row += STEP_Y; + sweep_line.current_subrow = sweep_line.current_row; + } + /* clear the rest */ + if (sweep_line.current_subrow < ybot) { + bottom = _cairo_fixed_integer_part (sweep_line.current_row); + status = renderer->render_rows (renderer, + bottom, _cairo_fixed_integer_ceil (ybot) - bottom, + NULL, 0); + } + + unwind: + sweep_line_fini (&sweep_line); + + return status; +} + +static cairo_status_t +_cairo_botor_scan_converter_generate (void *converter, + cairo_span_renderer_t *renderer) +{ + cairo_botor_scan_converter_t *self = converter; + start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (start_event_t)]; + start_event_t *events; + event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1]; + event_t **event_ptrs; + struct _cairo_botor_scan_converter_chunk *chunk; + cairo_status_t status; + int num_events; + int i, j; + + num_events = self->num_edges; + if (unlikely (0 == num_events)) { + return renderer->render_rows (renderer, + _cairo_fixed_integer_floor (self->extents.p1.y), + _cairo_fixed_integer_ceil (self->extents.p2.y) - + _cairo_fixed_integer_floor (self->extents.p1.y), + NULL, 0); + } + + events = stack_events; + event_ptrs = stack_event_ptrs; + if (unlikely (num_events >= ARRAY_LENGTH (stack_events))) { + events = _cairo_malloc_ab_plus_c (num_events, + sizeof (start_event_t) + sizeof (event_t *), + sizeof (event_t *)); + if (unlikely (events == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + event_ptrs = (event_t **) (events + num_events); + } + + j = 0; + for (chunk = &self->chunks; chunk != NULL; chunk = chunk->next) { + edge_t *edge; + + edge = chunk->base; + for (i = 0; i < chunk->count; i++) { + event_ptrs[j] = (event_t *) &events[j]; + + events[j].y = edge->edge.top; + events[j].type = EVENT_TYPE_START; + events[j].edge = edge; + + edge++, j++; + } + } + + status = botor_generate (self, event_ptrs, renderer); + + if (events != stack_events) + free (events); + + return status; +} + +static edge_t * +botor_allocate_edge (cairo_botor_scan_converter_t *self) +{ + struct _cairo_botor_scan_converter_chunk *chunk; + + chunk = self->tail; + if (chunk->count == chunk->size) { + int size; + + size = chunk->size * 2; + chunk->next = _cairo_malloc_ab_plus_c (size, + sizeof (edge_t), + sizeof (struct _cairo_botor_scan_converter_chunk)); + if (unlikely (chunk->next == NULL)) + return NULL; + + chunk = chunk->next; + chunk->next = NULL; + chunk->count = 0; + chunk->size = size; + chunk->base = chunk + 1; + self->tail = chunk; + } + + return (edge_t *) chunk->base + chunk->count++; +} + +static cairo_status_t +botor_add_edge (cairo_botor_scan_converter_t *self, + const cairo_edge_t *edge) +{ + edge_t *e; + cairo_fixed_t dx, dy; + + e = botor_allocate_edge (self); + if (unlikely (e == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + cairo_list_init (&e->link); + e->edge = *edge; + + dx = edge->line.p2.x - edge->line.p1.x; + dy = edge->line.p2.y - edge->line.p1.y; + e->dy = dy; + + if (dx == 0) { + e->vertical = TRUE; + e->x.quo = edge->line.p1.x; + e->x.rem = 0; + e->dxdy.quo = 0; + e->dxdy.rem = 0; + e->dxdy_full.quo = 0; + e->dxdy_full.rem = 0; + } else { + e->vertical = FALSE; + e->dxdy = floored_divrem (dx, dy); + if (edge->top == edge->line.p1.y) { + e->x.quo = edge->line.p1.x; + e->x.rem = 0; + } else { + e->x = floored_muldivrem (edge->top - edge->line.p1.y, + dx, dy); + e->x.quo += edge->line.p1.x; + } + + if (_cairo_fixed_integer_part (edge->bottom) - _cairo_fixed_integer_part (edge->top) > 1) { + e->dxdy_full = floored_muldivrem (STEP_Y, dx, dy); + } else { + e->dxdy_full.quo = 0; + e->dxdy_full.rem = 0; + } + } + + e->x.rem = -e->dy; + e->current_sign = 0; + e->runs = NULL; + e->flags = START; + + self->num_edges++; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_botor_scan_converter_add_edge (void *converter, + const cairo_point_t *p1, + const cairo_point_t *p2, + int top, int bottom, + int dir) +{ + cairo_botor_scan_converter_t *self = converter; + cairo_edge_t edge; + + edge.line.p1 = *p1; + edge.line.p2 = *p2; + edge.top = top; + edge.bottom = bottom; + edge.dir = dir; + + return botor_add_edge (self, &edge); +} + +static cairo_status_t +_cairo_botor_scan_converter_add_polygon (void *converter, + const cairo_polygon_t *polygon) +{ + cairo_botor_scan_converter_t *self = converter; + cairo_status_t status; + int i; + + for (i = 0; i < polygon->num_edges; i++) { + status = botor_add_edge (self, &polygon->edges[i]); + if (unlikely (status)) + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_botor_scan_converter_destroy (void *converter) +{ + cairo_botor_scan_converter_t *self = converter; + struct _cairo_botor_scan_converter_chunk *chunk, *next; + + for (chunk = self->chunks.next; chunk != NULL; chunk = next) { + next = chunk->next; + free (chunk); + } +} + +void +_cairo_botor_scan_converter_init (cairo_botor_scan_converter_t *self, + const cairo_box_t *extents, + cairo_fill_rule_t fill_rule) +{ + self->base.destroy = _cairo_botor_scan_converter_destroy; + self->base.add_edge = _cairo_botor_scan_converter_add_edge; + self->base.add_polygon = _cairo_botor_scan_converter_add_polygon; + self->base.generate = _cairo_botor_scan_converter_generate; + + self->extents = *extents; + self->fill_rule = fill_rule; + + self->xmin = _cairo_fixed_integer_floor (extents->p1.x); + self->xmax = _cairo_fixed_integer_ceil (extents->p2.x); + + self->chunks.base = self->buf; + self->chunks.next = NULL; + self->chunks.count = 0; + self->chunks.size = sizeof (self->buf) / sizeof (edge_t); + self->tail = &self->chunks; + + self->num_edges = 0; +} diff --git a/gfx/cairo/cairo/src/cairo-boxes-private.h b/gfx/cairo/cairo/src/cairo-boxes-private.h new file mode 100644 index 000000000000..3af0fbdefe7f --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-boxes-private.h @@ -0,0 +1,84 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_BOXES_H +#define CAIRO_BOXES_H + +#include "cairo-types-private.h" +#include "cairo-compiler-private.h" + +struct _cairo_boxes_t { + cairo_status_t status; + cairo_box_t limit; + const cairo_box_t *limits; + int num_limits; + int num_boxes; + unsigned int is_pixel_aligned : 1; + + struct _cairo_boxes_chunk { + struct _cairo_boxes_chunk *next; + cairo_box_t *base; + int count; + int size; + } chunks, *tail; + cairo_box_t boxes_embedded[32]; +}; + +cairo_private void +_cairo_boxes_init (cairo_boxes_t *boxes); + +cairo_private void +_cairo_boxes_init_for_array (cairo_boxes_t *boxes, + cairo_box_t *array, + int num_boxes); + +cairo_private void +_cairo_boxes_limit (cairo_boxes_t *boxes, + const cairo_box_t *limits, + int num_limits); + +cairo_private cairo_status_t +_cairo_boxes_add (cairo_boxes_t *boxes, + const cairo_box_t *box); + +cairo_private void +_cairo_boxes_extents (const cairo_boxes_t *boxes, + cairo_rectangle_int_t *extents); + +cairo_private void +_cairo_boxes_clear (cairo_boxes_t *boxes); + +cairo_private void +_cairo_boxes_fini (cairo_boxes_t *boxes); + +#endif /* CAIRO_BOXES_H */ diff --git a/gfx/cairo/cairo/src/cairo-boxes.c b/gfx/cairo/cairo/src/cairo-boxes.c new file mode 100644 index 000000000000..31bfc0e4ebb6 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-boxes.c @@ -0,0 +1,300 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-boxes-private.h" +#include "cairo-error-private.h" + +void +_cairo_boxes_init (cairo_boxes_t *boxes) +{ + boxes->status = CAIRO_STATUS_SUCCESS; + boxes->num_limits = 0; + boxes->num_boxes = 0; + + boxes->tail = &boxes->chunks; + boxes->chunks.next = NULL; + boxes->chunks.base = boxes->boxes_embedded; + boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded); + boxes->chunks.count = 0; + + boxes->is_pixel_aligned = TRUE; +} + +void +_cairo_boxes_init_for_array (cairo_boxes_t *boxes, + cairo_box_t *array, + int num_boxes) +{ + int n; + + boxes->status = CAIRO_STATUS_SUCCESS; + boxes->num_limits = 0; + boxes->num_boxes = num_boxes; + + boxes->tail = &boxes->chunks; + boxes->chunks.next = NULL; + boxes->chunks.base = array; + boxes->chunks.size = num_boxes; + boxes->chunks.count = num_boxes; + + for (n = 0; n < num_boxes; n++) { + if (! _cairo_fixed_is_integer (array[n].p1.x) || + ! _cairo_fixed_is_integer (array[n].p1.y) || + ! _cairo_fixed_is_integer (array[n].p2.x) || + ! _cairo_fixed_is_integer (array[n].p2.y)) + { + break; + } + } + + boxes->is_pixel_aligned = n == num_boxes; +} + +void +_cairo_boxes_limit (cairo_boxes_t *boxes, + const cairo_box_t *limits, + int num_limits) +{ + int n; + + boxes->limits = limits; + boxes->num_limits = num_limits; + + if (boxes->num_limits) { + boxes->limit = limits[0]; + for (n = 1; n < num_limits; n++) { + if (limits[n].p1.x < boxes->limit.p1.x) + boxes->limit.p1.x = limits[n].p1.x; + + if (limits[n].p1.y < boxes->limit.p1.y) + boxes->limit.p1.y = limits[n].p1.y; + + if (limits[n].p2.x > boxes->limit.p2.x) + boxes->limit.p2.x = limits[n].p2.x; + + if (limits[n].p2.y > boxes->limit.p2.y) + boxes->limit.p2.y = limits[n].p2.y; + } + } +} + +static void +_cairo_boxes_add_internal (cairo_boxes_t *boxes, + const cairo_box_t *box) +{ + struct _cairo_boxes_chunk *chunk; + + if (unlikely (boxes->status)) + return; + + chunk = boxes->tail; + if (unlikely (chunk->count == chunk->size)) { + int size; + + size = chunk->size * 2; + chunk->next = _cairo_malloc_ab_plus_c (size, + sizeof (cairo_box_t), + sizeof (struct _cairo_boxes_chunk)); + + if (unlikely (chunk->next == NULL)) { + boxes->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + return; + } + + chunk = chunk->next; + boxes->tail = chunk; + + chunk->next = NULL; + chunk->count = 0; + chunk->size = size; + chunk->base = (cairo_box_t *) (chunk + 1); + } + + chunk->base[chunk->count++] = *box; + boxes->num_boxes++; + + if (boxes->is_pixel_aligned) { + boxes->is_pixel_aligned = + _cairo_fixed_is_integer (box->p1.x) && + _cairo_fixed_is_integer (box->p1.y) && + _cairo_fixed_is_integer (box->p2.x) && + _cairo_fixed_is_integer (box->p2.y); + } +} + +cairo_status_t +_cairo_boxes_add (cairo_boxes_t *boxes, + const cairo_box_t *box) +{ + if (box->p1.y == box->p2.y) + return CAIRO_STATUS_SUCCESS; + + if (box->p1.x == box->p2.x) + return CAIRO_STATUS_SUCCESS; + + if (boxes->num_limits) { + cairo_point_t p1, p2; + cairo_bool_t reversed = FALSE; + int n; + + /* support counter-clockwise winding for rectangular tessellation */ + if (box->p1.x < box->p2.x) { + p1.x = box->p1.x; + p2.x = box->p2.x; + } else { + p2.x = box->p1.x; + p1.x = box->p2.x; + reversed = ! reversed; + } + + if (p1.x >= boxes->limit.p2.x || p2.x <= boxes->limit.p1.x) + return CAIRO_STATUS_SUCCESS; + + if (box->p1.y < box->p2.y) { + p1.y = box->p1.y; + p2.y = box->p2.y; + } else { + p2.y = box->p1.y; + p1.y = box->p2.y; + reversed = ! reversed; + } + + if (p1.y >= boxes->limit.p2.y || p2.y <= boxes->limit.p1.y) + return CAIRO_STATUS_SUCCESS; + + for (n = 0; n < boxes->num_limits; n++) { + const cairo_box_t *limits = &boxes->limits[n]; + cairo_box_t _box; + cairo_point_t _p1, _p2; + + if (p1.x >= limits->p2.x || p2.x <= limits->p1.x) + continue; + if (p1.y >= limits->p2.y || p2.y <= limits->p1.y) + continue; + + /* Otherwise, clip the box to the limits. */ + _p1 = p1; + if (_p1.x < limits->p1.x) + _p1.x = limits->p1.x; + if (_p1.y < limits->p1.y) + _p1.y = limits->p1.y; + + _p2 = p2; + if (_p2.x > limits->p2.x) + _p2.x = limits->p2.x; + if (_p2.y > limits->p2.y) + _p2.y = limits->p2.y; + + if (_p2.y <= _p1.y || _p2.x <= _p1.x) + continue; + + _box.p1.y = _p1.y; + _box.p2.y = _p2.y; + if (reversed) { + _box.p1.x = _p2.x; + _box.p2.x = _p1.x; + } else { + _box.p1.x = _p1.x; + _box.p2.x = _p2.x; + } + + _cairo_boxes_add_internal (boxes, &_box); + } + } else { + _cairo_boxes_add_internal (boxes, box); + } + + return boxes->status; +} + +void +_cairo_boxes_extents (const cairo_boxes_t *boxes, + cairo_rectangle_int_t *extents) +{ + const struct _cairo_boxes_chunk *chunk; + cairo_box_t box; + int i; + + box.p1.y = box.p1.x = INT_MAX; + box.p2.y = box.p2.x = INT_MIN; + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *b = chunk->base; + for (i = 0; i < chunk->count; i++) { + if (b[i].p1.x < box.p1.x) + box.p1.x = b[i].p1.x; + + if (b[i].p1.y < box.p1.y) + box.p1.y = b[i].p1.y; + + if (b[i].p2.x > box.p2.x) + box.p2.x = b[i].p2.x; + + if (b[i].p2.y > box.p2.y) + box.p2.y = b[i].p2.y; + } + } + + _cairo_box_round_to_rectangle (&box, extents); +} + +void +_cairo_boxes_clear (cairo_boxes_t *boxes) +{ + struct _cairo_boxes_chunk *chunk, *next; + + for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) { + next = chunk->next; + free (chunk); + } + + boxes->tail = &boxes->chunks; + boxes->chunks.next = 0; + boxes->chunks.count = 0; + boxes->num_boxes = 0; + + boxes->is_pixel_aligned = TRUE; +} + +void +_cairo_boxes_fini (cairo_boxes_t *boxes) +{ + struct _cairo_boxes_chunk *chunk, *next; + + for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) { + next = chunk->next; + free (chunk); + } +} diff --git a/gfx/cairo/cairo/src/cairo-cache-private.h b/gfx/cairo/cairo/src/cairo-cache-private.h index 49ff69cc0979..76b556194d5e 100644 --- a/gfx/cairo/cairo/src/cairo-cache-private.h +++ b/gfx/cairo/cairo/src/cairo-cache-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-cache.c b/gfx/cairo/cairo/src/cairo-cache.c index 025dd9ff96ca..5c4e4caa3d00 100644 --- a/gfx/cairo/cairo/src/cairo-cache.c +++ b/gfx/cairo/cairo/src/cairo-cache.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,6 +37,7 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" static void _cairo_cache_shrink_to_accommodate (cairo_cache_t *cache, @@ -174,9 +175,7 @@ _cairo_cache_thaw (cairo_cache_t *cache) { assert (cache->freeze_count > 0); - cache->freeze_count--; - - if (cache->freeze_count == 0) + if (--cache->freeze_count == 0) _cairo_cache_shrink_to_accommodate (cache, 0); } @@ -240,9 +239,6 @@ static void _cairo_cache_shrink_to_accommodate (cairo_cache_t *cache, unsigned long additional) { - if (cache->freeze_count) - return; - while (cache->size + additional > cache->max_size) { if (! _cairo_cache_remove_random (cache)) return; @@ -267,7 +263,8 @@ _cairo_cache_insert (cairo_cache_t *cache, { cairo_status_t status; - _cairo_cache_shrink_to_accommodate (cache, entry->size); + if (entry->size && ! cache->freeze_count) + _cairo_cache_shrink_to_accommodate (cache, entry->size); status = _cairo_hash_table_insert (cache->hash_table, (cairo_hash_entry_t *) entry); diff --git a/gfx/cairo/cairo/src/cairo-cff-subset.c b/gfx/cairo/cairo/src/cairo-cff-subset.c index 1f4cb9228ba4..a4a434f77cd3 100644 --- a/gfx/cairo/cairo/src/cairo-cff-subset.c +++ b/gfx/cairo/cairo/src/cairo-cff-subset.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -41,6 +41,7 @@ #define _BSD_SOURCE /* for snprintf(), strdup() */ #include "cairoint.h" +#include "cairo-error-private.h" #if CAIRO_HAS_FONT_SUBSET @@ -117,6 +118,7 @@ typedef struct _cairo_cff_font { cairo_array_t local_sub_index; int num_glyphs; cairo_bool_t is_cid; + int units_per_em; /* CID Font Data */ int *fdselect; @@ -1772,6 +1774,9 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset, font->y_max = (int16_t) be16_to_cpu (head.y_max); font->ascent = (int16_t) be16_to_cpu (hhea.ascender); font->descent = (int16_t) be16_to_cpu (hhea.descender); + font->units_per_em = (int16_t) be16_to_cpu (head.units_per_em); + if (font->units_per_em == 0) + font->units_per_em = 1000; font->font_name = NULL; status = _cairo_truetype_read_font_name (scaled_font_subset->scaled_font, @@ -1955,20 +1960,20 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset, cff_subset->font_name = NULL; } - cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); + cff_subset->widths = calloc (sizeof (double), font->scaled_font_subset->num_glyphs); if (unlikely (cff_subset->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) - cff_subset->widths[i] = font->widths[i]; + cff_subset->widths[i] = (double)font->widths[i]/font->units_per_em; - cff_subset->x_min = font->x_min; - cff_subset->y_min = font->y_min; - cff_subset->x_max = font->x_max; - cff_subset->y_max = font->y_max; - cff_subset->ascent = font->ascent; - cff_subset->descent = font->descent; + cff_subset->x_min = (double)font->x_min/font->units_per_em; + cff_subset->y_min = (double)font->y_min/font->units_per_em; + cff_subset->x_max = (double)font->x_max/font->units_per_em; + cff_subset->y_max = (double)font->y_max/font->units_per_em; + cff_subset->ascent = (double)font->ascent/font->units_per_em; + cff_subset->descent = (double)font->descent/font->units_per_em; cff_subset->data = malloc (length); if (unlikely (cff_subset->data == NULL)) { @@ -2212,21 +2217,21 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset, goto fail2; } - cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); + cff_subset->widths = calloc (sizeof (double), font->scaled_font_subset->num_glyphs); if (unlikely (cff_subset->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail3; } for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) - cff_subset->widths[i] = type2_subset.widths[i]; + cff_subset->widths[i] = (double)type2_subset.widths[i]/1000; - cff_subset->x_min = type2_subset.x_min; - cff_subset->y_min = type2_subset.y_min; - cff_subset->x_max = type2_subset.x_max; - cff_subset->y_max = type2_subset.y_max; - cff_subset->ascent = type2_subset.y_max; - cff_subset->descent = type2_subset.y_min; + cff_subset->x_min = (double)type2_subset.x_min/1000; + cff_subset->y_min = (double)type2_subset.y_min/1000; + cff_subset->x_max = (double)type2_subset.x_max/1000; + cff_subset->y_max = (double)type2_subset.y_max/1000; + cff_subset->ascent = (double)type2_subset.y_max/1000; + cff_subset->descent = (double)type2_subset.y_min/1000; cff_subset->data = malloc (length); if (unlikely (cff_subset->data == NULL)) { diff --git a/gfx/cairo/cairo/src/cairo-clip-private.h b/gfx/cairo/cairo/src/cairo-clip-private.h index 6128243502b1..faf486409954 100644 --- a/gfx/cairo/cairo/src/cairo-clip-private.h +++ b/gfx/cairo/cairo/src/cairo-clip-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -76,10 +76,6 @@ struct _cairo_clip { cairo_private void _cairo_clip_init (cairo_clip_t *clip); -cairo_private cairo_status_t -_cairo_clip_init_rectangle (cairo_clip_t *clip, - const cairo_rectangle_int_t *rect); - cairo_private_no_warn cairo_clip_t * _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other); @@ -91,6 +87,10 @@ _cairo_clip_init_copy_transformed (cairo_clip_t *clip, cairo_private void _cairo_clip_reset (cairo_clip_t *clip); +cairo_private cairo_bool_t +_cairo_clip_equal (const cairo_clip_t *clip_a, + const cairo_clip_t *clip_b); + #define _cairo_clip_fini(clip) _cairo_clip_reset (clip) cairo_private cairo_status_t @@ -112,12 +112,12 @@ cairo_private const cairo_rectangle_int_t * _cairo_clip_get_extents (const cairo_clip_t *clip); cairo_private cairo_surface_t * -_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst); +_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst, int *tx, int *ty); cairo_private cairo_status_t _cairo_clip_combine_with_surface (cairo_clip_t *clip, cairo_surface_t *dst, - const cairo_rectangle_int_t *extents); + int dst_x, int dst_y); cairo_private cairo_int_status_t _cairo_clip_get_region (cairo_clip_t *clip, @@ -128,6 +128,20 @@ _cairo_clip_get_boxes (cairo_clip_t *clip, cairo_box_t **boxes, int *count); +cairo_private cairo_status_t +_cairo_clip_to_boxes (cairo_clip_t **clip, + cairo_composite_rectangles_t *extents, + cairo_box_t **boxes, + int *num_boxes); + +cairo_private cairo_bool_t +_cairo_clip_contains_rectangle (cairo_clip_t *clip, + const cairo_rectangle_int_t *rect); + +cairo_private cairo_bool_t +_cairo_clip_contains_extents (cairo_clip_t *clip, + const cairo_composite_rectangles_t *extents); + cairo_private void _cairo_clip_drop_cache (cairo_clip_t *clip); diff --git a/gfx/cairo/cairo/src/cairo-clip.c b/gfx/cairo/cairo/src/cairo-clip.c index 4d4aaa7703ef..d5a2fab7e7e2 100644 --- a/gfx/cairo/cairo/src/cairo-clip.c +++ b/gfx/cairo/cairo/src/cairo-clip.c @@ -15,7 +15,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -41,95 +41,16 @@ #include "cairoint.h" #include "cairo-clip-private.h" +#include "cairo-error-private.h" +#include "cairo-freed-pool-private.h" +#include "cairo-gstate-private.h" #include "cairo-path-fixed-private.h" +#include "cairo-composite-rectangles-private.h" #include "cairo-region-private.h" -/* Keep a stash of recently freed clip_paths, since we need to - * reallocate them frequently. - */ -#define MAX_FREED_POOL_SIZE 4 -typedef struct { - void *pool[MAX_FREED_POOL_SIZE]; - int top; -} freed_pool_t; - +#if HAS_FREED_POOL static freed_pool_t clip_path_pool; - -static void * -_atomic_fetch (void **slot) -{ - return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL); -} - -static cairo_bool_t -_atomic_store (void **slot, void *ptr) -{ - return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr) == NULL; -} - -static void * -_freed_pool_get (freed_pool_t *pool) -{ - void *ptr; - int i; - - i = pool->top - 1; - if (i < 0) - i = 0; - - ptr = _atomic_fetch (&pool->pool[i]); - if (ptr != NULL) { - pool->top = i; - return ptr; - } - - /* either empty or contended */ - for (i = ARRAY_LENGTH (pool->pool); i--;) { - ptr = _atomic_fetch (&pool->pool[i]); - if (ptr != NULL) { - pool->top = i; - return ptr; - } - } - - /* empty */ - pool->top = 0; - return NULL; -} - -static void -_freed_pool_put (freed_pool_t *pool, void *ptr) -{ - int i = pool->top; - - if (_atomic_store (&pool->pool[i], ptr)) { - pool->top = i + 1; - return; - } - - /* either full or contended */ - for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) { - if (_atomic_store (&pool->pool[i], ptr)) { - pool->top = i + 1; - return; - } - } - - /* full */ - pool->top = ARRAY_LENGTH (pool->pool); - free (ptr); -} - -static void -_freed_pool_reset (freed_pool_t *pool) -{ - int i; - - for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) { - free (pool->pool[i]); - pool->pool[i] = NULL; - } -} +#endif static cairo_clip_path_t * _cairo_clip_path_create (cairo_clip_t *clip) @@ -158,9 +79,6 @@ _cairo_clip_path_create (cairo_clip_t *clip) static cairo_clip_path_t * _cairo_clip_path_reference (cairo_clip_path_t *clip_path) { - if (clip_path == NULL) - return NULL; - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count)); _cairo_reference_count_inc (&clip_path->ref_count); @@ -247,47 +165,40 @@ _cairo_clip_intersect_rectangle (cairo_clip_t *clip, status = _cairo_path_fixed_close_path (&clip_path->path); assert (status == CAIRO_STATUS_SUCCESS); - clip_path->extents = *rect; clip_path->fill_rule = CAIRO_FILL_RULE_WINDING; clip_path->tolerance = 1; - clip_path->antialias = CAIRO_ANTIALIAS_NONE; + clip_path->antialias = CAIRO_ANTIALIAS_DEFAULT; clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX; + clip_path->extents = *rect; + if (clip_path->prev != NULL) { + if (! _cairo_rectangle_intersect (&clip_path->extents, + &clip_path->prev->extents)) + { + _cairo_clip_set_all_clipped (clip); + } + } + /* could preallocate the region if it proves worthwhile */ return CAIRO_STATUS_SUCCESS; } -/* XXX consider accepting a matrix, no users yet. */ -cairo_status_t -_cairo_clip_init_rectangle (cairo_clip_t *clip, - const cairo_rectangle_int_t *rect) -{ - _cairo_clip_init (clip); - - if (rect == NULL) - return CAIRO_STATUS_SUCCESS; - - if (rect->width == 0 || rect->height == 0) { - _cairo_clip_set_all_clipped (clip); - return CAIRO_STATUS_SUCCESS; - } - - return _cairo_clip_intersect_rectangle (clip, rect); -} - cairo_clip_t * _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other) { if (other != NULL) { clip->all_clipped = other->all_clipped; - clip->path = _cairo_clip_path_reference (other->path); - - /* this guy is here because of the weird return semantics of _cairo_clip_init_copy */ - if (!other->path) - return NULL; + if (other->path == NULL) { + clip->path = NULL; + if (! clip->all_clipped) + clip = NULL; + } else { + clip->path = _cairo_clip_path_reference (other->path); + } } else { _cairo_clip_init (clip); + clip = NULL; } return clip; @@ -318,9 +229,8 @@ _cairo_clip_intersect_path (cairo_clip_t *clip, if (clip->path != NULL) { if (clip->path->fill_rule == fill_rule && - (path->is_rectilinear || - (tolerance == clip->path->tolerance && - antialias == clip->path->antialias)) && + (path->is_rectilinear || tolerance == clip->path->tolerance) && + antialias == clip->path->antialias && _cairo_path_fixed_equal (&clip->path->path, path)) { return CAIRO_STATUS_SUCCESS; @@ -372,6 +282,38 @@ _cairo_clip_intersect_path (cairo_clip_t *clip, return CAIRO_STATUS_SUCCESS; } +cairo_bool_t +_cairo_clip_equal (const cairo_clip_t *clip_a, + const cairo_clip_t *clip_b) +{ + const cairo_clip_path_t *clip_path_a, *clip_path_b; + + clip_path_a = clip_a->path; + clip_path_b = clip_b->path; + + while (clip_path_a && clip_path_b) { + if (clip_path_a == clip_path_b) + return TRUE; + + if (clip_path_a->fill_rule != clip_path_b->fill_rule) + return FALSE; + + if (clip_path_a->tolerance != clip_path_b->tolerance) + return FALSE; + + if (clip_path_a->antialias != clip_path_b->antialias) + return FALSE; + + if (! _cairo_path_fixed_equal (&clip_path_a->path, &clip_path_b->path)) + return FALSE; + + clip_path_a = clip_path_a->prev; + clip_path_b = clip_path_b->prev; + } + + return clip_path_a == clip_path_b; /* ie both NULL */ +} + cairo_status_t _cairo_clip_clip (cairo_clip_t *clip, const cairo_path_fixed_t *path, @@ -409,7 +351,7 @@ _cairo_clip_rectangle (cairo_clip_t *clip, if (clip->path != NULL) { if (rectangle->x <= clip->path->extents.x && rectangle->y <= clip->path->extents.y && - rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width && + rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width && rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height) { return CAIRO_STATUS_SUCCESS; @@ -443,6 +385,7 @@ _cairo_clip_path_reapply_clip_path_transform (cairo_clip_t *clip, status = _cairo_path_fixed_init_copy (&clip_path->path, &other_path->path); if (unlikely (status)) { + clip->path = clip->path->prev; _cairo_clip_path_destroy (clip_path); return status; } @@ -485,6 +428,7 @@ _cairo_clip_path_reapply_clip_path_translate (cairo_clip_t *clip, status = _cairo_path_fixed_init_copy (&clip_path->path, &other_path->path); if (unlikely (status)) { + clip->path = clip->path->prev; _cairo_clip_path_destroy (clip_path); return status; } @@ -500,6 +444,13 @@ _cairo_clip_path_reapply_clip_path_translate (cairo_clip_t *clip, clip_path->flags = other_path->flags; if (other_path->region != NULL) { clip_path->region = cairo_region_copy (other_path->region); + status = clip_path->region->status; + if (unlikely (status)) { + clip->path = clip->path->prev; + _cairo_clip_path_destroy (clip_path); + return status; + } + cairo_region_translate (clip_path->region, tx, ty); } clip_path->surface = cairo_surface_reference (other_path->surface); @@ -997,104 +948,73 @@ _cairo_clip_path_to_boxes (cairo_clip_path_t *clip_path, return CAIRO_STATUS_SUCCESS; } -static cairo_status_t -_combine_region (cairo_surface_t *surface, - const cairo_region_t *region, - const cairo_rectangle_int_t *extents) -{ - cairo_region_t clear_region; - cairo_status_t status; - - _cairo_region_init_rectangle (&clear_region, extents); - status = cairo_region_subtract (&clear_region, region); - if (unlikely (status)) - return status; - - if (! cairo_region_is_empty (&clear_region)) { - cairo_region_translate (&clear_region, -extents->x, -extents->y); - status = _cairo_surface_fill_region (surface, - CAIRO_OPERATOR_CLEAR, - CAIRO_COLOR_TRANSPARENT, - &clear_region); - } - _cairo_region_fini (&clear_region); - - return status; -} - static cairo_surface_t * _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path, - cairo_surface_t *target) + cairo_surface_t *target, + int *tx, int *ty) { - cairo_surface_t *surface; - cairo_pattern_union_t pattern; - cairo_status_t status; const cairo_rectangle_int_t *clip_extents = &clip_path->extents; - cairo_clip_path_t *prev; cairo_bool_t need_translate; + cairo_surface_t *surface; + cairo_clip_path_t *prev; + cairo_status_t status; + while (clip_path->prev != NULL && + clip_path->flags & CAIRO_CLIP_PATH_IS_BOX && + clip_path->path.maybe_fill_region) + { + clip_path = clip_path->prev; + } + + clip_extents = &clip_path->extents; if (clip_path->surface != NULL && clip_path->surface->backend == target->backend) { - return cairo_surface_reference (clip_path->surface); + *tx = clip_extents->x; + *ty = clip_extents->y; + return clip_path->surface; } - surface = _cairo_surface_create_similar_solid (target, - CAIRO_CONTENT_ALPHA, - clip_extents->width, - clip_extents->height, - CAIRO_COLOR_TRANSPARENT, - FALSE); + surface = _cairo_surface_create_similar_scratch (target, + CAIRO_CONTENT_ALPHA, + clip_extents->width, + clip_extents->height); if (surface == NULL) { - if (clip_path->surface != NULL && - clip_path->surface->backend == &_cairo_image_surface_backend) - { - return cairo_surface_reference (clip_path->surface); - } - - surface = - _cairo_image_surface_create_with_content (CAIRO_CONTENT_ALPHA, - clip_extents->width, - clip_extents->height); + surface = cairo_image_surface_create (CAIRO_FORMAT_A8, + clip_extents->width, + clip_extents->height); } if (unlikely (surface->status)) return surface; - _cairo_pattern_init_solid (&pattern.solid, - CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - - status = _cairo_clip_path_to_region (clip_path); - if (unlikely (_cairo_status_is_error (status))) - goto BAIL; - need_translate = clip_extents->x | clip_extents->y; - if (status == CAIRO_STATUS_SUCCESS) { - if (need_translate) { - cairo_region_translate (clip_path->region, - -clip_extents->x, -clip_extents->y); - } - status = _cairo_surface_fill_region (surface, - CAIRO_OPERATOR_SOURCE, - CAIRO_COLOR_WHITE, - clip_path->region); - if (need_translate) { - cairo_region_translate (clip_path->region, - clip_extents->x, clip_extents->y); - } + if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX && + clip_path->path.maybe_fill_region) + { + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_SOURCE, + &_cairo_pattern_white.base, + NULL); + if (unlikely (status)) + goto BAIL; + } + else + { + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + NULL); if (unlikely (status)) goto BAIL; - goto DONE; - } else { if (need_translate) { _cairo_path_fixed_translate (&clip_path->path, _cairo_fixed_from_int (-clip_extents->x), _cairo_fixed_from_int (-clip_extents->y)); } status = _cairo_surface_fill (surface, - CAIRO_OPERATOR_OVER, - &pattern.base, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, &clip_path->path, clip_path->fill_rule, clip_path->tolerance, @@ -1111,19 +1031,16 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path, } prev = clip_path->prev; - NEXT_PATH: - if (prev != NULL) { - status = _cairo_clip_path_to_region (prev); - if (unlikely (_cairo_status_is_error (status))) - goto BAIL; - - if (status == CAIRO_STATUS_SUCCESS) { - status = _combine_region (surface, prev->region, clip_extents); - if (unlikely (status)) - goto BAIL; - } else if (prev->flags & CAIRO_CLIP_PATH_IS_BOX) { + while (prev != NULL) { + if (prev->flags & CAIRO_CLIP_PATH_IS_BOX && + prev->path.maybe_fill_region) + { /* a simple box only affects the extents */ - } else if (prev->path.is_rectilinear) { + } + else if (prev->path.is_rectilinear || + prev->surface == NULL || + prev->surface->backend != target->backend) + { if (need_translate) { _cairo_path_fixed_translate (&prev->path, _cairo_fixed_from_int (-clip_extents->x), @@ -1131,7 +1048,7 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path, } status = _cairo_surface_fill (surface, CAIRO_OPERATOR_IN, - &pattern.base, + &_cairo_pattern_white.base, &prev->path, prev->fill_rule, prev->tolerance, @@ -1145,19 +1062,23 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path, if (unlikely (status)) goto BAIL; - - prev = prev->prev; - goto NEXT_PATH; - } else { + } + else + { + cairo_surface_pattern_t pattern; cairo_surface_t *prev_surface; + int prev_tx, prev_ty; - prev_surface = _cairo_clip_path_get_surface (prev, target); - _cairo_pattern_init_for_surface (&pattern.surface, prev_surface); - cairo_surface_destroy (prev_surface); + prev_surface = _cairo_clip_path_get_surface (prev, target, &prev_tx, &prev_ty); + status = prev_surface->status; + if (unlikely (status)) + goto BAIL; + _cairo_pattern_init_for_surface (&pattern, prev_surface); + pattern.base.filter = CAIRO_FILTER_NEAREST; cairo_matrix_init_translate (&pattern.base.matrix, - -prev->extents.x + clip_extents->x, - -prev->extents.y + clip_extents->y); + clip_extents->x - prev_tx, + clip_extents->y - prev_ty); status = _cairo_surface_paint (surface, CAIRO_OPERATOR_IN, &pattern.base, @@ -1166,18 +1087,75 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path, if (unlikely (status)) goto BAIL; + + break; } + + prev = prev->prev; } - DONE: + *tx = clip_extents->x; + *ty = clip_extents->y; cairo_surface_destroy (clip_path->surface); - return clip_path->surface = cairo_surface_reference (surface); + return clip_path->surface = surface; BAIL: cairo_surface_destroy (surface); return _cairo_surface_create_in_error (status); } +cairo_bool_t +_cairo_clip_contains_rectangle (cairo_clip_t *clip, + const cairo_rectangle_int_t *rect) +{ + cairo_clip_path_t *clip_path; + + if (clip == NULL) + return FALSE; + + clip_path = clip->path; + if (clip_path->extents.x > rect->x || + clip_path->extents.y > rect->y || + clip_path->extents.x + clip_path->extents.width < rect->x + rect->width || + clip_path->extents.y + clip_path->extents.height < rect->y + rect->height) + { + return FALSE; + } + + do { + cairo_box_t box; + + if ((clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) + return FALSE; + + if (! _cairo_path_fixed_is_box (&clip_path->path, &box)) + return FALSE; + + if (box.p1.x > _cairo_fixed_from_int (rect->x) || + box.p1.y > _cairo_fixed_from_int (rect->y) || + box.p2.x < _cairo_fixed_from_int (rect->x + rect->width) || + box.p2.y < _cairo_fixed_from_int (rect->y + rect->height)) + { + return FALSE; + } + } while ((clip_path = clip_path->prev) != NULL); + + return TRUE; +} + +cairo_bool_t +_cairo_clip_contains_extents (cairo_clip_t *clip, + const cairo_composite_rectangles_t *extents) +{ + const cairo_rectangle_int_t *rect; + + if (clip == NULL) + return FALSE; + + rect = extents->is_bounded ? &extents->bounded : &extents->unbounded; + return _cairo_clip_contains_rectangle (clip, rect); +} + void _cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip) { @@ -1202,72 +1180,48 @@ _cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip) clip_path = clip->path; do { - fprintf (stream, "path: has region? %s, has surface? %s: ", + fprintf (stream, "path: has region? %s, has surface? %s, aa=%d, tolerance=%f, rule=%d: ", clip_path->region == NULL ? "no" : "yes", - clip_path->surface == NULL ? "no" : "yes"); + clip_path->surface == NULL ? "no" : "yes", + clip_path->antialias, + clip_path->tolerance, + clip_path->fill_rule); _cairo_debug_print_path (stream, &clip_path->path); fprintf (stream, "\n"); } while ((clip_path = clip_path->prev) != NULL); } cairo_surface_t * -_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target) +_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target, int *tx, int *ty) { + /* XXX is_clear -> all_clipped */ assert (clip->path != NULL); - return _cairo_clip_path_get_surface (clip->path, target); + return _cairo_clip_path_get_surface (clip->path, target, tx, ty); } cairo_status_t _cairo_clip_combine_with_surface (cairo_clip_t *clip, cairo_surface_t *dst, - const cairo_rectangle_int_t *extents) + int dst_x, int dst_y) { - cairo_pattern_union_t pattern; cairo_clip_path_t *clip_path = clip->path; cairo_bool_t need_translate; cairo_status_t status; assert (clip_path != NULL); - if (clip_path->surface != NULL && - clip_path->surface->backend == dst->backend) - { - _cairo_pattern_init_for_surface (&pattern.surface, - clip_path->surface); - cairo_matrix_init_translate (&pattern.base.matrix, - extents->x - clip_path->extents.x, - extents->y - clip_path->extents.y); - status = _cairo_surface_paint (dst, - CAIRO_OPERATOR_IN, - &pattern.base, - NULL); - - _cairo_pattern_fini (&pattern.base); - - return status; - } - - _cairo_pattern_init_solid (&pattern.solid, - CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - - need_translate = extents->x | extents->y; + need_translate = dst_x | dst_y; do { - status = _cairo_clip_path_to_region (clip_path); - if (unlikely (_cairo_status_is_error (status))) - return status; - - if (status == CAIRO_STATUS_SUCCESS) - return _combine_region (dst, clip_path->region, extents); - if (clip_path->surface != NULL && clip_path->surface->backend == dst->backend) { - _cairo_pattern_init_for_surface (&pattern.surface, - clip_path->surface); + cairo_surface_pattern_t pattern; + + _cairo_pattern_init_for_surface (&pattern, clip_path->surface); cairo_matrix_init_translate (&pattern.base.matrix, - extents->x - clip_path->extents.x, - extents->y - clip_path->extents.y); + dst_x - clip_path->extents.x, + dst_y - clip_path->extents.y); + pattern.base.filter = CAIRO_FILTER_NEAREST; status = _cairo_surface_paint (dst, CAIRO_OPERATOR_IN, &pattern.base, @@ -1278,30 +1232,29 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip, return status; } - if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) { - cairo_region_t clip_region; + if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX && + clip_path->path.maybe_fill_region) + { + continue; + } - _cairo_region_init_rectangle (&clip_region, &clip_path->extents); - status = _combine_region (dst, &clip_region, extents); - } else { - if (need_translate) { - _cairo_path_fixed_translate (&clip_path->path, - _cairo_fixed_from_int (-extents->x), - _cairo_fixed_from_int (-extents->y)); - } - status = _cairo_surface_fill (dst, - CAIRO_OPERATOR_IN, - &pattern.base, - &clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - clip_path->antialias, - NULL); - if (need_translate) { - _cairo_path_fixed_translate (&clip_path->path, - _cairo_fixed_from_int (extents->x), - _cairo_fixed_from_int (extents->y)); - } + if (need_translate) { + _cairo_path_fixed_translate (&clip_path->path, + _cairo_fixed_from_int (-dst_x), + _cairo_fixed_from_int (-dst_y)); + } + status = _cairo_surface_fill (dst, + CAIRO_OPERATOR_IN, + &_cairo_pattern_white.base, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias, + NULL); + if (need_translate) { + _cairo_path_fixed_translate (&clip_path->path, + _cairo_fixed_from_int (dst_x), + _cairo_fixed_from_int (dst_y)); } if (unlikely (status)) @@ -1432,6 +1385,90 @@ _cairo_clip_get_boxes (cairo_clip_t *clip, return CAIRO_STATUS_SUCCESS; } +static cairo_bool_t +box_is_aligned (const cairo_box_t *box) +{ + return + _cairo_fixed_is_integer (box->p1.x) && + _cairo_fixed_is_integer (box->p1.y) && + _cairo_fixed_is_integer (box->p2.x) && + _cairo_fixed_is_integer (box->p2.y); +} + +static void +intersect_with_boxes (cairo_composite_rectangles_t *extents, + cairo_box_t *boxes, + int num_boxes) +{ + cairo_rectangle_int_t rect; + cairo_box_t box; + cairo_bool_t is_empty; + + box.p1.x = box.p1.y = INT_MIN; + box.p2.x = box.p2.y = INT_MAX; + while (num_boxes--) { + if (boxes->p1.x < box.p1.x) + box.p1.x = boxes->p1.x; + if (boxes->p1.y < box.p1.y) + box.p1.y = boxes->p1.y; + + if (boxes->p2.x > box.p2.x) + box.p2.x = boxes->p2.x; + if (boxes->p2.y > box.p2.y) + box.p2.y = boxes->p2.y; + } + + _cairo_box_round_to_rectangle (&box, &rect); + is_empty = _cairo_rectangle_intersect (&extents->bounded, &rect); + is_empty = _cairo_rectangle_intersect (&extents->unbounded, &rect); +} + +cairo_status_t +_cairo_clip_to_boxes (cairo_clip_t **clip, + cairo_composite_rectangles_t *extents, + cairo_box_t **boxes, + int *num_boxes) +{ + cairo_status_t status; + const cairo_rectangle_int_t *rect; + + rect = extents->is_bounded ? &extents->bounded : &extents->unbounded; + + if (*clip == NULL) + goto EXTENTS; + + status = _cairo_clip_rectangle (*clip, rect); + if (unlikely (status)) + return status; + + status = _cairo_clip_get_boxes (*clip, boxes, num_boxes); + switch ((int) status) { + case CAIRO_STATUS_SUCCESS: + intersect_with_boxes (extents, *boxes, *num_boxes); + if (rect->width == 0 || rect->height == 0 || + extents->is_bounded || + (*num_boxes == 1 && box_is_aligned (*boxes))) + { + *clip = NULL; + } + goto DONE; + + case CAIRO_INT_STATUS_UNSUPPORTED: + goto EXTENTS; + + default: + return status; + } + + EXTENTS: + status = CAIRO_STATUS_SUCCESS; + _cairo_box_from_rectangle (&(*boxes)[0], rect); + *num_boxes = 1; + DONE: + return status; +} + + static cairo_rectangle_list_t * _cairo_rectangle_list_create_in_error (cairo_status_t status) { diff --git a/gfx/cairo/cairo/src/cairo-color.c b/gfx/cairo/cairo/src/cairo-color.c index 7640bf43621d..d20fea4d2f3c 100644 --- a/gfx/cairo/cairo/src/cairo-color.c +++ b/gfx/cairo/cairo/src/cairo-color.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -67,13 +67,14 @@ _cairo_stock_color (cairo_stock_t stock) return &cairo_color_black; case CAIRO_STOCK_TRANSPARENT: return &cairo_color_transparent; + + case CAIRO_STOCK_NUM_COLORS: + default: + ASSERT_NOT_REACHED; + /* If the user can get here somehow, give a color that indicates a + * problem. */ + return &cairo_color_magenta; } - - ASSERT_NOT_REACHED; - - /* If the user can get here somehow, give a color that indicates a - * problem. */ - return &cairo_color_magenta; } void @@ -161,6 +162,7 @@ _cairo_color_get_rgba_premultiplied (cairo_color_t *color, *alpha = color->alpha; } +/* NB: This function works both for unmultiplied and premultiplied colors */ cairo_bool_t _cairo_color_equal (const cairo_color_t *color_a, const cairo_color_t *color_b) @@ -168,8 +170,42 @@ _cairo_color_equal (const cairo_color_t *color_a, if (color_a == color_b) return TRUE; + if (color_a->alpha_short != color_b->alpha_short) + return FALSE; + + if (color_a->alpha_short == 0) + return TRUE; + return color_a->red_short == color_b->red_short && color_a->green_short == color_b->green_short && - color_a->blue_short == color_b->blue_short && - color_a->alpha_short == color_b->alpha_short; + color_a->blue_short == color_b->blue_short; +} + +cairo_bool_t +_cairo_color_stop_equal (const cairo_color_stop_t *color_a, + const cairo_color_stop_t *color_b) +{ + if (color_a == color_b) + return TRUE; + + return color_a->alpha_short == color_b->alpha_short && + color_a->red_short == color_b->red_short && + color_a->green_short == color_b->green_short && + color_a->blue_short == color_b->blue_short; +} + +cairo_content_t +_cairo_color_get_content (const cairo_color_t *color) +{ + if (CAIRO_COLOR_IS_OPAQUE (color)) + return CAIRO_CONTENT_COLOR; + + if (color->red_short == 0 && + color->green_short == 0 && + color->blue_short == 0) + { + return CAIRO_CONTENT_ALPHA; + } + + return CAIRO_CONTENT_COLOR_ALPHA; } diff --git a/gfx/cairo/cairo/src/cairo-combsort-private.h b/gfx/cairo/cairo/src/cairo-combsort-private.h index ce31257ececd..bb7abb477697 100644 --- a/gfx/cairo/cairo/src/cairo-combsort-private.h +++ b/gfx/cairo/cairo/src/cairo-combsort-private.h @@ -11,7 +11,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-compiler-private.h b/gfx/cairo/cairo/src/cairo-compiler-private.h index 403c3f7a136e..bc6a88028535 100644 --- a/gfx/cairo/cairo/src/cairo-compiler-private.h +++ b/gfx/cairo/cairo/src/cairo-compiler-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -44,6 +44,45 @@ #include "config.h" #endif +/* Size in bytes of buffer to use off the stack per functions. + * Mostly used by text functions. For larger allocations, they'll + * malloc(). */ +#ifndef CAIRO_STACK_BUFFER_SIZE +#define CAIRO_STACK_BUFFER_SIZE (512 * sizeof (int)) +#endif + +#define CAIRO_STACK_ARRAY_LENGTH(T) (CAIRO_STACK_BUFFER_SIZE / sizeof(T)) + +/* + * The goal of this block is to define the following macros for + * providing faster linkage to functions in the public API for calls + * from within cairo. + * + * slim_hidden_proto(f) + * slim_hidden_proto_no_warn(f) + * + * Declares `f' as a library internal function and hides the + * function from the global symbol table. This macro must be + * expanded after `f' has been declared with a prototype but before + * any calls to the function are seen by the compiler. The no_warn + * variant inhibits warnings about the return value being unused at + * call sites. The macro works by renaming `f' to an internal name + * in the symbol table and hiding that. As far as cairo internal + * calls are concerned they're calling a library internal function + * and thus don't need to bounce via the PLT. + * + * slim_hidden_def(f) + * + * Exports `f' back to the global symbol table. This macro must be + * expanded right after the function definition and only for symbols + * hidden previously with slim_hidden_proto(). The macro works by + * adding a global entry to the symbol table which points at the + * internal name of `f' created by slim_hidden_proto(). + * + * Functions in the public API which aren't called by the library + * don't need to be hidden and re-exported using the slim hidden + * macros. + */ #if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun) # define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private # define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private_no_warn @@ -134,9 +173,11 @@ #if __GNUC__ >= 3 #define cairo_pure __attribute__((pure)) #define cairo_const __attribute__((const)) +#define cairo_always_inline inline __attribute__((always_inline)) #else #define cairo_pure #define cairo_const +#define cairo_always_inline inline #endif #if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) @@ -171,6 +212,26 @@ #ifdef _MSC_VER #undef inline #define inline __inline + +/* there are currently linkage problems that arise when trying to include intrin.h in c++: + * D:\sdks\v7.0\include\winnt.h(3674) : error C2733: second C linkage of overloaded function '_interlockedbittestandset' not allowed + * so avoid defining ffs in c++ code for now */ +#ifndef __cplusplus +/* Add a definition of ffs */ +#include +#pragma intrinsic(_BitScanForward) +static __forceinline int +ffs (int x) +{ + unsigned long i; + + if (_BitScanForward(&i, x) != 0) + return i + 1; + + return 0; +} +#endif + #endif #if defined(_MSC_VER) && defined(_M_IX86) diff --git a/gfx/cairo/cairo/src/cairo-composite-rectangles-private.h b/gfx/cairo/cairo/src/cairo-composite-rectangles-private.h new file mode 100644 index 000000000000..8c3c5abcc7a9 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-composite-rectangles-private.h @@ -0,0 +1,105 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H +#define CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H + +#include "cairo-types-private.h" + +CAIRO_BEGIN_DECLS + +/* Rectangles that take part in a composite operation. + * + * The source and mask track the extents of the respective patterns in device + * space. The unbounded rectangle is essentially the clip rectangle. And the + * intersection of all is the bounded rectangle, which is the minimum extents + * the operation may require. Whether or not the operation is actually bounded + * is tracked in the is_bounded boolean. + * + */ +struct _cairo_composite_rectangles { + cairo_rectangle_int_t source; + cairo_rectangle_int_t mask; + cairo_rectangle_int_t bounded; /* dst */ + cairo_rectangle_int_t unbounded; /* clip */ + uint32_t is_bounded; +}; + +cairo_private cairo_int_status_t +_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents, + const cairo_rectangle_int_t *surface_extents, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents, + const cairo_rectangle_int_t *surface_extents, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents, + const cairo_rectangle_int_t *surface_extents, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents, + const cairo_rectangle_int_t *surface_extents, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents, + const cairo_rectangle_int_t *surface_extents, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_clip_t *clip, + cairo_bool_t *overlap); + +#endif /* CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-composite-rectangles.c b/gfx/cairo/cairo/src/cairo-composite-rectangles.c new file mode 100644 index 000000000000..7f6484339d55 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-composite-rectangles.c @@ -0,0 +1,195 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-composite-rectangles-private.h" + +/* A collection of routines to facilitate writing compositors. */ + +static inline cairo_bool_t +_cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents, + const cairo_rectangle_int_t *surface_extents, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + extents->unbounded = *surface_extents; + + if (clip != NULL) { + const cairo_rectangle_int_t *clip_extents; + + clip_extents = _cairo_clip_get_extents (clip); + if (clip_extents == NULL) + return FALSE; + + if (! _cairo_rectangle_intersect (&extents->unbounded, clip_extents)) + return FALSE; + } + + extents->bounded = extents->unbounded; + extents->is_bounded = _cairo_operator_bounded_by_either (op); + + _cairo_pattern_get_extents (source, &extents->source); + if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) { + if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source)) + return FALSE; + } + + return TRUE; +} + +cairo_int_status_t +_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents, + const cairo_rectangle_int_t *surface_extents, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + if (! _cairo_composite_rectangles_init (extents, + surface_extents, + op, source, clip)) + { + return CAIRO_INT_STATUS_NOTHING_TO_DO; + } + + extents->mask = extents->bounded; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents) +{ + cairo_bool_t ret; + + ret = _cairo_rectangle_intersect (&extents->bounded, &extents->mask); + if (! ret && extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_int_status_t +_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents, + const cairo_rectangle_int_t *surface_extents, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) +{ + if (! _cairo_composite_rectangles_init (extents, + surface_extents, + op, source, clip)) + { + return CAIRO_INT_STATUS_NOTHING_TO_DO; + } + + _cairo_pattern_get_extents (mask, &extents->mask); + + return _cairo_composite_rectangles_intersect (extents); +} + +cairo_int_status_t +_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents, + const cairo_rectangle_int_t *surface_extents, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + cairo_clip_t *clip) +{ + if (! _cairo_composite_rectangles_init (extents, + surface_extents, + op, source, clip)) + { + return CAIRO_INT_STATUS_NOTHING_TO_DO; + } + + _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &extents->mask); + + return _cairo_composite_rectangles_intersect (extents); +} + +cairo_int_status_t +_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents, + const cairo_rectangle_int_t *surface_extents, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_clip_t *clip) +{ + if (! _cairo_composite_rectangles_init (extents, + surface_extents, + op, source, clip)) + { + return CAIRO_INT_STATUS_NOTHING_TO_DO; + } + + _cairo_path_fixed_approximate_fill_extents (path, &extents->mask); + + return _cairo_composite_rectangles_intersect (extents); +} + +cairo_int_status_t +_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents, + const cairo_rectangle_int_t *surface_extents, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_clip_t *clip, + cairo_bool_t *overlap) +{ + cairo_status_t status; + + if (! _cairo_composite_rectangles_init (extents, + surface_extents, + op, source, clip)) + { + return CAIRO_INT_STATUS_NOTHING_TO_DO; + } + + status = _cairo_scaled_font_glyph_device_extents (scaled_font, + glyphs, num_glyphs, + &extents->mask, + overlap); + if (unlikely (status)) + return status; + + return _cairo_composite_rectangles_intersect (extents); +} diff --git a/gfx/cairo/cairo/src/cairo-d2d-private.h b/gfx/cairo/cairo/src/cairo-d2d-private.h index 80e480ff0f23..4fc2f60d4ac2 100644 --- a/gfx/cairo/cairo/src/cairo-d2d-private.h +++ b/gfx/cairo/cairo/src/cairo-d2d-private.h @@ -43,10 +43,8 @@ #include #include -extern "C" { #include "cairoint.h" #include "cairo-surface-clipper-private.h" -} #include "cairo-win32-refptr.h" #include "cairo-d2d-private-fx.h" diff --git a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp index 43ae796c4512..6df6dd8c4111 100644 --- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp +++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp @@ -39,10 +39,9 @@ #include "cairo-d2d-private.h" #include "cairo-dwrite-private.h" -extern "C" { #include "cairo-win32.h" #include "cairo-analysis-surface-private.h" -} +#include "cairo-error-private.h" // Required for using placement new. #include @@ -649,9 +648,9 @@ _cairo_d2d_stroke(void *surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip); @@ -763,6 +762,16 @@ _cairo_d2d_compute_surface_mem_size(cairo_d2d_surface_t *surface) return size; } +static D2D1_COLOR_F +_cairo_d2d_color_from_cairo_color_stop(const cairo_color_stop_t &color) +{ + return D2D1::ColorF((FLOAT)color.red, + (FLOAT)color.green, + (FLOAT)color.blue, + (FLOAT)color.alpha); +} + + /** * Gets the surface buffer texture for window surfaces whose backbuffer * is not directly usable as a bitmap. @@ -1435,7 +1444,7 @@ _cairo_d2d_create_radial_gradient_brush(cairo_d2d_surface_t *d2dsurf, stops[i].position = (FLOAT)((repeat + source_pattern->base.stops[stop].offset) * stop_scale); } stops[i].color = - _cairo_d2d_color_from_cairo_color(source_pattern->base.stops[stop].color); + _cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[stop].color); } } else { // Simple case, we don't need to reflect. @@ -1445,7 +1454,7 @@ _cairo_d2d_create_radial_gradient_brush(cairo_d2d_surface_t *d2dsurf, // Calculate which stop this would be in the original pattern cairo_gradient_stop_t *stop = &source_pattern->base.stops[i % source_pattern->base.n_stops]; stops[i].position = (FLOAT)((repeat + stop->offset) * stop_scale); - stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color); + stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color); } } } else if (source_pattern->base.base.extend == CAIRO_EXTEND_PAD) { @@ -1458,7 +1467,7 @@ _cairo_d2d_create_radial_gradient_brush(cairo_d2d_surface_t *d2dsurf, for (unsigned int i = 0; i < source_pattern->base.n_stops; i++) { cairo_gradient_stop_t *stop = &source_pattern->base.stops[i]; stops[i].position = (FLOAT)(global_offset + stop->offset * offset_factor); - stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color); + stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color); } } else if (source_pattern->base.base.extend == CAIRO_EXTEND_NONE) { float offset_factor = (outer_radius - inner_radius) / outer_radius; @@ -1482,7 +1491,7 @@ _cairo_d2d_create_radial_gradient_brush(cairo_d2d_surface_t *d2dsurf, for (unsigned int j = 0; j < source_pattern->base.n_stops; j++, i++) { cairo_gradient_stop_t *stop = &source_pattern->base.stops[j]; stops[i].position = (FLOAT)(global_offset + stop->offset * offset_factor); - stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color); + stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color); } stops[i].position = 1.0f; stops[i].color = D2D1::ColorF(0, 0); @@ -1514,7 +1523,7 @@ _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf, // Cairo behavior in this situation is to draw a solid color the size of the last stop. RefPtr brush; d2dsurf->rt->CreateSolidColorBrush( - _cairo_d2d_color_from_cairo_color(source_pattern->base.stops[source_pattern->base.n_stops - 1].color), + _cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[source_pattern->base.n_stops - 1].color), &brush); return brush; } @@ -1619,7 +1628,7 @@ _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf, stops[i].position = (FLOAT)((repeat + source_pattern->base.stops[stop].offset) * stop_scale); } stops[i].color = - _cairo_d2d_color_from_cairo_color(source_pattern->base.stops[stop].color); + _cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[stop].color); } } else { // Simple case, we don't need to reflect. @@ -1629,7 +1638,7 @@ _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf, // Calculate which stop this would be in the original pattern cairo_gradient_stop_t *stop = &source_pattern->base.stops[i % source_pattern->base.n_stops]; stops[i].position = (FLOAT)((repeat + stop->offset) * stop_scale); - stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color); + stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color); } } } else if (source_pattern->base.base.extend == CAIRO_EXTEND_PAD) { @@ -1637,7 +1646,7 @@ _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf, for (unsigned int i = 0; i < source_pattern->base.n_stops; i++) { cairo_gradient_stop_t *stop = &source_pattern->base.stops[i]; stops[i].position = (FLOAT)stop->offset; - stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color); + stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color); } } else if (source_pattern->base.base.extend == CAIRO_EXTEND_NONE) { num_stops += 2; @@ -1647,7 +1656,7 @@ _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf, for (unsigned int i = 1; i < source_pattern->base.n_stops + 1; i++) { cairo_gradient_stop_t *stop = &source_pattern->base.stops[i - 1]; stops[i].position = (FLOAT)stop->offset; - stops[i].color = _cairo_d2d_color_from_cairo_color(stop->color); + stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color); } stops[source_pattern->base.n_stops + 1].position = 1.0f; stops[source_pattern->base.n_stops + 1].color = D2D1::ColorF(0, 0); @@ -2309,6 +2318,16 @@ static cairo_operator_t _cairo_d2d_simplify_operator(cairo_operator_t op, return op; } +void +_cairo_d2d_surface_init(cairo_d2d_surface_t *newSurf, cairo_d2d_device_t *d2d_device, cairo_format_t format) +{ + newSurf->format = format; + + newSurf->device = d2d_device; + cairo_addref_device(&d2d_device->base); + d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf); +} + // Implementation static cairo_surface_t* _cairo_d2d_create_similar(void *surface, @@ -2320,7 +2339,7 @@ _cairo_d2d_create_similar(void *surface, cairo_d2d_surface_t *newSurf = static_cast(malloc(sizeof(cairo_d2d_surface_t))); new (newSurf) cairo_d2d_surface_t(); - _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content); + _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content); D2D1_SIZE_U sizePixels; @@ -2425,9 +2444,7 @@ _cairo_d2d_create_similar(void *surface, _d2d_clear_surface(newSurf); - newSurf->device = d2dsurf->device; - cairo_addref_device(&newSurf->device->base); - newSurf->device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf); + _cairo_d2d_surface_init(newSurf, d2dsurf->device, _cairo_format_from_content(content)); return reinterpret_cast(newSurf); @@ -2501,8 +2518,8 @@ _cairo_d2d_acquire_source_image(void *abstract_surface, return _cairo_error(CAIRO_STATUS_NO_DEVICE); } *image_out = - (cairo_image_surface_t*)_cairo_image_surface_create_for_data_with_content((unsigned char*)data.pData, - d2dsurf->base.content, + (cairo_image_surface_t*)cairo_image_surface_create_for_data((unsigned char*)data.pData, + d2dsurf->format, size.width, size.height, data.RowPitch); @@ -2573,8 +2590,8 @@ _cairo_d2d_acquire_dest_image(void *abstract_surface, return _cairo_error(CAIRO_STATUS_NO_DEVICE); } *image_out = - (cairo_image_surface_t*)_cairo_image_surface_create_for_data_with_content((unsigned char*)data.pData, - d2dsurf->base.content, + (cairo_image_surface_t*)cairo_image_surface_create_for_data((unsigned char*)data.pData, + _cairo_format_from_content(d2dsurf->base.content), size.width, size.height, data.RowPitch); @@ -3178,7 +3195,7 @@ _cairo_d2d_mask(void *surface, if (mask->type == CAIRO_PATTERN_TYPE_SOLID) { cairo_solid_pattern_t *solidPattern = (cairo_solid_pattern_t*)mask; - if (solidPattern->content = CAIRO_CONTENT_ALPHA) { + if (_cairo_color_get_content (&solidPattern->color) == CAIRO_CONTENT_ALPHA) { isSolidAlphaMask = true; solidAlphaValue = solidPattern->color.alpha; } @@ -3321,9 +3338,9 @@ _cairo_d2d_stroke(void *surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) @@ -3526,7 +3543,12 @@ _cairo_d2d_fill(void *surface, if (target_rt.get() != d2dsurf->rt.get()) { double x1, y1, x2, y2; - _cairo_path_fixed_bounds(path, &x1, &y1, &x2, &y2); + cairo_box_t box; + _cairo_path_fixed_extents (path, &box); + x1 = _cairo_fixed_to_double (box.p1.x); + y1 = _cairo_fixed_to_double (box.p1.y); + x2 = _cairo_fixed_to_double (box.p2.x); + y2 = _cairo_fixed_to_double (box.p2.y); cairo_rectangle_int_t bounds; _cairo_d2d_round_out_to_int_rect(&bounds, x1, y1, x2, y2); return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip, &bounds); @@ -4118,6 +4140,8 @@ _cairo_d2d_getextents(void *surface, /** Helper functions. */ + + cairo_surface_t* cairo_d2d_surface_create_for_hwnd(cairo_device_t *cairo_device, HWND wnd, @@ -4127,7 +4151,7 @@ cairo_d2d_surface_create_for_hwnd(cairo_device_t *cairo_device, cairo_d2d_surface_t *newSurf = static_cast(malloc(sizeof(cairo_d2d_surface_t))); new (newSurf) cairo_d2d_surface_t(); - _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content); + _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content); RECT rc; HRESULT hr; @@ -4229,9 +4253,7 @@ cairo_d2d_surface_create_for_hwnd(cairo_device_t *cairo_device, _d2d_clear_surface(newSurf); - newSurf->device = d2d_device; - cairo_addref_device(cairo_device); - d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf); + _cairo_d2d_surface_init(newSurf, d2d_device, _cairo_format_from_content(content)); return reinterpret_cast(newSurf); @@ -4241,6 +4263,8 @@ FAIL_HWND: return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY)); } + + cairo_surface_t * cairo_d2d_surface_create(cairo_device_t *device, cairo_format_t format, @@ -4258,12 +4282,12 @@ cairo_d2d_surface_create(cairo_device_t *device, DXGI_FORMAT dxgiformat = DXGI_FORMAT_B8G8R8A8_UNORM; D2D1_ALPHA_MODE alpha = D2D1_ALPHA_MODE_PREMULTIPLIED; if (format == CAIRO_FORMAT_ARGB32) { - _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_COLOR_ALPHA); + _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_COLOR_ALPHA); } else if (format == CAIRO_FORMAT_RGB24) { - _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_COLOR); + _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_COLOR); alpha = D2D1_ALPHA_MODE_IGNORE; } else { - _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_ALPHA); + _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_ALPHA); dxgiformat = DXGI_FORMAT_A8_UNORM; } @@ -4343,9 +4367,7 @@ cairo_d2d_surface_create(cairo_device_t *device, _d2d_clear_surface(newSurf); - newSurf->device = d2d_device; - cairo_addref_device(device); - d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf); + _cairo_d2d_surface_init(newSurf, d2d_device, format); return reinterpret_cast(newSurf); @@ -4398,7 +4420,7 @@ cairo_d2d_surface_create_for_handle(cairo_device_t *device, HANDLE handle, cairo status = CAIRO_STATUS_INVALID_CONTENT; goto FAIL_CREATEHANDLE; } - _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content); + _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content); if (content == CAIRO_CONTENT_COLOR) { alpha = D2D1_ALPHA_MODE_IGNORE; } @@ -4407,7 +4429,7 @@ cairo_d2d_surface_create_for_handle(cairo_device_t *device, HANDLE handle, cairo status = CAIRO_STATUS_INVALID_CONTENT; goto FAIL_CREATEHANDLE; } - _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_ALPHA); + _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_ALPHA); } else { status = CAIRO_STATUS_INVALID_FORMAT; // We don't know how to support this format! @@ -4444,9 +4466,7 @@ cairo_d2d_surface_create_for_handle(cairo_device_t *device, HANDLE handle, cairo newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush); - newSurf->device = d2d_device; - cairo_addref_device(device); - d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf); + _cairo_d2d_surface_init(newSurf, d2d_device, _cairo_format_from_content(content)); return &newSurf->base; @@ -4467,10 +4487,10 @@ cairo_d2d_surface_create_for_texture(cairo_device_t *device, D2D1_ALPHA_MODE alpha = D2D1_ALPHA_MODE_PREMULTIPLIED; if (content == CAIRO_CONTENT_COLOR) { - _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_COLOR); + _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_COLOR); alpha = D2D1_ALPHA_MODE_IGNORE; } else { - _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content); + _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content); } D2D1_SIZE_U sizePixels; @@ -4527,9 +4547,7 @@ cairo_d2d_surface_create_for_texture(cairo_device_t *device, newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush); - newSurf->device = d2d_device; - cairo_addref_device(device); - d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf); + _cairo_d2d_surface_init(newSurf, d2d_device, _cairo_format_from_content(content)); return reinterpret_cast(newSurf); diff --git a/gfx/cairo/cairo/src/cairo-debug.c b/gfx/cairo/cairo/src/cairo-debug.c index 9160728e0ff7..c95675318397 100644 --- a/gfx/cairo/cairo/src/cairo-debug.c +++ b/gfx/cairo/cairo/src/cairo-debug.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -77,10 +77,14 @@ cairo_debug_reset_static_data (void) _cairo_clip_reset_static_data (); + _cairo_image_reset_static_data (); + #if CAIRO_HAS_DRM_SURFACE _cairo_drm_device_reset_static_data (); #endif + _cairo_reset_static_data (); + CAIRO_MUTEX_FINALIZE (); } @@ -106,10 +110,14 @@ _cairo_debug_check_image_surface_is_defined (const cairo_surface_t *surface) case CAIRO_FORMAT_A8: width = image->width; break; + case CAIRO_FORMAT_RGB16_565: + width = image->width*2; + break; case CAIRO_FORMAT_RGB24: case CAIRO_FORMAT_ARGB32: width = image->width*4; break; + case CAIRO_FORMAT_INVALID: default: /* XXX compute width from pixman bpp */ return; @@ -221,6 +229,12 @@ _cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path) { cairo_status_t status; + printf ("path: extents=(%f, %f), (%f, %f)\n", + _cairo_fixed_to_double (path->extents.p1.x), + _cairo_fixed_to_double (path->extents.p1.y), + _cairo_fixed_to_double (path->extents.p2.x), + _cairo_fixed_to_double (path->extents.p2.y)); + status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, _print_move_to, diff --git a/gfx/cairo/cairo/src/cairo-deflate-stream.c b/gfx/cairo/cairo/src/cairo-deflate-stream.c index 863189f45653..ba5f18392b4b 100644 --- a/gfx/cairo/cairo/src/cairo-deflate-stream.c +++ b/gfx/cairo/cairo/src/cairo-deflate-stream.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -35,6 +35,7 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-output-stream-private.h" #include diff --git a/gfx/cairo/cairo/src/cairo-deprecated.h b/gfx/cairo/cairo/src/cairo-deprecated.h index 438e1d89858f..7a56aadbfe18 100644 --- a/gfx/cairo/cairo/src/cairo-deprecated.h +++ b/gfx/cairo/cairo/src/cairo-deprecated.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -36,20 +36,6 @@ #ifndef CAIRO_DEPRECATED_H #define CAIRO_DEPRECATED_H -/* The %CAIRO_FORMAT_RGB16_565 value was added in cairo 1.2.0 as part - * of fixing cairo's xlib backend to work with X servers advertising a - * 16-bit, 565 visual. But as it turned out, adding this format to - * #cairo_format_t was not necessary, and was a mistake, (cairo's xlib - * backend can work fine with 16-bit visuals in the same way it works - * with BGR visuals without any BGR formats in - * #cairo_format_t). - * - * Additionally, the support for the RGB16_565 format was never - * completely implemented. So while this format value is currently - * deprecated, it may eventually acquire complete support in the future. - */ -/* #define CAIRO_FORMAT_RGB16_565 4 */ - #define CAIRO_FONT_TYPE_ATSUI CAIRO_FONT_TYPE_QUARTZ /* Obsolete functions. These definitions exist to coerce the compiler @@ -123,7 +109,6 @@ #define cairo_matrix_copy cairo_matrix_copy_DEPRECATED_BY_cairo_matrix_t #define cairo_matrix_get_affine cairo_matrix_get_affine_DEPRECATED_BY_cairo_matrix_t #define cairo_set_target_surface cairo_set_target_surface_DEPRECATED_BY_cairo_create -#define cairo_set_target_glitz cairo_set_target_glitz_DEPRECATED_BY_cairo_glitz_surface_create #define cairo_set_target_image cairo_set_target_image_DEPRECATED_BY_cairo_image_surface_create_for_data #define cairo_set_target_pdf cairo_set_target_pdf_DEPRECATED_BY_cairo_pdf_surface_create #define cairo_set_target_png cairo_set_target_png_DEPRECATED_BY_cairo_surface_write_to_png diff --git a/gfx/cairo/cairo/src/cairo-device-private.h b/gfx/cairo/cairo/src/cairo-device-private.h new file mode 100644 index 000000000000..6eb44f3b6343 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-device-private.h @@ -0,0 +1,86 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributors(s): + * Chris Wilson + */ + +#ifndef _CAIRO_DEVICE_PRIVATE_H_ +#define _CAIRO_DEVICE_PRIVATE_H_ + +#include "cairo-compiler-private.h" +#include "cairo-mutex-private.h" +#include "cairo-reference-count-private.h" +#include "cairo-types-private.h" + +struct _cairo_device { + cairo_reference_count_t ref_count; + cairo_status_t status; + cairo_user_data_array_t user_data; + + const cairo_device_backend_t *backend; + + cairo_recursive_mutex_t mutex; + unsigned mutex_depth; + + cairo_bool_t finished; +}; + +struct _cairo_device_backend { + cairo_device_type_t type; + + void (*lock) (void *device); + void (*unlock) (void *device); + + cairo_warn cairo_status_t (*flush) (void *device); + void (*finish) (void *device); + void (*destroy) (void *device); +}; + +cairo_private cairo_device_t * +_cairo_device_create_in_error (cairo_status_t status); + +cairo_private void +_cairo_device_init (cairo_device_t *device, + const cairo_device_backend_t *backend); + +cairo_private cairo_status_t +_cairo_device_set_error (cairo_device_t *device, + cairo_status_t error); + +slim_hidden_proto_no_warn (cairo_device_reference); +slim_hidden_proto (cairo_device_acquire); +slim_hidden_proto (cairo_device_release); +slim_hidden_proto (cairo_device_flush); +slim_hidden_proto (cairo_device_finish); +slim_hidden_proto (cairo_device_destroy); + +#endif /* _CAIRO_DEVICE_PRIVATE_H_ */ diff --git a/gfx/cairo/cairo/src/cairo-device.c b/gfx/cairo/cairo/src/cairo-device.c new file mode 100644 index 000000000000..15b048477598 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-device.c @@ -0,0 +1,533 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributors(s): + * Chris Wilson + */ + +#include "cairoint.h" +#include "cairo-device-private.h" +#include "cairo-error-private.h" + +/** + * SECTION:cairo-device + * @Title: cairo_device_t + * @Short_Description: interface to underlying rendering system + * @See_Also: #cairo_surface_t + * + * Devices are the abstraction Cairo employs for the rendering system + * used by a #cairo_surface_t. You can get the device of a surface using + * cairo_surface_get_device(). + * + * Devices are created using custom functions specific to the rendering + * system you want to use. See the documentation for the surface types + * for those functions. + * + * An important function that devices fulfill is sharing access to the + * rendering system between Cairo and your application. If you want to + * access a device directly that you used to draw to with Cairo, you must + * first call cairo_device_flush() to ensure that Cairo finishes all + * operations on the device and resets it to a clean state. + * + * Cairo also provides the functions cairo_device_acquire() and + * cairo_device_release() to synchronize access to the rendering system + * in a multithreaded environment. This is done internally, but can also + * be used by applications. + * + * Putting this all together, a function that works with devices should + * look something like this: + * + * void + * my_device_modifying_function (cairo_device_t *device) + * { + * cairo_status_t status; + * + * // Ensure the device is properly reset + * cairo_device_flush (device); + * // Try to acquire the device + * status = cairo_device_acquire (device); + * if (status != CAIRO_STATUS_SUCCESS) { + * printf ("Failed to acquire the device: %s\n", cairo_status_to_string (status)); + * return; + * } + * + * // Do the custom operations on the device here. + * // But do not call any Cairo functions that might acquire devices. + * + * // Release the device when done. + * cairo_device_release (device); + * } + * + * + * Please refer to the documentation of each backend for + * additional usage requirements, guarantees provided, and + * interactions with existing surface API of the device functions for + * surfaces of that type. + * + */ + +static const cairo_device_t _nil_device = { + CAIRO_REFERENCE_COUNT_INVALID, + CAIRO_STATUS_NO_MEMORY, +}; + +static const cairo_device_t _mismatch_device = { + CAIRO_REFERENCE_COUNT_INVALID, + CAIRO_STATUS_DEVICE_TYPE_MISMATCH, +}; + +static const cairo_device_t _invalid_device = { + CAIRO_REFERENCE_COUNT_INVALID, + CAIRO_STATUS_DEVICE_ERROR, +}; + +cairo_device_t * +_cairo_device_create_in_error (cairo_status_t status) +{ + switch (status) { + case CAIRO_STATUS_NO_MEMORY: + return (cairo_device_t *) &_nil_device; + case CAIRO_STATUS_DEVICE_ERROR: + return (cairo_device_t *) &_invalid_device; + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: + return (cairo_device_t *) &_mismatch_device; + + case CAIRO_STATUS_SUCCESS: + case CAIRO_STATUS_LAST_STATUS: + ASSERT_NOT_REACHED; + /* fall-through */ + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: + case CAIRO_STATUS_INVALID_STATUS: + case CAIRO_STATUS_INVALID_FORMAT: + case CAIRO_STATUS_INVALID_VISUAL: + case CAIRO_STATUS_READ_ERROR: + case CAIRO_STATUS_WRITE_ERROR: + case CAIRO_STATUS_FILE_NOT_FOUND: + case CAIRO_STATUS_TEMP_FILE_ERROR: + case CAIRO_STATUS_INVALID_STRIDE: + case CAIRO_STATUS_INVALID_SIZE: + case CAIRO_STATUS_INVALID_RESTORE: + case CAIRO_STATUS_INVALID_POP_GROUP: + case CAIRO_STATUS_NO_CURRENT_POINT: + case CAIRO_STATUS_INVALID_MATRIX: + case CAIRO_STATUS_NULL_POINTER: + case CAIRO_STATUS_INVALID_STRING: + case CAIRO_STATUS_INVALID_PATH_DATA: + case CAIRO_STATUS_SURFACE_FINISHED: + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: + case CAIRO_STATUS_INVALID_DASH: + case CAIRO_STATUS_INVALID_DSC_COMMENT: + case CAIRO_STATUS_INVALID_INDEX: + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: + case CAIRO_STATUS_FONT_TYPE_MISMATCH: + case CAIRO_STATUS_USER_FONT_IMMUTABLE: + case CAIRO_STATUS_USER_FONT_ERROR: + case CAIRO_STATUS_NEGATIVE_COUNT: + case CAIRO_STATUS_INVALID_CLUSTERS: + case CAIRO_STATUS_INVALID_SLANT: + case CAIRO_STATUS_INVALID_WEIGHT: + case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: + case CAIRO_STATUS_INVALID_CONTENT: + default: + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_device_t *) &_nil_device; + } +} + +void +_cairo_device_init (cairo_device_t *device, + const cairo_device_backend_t *backend) +{ + CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1); + device->status = CAIRO_STATUS_SUCCESS; + + device->backend = backend; + + CAIRO_RECURSIVE_MUTEX_INIT (device->mutex); + device->mutex_depth = 0; + + device->finished = FALSE; + + _cairo_user_data_array_init (&device->user_data); +} + +/** + * cairo_device_reference: + * @device: a #cairo_device_t + * + * Increases the reference count on @device by one. This prevents + * @device from being destroyed until a matching call to + * cairo_device_destroy() is made. + * + * The number of references to a #cairo_device_t can be get using + * cairo_device_get_reference_count(). + * + * Return value: the referenced #cairo_device_t. + * + * Since: 1.10 + **/ +cairo_device_t * +cairo_device_reference (cairo_device_t *device) +{ + if (device == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count)) + { + return device; + } + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count)); + _cairo_reference_count_inc (&device->ref_count); + + return device; +} +slim_hidden_def (cairo_device_reference); + +/** + * cairo_device_status: + * @device: a #cairo_device_t + * + * Checks whether an error has previously occurred for this + * device. + * + * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if + * the device is in an error state. + * + * Since: 1.10 + **/ +cairo_status_t +cairo_device_status (cairo_device_t *device) +{ + if (device == NULL) + return CAIRO_STATUS_NULL_POINTER; + + return device->status; +} + +/** + * cairo_device_flush: + * @device: a #cairo_device_t + * + * Finish any pending operations for the device and also restore any + * temporary modifications cairo has made to the device's state. + * This function must be called before switching from using the + * device with Cairo to operating on it directly with native APIs. + * If the device doesn't support direct access, then this function + * does nothing. + * + * This function may acquire devices. + * + * Since: 1.10 + **/ +void +cairo_device_flush (cairo_device_t *device) +{ + cairo_status_t status; + + if (device == NULL || device->status) + return; + + if (device->backend->flush != NULL) { + status = device->backend->flush (device); + if (unlikely (status)) + status = _cairo_device_set_error (device, status); + } +} +slim_hidden_def (cairo_device_flush); + +/** + * cairo_device_finish: + * @device: the #cairo_device_t to finish + * + * This function finishes the device and drops all references to + * external resources. All surfaces, fonts and other objects created + * for this @device will be finished, too. + * Further operations on the @device will not affect the @device but + * will instead trigger a %CAIRO_STATUS_DEVICE_FINISHED error. + * + * When the last call to cairo_device_destroy() decreases the + * reference count to zero, cairo will call cairo_device_finish() if + * it hasn't been called already, before freeing the resources + * associated with the device. + * + * This function may acquire devices. + * + * Since: 1.10 + **/ +void +cairo_device_finish (cairo_device_t *device) +{ + if (device == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count)) + { + return; + } + + if (device->finished) + return; + + cairo_device_flush (device); + + device->finished = TRUE; + + if (device->backend->finish != NULL) + device->backend->finish (device); +} +slim_hidden_def (cairo_device_finish); + +/** + * cairo_device_destroy: + * @device: a #cairo_device_t + * + * Decreases the reference count on @device by one. If the result is + * zero, then @device and all associated resources are freed. See + * cairo_device_reference(). + * + * This function may acquire devices if the last reference was dropped. + * + * Since: 1.10 + **/ +void +cairo_device_destroy (cairo_device_t *device) +{ + cairo_user_data_array_t user_data; + + if (device == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count)) + { + return; + } + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count)); + if (! _cairo_reference_count_dec_and_test (&device->ref_count)) + return; + + cairo_device_finish (device); + + assert (device->mutex_depth == 0); + CAIRO_MUTEX_FINI (device->mutex); + + user_data = device->user_data; + + device->backend->destroy (device); + + _cairo_user_data_array_fini (&user_data); + +} +slim_hidden_def (cairo_device_destroy); + +/** + * cairo_device_get_type: + * @device: a #cairo_device_t + * + * This function returns the type of the device. See #cairo_device_type_t + * for available types. + * + * Return value: The type of @device. + * + * Since: 1.10 + **/ +cairo_device_type_t +cairo_device_get_type (cairo_device_t *device) +{ + if (device == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count)) + { + return (cairo_device_type_t) -1; + } + + return device->backend->type; +} + +/** + * cairo_device_acquire: + * @device: a #cairo_device_t + * + * Acquires the @device for the current thread. This function will block + * until no other thread has acquired the device. + * + * If the return value is %CAIRO_STATUS_SUCCESS, you successfully acquired the + * device. From now on your thread owns the device and no other thread will be + * able to acquire it until a matching call to cairo_device_release(). It is + * allowed to recursively acquire the device multiple times from the same + * thread. + * + * You must never acquire two different devices at the same time + * unless this is explicitly allowed. Otherwise the possibility of deadlocks + * exist. + * + * As various Cairo functions can acquire devices when called, these functions + * may also cause deadlocks when you call them with an acquired device. So you + * must not have a device acquired when calling them. These functions are + * marked in the documentation. + * + * + * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if + * the device is in an error state and could not be + * acquired. After a successful call to cairo_device_acquire(), + * a matching call to cairo_device_release() is required. + * + * Since: 1.10 + **/ +cairo_status_t +cairo_device_acquire (cairo_device_t *device) +{ + if (device == NULL) + return CAIRO_STATUS_SUCCESS; + + if (unlikely (device->status)) + return device->status; + + if (unlikely (device->finished)) + return _cairo_device_set_error (device, CAIRO_STATUS_SURFACE_FINISHED); /* XXX */ + + CAIRO_MUTEX_LOCK (device->mutex); + if (device->mutex_depth++ == 0) { + if (device->backend->lock != NULL) + device->backend->lock (device); + } + + return CAIRO_STATUS_SUCCESS; +} +slim_hidden_def (cairo_device_acquire); + +/** + * cairo_device_release: + * @device: a #cairo_device_t + * + * Releases a @device previously acquired using cairo_device_acquire(). See + * that function for details. + * + * Since: 1.10 + **/ +void +cairo_device_release (cairo_device_t *device) +{ + if (device == NULL) + return; + + assert (device->mutex_depth > 0); + + if (--device->mutex_depth == 0) { + if (device->backend->unlock != NULL) + device->backend->unlock (device); + } + + CAIRO_MUTEX_UNLOCK (device->mutex); +} +slim_hidden_def (cairo_device_release); + +cairo_status_t +_cairo_device_set_error (cairo_device_t *device, + cairo_status_t status) +{ + if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + /* Don't overwrite an existing error. This preserves the first + * error, which is the most significant. */ + _cairo_status_set_error (&device->status, status); + + return _cairo_error (status); +} + +/** + * cairo_device_get_reference_count: + * @device: a #cairo_device_t + * + * Returns the current reference count of @device. + * + * Return value: the current reference count of @device. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.10 + **/ +unsigned int +cairo_device_get_reference_count (cairo_device_t *device) +{ + if (device == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count)) + return 0; + + return CAIRO_REFERENCE_COUNT_GET_VALUE (&device->ref_count); +} + +/** + * cairo_device_get_user_data: + * @device: a #cairo_device_t + * @key: the address of the #cairo_user_data_key_t the user data was + * attached to + * + * Return user data previously attached to @device using the + * specified key. If no user data has been attached with the given + * key this function returns %NULL. + * + * Return value: the user data previously attached or %NULL. + * + * Since: 1.10 + **/ +void * +cairo_device_get_user_data (cairo_device_t *device, + const cairo_user_data_key_t *key) +{ + return _cairo_user_data_array_get_data (&device->user_data, + key); +} + +/** + * cairo_device_set_user_data: + * @device: a #cairo_device_t + * @key: the address of a #cairo_user_data_key_t to attach the user data to + * @user_data: the user data to attach to the #cairo_device_t + * @destroy: a #cairo_destroy_func_t which will be called when the + * #cairo_t is destroyed or when new user data is attached using the + * same key. + * + * Attach user data to @device. To remove user data from a surface, + * call this function with the key that was used to set it and %NULL + * for @data. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a + * slot could not be allocated for the user data. + * + * Since: 1.10 + **/ +cairo_status_t +cairo_device_set_user_data (cairo_device_t *device, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy) +{ + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count)) + return device->status; + + return _cairo_user_data_array_set_data (&device->user_data, + key, user_data, destroy); +} diff --git a/gfx/cairo/cairo/src/cairo-directfb-surface.c b/gfx/cairo/cairo/src/cairo-directfb-surface.c index afad2705268e..fc7509c1a490 100644 --- a/gfx/cairo/cairo/src/cairo-directfb-surface.c +++ b/gfx/cairo/cairo/src/cairo-directfb-surface.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -39,6 +39,7 @@ #include "cairo-directfb.h" #include "cairo-clip-private.h" +#include "cairo-error-private.h" #include @@ -564,6 +565,7 @@ _cairo_directfb_surface_create_internal (IDirectFB *dfb, _cairo_surface_init (&surface->base, &_cairo_directfb_surface_backend, + NULL, /* device */ content); surface->pixman_format = _directfb_to_pixman_format (format); surface->supported_destination = pixman_format_supported_destination (surface->pixman_format); @@ -762,14 +764,14 @@ _cairo_directfb_surface_clone_similar (void *abstract_surface, return _cairo_error (CAIRO_STATUS_NO_MEMORY); } - pixman_image_composite (PIXMAN_OP_SRC, - image_src->pixman_image, - NULL, - pixman_image, - src_x, src_y, - 0, 0, - 0, 0, - width, height); + pixman_image_composite32 (PIXMAN_OP_SRC, + image_src->pixman_image, + NULL, + pixman_image, + src_x, src_y, + 0, 0, + 0, 0, + width, height); pixman_image_unref (pixman_image); @@ -1814,7 +1816,7 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst, static cairo_bool_t -_cairo_directfb_surface_is_similar (void *surface_a, void *surface_b, cairo_content_t content) +_cairo_directfb_surface_is_similar (void *surface_a, void *surface_b) { cairo_directfb_surface_t *a = (cairo_directfb_surface_t *) surface_a; cairo_directfb_surface_t *b = (cairo_directfb_surface_t *) surface_b; @@ -1955,6 +1957,7 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface) _cairo_surface_init (&surface->base, &_cairo_directfb_surface_backend, + NULL, /* device */ _directfb_format_to_content (format)); return &surface->base; diff --git a/gfx/cairo/cairo/src/cairo-directfb.h b/gfx/cairo/cairo/src/cairo-directfb.h index 0396cb13a210..e3d818c6687c 100644 --- a/gfx/cairo/cairo/src/cairo-directfb.h +++ b/gfx/cairo/cairo/src/cairo-directfb.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-drm.h b/gfx/cairo/cairo/src/cairo-drm.h index 1b50b1bd4ebb..907610dcde87 100644 --- a/gfx/cairo/cairo/src/cairo-drm.h +++ b/gfx/cairo/cairo/src/cairo-drm.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -39,56 +39,41 @@ CAIRO_BEGIN_DECLS -typedef struct _cairo_drm_device cairo_drm_device_t; - struct udev_device; -cairo_public cairo_drm_device_t * +cairo_public cairo_device_t * cairo_drm_device_get (struct udev_device *device); -cairo_public cairo_drm_device_t * +cairo_public cairo_device_t * cairo_drm_device_get_for_fd (int fd); -cairo_public cairo_drm_device_t * +cairo_public cairo_device_t * cairo_drm_device_default (void); -cairo_public cairo_drm_device_t * -cairo_drm_device_reference (cairo_drm_device_t *device); - -cairo_public cairo_status_t -cairo_drm_device_status (cairo_drm_device_t *device); - cairo_public int -cairo_drm_device_get_fd (cairo_drm_device_t *device); +cairo_drm_device_get_fd (cairo_device_t *device); cairo_public void -cairo_drm_device_throttle (cairo_drm_device_t *device); - -cairo_public void -cairo_drm_device_destroy (cairo_drm_device_t *device); - +cairo_drm_device_throttle (cairo_device_t *device); cairo_public cairo_surface_t * -cairo_drm_surface_create (cairo_drm_device_t *device, - cairo_content_t content, +cairo_drm_surface_create (cairo_device_t *device, + cairo_format_t format, int width, int height); cairo_public cairo_surface_t * -cairo_drm_surface_create_for_name (cairo_drm_device_t *device, +cairo_drm_surface_create_for_name (cairo_device_t *device, unsigned int name, cairo_format_t format, int width, int height, int stride); cairo_public cairo_surface_t * -cairo_drm_surface_create_from_cacheable_image (cairo_drm_device_t *device, +cairo_drm_surface_create_from_cacheable_image (cairo_device_t *device, cairo_surface_t *surface); cairo_public cairo_status_t cairo_drm_surface_enable_scan_out (cairo_surface_t *surface); -cairo_public cairo_drm_device_t * -cairo_drm_surface_get_device (cairo_surface_t *abstract_surface); - cairo_public unsigned int cairo_drm_surface_get_handle (cairo_surface_t *surface); @@ -120,7 +105,7 @@ cairo_drm_surface_get_stride (cairo_surface_t *surface); * will also disassociate the mapping.) */ cairo_public cairo_surface_t * -cairo_drm_surface_map (cairo_surface_t *surface); +cairo_drm_surface_map_to_image (cairo_surface_t *surface); cairo_public void cairo_drm_surface_unmap (cairo_surface_t *drm_surface, diff --git a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp index f53f7fa502e7..0c937d072283 100644 --- a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp +++ b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp @@ -34,13 +34,12 @@ * Bas Schouten */ -extern "C" { #include "cairoint.h" #include "cairo-win32-private.h" #include "cairo-surface-private.h" #include "cairo-clip-private.h" -} + #include "cairo-d2d-private.h" #include "cairo-dwrite-private.h" #include diff --git a/gfx/cairo/cairo/src/cairo-error-private.h b/gfx/cairo/cairo/src/cairo-error-private.h new file mode 100644 index 000000000000..fc0c56438846 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-error-private.h @@ -0,0 +1,60 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef _CAIRO_ERROR_PRIVATE_H_ +#define _CAIRO_ERROR_PRIVATE_H_ + +#include "cairo.h" +#include "cairo-compiler-private.h" + +CAIRO_BEGIN_DECLS + +#define _cairo_status_is_error(status) \ + (status != CAIRO_STATUS_SUCCESS && status <= CAIRO_STATUS_LAST_STATUS) + +cairo_private cairo_status_t +_cairo_error (cairo_status_t status); + +/* hide compiler warnings when discarding the return value */ +#define _cairo_error_throw(status) do { \ + cairo_status_t status__ = _cairo_error (status); \ + (void) status__; \ +} while (0) + +CAIRO_END_DECLS + +#endif /* _CAIRO_ERROR_PRIVATE_H_ */ diff --git a/gfx/cairo/cairo/src/cairo-features.h.in b/gfx/cairo/cairo/src/cairo-features.h.in index 97fca33c94e0..c83e91a20ab1 100644 --- a/gfx/cairo/cairo/src/cairo-features.h.in +++ b/gfx/cairo/cairo/src/cairo-features.h.in @@ -89,6 +89,8 @@ @QUARTZ_FONT_FEATURE@ +@TEE_SURFACE_FEATURE@ + @PNG_FUNCTIONS_FEATURE@ @FC_FONT_FEATURE@ diff --git a/gfx/cairo/cairo/src/cairo-fixed-private.h b/gfx/cairo/cairo/src/cairo-fixed-private.h index a37ca6a70a50..9478d7d4fbc5 100644 --- a/gfx/cairo/cairo/src/cairo-fixed-private.h +++ b/gfx/cairo/cairo/src/cairo-fixed-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -53,7 +53,7 @@ #define CAIRO_FIXED_ONE_FLOAT ((float)(1 << CAIRO_FIXED_FRAC_BITS)) #define CAIRO_FIXED_EPSILON ((cairo_fixed_t)(1)) -#define CAIRO_FIXED_FRAC_MASK (((cairo_fixed_unsigned_t)(-1)) >> (CAIRO_FIXED_BITS - CAIRO_FIXED_FRAC_BITS)) +#define CAIRO_FIXED_FRAC_MASK ((cairo_fixed_t)(((cairo_fixed_unsigned_t)(-1)) >> (CAIRO_FIXED_BITS - CAIRO_FIXED_FRAC_BITS))) #define CAIRO_FIXED_WHOLE_MASK (~CAIRO_FIXED_FRAC_MASK) static inline cairo_fixed_t @@ -136,6 +136,16 @@ _cairo_fixed_from_26_6 (uint32_t i) #endif } +static inline cairo_fixed_t +_cairo_fixed_from_16_16 (uint32_t i) +{ +#if CAIRO_FIXED_FRAC_BITS > 16 + return i << (CAIRO_FIXED_FRAC_BITS - 16); +#else + return i >> (16 - CAIRO_FIXED_FRAC_BITS); +#endif +} + static inline double _cairo_fixed_to_double (cairo_fixed_t f) { @@ -154,12 +164,48 @@ _cairo_fixed_is_integer (cairo_fixed_t f) return (f & CAIRO_FIXED_FRAC_MASK) == 0; } +static inline cairo_fixed_t +_cairo_fixed_floor (cairo_fixed_t f) +{ + return f & ~CAIRO_FIXED_FRAC_MASK; +} + +static inline cairo_fixed_t +_cairo_fixed_round (cairo_fixed_t f) +{ + return _cairo_fixed_floor (f + (CAIRO_FIXED_FRAC_MASK+1)/2); +} + +static inline cairo_fixed_t +_cairo_fixed_round_down (cairo_fixed_t f) +{ + return _cairo_fixed_floor (f + CAIRO_FIXED_FRAC_MASK/2); +} + static inline int _cairo_fixed_integer_part (cairo_fixed_t f) { return f >> CAIRO_FIXED_FRAC_BITS; } +static inline int +_cairo_fixed_integer_round (cairo_fixed_t f) +{ + return _cairo_fixed_integer_part (f + (CAIRO_FIXED_FRAC_MASK+1)/2); +} + +static inline int +_cairo_fixed_integer_round_down (cairo_fixed_t f) +{ + return _cairo_fixed_integer_part (f + CAIRO_FIXED_FRAC_MASK/2); +} + +static inline int +_cairo_fixed_fractional_part (cairo_fixed_t f) +{ + return f & CAIRO_FIXED_FRAC_MASK; +} + static inline int _cairo_fixed_integer_floor (cairo_fixed_t f) { @@ -225,12 +271,18 @@ _cairo_fixed_16_16_from_double (double d) } static inline int -_cairo_fixed_16_16_floor (cairo_fixed_t f) +_cairo_fixed_16_16_floor (cairo_fixed_16_16_t f) { if (f >= 0) - return f >> 16; + return f >> 16; else - return -((-f - 1) >> 16) - 1; + return -((-f - 1) >> 16) - 1; +} + +static inline double +_cairo_fixed_16_16_to_double (cairo_fixed_16_16_t f) +{ + return ((double) f) / (double) (1 << 16); } #if CAIRO_FIXED_BITS == 32 diff --git a/gfx/cairo/cairo/src/cairo-fixed-type-private.h b/gfx/cairo/cairo/src/cairo-fixed-type-private.h index ce3c007f5851..2bbd5f786210 100644 --- a/gfx/cairo/cairo/src/cairo-fixed-type-private.h +++ b/gfx/cairo/cairo/src/cairo-fixed-type-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-fixed.c b/gfx/cairo/cairo/src/cairo-fixed.c index 2bb0dfe17673..03e05592354d 100644 --- a/gfx/cairo/cairo/src/cairo-fixed.c +++ b/gfx/cairo/cairo/src/cairo-fixed.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-font-face-twin.c b/gfx/cairo/cairo/src/cairo-font-face-twin.c index 56ebaeaa6a4a..98c6dd8a90a9 100644 --- a/gfx/cairo/cairo/src/cairo-font-face-twin.c +++ b/gfx/cairo/cairo/src/cairo-font-face-twin.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -35,6 +35,7 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" #include diff --git a/gfx/cairo/cairo/src/cairo-font-face.c b/gfx/cairo/cairo/src/cairo-font-face.c index 6744899b69e6..a66054ead83b 100644 --- a/gfx/cairo/cairo/src/cairo-font-face.c +++ b/gfx/cairo/cairo/src/cairo-font-face.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -39,6 +39,24 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" + +/** + * SECTION:cairo-font-face + * @Title: cairo_font_face_t + * @Short_Description: Base class for font faces + * @See_Also: #cairo_scaled_font_t + * + * #cairo_font_face_t represents a particular font at a particular weight, + * slant, and other characteristic but no size, transformation, or size. + * + * Font faces are created using font-backend-specific + * constructors, typically of the form + * cairo_backend_font_face_create(), or implicitly + * using the toy text API by way of + * cairo_select_font_face(). The resulting face can be accessed using + * cairo_get_font_face(). + */ /* #cairo_font_face_t */ diff --git a/gfx/cairo/cairo/src/cairo-font-options.c b/gfx/cairo/cairo/src/cairo-font-options.c index b2cb230ba65f..5d59fb0f2427 100644 --- a/gfx/cairo/cairo/src/cairo-font-options.c +++ b/gfx/cairo/cairo/src/cairo-font-options.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -35,12 +35,27 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" + +/** + * SECTION:cairo-font-options + * @Title: cairo_font_options_t + * @Short_Description: How a font should be rendered + * @See_Also: #cairo_scaled_font_t + * + * The font options specify how fonts should be rendered. Most of the + * time the font options implied by a surface are just right and do not + * need any changes, but for pixel-based targets tweaking font options + * may result in superior output on a particular display. + */ static const cairo_font_options_t _cairo_font_options_nil = { CAIRO_ANTIALIAS_DEFAULT, CAIRO_SUBPIXEL_ORDER_DEFAULT, + CAIRO_LCD_FILTER_DEFAULT, CAIRO_HINT_STYLE_DEFAULT, - CAIRO_HINT_METRICS_DEFAULT + CAIRO_HINT_METRICS_DEFAULT, + CAIRO_ROUND_GLYPH_POS_DEFAULT }; /** @@ -54,8 +69,10 @@ _cairo_font_options_init_default (cairo_font_options_t *options) { options->antialias = CAIRO_ANTIALIAS_DEFAULT; options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + options->lcd_filter = CAIRO_LCD_FILTER_DEFAULT; options->hint_style = CAIRO_HINT_STYLE_DEFAULT; options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT; + options->round_glyph_positions = CAIRO_ROUND_GLYPH_POS_DEFAULT; } void @@ -64,8 +81,10 @@ _cairo_font_options_init_copy (cairo_font_options_t *options, { options->antialias = other->antialias; options->subpixel_order = other->subpixel_order; + options->lcd_filter = other->lcd_filter; options->hint_style = other->hint_style; options->hint_metrics = other->hint_metrics; + options->round_glyph_positions = other->round_glyph_positions; } /** @@ -189,10 +208,14 @@ cairo_font_options_merge (cairo_font_options_t *options, options->antialias = other->antialias; if (other->subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) options->subpixel_order = other->subpixel_order; + if (other->lcd_filter != CAIRO_LCD_FILTER_DEFAULT) + options->lcd_filter = other->lcd_filter; if (other->hint_style != CAIRO_HINT_STYLE_DEFAULT) options->hint_style = other->hint_style; if (other->hint_metrics != CAIRO_HINT_METRICS_DEFAULT) options->hint_metrics = other->hint_metrics; + if (other->round_glyph_positions != CAIRO_ROUND_GLYPH_POS_DEFAULT) + options->round_glyph_positions = other->round_glyph_positions; } slim_hidden_def (cairo_font_options_merge); @@ -221,8 +244,10 @@ cairo_font_options_equal (const cairo_font_options_t *options, return (options->antialias == other->antialias && options->subpixel_order == other->subpixel_order && + options->lcd_filter == other->lcd_filter && options->hint_style == other->hint_style && - options->hint_metrics == other->hint_metrics); + options->hint_metrics == other->hint_metrics && + options->round_glyph_positions == other->round_glyph_positions); } slim_hidden_def (cairo_font_options_equal); @@ -246,7 +271,8 @@ cairo_font_options_hash (const cairo_font_options_t *options) return ((options->antialias) | (options->subpixel_order << 4) | - (options->hint_style << 8) | + (options->lcd_filter << 8) | + (options->hint_style << 12) | (options->hint_metrics << 16)); } slim_hidden_def (cairo_font_options_hash); @@ -327,6 +353,87 @@ cairo_font_options_get_subpixel_order (const cairo_font_options_t *options) return options->subpixel_order; } +/** + * _cairo_font_options_set_lcd_filter: + * @options: a #cairo_font_options_t + * @lcd_filter: the new LCD filter + * + * Sets the LCD filter for the font options object. The LCD filter + * specifies how pixels are filtered when rendered with an antialiasing + * mode of %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for + * #cairo_lcd_filter_t for full details. + * + * Since: 1.8 + **/ +void +_cairo_font_options_set_lcd_filter (cairo_font_options_t *options, + cairo_lcd_filter_t lcd_filter) +{ + if (cairo_font_options_status (options)) + return; + + options->lcd_filter = lcd_filter; +} + +/** + * _cairo_font_options_get_lcd_filter: + * @options: a #cairo_font_options_t + * + * Gets the LCD filter for the font options object. + * See the documentation for #cairo_lcd_filter_t for full details. + * + * Return value: the LCD filter for the font options object + * + * Since: 1.8 + **/ +cairo_lcd_filter_t +_cairo_font_options_get_lcd_filter (const cairo_font_options_t *options) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return CAIRO_LCD_FILTER_DEFAULT; + + return options->lcd_filter; +} + +/** + * _cairo_font_options_set_round_glyph_positions: + * @options: a #cairo_font_options_t + * @round: the new rounding value + * + * Sets the rounding options for the font options object. If rounding is set, a + * glyph's position will be rounded to integer values. + * + * Since: 1.12 + **/ +void +_cairo_font_options_set_round_glyph_positions (cairo_font_options_t *options, + cairo_round_glyph_positions_t round) +{ + if (cairo_font_options_status (options)) + return; + + options->round_glyph_positions = round; +} + +/** + * _cairo_font_options_get_round_glyph_positions: + * @options: a #cairo_font_options_t + * + * Gets the glyph position rounding option for the font options object. + * + * Return value: The round glyph posistions flag for the font options object. + * + * Since: 1.12 + **/ +cairo_round_glyph_positions_t +_cairo_font_options_get_round_glyph_positions (const cairo_font_options_t *options) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return CAIRO_ROUND_GLYPH_POS_DEFAULT; + + return options->round_glyph_positions; +} + /** * cairo_font_options_set_hint_style: * @options: a #cairo_font_options_t diff --git a/gfx/cairo/cairo/src/cairo-fontconfig-private.h b/gfx/cairo/cairo/src/cairo-fontconfig-private.h new file mode 100644 index 000000000000..ea873abe7e4d --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-fontconfig-private.h @@ -0,0 +1,78 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2000 Keith Packard + * Copyright © 2005 Red Hat, Inc + * Copyright © 2010 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Graydon Hoare + * Owen Taylor + * Keith Packard + * Carl Worth + * Chris Wilson + */ + +#ifndef _CAIRO_FONTCONFIG_PRIVATE_H +#define _CAIRO_FONTCONFIG_PRIVATE_H + +#include "cairo.h" + +#if CAIRO_HAS_FC_FONT +#include +#include +#endif + +/* sub-pixel order */ +#ifndef FC_RGBA_UNKNOWN +#define FC_RGBA_UNKNOWN 0 +#define FC_RGBA_RGB 1 +#define FC_RGBA_BGR 2 +#define FC_RGBA_VRGB 3 +#define FC_RGBA_VBGR 4 +#define FC_RGBA_NONE 5 +#endif + +/* hinting style */ +#ifndef FC_HINT_NONE +#define FC_HINT_NONE 0 +#define FC_HINT_SLIGHT 1 +#define FC_HINT_MEDIUM 2 +#define FC_HINT_FULL 3 +#endif + +/* LCD filter */ +#ifndef FC_LCD_NONE +#define FC_LCD_NONE 0 +#define FC_LCD_DEFAULT 1 +#define FC_LCD_LIGHT 2 +#define FC_LCD_LEGACY 3 +#endif + +#endif /* _CAIRO_FONTCONFIG_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-freed-pool-private.h b/gfx/cairo/cairo/src/cairo-freed-pool-private.h new file mode 100644 index 000000000000..0a4ab0eee5ae --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-freed-pool-private.h @@ -0,0 +1,129 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_FREED_POOL_H +#define CAIRO_FREED_POOL_H + +#include "cairoint.h" +#include "cairo-atomic-private.h" + +#if HAS_ATOMIC_OPS +/* Keep a stash of recently freed clip_paths, since we need to + * reallocate them frequently. + */ +#define MAX_FREED_POOL_SIZE 4 +typedef struct { + void *pool[MAX_FREED_POOL_SIZE]; + int top; +} freed_pool_t; + +static cairo_always_inline void * +_atomic_fetch (void **slot) +{ + void *ptr; + + do { + ptr = _cairo_atomic_ptr_get (slot); + } while (! _cairo_atomic_ptr_cmpxchg (slot, ptr, NULL)); + + return ptr; +} + +static cairo_always_inline cairo_bool_t +_atomic_store (void **slot, void *ptr) +{ + return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr); +} + +cairo_private void * +_freed_pool_get_search (freed_pool_t *pool); + +static inline void * +_freed_pool_get (freed_pool_t *pool) +{ + void *ptr; + int i; + + i = pool->top - 1; + if (i < 0) + i = 0; + + ptr = _atomic_fetch (&pool->pool[i]); + if (likely (ptr != NULL)) { + pool->top = i; + return ptr; + } + + /* either empty or contended */ + return _freed_pool_get_search (pool); +} + +cairo_private void +_freed_pool_put_search (freed_pool_t *pool, void *ptr); + +static inline void +_freed_pool_put (freed_pool_t *pool, void *ptr) +{ + int i; + + i = pool->top; + if (likely (i < ARRAY_LENGTH (pool->pool) && + _atomic_store (&pool->pool[i], ptr))) + { + pool->top = i + 1; + return; + } + + /* either full or contended */ + _freed_pool_put_search (pool, ptr); +} + +cairo_private void +_freed_pool_reset (freed_pool_t *pool); + +#define HAS_FREED_POOL 1 + +#else + +typedef int freed_pool_t; + +#define _freed_pool_get(pool) NULL +#define _freed_pool_put(pool, ptr) free(ptr) +#define _freed_pool_reset(ptr) + +#endif + +#endif /* CAIRO_FREED_POOL_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-freed-pool.c b/gfx/cairo/cairo/src/cairo-freed-pool.c new file mode 100644 index 000000000000..cfdc8e96b059 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-freed-pool.c @@ -0,0 +1,93 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-freed-pool-private.h" + +#if HAS_FREED_POOL + +void * +_freed_pool_get_search (freed_pool_t *pool) +{ + void *ptr; + int i; + + for (i = ARRAY_LENGTH (pool->pool); i--;) { + ptr = _atomic_fetch (&pool->pool[i]); + if (ptr != NULL) { + pool->top = i; + return ptr; + } + } + + /* empty */ + pool->top = 0; + return NULL; +} + +void +_freed_pool_put_search (freed_pool_t *pool, void *ptr) +{ + int i; + + for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) { + if (_atomic_store (&pool->pool[i], ptr)) { + pool->top = i + 1; + return; + } + } + + /* full */ + pool->top = i; + free (ptr); +} + +void +_freed_pool_reset (freed_pool_t *pool) +{ + int i; + + for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) { + free (pool->pool[i]); + pool->pool[i] = NULL; + } + + pool->top = 0; +} + +#endif diff --git a/gfx/cairo/cairo/src/cairo-freelist-private.h b/gfx/cairo/cairo/src/cairo-freelist-private.h index 5be22b1f9646..703181b567c3 100644 --- a/gfx/cairo/cairo/src/cairo-freelist-private.h +++ b/gfx/cairo/cairo/src/cairo-freelist-private.h @@ -24,6 +24,7 @@ #include "cairo-types-private.h" #include "cairo-compiler-private.h" +#include "cairo-freelist-type-private.h" /* for stand-alone compilation*/ #ifndef VG @@ -34,32 +35,6 @@ #define NULL (void *) 0 #endif -typedef struct _cairo_freelist_node cairo_freelist_node_t; -struct _cairo_freelist_node { - cairo_freelist_node_t *next; -}; - -typedef struct _cairo_freelist { - cairo_freelist_node_t *first_free_node; - unsigned nodesize; -} cairo_freelist_t; - -typedef struct _cairo_freelist_pool cairo_freelist_pool_t; -struct _cairo_freelist_pool { - cairo_freelist_pool_t *next; - unsigned size, rem; - uint8_t *data; -}; - -typedef struct _cairo_freepool { - cairo_freelist_node_t *first_free_node; - cairo_freelist_pool_t *pools; - unsigned nodesize; - cairo_freelist_pool_t embedded_pool; - uint8_t embedded_data[1000]; -} cairo_freepool_t; - - /* Initialise a freelist that will be responsible for allocating * nodes of size nodesize. */ cairo_private void @@ -96,6 +71,20 @@ _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize); cairo_private void _cairo_freepool_fini (cairo_freepool_t *freepool); +static inline void +_cairo_freepool_reset (cairo_freepool_t *freepool) +{ + while (freepool->pools != &freepool->embedded_pool) { + cairo_freelist_pool_t *pool = freepool->pools; + freepool->pools = pool->next; + pool->next = freepool->freepools; + freepool->freepools = pool; + } + + freepool->embedded_pool.rem = sizeof (freepool->embedded_data); + freepool->embedded_pool.data = freepool->embedded_data; +} + cairo_private void * _cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool); diff --git a/gfx/cairo/cairo/src/cairo-freelist-type-private.h b/gfx/cairo/cairo/src/cairo-freelist-type-private.h new file mode 100644 index 000000000000..4dd056461078 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-freelist-type-private.h @@ -0,0 +1,54 @@ +/* + * Copyright © 2010 Joonas Pihlaja + * + * 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 copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#ifndef CAIRO_FREELIST_TYPE_H +#define CAIRO_FREELIST_TYPE_H + +#include "cairo-types-private.h" +#include "cairo-compiler-private.h" + +typedef struct _cairo_freelist_node cairo_freelist_node_t; +struct _cairo_freelist_node { + cairo_freelist_node_t *next; +}; + +typedef struct _cairo_freelist { + cairo_freelist_node_t *first_free_node; + unsigned nodesize; +} cairo_freelist_t; + +typedef struct _cairo_freelist_pool cairo_freelist_pool_t; +struct _cairo_freelist_pool { + cairo_freelist_pool_t *next; + unsigned size, rem; + uint8_t *data; +}; + +typedef struct _cairo_freepool { + cairo_freelist_node_t *first_free_node; + cairo_freelist_pool_t *pools; + cairo_freelist_pool_t *freepools; + unsigned nodesize; + cairo_freelist_pool_t embedded_pool; + uint8_t embedded_data[1000]; +} cairo_freepool_t; + +#endif /* CAIRO_FREELIST_TYPE_H */ diff --git a/gfx/cairo/cairo/src/cairo-freelist.c b/gfx/cairo/cairo/src/cairo-freelist.c index acf31573f048..d596eab81dcb 100644 --- a/gfx/cairo/cairo/src/cairo-freelist.c +++ b/gfx/cairo/cairo/src/cairo-freelist.c @@ -22,6 +22,7 @@ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-freelist-private.h" void @@ -83,12 +84,12 @@ _cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode) } } - void _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize) { freepool->first_free_node = NULL; freepool->pools = &freepool->embedded_pool; + freepool->freepools = NULL; freepool->nodesize = nodesize; freepool->embedded_pool.next = NULL; @@ -96,19 +97,28 @@ _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize) freepool->embedded_pool.rem = sizeof (freepool->embedded_data); freepool->embedded_pool.data = freepool->embedded_data; - VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data, - sizeof (freepool->embedded_data))); + VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data, sizeof (freepool->embedded_data))); } void _cairo_freepool_fini (cairo_freepool_t *freepool) { - cairo_freelist_pool_t *pool = freepool->pools; + cairo_freelist_pool_t *pool; + + pool = freepool->pools; while (pool != &freepool->embedded_pool) { cairo_freelist_pool_t *next = pool->next; free (pool); pool = next; } + + pool = freepool->freepools; + while (pool != NULL) { + cairo_freelist_pool_t *next = pool->next; + free (pool); + pool = next; + } + VG (VALGRIND_MAKE_MEM_NOACCESS (freepool, sizeof (freepool))); } @@ -118,23 +128,31 @@ _cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool) cairo_freelist_pool_t *pool; int poolsize; - if (freepool->pools != &freepool->embedded_pool) - poolsize = 2 * freepool->pools->size; - else - poolsize = (128 * freepool->nodesize + 8191) & -8192; - pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize); - if (unlikely (pool == NULL)) - return pool; + if (freepool->freepools != NULL) { + pool = freepool->freepools; + freepool->freepools = pool->next; + + poolsize = pool->size; + } else { + if (freepool->pools != &freepool->embedded_pool) + poolsize = 2 * freepool->pools->size; + else + poolsize = (128 * freepool->nodesize + 8191) & -8192; + + pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize); + if (unlikely (pool == NULL)) + return pool; + + pool->size = poolsize; + } pool->next = freepool->pools; freepool->pools = pool; - pool->size = poolsize; pool->rem = poolsize - freepool->nodesize; pool->data = (uint8_t *) (pool + 1) + freepool->nodesize; - VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, poolsize)); - VG (VALGRIND_MAKE_MEM_UNDEFINED (pool->data, freepool->nodesize)); + VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, pool->rem)); return pool + 1; } diff --git a/gfx/cairo/cairo/src/cairo-ft-font.c b/gfx/cairo/cairo/src/cairo-ft-font.c index e94cdb73aec3..986036e7087f 100644 --- a/gfx/cairo/cairo/src/cairo-ft-font.c +++ b/gfx/cairo/cairo/src/cairo-ft-font.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -41,14 +41,12 @@ #define _BSD_SOURCE /* for strdup() */ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-ft-private.h" #include -#if CAIRO_HAS_FC_FONT -#include -#include -#endif +#include "cairo-fontconfig-private.h" #include #include FT_FREETYPE_H @@ -59,6 +57,30 @@ #include FT_SYNTHESIS_H #endif +#if HAVE_FT_LIBRARY_SETLCDFILTER +#include FT_LCD_FILTER_H +#endif + +/* Fontconfig version older than 2.6 didn't have these options */ +#ifndef FC_LCD_FILTER +#define FC_LCD_FILTER "lcdfilter" +#endif +/* Some Ubuntu versions defined FC_LCD_FILTER without defining the following */ +#ifndef FC_LCD_NONE +#define FC_LCD_NONE 0 +#define FC_LCD_DEFAULT 1 +#define FC_LCD_LIGHT 2 +#define FC_LCD_LEGACY 3 +#endif + +/* FreeType version older than 2.3.5(?) didn't have these options */ +#ifndef FT_LCD_FILTER_NONE +#define FT_LCD_FILTER_NONE 0 +#define FT_LCD_FILTER_DEFAULT 1 +#define FT_LCD_FILTER_LIGHT 2 +#define FT_LCD_FILTER_LEGACY 16 +#endif + #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)) @@ -67,11 +89,35 @@ /* This is the max number of FT_face objects we keep open at once */ #define MAX_OPEN_FACES 10 - /* This is the maximum font size we allow to be passed to FT_Set_Char_Size */ #define MAX_FONT_SIZE 1000 +/** + * SECTION:cairo-ft + * @Title: FreeType Fonts + * @Short_Description: Font support for FreeType + * @See_Also: #cairo_font_face_t + * + * The FreeType font backend is primarily used to render text on GNU/Linux + * systems, but can be used on other platforms too. + */ + +/** + * CAIRO_HAS_FT_FONT: + * + * Defined if the FreeType font backend is available. + * This macro can be used to conditionally compile backend-specific code. + */ + +/** + * CAIRO_HAS_FC_FONT: + * + * Defined if the Fontconfig-specific functions of the FreeType font backend + * are available. + * This macro can be used to conditionally compile backend-specific code. + */ + /* * The simple 2x2 matrix is converted into separate scale and shape * factors so that hinting works right @@ -180,6 +226,7 @@ typedef struct _cairo_ft_unscaled_font_map { static cairo_ft_unscaled_font_map_t *cairo_ft_unscaled_font_map = NULL; + static void _font_map_release_face_lock_held (cairo_ft_unscaled_font_map_t *font_map, cairo_ft_unscaled_font_t *unscaled) @@ -779,23 +826,279 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, return CAIRO_STATUS_SUCCESS; } -/* Empirically-derived subpixel filtering values thanks to Keith - * Packard and libXft. */ -static const int filters[3][3] = { - /* red */ -#if 0 - { 65538*4/7,65538*2/7,65538*1/7 }, - /* green */ - { 65536*1/4, 65536*2/4, 65537*1/4 }, - /* blue */ - { 65538*1/7,65538*2/7,65538*4/7 }, -#endif - { 65538*9/13,65538*3/13,65538*1/13 }, - /* green */ - { 65538*1/6, 65538*4/6, 65538*1/6 }, - /* blue */ - { 65538*1/13,65538*3/13,65538*9/13 }, -}; +/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot + * into a different format. For example, we want to convert a + * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit + * ARGB or ABGR bitmap. + * + * this function prepares a target descriptor for this operation. + * + * input :: target bitmap descriptor. The function will set its + * 'width', 'rows' and 'pitch' fields, and only these + * + * slot :: the glyph slot containing the source bitmap. this + * function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP + * + * mode :: the requested final rendering mode. supported values are + * MONO, NORMAL (i.e. gray), LCD and LCD_V + * + * the function returns the size in bytes of the corresponding buffer, + * it's up to the caller to allocate the corresponding memory block + * before calling _fill_xrender_bitmap + * + * it also returns -1 in case of error (e.g. incompatible arguments, + * like trying to convert a gray bitmap into a monochrome one) + */ +static int +_compute_xrender_bitmap_size(FT_Bitmap *target, + FT_GlyphSlot slot, + FT_Render_Mode mode) +{ + FT_Bitmap *ftbit; + int width, height, pitch; + + if (slot->format != FT_GLYPH_FORMAT_BITMAP) + return -1; + + /* compute the size of the final bitmap */ + ftbit = &slot->bitmap; + + width = ftbit->width; + height = ftbit->rows; + pitch = (width + 3) & ~3; + + switch (ftbit->pixel_mode) { + case FT_PIXEL_MODE_MONO: + if (mode == FT_RENDER_MODE_MONO) { + pitch = (((width + 31) & ~31) >> 3); + break; + } + /* fall-through */ + + case FT_PIXEL_MODE_GRAY: + if (mode == FT_RENDER_MODE_LCD || + mode == FT_RENDER_MODE_LCD_V) + { + /* each pixel is replicated into a 32-bit ARGB value */ + pitch = width * 4; + } + break; + + case FT_PIXEL_MODE_LCD: + if (mode != FT_RENDER_MODE_LCD) + return -1; + + /* horz pixel triplets are packed into 32-bit ARGB values */ + width /= 3; + pitch = width * 4; + break; + + case FT_PIXEL_MODE_LCD_V: + if (mode != FT_RENDER_MODE_LCD_V) + return -1; + + /* vert pixel triplets are packed into 32-bit ARGB values */ + height /= 3; + pitch = width * 4; + break; + + default: /* unsupported source format */ + return -1; + } + + target->width = width; + target->rows = height; + target->pitch = pitch; + target->buffer = NULL; + + return pitch * height; +} + +/* this functions converts the glyph bitmap found in a FT_GlyphSlot + * into a different format (see _compute_xrender_bitmap_size) + * + * you should call this function after _compute_xrender_bitmap_size + * + * target :: target bitmap descriptor. Note that its 'buffer' pointer + * must point to memory allocated by the caller + * + * slot :: the glyph slot containing the source bitmap + * + * mode :: the requested final rendering mode + * + * bgr :: boolean, set if BGR or VBGR pixel ordering is needed + */ +static void +_fill_xrender_bitmap(FT_Bitmap *target, + FT_GlyphSlot slot, + FT_Render_Mode mode, + int bgr) +{ + FT_Bitmap *ftbit = &slot->bitmap; + unsigned char *srcLine = ftbit->buffer; + unsigned char *dstLine = target->buffer; + int src_pitch = ftbit->pitch; + int width = target->width; + int height = target->rows; + int pitch = target->pitch; + int subpixel; + int h; + + subpixel = (mode == FT_RENDER_MODE_LCD || + mode == FT_RENDER_MODE_LCD_V); + + if (src_pitch < 0) + srcLine -= src_pitch * (ftbit->rows - 1); + + target->pixel_mode = ftbit->pixel_mode; + + switch (ftbit->pixel_mode) { + case FT_PIXEL_MODE_MONO: + if (subpixel) { + /* convert mono to ARGB32 values */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { + int x; + + for (x = 0; x < width; x++) { + if (srcLine[(x >> 3)] & (0x80 >> (x & 7))) + ((unsigned int *) dstLine)[x] = 0xffffffffU; + } + } + target->pixel_mode = FT_PIXEL_MODE_LCD; + + } else if (mode == FT_RENDER_MODE_NORMAL) { + /* convert mono to 8-bit gray */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { + int x; + + for (x = 0; x < width; x++) { + if (srcLine[(x >> 3)] & (0x80 >> (x & 7))) + dstLine[x] = 0xff; + } + } + target->pixel_mode = FT_PIXEL_MODE_GRAY; + + } else { + /* copy mono to mono */ + + int bytes = (width + 7) >> 3; + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) + memcpy (dstLine, srcLine, bytes); + } + break; + + case FT_PIXEL_MODE_GRAY: + if (subpixel) { + /* convert gray to ARGB32 values */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { + int x; + unsigned int *dst = (unsigned int *) dstLine; + + for (x = 0; x < width; x++) { + unsigned int pix = srcLine[x]; + + pix |= (pix << 8); + pix |= (pix << 16); + + dst[x] = pix; + } + } + target->pixel_mode = FT_PIXEL_MODE_LCD; + } else { + /* copy gray into gray */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) + memcpy (dstLine, srcLine, width); + } + break; + + case FT_PIXEL_MODE_LCD: + if (!bgr) { + /* convert horizontal RGB into ARGB32 */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { + int x; + unsigned char *src = srcLine; + unsigned int *dst = (unsigned int *) dstLine; + + for (x = 0; x < width; x++, src += 3) { + unsigned int pix; + + pix = ((unsigned int)src[0] << 16) | + ((unsigned int)src[1] << 8) | + ((unsigned int)src[2] ) | + ((unsigned int)src[1] << 24) ; + + dst[x] = pix; + } + } + } else { + /* convert horizontal BGR into ARGB32 */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { + + int x; + unsigned char *src = srcLine; + unsigned int *dst = (unsigned int *) dstLine; + + for (x = 0; x < width; x++, src += 3) { + unsigned int pix; + + pix = ((unsigned int)src[2] << 16) | + ((unsigned int)src[1] << 8) | + ((unsigned int)src[0] ) | + ((unsigned int)src[1] << 24) ; + + dst[x] = pix; + } + } + } + break; + + default: /* FT_PIXEL_MODE_LCD_V */ + /* convert vertical RGB into ARGB32 */ + if (!bgr) { + + for (h = height; h > 0; h--, srcLine += 3 * src_pitch, dstLine += pitch) { + int x; + unsigned char* src = srcLine; + unsigned int* dst = (unsigned int *) dstLine; + + for (x = 0; x < width; x++, src += 1) { + unsigned int pix; + pix = ((unsigned int)src[0] << 16) | + ((unsigned int)src[src_pitch] << 8) | + ((unsigned int)src[src_pitch*2] ) | + ((unsigned int)src[src_pitch] << 24) ; + dst[x] = pix; + } + } + } else { + + for (h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch) { + int x; + unsigned char *src = srcLine; + unsigned int *dst = (unsigned int *) dstLine; + + for (x = 0; x < width; x++, src += 1) { + unsigned int pix; + + pix = ((unsigned int)src[src_pitch * 2] << 16) | + ((unsigned int)src[src_pitch] << 8) | + ((unsigned int)src[0] ) | + ((unsigned int)src[src_pitch] << 24) ; + + dst[x] = pix; + } + } + } + } +} + /* Fills in val->image with an image surface created from @bitmap */ @@ -808,6 +1111,7 @@ _get_bitmap_surface (FT_Bitmap *bitmap, int width, height, stride; unsigned char *data; int format = CAIRO_FORMAT_A8; + cairo_image_surface_t *image; width = bitmap->width; height = bitmap->rows; @@ -864,11 +1168,7 @@ _get_bitmap_surface (FT_Bitmap *bitmap, case FT_PIXEL_MODE_LCD: case FT_PIXEL_MODE_LCD_V: case FT_PIXEL_MODE_GRAY: - switch (font_options->antialias) { - case CAIRO_ANTIALIAS_DEFAULT: - case CAIRO_ANTIALIAS_GRAY: - case CAIRO_ANTIALIAS_NONE: - default: + if (font_options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) { stride = bitmap->pitch; if (own_buffer) { data = bitmap->buffer; @@ -879,104 +1179,18 @@ _get_bitmap_surface (FT_Bitmap *bitmap, memcpy (data, bitmap->buffer, stride * height); } - format = CAIRO_FORMAT_A8; - break; - case CAIRO_ANTIALIAS_SUBPIXEL: { - int x, y; - unsigned char *in_line, *out_line, *in; - unsigned int *out; - unsigned int red, green, blue; - int rf, gf, bf; - int s; - int o, os; - unsigned char *data_rgba; - unsigned int width_rgba, stride_rgba; - int vmul = 1; - int hmul = 1; - switch (font_options->subpixel_order) { - case CAIRO_SUBPIXEL_ORDER_DEFAULT: - case CAIRO_SUBPIXEL_ORDER_RGB: - case CAIRO_SUBPIXEL_ORDER_BGR: - default: - width /= 3; - hmul = 3; - break; - case CAIRO_SUBPIXEL_ORDER_VRGB: - case CAIRO_SUBPIXEL_ORDER_VBGR: - vmul = 3; - height /= 3; - break; - } - /* - * Filter the glyph to soften the color fringes - */ - width_rgba = width; - stride = bitmap->pitch; - stride_rgba = (width_rgba * 4 + 3) & ~3; - data_rgba = calloc (stride_rgba, height); - if (unlikely (data_rgba == NULL)) { - if (own_buffer) - free (bitmap->buffer); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } + format = CAIRO_FORMAT_A8; + } else { + /* if we get there, the data from the source bitmap + * really comes from _fill_xrender_bitmap, and is + * made of 32-bit ARGB or ABGR values */ + assert (own_buffer != 0); + assert (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY); - os = 1; - switch (font_options->subpixel_order) { - case CAIRO_SUBPIXEL_ORDER_VRGB: - os = stride; - case CAIRO_SUBPIXEL_ORDER_DEFAULT: - case CAIRO_SUBPIXEL_ORDER_RGB: - default: - rf = 0; - gf = 1; - bf = 2; - break; - case CAIRO_SUBPIXEL_ORDER_VBGR: - os = stride; - case CAIRO_SUBPIXEL_ORDER_BGR: - bf = 0; - gf = 1; - rf = 2; - break; - } - in_line = bitmap->buffer; - out_line = data_rgba; - for (y = 0; y < height; y++) - { - in = in_line; - out = (unsigned int *) out_line; - in_line += stride * vmul; - out_line += stride_rgba; - for (x = 0; x < width * hmul; x += hmul) - { - red = green = blue = 0; - o = 0; - for (s = 0; s < 3; s++) - { - red += filters[rf][s]*in[x+o]; - green += filters[gf][s]*in[x+o]; - blue += filters[bf][s]*in[x+o]; - o += os; - } - red = red / 65536; - green = green / 65536; - blue = blue / 65536; - *out++ = (green << 24) | (red << 16) | (green << 8) | blue; - } - } - - /* Images here are stored in native format. The - * backend must convert to its own format as needed - */ - - if (own_buffer) - free (bitmap->buffer); - data = data_rgba; - stride = stride_rgba; - format = CAIRO_FORMAT_ARGB32; - break; - } + data = bitmap->buffer; + stride = bitmap->pitch; + format = CAIRO_FORMAT_ARGB32; } break; case FT_PIXEL_MODE_GRAY2: @@ -988,18 +1202,22 @@ _get_bitmap_surface (FT_Bitmap *bitmap, return _cairo_error (CAIRO_STATUS_NO_MEMORY); } - *surface = (cairo_image_surface_t *) + /* XXX */ + *surface = image = (cairo_image_surface_t *) cairo_image_surface_create_for_data (data, format, width, height, stride); - if ((*surface)->base.status) { + if (image->base.status) { free (data); return (*surface)->base.status; } - _cairo_image_surface_assume_ownership_of_data ((*surface)); + if (format == CAIRO_FORMAT_ARGB32) + pixman_image_set_component_alpha (image->pixman_image, TRUE); - _cairo_debug_check_image_surface_is_defined (&(*surface)->base); + _cairo_image_surface_assume_ownership_of_data (image); + + _cairo_debug_check_image_surface_is_defined (&image->base); return CAIRO_STATUS_SUCCESS; } @@ -1024,16 +1242,59 @@ _render_glyph_outline (FT_Face face, cairo_font_options_t *font_options, cairo_image_surface_t **surface) { + int rgba = FC_RGBA_UNKNOWN; + int lcd_filter = FT_LCD_FILTER_LEGACY; FT_GlyphSlot glyphslot = face->glyph; FT_Outline *outline = &glyphslot->outline; FT_Bitmap bitmap; FT_BBox cbox; - FT_Matrix matrix; - int hmul = 1; - int vmul = 1; - unsigned int width, height, stride; - cairo_bool_t subpixel = FALSE; + unsigned int width, height; cairo_status_t status; + FT_Error fterror; + FT_Library library = glyphslot->library; + FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL; + + switch (font_options->antialias) { + case CAIRO_ANTIALIAS_NONE: + render_mode = FT_RENDER_MODE_MONO; + break; + + case CAIRO_ANTIALIAS_SUBPIXEL: + switch (font_options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + case CAIRO_SUBPIXEL_ORDER_BGR: + render_mode = FT_RENDER_MODE_LCD; + break; + + case CAIRO_SUBPIXEL_ORDER_VRGB: + case CAIRO_SUBPIXEL_ORDER_VBGR: + render_mode = FT_RENDER_MODE_LCD_V; + break; + } + + switch (font_options->lcd_filter) { + case CAIRO_LCD_FILTER_NONE: + lcd_filter = FT_LCD_FILTER_NONE; + break; + case CAIRO_LCD_FILTER_DEFAULT: + case CAIRO_LCD_FILTER_INTRA_PIXEL: + lcd_filter = FT_LCD_FILTER_LEGACY; + break; + case CAIRO_LCD_FILTER_FIR3: + lcd_filter = FT_LCD_FILTER_LIGHT; + break; + case CAIRO_LCD_FILTER_FIR5: + lcd_filter = FT_LCD_FILTER_DEFAULT; + break; + } + + break; + + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_GRAY: + render_mode = FT_RENDER_MODE_NORMAL; + } FT_Outline_Get_CBox (outline, &cbox); @@ -1044,20 +1305,21 @@ _render_glyph_outline (FT_Face face, width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); - stride = (width * hmul + 3) & ~3; if (width * height == 0) { cairo_format_t format; /* Looks like fb handles zero-sized images just fine */ - switch (font_options->antialias) { - case CAIRO_ANTIALIAS_NONE: + switch (render_mode) { + case FT_RENDER_MODE_MONO: format = CAIRO_FORMAT_A1; break; - case CAIRO_ANTIALIAS_SUBPIXEL: + case FT_RENDER_MODE_LCD: + case FT_RENDER_MODE_LCD_V: format= CAIRO_FORMAT_ARGB32; break; - case CAIRO_ANTIALIAS_DEFAULT: - case CAIRO_ANTIALIAS_GRAY: + case FT_RENDER_MODE_LIGHT: + case FT_RENDER_MODE_NORMAL: + case FT_RENDER_MODE_MAX: default: format = CAIRO_FORMAT_A8; break; @@ -1067,75 +1329,74 @@ _render_glyph_outline (FT_Face face, cairo_image_surface_create_for_data (NULL, format, 0, 0, 0); if ((*surface)->base.status) return (*surface)->base.status; - } else { + } else { - matrix.xx = matrix.yy = 0x10000L; - matrix.xy = matrix.yx = 0; + int bitmap_size; - switch (font_options->antialias) { - case CAIRO_ANTIALIAS_NONE: - bitmap.pixel_mode = FT_PIXEL_MODE_MONO; - bitmap.num_grays = 1; - stride = ((width + 31) & -32) >> 3; - break; - case CAIRO_ANTIALIAS_DEFAULT: - case CAIRO_ANTIALIAS_GRAY: - bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; - bitmap.num_grays = 256; - stride = (width + 3) & -4; - break; - case CAIRO_ANTIALIAS_SUBPIXEL: - switch (font_options->subpixel_order) { - case CAIRO_SUBPIXEL_ORDER_RGB: - case CAIRO_SUBPIXEL_ORDER_BGR: - case CAIRO_SUBPIXEL_ORDER_DEFAULT: - default: - matrix.xx *= 3; - hmul = 3; - subpixel = TRUE; - break; - case CAIRO_SUBPIXEL_ORDER_VRGB: - case CAIRO_SUBPIXEL_ORDER_VBGR: - matrix.yy *= 3; - vmul = 3; - subpixel = TRUE; - break; + switch (render_mode) { + case FT_RENDER_MODE_LCD: + if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_BGR) { + rgba = FC_RGBA_BGR; + } else { + rgba = FC_RGBA_RGB; + } + case FT_RENDER_MODE_LCD_V: + if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_VBGR) { + rgba = FC_RGBA_VBGR; + } else { + rgba = FC_RGBA_VRGB; + } + break; + case FT_RENDER_MODE_MONO: + case FT_RENDER_MODE_LIGHT: + case FT_RENDER_MODE_NORMAL: + case FT_RENDER_MODE_MAX: + default: + break; } - FT_Outline_Transform (outline, &matrix); - bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; - bitmap.num_grays = 256; - stride = (width * hmul + 3) & -4; - } +#if HAVE_FT_LIBRARY_SETLCDFILTER + FT_Library_SetLcdFilter (library, lcd_filter); +#endif - bitmap.pitch = stride; - bitmap.width = width * hmul; - bitmap.rows = height * vmul; - bitmap.buffer = calloc (stride, bitmap.rows); - if (unlikely (bitmap.buffer == NULL)) + fterror = FT_Render_Glyph (face->glyph, render_mode); + +#if HAVE_FT_LIBRARY_SETLCDFILTER + FT_Library_SetLcdFilter (library, FT_LCD_FILTER_NONE); +#endif + + if (fterror != 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + bitmap_size = _compute_xrender_bitmap_size (&bitmap, + face->glyph, + render_mode); + if (bitmap_size < 0) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul); + bitmap.buffer = calloc (1, bitmap_size); + if (bitmap.buffer == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); - if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) { - free (bitmap.buffer); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } + _fill_xrender_bitmap (&bitmap, face->glyph, render_mode, + (rgba == FC_RGBA_BGR || rgba == FC_RGBA_VBGR)); + /* Note: + * _get_bitmap_surface will free bitmap.buffer if there is an error + */ status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface); if (unlikely (status)) return status; - } - /* - * Note: the font's coordinate system is upside down from ours, so the - * Y coordinate of the control box needs to be negated. Moreover, device - * offsets are position of glyph origin relative to top left while xMin - * and yMax are offsets of top left relative to origin. Another negation. - */ - cairo_surface_set_device_offset (&(*surface)->base, - floor (-(double) cbox.xMin / 64.0), - floor (+(double) cbox.yMax / 64.0)); + /* Note: the font's coordinate system is upside down from ours, so the + * Y coordinate of the control box needs to be negated. Moreover, device + * offsets are position of glyph origin relative to top left while xMin + * and yMax are offsets of top left relative to origin. Another negation. + */ + cairo_surface_set_device_offset (&(*surface)->base, + (double)-glyphslot->bitmap_left, + (double)+glyphslot->bitmap_top); + } return CAIRO_STATUS_SUCCESS; } @@ -1207,8 +1468,8 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, original_to_transformed = *shape; cairo_surface_get_device_offset (&(*surface)->base, &origin_x, &origin_y); - orig_width = cairo_image_surface_get_width (&(*surface)->base); - orig_height = cairo_image_surface_get_height (&(*surface)->base); + orig_width = (*surface)->width; + orig_height = (*surface)->height; cairo_matrix_translate (&original_to_transformed, -origin_x, -origin_y); @@ -1246,9 +1507,8 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, original_to_transformed.x0 -= x_min; original_to_transformed.y0 -= y_min; - /* Create the transformed bitmap - */ - width = x_max - x_min; + /* Create the transformed bitmap */ + width = x_max - x_min; height = y_max - y_min; transformed_to_original = original_to_transformed; @@ -1256,30 +1516,19 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, if (unlikely (status)) return status; - /* We need to pad out the width to 32-bit intervals for cairo-xlib-surface.c */ - width = (width + 3) & ~3; image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); if (unlikely (image->status)) return image->status; - /* Initialize it to empty - */ - status = _cairo_surface_fill_rectangle (image, CAIRO_OPERATOR_CLEAR, - CAIRO_COLOR_TRANSPARENT, - 0, 0, - width, height); - if (unlikely (status)) { - cairo_surface_destroy (image); - return status; - } - /* Draw the original bitmap transformed into the new bitmap */ _cairo_pattern_init_for_surface (&pattern, &(*surface)->base); cairo_pattern_set_matrix (&pattern.base, &transformed_to_original); - status = _cairo_surface_paint (image, CAIRO_OPERATOR_OVER, - &pattern.base, NULL); + status = _cairo_surface_paint (image, + CAIRO_OPERATOR_SOURCE, + &pattern.base, + NULL); _cairo_pattern_fini (&pattern.base); @@ -1355,6 +1604,7 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret) if (antialias) { cairo_subpixel_order_t subpixel_order; + int lcd_filter; /* disable hinting if requested */ if (FcPatternGetBool (pattern, @@ -1390,6 +1640,25 @@ _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret) ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL; } + if (FcPatternGetInteger (pattern, + FC_LCD_FILTER, 0, &lcd_filter) == FcResultMatch) + { + switch (lcd_filter) { + case FC_LCD_NONE: + ft_options.base.lcd_filter = CAIRO_LCD_FILTER_NONE; + break; + case FC_LCD_DEFAULT: + ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR5; + break; + case FC_LCD_LIGHT: + ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR3; + break; + case FC_LCD_LEGACY: + ft_options.base.lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL; + break; + } + } + #ifdef FC_HINT_STYLE if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) @@ -1491,6 +1760,12 @@ _cairo_ft_options_merge (cairo_ft_options_t *options, if (other->base.hint_style == CAIRO_HINT_STYLE_NONE) options->base.hint_style = CAIRO_HINT_STYLE_NONE; + if (options->base.lcd_filter == CAIRO_LCD_FILTER_DEFAULT) + options->base.lcd_filter = other->base.lcd_filter; + + if (other->base.lcd_filter == CAIRO_LCD_FILTER_NONE) + options->base.lcd_filter = CAIRO_LCD_FILTER_NONE; + if (options->base.antialias == CAIRO_ANTIALIAS_NONE) { if (options->base.hint_style == CAIRO_HINT_STYLE_NONE) load_flags |= FT_LOAD_NO_HINTING; @@ -1514,11 +1789,11 @@ _cairo_ft_options_merge (cairo_ft_options_t *options, case CAIRO_SUBPIXEL_ORDER_DEFAULT: case CAIRO_SUBPIXEL_ORDER_RGB: case CAIRO_SUBPIXEL_ORDER_BGR: - load_target |= FT_LOAD_TARGET_LCD; + load_target = FT_LOAD_TARGET_LCD; break; case CAIRO_SUBPIXEL_ORDER_VRGB: case CAIRO_SUBPIXEL_ORDER_VBGR: - load_target |= FT_LOAD_TARGET_LCD_V; + load_target = FT_LOAD_TARGET_LCD_V; break; } } @@ -2517,6 +2792,34 @@ _cairo_ft_font_options_substitute (const cairo_font_options_t *options, } } + if (options->lcd_filter != CAIRO_LCD_FILTER_DEFAULT) + { + if (FcPatternGet (pattern, FC_LCD_FILTER, 0, &v) == FcResultNoMatch) + { + int lcd_filter; + + switch (options->lcd_filter) { + case CAIRO_LCD_FILTER_NONE: + lcd_filter = FT_LCD_FILTER_NONE; + break; + case CAIRO_LCD_FILTER_DEFAULT: + case CAIRO_LCD_FILTER_INTRA_PIXEL: + lcd_filter = FT_LCD_FILTER_LEGACY; + break; + case CAIRO_LCD_FILTER_FIR3: + lcd_filter = FT_LCD_FILTER_LIGHT; + break; + default: + case CAIRO_LCD_FILTER_FIR5: + lcd_filter = FT_LCD_FILTER_DEFAULT; + break; + } + + if (! FcPatternAddInteger (pattern, FC_LCD_FILTER, lcd_filter)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + if (options->hint_style != CAIRO_HINT_STYLE_DEFAULT) { if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch) @@ -2638,13 +2941,11 @@ _cairo_ft_resolve_pattern (FcPattern *pattern, } status = _cairo_ft_unscaled_font_create_for_pattern (resolved, &unscaled); - if (unlikely (status)) { + if (unlikely (status || unscaled == NULL)) { font_face = (cairo_font_face_t *)&_cairo_font_face_nil; goto FREE_RESOLVED; } - assert (unscaled != NULL); - _get_pattern_ft_options (resolved, &ft_options); font_face = _cairo_ft_font_face_create (unscaled, &ft_options); _cairo_unscaled_font_destroy (&unscaled->base); diff --git a/gfx/cairo/cairo/src/cairo-ft-private.h b/gfx/cairo/cairo/src/cairo-ft-private.h index 00f7f77cb50e..ff6ad4e655fa 100644 --- a/gfx/cairo/cairo/src/cairo-ft-private.h +++ b/gfx/cairo/cairo/src/cairo-ft-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-ft.h b/gfx/cairo/cairo/src/cairo-ft.h index b7178d35f5a2..56d48c3280a5 100644 --- a/gfx/cairo/cairo/src/cairo-ft.h +++ b/gfx/cairo/cairo/src/cairo-ft.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-gl-glyphs.c b/gfx/cairo/cairo/src/cairo-gl-glyphs.c index dbc71003355b..4736e190e0de 100644 --- a/gfx/cairo/cairo/src/cairo-gl-glyphs.c +++ b/gfx/cairo/cairo/src/cairo-gl-glyphs.c @@ -1,6 +1,8 @@ /* Cairo - a vector graphics library with display and print output * * Copyright © 2009 Chris Wilson + * Copyright © 2010 Intel Corporation + * Copyright © 2010 Red Hat, Inc * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -12,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -28,11 +30,17 @@ * The Original Code is the cairo graphics library. * * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributors: + * Benjamin Otte + * Chris Wilson */ #include "cairoint.h" #include "cairo-gl-private.h" + +#include "cairo-error-private.h" #include "cairo-rtree-private.h" #define GLYPH_CACHE_WIDTH 1024 @@ -47,40 +55,16 @@ typedef struct _cairo_gl_glyph_private { } cairo_gl_glyph_private_t; static cairo_status_t -_cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache, +_cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx, + cairo_gl_glyph_cache_t *cache, cairo_scaled_glyph_t *scaled_glyph) { cairo_image_surface_t *glyph_surface = scaled_glyph->surface; + cairo_gl_surface_t *cache_surface; cairo_gl_glyph_private_t *glyph_private; cairo_rtree_node_t *node = NULL; - cairo_image_surface_t *clone = NULL; cairo_status_t status; int width, height; - GLenum internal_format, format, type; - cairo_bool_t has_alpha; - - if (! _cairo_gl_get_image_format_and_type (glyph_surface->pixman_format, - &internal_format, - &format, - &type, - &has_alpha)) - { - cairo_bool_t is_supported; - - clone = _cairo_image_surface_coerce (glyph_surface, - _cairo_format_from_content (glyph_surface->base.content)); - if (unlikely (clone->base.status)) - return clone->base.status; - - is_supported = - _cairo_gl_get_image_format_and_type (clone->pixman_format, - &internal_format, - &format, - &type, - &has_alpha); - assert (is_supported); - glyph_surface = clone; - } width = glyph_surface->width; if (width < GLYPH_CACHE_MIN_SIZE) @@ -103,16 +87,17 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache, if (status) return status; - glPixelStorei (GL_UNPACK_ALIGNMENT, 1); - glPixelStorei (GL_UNPACK_ROW_LENGTH, - glyph_surface->stride / - (PIXMAN_FORMAT_BPP (glyph_surface->pixman_format) / 8)); - glTexSubImage2D (GL_TEXTURE_2D, 0, - node->x, node->y, - glyph_surface->width, glyph_surface->height, - format, type, - glyph_surface->data); - glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); + cache_surface = (cairo_gl_surface_t *) cache->pattern.surface; + + /* XXX: Make sure we use the mask texture. This should work automagically somehow */ + glActiveTexture (GL_TEXTURE1); + status = _cairo_gl_surface_draw_image (cache_surface, + glyph_surface, + 0, 0, + glyph_surface->width, glyph_surface->height, + node->x, node->y); + if (unlikely (status)) + return status; scaled_glyph->surface_private = node; node->owner = &scaled_glyph->surface_private; @@ -121,14 +106,16 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache, glyph_private->cache = cache; /* compute tex coords */ - glyph_private->p1.x = node->x / (double) cache->width; - glyph_private->p1.y = node->y / (double) cache->height; - glyph_private->p2.x = - (node->x + glyph_surface->width) / (double) cache->width; - glyph_private->p2.y = - (node->y + glyph_surface->height) / (double) cache->height; - - cairo_surface_destroy (&clone->base); + glyph_private->p1.x = node->x; + glyph_private->p1.y = node->y; + glyph_private->p2.x = node->x + glyph_surface->width; + glyph_private->p2.y = node->y + glyph_surface->height; + if (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base)) { + glyph_private->p1.x /= cache_surface->width; + glyph_private->p1.y /= cache_surface->height; + glyph_private->p2.x /= cache_surface->width; + glyph_private->p2.y /= cache_surface->height; + } return CAIRO_STATUS_SUCCESS; } @@ -140,53 +127,50 @@ _cairo_gl_glyph_cache_lock (cairo_gl_glyph_cache_t *cache, return _cairo_rtree_pin (&cache->rtree, scaled_glyph->surface_private); } -static cairo_gl_glyph_cache_t * +static cairo_status_t cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx, - cairo_format_t format) + cairo_format_t format, + cairo_gl_glyph_cache_t **cache_out) { cairo_gl_glyph_cache_t *cache; + cairo_content_t content; switch (format) { + case CAIRO_FORMAT_RGB16_565: case CAIRO_FORMAT_ARGB32: case CAIRO_FORMAT_RGB24: cache = &ctx->glyph_cache[0]; - format = CAIRO_FORMAT_ARGB32; + content = CAIRO_CONTENT_COLOR_ALPHA; break; case CAIRO_FORMAT_A8: case CAIRO_FORMAT_A1: cache = &ctx->glyph_cache[1]; - format = CAIRO_FORMAT_A8; + content = CAIRO_CONTENT_ALPHA; break; + case CAIRO_FORMAT_INVALID: + ASSERT_NOT_REACHED; + return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); } - if (unlikely (cache->tex == 0)) { - GLenum internal_format; - - cache->width = GLYPH_CACHE_WIDTH; - cache->height = GLYPH_CACHE_HEIGHT; - - switch (format) { - case CAIRO_FORMAT_A1: - case CAIRO_FORMAT_RGB24: - ASSERT_NOT_REACHED; - case CAIRO_FORMAT_ARGB32: - internal_format = GL_RGBA; - break; - case CAIRO_FORMAT_A8: - internal_format = GL_ALPHA; - break; - } - - glGenTextures (1, &cache->tex); - glBindTexture (GL_TEXTURE_2D, cache->tex); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D (GL_TEXTURE_2D, 0, internal_format, - GLYPH_CACHE_WIDTH, GLYPH_CACHE_HEIGHT, 0, - internal_format, GL_FLOAT, NULL); + if (unlikely (cache->pattern.surface == NULL)) { + cairo_surface_t *surface; + surface = cairo_gl_surface_create (&ctx->base, + content, + GLYPH_CACHE_WIDTH, + GLYPH_CACHE_HEIGHT); + if (unlikely (surface->status)) { + cairo_status_t status = surface->status; + cairo_surface_destroy (surface); + return status; + } + _cairo_surface_release_device_reference (surface); + _cairo_pattern_init_for_surface (&cache->pattern, surface); + cairo_surface_destroy (surface); + cache->pattern.base.has_component_alpha = (content == CAIRO_CONTENT_COLOR_ALPHA); } - return cache; + *cache_out = cache; + return CAIRO_STATUS_SUCCESS; } static void @@ -199,12 +183,12 @@ static cairo_bool_t _cairo_gl_surface_owns_font (cairo_gl_surface_t *surface, cairo_scaled_font_t *scaled_font) { - cairo_gl_context_t *font_private; + cairo_device_t *font_private; font_private = scaled_font->surface_private; if ((scaled_font->surface_backend != NULL && scaled_font->surface_backend != &_cairo_gl_surface_backend) || - (font_private != NULL && font_private != surface->ctx)) + (font_private != NULL && font_private != surface->base.device)) { return FALSE; } @@ -212,6 +196,12 @@ _cairo_gl_surface_owns_font (cairo_gl_surface_t *surface, return TRUE; } +void +_cairo_gl_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font) +{ + cairo_list_del (&scaled_font->link); +} + void _cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_font_t *scaled_font) @@ -229,109 +219,6 @@ _cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, } } -typedef struct _cairo_gl_glyphs_setup -{ - unsigned int vbo_size; /* units of floats */ - unsigned int vb_offset; /* units of floats */ - unsigned int vertex_size; /* units of floats */ - unsigned int num_prims; - float *vb; - cairo_gl_composite_setup_t *composite; - cairo_region_t *clip; - cairo_gl_surface_t *dst; -} cairo_gl_glyphs_setup_t; - -static void -_cairo_gl_flush_glyphs (cairo_gl_context_t *ctx, - cairo_gl_glyphs_setup_t *setup) -{ - int i; - - if (setup->vb != NULL) { - glUnmapBufferARB (GL_ARRAY_BUFFER_ARB); - setup->vb = NULL; - - if (setup->num_prims != 0) { - if (setup->clip) { - int num_rectangles = cairo_region_num_rectangles (setup->clip); - - glEnable (GL_SCISSOR_TEST); - for (i = 0; i < num_rectangles; i++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (setup->clip, i, &rect); - - glScissor (rect.x, - _cairo_gl_y_flip (setup->dst, rect.y), - rect.x + rect.width, - _cairo_gl_y_flip (setup->dst, - rect.y + rect.height)); - glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims); - } - glDisable (GL_SCISSOR_TEST); - } else { - glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims); - } - setup->num_prims = 0; - } - } -} - -static void -_cairo_gl_glyphs_emit_vertex (cairo_gl_glyphs_setup_t *setup, - int x, int y, float glyph_x, float glyph_y) -{ - int i = 0; - float *vb = &setup->vb[setup->vb_offset]; - cairo_surface_attributes_t *src_attributes; - - src_attributes = &setup->composite->src.operand.texture.attributes; - - vb[i++] = x; - vb[i++] = y; - - vb[i++] = glyph_x; - vb[i++] = glyph_y; - - if (setup->composite->src.type == OPERAND_TEXTURE) { - double s = x; - double t = y; - cairo_matrix_transform_point (&src_attributes->matrix, &s, &t); - vb[i++] = s; - vb[i++] = t; - } - - setup->vb_offset += setup->vertex_size; -} - - -static void -_cairo_gl_emit_glyph_rectangle (cairo_gl_context_t *ctx, - cairo_gl_glyphs_setup_t *setup, - int x1, int y1, - int x2, int y2, - cairo_gl_glyph_private_t *glyph) -{ - if (setup->vb != NULL && - setup->vb_offset + 4 * setup->vertex_size > setup->vbo_size) { - _cairo_gl_flush_glyphs (ctx, setup); - } - - if (setup->vb == NULL) { - glBufferDataARB (GL_ARRAY_BUFFER_ARB, - setup->vbo_size * sizeof (GLfloat), - NULL, GL_STREAM_DRAW_ARB); - setup->vb = glMapBufferARB (GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - setup->vb_offset = 0; - } - - _cairo_gl_glyphs_emit_vertex (setup, x1, y1, glyph->p1.x, glyph->p1.y); - _cairo_gl_glyphs_emit_vertex (setup, x2, y1, glyph->p2.x, glyph->p1.y); - _cairo_gl_glyphs_emit_vertex (setup, x2, y2, glyph->p2.x, glyph->p2.y); - _cairo_gl_glyphs_emit_vertex (setup, x1, y2, glyph->p1.x, glyph->p2.y); - setup->num_prims++; -} - static cairo_status_t _render_glyphs (cairo_gl_surface_t *dst, int dst_x, int dst_y, @@ -345,106 +232,51 @@ _render_glyphs (cairo_gl_surface_t *dst, cairo_region_t *clip_region, int *remaining_glyphs) { - cairo_format_t last_format = (cairo_format_t) -1; + cairo_format_t last_format = CAIRO_FORMAT_INVALID; cairo_gl_glyph_cache_t *cache = NULL; cairo_gl_context_t *ctx; - cairo_gl_glyphs_setup_t setup; - cairo_gl_composite_setup_t composite_setup; + cairo_gl_composite_t setup; cairo_status_t status; int i = 0; - GLuint vbo = 0; *has_component_alpha = FALSE; - status = _cairo_gl_operand_init (&composite_setup.src, source, dst, - glyph_extents->x, glyph_extents->y, - dst_x, dst_y, - glyph_extents->width, - glyph_extents->height); + status = _cairo_gl_context_acquire (dst->base.device, &ctx); if (unlikely (status)) return status; - ctx = _cairo_gl_context_acquire (dst->ctx); - - /* Set up the IN operator for source IN mask. - * - * IN (normal, any op): dst.argb = src.argb * mask.aaaa - * IN (component, ADD): dst.argb = src.argb * mask.argb - * - * The mask channel selection for component alpha ADD will be updated in - * the loop over glyphs below. - */ - glActiveTexture (GL_TEXTURE1); - glEnable (GL_TEXTURE_2D); - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); - - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); - - _cairo_gl_set_destination (dst); - /* If we're doing some CA glyphs, we're only doing it for ADD, - * which doesn't require the source alpha value in blending. - */ - _cairo_gl_set_operator (dst, op, FALSE); - _cairo_gl_set_src_operand (ctx, &composite_setup); - _cairo_scaled_font_freeze_cache (scaled_font); + + status = _cairo_gl_composite_init (&setup, op, dst, + TRUE, glyph_extents); + + if (unlikely (status)) + goto FINISH; + if (! _cairo_gl_surface_owns_font (dst, scaled_font)) { status = CAIRO_INT_STATUS_UNSUPPORTED; - goto CLEANUP_FONT; + goto FINISH; } + status = _cairo_gl_composite_set_source (&setup, source, + glyph_extents->x, glyph_extents->y, + dst_x, dst_y, + glyph_extents->width, + glyph_extents->height); + if (unlikely (status)) + goto FINISH; + if (scaled_font->surface_private == NULL) { - /* XXX couple into list to remove on context destruction */ scaled_font->surface_private = ctx; scaled_font->surface_backend = &_cairo_gl_surface_backend; + cairo_list_add (&scaled_font->link, &ctx->fonts); } - /* Create our VBO so that we can accumulate a bunch of glyph primitives - * into one giant DrawArrays. - */ - memset(&setup, 0, sizeof(setup)); - setup.composite = &composite_setup; - setup.clip = clip_region; - setup.dst = dst; - setup.vertex_size = 4; - if (composite_setup.src.type == OPERAND_TEXTURE) - setup.vertex_size += 2; - setup.vbo_size = num_glyphs * 4 * setup.vertex_size; - if (setup.vbo_size > 4096) - setup.vbo_size = 4096; - - glGenBuffersARB (1, &vbo); - glBindBufferARB (GL_ARRAY_BUFFER_ARB, vbo); - - glVertexPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat), - (void *)(uintptr_t)(0)); - glEnableClientState (GL_VERTEX_ARRAY); - if (composite_setup.src.type == OPERAND_TEXTURE) { - /* Note that we're packing texcoord 0 after texcoord 1, for - * convenience. - */ - glClientActiveTexture (GL_TEXTURE0); - glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat), - (void *)(uintptr_t)(4 * sizeof (GLfloat))); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); - } - glClientActiveTexture (GL_TEXTURE1); - glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat), - (void *)(uintptr_t)(2 * sizeof (GLfloat))); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); + _cairo_gl_composite_set_clip_region (&setup, clip_region); for (i = 0; i < num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; + cairo_gl_glyph_private_t *glyph; double x_offset, y_offset; double x1, x2, y1, y2; @@ -468,39 +300,40 @@ _render_glyphs (cairo_gl_surface_t *dst, } if (scaled_glyph->surface->format != last_format) { - /* Switching textures, so flush any queued prims. */ - _cairo_gl_flush_glyphs (ctx, &setup); - - glActiveTexture (GL_TEXTURE1); - cache = cairo_gl_context_get_glyph_cache (ctx, - scaled_glyph->surface->format); - - glBindTexture (GL_TEXTURE_2D, cache->tex); + status = cairo_gl_context_get_glyph_cache (ctx, + scaled_glyph->surface->format, + &cache); + if (unlikely (status)) + goto FINISH; last_format = scaled_glyph->surface->format; - /* If we're doing component alpha in this function, it should - * only be in the case of CAIRO_OPERATOR_ADD. In that case, we just - * need to make sure we send the rgb bits down to the destination. - */ - if (last_format == CAIRO_FORMAT_ARGB32) { - assert (op == CAIRO_OPERATOR_ADD); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - *has_component_alpha = TRUE; - } else { - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA); - } - /* XXX component alpha */ + status = _cairo_gl_composite_set_mask (&setup, + &cache->pattern.base, + 0, 0, 0, 0, 0, 0); + if (unlikely (status)) + goto FINISH; + + *has_component_alpha |= cache->pattern.base.has_component_alpha; + + /* XXX: _cairo_gl_composite_begin() acquires the context a + * second time. Need to refactor this loop so this doesn't happen. + */ + status = _cairo_gl_composite_begin (&setup, &ctx); + + status = _cairo_gl_context_release (ctx, status); + if (unlikely (status)) + goto FINISH; } if (scaled_glyph->surface_private == NULL) { - status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph); + status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph); if (status == CAIRO_INT_STATUS_UNSUPPORTED) { /* Cache is full, so flush existing prims and try again. */ - _cairo_gl_flush_glyphs (ctx, &setup); + _cairo_gl_composite_flush (ctx); _cairo_gl_glyph_cache_unlock (cache); - status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph); + status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph); } if (unlikely (_cairo_status_is_error (status))) @@ -515,40 +348,20 @@ _render_glyphs (cairo_gl_surface_t *dst, x2 = x1 + scaled_glyph->surface->width; y2 = y1 + scaled_glyph->surface->height; - _cairo_gl_emit_glyph_rectangle (ctx, &setup, + glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph); + _cairo_gl_composite_emit_glyph (ctx, x1, y1, x2, y2, - _cairo_gl_glyph_cache_lock (cache, scaled_glyph)); + glyph->p1.x, glyph->p1.y, + glyph->p2.x, glyph->p2.y); } status = CAIRO_STATUS_SUCCESS; FINISH: - _cairo_gl_flush_glyphs (ctx, &setup); - CLEANUP_FONT: _cairo_scaled_font_thaw_cache (scaled_font); - glDisable (GL_BLEND); - glDisable (GL_SCISSOR_TEST); + status = _cairo_gl_context_release (ctx, status); - glDisableClientState (GL_VERTEX_ARRAY); - - glClientActiveTexture (GL_TEXTURE0); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - glActiveTexture (GL_TEXTURE0); - glDisable (GL_TEXTURE_2D); - - glClientActiveTexture (GL_TEXTURE1); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - glActiveTexture (GL_TEXTURE1); - glDisable (GL_TEXTURE_2D); - - if (vbo != 0) { - glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0); - glDeleteBuffersARB (1, &vbo); - } - - _cairo_gl_context_release (ctx); - - _cairo_gl_operand_destroy (&composite_setup.src); + _cairo_gl_composite_fini (&setup); *remaining_glyphs = num_glyphs - i; return status; @@ -567,26 +380,25 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst, { cairo_surface_t *mask; cairo_status_t status; - cairo_solid_pattern_t solid; cairo_bool_t has_component_alpha; int i; /* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */ - mask = cairo_gl_surface_create (dst->ctx, - CAIRO_CONTENT_COLOR_ALPHA, - glyph_extents->width, - glyph_extents->height); + mask = cairo_gl_surface_create (dst->base.device, + CAIRO_CONTENT_COLOR_ALPHA, + glyph_extents->width, + glyph_extents->height); if (unlikely (mask->status)) - return mask->status; + return mask->status; for (i = 0; i < num_glyphs; i++) { glyphs[i].x -= glyph_extents->x; glyphs[i].y -= glyph_extents->y; } - _cairo_pattern_init_solid (&solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR_ALPHA); status = _render_glyphs ((cairo_gl_surface_t *) mask, 0, 0, - CAIRO_OPERATOR_ADD, &solid.base, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, glyphs, num_glyphs, glyph_extents, scaled_font, &has_component_alpha, NULL, remaining_glyphs); @@ -610,6 +422,7 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst, } cairo_surface_destroy (mask); + return status; } @@ -627,15 +440,11 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst, cairo_rectangle_int_t surface_extents; cairo_rectangle_int_t extents; cairo_region_t *clip_region = NULL; - cairo_solid_pattern_t solid_pattern; cairo_bool_t overlap, use_mask = FALSE; cairo_bool_t has_component_alpha; cairo_status_t status; int i; - if (! GLEW_ARB_vertex_buffer_object) - return UNSUPPORTED ("requires ARB_vertex_buffer_object"); - if (! _cairo_gl_operator_is_supported (op)) return UNSUPPORTED ("unsupported operator"); @@ -646,18 +455,20 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst, * since only _cairo_gl_surface_composite() currently supports component * alpha. */ - for (i = 0; i < num_glyphs; i++) { - cairo_scaled_glyph_t *scaled_glyph; + if (!use_mask && op != CAIRO_OPERATOR_OVER) { + for (i = 0; i < num_glyphs; i++) { + cairo_scaled_glyph_t *scaled_glyph; - status = _cairo_scaled_glyph_lookup (scaled_font, - glyphs[i].index, - CAIRO_SCALED_GLYPH_INFO_SURFACE, - &scaled_glyph); - if (!_cairo_status_is_error (status) && - scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32) - { - use_mask = TRUE; - break; + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[i].index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + &scaled_glyph); + if (!_cairo_status_is_error (status) && + scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32) + { + use_mask = TRUE; + break; + } } } @@ -682,9 +493,7 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst, * mask IN clip ? 0 : dest */ if (op == CAIRO_OPERATOR_CLEAR) { - _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - source = &solid_pattern.base; + source = &_cairo_pattern_white.base; op = CAIRO_OPERATOR_DEST_OUT; } @@ -772,26 +581,25 @@ EMPTY: return CAIRO_STATUS_SUCCESS; } -void -_cairo_gl_glyph_cache_fini (cairo_gl_glyph_cache_t *cache) -{ - if (cache->tex == 0) - return; - - glDeleteTextures (1, &cache->tex); - - _cairo_rtree_fini (&cache->rtree); -} - void _cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache) { - cache->tex = 0; - _cairo_rtree_init (&cache->rtree, GLYPH_CACHE_WIDTH, GLYPH_CACHE_HEIGHT, GLYPH_CACHE_MIN_SIZE, - sizeof (cairo_gl_glyph_private_t), - NULL); + sizeof (cairo_gl_glyph_private_t)); } + +void +_cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx, + cairo_gl_glyph_cache_t *cache) +{ + _cairo_rtree_fini (&cache->rtree); + + if (cache->pattern.surface) { + _cairo_pattern_fini (&cache->pattern.base); + cache->pattern.surface = NULL; + } +} + diff --git a/gfx/cairo/cairo/src/cairo-gl-private.h b/gfx/cairo/cairo/src/cairo-gl-private.h index 490bc5c49039..54f226f425a6 100644 --- a/gfx/cairo/cairo/src/cairo-gl-private.h +++ b/gfx/cairo/cairo/src/cairo-gl-private.h @@ -2,7 +2,7 @@ * * Copyright © 2009 Eric Anholt * Copyright © 2009 Chris Wilson - * Copyright © 2005 Red Hat, Inc + * Copyright © 2005,2010 Red Hat, Inc * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -32,16 +32,26 @@ * The Initial Developer of the Original Code is Red Hat, Inc. * * Contributor(s): + * Benjamin Otte * Carl Worth * Chris Wilson + * Eric Anholt + * T. Zachary Laine */ #ifndef CAIRO_GL_PRIVATE_H #define CAIRO_GL_PRIVATE_H #include "cairoint.h" + +#include "cairo-gl-gradient-private.h" + +#include "cairo-device-private.h" +#include "cairo-error-private.h" #include "cairo-rtree-private.h" +#include + #include #include "cairo-gl.h" @@ -63,51 +73,75 @@ #define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED #endif +/* maximal number of shaders we keep in the cache. + * Random number that is hopefully big enough to not cause many cache evictions. */ +#define CAIRO_GL_MAX_SHADERS_PER_CONTEXT 64 + +/* VBO size that we allocate, smaller size means we gotta flush more often */ +#define CAIRO_GL_VBO_SIZE 16384 + typedef struct _cairo_gl_surface { cairo_surface_t base; - cairo_gl_context_t *ctx; int width, height; GLuint tex; /* GL texture object containing our data. */ GLuint fb; /* GL framebuffer object wrapping our data. */ + GLuint depth; /* GL framebuffer object holding depth */ + int owns_tex; } cairo_gl_surface_t; typedef struct cairo_gl_glyph_cache { cairo_rtree_t rtree; - GLuint tex; - unsigned int width, height; + cairo_surface_pattern_t pattern; } cairo_gl_glyph_cache_t; -struct _cairo_gl_context { - cairo_reference_count_t ref_count; - cairo_status_t status; +typedef enum cairo_gl_tex { + CAIRO_GL_TEX_SOURCE = 0, + CAIRO_GL_TEX_MASK = 1, + CAIRO_GL_TEX_TEMP = 2 +} cairo_gl_tex_t; - cairo_mutex_t mutex; /* needed? */ - GLuint dummy_tex; - GLint fill_rectangles_shader; - GLint fill_rectangles_color_uniform; - GLint max_framebuffer_size; - GLint max_texture_size; +typedef enum cairo_gl_operand_type { + CAIRO_GL_OPERAND_NONE, + CAIRO_GL_OPERAND_CONSTANT, + CAIRO_GL_OPERAND_TEXTURE, + CAIRO_GL_OPERAND_LINEAR_GRADIENT, + CAIRO_GL_OPERAND_RADIAL_GRADIENT, + CAIRO_GL_OPERAND_SPANS, - cairo_gl_surface_t *current_target; - cairo_gl_glyph_cache_t glyph_cache[2]; + CAIRO_GL_OPERAND_COUNT +} cairo_gl_operand_type_t; - void (*make_current)(void *ctx, cairo_gl_surface_t *surface); - void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface); - void (*destroy) (void *ctx); -}; +typedef struct cairo_gl_shader_impl cairo_gl_shader_impl_t; -enum cairo_gl_composite_operand_type { - OPERAND_CONSTANT, - OPERAND_TEXTURE, -}; +typedef struct cairo_gl_shader { + GLuint fragment_shader; + GLuint program; +} cairo_gl_shader_t; + +typedef enum cairo_gl_shader_in { + CAIRO_GL_SHADER_IN_NORMAL, + CAIRO_GL_SHADER_IN_CA_SOURCE, + CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA, + + CAIRO_GL_SHADER_IN_COUNT +} cairo_gl_shader_in_t; + +typedef enum cairo_gl_var_type { + CAIRO_GL_VAR_NONE, + CAIRO_GL_VAR_TEXCOORDS, + CAIRO_GL_VAR_COVERAGE +} cairo_gl_var_type_t; + +#define cairo_gl_var_type_hash(src,mask,dest) ((mask) << 2 | (src << 1) | (dest)) +#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_COVERAGE << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS) /* This union structure describes a potential source or mask operand to the * compositing equation. */ -typedef struct cairo_gl_composite_operand { - enum cairo_gl_composite_operand_type type; +typedef struct cairo_gl_operand { + cairo_gl_operand_type_t type; union { struct { GLuint tex; @@ -117,30 +151,111 @@ typedef struct cairo_gl_composite_operand { struct { GLfloat color[4]; } constant; - } operand; + struct { + cairo_gl_gradient_t *gradient; + cairo_matrix_t m; + float segment_x; + float segment_y; + cairo_extend_t extend; + } linear; + struct { + cairo_gl_gradient_t *gradient; + cairo_matrix_t m; + float circle_1_x; + float circle_1_y; + float radius_0; + float radius_1; + cairo_extend_t extend; + } radial; + }; + unsigned int vertex_offset; +} cairo_gl_operand_t; - const cairo_pattern_t *pattern; -} cairo_gl_composite_operand_t; +struct _cairo_gl_context { + cairo_device_t base; -typedef struct _cairo_gl_composite_setup { - cairo_gl_composite_operand_t src; - cairo_gl_composite_operand_t mask; -} cairo_gl_composite_setup_t; + GLuint dummy_tex; + GLuint texture_load_pbo; + GLuint vbo; + GLint max_framebuffer_size; + GLint max_texture_size; + GLint max_textures; + GLenum tex_target; + + const cairo_gl_shader_impl_t *shader_impl; + + GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX + 1]; + cairo_gl_shader_t fill_rectangles_shader; + cairo_cache_t shaders; + + cairo_cache_t gradients; + + cairo_gl_glyph_cache_t glyph_cache[2]; + cairo_list_t fonts; + + cairo_gl_surface_t *current_target; + cairo_operator_t current_operator; + cairo_gl_shader_t *pre_shader; /* for component alpha */ + cairo_gl_shader_t *current_shader; + + cairo_gl_operand_t operands[2]; + + char *vb; + unsigned int vb_offset; + unsigned int vertex_size; + cairo_region_t *clip_region; + + void (*acquire) (void *ctx); + void (*release) (void *ctx); + + void (*make_current) (void *ctx, cairo_gl_surface_t *surface); + void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface); + void (*destroy) (void *ctx); +}; + +typedef struct _cairo_gl_composite { + cairo_gl_surface_t *dst; + cairo_operator_t op; + cairo_region_t *clip_region; + + cairo_gl_operand_t src; + cairo_gl_operand_t mask; +} cairo_gl_composite_t; cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend; -cairo_private cairo_gl_context_t * -_cairo_gl_context_create_in_error (cairo_status_t status); +static cairo_always_inline GLenum +_cairo_gl_get_error (void) +{ + GLenum err = glGetError(); + + if (unlikely (err)) + while (glGetError ()); + + return err; +} + +static inline cairo_device_t * +_cairo_gl_context_create_in_error (cairo_status_t status) +{ + return (cairo_device_t *) _cairo_device_create_in_error (status); +} cairo_private cairo_status_t _cairo_gl_context_init (cairo_gl_context_t *ctx); cairo_private void -_cairo_gl_surface_init (cairo_gl_context_t *ctx, +_cairo_gl_surface_init (cairo_device_t *device, cairo_gl_surface_t *surface, cairo_content_t content, int width, int height); +static cairo_always_inline cairo_bool_t cairo_warn +_cairo_gl_surface_is_texture (cairo_gl_surface_t *surface) +{ + return surface->tex != 0; +} + cairo_private cairo_status_t _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, cairo_image_surface_t *src, @@ -148,42 +263,133 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, int width, int height, int dst_x, int dst_y); -cairo_private cairo_int_status_t -_cairo_gl_operand_init (cairo_gl_composite_operand_t *operand, - const cairo_pattern_t *pattern, - cairo_gl_surface_t *dst, - int src_x, int src_y, - int dst_x, int dst_y, - int width, int height); +static cairo_always_inline cairo_bool_t +_cairo_gl_device_has_glsl (cairo_device_t *device) +{ + return ((cairo_gl_context_t *) device)->shader_impl != NULL; +} -cairo_private cairo_gl_context_t * -_cairo_gl_context_acquire (cairo_gl_context_t *ctx); +static cairo_always_inline cairo_bool_t +_cairo_gl_device_requires_power_of_two_textures (cairo_device_t *device) +{ + return ((cairo_gl_context_t *) device)->tex_target == GL_TEXTURE_RECTANGLE_EXT; +} + +static cairo_always_inline cairo_status_t cairo_warn +_cairo_gl_context_acquire (cairo_device_t *device, + cairo_gl_context_t **ctx) +{ + cairo_status_t status; + + status = cairo_device_acquire (device); + if (unlikely (status)) + return status; + + /* clear potential previous GL errors */ + _cairo_gl_get_error (); + + *ctx = (cairo_gl_context_t *) device; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_always_inline cairo_warn cairo_status_t +_cairo_gl_context_release (cairo_gl_context_t *ctx, cairo_status_t status) +{ + GLenum err; + + err = _cairo_gl_get_error (); + + if (unlikely (err)) { + cairo_status_t new_status; + new_status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR); + if (status == CAIRO_STATUS_SUCCESS) + status = new_status; + } + + cairo_device_release (&(ctx)->base); + + return status; +} cairo_private void -_cairo_gl_context_release (cairo_gl_context_t *ctx); +_cairo_gl_context_set_destination (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface); cairo_private void -_cairo_gl_set_destination (cairo_gl_surface_t *surface); +_cairo_gl_context_activate (cairo_gl_context_t *ctx, + cairo_gl_tex_t tex_unit); cairo_private cairo_bool_t _cairo_gl_operator_is_supported (cairo_operator_t op); -cairo_private void -_cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op, - cairo_bool_t component_alpha); +cairo_private cairo_status_t +_cairo_gl_composite_init (cairo_gl_composite_t *setup, + cairo_operator_t op, + cairo_gl_surface_t *dst, + cairo_bool_t has_component_alpha, + const cairo_rectangle_int_t *rect); cairo_private void -_cairo_gl_set_src_operand (cairo_gl_context_t *ctx, - cairo_gl_composite_setup_t *setup); +_cairo_gl_composite_fini (cairo_gl_composite_t *setup); cairo_private void -_cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand); +_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup, + cairo_region_t *clip_region); + +cairo_private cairo_int_status_t +_cairo_gl_composite_set_source (cairo_gl_composite_t *setup, + const cairo_pattern_t *pattern, + int src_x, int src_y, + int dst_x, int dst_y, + int width, int height); + +cairo_private cairo_int_status_t +_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup, + const cairo_pattern_t *pattern, + int src_x, int src_y, + int dst_x, int dst_y, + int width, int height); + +cairo_private void +_cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup); + +cairo_private cairo_status_t +_cairo_gl_composite_begin (cairo_gl_composite_t *setup, + cairo_gl_context_t **ctx); + +cairo_private void +_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx, + GLfloat x1, + GLfloat y1, + GLfloat x2, + GLfloat y2, + uint8_t alpha); + +cairo_private void +_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx, + GLfloat x1, + GLfloat y1, + GLfloat x2, + GLfloat y2, + GLfloat glyph_x1, + GLfloat glyph_y1, + GLfloat glyph_x2, + GLfloat glyph_y2); + +cairo_private void +_cairo_gl_composite_flush (cairo_gl_context_t *ctx); + +cairo_private void +_cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx, + cairo_gl_tex_t tex_unit); cairo_private cairo_bool_t _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format, GLenum *internal_format, GLenum *format, GLenum *type, cairo_bool_t *has_alpha); +cairo_private void +_cairo_gl_surface_scaled_font_fini ( cairo_scaled_font_t *scaled_font); + cairo_private void _cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_font_t *scaled_font); @@ -191,6 +397,10 @@ _cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, cairo_private void _cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache); +cairo_private void +_cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx, + cairo_gl_glyph_cache_t *cache); + cairo_private cairo_int_status_t _cairo_gl_surface_show_glyphs (void *abstract_dst, cairo_operator_t op, @@ -201,13 +411,6 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst, cairo_clip_t *clip, int *remaining_glyphs); -cairo_private void -_cairo_gl_glyph_cache_fini (cairo_gl_glyph_cache_t *cache); - -cairo_private cairo_status_t -_cairo_gl_load_glsl (GLint *shader, - const char *vs_source, const char *fs_source); - static inline int _cairo_gl_y_flip (cairo_gl_surface_t *surface, int y) { @@ -217,6 +420,66 @@ _cairo_gl_y_flip (cairo_gl_surface_t *surface, int y) return (surface->height - 1) - y; } +cairo_private cairo_status_t +_cairo_gl_context_init_shaders (cairo_gl_context_t *ctx); + +cairo_private void +_cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx); + +static cairo_always_inline cairo_bool_t +_cairo_gl_context_is_flushed (cairo_gl_context_t *ctx) +{ + return ctx->vb == NULL; +} + +cairo_private cairo_status_t +_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx, + cairo_gl_operand_type_t source, + cairo_gl_operand_type_t mask, + cairo_gl_shader_in_t in, + cairo_gl_shader_t **shader); + +cairo_private void +_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx, + const char *name, + float value); + +cairo_private void +_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx, + const char *name, + float value0, float value1); + +cairo_private void +_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx, + const char *name, + float value0, + float value1, + float value2); + +cairo_private void +_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx, + const char *name, + float value0, float value1, + float value2, float value3); + +cairo_private void +_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx, + const char *name, + cairo_matrix_t* m); + +cairo_private void +_cairo_gl_shader_bind_texture (cairo_gl_context_t *ctx, + const char *name, + GLuint tex_unit); + +cairo_private void +_cairo_gl_set_shader (cairo_gl_context_t *ctx, + cairo_gl_shader_t *shader); + +cairo_private void +_cairo_gl_shader_fini (cairo_gl_context_t *ctx, cairo_gl_shader_t *shader); + slim_hidden_proto (cairo_gl_surface_create); +slim_hidden_proto (cairo_gl_surface_create_for_texture); #endif /* CAIRO_GL_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-gl-shaders.c b/gfx/cairo/cairo/src/cairo-gl-shaders.c index f06991eefe59..d7773f567781 100644 --- a/gfx/cairo/cairo/src/cairo-gl-shaders.c +++ b/gfx/cairo/cairo/src/cairo-gl-shaders.c @@ -1,6 +1,8 @@ /* cairo - a vector graphics library with display and print output * + * Copyright © 2009 T. Zachary Laine * Copyright © 2010 Eric Anholt + * Copyright © 2010 Red Hat, Inc * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -12,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -27,91 +29,967 @@ * * The Original Code is the cairo graphics library. * - * The Initial Developer of the Original Code is Eric Anholt. + * The Initial Developer of the Original Code is T. Zachary Laine. + * + * Contributor(s): + * Benjamin Otte + * Eric Anholt + * T. Zachary Laine */ #include "cairoint.h" #include "cairo-gl-private.h" +#include "cairo-error-private.h" +#include "cairo-output-stream-private.h" -static GLint -_cairo_gl_compile_glsl(GLenum type, GLint *shader_out, const char *source) +typedef struct cairo_gl_shader_impl { + void + (*compile_shader) (GLuint *shader, GLenum type, const char *text); + + void + (*link_shader) (GLuint *program, GLuint vert, GLuint frag); + + void + (*destroy_shader) (GLuint shader); + + void + (*destroy_program) (GLuint program); + + void + (*bind_float) (cairo_gl_shader_t *shader, + const char *name, + float value); + + void + (*bind_vec2) (cairo_gl_shader_t *shader, + const char *name, + float value0, + float value1); + + void + (*bind_vec3) (cairo_gl_shader_t *shader, + const char *name, + float value0, + float value1, + float value2); + + void + (*bind_vec4) (cairo_gl_shader_t *shader, + const char *name, + float value0, float value1, + float value2, float value3); + + void + (*bind_matrix) (cairo_gl_shader_t *shader, + const char *name, + cairo_matrix_t* m); + + void + (*bind_texture) (cairo_gl_shader_t *shader, + const char *name, + cairo_gl_tex_t tex_unit); + + void + (*use) (cairo_gl_shader_t *shader); +} shader_impl_t; + +static cairo_status_t +_cairo_gl_shader_compile (cairo_gl_context_t *ctx, + cairo_gl_shader_t *shader, + cairo_gl_var_type_t src, + cairo_gl_var_type_t mask, + const char *fragment_text); + +/* ARB_shader_objects / ARB_vertex_shader / ARB_fragment_shader extensions + API. */ +static void +compile_shader_arb (GLuint *shader, GLenum type, const char *text) { - GLint ok; - GLint shader; + const char* strings[1] = { text }; + GLint gl_status; - shader = glCreateShaderObjectARB (type); - glShaderSourceARB (shader, 1, (const GLchar **)&source, NULL); - glCompileShaderARB (shader); - glGetObjectParameterivARB (shader, GL_OBJECT_COMPILE_STATUS_ARB, &ok); - if (!ok) { - GLchar *info; - GLint size; + *shader = glCreateShaderObjectARB (type); + glShaderSourceARB (*shader, 1, strings, 0); + glCompileShaderARB (*shader); + glGetObjectParameterivARB (*shader, GL_OBJECT_COMPILE_STATUS_ARB, &gl_status); + if (gl_status == GL_FALSE) { + GLint log_size; + glGetObjectParameterivARB (*shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_size); + if (0 < log_size) { + char *log = _cairo_malloc (log_size); + GLint chars; - glGetObjectParameterivARB (shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, - &size); - info = malloc (size); + log[log_size - 1] = '\0'; + glGetInfoLogARB (*shader, log_size, &chars, log); + printf ("OpenGL shader compilation failed. Shader:\n" + "%s\n" + "OpenGL compilation log:\n" + "%s\n", + text, log); - if (info) - glGetInfoLogARB (shader, size, NULL, info); - fprintf (stderr, "Failed to compile %s: %s\n", - type == GL_FRAGMENT_SHADER ? "FS" : "VS", - info); - fprintf (stderr, "Shader source:\n%s", source); - fprintf (stderr, "GLSL compile failure\n"); + free (log); + } else { + printf ("OpenGL shader compilation failed.\n"); + } - glDeleteObjectARB (shader); - - return CAIRO_INT_STATUS_UNSUPPORTED; + ASSERT_NOT_REACHED; } +} - *shader_out = shader; +static void +link_shader_arb (GLuint *program, GLuint vert, GLuint frag) +{ + GLint gl_status; - return CAIRO_STATUS_SUCCESS; + *program = glCreateProgramObjectARB (); + glAttachObjectARB (*program, vert); + glAttachObjectARB (*program, frag); + glLinkProgramARB (*program); + glGetObjectParameterivARB (*program, GL_OBJECT_LINK_STATUS_ARB, &gl_status); + if (gl_status == GL_FALSE) { + GLint log_size; + glGetObjectParameterivARB (*program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_size); + if (0 < log_size) { + char *log = _cairo_malloc (log_size); + GLint chars; + + log[log_size - 1] = '\0'; + glGetInfoLogARB (*program, log_size, &chars, log); + printf ("OpenGL shader link failed:\n%s\n", log); + + free (log); + } else { + printf ("OpenGL shader link failed.\n"); + } + + ASSERT_NOT_REACHED; + } +} + +static void +destroy_shader_arb (GLuint shader) +{ + glDeleteObjectARB (shader); +} + +static void +destroy_program_arb (GLuint shader) +{ + glDeleteObjectARB (shader); +} + +static void +bind_float_arb (cairo_gl_shader_t *shader, + const char *name, + float value) +{ + GLint location = glGetUniformLocationARB (shader->program, name); + assert (location != -1); + glUniform1fARB (location, value); +} + +static void +bind_vec2_arb (cairo_gl_shader_t *shader, + const char *name, + float value0, + float value1) +{ + GLint location = glGetUniformLocationARB (shader->program, name); + assert (location != -1); + glUniform2fARB (location, value0, value1); +} + +static void +bind_vec3_arb (cairo_gl_shader_t *shader, + const char *name, + float value0, + float value1, + float value2) +{ + GLint location = glGetUniformLocationARB (shader->program, name); + assert (location != -1); + glUniform3fARB (location, value0, value1, value2); +} + +static void +bind_vec4_arb (cairo_gl_shader_t *shader, + const char *name, + float value0, + float value1, + float value2, + float value3) +{ + GLint location = glGetUniformLocationARB (shader->program, name); + assert (location != -1); + glUniform4fARB (location, value0, value1, value2, value3); +} + +static void +bind_matrix_arb (cairo_gl_shader_t *shader, + const char *name, + cairo_matrix_t* m) +{ + GLint location = glGetUniformLocationARB (shader->program, name); + float gl_m[9] = { + m->xx, m->xy, m->x0, + m->yx, m->yy, m->y0, + 0, 0, 1 + }; + assert (location != -1); + glUniformMatrix3fvARB (location, 1, GL_TRUE, gl_m); +} + +static void +bind_texture_arb (cairo_gl_shader_t *shader, + const char *name, + cairo_gl_tex_t tex_unit) +{ + GLint location = glGetUniformLocationARB (shader->program, name); + assert (location != -1); + glUniform1iARB (location, tex_unit); +} + +static void +use_program_arb (cairo_gl_shader_t *shader) +{ + if (shader) + glUseProgramObjectARB (shader->program); + else + glUseProgramObjectARB (0); +} + +/* OpenGL Core 2.0 API. */ +static void +compile_shader_core_2_0 (GLuint *shader, GLenum type, const char *text) +{ + const char* strings[1] = { text }; + GLint gl_status; + + *shader = glCreateShader (type); + glShaderSource (*shader, 1, strings, 0); + glCompileShader (*shader); + glGetShaderiv (*shader, GL_COMPILE_STATUS, &gl_status); + if (gl_status == GL_FALSE) { + GLint log_size; + glGetShaderiv (*shader, GL_INFO_LOG_LENGTH, &log_size); + if (0 < log_size) { + char *log = _cairo_malloc (log_size); + GLint chars; + + log[log_size - 1] = '\0'; + glGetShaderInfoLog (*shader, log_size, &chars, log); + printf ("OpenGL shader compilation failed. Shader:\n" + "%s\n" + "OpenGL compilation log:\n" + "%s\n", + text, log); + + free (log); + } else { + printf ("OpenGL shader compilation failed.\n"); + } + + ASSERT_NOT_REACHED; + } +} + +static void +link_shader_core_2_0 (GLuint *program, GLuint vert, GLuint frag) +{ + GLint gl_status; + + *program = glCreateProgram (); + glAttachShader (*program, vert); + glAttachShader (*program, frag); + glLinkProgram (*program); + glGetProgramiv (*program, GL_LINK_STATUS, &gl_status); + if (gl_status == GL_FALSE) { + GLint log_size; + glGetProgramiv (*program, GL_INFO_LOG_LENGTH, &log_size); + if (0 < log_size) { + char *log = _cairo_malloc (log_size); + GLint chars; + + log[log_size - 1] = '\0'; + glGetProgramInfoLog (*program, log_size, &chars, log); + printf ("OpenGL shader link failed:\n%s\n", log); + + free (log); + } else { + printf ("OpenGL shader link failed.\n"); + } + + ASSERT_NOT_REACHED; + } +} + +static void +destroy_shader_core_2_0 (GLuint shader) +{ + glDeleteShader (shader); +} + +static void +destroy_program_core_2_0 (GLuint shader) +{ + glDeleteProgram (shader); +} + +static void +bind_float_core_2_0 (cairo_gl_shader_t *shader, + const char *name, + float value) +{ + GLint location = glGetUniformLocation (shader->program, name); + assert (location != -1); + glUniform1f (location, value); +} + +static void +bind_vec2_core_2_0 (cairo_gl_shader_t *shader, + const char *name, + float value0, + float value1) +{ + GLint location = glGetUniformLocation (shader->program, name); + assert (location != -1); + glUniform2f (location, value0, value1); +} + +static void +bind_vec3_core_2_0 (cairo_gl_shader_t *shader, + const char *name, + float value0, + float value1, + float value2) +{ + GLint location = glGetUniformLocation (shader->program, name); + assert (location != -1); + glUniform3f (location, value0, value1, value2); +} + +static void +bind_vec4_core_2_0 (cairo_gl_shader_t *shader, + const char *name, + float value0, + float value1, + float value2, + float value3) +{ + GLint location = glGetUniformLocation (shader->program, name); + assert (location != -1); + glUniform4f (location, value0, value1, value2, value3); +} + +static void +bind_matrix_core_2_0 (cairo_gl_shader_t *shader, const char *name, cairo_matrix_t* m) +{ + GLint location = glGetUniformLocation (shader->program, name); + float gl_m[16] = { + m->xx, m->xy, m->x0, + m->yx, m->yy, m->y0, + 0, 0, 1 + }; + assert (location != -1); + glUniformMatrix3fv (location, 1, GL_TRUE, gl_m); +} + +static void +bind_texture_core_2_0 (cairo_gl_shader_t *shader, const char *name, cairo_gl_tex_t tex_unit) +{ + GLint location = glGetUniformLocation (shader->program, name); + assert (location != -1); + glUniform1i (location, tex_unit); +} + +static void +use_program_core_2_0 (cairo_gl_shader_t *shader) +{ + if (shader) + glUseProgram (shader->program); + else + glUseProgram (0); +} + +static const cairo_gl_shader_impl_t shader_impl_core_2_0 = { + compile_shader_core_2_0, + link_shader_core_2_0, + destroy_shader_core_2_0, + destroy_program_core_2_0, + bind_float_core_2_0, + bind_vec2_core_2_0, + bind_vec3_core_2_0, + bind_vec4_core_2_0, + bind_matrix_core_2_0, + bind_texture_core_2_0, + use_program_core_2_0, +}; + +static const cairo_gl_shader_impl_t shader_impl_arb = { + compile_shader_arb, + link_shader_arb, + destroy_shader_arb, + destroy_program_arb, + bind_float_arb, + bind_vec2_arb, + bind_vec3_arb, + bind_vec4_arb, + bind_matrix_arb, + bind_texture_arb, + use_program_arb, +}; + +typedef struct _cairo_shader_cache_entry { + cairo_cache_entry_t base; + + cairo_gl_operand_type_t src; + cairo_gl_operand_type_t mask; + cairo_gl_operand_type_t dest; + cairo_gl_shader_in_t in; + + cairo_gl_context_t *ctx; /* XXX: needed to destroy the program */ + cairo_gl_shader_t shader; +} cairo_shader_cache_entry_t; + +static cairo_bool_t +_cairo_gl_shader_cache_equal (const void *key_a, const void *key_b) +{ + const cairo_shader_cache_entry_t *a = key_a; + const cairo_shader_cache_entry_t *b = key_b; + + return a->src == b->src && + a->mask == b->mask && + a->dest == b->dest && + a->in == b->in; +} + +static unsigned long +_cairo_gl_shader_cache_hash (const cairo_shader_cache_entry_t *entry) +{ + return (entry->src << 24) | (entry->mask << 16) | (entry->dest << 8) | (entry->in); +} + +static void +_cairo_gl_shader_cache_destroy (void *data) +{ + cairo_shader_cache_entry_t *entry = data; + + _cairo_gl_shader_fini (entry->ctx, &entry->shader); + if (entry->ctx->current_shader == &entry->shader) + entry->ctx->current_shader = NULL; + free (entry); +} + +static void +_cairo_gl_shader_init (cairo_gl_shader_t *shader) +{ + shader->fragment_shader = 0; + shader->program = 0; } cairo_status_t -_cairo_gl_load_glsl (GLint *shader_out, - const char *vs_source, const char *fs_source) +_cairo_gl_context_init_shaders (cairo_gl_context_t *ctx) { - GLint ok; - GLint shader, vs, fs; + static const char *fill_fs_source = + "uniform vec4 color;\n" + "void main()\n" + "{\n" + " gl_FragColor = color;\n" + "}\n"; cairo_status_t status; - shader = glCreateProgramObjectARB (); - - status = _cairo_gl_compile_glsl (GL_VERTEX_SHADER_ARB, &vs, vs_source); - if (_cairo_status_is_error (status)) - goto fail; - status = _cairo_gl_compile_glsl (GL_FRAGMENT_SHADER_ARB, &fs, fs_source); - if (_cairo_status_is_error (status)) - goto fail; - - glAttachObjectARB (shader, vs); - glAttachObjectARB (shader, fs); - glLinkProgram (shader); - glGetObjectParameterivARB (shader, GL_OBJECT_LINK_STATUS_ARB, &ok); - if (!ok) { - GLchar *info; - GLint size; - - glGetObjectParameterivARB (shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, - &size); - info = malloc (size); - - if (info) - glGetInfoLogARB (shader, size, NULL, info); - fprintf (stderr, "Failed to link: %s\n", info); - free (info); - status = CAIRO_INT_STATUS_UNSUPPORTED; - - return CAIRO_INT_STATUS_UNSUPPORTED; + /* XXX multiple device support? */ + if (GLEW_VERSION_2_0) { + ctx->shader_impl = &shader_impl_core_2_0; + } else if (GLEW_ARB_shader_objects && + GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_program) { + ctx->shader_impl = &shader_impl_arb; + } else { + ctx->shader_impl = NULL; } - *shader_out = shader; + memset (ctx->vertex_shaders, 0, sizeof (ctx->vertex_shaders)); + + status = _cairo_cache_init (&ctx->shaders, + _cairo_gl_shader_cache_equal, + NULL, + _cairo_gl_shader_cache_destroy, + CAIRO_GL_MAX_SHADERS_PER_CONTEXT); + if (unlikely (status)) + return status; + + if (ctx->shader_impl != NULL) { + _cairo_gl_shader_init (&ctx->fill_rectangles_shader); + status = _cairo_gl_shader_compile (ctx, + &ctx->fill_rectangles_shader, + CAIRO_GL_VAR_NONE, + CAIRO_GL_VAR_NONE, + fill_fs_source); + if (unlikely (status)) + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx) +{ + int i; + + for (i = 0; i <= CAIRO_GL_VAR_TYPE_MAX; i++) { + if (ctx->vertex_shaders[i]) + ctx->shader_impl->destroy_shader (ctx->vertex_shaders[i]); + } + + _cairo_cache_fini (&ctx->shaders); +} + +void +_cairo_gl_shader_fini (cairo_gl_context_t *ctx, + cairo_gl_shader_t *shader) +{ + if (shader->fragment_shader) + ctx->shader_impl->destroy_shader (shader->fragment_shader); + + if (shader->program) + ctx->shader_impl->destroy_program (shader->program); +} + +static const char *operand_names[] = { "source", "mask", "dest" }; + +static cairo_gl_var_type_t +cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type) +{ + switch (type) { + default: + case CAIRO_GL_OPERAND_COUNT: + ASSERT_NOT_REACHED; + case CAIRO_GL_OPERAND_NONE: + case CAIRO_GL_OPERAND_CONSTANT: + case CAIRO_GL_OPERAND_LINEAR_GRADIENT: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT: + return CAIRO_GL_VAR_NONE; + case CAIRO_GL_OPERAND_TEXTURE: + return CAIRO_GL_VAR_TEXCOORDS; + case CAIRO_GL_OPERAND_SPANS: + return CAIRO_GL_VAR_COVERAGE; + } +} + +static void +cairo_gl_shader_emit_variable (cairo_output_stream_t *stream, + cairo_gl_var_type_t type, + cairo_gl_tex_t name) +{ + switch (type) { + default: + ASSERT_NOT_REACHED; + case CAIRO_GL_VAR_NONE: + break; + case CAIRO_GL_VAR_TEXCOORDS: + _cairo_output_stream_printf (stream, + "varying vec2 %s_texcoords;\n", + operand_names[name]); + break; + case CAIRO_GL_VAR_COVERAGE: + _cairo_output_stream_printf (stream, + "varying float %s_coverage;\n", + operand_names[name]); + break; + } +} + +static void +cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream, + cairo_gl_var_type_t type, + cairo_gl_tex_t name) +{ + switch (type) { + default: + ASSERT_NOT_REACHED; + case CAIRO_GL_VAR_NONE: + break; + case CAIRO_GL_VAR_TEXCOORDS: + _cairo_output_stream_printf (stream, + " %s_texcoords = gl_MultiTexCoord%d.xy;\n", + operand_names[name], name); + break; + case CAIRO_GL_VAR_COVERAGE: + _cairo_output_stream_printf (stream, + " %s_coverage = gl_Color.a;\n", + operand_names[name]); + break; + } +} + +static cairo_status_t +cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src, + cairo_gl_var_type_t mask, + cairo_gl_var_type_t dest, + char **out) +{ + cairo_output_stream_t *stream = _cairo_memory_stream_create (); + unsigned char *source; + unsigned int length; + cairo_status_t status; + + cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_TEX_SOURCE); + cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_TEX_MASK); + + _cairo_output_stream_printf (stream, + "void main()\n" + "{\n" + " gl_Position = ftransform();\n"); + + cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_TEX_SOURCE); + cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_TEX_MASK); + + _cairo_output_stream_write (stream, + "}\n\0", 3); + + status = _cairo_memory_stream_destroy (stream, &source, &length); + if (unlikely (status)) + return status; + + *out = (char *) source; + return CAIRO_STATUS_SUCCESS; +} + +static void +cairo_gl_shader_emit_color (cairo_output_stream_t *stream, + GLuint tex_target, + cairo_gl_operand_type_t type, + cairo_gl_tex_t name) +{ + const char *namestr = operand_names[name]; + const char *rectstr = (tex_target == GL_TEXTURE_RECTANGLE_EXT ? "Rect" : ""); + + switch (type) { + case CAIRO_GL_OPERAND_COUNT: + default: + ASSERT_NOT_REACHED; + break; + case CAIRO_GL_OPERAND_NONE: + _cairo_output_stream_printf (stream, + "vec4 get_%s()\n" + "{\n" + " return vec4 (0, 0, 0, 1);\n" + "}\n", + namestr); + break; + case CAIRO_GL_OPERAND_CONSTANT: + _cairo_output_stream_printf (stream, + "uniform vec4 %s_constant;\n" + "vec4 get_%s()\n" + "{\n" + " return %s_constant;\n" + "}\n", + namestr, namestr, namestr); + break; + case CAIRO_GL_OPERAND_TEXTURE: + _cairo_output_stream_printf (stream, + "uniform sampler2D%s %s_sampler;\n" + "varying vec2 %s_texcoords;\n" + "vec4 get_%s()\n" + "{\n" + " return texture2D%s(%s_sampler, %s_texcoords);\n" + "}\n", + rectstr, namestr, namestr, namestr, rectstr, namestr, namestr); + break; + case CAIRO_GL_OPERAND_LINEAR_GRADIENT: + _cairo_output_stream_printf (stream, + "uniform sampler1D %s_sampler;\n" + "uniform mat3 %s_matrix;\n" + "uniform vec2 %s_segment;\n" + "\n" + "vec4 get_%s()\n" + "{\n" + " vec2 pos = (%s_matrix * vec3 (gl_FragCoord.xy, 1.0)).xy;\n" + " float t = dot (pos, %s_segment) / dot (%s_segment, %s_segment);\n" + " return texture1D (%s_sampler, t);\n" + "}\n", + namestr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr); + break; + case CAIRO_GL_OPERAND_RADIAL_GRADIENT: + _cairo_output_stream_printf (stream, + "uniform sampler1D %s_sampler;\n" + "uniform mat3 %s_matrix;\n" + "uniform vec2 %s_circle_1;\n" + "uniform float %s_radius_0;\n" + "uniform float %s_radius_1;\n" + "\n" + "vec4 get_%s()\n" + "{\n" + " vec2 pos = (%s_matrix * vec3 (gl_FragCoord.xy, 1.0)).xy;\n" + " \n" + " float dr = %s_radius_1 - %s_radius_0;\n" + " float dot_circle_1 = dot (%s_circle_1, %s_circle_1);\n" + " float dot_pos_circle_1 = dot (pos, %s_circle_1);\n" + " \n" + " float A = dot_circle_1 - dr * dr;\n" + " float B = -2.0 * (dot_pos_circle_1 + %s_radius_0 * dr);\n" + " float C = dot (pos, pos) - %s_radius_0 * %s_radius_0;\n" + " float det = B * B - 4.0 * A * C;\n" + " det = max (det, 0.0);\n" + " \n" + " float sqrt_det = sqrt (det);\n" + " sqrt_det *= sign(A);\n" + " \n" + " float t = (-B + sqrt_det) / (2.0 * A);\n" + " return texture1D (%s_sampler, t);\n" + "}\n", + namestr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr, namestr, + namestr); + break; + case CAIRO_GL_OPERAND_SPANS: + _cairo_output_stream_printf (stream, + "varying float %s_coverage;\n" + "vec4 get_%s()\n" + "{\n" + " return vec4(0, 0, 0, %s_coverage);\n" + "}\n", + namestr, namestr, namestr); + break; + } +} + +static cairo_status_t +cairo_gl_shader_get_fragment_source (GLuint tex_target, + cairo_gl_shader_in_t in, + cairo_gl_operand_type_t src, + cairo_gl_operand_type_t mask, + cairo_gl_operand_type_t dest, + char **out) +{ + cairo_output_stream_t *stream = _cairo_memory_stream_create (); + unsigned char *source; + unsigned int length; + cairo_status_t status; + + cairo_gl_shader_emit_color (stream, tex_target, src, CAIRO_GL_TEX_SOURCE); + cairo_gl_shader_emit_color (stream, tex_target, mask, CAIRO_GL_TEX_MASK); + + _cairo_output_stream_printf (stream, + "void main()\n" + "{\n"); + switch (in) { + case CAIRO_GL_SHADER_IN_COUNT: + default: + ASSERT_NOT_REACHED; + case CAIRO_GL_SHADER_IN_NORMAL: + _cairo_output_stream_printf (stream, + " gl_FragColor = get_source() * get_mask().a;\n"); + break; + case CAIRO_GL_SHADER_IN_CA_SOURCE: + _cairo_output_stream_printf (stream, + " gl_FragColor = get_source() * get_mask();\n"); + break; + case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA: + _cairo_output_stream_printf (stream, + " gl_FragColor = get_source().a * get_mask();\n"); + break; + } + + _cairo_output_stream_write (stream, + "}\n\0", 3); + + status = _cairo_memory_stream_destroy (stream, &source, &length); + if (unlikely (status)) + return status; + + *out = (char *) source; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_gl_shader_compile (cairo_gl_context_t *ctx, + cairo_gl_shader_t *shader, + cairo_gl_var_type_t src, + cairo_gl_var_type_t mask, + const char *fragment_text) +{ + unsigned int vertex_shader; + cairo_status_t status; + + if (ctx->shader_impl == NULL) + return CAIRO_STATUS_SUCCESS; + + assert (shader->program == 0); + + vertex_shader = cairo_gl_var_type_hash (src, mask, CAIRO_GL_VAR_NONE); + if (ctx->vertex_shaders[vertex_shader] == 0) { + char *source; + + status = cairo_gl_shader_get_vertex_source (src, + mask, + CAIRO_GL_VAR_NONE, + &source); + if (unlikely (status)) + goto FAILURE; + + ctx->shader_impl->compile_shader (&ctx->vertex_shaders[vertex_shader], + GL_VERTEX_SHADER, + source); + free (source); + } + + ctx->shader_impl->compile_shader (&shader->fragment_shader, + GL_FRAGMENT_SHADER, + fragment_text); + + ctx->shader_impl->link_shader (&shader->program, + ctx->vertex_shaders[vertex_shader], + shader->fragment_shader); return CAIRO_STATUS_SUCCESS; -fail: - glDeleteObjectARB (shader); + FAILURE: + _cairo_gl_shader_fini (ctx, shader); + shader->fragment_shader = 0; + shader->program = 0; + return status; } + +void +_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx, + const char *name, + float value) +{ + ctx->shader_impl->bind_float (ctx->current_shader, name, value); +} + +void +_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx, + const char *name, + float value0, + float value1) +{ + ctx->shader_impl->bind_vec2 (ctx->current_shader, name, value0, value1); +} + +void +_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx, + const char *name, + float value0, + float value1, + float value2) +{ + ctx->shader_impl->bind_vec3 (ctx->current_shader, name, value0, value1, value2); +} + +void +_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx, + const char *name, + float value0, float value1, + float value2, float value3) +{ + ctx->shader_impl->bind_vec4 (ctx->current_shader, name, value0, value1, value2, value3); +} + +void +_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx, + const char *name, cairo_matrix_t* m) +{ + ctx->shader_impl->bind_matrix (ctx->current_shader, name, m); +} + +void +_cairo_gl_shader_bind_texture (cairo_gl_context_t *ctx, + const char *name, GLuint tex_unit) +{ + ctx->shader_impl->bind_texture (ctx->current_shader, name, tex_unit); +} + +void +_cairo_gl_set_shader (cairo_gl_context_t *ctx, + cairo_gl_shader_t *shader) +{ + if (ctx->shader_impl == NULL) + return; + + if (ctx->current_shader == shader) + return; + + ctx->shader_impl->use (shader); + + ctx->current_shader = shader; +} + +cairo_status_t +_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx, + cairo_gl_operand_type_t source, + cairo_gl_operand_type_t mask, + cairo_gl_shader_in_t in, + cairo_gl_shader_t **shader) +{ + cairo_shader_cache_entry_t lookup, *entry; + char *fs_source; + cairo_status_t status; + + if (ctx->shader_impl == NULL) { + *shader = NULL; + return CAIRO_STATUS_SUCCESS; + } + + lookup.src = source; + lookup.mask = mask; + lookup.dest = CAIRO_GL_OPERAND_NONE; + lookup.in = in; + lookup.base.hash = _cairo_gl_shader_cache_hash (&lookup); + lookup.base.size = 1; + + entry = _cairo_cache_lookup (&ctx->shaders, &lookup.base); + if (entry) { + assert (entry->shader.program); + *shader = &entry->shader; + return CAIRO_STATUS_SUCCESS; + } + + status = cairo_gl_shader_get_fragment_source (ctx->tex_target, + in, + source, + mask, + CAIRO_GL_OPERAND_NONE, + &fs_source); + if (unlikely (status)) + return status; + + entry = malloc (sizeof (cairo_shader_cache_entry_t)); + if (unlikely (entry == NULL)) { + free (fs_source); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + memcpy (entry, &lookup, sizeof (cairo_shader_cache_entry_t)); + + entry->ctx = ctx; + _cairo_gl_shader_init (&entry->shader); + status = _cairo_gl_shader_compile (ctx, + &entry->shader, + cairo_gl_operand_get_var_type (source), + cairo_gl_operand_get_var_type (mask), + fs_source); + free (fs_source); + + if (unlikely (status)) { + free (entry); + return status; + } + + status = _cairo_cache_insert (&ctx->shaders, &entry->base); + if (unlikely (status)) { + _cairo_gl_shader_fini (ctx, &entry->shader); + free (entry); + return status; + } + + *shader = &entry->shader; + + return CAIRO_STATUS_SUCCESS; +} diff --git a/gfx/cairo/cairo/src/cairo-gl-surface.c b/gfx/cairo/cairo/src/cairo-gl-surface.c index 019249e44521..278e6429dce0 100644 --- a/gfx/cairo/cairo/src/cairo-gl-surface.c +++ b/gfx/cairo/cairo/src/cairo-gl-surface.c @@ -2,7 +2,7 @@ * * Copyright © 2009 Eric Anholt * Copyright © 2009 Chris Wilson - * Copyright © 2005 Red Hat, Inc + * Copyright © 2005,2010 Red Hat, Inc * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -32,161 +32,48 @@ * The Initial Developer of the Original Code is Red Hat, Inc. * * Contributor(s): + * Benjamin Otte * Carl Worth + * Chris Wilson + * Eric Anholt */ #include "cairoint.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-error-private.h" #include "cairo-gl-private.h" -slim_hidden_proto (cairo_gl_context_reference); -slim_hidden_proto (cairo_gl_context_destroy); - static cairo_int_status_t -_cairo_gl_surface_fill_rectangles (void *abstract_surface, +_cairo_gl_surface_fill_rectangles (void *abstract_dst, cairo_operator_t op, const cairo_color_t *color, cairo_rectangle_int_t *rects, int num_rects); -#define BIAS .375 +static cairo_int_status_t +_cairo_gl_surface_composite (cairo_operator_t op, + const cairo_pattern_t *src, + const cairo_pattern_t *mask, + void *abstract_dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, + cairo_region_t *clip_region); -static inline float -int_as_float (uint32_t val) -{ - union fi { - float f; - uint32_t u; - } fi; - - fi.u = val; - return fi.f; -} - -static const cairo_gl_context_t _nil_context = { - CAIRO_REFERENCE_COUNT_INVALID, - CAIRO_STATUS_NO_MEMORY -}; - -static const cairo_gl_context_t _nil_context__invalid_format = { - CAIRO_REFERENCE_COUNT_INVALID, - CAIRO_STATUS_INVALID_FORMAT -}; +static cairo_status_t +_cairo_gl_surface_flush (void *abstract_surface); static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface) { return surface->backend == &_cairo_gl_surface_backend; } -cairo_gl_context_t * -_cairo_gl_context_create_in_error (cairo_status_t status) -{ - if (status == CAIRO_STATUS_NO_MEMORY) - return (cairo_gl_context_t *) &_nil_context; - - if (status == CAIRO_STATUS_INVALID_FORMAT) - return (cairo_gl_context_t *) &_nil_context__invalid_format; - - ASSERT_NOT_REACHED; - return NULL; -} - -cairo_status_t -_cairo_gl_context_init (cairo_gl_context_t *ctx) -{ - int n; - - ctx->status = CAIRO_STATUS_SUCCESS; - CAIRO_REFERENCE_COUNT_INIT (&ctx->ref_count, 1); - CAIRO_MUTEX_INIT (ctx->mutex); - - memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache)); - - if (glewInit () != GLEW_OK) - return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */ - - if (! GLEW_EXT_framebuffer_object || - ! GLEW_ARB_texture_env_combine || - ! GLEW_ARB_texture_non_power_of_two) - { - fprintf (stderr, - "Required GL extensions not available:\n"); - if (! GLEW_EXT_framebuffer_object) - fprintf (stderr, " GL_EXT_framebuffer_object\n"); - if (! GLEW_ARB_texture_env_combine) - fprintf (stderr, " GL_ARB_texture_env_combine\n"); - if (! GLEW_ARB_texture_non_power_of_two) - fprintf (stderr, " GL_ARB_texture_non_power_of_two\n"); - - return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */ - } - - /* Set up the dummy texture for tex_env_combine with constant color. */ - glGenTextures (1, &ctx->dummy_tex); - glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex); - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - ctx->max_framebuffer_size = 0; - glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size); - ctx->max_texture_size = 0; - glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size); - - for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++) - _cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]); - - return CAIRO_STATUS_SUCCESS; -} - -cairo_gl_context_t * -cairo_gl_context_reference (cairo_gl_context_t *context) -{ - if (context == NULL || - CAIRO_REFERENCE_COUNT_IS_INVALID (&context->ref_count)) - { - return context; - } - - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count)); - _cairo_reference_count_inc (&context->ref_count); - - return context; -} -slim_hidden_def (cairo_gl_context_reference); - -void -cairo_gl_context_destroy (cairo_gl_context_t *context) -{ - int n; - - if (context == NULL || - CAIRO_REFERENCE_COUNT_IS_INVALID (&context->ref_count)) - { - return; - } - - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count)); - if (! _cairo_reference_count_dec_and_test (&context->ref_count)) - return; - - glDeleteTextures (1, &context->dummy_tex); - - for (n = 0; n < ARRAY_LENGTH (context->glyph_cache); n++) - _cairo_gl_glyph_cache_fini (&context->glyph_cache[n]); - - context->destroy (context); - - free (context); -} -slim_hidden_def (cairo_gl_context_destroy); - -cairo_gl_context_t * -_cairo_gl_context_acquire (cairo_gl_context_t *ctx) -{ - CAIRO_MUTEX_LOCK (ctx->mutex); - return ctx; -} - cairo_bool_t _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format, GLenum *internal_format, GLenum *format, @@ -218,7 +105,7 @@ _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format, *has_alpha = FALSE; return TRUE; case PIXMAN_b8g8r8a8: - *internal_format = GL_BGRA; + *internal_format = GL_RGBA; *format = GL_BGRA; *type = GL_UNSIGNED_INT_8_8_8_8; return TRUE; @@ -301,54 +188,13 @@ _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format, case PIXMAN_g1: case PIXMAN_yuy2: case PIXMAN_yv12: -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16) case PIXMAN_x2r10g10b10: case PIXMAN_a2r10g10b10: -#endif default: return FALSE; } } -void -_cairo_gl_context_release (cairo_gl_context_t *ctx) -{ - CAIRO_MUTEX_UNLOCK (ctx->mutex); -} - -void -_cairo_gl_set_destination (cairo_gl_surface_t *surface) -{ - cairo_gl_context_t *ctx = surface->ctx; - - if (ctx->current_target != surface) { - ctx->current_target = surface; - - if (surface->fb) { - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb); - glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); - glReadBuffer (GL_COLOR_ATTACHMENT0_EXT); - } else { - ctx->make_current (ctx, surface); - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); - glDrawBuffer (GL_BACK_LEFT); - glReadBuffer (GL_BACK_LEFT); - } - } - - glViewport (0, 0, surface->width, surface->height); - - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - if (surface->fb) - glOrtho (0, surface->width, 0, surface->height, -1.0, 1.0); - else - glOrtho (0, surface->width, surface->height, 0, -1.0, 1.0); - - glMatrixMode (GL_MODELVIEW); - glLoadIdentity (); -} - cairo_bool_t _cairo_gl_operator_is_supported (cairo_operator_t op) { @@ -356,116 +202,47 @@ _cairo_gl_operator_is_supported (cairo_operator_t op) } void -_cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op, - cairo_bool_t component_alpha) -{ - struct { - GLenum src; - GLenum dst; - } blend_factors[] = { - { GL_ZERO, GL_ZERO }, /* Clear */ - { GL_ONE, GL_ZERO }, /* Source */ - { GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* Over */ - { GL_DST_ALPHA, GL_ZERO }, /* In */ - { GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* Out */ - { GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Atop */ - - { GL_ZERO, GL_ONE }, /* Dest */ - { GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* DestOver */ - { GL_ZERO, GL_SRC_ALPHA }, /* DestIn */ - { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* DestOut */ - { GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /* DestAtop */ - - { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */ - { GL_ONE, GL_ONE }, /* Add */ - }; - GLenum src_factor, dst_factor; - - assert (op < ARRAY_LENGTH (blend_factors)); - - src_factor = blend_factors[op].src; - dst_factor = blend_factors[op].dst; - - /* Even when the user requests CAIRO_CONTENT_COLOR, we use GL_RGBA - * due to texture filtering of GL_CLAMP_TO_BORDER. So fix those - * bits in that case. - */ - if (dst->base.content == CAIRO_CONTENT_COLOR) { - if (src_factor == GL_ONE_MINUS_DST_ALPHA) - src_factor = GL_ZERO; - if (src_factor == GL_DST_ALPHA) - src_factor = GL_ONE; - } - - if (component_alpha) { - if (dst_factor == GL_ONE_MINUS_SRC_ALPHA) - dst_factor = GL_ONE_MINUS_SRC_COLOR; - if (dst_factor == GL_SRC_ALPHA) - dst_factor = GL_SRC_COLOR; - } - - glEnable (GL_BLEND); - glBlendFunc (src_factor, dst_factor); -} - -static void -_cairo_gl_set_texture_surface (int tex_unit, GLuint tex, - cairo_surface_attributes_t *attributes) -{ - glActiveTexture (GL_TEXTURE0 + tex_unit); - glBindTexture (GL_TEXTURE_2D, tex); - switch (attributes->extend) { - case CAIRO_EXTEND_NONE: - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - break; - case CAIRO_EXTEND_PAD: - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - break; - case CAIRO_EXTEND_REPEAT: - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - break; - case CAIRO_EXTEND_REFLECT: - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - break; - } - switch (attributes->filter) { - case CAIRO_FILTER_FAST: - case CAIRO_FILTER_NEAREST: - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - break; - case CAIRO_FILTER_GOOD: - case CAIRO_FILTER_BEST: - case CAIRO_FILTER_BILINEAR: - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - break; - default: - case CAIRO_FILTER_GAUSSIAN: - ASSERT_NOT_REACHED; - } - glEnable (GL_TEXTURE_2D); -} - -void -_cairo_gl_surface_init (cairo_gl_context_t *ctx, +_cairo_gl_surface_init (cairo_device_t *device, cairo_gl_surface_t *surface, cairo_content_t content, int width, int height) { _cairo_surface_init (&surface->base, &_cairo_gl_surface_backend, + device, content); - surface->ctx = cairo_gl_context_reference (ctx); surface->width = width; surface->height = height; } +static cairo_surface_t * +_cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t *ctx, + cairo_content_t content, + GLuint tex, + int width, + int height) +{ + cairo_gl_surface_t *surface; + + assert (width <= ctx->max_framebuffer_size && height <= ctx->max_framebuffer_size); + + surface = calloc (1, sizeof (cairo_gl_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_gl_surface_init (&ctx->base, surface, content, width, height); + surface->tex = tex; + + /* Create the texture used to store the surface's data. */ + _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); + glBindTexture (ctx->tex_target, surface->tex); + glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + return &surface->base; +} + static cairo_surface_t * _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx, cairo_content_t content, @@ -473,19 +250,23 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx, int height) { cairo_gl_surface_t *surface; - GLenum err, format; - cairo_status_t status; + GLenum format; + GLuint tex; - if (ctx->status) - return _cairo_surface_create_in_error (ctx->status); + glGenTextures (1, &tex); + surface = (cairo_gl_surface_t *) + _cairo_gl_surface_create_scratch_for_texture (ctx, content, + tex, width, height); + if (unlikely (surface->base.status)) + return &surface->base; - assert (width <= ctx->max_framebuffer_size && height <= ctx->max_framebuffer_size); + surface->owns_tex = TRUE; - surface = calloc (1, sizeof (cairo_gl_surface_t)); - if (unlikely (surface == NULL)) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - - _cairo_gl_surface_init (ctx, surface, content, width, height); + /* adjust the texture size after setting our real extents */ + if (width < 1) + width = 1; + if (height < 1) + height = 1; switch (content) { default: @@ -510,83 +291,157 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx, break; } - /* Create the texture used to store the surface's data. */ - glGenTextures (1, &surface->tex); - glBindTexture (GL_TEXTURE_2D, surface->tex); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, + glTexImage2D (ctx->tex_target, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL); - /* Create a framebuffer object wrapping the texture so that we can render - * to it. - */ - glGenFramebuffersEXT (1, &surface->fb); - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb); - glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, - surface->tex, - 0); - ctx->current_target = NULL; - - while ((err = glGetError ())) { - fprintf (stderr, "GL error in surface create: 0x%08x\n", err); - } - - status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - fprintf (stderr, "destination is framebuffer incomplete\n"); - return &surface->base; } -static void -_cairo_gl_surface_clear (cairo_gl_surface_t *surface) +static cairo_status_t +_cairo_gl_surface_clear (cairo_gl_surface_t *surface, + const cairo_color_t *color) { cairo_gl_context_t *ctx; + cairo_status_t status; + double r, g, b, a; - ctx = _cairo_gl_context_acquire (surface->ctx); - _cairo_gl_set_destination (surface); - if (surface->base.content == CAIRO_CONTENT_COLOR) - glClearColor (0.0, 0.0, 0.0, 1.0); - else - glClearColor (0.0, 0.0, 0.0, 0.0); + status = _cairo_gl_context_acquire (surface->base.device, &ctx); + if (unlikely (status)) + return status; + + _cairo_gl_context_set_destination (ctx, surface); + if (surface->base.content & CAIRO_CONTENT_COLOR) { + r = color->red * color->alpha; + g = color->green * color->alpha; + b = color->blue * color->alpha; + } else { + r = g = b = 0; + } + if (surface->base.content & CAIRO_CONTENT_ALPHA) { + a = color->alpha; + } else { + a = 1.0; + } + + glDisable (GL_SCISSOR_TEST); + glClearColor (r, g, b, a); glClear (GL_COLOR_BUFFER_BIT); - _cairo_gl_context_release (ctx); - - surface->base.is_clear = TRUE; + return _cairo_gl_context_release (ctx, status); } cairo_surface_t * -cairo_gl_surface_create (cairo_gl_context_t *ctx, - cairo_content_t content, - int width, - int height) +cairo_gl_surface_create (cairo_device_t *abstract_device, + cairo_content_t content, + int width, + int height) { + cairo_gl_context_t *ctx; cairo_gl_surface_t *surface; + cairo_status_t status; - if (!CAIRO_CONTENT_VALID (content)) + if (! CAIRO_CONTENT_VALID (content)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); - if (ctx == NULL) { + if (abstract_device == NULL) { return cairo_image_surface_create (_cairo_format_from_content (content), width, height); } + if (abstract_device->status) + return _cairo_surface_create_in_error (abstract_device->status); + + if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + + status = _cairo_gl_context_acquire (abstract_device, &ctx); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + surface = (cairo_gl_surface_t *) _cairo_gl_surface_create_scratch (ctx, content, width, height); - if (unlikely (surface->base.status)) - return &surface->base; + if (unlikely (surface->base.status)) { + status = _cairo_gl_context_release (ctx, surface->base.status); + cairo_surface_destroy (&surface->base); + return _cairo_surface_create_in_error (status); + } /* Cairo surfaces start out initialized to transparent (black) */ - _cairo_gl_surface_clear (surface); + status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT); + + status = _cairo_gl_context_release (ctx, status); + if (unlikely (status)) { + cairo_surface_destroy (&surface->base); + return _cairo_surface_create_in_error (status); + } return &surface->base; } slim_hidden_def (cairo_gl_surface_create); + +/** + * cairo_gl_surface_create_for_texture: + * @content: type of content in the surface + * @tex: name of texture to use for storage of surface pixels + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates a GL surface for the specified texture with the specified + * content and dimensions. The texture must be kept around until the + * #cairo_surface_t is destroyed or cairo_surface_finish() is called + * on the surface. The initial contents of @tex will be used as the + * initial image contents; you must explicitly clear the buffer, + * using, for example, cairo_rectangle() and cairo_fill() if you want + * it cleared. The format of @tex should be compatible with @content, + * in the sense that it must have the color components required by + * @content. + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + **/ +cairo_surface_t * +cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device, + cairo_content_t content, + unsigned int tex, + int width, + int height) +{ + cairo_gl_context_t *ctx; + cairo_gl_surface_t *surface; + cairo_status_t status; + + if (! CAIRO_CONTENT_VALID (content)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); + + if (abstract_device == NULL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER)); + + if (abstract_device->status) + return _cairo_surface_create_in_error (abstract_device->status); + + if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + + status = _cairo_gl_context_acquire (abstract_device, &ctx); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + surface = (cairo_gl_surface_t *) + _cairo_gl_surface_create_scratch_for_texture (ctx, content, + tex, width, height); + status = _cairo_gl_context_release (ctx, status); + + return &surface->base; +} +slim_hidden_def (cairo_gl_surface_create_for_texture); + + void cairo_gl_surface_set_size (cairo_surface_t *abstract_surface, int width, @@ -595,9 +450,18 @@ cairo_gl_surface_set_size (cairo_surface_t *abstract_surface, cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface; cairo_status_t status; - if (! _cairo_surface_is_gl (abstract_surface) || surface->fb) { + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { status = _cairo_surface_set_error (abstract_surface, - CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + if (! _cairo_surface_is_gl (abstract_surface) || + ! _cairo_gl_surface_is_texture (surface)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; } @@ -627,21 +491,42 @@ cairo_gl_surface_get_height (cairo_surface_t *abstract_surface) return surface->height; } - void cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface) { cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface; cairo_status_t status; + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + if (! _cairo_surface_is_gl (abstract_surface)) { status = _cairo_surface_set_error (abstract_surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return; } - if (! surface->fb) - surface->ctx->swap_buffers (surface->ctx, surface); + if (! _cairo_gl_surface_is_texture (surface)) { + cairo_gl_context_t *ctx; + cairo_status_t status; + + status = _cairo_gl_context_acquire (surface->base.device, &ctx); + if (unlikely (status)) + return; + + cairo_surface_flush (abstract_surface); + + ctx->swap_buffers (ctx, surface); + + status = _cairo_gl_context_release (ctx, status); + if (status) + status = _cairo_surface_set_error (abstract_surface, status); + } } static cairo_surface_t * @@ -650,22 +535,35 @@ _cairo_gl_surface_create_similar (void *abstract_surface, int width, int height) { - cairo_gl_surface_t *surface = abstract_surface; + cairo_surface_t *surface = abstract_surface; + cairo_gl_context_t *ctx; + cairo_status_t status; - assert (CAIRO_CONTENT_VALID (content)); + if (width < 1 || height < 1) + return cairo_image_surface_create (_cairo_format_from_content (content), + width, height); - if (width > surface->ctx->max_framebuffer_size || - height > surface->ctx->max_framebuffer_size) + status = _cairo_gl_context_acquire (surface->device, &ctx); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + if (width > ctx->max_framebuffer_size || + height > ctx->max_framebuffer_size) { - return NULL; + surface = NULL; + goto RELEASE; } - if (width < 1) - width = 1; - if (height < 1) - height = 1; + surface = _cairo_gl_surface_create_scratch (ctx, content, width, height); - return _cairo_gl_surface_create_scratch (surface->ctx, content, width, height); +RELEASE: + status = _cairo_gl_context_release (ctx, status); + if (unlikely (status)) { + cairo_surface_destroy (surface); + return _cairo_surface_create_in_error (status); + } + + return surface; } cairo_status_t @@ -678,18 +576,19 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, GLenum internal_format, format, type; cairo_bool_t has_alpha; cairo_image_surface_t *clone = NULL; + cairo_gl_context_t *ctx; int cpp; + cairo_status_t status = CAIRO_STATUS_SUCCESS; if (! _cairo_gl_get_image_format_and_type (src->pixman_format, - &internal_format, - &format, - &type, - &has_alpha)) + &internal_format, + &format, + &type, + &has_alpha)) { cairo_bool_t is_supported; - clone = _cairo_image_surface_coerce (src, - _cairo_format_from_content (src->base.content)); + clone = _cairo_image_surface_coerce (src); if (unlikely (clone->base.status)) return clone->base.status; @@ -705,46 +604,90 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8; - glBindTexture (GL_TEXTURE_2D, dst->tex); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + status = _cairo_gl_context_acquire (dst->base.device, &ctx); + if (unlikely (status)) + return status; + + status = _cairo_gl_surface_flush (&dst->base); + if (unlikely (status)) + goto FAIL; + glPixelStorei (GL_UNPACK_ALIGNMENT, 1); glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp); - glTexSubImage2D (GL_TEXTURE_2D, 0, - dst_x, dst_y, width, height, - format, GL_UNSIGNED_BYTE, - src->data + src_y * src->stride + src_x * cpp); - glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); + if (_cairo_gl_surface_is_texture (dst)) { + _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); + glBindTexture (ctx->tex_target, dst->tex); + glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexSubImage2D (ctx->tex_target, 0, + dst_x, dst_y, width, height, + format, type, + src->data + src_y * src->stride + src_x * cpp); - cairo_surface_destroy (&clone->base); + /* If we just treated some rgb-only data as rgba, then we have to + * go back and fix up the alpha channel where we filled in this + * texture data. + */ + if (!has_alpha) { + cairo_rectangle_int_t rect; - /* If we just treated some rgb-only data as rgba, then we have to - * go back and fix up the alpha channel where we filled in this - * texture data. - */ - if (!has_alpha) { - cairo_rectangle_int_t rect; - cairo_color_t color; + rect.x = dst_x; + rect.y = dst_y; + rect.width = width; + rect.height = height; - rect.x = dst_x; - rect.y = dst_y; - rect.width = width; - rect.height = height; + _cairo_gl_composite_flush (ctx); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); + _cairo_gl_surface_fill_rectangles (dst, + CAIRO_OPERATOR_SOURCE, + CAIRO_COLOR_BLACK, + &rect, 1); + _cairo_gl_composite_flush (ctx); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + } else { + cairo_surface_t *tmp; + + tmp = _cairo_gl_surface_create_scratch (ctx, + dst->base.content, + width, height); + if (unlikely (tmp->status)) { + cairo_surface_destroy (tmp); + goto FAIL; + } + status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *) tmp, + src, + src_x, src_y, + width, height, + 0, 0); + if (status == CAIRO_STATUS_SUCCESS) { + cairo_surface_pattern_t tmp_pattern; - color.red = 0.0; - color.green = 0.0; - color.blue = 0.0; - color.alpha = 1.0; + _cairo_pattern_init_for_surface (&tmp_pattern, tmp); + _cairo_gl_surface_composite (CAIRO_OPERATOR_SOURCE, + &tmp_pattern.base, + NULL, + dst, + 0, 0, + 0, 0, + dst_x, dst_y, + width, height, + NULL); + _cairo_pattern_fini (&tmp_pattern.base); + } - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - _cairo_gl_surface_fill_rectangles (dst, - CAIRO_OPERATOR_SOURCE, - &color, - &rect, 1); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + cairo_surface_destroy (tmp); } - return CAIRO_STATUS_SUCCESS; +FAIL: + glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); + + status = _cairo_gl_context_release (ctx, status); + + if (clone) + cairo_surface_destroy (&clone->base); + + return status; } static cairo_status_t @@ -754,10 +697,11 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t *surface, cairo_rectangle_int_t *rect_out) { cairo_image_surface_t *image; - GLenum err; + cairo_gl_context_t *ctx; GLenum format, type; cairo_format_t cairo_format; unsigned int cpp; + cairo_status_t status; /* Want to use a switch statement here but the compiler gets whiny. */ if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) { @@ -790,20 +734,33 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t *surface, * it the destination. But then, this is the fallback path, so let's not * fall back instead. */ - _cairo_gl_set_destination (surface); + status = _cairo_gl_context_acquire (surface->base.device, &ctx); + if (unlikely (status)) + return status; + + _cairo_gl_composite_flush (ctx); + _cairo_gl_context_set_destination (ctx, surface); glPixelStorei (GL_PACK_ALIGNMENT, 1); glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp); + if (! _cairo_gl_surface_is_texture (surface) && GLEW_MESA_pack_invert) + glPixelStorei (GL_PACK_INVERT_MESA, 1); glReadPixels (interest->x, interest->y, interest->width, interest->height, format, type, image->data); + if (! _cairo_gl_surface_is_texture (surface) && GLEW_MESA_pack_invert) + glPixelStorei (GL_PACK_INVERT_MESA, 0); - while ((err = glGetError ())) - fprintf (stderr, "GL error 0x%08x\n", (int) err); + status = _cairo_gl_context_release (ctx, status); + if (unlikely (status)) { + cairo_surface_destroy (&image->base); + return status; + } *image_out = image; if (rect_out != NULL) *rect_out = *interest; + return CAIRO_STATUS_SUCCESS; } @@ -811,16 +768,30 @@ static cairo_status_t _cairo_gl_surface_finish (void *abstract_surface) { cairo_gl_surface_t *surface = abstract_surface; + cairo_status_t status; + cairo_gl_context_t *ctx; - glDeleteFramebuffersEXT (1, &surface->fb); - glDeleteTextures (1, &surface->tex); + status = _cairo_gl_context_acquire (surface->base.device, &ctx); + if (unlikely (status)) + return status; - if (surface->ctx->current_target == surface) - surface->ctx->current_target = NULL; + if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE && + ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface) + _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE); + if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE && + ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface) + _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK); + if (ctx->current_target == surface) + ctx->current_target = NULL; - cairo_gl_context_destroy (surface->ctx); + if (surface->depth) + glDeleteFramebuffersEXT (1, &surface->depth); + if (surface->fb) + glDeleteFramebuffersEXT (1, &surface->fb); + if (surface->owns_tex) + glDeleteTextures (1, &surface->tex); - return CAIRO_STATUS_SUCCESS; + return _cairo_gl_context_release (ctx, status); } static cairo_status_t @@ -893,7 +864,9 @@ _cairo_gl_surface_clone_similar (void *abstract_surface, { cairo_gl_surface_t *surface = abstract_surface; - if (src->backend == surface->base.backend) { + /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */ + if (src->device == surface->base.device && + _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) { *clone_offset_x = 0; *clone_offset_y = 0; *clone_out = cairo_surface_reference (src); @@ -984,557 +957,6 @@ _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst, return CAIRO_STATUS_SUCCESS; } -/** - * Like cairo_pattern_acquire_surface(), but returns a matrix that transforms - * from dest to src coords. - */ -static cairo_status_t -_cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand, - const cairo_pattern_t *src, - cairo_gl_surface_t *dst, - int src_x, int src_y, - int dst_x, int dst_y, - int width, int height) -{ - cairo_status_t status; - cairo_matrix_t m; - cairo_gl_surface_t *surface; - cairo_surface_attributes_t *attributes; - - attributes = &operand->operand.texture.attributes; - - status = _cairo_pattern_acquire_surface (src, &dst->base, - src_x, src_y, - width, height, - CAIRO_PATTERN_ACQUIRE_NONE, - (cairo_surface_t **) - &surface, - attributes); - if (unlikely (status)) - return status; - - assert (surface->base.backend == &_cairo_gl_surface_backend); - - operand->operand.texture.surface = surface; - operand->operand.texture.tex = surface->tex; - - /* Translate the matrix from - * (unnormalized src -> unnormalized src) to - * (unnormalized dst -> unnormalized src) - */ - cairo_matrix_init_translate (&m, - src_x - dst_x + attributes->x_offset, - src_y - dst_y + attributes->y_offset); - cairo_matrix_multiply (&attributes->matrix, - &m, - &attributes->matrix); - - - /* Translate the matrix from - * (unnormalized src -> unnormalized src) to - * (unnormalized dst -> normalized src) - */ - cairo_matrix_init_scale (&m, - 1.0 / surface->width, - 1.0 / surface->height); - cairo_matrix_multiply (&attributes->matrix, - &attributes->matrix, - &m); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_gl_solid_operand_init (cairo_gl_composite_operand_t *operand, - const cairo_color_t *color) -{ - operand->type = OPERAND_CONSTANT; - operand->operand.constant.color[0] = color->red * color->alpha; - operand->operand.constant.color[1] = color->green * color->alpha; - operand->operand.constant.color[2] = color->blue * color->alpha; - operand->operand.constant.color[3] = color->alpha; - return CAIRO_STATUS_SUCCESS; -} - -cairo_int_status_t -_cairo_gl_operand_init (cairo_gl_composite_operand_t *operand, - const cairo_pattern_t *pattern, - cairo_gl_surface_t *dst, - int src_x, int src_y, - int dst_x, int dst_y, - int width, int height) -{ - operand->pattern = pattern; - - switch (pattern->type) { - case CAIRO_PATTERN_TYPE_SOLID: - return _cairo_gl_solid_operand_init (operand, - &((cairo_solid_pattern_t *) pattern)->color); - case CAIRO_PATTERN_TYPE_LINEAR: - case CAIRO_PATTERN_TYPE_RADIAL: - { - cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern; - - /* Fast path for gradients with less than 2 color stops. - * Required to prevent _cairo_pattern_acquire_surface() returning - * a solid color which is cached beyond the life of the context. - */ - if (src->n_stops < 2) { - if (src->n_stops) { - return _cairo_gl_solid_operand_init (operand, - &src->stops->color); - } else { - return _cairo_gl_solid_operand_init (operand, - CAIRO_COLOR_TRANSPARENT); - } - } else { - unsigned int i; - - /* Is the gradient a uniform colour? - * Happens more often than you would believe. - */ - for (i = 1; i < src->n_stops; i++) { - if (! _cairo_color_equal (&src->stops[0].color, - &src->stops[i].color)) - { - break; - } - } - if (i == src->n_stops) { - return _cairo_gl_solid_operand_init (operand, - &src->stops->color); - } - } - } - - /* fall through */ - - default: - case CAIRO_PATTERN_TYPE_SURFACE: - operand->type = OPERAND_TEXTURE; - return _cairo_gl_pattern_texture_setup (operand, - pattern, dst, - src_x, src_y, - dst_x, dst_y, - width, height); - } -} - -void -_cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand) -{ - switch (operand->type) { - case OPERAND_CONSTANT: - break; - case OPERAND_TEXTURE: - if (operand->operand.texture.surface != NULL) { - cairo_gl_surface_t *surface = operand->operand.texture.surface; - - _cairo_pattern_release_surface (operand->pattern, - &surface->base, - &operand->operand.texture.attributes); - } - break; - } -} - -static void -_cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx, int tex_unit, - GLfloat *color) -{ - glActiveTexture (GL_TEXTURE0 + tex_unit); - /* Have to have a dummy texture bound in order to use the combiner unit. */ - glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex); - glEnable (GL_TEXTURE_2D); - - glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - if (tex_unit == 0) { - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - } else { - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); - } - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT); - if (tex_unit == 0) { - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - } else { - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); - } -} - -void -_cairo_gl_set_src_operand (cairo_gl_context_t *ctx, - cairo_gl_composite_setup_t *setup) -{ - cairo_surface_attributes_t *src_attributes; - GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0}; - - src_attributes = &setup->src.operand.texture.attributes; - - switch (setup->src.type) { - case OPERAND_CONSTANT: - _cairo_gl_set_tex_combine_constant_color (ctx, 0, - setup->src.operand.constant.color); - break; - case OPERAND_TEXTURE: - _cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex, - src_attributes); - /* Set up the constant color we use to set color to 0 if needed. */ - glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color); - /* Set up the combiner to just set color to the sampled texture. */ - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - - /* Force the src color to 0 if the surface should be alpha-only. - * We may have a teximage with color bits if the implementation doesn't - * support GL_ALPHA FBOs. - */ - if (setup->src.operand.texture.surface->base.content != - CAIRO_CONTENT_ALPHA) - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0); - else - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - break; - } -} - -/* This is like _cairo_gl_set_src_operand, but instead swizzles the source - * for creating the "source alpha" value (src.aaaa * mask.argb) required by - * component alpha rendering. - */ -static void -_cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx, - cairo_gl_composite_setup_t *setup) -{ - GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0}; - cairo_surface_attributes_t *src_attributes; - - src_attributes = &setup->src.operand.texture.attributes; - - switch (setup->src.type) { - case OPERAND_CONSTANT: - constant_color[0] = setup->src.operand.constant.color[3]; - constant_color[1] = setup->src.operand.constant.color[3]; - constant_color[2] = setup->src.operand.constant.color[3]; - constant_color[3] = setup->src.operand.constant.color[3]; - _cairo_gl_set_tex_combine_constant_color (ctx, 0, constant_color); - break; - case OPERAND_TEXTURE: - constant_color[0] = 0.0; - constant_color[1] = 0.0; - constant_color[2] = 0.0; - constant_color[3] = 1.0; - _cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex, - src_attributes); - /* Set up the combiner to just set color to the sampled texture. */ - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - break; - } -} - -/* This is like _cairo_gl_set_src_alpha_operand, for component alpha setup - * of the mask part of IN to produce a "source alpha" value. - */ -static void -_cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx, - cairo_gl_composite_setup_t *setup) -{ - cairo_surface_attributes_t *mask_attributes; - GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0}; - - mask_attributes = &setup->mask.operand.texture.attributes; - - glActiveTexture (GL_TEXTURE1); - glEnable (GL_TEXTURE_2D); - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); - - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); - - switch (setup->mask.type) { - case OPERAND_CONSTANT: - /* Have to have a dummy texture bound in order to use the combiner unit. */ - glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex); - - glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, - setup->mask.operand.constant.color); - - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - - break; - case OPERAND_TEXTURE: - _cairo_gl_set_texture_surface (1, setup->mask.operand.texture.tex, - mask_attributes); - /* Set up the constant color we use to set color to 0 if needed. */ - glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color); - - /* Force the mask color to 0 if the surface should be alpha-only. - * We may have a teximage with color bits if the implementation doesn't - * support GL_ALPHA FBOs. - */ - if (setup->mask.operand.texture.surface->base.content != - CAIRO_CONTENT_ALPHA) - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1); - else - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - break; - } -} - -/** - * implements component-alpha CAIRO_OPERATOR_SOURCE using two passes of - * the simpler operations CAIRO_OPERATOR_DEST_OUT and CAIRO_OPERATOR_ADD. - * - * From http://anholt.livejournal.com/32058.html: - * - * The trouble is that component-alpha rendering requires two different sources - * for blending: one for the source value to the blender, which is the - * per-channel multiplication of source and mask, and one for the source alpha - * for multiplying with the destination channels, which is the multiplication - * of the source channels by the mask alpha. So the equation for Over is: - * - * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A - * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R - * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G - * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B - * - * But we can do some simpler operations, right? How about PictOpOutReverse, - * which has a source factor of 0 and dest factor of (1 - source alpha). We - * can get the source alpha value (srca.X = src.A * mask.X) out of the texture - * blenders pretty easily. So we can do a component-alpha OutReverse, which - * gets us: - * - * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A - * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R - * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G - * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B - * - * OK. And if an op doesn't use the source alpha value for the destination - * factor, then we can do the channel multiplication in the texture blenders - * to get the source value, and ignore the source alpha that we wouldn't use. - * We've supported this in the Radeon driver for a long time. An example would - * be PictOpAdd, which does: - * - * dst.A = src.A * mask.A + dst.A - * dst.R = src.R * mask.R + dst.R - * dst.G = src.G * mask.G + dst.G - * dst.B = src.B * mask.B + dst.B - * - * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right - * after it, we get: - * - * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) - * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) - * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) - * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) - * - * This two-pass trickery could be avoided using a new GL extension that - * lets two values come out of the shader and into the blend unit. - */ -static cairo_int_status_t -_cairo_gl_surface_composite_component_alpha (cairo_operator_t op, - const cairo_pattern_t *src, - const cairo_pattern_t *mask, - void *abstract_dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height, - cairo_region_t *clip_region) -{ - cairo_gl_surface_t *dst = abstract_dst; - cairo_surface_attributes_t *src_attributes, *mask_attributes = NULL; - cairo_gl_context_t *ctx; - struct gl_point { - GLfloat x, y; - } vertices_stack[8], texcoord_src_stack[8], texcoord_mask_stack[8]; - struct gl_point *vertices = vertices_stack; - struct gl_point *texcoord_src = texcoord_src_stack; - struct gl_point *texcoord_mask = texcoord_mask_stack; - cairo_status_t status; - int num_vertices, i; - GLenum err; - cairo_gl_composite_setup_t setup; - - if (op != CAIRO_OPERATOR_OVER) - return UNSUPPORTED ("unsupported component alpha operator"); - - memset (&setup, 0, sizeof (setup)); - - status = _cairo_gl_operand_init (&setup.src, src, dst, - src_x, src_y, - dst_x, dst_y, - width, height); - if (unlikely (status)) - return status; - src_attributes = &setup.src.operand.texture.attributes; - - status = _cairo_gl_operand_init (&setup.mask, mask, dst, - mask_x, mask_y, - dst_x, dst_y, - width, height); - if (unlikely (status)) { - _cairo_gl_operand_destroy (&setup.src); - return status; - } - mask_attributes = &setup.mask.operand.texture.attributes; - - ctx = _cairo_gl_context_acquire (dst->ctx); - _cairo_gl_set_destination (dst); - - if (clip_region != NULL) { - int num_rectangles; - - num_rectangles = cairo_region_num_rectangles (clip_region); - if (num_rectangles * 4 > ARRAY_LENGTH (vertices_stack)) { - vertices = _cairo_malloc_ab (num_rectangles, - 4*3*sizeof (vertices[0])); - if (unlikely (vertices == NULL)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto CONTEXT_RELEASE; - } - - texcoord_src = vertices + num_rectangles * 4; - texcoord_mask = texcoord_src + num_rectangles * 4; - } - - for (i = 0; i < num_rectangles; i++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (clip_region, i, &rect); - vertices[4*i + 0].x = rect.x; - vertices[4*i + 0].y = rect.y; - vertices[4*i + 1].x = rect.x + rect.width; - vertices[4*i + 1].y = rect.y; - vertices[4*i + 2].x = rect.x + rect.width; - vertices[4*i + 2].y = rect.y + rect.height; - vertices[4*i + 3].x = rect.x; - vertices[4*i + 3].y = rect.y + rect.height; - } - - num_vertices = 4 * num_rectangles; - } else { - vertices[0].x = dst_x; - vertices[0].y = dst_y; - vertices[1].x = dst_x + width; - vertices[1].y = dst_y; - vertices[2].x = dst_x + width; - vertices[2].y = dst_y + height; - vertices[3].x = dst_x; - vertices[3].y = dst_y + height; - - num_vertices = 4; - } - - glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices); - glEnableClientState (GL_VERTEX_ARRAY); - - if (setup.src.type == OPERAND_TEXTURE) { - for (i = 0; i < num_vertices; i++) { - double s, t; - - s = vertices[i].x; - t = vertices[i].y; - cairo_matrix_transform_point (&src_attributes->matrix, &s, &t); - texcoord_src[i].x = s; - texcoord_src[i].y = t; - } - - glClientActiveTexture (GL_TEXTURE0); - glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat)*2, texcoord_src); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); - } - - if (setup.mask.type == OPERAND_TEXTURE) { - for (i = 0; i < num_vertices; i++) { - double s, t; - - s = vertices[i].x; - t = vertices[i].y; - cairo_matrix_transform_point (&mask_attributes->matrix, &s, &t); - texcoord_mask[i].x = s; - texcoord_mask[i].y = t; - } - - glClientActiveTexture (GL_TEXTURE1); - glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat)*2, texcoord_mask); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); - } - - _cairo_gl_set_operator (dst, CAIRO_OPERATOR_DEST_OUT, TRUE); - _cairo_gl_set_src_alpha_operand (ctx, &setup); - _cairo_gl_set_component_alpha_mask_operand (ctx, &setup); - glDrawArrays (GL_QUADS, 0, num_vertices); - - _cairo_gl_set_operator (dst, CAIRO_OPERATOR_ADD, TRUE); - _cairo_gl_set_src_operand (ctx, &setup); - glDrawArrays (GL_QUADS, 0, num_vertices); - - glDisable (GL_BLEND); - - glDisableClientState (GL_VERTEX_ARRAY); - - glClientActiveTexture (GL_TEXTURE0); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - glActiveTexture (GL_TEXTURE0); - glDisable (GL_TEXTURE_2D); - - glClientActiveTexture (GL_TEXTURE1); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - glActiveTexture (GL_TEXTURE1); - glDisable (GL_TEXTURE_2D); - - while ((err = glGetError ())) - fprintf (stderr, "GL error 0x%08x\n", (int) err); - - CONTEXT_RELEASE: - _cairo_gl_context_release (ctx); - - _cairo_gl_operand_destroy (&setup.src); - if (mask != NULL) - _cairo_gl_operand_destroy (&setup.mask); - - if (vertices != vertices_stack) - free (vertices); - - return status; -} - static cairo_int_status_t _cairo_gl_surface_composite (cairo_operator_t op, const cairo_pattern_t *src, @@ -1550,206 +972,84 @@ _cairo_gl_surface_composite (cairo_operator_t op, unsigned int height, cairo_region_t *clip_region) { - cairo_gl_surface_t *dst = abstract_dst; - cairo_surface_attributes_t *src_attributes, *mask_attributes = NULL; + cairo_gl_surface_t *dst = abstract_dst; cairo_gl_context_t *ctx; - struct gl_point { - GLfloat x, y; - } vertices_stack[8], texcoord_src_stack[8], texcoord_mask_stack[8]; - struct gl_point *vertices = vertices_stack; - struct gl_point *texcoord_src = texcoord_src_stack; - struct gl_point *texcoord_mask = texcoord_mask_stack; cairo_status_t status; - int num_vertices, i; - GLenum err; - cairo_gl_composite_setup_t setup; + cairo_gl_composite_t setup; + cairo_rectangle_int_t rect = { dst_x, dst_y, width, height }; + int dx, dy; - if (! _cairo_gl_operator_is_supported (op)) - return UNSUPPORTED ("unsupported operator"); - - if (mask && mask->has_component_alpha) { - /* Try two-pass component alpha support, or bail. */ - return _cairo_gl_surface_composite_component_alpha(op, - src, - mask, - abstract_dst, - src_x, - src_y, - mask_x, - mask_y, - dst_x, - dst_y, - width, - height, - clip_region); + if (op == CAIRO_OPERATOR_SOURCE && + mask == NULL && + src->type == CAIRO_PATTERN_TYPE_SURFACE && + _cairo_surface_is_image (((cairo_surface_pattern_t *) src)->surface) && + _cairo_matrix_is_integer_translation (&src->matrix, &dx, &dy)) { + cairo_image_surface_t *image = (cairo_image_surface_t *) + ((cairo_surface_pattern_t *) src)->surface; + dx += src_x; + dy += src_y; + if (dx >= 0 && + dy >= 0 && + dx + width <= (unsigned int) image->width && + dy + height <= (unsigned int) image->height) { + status = _cairo_gl_surface_draw_image (dst, image, + dx, dy, + width, height, + dst_x, dst_y); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } } - memset (&setup, 0, sizeof (setup)); - - status = _cairo_gl_operand_init (&setup.src, src, dst, - src_x, src_y, - dst_x, dst_y, - width, height); + status = _cairo_gl_composite_init (&setup, op, dst, + mask && mask->has_component_alpha, + &rect); if (unlikely (status)) - return status; - src_attributes = &setup.src.operand.texture.attributes; + goto CLEANUP; - if (mask != NULL) { - status = _cairo_gl_operand_init (&setup.mask, mask, dst, - mask_x, mask_y, - dst_x, dst_y, - width, height); - if (unlikely (status)) { - _cairo_gl_operand_destroy (&setup.src); - return status; - } - mask_attributes = &setup.mask.operand.texture.attributes; - } + status = _cairo_gl_composite_set_source (&setup, src, + src_x, src_y, + dst_x, dst_y, + width, height); + if (unlikely (status)) + goto CLEANUP; - ctx = _cairo_gl_context_acquire (dst->ctx); - _cairo_gl_set_destination (dst); - _cairo_gl_set_operator (dst, op, FALSE); + status = _cairo_gl_composite_set_mask (&setup, mask, + mask_x, mask_y, + dst_x, dst_y, + width, height); + if (unlikely (status)) + goto CLEANUP; - _cairo_gl_set_src_operand (ctx, &setup); - - if (mask != NULL) { - switch (setup.mask.type) { - case OPERAND_CONSTANT: - _cairo_gl_set_tex_combine_constant_color (ctx, 1, - setup.mask.operand.constant.color); - break; - - case OPERAND_TEXTURE: - _cairo_gl_set_texture_surface (1, setup.mask.operand.texture.tex, - mask_attributes); - - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); - - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - - /* IN: dst.argb = src.argb * mask.aaaa */ - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); - break; - } - } + status = _cairo_gl_composite_begin (&setup, &ctx); + if (unlikely (status)) + goto CLEANUP; if (clip_region != NULL) { - int num_rectangles; + int i, num_rectangles; - num_rectangles = cairo_region_num_rectangles (clip_region); - if (num_rectangles * 4 > ARRAY_LENGTH (vertices_stack)) { - vertices = _cairo_malloc_ab (num_rectangles, - 4*3*sizeof (vertices[0])); - if (unlikely (vertices == NULL)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto CONTEXT_RELEASE; - } - - texcoord_src = vertices + num_rectangles * 4; - texcoord_mask = texcoord_src + num_rectangles * 4; - } + num_rectangles = cairo_region_num_rectangles (clip_region); for (i = 0; i < num_rectangles; i++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (clip_region, i, &rect); - vertices[4*i + 0].x = rect.x; - vertices[4*i + 0].y = rect.y; - vertices[4*i + 1].x = rect.x + rect.width; - vertices[4*i + 1].y = rect.y; - vertices[4*i + 2].x = rect.x + rect.width; - vertices[4*i + 2].y = rect.y + rect.height; - vertices[4*i + 3].x = rect.x; - vertices[4*i + 3].y = rect.y + rect.height; + _cairo_gl_composite_emit_rect (ctx, + rect.x, rect.y, + rect.x + rect.width, rect.y + rect.height, + 0); } - - num_vertices = 4 * num_rectangles; } else { - vertices[0].x = dst_x; - vertices[0].y = dst_y; - vertices[1].x = dst_x + width; - vertices[1].y = dst_y; - vertices[2].x = dst_x + width; - vertices[2].y = dst_y + height; - vertices[3].x = dst_x; - vertices[3].y = dst_y + height; - - num_vertices = 4; + _cairo_gl_composite_emit_rect (ctx, + dst_x, dst_y, + dst_x + width, dst_y + height, + 0); } - glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices); - glEnableClientState (GL_VERTEX_ARRAY); + status = _cairo_gl_context_release (ctx, status); - if (setup.src.type == OPERAND_TEXTURE) { - for (i = 0; i < num_vertices; i++) { - double s, t; - - s = vertices[i].x; - t = vertices[i].y; - cairo_matrix_transform_point (&src_attributes->matrix, &s, &t); - texcoord_src[i].x = s; - texcoord_src[i].y = t; - } - - glClientActiveTexture (GL_TEXTURE0); - glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat)*2, texcoord_src); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); - } - - if (mask != NULL) { - if (setup.mask.type == OPERAND_TEXTURE) { - for (i = 0; i < num_vertices; i++) { - double s, t; - - s = vertices[i].x; - t = vertices[i].y; - cairo_matrix_transform_point (&mask_attributes->matrix, &s, &t); - texcoord_mask[i].x = s; - texcoord_mask[i].y = t; - } - - glClientActiveTexture (GL_TEXTURE1); - glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat)*2, texcoord_mask); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); - } - } - - glDrawArrays (GL_QUADS, 0, num_vertices); - - glDisable (GL_BLEND); - - glDisableClientState (GL_VERTEX_ARRAY); - - glClientActiveTexture (GL_TEXTURE0); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - glActiveTexture (GL_TEXTURE0); - glDisable (GL_TEXTURE_2D); - - glClientActiveTexture (GL_TEXTURE1); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - glActiveTexture (GL_TEXTURE1); - glDisable (GL_TEXTURE_2D); - - while ((err = glGetError ())) - fprintf (stderr, "GL error 0x%08x\n", (int) err); - - CONTEXT_RELEASE: - _cairo_gl_context_release (ctx); - - _cairo_gl_operand_destroy (&setup.src); - if (mask != NULL) - _cairo_gl_operand_destroy (&setup.mask); - - if (vertices != vertices_stack) - free (vertices); + CLEANUP: + _cairo_gl_composite_fini (&setup); return status; } @@ -1774,20 +1074,6 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op, if (! _cairo_gl_operator_is_supported (op)) return UNSUPPORTED ("unsupported operator"); - if (_cairo_surface_check_span_renderer (op,pattern,&dst->base, antialias)) { - status = - _cairo_surface_composite_trapezoids_as_polygon (&dst->base, - op, pattern, - antialias, - src_x, src_y, - dst_x, dst_y, - width, height, - traps, num_traps, - clip_region); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; - } - status = _cairo_gl_get_traps_pattern (dst, dst_x, dst_y, width, height, traps, num_traps, antialias, @@ -1805,356 +1091,77 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op, _cairo_pattern_fini (&traps_pattern.base); + assert (status != CAIRO_INT_STATUS_UNSUPPORTED); return status; } static cairo_int_status_t -_cairo_gl_surface_fill_rectangles_fixed (void *abstract_surface, - cairo_operator_t op, - const cairo_color_t *color, - cairo_rectangle_int_t *rects, - int num_rects) -{ -#define N_STACK_RECTS 4 - cairo_gl_surface_t *surface = abstract_surface; - GLfloat vertices_stack[N_STACK_RECTS*4*2]; - GLfloat colors_stack[N_STACK_RECTS*4*4]; - cairo_gl_context_t *ctx; - int i; - GLfloat *vertices; - GLfloat *colors; - - if (! _cairo_gl_operator_is_supported (op)) - return UNSUPPORTED ("unsupported operator"); - - ctx = _cairo_gl_context_acquire (surface->ctx); - - _cairo_gl_set_destination (surface); - _cairo_gl_set_operator (surface, op, FALSE); - - if (num_rects > N_STACK_RECTS) { - vertices = _cairo_malloc_ab (num_rects, sizeof (GLfloat) * 4 * 2); - colors = _cairo_malloc_ab (num_rects, sizeof (GLfloat) * 4 * 4); - if (!vertices || !colors) { - _cairo_gl_context_release (ctx); - free (vertices); - free (colors); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - } else { - vertices = vertices_stack; - colors = colors_stack; - } - - /* This should be loaded in as either a blend constant and an operator - * setup specific to this, or better, a fragment shader constant. - */ - colors[0] = color->red * color->alpha; - colors[1] = color->green * color->alpha; - colors[2] = color->blue * color->alpha; - colors[3] = color->alpha; - for (i = 1; i < num_rects * 4; i++) { - colors[i*4 + 0] = colors[0]; - colors[i*4 + 1] = colors[1]; - colors[i*4 + 2] = colors[2]; - colors[i*4 + 3] = colors[3]; - } - - for (i = 0; i < num_rects; i++) { - vertices[i * 8 + 0] = rects[i].x; - vertices[i * 8 + 1] = rects[i].y; - vertices[i * 8 + 2] = rects[i].x + rects[i].width; - vertices[i * 8 + 3] = rects[i].y; - vertices[i * 8 + 4] = rects[i].x + rects[i].width; - vertices[i * 8 + 5] = rects[i].y + rects[i].height; - vertices[i * 8 + 6] = rects[i].x; - vertices[i * 8 + 7] = rects[i].y + rects[i].height; - } - - glVertexPointer (2, GL_FLOAT, sizeof (GLfloat)*2, vertices); - glEnableClientState (GL_VERTEX_ARRAY); - glColorPointer (4, GL_FLOAT, sizeof (GLfloat)*4, colors); - glEnableClientState (GL_COLOR_ARRAY); - - glDrawArrays (GL_QUADS, 0, 4 * num_rects); - - glDisableClientState (GL_COLOR_ARRAY); - glDisableClientState (GL_VERTEX_ARRAY); - glDisable (GL_BLEND); - - _cairo_gl_context_release (ctx); - if (vertices != vertices_stack) - free (vertices); - if (colors != colors_stack) - free (colors); - - return CAIRO_STATUS_SUCCESS; -#undef N_STACK_RECTS -} - -static cairo_int_status_t -_cairo_gl_surface_fill_rectangles_glsl (void *abstract_surface, - cairo_operator_t op, - const cairo_color_t *color, - cairo_rectangle_int_t *rects, - int num_rects) -{ -#define N_STACK_RECTS 4 - cairo_gl_surface_t *surface = abstract_surface; - GLfloat vertices_stack[N_STACK_RECTS*4*2]; - GLfloat gl_color[4]; - cairo_gl_context_t *ctx; - int i; - GLfloat *vertices; - static const char *fill_vs_source = - "void main()\n" - "{\n" - " gl_Position = ftransform();\n" - "}\n"; - static const char *fill_fs_source = - "uniform vec4 color;\n" - "void main()\n" - "{\n" - " gl_FragColor = color;\n" - "}\n"; - cairo_status_t status; - - if (! _cairo_gl_operator_is_supported (op)) - return UNSUPPORTED ("unsupported operator"); - - ctx = _cairo_gl_context_acquire (surface->ctx); - - if (ctx->fill_rectangles_shader == 0) { - status = _cairo_gl_load_glsl (&ctx->fill_rectangles_shader, - fill_vs_source, fill_fs_source); - if (_cairo_status_is_error (status)) - return status; - - ctx->fill_rectangles_color_uniform = - glGetUniformLocationARB (ctx->fill_rectangles_shader, "color"); - } - - if (num_rects > N_STACK_RECTS) { - vertices = _cairo_malloc_ab (num_rects, sizeof (GLfloat) * 4 * 2); - if (!vertices) { - _cairo_gl_context_release (ctx); - free (vertices); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - } else { - vertices = vertices_stack; - } - - glUseProgramObjectARB (ctx->fill_rectangles_shader); - - _cairo_gl_set_destination (surface); - _cairo_gl_set_operator (surface, op, FALSE); - - gl_color[0] = color->red * color->alpha; - gl_color[1] = color->green * color->alpha; - gl_color[2] = color->blue * color->alpha; - gl_color[3] = color->alpha; - glUniform4fvARB (ctx->fill_rectangles_color_uniform, 1, gl_color); - - for (i = 0; i < num_rects; i++) { - vertices[i * 8 + 0] = rects[i].x; - vertices[i * 8 + 1] = rects[i].y; - vertices[i * 8 + 2] = rects[i].x + rects[i].width; - vertices[i * 8 + 3] = rects[i].y; - vertices[i * 8 + 4] = rects[i].x + rects[i].width; - vertices[i * 8 + 5] = rects[i].y + rects[i].height; - vertices[i * 8 + 6] = rects[i].x; - vertices[i * 8 + 7] = rects[i].y + rects[i].height; - } - - glVertexPointer (2, GL_FLOAT, sizeof (GLfloat)*2, vertices); - glEnableClientState (GL_VERTEX_ARRAY); - - glDrawArrays (GL_QUADS, 0, 4 * num_rects); - - glDisableClientState (GL_VERTEX_ARRAY); - glDisable (GL_BLEND); - glUseProgramObjectARB (0); - - _cairo_gl_context_release (ctx); - if (vertices != vertices_stack) - free (vertices); - - return CAIRO_STATUS_SUCCESS; -#undef N_STACK_RECTS -} - - -static cairo_int_status_t -_cairo_gl_surface_fill_rectangles (void *abstract_surface, +_cairo_gl_surface_fill_rectangles (void *abstract_dst, cairo_operator_t op, const cairo_color_t *color, cairo_rectangle_int_t *rects, int num_rects) { - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader) { - return _cairo_gl_surface_fill_rectangles_glsl(abstract_surface, - op, - color, - rects, - num_rects); - } else { - return _cairo_gl_surface_fill_rectangles_fixed(abstract_surface, - op, - color, - rects, - num_rects); + cairo_gl_surface_t *dst = abstract_dst; + cairo_solid_pattern_t solid; + cairo_gl_context_t *ctx; + cairo_status_t status; + cairo_gl_composite_t setup; + int i; + + status = _cairo_gl_composite_init (&setup, op, dst, + FALSE, + /* XXX */ NULL); + if (unlikely (status)) + goto CLEANUP; + + _cairo_pattern_init_solid (&solid, color); + status = _cairo_gl_composite_set_source (&setup, &solid.base, + 0, 0, + 0, 0, + 0, 0); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_gl_composite_set_mask (&setup, NULL, + 0, 0, + 0, 0, + 0, 0); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_gl_composite_begin (&setup, &ctx); + if (unlikely (status)) + goto CLEANUP; + + for (i = 0; i < num_rects; i++) { + _cairo_gl_composite_emit_rect (ctx, + rects[i].x, + rects[i].y, + rects[i].x + rects[i].width, + rects[i].y + rects[i].height, + 0); } + + status = _cairo_gl_context_release (ctx, status); + + CLEANUP: + _cairo_gl_composite_fini (&setup); + + return status; } typedef struct _cairo_gl_surface_span_renderer { cairo_span_renderer_t base; - cairo_gl_composite_setup_t setup; + cairo_gl_composite_t setup; int xmin, xmax; + int ymin, ymax; - cairo_operator_t op; - cairo_antialias_t antialias; - - cairo_gl_surface_t *dst; - cairo_region_t *clip; - - GLuint vbo; - void *vbo_base; - unsigned int vbo_size; - unsigned int vbo_offset; - unsigned int vertex_size; + cairo_gl_context_t *ctx; } cairo_gl_surface_span_renderer_t; -static void -_cairo_gl_span_renderer_flush (cairo_gl_surface_span_renderer_t *renderer) -{ - int count; - - if (renderer->vbo_offset == 0) - return; - - glUnmapBufferARB (GL_ARRAY_BUFFER_ARB); - - count = renderer->vbo_offset / renderer->vertex_size; - renderer->vbo_offset = 0; - - if (renderer->clip) { - int i, num_rectangles = cairo_region_num_rectangles (renderer->clip); - - glEnable (GL_SCISSOR_TEST); - for (i = 0; i < num_rectangles; i++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (renderer->clip, i, &rect); - - glScissor (rect.x, rect.y, rect.width, rect.height); - glDrawArrays (GL_QUADS, 0, count); - } - glDisable (GL_SCISSOR_TEST); - } else { - glDrawArrays (GL_QUADS, 0, count); - } -} - -static void * -_cairo_gl_span_renderer_get_vbo (cairo_gl_surface_span_renderer_t *renderer, - unsigned int num_vertices) -{ - unsigned int offset; - - if (renderer->vbo == 0) { - renderer->vbo_size = 16384; - glGenBuffersARB (1, &renderer->vbo); - glBindBufferARB (GL_ARRAY_BUFFER_ARB, renderer->vbo); - - if (renderer->setup.src.type == OPERAND_TEXTURE) - renderer->vertex_size = 4 * sizeof (float) + sizeof (uint32_t); - else - renderer->vertex_size = 2 * sizeof (float) + sizeof (uint32_t); - - glVertexPointer (2, GL_FLOAT, renderer->vertex_size, 0); - glEnableClientState (GL_VERTEX_ARRAY); - - glColorPointer (4, GL_UNSIGNED_BYTE, renderer->vertex_size, - (void *) (uintptr_t) (2 * sizeof (float))); - glEnableClientState (GL_COLOR_ARRAY); - - if (renderer->setup.src.type == OPERAND_TEXTURE) { - glClientActiveTexture (GL_TEXTURE0); - glTexCoordPointer (2, GL_FLOAT, renderer->vertex_size, - (void *) (uintptr_t) (2 * sizeof (float) + - sizeof (uint32_t))); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); - } - } - - if (renderer->vbo_offset + num_vertices * renderer->vertex_size > - renderer->vbo_size) { - _cairo_gl_span_renderer_flush (renderer); - } - - if (renderer->vbo_offset == 0) { - /* We'll only be using these vertices once. */ - glBufferDataARB (GL_ARRAY_BUFFER_ARB, renderer->vbo_size, NULL, - GL_STREAM_DRAW_ARB); - renderer->vbo_base = glMapBufferARB (GL_ARRAY_BUFFER_ARB, - GL_WRITE_ONLY_ARB); - } - - offset = renderer->vbo_offset; - renderer->vbo_offset += num_vertices * renderer->vertex_size; - - return (char *) renderer->vbo_base + offset; -} - -static void -_cairo_gl_emit_span_vertex (cairo_gl_surface_span_renderer_t *renderer, - int dst_x, int dst_y, uint8_t alpha, - float *vertices) -{ - cairo_surface_attributes_t *src_attributes; - int v = 0; - - src_attributes = &renderer->setup.src.operand.texture.attributes; - - vertices[v++] = dst_x + BIAS; - vertices[v++] = dst_y + BIAS; - vertices[v++] = int_as_float (alpha << 24); - if (renderer->setup.src.type == OPERAND_TEXTURE) { - double s, t; - - s = dst_x + BIAS; - t = dst_y + BIAS; - cairo_matrix_transform_point (&src_attributes->matrix, &s, &t); - vertices[v++] = s; - vertices[v++] = t; - } -} - -static void -_cairo_gl_emit_span (cairo_gl_surface_span_renderer_t *renderer, - int x, int y1, int y2, - uint8_t alpha) -{ - float *vertices = _cairo_gl_span_renderer_get_vbo (renderer, 2); - - _cairo_gl_emit_span_vertex (renderer, x, y1, alpha, vertices); - _cairo_gl_emit_span_vertex (renderer, x, y2, alpha, - vertices + renderer->vertex_size / 4); -} - -static void -_cairo_gl_emit_rectangle (cairo_gl_surface_span_renderer_t *renderer, - int x1, int y1, - int x2, int y2, - int coverage) -{ - _cairo_gl_emit_span (renderer, x1, y1, y2, coverage); - _cairo_gl_emit_span (renderer, x2, y2, y1, coverage); -} - static cairo_status_t _cairo_gl_render_bounded_spans (void *abstract_renderer, int y, int height, @@ -2168,10 +1175,10 @@ _cairo_gl_render_bounded_spans (void *abstract_renderer, do { if (spans[0].coverage) { - _cairo_gl_emit_rectangle (renderer, - spans[0].x, y, - spans[1].x, y + height, - spans[0].coverage); + _cairo_gl_composite_emit_rect (renderer->ctx, + spans[0].x, y, + spans[1].x, y + height, + spans[0].coverage); } spans++; @@ -2188,39 +1195,69 @@ _cairo_gl_render_unbounded_spans (void *abstract_renderer, { cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; + if (y > renderer->ymin) { + _cairo_gl_composite_emit_rect (renderer->ctx, + renderer->xmin, renderer->ymin, + renderer->xmax, y, + 0); + } + if (num_spans == 0) { - _cairo_gl_emit_rectangle (renderer, - renderer->xmin, y, - renderer->xmax, y + height, - 0); - return CAIRO_STATUS_SUCCESS; - } - - if (spans[0].x != renderer->xmin) { - _cairo_gl_emit_rectangle (renderer, - renderer->xmin, y, - spans[0].x, y + height, - 0); - } - - do { - _cairo_gl_emit_rectangle (renderer, - spans[0].x, y, - spans[1].x, y + height, - spans[0].coverage); - spans++; - } while (--num_spans > 1); - - if (spans[0].x != renderer->xmax) { - _cairo_gl_emit_rectangle (renderer, - spans[0].x, y, - renderer->xmax, y + height, - 0); + _cairo_gl_composite_emit_rect (renderer->ctx, + renderer->xmin, y, + renderer->xmax, y + height, + 0); + } else { + if (spans[0].x != renderer->xmin) { + _cairo_gl_composite_emit_rect (renderer->ctx, + renderer->xmin, y, + spans[0].x, y + height, + 0); + } + + do { + _cairo_gl_composite_emit_rect (renderer->ctx, + spans[0].x, y, + spans[1].x, y + height, + spans[0].coverage); + spans++; + } while (--num_spans > 1); + + if (spans[0].x != renderer->xmax) { + _cairo_gl_composite_emit_rect (renderer->ctx, + spans[0].x, y, + renderer->xmax, y + height, + 0); + } } + renderer->ymin = y + height; return CAIRO_STATUS_SUCCESS; } +static cairo_status_t +_cairo_gl_finish_unbounded_spans (void *abstract_renderer) +{ + cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; + + if (renderer->ymax > renderer->ymin) { + _cairo_gl_composite_emit_rect (renderer->ctx, + renderer->xmin, renderer->ymin, + renderer->xmax, renderer->ymax, + 0); + } + + return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS); +} + +static cairo_status_t +_cairo_gl_finish_bounded_spans (void *abstract_renderer) +{ + cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; + + return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS); +} + static void _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer) { @@ -2229,49 +1266,20 @@ _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer) if (!renderer) return; - _cairo_gl_operand_destroy (&renderer->setup.src); - _cairo_gl_context_release (renderer->dst->ctx); + _cairo_gl_composite_fini (&renderer->setup); free (renderer); } -static cairo_status_t -_cairo_gl_surface_span_renderer_finish (void *abstract_renderer) -{ - cairo_gl_surface_span_renderer_t *renderer = abstract_renderer; - - _cairo_gl_span_renderer_flush (renderer); - - glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0); - glDeleteBuffersARB (1, &renderer->vbo); - glDisableClientState (GL_VERTEX_ARRAY); - glDisableClientState (GL_COLOR_ARRAY); - - glClientActiveTexture (GL_TEXTURE0); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - glActiveTexture (GL_TEXTURE0); - glDisable (GL_TEXTURE_2D); - - glActiveTexture (GL_TEXTURE1); - glDisable (GL_TEXTURE_2D); - - glDisable (GL_BLEND); - - return CAIRO_STATUS_SUCCESS; -} - static cairo_bool_t -_cairo_gl_surface_check_span_renderer (cairo_operator_t op, +_cairo_gl_surface_check_span_renderer (cairo_operator_t op, const cairo_pattern_t *pattern, - void *abstract_dst, - cairo_antialias_t antialias) + void *abstract_dst, + cairo_antialias_t antialias) { if (! _cairo_gl_operator_is_supported (op)) return FALSE; - if (! GLEW_ARB_vertex_buffer_object) - return FALSE; - return TRUE; (void) pattern; @@ -2290,65 +1298,53 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op, cairo_gl_surface_t *dst = abstract_dst; cairo_gl_surface_span_renderer_t *renderer; cairo_status_t status; - cairo_surface_attributes_t *src_attributes; - GLenum err; + const cairo_rectangle_int_t *extents; renderer = calloc (1, sizeof (*renderer)); if (unlikely (renderer == NULL)) return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY); renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy; - renderer->base.finish = _cairo_gl_surface_span_renderer_finish; - renderer->base.render_row = - _cairo_gl_surface_span_renderer_render_row; - renderer->op = op; - renderer->antialias = antialias; - renderer->dst = dst; - renderer->clip = clip_region; - - renderer->composite_rectangles = *rects; - - status = _cairo_gl_operand_init (&renderer->setup.src, src, dst, - rects->src.x, rects->src.y, - rects->dst.x, rects->dst.y, - width, height); - if (unlikely (status)) { - _cairo_gl_context_acquire (dst->ctx); - _cairo_gl_surface_span_renderer_destroy (renderer); - return _cairo_span_renderer_create_in_error (status); + if (rects->is_bounded) { + renderer->base.render_rows = _cairo_gl_render_bounded_spans; + renderer->base.finish = _cairo_gl_finish_bounded_spans; + extents = &rects->bounded; + } else { + renderer->base.render_rows = _cairo_gl_render_unbounded_spans; + renderer->base.finish = _cairo_gl_finish_unbounded_spans; + extents = &rects->unbounded; } + renderer->xmin = extents->x; + renderer->xmax = extents->x + extents->width; + renderer->ymin = extents->y; + renderer->ymax = extents->y + extents->height; - _cairo_gl_context_acquire (dst->ctx); - _cairo_gl_set_destination (dst); + status = _cairo_gl_composite_init (&renderer->setup, + op, dst, + FALSE, extents); + if (unlikely (status)) + goto FAIL; - src_attributes = &renderer->setup.src.operand.texture.attributes; + status = _cairo_gl_composite_set_source (&renderer->setup, src, + extents->x, extents->y, + extents->x, extents->y, + extents->width, extents->height); + if (unlikely (status)) + goto FAIL; - _cairo_gl_set_operator (dst, op, FALSE); - _cairo_gl_set_src_operand (dst->ctx, &renderer->setup); + _cairo_gl_composite_set_mask_spans (&renderer->setup); + _cairo_gl_composite_set_clip_region (&renderer->setup, clip_region); - /* Set up the mask to source from the incoming vertex color. */ - glActiveTexture (GL_TEXTURE1); - /* Have to have a dummy texture bound in order to use the combiner unit. */ - glBindTexture (GL_TEXTURE_2D, dst->ctx->dummy_tex); - glEnable (GL_TEXTURE_2D); - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); - - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PRIMARY_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); - - while ((err = glGetError ())) - fprintf (stderr, "GL error 0x%08x\n", (int) err); + status = _cairo_gl_composite_begin (&renderer->setup, &renderer->ctx); + if (unlikely (status)) + goto FAIL; return &renderer->base; + +FAIL: + _cairo_gl_composite_fini (&renderer->setup); + free (renderer); + return _cairo_span_renderer_create_in_error (status); } static cairo_bool_t @@ -2372,8 +1368,29 @@ _cairo_gl_surface_get_font_options (void *abstract_surface, _cairo_font_options_init_default (options); cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON); + _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON); } +static cairo_status_t +_cairo_gl_surface_flush (void *abstract_surface) +{ + cairo_gl_surface_t *surface = abstract_surface; + cairo_status_t status; + cairo_gl_context_t *ctx; + + status = _cairo_gl_context_acquire (surface->base.device, &ctx); + if (unlikely (status)) + return status; + + if ((ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE && + ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface) || + (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE && + ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface) || + (ctx->current_target == surface)) + _cairo_gl_composite_flush (ctx); + + return _cairo_gl_context_release (ctx, status); +} static cairo_int_status_t _cairo_gl_surface_paint (void *abstract_surface, @@ -2382,15 +1399,209 @@ _cairo_gl_surface_paint (void *abstract_surface, cairo_clip_t *clip) { /* simplify the common case of clearing the surface */ - if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) { - _cairo_gl_surface_clear (abstract_surface); - - return CAIRO_STATUS_SUCCESS; + if (clip == NULL) { + if (op == CAIRO_OPERATOR_CLEAR) + return _cairo_gl_surface_clear (abstract_surface, CAIRO_COLOR_TRANSPARENT); + else if (source->type == CAIRO_PATTERN_TYPE_SOLID && + (op == CAIRO_OPERATOR_SOURCE || + (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque_solid (source)))) { + return _cairo_gl_surface_clear (abstract_surface, + &((cairo_solid_pattern_t *) source)->color); + } } return CAIRO_INT_STATUS_UNSUPPORTED; } +static cairo_int_status_t +_cairo_gl_surface_polygon (cairo_gl_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *extents, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_region_t *clip_region = NULL; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + return CAIRO_STATUS_SUCCESS; + if (unlikely (_cairo_status_is_error (status))) + return status; + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + return UNSUPPORTED ("a clip surface would be required"); + } + + if (! _cairo_surface_check_span_renderer (op, src, &dst->base, antialias)) + return UNSUPPORTED ("no span renderer"); + + if (op == CAIRO_OPERATOR_SOURCE) + return UNSUPPORTED ("SOURCE compositing doesn't work in GL"); + if (op == CAIRO_OPERATOR_CLEAR) { + op = CAIRO_OPERATOR_DEST_OUT; + src = &_cairo_pattern_white.base; + } + + status = _cairo_surface_composite_polygon (&dst->base, + op, + src, + fill_rule, + antialias, + extents, + polygon, + clip_region); + return status; +} + +static cairo_int_status_t +_cairo_gl_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_gl_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; + cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; + int num_boxes = ARRAY_LENGTH (boxes_stack); + cairo_clip_t local_clip; + cairo_bool_t have_clip = FALSE; + cairo_polygon_t polygon; + cairo_status_t status; + + status = _cairo_composite_rectangles_init_for_stroke (&extents, + surface->width, + surface->height, + op, source, + path, style, ctm, + clip); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_extents (clip, &extents)) + clip = NULL; + + if (clip != NULL) { + clip = _cairo_clip_init_copy (&local_clip, clip); + have_clip = TRUE; + } + + status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); + if (unlikely (status)) { + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; + } + + _cairo_polygon_init (&polygon); + _cairo_polygon_limit (&polygon, clip_boxes, num_boxes); + + status = _cairo_path_fixed_stroke_to_polygon (path, + style, + ctm, ctm_inverse, + tolerance, + &polygon); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _cairo_gl_surface_polygon (surface, op, source, &polygon, + CAIRO_FILL_RULE_WINDING, antialias, + &extents, clip); + } + + _cairo_polygon_fini (&polygon); + + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; +} + +static cairo_int_status_t +_cairo_gl_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_gl_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; + cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; + cairo_clip_t local_clip; + cairo_bool_t have_clip = FALSE; + int num_boxes = ARRAY_LENGTH (boxes_stack); + cairo_polygon_t polygon; + cairo_status_t status; + + status = _cairo_composite_rectangles_init_for_fill (&extents, + surface->width, + surface->height, + op, source, path, + clip); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_extents (clip, &extents)) + clip = NULL; + +#if 0 + if (extents.is_bounded && clip != NULL) { + cairo_clip_path_t *clip_path; + + if (((clip_path = _clip_get_single_path (clip)) != NULL) && + _cairo_path_fixed_equal (&clip_path->path, path)) + { + clip = NULL; + } + } +#endif + + if (clip != NULL) { + clip = _cairo_clip_init_copy (&local_clip, clip); + have_clip = TRUE; + } + + status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); + if (unlikely (status)) { + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; + } + + _cairo_polygon_init (&polygon); + _cairo_polygon_limit (&polygon, clip_boxes, num_boxes); + + status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _cairo_gl_surface_polygon (surface, op, source, &polygon, + fill_rule, antialias, + &extents, clip); + } + + _cairo_polygon_fini (&polygon); + + if (clip_boxes != boxes_stack) + free (clip_boxes); + + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; +} + const cairo_surface_backend_t _cairo_gl_surface_backend = { CAIRO_SURFACE_TYPE_GL, _cairo_gl_surface_create_similar, @@ -2413,23 +1624,14 @@ const cairo_surface_backend_t _cairo_gl_surface_backend = { _cairo_gl_surface_get_extents, NULL, /* old_show_glyphs */ _cairo_gl_surface_get_font_options, - NULL, /* flush */ + _cairo_gl_surface_flush, NULL, /* mark_dirty_rectangle */ - NULL, /* scaled_font_fini */ + _cairo_gl_surface_scaled_font_fini, _cairo_gl_surface_scaled_glyph_fini, _cairo_gl_surface_paint, NULL, /* mask */ - NULL, /* stroke */ - NULL, /* fill */ + _cairo_gl_surface_stroke, + _cairo_gl_surface_fill, _cairo_gl_surface_show_glyphs, /* show_glyphs */ NULL /* snapshot */ }; - -/** Call glFinish(), used for accurate performance testing. */ -cairo_status_t -cairo_gl_surface_glfinish (cairo_surface_t *surface) -{ - glFinish (); - - return CAIRO_STATUS_SUCCESS; -} diff --git a/gfx/cairo/cairo/src/cairo-gl.h b/gfx/cairo/cairo/src/cairo-gl.h index 1b8f79554a15..131d1148bee2 100644 --- a/gfx/cairo/cairo/src/cairo-gl.h +++ b/gfx/cairo/cairo/src/cairo-gl.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -40,19 +40,16 @@ CAIRO_BEGIN_DECLS -typedef struct _cairo_gl_context cairo_gl_context_t; - -cairo_public cairo_gl_context_t * -cairo_gl_context_reference (cairo_gl_context_t *context); - -cairo_public void -cairo_gl_context_destroy (cairo_gl_context_t *context); - cairo_public cairo_surface_t * -cairo_gl_surface_create (cairo_gl_context_t *ctx, +cairo_gl_surface_create (cairo_device_t *device, cairo_content_t content, int width, int height); +cairo_public cairo_surface_t * +cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device, + cairo_content_t content, + unsigned int tex, + int width, int height); cairo_public void cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height); @@ -65,31 +62,52 @@ cairo_gl_surface_get_height (cairo_surface_t *abstract_surface); cairo_public void cairo_gl_surface_swapbuffers (cairo_surface_t *surface); -cairo_public cairo_status_t -cairo_gl_surface_glfinish (cairo_surface_t *surface); - #if CAIRO_HAS_GLX_FUNCTIONS #include -cairo_public cairo_gl_context_t * -cairo_glx_context_create (Display *dpy, GLXContext gl_ctx); +cairo_public cairo_device_t * +cairo_glx_device_create (Display *dpy, GLXContext gl_ctx); + +cairo_public Display * +cairo_glx_device_get_display (cairo_device_t *device); + +cairo_public GLXContext +cairo_glx_device_get_context (cairo_device_t *device); cairo_public cairo_surface_t * -cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx, +cairo_gl_surface_create_for_window (cairo_device_t *device, Window win, int width, int height); #endif -#if CAIRO_HAS_EAGLE_FUNCTIONS -#include +#if CAIRO_HAS_WGL_FUNCTIONS +#include -cairo_public cairo_gl_context_t * -cairo_eagle_context_create (EGLDisplay display, EGLContext context); +cairo_public cairo_device_t * +cairo_wgl_device_create (HGLRC rc); + +cairo_public HGLRC +cairo_wgl_device_get_context (cairo_device_t *device); cairo_public cairo_surface_t * -cairo_gl_surface_create_for_eagle (cairo_gl_context_t *ctx, - EGLSurface surface, - int width, int height); +cairo_gl_surface_create_for_dc (cairo_device_t *device, + HDC dc, + int width, + int height); +#endif + +#if CAIRO_HAS_EGL_FUNCTIONS +#include + +cairo_public cairo_device_t * +cairo_egl_device_create (EGLDisplay dpy, EGLContext egl); + +cairo_public cairo_surface_t * +cairo_gl_surface_create_for_egl (cairo_device_t *device, + EGLSurface egl, + int width, + int height); + #endif CAIRO_END_DECLS diff --git a/gfx/cairo/cairo/src/cairo-glx-context.c b/gfx/cairo/cairo/src/cairo-glx-context.c index b442a1fc5ed1..fa9d8be962e6 100644 --- a/gfx/cairo/cairo/src/cairo-glx-context.c +++ b/gfx/cairo/cairo/src/cairo-glx-context.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -40,6 +40,8 @@ #include "cairo-gl-private.h" +#include "cairo-error-private.h" + #include /* XXX needs hooking into XCloseDisplay() */ @@ -59,8 +61,24 @@ typedef struct _cairo_glx_surface { } cairo_glx_surface_t; static void -_glx_make_current (void *abstract_ctx, - cairo_gl_surface_t *abstract_surface) +_glx_acquire (void *abstract_ctx) +{ + cairo_glx_context_t *ctx = abstract_ctx; + GLXDrawable current_drawable; + + if (ctx->base.current_target == NULL || + _cairo_gl_surface_is_texture (ctx->base.current_target)) { + current_drawable = ctx->dummy_window; + } else { + cairo_glx_surface_t *surface = (cairo_glx_surface_t *) ctx->base.current_target; + current_drawable = surface->win; + } + + glXMakeCurrent (ctx->display, current_drawable, ctx->context); +} + +static void +_glx_make_current (void *abstract_ctx, cairo_gl_surface_t *abstract_surface) { cairo_glx_context_t *ctx = abstract_ctx; cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface; @@ -69,6 +87,14 @@ _glx_make_current (void *abstract_ctx, glXMakeCurrent (ctx->display, surface->win, ctx->context); } +static void +_glx_release (void *abstract_ctx) +{ + cairo_glx_context_t *ctx = abstract_ctx; + + glXMakeCurrent (ctx->display, None, None); +} + static void _glx_swap_buffers (void *abstract_ctx, cairo_gl_surface_t *abstract_surface) @@ -86,6 +112,8 @@ _glx_destroy (void *abstract_ctx) if (ctx->dummy_window != None) XDestroyWindow (ctx->display, ctx->dummy_window); + + glXMakeCurrent (ctx->display, 0, 0); } static cairo_status_t @@ -140,8 +168,8 @@ _glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy) return CAIRO_STATUS_SUCCESS; } -cairo_gl_context_t * -cairo_glx_context_create (Display *dpy, GLXContext gl_ctx) +cairo_device_t * +cairo_glx_device_create (Display *dpy, GLXContext gl_ctx) { cairo_glx_context_t *ctx; cairo_status_t status; @@ -159,6 +187,8 @@ cairo_glx_context_create (Display *dpy, GLXContext gl_ctx) ctx->dummy_window = dummy; ctx->context = gl_ctx; + ctx->base.acquire = _glx_acquire; + ctx->base.release = _glx_release; ctx->base.make_current = _glx_make_current; ctx->base.swap_buffers = _glx_swap_buffers; ctx->base.destroy = _glx_destroy; @@ -169,25 +199,60 @@ cairo_glx_context_create (Display *dpy, GLXContext gl_ctx) return _cairo_gl_context_create_in_error (status); } - return &ctx->base; + ctx->base.release (ctx); + + return &ctx->base.base; +} + +Display * +cairo_glx_device_get_display (cairo_device_t *device) +{ + cairo_glx_context_t *ctx; + + if (device->backend->type != CAIRO_DEVICE_TYPE_GL) { + _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + return NULL; + } + + ctx = (cairo_glx_context_t *) device; + + return ctx->display; +} + +GLXContext +cairo_glx_device_get_context (cairo_device_t *device) +{ + cairo_glx_context_t *ctx; + + if (device->backend->type != CAIRO_DEVICE_TYPE_GL) { + _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + return NULL; + } + + ctx = (cairo_glx_context_t *) device; + + return ctx->context; } cairo_surface_t * -cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx, - Window win, - int width, - int height) +cairo_gl_surface_create_for_window (cairo_device_t *device, + Window win, + int width, + int height) { cairo_glx_surface_t *surface; - if (unlikely (ctx->status)) - return _cairo_surface_create_in_error (ctx->status); + if (unlikely (device->status)) + return _cairo_surface_create_in_error (device->status); + + if (device->backend->type != CAIRO_DEVICE_TYPE_GL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); surface = calloc (1, sizeof (cairo_glx_surface_t)); if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - _cairo_gl_surface_init (ctx, &surface->base, + _cairo_gl_surface_init (device, &surface->base, CAIRO_CONTENT_COLOR_ALPHA, width, height); surface->win = win; diff --git a/gfx/cairo/cairo/src/cairo-gstate-private.h b/gfx/cairo/cairo/src/cairo-gstate-private.h index cb278e806e33..b41c7a296c31 100644 --- a/gfx/cairo/cairo/src/cairo-gstate-private.h +++ b/gfx/cairo/cairo/src/cairo-gstate-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -60,13 +60,326 @@ struct _cairo_gstate { cairo_surface_t *parent_target; /* The previous target which was receiving rendering */ cairo_surface_t *original_target; /* The original target the initial gstate was created with */ + /* the user is allowed to update the device after we have cached the matrices... */ + cairo_observer_t device_transform_observer; + cairo_matrix_t ctm; cairo_matrix_t ctm_inverse; cairo_matrix_t source_ctm_inverse; /* At the time ->source was set */ + cairo_bool_t is_identity; cairo_pattern_t *source; struct _cairo_gstate *next; }; +/* cairo-gstate.c */ +cairo_private cairo_status_t +_cairo_gstate_init (cairo_gstate_t *gstate, + cairo_surface_t *target); + +cairo_private void +_cairo_gstate_fini (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist); + +cairo_private cairo_status_t +_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist); + +cairo_private cairo_bool_t +_cairo_gstate_is_redirected (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child); + +cairo_private cairo_surface_t * +_cairo_gstate_get_target (cairo_gstate_t *gstate); + +cairo_private cairo_surface_t * +_cairo_gstate_get_parent_target (cairo_gstate_t *gstate); + +cairo_private cairo_surface_t * +_cairo_gstate_get_original_target (cairo_gstate_t *gstate); + +cairo_private cairo_clip_t * +_cairo_gstate_get_clip (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_t *source); + +cairo_private cairo_pattern_t * +_cairo_gstate_get_source (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op); + +cairo_private cairo_operator_t +_cairo_gstate_get_operator (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance); + +cairo_private double +_cairo_gstate_get_tolerance (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule); + +cairo_private cairo_fill_rule_t +_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width); + +cairo_private double +_cairo_gstate_get_line_width (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap); + +cairo_private cairo_line_cap_t +_cairo_gstate_get_line_cap (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join); + +cairo_private cairo_line_join_t +_cairo_gstate_get_line_join (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset); + +cairo_private void +_cairo_gstate_get_dash (cairo_gstate_t *gstate, double *dash, int *num_dashes, double *offset); + +cairo_private cairo_status_t +_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit); + +cairo_private double +_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate); + +cairo_private void +_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix); + +cairo_private cairo_status_t +_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty); + +cairo_private cairo_status_t +_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy); + +cairo_private cairo_status_t +_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle); + +cairo_private cairo_status_t +_cairo_gstate_transform (cairo_gstate_t *gstate, + const cairo_matrix_t *matrix); + +cairo_private cairo_status_t +_cairo_gstate_set_matrix (cairo_gstate_t *gstate, + const cairo_matrix_t *matrix); + +cairo_private void +_cairo_gstate_identity_matrix (cairo_gstate_t *gstate); + +cairo_private void +_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y); + +cairo_private void +_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, double *dx, double *dy); + +cairo_private void +_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y); + +cairo_private void +_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, double *dx, double *dy); + +cairo_private void +_do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y); + +static inline void +_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y) +{ + if (! gstate->is_identity) + _do_cairo_gstate_user_to_backend (gstate, x, y); +} + +cairo_private void +_do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y); + +static inline void +_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y) +{ + if (! gstate->is_identity) + _do_cairo_gstate_backend_to_user (gstate, x, y); +} + +cairo_private void +_cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2, + cairo_bool_t *is_tight); + +cairo_private void +_cairo_gstate_path_extents (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double *x1, double *y1, + double *x2, double *y2); + +cairo_private cairo_status_t +_cairo_gstate_paint (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_mask (cairo_gstate_t *gstate, + cairo_pattern_t *mask); + +cairo_private cairo_status_t +_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_gstate_copy_page (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_show_page (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_stroke_extents (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double *x1, double *y1, + double *x2, double *y2); + +cairo_private cairo_status_t +_cairo_gstate_fill_extents (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double *x1, double *y1, + double *x2, double *y2); + +cairo_private cairo_status_t +_cairo_gstate_in_stroke (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double x, + double y, + cairo_bool_t *inside_ret); + +cairo_private cairo_bool_t +_cairo_gstate_in_fill (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double x, + double y); + +cairo_private cairo_bool_t +_cairo_gstate_in_clip (cairo_gstate_t *gstate, + double x, + double y); + +cairo_private cairo_status_t +_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_gstate_reset_clip (cairo_gstate_t *gstate); + +cairo_private cairo_bool_t +_cairo_gstate_clip_extents (cairo_gstate_t *gstate, + double *x1, + double *y1, + double *x2, + double *y2); + +cairo_private cairo_rectangle_list_t* +_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_show_surface (cairo_gstate_t *gstate, + cairo_surface_t *surface, + double x, + double y, + double width, + double height); + +cairo_private cairo_status_t +_cairo_gstate_select_font_face (cairo_gstate_t *gstate, + const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight); + +cairo_private cairo_status_t +_cairo_gstate_set_font_size (cairo_gstate_t *gstate, + double size); + +cairo_private void +_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate, + cairo_matrix_t *matrix); + +cairo_private cairo_status_t +_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate, + const cairo_matrix_t *matrix); + +cairo_private void +_cairo_gstate_get_font_options (cairo_gstate_t *gstate, + cairo_font_options_t *options); + +cairo_private void +_cairo_gstate_set_font_options (cairo_gstate_t *gstate, + const cairo_font_options_t *options); + +cairo_private cairo_status_t +_cairo_gstate_get_font_face (cairo_gstate_t *gstate, + cairo_font_face_t **font_face); + +cairo_private cairo_status_t +_cairo_gstate_get_scaled_font (cairo_gstate_t *gstate, + cairo_scaled_font_t **scaled_font); + +cairo_private cairo_status_t +_cairo_gstate_get_font_extents (cairo_gstate_t *gstate, + cairo_font_extents_t *extents); + +cairo_private cairo_status_t +_cairo_gstate_set_font_face (cairo_gstate_t *gstate, + cairo_font_face_t *font_face); + +cairo_private cairo_status_t +_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, + double x, + double y, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + int *num_glyphs, + cairo_text_cluster_t **clusters, + int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags); + +cairo_private cairo_status_t +_cairo_gstate_glyph_extents (cairo_gstate_t *gstate, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents); + +cairo_private cairo_status_t +_cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, + const char *utf8, + int utf8_len, + const cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags); + +cairo_private cairo_status_t +_cairo_gstate_glyph_path (cairo_gstate_t *gstate, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_gstate_set_antialias (cairo_gstate_t *gstate, + cairo_antialias_t antialias); + +cairo_private cairo_antialias_t +_cairo_gstate_get_antialias (cairo_gstate_t *gstate); + #endif /* CAIRO_GSTATE_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-gstate.c b/gfx/cairo/cairo/src/cairo-gstate.c index ddd6f0a52fe1..c04ac7cbe435 100644 --- a/gfx/cairo/cairo/src/cairo-gstate.c +++ b/gfx/cairo/cairo/src/cairo-gstate.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -35,11 +35,10 @@ * Carl D. Worth */ -#define _GNU_SOURCE - #include "cairoint.h" #include "cairo-clip-private.h" +#include "cairo-error-private.h" #include "cairo-gstate-private.h" #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE) @@ -71,6 +70,18 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, int *num_transformed_glyphs, cairo_text_cluster_t *transformed_clusters); +static void +_cairo_gstate_update_device_transform (cairo_observer_t *observer, + void *arg) +{ + cairo_gstate_t *gstate = cairo_container_of (observer, + cairo_gstate_t, + device_transform_observer); + + gstate->is_identity = (_cairo_matrix_is_identity (&gstate->ctm) && + _cairo_matrix_is_identity (&gstate->target->device_transform)); +} + cairo_status_t _cairo_gstate_init (cairo_gstate_t *gstate, cairo_surface_t *target) @@ -106,6 +117,11 @@ _cairo_gstate_init (cairo_gstate_t *gstate, gstate->parent_target = NULL; gstate->original_target = cairo_surface_reference (target); + gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform; + cairo_list_add (&gstate->device_transform_observer.link, + &gstate->target->device_transform_observers); + + gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform); cairo_matrix_init_identity (&gstate->ctm); gstate->ctm_inverse = gstate->ctm; gstate->source_ctm_inverse = gstate->ctm; @@ -115,10 +131,6 @@ _cairo_gstate_init (cairo_gstate_t *gstate, /* Now that the gstate is fully initialized and ready for the eventual * _cairo_gstate_fini(), we can check for errors (and not worry about * the resource deallocation). */ - - if (target == NULL) - return _cairo_error (CAIRO_STATUS_NULL_POINTER); - status = target->status; if (unlikely (status)) return status; @@ -171,6 +183,11 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) gstate->parent_target = NULL; gstate->original_target = cairo_surface_reference (other->original_target); + gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform; + cairo_list_add (&gstate->device_transform_observer.link, + &gstate->target->device_transform_observers); + + gstate->is_identity = other->is_identity; gstate->ctm = other->ctm; gstate->ctm_inverse = other->ctm_inverse; gstate->source_ctm_inverse = other->source_ctm_inverse; @@ -198,6 +215,8 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) _cairo_clip_reset (&gstate->clip); + cairo_list_del (&gstate->device_transform_observer.link); + cairo_surface_destroy (gstate->target); gstate->target = NULL; @@ -307,6 +326,9 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) /* Now set up our new target; we overwrite gstate->target directly, * since its ref is now owned by gstate->parent_target */ gstate->target = cairo_surface_reference (child); + gstate->is_identity &= _cairo_matrix_is_identity (&child->device_transform); + cairo_list_move (&gstate->device_transform_observer.link, + &gstate->target->device_transform_observers); /* The clip is in surface backend coordinates for the previous target; * translate it into the child's backend coordinates. */ @@ -413,8 +435,7 @@ _cairo_gstate_get_source (cairo_gstate_t *gstate) { if (gstate->source == &_cairo_pattern_black.base) { /* do not expose the static object to the user */ - gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK, - CAIRO_CONTENT_COLOR); + gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK); } return gstate->source; @@ -533,6 +554,7 @@ _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dash for (i = 0; i < gstate->stroke_style.num_dashes; i++) { if (gstate->stroke_style.dash[i] < 0) return _cairo_error (CAIRO_STATUS_INVALID_DASH); + dash_total += gstate->stroke_style.dash[i]; } @@ -563,10 +585,11 @@ _cairo_gstate_get_dash (cairo_gstate_t *gstate, int *num_dashes, double *offset) { - if (dashes) + if (dashes) { memcpy (dashes, gstate->stroke_style.dash, sizeof (double) * gstate->stroke_style.num_dashes); + } if (num_dashes) *num_dashes = gstate->stroke_style.num_dashes; @@ -607,6 +630,7 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty) cairo_matrix_init_translate (&tmp, tx, ty); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + gstate->is_identity = FALSE; /* paranoid check against gradual numerical instability */ if (! _cairo_matrix_is_invertible (&gstate->ctm)) @@ -632,6 +656,7 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy) cairo_matrix_init_scale (&tmp, sx, sy); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + gstate->is_identity = FALSE; /* paranoid check against gradual numerical instability */ if (! _cairo_matrix_is_invertible (&gstate->ctm)) @@ -658,6 +683,7 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle) cairo_matrix_init_rotate (&tmp, angle); cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + gstate->is_identity = FALSE; /* paranoid check against gradual numerical instability */ if (! _cairo_matrix_is_invertible (&gstate->ctm)) @@ -676,6 +702,9 @@ _cairo_gstate_transform (cairo_gstate_t *gstate, cairo_matrix_t tmp; cairo_status_t status; + if (! _cairo_matrix_is_invertible (matrix)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + if (_cairo_matrix_is_identity (matrix)) return CAIRO_STATUS_SUCCESS; @@ -688,6 +717,7 @@ _cairo_gstate_transform (cairo_gstate_t *gstate, cairo_matrix_multiply (&gstate->ctm, matrix, &gstate->ctm); cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + gstate->is_identity = FALSE; /* paranoid check against gradual numerical instability */ if (! _cairo_matrix_is_invertible (&gstate->ctm)) @@ -708,12 +738,18 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate, if (! _cairo_matrix_is_invertible (matrix)) return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + if (_cairo_matrix_is_identity (matrix)) { + _cairo_gstate_identity_matrix (gstate); + return CAIRO_STATUS_SUCCESS; + } + _cairo_gstate_unset_scaled_font (gstate); gstate->ctm = *matrix; gstate->ctm_inverse = *matrix; status = cairo_matrix_invert (&gstate->ctm_inverse); assert (status == CAIRO_STATUS_SUCCESS); + gstate->is_identity = FALSE; return CAIRO_STATUS_SUCCESS; } @@ -728,6 +764,7 @@ _cairo_gstate_identity_matrix (cairo_gstate_t *gstate) cairo_matrix_init_identity (&gstate->ctm); cairo_matrix_init_identity (&gstate->ctm_inverse); + gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform); } void @@ -757,14 +794,14 @@ _cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, } void -_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y) +_do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y) { cairo_matrix_transform_point (&gstate->ctm, x, y); cairo_matrix_transform_point (&gstate->target->device_transform, x, y); } void -_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y) +_do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y) { cairo_matrix_transform_point (&gstate->target->device_transform_inverse, x, y); cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); @@ -802,14 +839,25 @@ _cairo_gstate_path_extents (cairo_gstate_t *gstate, double *x1, double *y1, double *x2, double *y2) { + cairo_box_t box; double px1, py1, px2, py2; - _cairo_path_fixed_bounds (path, - &px1, &py1, &px2, &py2); + if (_cairo_path_fixed_extents (path, &box)) { + px1 = _cairo_fixed_to_double (box.p1.x); + py1 = _cairo_fixed_to_double (box.p1.y); + px2 = _cairo_fixed_to_double (box.p2.x); + py2 = _cairo_fixed_to_double (box.p2.y); + + _cairo_gstate_backend_to_user_rectangle (gstate, + &px1, &py1, &px2, &py2, + NULL); + } else { + px1 = 0.0; + py1 = 0.0; + px2 = 0.0; + py2 = 0.0; + } - _cairo_gstate_backend_to_user_rectangle (gstate, - &px1, &py1, &px2, &py2, - NULL); if (x1) *x1 = px1; if (y1) @@ -820,70 +868,32 @@ _cairo_gstate_path_extents (cairo_gstate_t *gstate, *y2 = py2; } -static void -_init_solid_for_color_stop (cairo_solid_pattern_t *solid, - const cairo_color_t *color) -{ - cairo_color_t premult; - - /* Color stops aren't premultiplied, so fix that here */ - _cairo_color_init_rgba (&premult, - color->red, - color->green, - color->blue, - color->alpha); - _cairo_pattern_init_solid (solid, &premult, CAIRO_CONTENT_COLOR_ALPHA); -} - static void _cairo_gstate_copy_pattern (cairo_pattern_t *pattern, const cairo_pattern_t *original) { /* First check if the we can replace the original with a much simpler * pattern. For example, gradients that are uniform or just have a single - * stop can be replace with a solid. + * stop can sometimes be replaced with a solid. */ - switch (original->type) { - case CAIRO_PATTERN_TYPE_SOLID: - case CAIRO_PATTERN_TYPE_SURFACE: - break; - case CAIRO_PATTERN_TYPE_LINEAR: - case CAIRO_PATTERN_TYPE_RADIAL: + if (_cairo_pattern_is_clear (original)) { + _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern, + CAIRO_COLOR_TRANSPARENT); + return; + } + + if (original->type == CAIRO_PATTERN_TYPE_LINEAR || + original->type == CAIRO_PATTERN_TYPE_RADIAL) + { + cairo_color_t color; + if (_cairo_gradient_pattern_is_solid ((cairo_gradient_pattern_t *) original, + NULL, + &color)) { - cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) original; - - /* fast path for gradients with less than 2 color stops */ - if (src->n_stops < 2) { - if (src->n_stops) { - _init_solid_for_color_stop ((cairo_solid_pattern_t *) pattern, - &src->stops->color); - } else { - _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern, - CAIRO_COLOR_TRANSPARENT, - CAIRO_CONTENT_ALPHA); - } - - return; - } else { - unsigned int i; - - /* Is the gradient a uniform colour? - * Happens more often than you would believe. - */ - for (i = 1; i < src->n_stops; i++) { - if (! _cairo_color_equal (&src->stops[0].color, - &src->stops[i].color)) - { - break; - } - } - if (i == src->n_stops) { - _init_solid_for_color_stop ((cairo_solid_pattern_t *) pattern, - &src->stops->color); - return; - } - } + _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern, + &color); + return; } } @@ -913,9 +923,10 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate, if (! _cairo_matrix_is_identity (ctm_inverse)) _cairo_pattern_transform (pattern, ctm_inverse); - if (_cairo_surface_has_device_transform (gstate->target)) + if (_cairo_surface_has_device_transform (gstate->target)) { _cairo_pattern_transform (pattern, &gstate->target->device_transform_inverse); + } } static void @@ -970,24 +981,73 @@ _clipped (cairo_gstate_t *gstate) return _cairo_clip_get_region (&gstate->clip, NULL) == CAIRO_INT_STATUS_NOTHING_TO_DO; } +static cairo_operator_t +_reduce_op (cairo_gstate_t *gstate) +{ + cairo_operator_t op; + const cairo_pattern_t *pattern; + + op = gstate->op; + if (op != CAIRO_OPERATOR_SOURCE) + return op; + + pattern = gstate->source; + if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { + const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; + if (solid->color.alpha_short <= 0x00ff) { + op = CAIRO_OPERATOR_CLEAR; + } else if ((gstate->target->content & CAIRO_CONTENT_ALPHA) == 0) { + if ((solid->color.red_short | + solid->color.green_short | + solid->color.blue_short) <= 0x00ff) + { + op = CAIRO_OPERATOR_CLEAR; + } + } + } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern; + if (surface->surface->is_clear && + surface->surface->content & CAIRO_CONTENT_ALPHA) + { + op = CAIRO_OPERATOR_CLEAR; + } + } else { + const cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; + if (gradient->n_stops == 0) + op = CAIRO_OPERATOR_CLEAR; + } + + return op; +} + cairo_status_t _cairo_gstate_paint (cairo_gstate_t *gstate) { - cairo_pattern_union_t pattern; + cairo_pattern_union_t source_pattern; + const cairo_pattern_t *pattern; cairo_clip_t clip; cairo_status_t status; + cairo_operator_t op; if (unlikely (gstate->source->status)) return gstate->source->status; + if (gstate->op == CAIRO_OPERATOR_DEST) + return CAIRO_STATUS_SUCCESS; + if (_clipped (gstate)) return CAIRO_STATUS_SUCCESS; - _cairo_gstate_copy_transformed_source (gstate, &pattern.base); + op = _reduce_op (gstate); + if (op == CAIRO_OPERATOR_CLEAR) { + pattern = &_cairo_pattern_clear.base; + } else { + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + pattern = &source_pattern.base; + } status = _cairo_surface_paint (gstate->target, - gstate->op, - &pattern.base, + op, pattern, _gstate_get_clip (gstate, &clip)); _cairo_clip_fini (&clip); @@ -999,6 +1059,8 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, cairo_pattern_t *mask) { cairo_pattern_union_t source_pattern, mask_pattern; + const cairo_pattern_t *source; + cairo_operator_t op; cairo_clip_t clip; cairo_status_t status; @@ -1008,46 +1070,59 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, if (unlikely (gstate->source->status)) return gstate->source->status; + if (gstate->op == CAIRO_OPERATOR_DEST) + return CAIRO_STATUS_SUCCESS; + if (_clipped (gstate)) return CAIRO_STATUS_SUCCESS; - if (_cairo_pattern_is_opaque (mask)) + if (_cairo_pattern_is_opaque (mask, NULL)) return _cairo_gstate_paint (gstate); - _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + if (_cairo_pattern_is_clear (mask) && + _cairo_operator_bounded_by_mask (gstate->op)) + { + return CAIRO_STATUS_SUCCESS; + } + + op = _reduce_op (gstate); + if (op == CAIRO_OPERATOR_CLEAR) { + source = &_cairo_pattern_clear.base; + } else { + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + source = &source_pattern.base; + } _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask); - if (source_pattern.type == CAIRO_PATTERN_TYPE_SOLID && - mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID) + if (source->type == CAIRO_PATTERN_TYPE_SOLID && + mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID && + _cairo_operator_bounded_by_source (op)) { + const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; cairo_color_t combined; if (mask_pattern.base.has_component_alpha) { #define M(R, A, B, c) R.c = A.c * B.c - M(combined, source_pattern.solid.color, mask_pattern.solid.color, red); - M(combined, source_pattern.solid.color, mask_pattern.solid.color, green); - M(combined, source_pattern.solid.color, mask_pattern.solid.color, blue); - M(combined, source_pattern.solid.color, mask_pattern.solid.color, alpha); + M(combined, solid->color, mask_pattern.solid.color, red); + M(combined, solid->color, mask_pattern.solid.color, green); + M(combined, solid->color, mask_pattern.solid.color, blue); + M(combined, solid->color, mask_pattern.solid.color, alpha); #undef M } else { - combined = source_pattern.solid.color; + combined = solid->color; _cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha); } - _cairo_pattern_init_solid (&source_pattern.solid, &combined, - source_pattern.solid.content | - mask_pattern.solid.content); + _cairo_pattern_init_solid (&source_pattern.solid, &combined); - status = _cairo_surface_paint (gstate->target, - gstate->op, + status = _cairo_surface_paint (gstate->target, op, &source_pattern.base, _gstate_get_clip (gstate, &clip)); } else { - status = _cairo_surface_mask (gstate->target, - gstate->op, - &source_pattern.base, + status = _cairo_surface_mask (gstate->target, op, + source, &mask_pattern.base, _gstate_get_clip (gstate, &clip)); } @@ -1060,25 +1135,39 @@ cairo_status_t _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { cairo_pattern_union_t source_pattern; + cairo_stroke_style_t style; + double dash[2]; cairo_clip_t clip; cairo_status_t status; if (unlikely (gstate->source->status)) return gstate->source->status; + if (gstate->op == CAIRO_OPERATOR_DEST) + return CAIRO_STATUS_SUCCESS; + if (gstate->stroke_style.line_width <= 0.0) return CAIRO_STATUS_SUCCESS; if (_clipped (gstate)) return CAIRO_STATUS_SUCCESS; + memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style)); + if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance)) { + style.dash = dash; + _cairo_stroke_style_dash_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance, + &style.dash_offset, + style.dash, + &style.num_dashes); + } + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); status = _cairo_surface_stroke (gstate->target, gstate->op, &source_pattern.base, path, - &gstate->stroke_style, + &style, &gstate->ctm, &gstate->ctm_inverse, gstate->tolerance, @@ -1150,13 +1239,15 @@ BAIL: cairo_status_t _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { - cairo_pattern_union_t pattern; cairo_clip_t clip; cairo_status_t status; if (unlikely (gstate->source->status)) return gstate->source->status; + if (gstate->op == CAIRO_OPERATOR_DEST) + return CAIRO_STATUS_SUCCESS; + if (_clipped (gstate)) return CAIRO_STATUS_SUCCESS; @@ -1164,24 +1255,45 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) if (_cairo_operator_bounded_by_mask (gstate->op)) return CAIRO_STATUS_SUCCESS; - _cairo_pattern_init_solid (&pattern.solid, - CAIRO_COLOR_TRANSPARENT, - CAIRO_CONTENT_COLOR_ALPHA); status = _cairo_surface_paint (gstate->target, CAIRO_OPERATOR_CLEAR, - &pattern.base, + &_cairo_pattern_clear.base, _gstate_get_clip (gstate, &clip)); } else { - _cairo_gstate_copy_transformed_source (gstate, &pattern.base); + cairo_pattern_union_t source_pattern; + const cairo_pattern_t *pattern; + cairo_operator_t op; + cairo_rectangle_int_t extents; + cairo_box_t box; - status = _cairo_surface_fill (gstate->target, - gstate->op, - &pattern.base, - path, - gstate->fill_rule, - gstate->tolerance, - gstate->antialias, - _gstate_get_clip (gstate, &clip)); + op = _reduce_op (gstate); + if (op == CAIRO_OPERATOR_CLEAR) { + pattern = &_cairo_pattern_clear.base; + } else { + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + pattern = &source_pattern.base; + } + + /* Toolkits often paint the entire background with a fill */ + if (_cairo_surface_get_extents (gstate->target, &extents) && + _cairo_path_fixed_is_box (path, &box) && + box.p1.x <= _cairo_fixed_from_int (extents.x) && + box.p1.y <= _cairo_fixed_from_int (extents.y) && + box.p2.x >= _cairo_fixed_from_int (extents.x + extents.width) && + box.p2.y >= _cairo_fixed_from_int (extents.y + extents.height)) + { + status = _cairo_surface_paint (gstate->target, op, pattern, + _gstate_get_clip (gstate, &clip)); + } + else + { + status = _cairo_surface_fill (gstate->target, op, pattern, + path, + gstate->fill_rule, + gstate->tolerance, + gstate->antialias, + _gstate_get_clip (gstate, &clip)); + } } _cairo_clip_fini (&clip); @@ -1793,16 +1905,21 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, cairo_text_cluster_flags_t cluster_flags) { cairo_pattern_union_t source_pattern; + const cairo_pattern_t *pattern; cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)]; cairo_glyph_t *transformed_glyphs; cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)]; cairo_text_cluster_t *transformed_clusters; + cairo_operator_t op; cairo_status_t status; cairo_clip_t clip; if (unlikely (gstate->source->status)) return gstate->source->status; + if (gstate->op == CAIRO_OPERATOR_DEST) + return CAIRO_STATUS_SUCCESS; + if (_clipped (gstate)) return CAIRO_STATUS_SUCCESS; @@ -1845,7 +1962,13 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, if (status || num_glyphs == 0) goto CLEANUP_GLYPHS; - _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + op = _reduce_op (gstate); + if (op == CAIRO_OPERATOR_CLEAR) { + pattern = &_cairo_pattern_clear.base; + } else { + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + pattern = &source_pattern.base; + } _cairo_clip_init(&clip); /* For really huge font sizes, we can just do path;fill instead of @@ -1864,10 +1987,9 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, * Needless to say, do this only if show_text_glyphs is not available. */ if (cairo_surface_has_show_text_glyphs (gstate->target) || _cairo_scaled_font_get_max_scale (gstate->scaled_font) <= - _cairo_surface_get_text_path_fill_threshold (gstate->target)) { - status = _cairo_surface_show_text_glyphs (gstate->target, - gstate->op, - &source_pattern.base, + _cairo_surface_get_text_path_fill_threshold (gstate->target)) + { + status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern, utf8, utf8_len, transformed_glyphs, num_glyphs, transformed_clusters, num_clusters, @@ -1886,9 +2008,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, &path); if (status == CAIRO_STATUS_SUCCESS) { - status = _cairo_surface_fill (gstate->target, - gstate->op, - &source_pattern.base, + status = _cairo_surface_fill (gstate->target, op, pattern, &path, CAIRO_FILL_RULE_WINDING, gstate->tolerance, @@ -2044,6 +2164,7 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, if (! drop) { memcpy (transformed_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t)); + j = num_glyphs; } else if (num_clusters == 0) { for (i = 0; i < num_glyphs; i++) { transformed_glyphs[j].index = glyphs[i].index; diff --git a/gfx/cairo/cairo/src/cairo-hash-private.h b/gfx/cairo/cairo/src/cairo-hash-private.h index 32078bd212ca..30e51ffe6691 100644 --- a/gfx/cairo/cairo/src/cairo-hash-private.h +++ b/gfx/cairo/cairo/src/cairo-hash-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-hash.c b/gfx/cairo/cairo/src/cairo-hash.c index 15159d928b34..81a48a235985 100644 --- a/gfx/cairo/cairo/src/cairo-hash.c +++ b/gfx/cairo/cairo/src/cairo-hash.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,6 +37,7 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" /* * An entry can be in one of three states: diff --git a/gfx/cairo/cairo/src/cairo-hull.c b/gfx/cairo/cairo/src/cairo-hull.c index 8a1a31e24e33..c65593327f67 100644 --- a/gfx/cairo/cairo/src/cairo-hull.c +++ b/gfx/cairo/cairo/src/cairo-hull.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -36,6 +36,7 @@ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-slope-private.h" typedef struct cairo_hull { @@ -94,6 +95,13 @@ _cairo_hull_vertex_compare (const void *av, const void *bv) cairo_hull_t *b = (cairo_hull_t *) bv; int ret; + /* Some libraries are reported to actually compare identical + * pointers and require the result to be 0. This is the crazy world we + * have to live in. + */ + if (a == b) + return 0; + ret = _cairo_slope_compare (&a->slope, &b->slope); /* diff --git a/gfx/cairo/cairo/src/cairo-image-info-private.h b/gfx/cairo/cairo/src/cairo-image-info-private.h index 6e1c4ad751c8..0d9ef84985f3 100644 --- a/gfx/cairo/cairo/src/cairo-image-info-private.h +++ b/gfx/cairo/cairo/src/cairo-image-info-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -53,11 +53,11 @@ _cairo_image_info_get_jpeg_info (cairo_image_info_t *info, cairo_private cairo_int_status_t _cairo_image_info_get_jpx_info (cairo_image_info_t *info, const unsigned char *data, - long length); + unsigned long length); cairo_private cairo_int_status_t -_cairo_image_info_get_png_info (cairo_image_info_t *info, +_cairo_image_info_get_png_info (cairo_image_info_t *info, const unsigned char *data, - long length); + unsigned long length); #endif /* CAIRO_IMAGE_INFO_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-image-info.c b/gfx/cairo/cairo/src/cairo-image-info.c index 8fc770550ec6..63201e65beeb 100644 --- a/gfx/cairo/cairo/src/cairo-image-info.c +++ b/gfx/cairo/cairo/src/cairo-image-info.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -214,7 +214,7 @@ _jpx_extract_info (const unsigned char *p, cairo_image_info_t *info) cairo_int_status_t _cairo_image_info_get_jpx_info (cairo_image_info_t *info, const unsigned char *data, - long length) + unsigned long length) { const unsigned char *p = data; const unsigned char *end = data + length; @@ -262,7 +262,7 @@ static const unsigned char _png_magic[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; cairo_int_status_t _cairo_image_info_get_png_info (cairo_image_info_t *info, const unsigned char *data, - long length) + unsigned long length) { const unsigned char *p = data; const unsigned char *end = data + length; diff --git a/gfx/cairo/cairo/src/cairo-image-surface.c b/gfx/cairo/cairo/src/cairo-image-surface.c index 1ca25b0b7228..10c302e680ad 100644 --- a/gfx/cairo/cairo/src/cairo-image-surface.c +++ b/gfx/cairo/cairo/src/cairo-image-surface.c @@ -2,6 +2,7 @@ /* cairo - a vector graphics library with display and print output * * Copyright © 2003 University of Southern California + * Copyright © 2009,2010 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -13,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -33,17 +34,59 @@ * * Contributor(s): * Carl D. Worth + * Chris Wilson */ #include "cairoint.h" +#include "cairo-boxes-private.h" #include "cairo-clip-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-error-private.h" #include "cairo-region-private.h" +#include "cairo-scaled-font-private.h" +#include "cairo-surface-snapshot-private.h" +#include "cairo-surface-subsurface-private.h" /* Limit on the width / height of an image surface in pixels. This is * mainly determined by coordinates of things sent to pixman at the * moment being in 16.16 format. */ #define MAX_IMAGE_SIZE 32767 +#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ + +/** + * SECTION:cairo-image + * @Title: Image Surfaces + * @Short_Description: Rendering to memory buffers + * @See_Also: #cairo_surface_t + * + * Image surfaces provide the ability to render to memory buffers + * either allocated by cairo or by the calling code. The supported + * image formats are those defined in #cairo_format_t. + */ + +/** + * CAIRO_HAS_IMAGE_SURFACE: + * + * Defined if the image surface backend is available. + * The image surface backend is always built in. + * This macro was added for completeness in cairo 1.8. + * + * @Since: 1.8 + */ + +static cairo_int_status_t +_cairo_image_surface_fill (void *dst, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip); + +static pixman_image_t * +_pixman_image_for_solid (const cairo_solid_pattern_t *pattern); static cairo_bool_t _cairo_image_surface_is_size_valid (int width, int height) @@ -52,7 +95,7 @@ _cairo_image_surface_is_size_valid (int width, int height) 0 <= height && height <= MAX_IMAGE_SIZE; } -static cairo_format_t +cairo_format_t _cairo_format_from_pixman_format (pixman_format_code_t pixman_format) { switch (pixman_format) { @@ -77,18 +120,12 @@ _cairo_format_from_pixman_format (pixman_format_code_t pixman_format) case PIXMAN_a1r1g1b1: case PIXMAN_a1b1g1r1: case PIXMAN_c4: case PIXMAN_g4: case PIXMAN_g1: case PIXMAN_yuy2: case PIXMAN_yv12: -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9) - case PIXMAN_x2b10g10r10: - case PIXMAN_a2b10g10r10: -#endif -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1) case PIXMAN_b8g8r8x8: case PIXMAN_b8g8r8a8: -#endif -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16) + case PIXMAN_x2b10g10r10: + case PIXMAN_a2b10g10r10: case PIXMAN_x2r10g10b10: case PIXMAN_a2r10g10b10: -#endif default: return CAIRO_FORMAT_INVALID; } @@ -96,69 +133,18 @@ _cairo_format_from_pixman_format (pixman_format_code_t pixman_format) return CAIRO_FORMAT_INVALID; } -static cairo_content_t +cairo_content_t _cairo_content_from_pixman_format (pixman_format_code_t pixman_format) { - switch (pixman_format) { - case PIXMAN_a8r8g8b8: - case PIXMAN_a8b8g8r8: - case PIXMAN_a1r5g5b5: - case PIXMAN_a1b5g5r5: - case PIXMAN_a4r4g4b4: - case PIXMAN_a4b4g4r4: - case PIXMAN_a2r2g2b2: - case PIXMAN_a2b2g2r2: - case PIXMAN_a1r1g1b1: - case PIXMAN_a1b1g1r1: -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9) - case PIXMAN_a2b10g10r10: -#endif -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1) - case PIXMAN_b8g8r8a8: -#endif -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16) - case PIXMAN_a2r10g10b10: -#endif - return CAIRO_CONTENT_COLOR_ALPHA; - case PIXMAN_x8r8g8b8: - case PIXMAN_x8b8g8r8: - case PIXMAN_r8g8b8: - case PIXMAN_b8g8r8: - case PIXMAN_r5g6b5: - case PIXMAN_b5g6r5: - case PIXMAN_x1r5g5b5: - case PIXMAN_x1b5g5r5: - case PIXMAN_x4r4g4b4: - case PIXMAN_x4b4g4r4: - case PIXMAN_r3g3b2: - case PIXMAN_b2g3r3: - case PIXMAN_c8: - case PIXMAN_g8: - case PIXMAN_r1g2b1: - case PIXMAN_b1g2r1: - case PIXMAN_c4: - case PIXMAN_g4: - case PIXMAN_g1: - case PIXMAN_yuy2: - case PIXMAN_yv12: -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9) - case PIXMAN_x2b10g10r10: -#endif -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1) - case PIXMAN_b8g8r8x8: -#endif -#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16) - case PIXMAN_x2r10g10b10: -#endif - return CAIRO_CONTENT_COLOR; - case PIXMAN_a8: - case PIXMAN_a1: - case PIXMAN_x4a4: - case PIXMAN_a4: - return CAIRO_CONTENT_ALPHA; - } + cairo_content_t content; - return CAIRO_CONTENT_COLOR_ALPHA; + content = 0; + if (PIXMAN_FORMAT_RGB (pixman_format)) + content |= CAIRO_CONTENT_COLOR; + if (PIXMAN_FORMAT_A (pixman_format)) + content |= CAIRO_CONTENT_ALPHA; + + return content; } cairo_surface_t * @@ -169,22 +155,20 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, int width = pixman_image_get_width (pixman_image); int height = pixman_image_get_height (pixman_image); - if (! _cairo_image_surface_is_size_valid (width, height)) { - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); - } - surface = malloc (sizeof (cairo_image_surface_t)); if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - _cairo_surface_init (&surface->base, &_cairo_image_surface_backend, + _cairo_surface_init (&surface->base, + &_cairo_image_surface_backend, + NULL, /* device */ _cairo_content_from_pixman_format (pixman_format)); surface->pixman_image = pixman_image; surface->pixman_format = pixman_format; surface->format = _cairo_format_from_pixman_format (pixman_format); - surface->data = (unsigned char *) pixman_image_get_data (pixman_image); + surface->data = (uint8_t *) pixman_image_get_data (pixman_image); surface->owns_data = FALSE; surface->transparency = CAIRO_IMAGE_UNKNOWN; @@ -193,8 +177,6 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, surface->stride = pixman_image_get_stride (pixman_image); surface->depth = pixman_image_get_depth (pixman_image); - surface->clip_region = NULL; - return &surface->base; } @@ -303,47 +285,7 @@ _pixman_format_to_masks (pixman_format_code_t format, } } -/* XXX: This function really should be eliminated. We don't really - * want to advertise a cairo image surface that supports any possible - * format. A minimal step would be to replace this function with one - * that accepts a #cairo_internal_format_t rather than mask values. */ -cairo_surface_t * -_cairo_image_surface_create_with_masks (unsigned char *data, - cairo_format_masks_t *masks, - int width, - int height, - int stride) -{ - pixman_format_code_t pixman_format; - - if (! _pixman_format_from_masks (masks, &pixman_format)) { - fprintf (stderr, - "Error: Cairo %s does not yet support the requested image format:\n" - "\tDepth: %d\n" - "\tAlpha mask: 0x%08lx\n" - "\tRed mask: 0x%08lx\n" - "\tGreen mask: 0x%08lx\n" - "\tBlue mask: 0x%08lx\n" -#ifdef PACKAGE_BUGGREPORT - "Please file an enhancement request (quoting the above) at:\n" - PACKAGE_BUGREPORT"\n" -#endif - , - cairo_version_string (), - masks->bpp, masks->alpha_mask, - masks->red_mask, masks->green_mask, masks->blue_mask); - - ASSERT_NOT_REACHED; - } - - return _cairo_image_surface_create_with_pixman_format (data, - pixman_format, - width, - height, - stride); -} - -static pixman_format_code_t +pixman_format_code_t _cairo_format_to_pixman_format_code (cairo_format_t format) { pixman_format_code_t ret; @@ -361,6 +303,7 @@ _cairo_format_to_pixman_format_code (cairo_format_t format) ret = PIXMAN_r5g6b5; break; case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_INVALID: default: ret = PIXMAN_a8r8g8b8; break; @@ -443,9 +386,6 @@ _cairo_image_surface_create_with_content (cairo_content_t content, int width, int height) { - if (! CAIRO_CONTENT_VALID (content)) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); - return cairo_image_surface_create (_cairo_format_from_content (content), width, height); } @@ -555,6 +495,9 @@ cairo_image_surface_create_for_data (unsigned char *data, if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); + if (! _cairo_image_surface_is_size_valid (width, height)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + minstride = cairo_format_stride_for_width (format, width); if (stride < 0) { if (stride > -minstride) { @@ -574,21 +517,6 @@ cairo_image_surface_create_for_data (unsigned char *data, } slim_hidden_def (cairo_image_surface_create_for_data); -cairo_surface_t * -_cairo_image_surface_create_for_data_with_content (unsigned char *data, - cairo_content_t content, - int width, - int height, - int stride) -{ - if (! CAIRO_CONTENT_VALID (content)) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); - - return cairo_image_surface_create_for_data (data, - _cairo_format_from_content (content), - width, height, stride); -} - /** * cairo_image_surface_get_data: * @surface: a #cairo_image_surface_t @@ -725,7 +653,7 @@ _cairo_format_from_content (cairo_content_t content) } ASSERT_NOT_REACHED; - return CAIRO_FORMAT_ARGB32; + return CAIRO_FORMAT_INVALID; } cairo_content_t @@ -741,6 +669,8 @@ _cairo_content_from_format (cairo_format_t format) case CAIRO_FORMAT_A8: case CAIRO_FORMAT_A1: return CAIRO_CONTENT_ALPHA; + case CAIRO_FORMAT_INVALID: + break; } ASSERT_NOT_REACHED; @@ -761,6 +691,7 @@ _cairo_format_bits_per_pixel (cairo_format_t format) return 8; case CAIRO_FORMAT_A1: return 1; + case CAIRO_FORMAT_INVALID: default: ASSERT_NOT_REACHED; return 0; @@ -775,6 +706,9 @@ _cairo_image_surface_create_similar (void *abstract_other, { cairo_image_surface_t *other = abstract_other; + if (! _cairo_image_surface_is_size_valid (width, height)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + if (content == other->base.content) { return _cairo_image_surface_create_with_pixman_format (NULL, other->pixman_format, @@ -801,8 +735,6 @@ _cairo_image_surface_finish (void *abstract_surface) surface->data = NULL; } - cairo_region_destroy (surface->clip_region); - return CAIRO_STATUS_SUCCESS; } @@ -830,176 +762,6 @@ _cairo_image_surface_release_source_image (void *abstract_surf { } -static cairo_status_t -_cairo_image_surface_acquire_dest_image (void *abstract_surface, - cairo_rectangle_int_t *interest_rect, - cairo_image_surface_t **image_out, - cairo_rectangle_int_t *image_rect_out, - void **image_extra) -{ - cairo_image_surface_t *surface = abstract_surface; - - image_rect_out->x = 0; - image_rect_out->y = 0; - image_rect_out->width = surface->width; - image_rect_out->height = surface->height; - - *image_out = surface; - *image_extra = NULL; - - return CAIRO_STATUS_SUCCESS; -} - -static void -_cairo_image_surface_release_dest_image (void *abstract_surface, - cairo_rectangle_int_t *interest_rect, - cairo_image_surface_t *image, - cairo_rectangle_int_t *image_rect, - void *image_extra) -{ -} - -static cairo_status_t -_cairo_image_surface_clone_similar (void *abstract_surface, - cairo_surface_t *src, - int src_x, - int src_y, - int width, - int height, - int *clone_offset_x, - int *clone_offset_y, - cairo_surface_t **clone_out) -{ - cairo_image_surface_t *surface = abstract_surface; - - if (src->backend == surface->base.backend) { - *clone_offset_x = *clone_offset_y = 0; - *clone_out = cairo_surface_reference (src); - - return CAIRO_STATUS_SUCCESS; - } - - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -static cairo_status_t -_cairo_image_surface_set_matrix (cairo_image_surface_t *surface, - const cairo_matrix_t *matrix, - double xc, double yc) -{ - pixman_transform_t pixman_transform; - - _cairo_matrix_to_pixman_matrix (matrix, &pixman_transform, xc, yc); - - if (! pixman_image_set_transform (surface->pixman_image, &pixman_transform)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_image_surface_set_filter (cairo_image_surface_t *surface, - cairo_filter_t filter) -{ - pixman_filter_t pixman_filter; - - switch (filter) { - case CAIRO_FILTER_FAST: - pixman_filter = PIXMAN_FILTER_FAST; - break; - case CAIRO_FILTER_GOOD: - pixman_filter = PIXMAN_FILTER_GOOD; - break; - case CAIRO_FILTER_BEST: - pixman_filter = PIXMAN_FILTER_BEST; - break; - case CAIRO_FILTER_NEAREST: - pixman_filter = PIXMAN_FILTER_NEAREST; - break; - case CAIRO_FILTER_BILINEAR: - pixman_filter = PIXMAN_FILTER_BILINEAR; - break; - case CAIRO_FILTER_GAUSSIAN: - /* XXX: The GAUSSIAN value has no implementation in cairo - * whatsoever, so it was really a mistake to have it in the - * API. We could fix this by officially deprecating it, or - * else inventing semantics and providing an actual - * implementation for it. */ - default: - pixman_filter = PIXMAN_FILTER_BEST; - } - - if (! pixman_image_set_filter (surface->pixman_image, - pixman_filter, - NULL, 0)) - { - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_image_surface_set_extend (cairo_image_surface_t *surface, - cairo_extend_t extend) -{ - pixman_repeat_t pixman_repeat; - - switch (extend) { - case CAIRO_EXTEND_NONE: - pixman_repeat = PIXMAN_REPEAT_NONE; - break; - case CAIRO_EXTEND_REPEAT: - pixman_repeat = PIXMAN_REPEAT_NORMAL; - break; - case CAIRO_EXTEND_REFLECT: - pixman_repeat = PIXMAN_REPEAT_REFLECT; - break; - case CAIRO_EXTEND_PAD: - pixman_repeat = PIXMAN_REPEAT_PAD; - break; - } - - pixman_image_set_repeat (surface->pixman_image, pixman_repeat); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_image_surface_set_component_alpha (cairo_image_surface_t *surface, - cairo_bool_t ca) -{ - pixman_image_set_component_alpha (surface->pixman_image, ca); - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_image_surface_set_attributes (cairo_image_surface_t *surface, - cairo_surface_attributes_t *attributes, - double xc, double yc) -{ - cairo_int_status_t status; - - status = _cairo_image_surface_set_matrix (surface, &attributes->matrix, - xc, yc); - if (unlikely (status)) - return status; - - status = _cairo_image_surface_set_filter (surface, attributes->filter); - if (unlikely (status)) - return status; - - status = _cairo_image_surface_set_extend (surface, attributes->extend); - if (unlikely (status)) - return status; - - status = _cairo_image_surface_set_component_alpha (surface, - attributes->has_component_alpha); - if (unlikely (status)) - return status; - - return CAIRO_STATUS_SUCCESS; -} - /* XXX: I think we should fix pixman to match the names/order of the * cairo operators, but that will likely be better done at the same * time the X server is ported to pixman, (which will change a lot of @@ -1082,24 +844,3325 @@ static cairo_status_t _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, cairo_region_t *region) { - if (region == surface->clip_region) - return CAIRO_STATUS_SUCCESS; - - if (cairo_region_equal (surface->clip_region, region)) - return CAIRO_STATUS_SUCCESS; - - cairo_region_destroy (surface->clip_region); - surface->clip_region = cairo_region_reference (region); - - if (! pixman_image_set_clip_region32 (surface->pixman_image, - region ? ®ion->rgn : NULL)) - { + if (! pixman_image_set_clip_region32 (surface->pixman_image, ®ion->rgn)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_image_surface_unset_clip_region (cairo_image_surface_t *surface) +{ + pixman_image_set_clip_region32 (surface->pixman_image, NULL); +} + +static double +_pixman_nearest_sample (double d) +{ + return ceil (d - .5); +} + +static cairo_bool_t +_nearest_sample (cairo_filter_t filter, double *tx, double *ty) +{ + if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) { + *tx = _pixman_nearest_sample (*tx); + *ty = _pixman_nearest_sample (*ty); + } else { + if (*tx != floor (*tx) || *ty != floor (*ty)) + return FALSE; + } + return fabs (*tx) < PIXMAN_MAX_INT && fabs (*ty) < PIXMAN_MAX_INT; +} + +#if HAS_ATOMIC_OPS +static pixman_image_t *__pixman_transparent_image; +static pixman_image_t *__pixman_black_image; +static pixman_image_t *__pixman_white_image; + +static pixman_image_t * +_pixman_transparent_image (void) +{ + pixman_image_t *image; + + image = __pixman_transparent_image; + if (unlikely (image == NULL)) { + pixman_color_t color; + + color.red = 0x00; + color.green = 0x00; + color.blue = 0x00; + color.alpha = 0x00; + + image = pixman_image_create_solid_fill (&color); + if (unlikely (image == NULL)) + return NULL; + + if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image, + NULL, image)) + { + pixman_image_ref (image); + } + } else { + pixman_image_ref (image); + } + + return image; +} + +static pixman_image_t * +_pixman_black_image (void) +{ + pixman_image_t *image; + + image = __pixman_black_image; + if (unlikely (image == NULL)) { + pixman_color_t color; + + color.red = 0x00; + color.green = 0x00; + color.blue = 0x00; + color.alpha = 0xffff; + + image = pixman_image_create_solid_fill (&color); + if (unlikely (image == NULL)) + return NULL; + + if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image, + NULL, image)) + { + pixman_image_ref (image); + } + } else { + pixman_image_ref (image); + } + + return image; +} + +static pixman_image_t * +_pixman_white_image (void) +{ + pixman_image_t *image; + + image = __pixman_white_image; + if (unlikely (image == NULL)) { + pixman_color_t color; + + color.red = 0xffff; + color.green = 0xffff; + color.blue = 0xffff; + color.alpha = 0xffff; + + image = pixman_image_create_solid_fill (&color); + if (unlikely (image == NULL)) + return NULL; + + if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image, + NULL, image)) + { + pixman_image_ref (image); + } + } else { + pixman_image_ref (image); + } + + return image; +} +#else +static pixman_image_t * +_pixman_transparent_image (void) +{ + return _pixman_image_for_solid (&_cairo_pattern_clear); +} +static pixman_image_t * +_pixman_black_image (void) +{ + return _pixman_image_for_solid (&_cairo_pattern_black); +} +static pixman_image_t * +_pixman_white_image (void) +{ + return _pixman_image_for_solid (&_cairo_pattern_white); +} +#endif + +static uint32_t +hars_petruska_f54_1_random (void) +{ +#define rol(x,k) ((x << k) | (x >> (32-k))) + static uint32_t x; + return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849; +#undef rol +} + +static struct { + cairo_color_t color; + pixman_image_t *image; +} cache[16]; +static int n_cached; + +void +_cairo_image_reset_static_data (void) +{ + while (n_cached) + pixman_image_unref (cache[--n_cached].image); + +#if HAS_ATOMIC_OPS + if (__pixman_transparent_image) { + pixman_image_unref (__pixman_transparent_image); + __pixman_transparent_image = NULL; + } + + if (__pixman_black_image) { + pixman_image_unref (__pixman_black_image); + __pixman_black_image = NULL; + } + + if (__pixman_white_image) { + pixman_image_unref (__pixman_white_image); + __pixman_white_image = NULL; + } +#endif +} + +static pixman_image_t * +_pixman_image_for_solid (const cairo_solid_pattern_t *pattern) +{ + pixman_color_t color; + pixman_image_t *image; + int i; + +#if HAS_ATOMIC_OPS + if (pattern->color.alpha_short <= 0x00ff) + return _pixman_transparent_image (); + + if (pattern->color.alpha_short >= 0xff00) { + if (pattern->color.red_short <= 0x00ff && + pattern->color.green_short <= 0x00ff && + pattern->color.blue_short <= 0x00ff) + { + return _pixman_black_image (); + } + + if (pattern->color.red_short >= 0xff00 && + pattern->color.green_short >= 0xff00 && + pattern->color.blue_short >= 0xff00) + { + return _pixman_white_image (); + } + } +#endif + + CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex); + for (i = 0; i < n_cached; i++) { + if (_cairo_color_equal (&cache[i].color, &pattern->color)) { + image = pixman_image_ref (cache[i].image); + goto UNLOCK; + } + } + + color.red = pattern->color.red_short; + color.green = pattern->color.green_short; + color.blue = pattern->color.blue_short; + color.alpha = pattern->color.alpha_short; + + image = pixman_image_create_solid_fill (&color); + if (image == NULL) + goto UNLOCK; + + if (n_cached < ARRAY_LENGTH (cache)) { + i = n_cached++; + } else { + i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache); + pixman_image_unref (cache[i].image); + } + cache[i].image = pixman_image_ref (image); + cache[i].color = pattern->color; + +UNLOCK: + CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex); + return image; +} + +static pixman_image_t * +_pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + int *ix, int *iy) +{ + pixman_image_t *pixman_image; + pixman_gradient_stop_t pixman_stops_static[2]; + pixman_gradient_stop_t *pixman_stops = pixman_stops_static; + cairo_matrix_t matrix = pattern->base.matrix; + double tx, ty; + unsigned int i; + + if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) { + pixman_stops = _cairo_malloc_ab (pattern->n_stops, + sizeof(pixman_gradient_stop_t)); + if (unlikely (pixman_stops == NULL)) + return NULL; + } + + for (i = 0; i < pattern->n_stops; i++) { + pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset); + pixman_stops[i].color.red = pattern->stops[i].color.red_short; + pixman_stops[i].color.green = pattern->stops[i].color.green_short; + pixman_stops[i].color.blue = pattern->stops[i].color.blue_short; + pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short; + } + + if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern; + pixman_point_fixed_t p1, p2; + cairo_fixed_t xdim, ydim; + + xdim = fabs (linear->p2.x - linear->p1.x); + ydim = fabs (linear->p2.y - linear->p1.y); + + /* + * Transform the matrix to avoid overflow when converting between + * cairo_fixed_t and pixman_fixed_t (without incurring performance + * loss when the transformation is unnecessary). + * + * XXX: Consider converting out-of-range co-ordinates and transforms. + * Having a function to compute the required transformation to + * "normalize" a given bounding box would be generally useful - + * cf linear patterns, gradient patterns, surface patterns... + */ + if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT || + _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT) + { + double sf; + + if (xdim > ydim) + sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim); + else + sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim); + + p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf); + p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf); + p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf); + p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf); + + cairo_matrix_scale (&matrix, sf, sf); + } + else + { + p1.x = _cairo_fixed_to_16_16 (linear->p1.x); + p1.y = _cairo_fixed_to_16_16 (linear->p1.y); + p2.x = _cairo_fixed_to_16_16 (linear->p2.x); + p2.y = _cairo_fixed_to_16_16 (linear->p2.y); + } + + pixman_image = pixman_image_create_linear_gradient (&p1, &p2, + pixman_stops, + pattern->n_stops); + } else { + cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern; + pixman_point_fixed_t c1, c2; + pixman_fixed_t r1, r2; + + c1.x = _cairo_fixed_to_16_16 (radial->c1.x); + c1.y = _cairo_fixed_to_16_16 (radial->c1.y); + r1 = _cairo_fixed_to_16_16 (radial->r1); + + c2.x = _cairo_fixed_to_16_16 (radial->c2.x); + c2.y = _cairo_fixed_to_16_16 (radial->c2.y); + r2 = _cairo_fixed_to_16_16 (radial->r2); + + pixman_image = pixman_image_create_radial_gradient (&c1, &c2, r1, r2, + pixman_stops, + pattern->n_stops); + } + + if (pixman_stops != pixman_stops_static) + free (pixman_stops); + + if (unlikely (pixman_image == NULL)) + return NULL; + + tx = pattern->base.matrix.x0; + ty = pattern->base.matrix.y0; + if (! _cairo_matrix_is_translation (&pattern->base.matrix) || + ! _nearest_sample (pattern->base.filter, &tx, &ty)) + { + pixman_transform_t pixman_transform; + + if (tx != 0. || ty != 0.) { + cairo_matrix_t m, inv; + cairo_status_t status; + double x, y; + + /* pixman also limits the [xy]_offset to 16 bits so evenly + * spread the bits between the two. + */ + inv = pattern->base.matrix; + status = cairo_matrix_invert (&inv); + assert (status == CAIRO_STATUS_SUCCESS); + + x = _cairo_lround (inv.x0 / 2); + y = _cairo_lround (inv.y0 / 2); + tx = -x; + ty = -y; + cairo_matrix_init_translate (&inv, x, y); + cairo_matrix_multiply (&m, &inv, &pattern->base.matrix); + _cairo_matrix_to_pixman_matrix (&m, &pixman_transform, + extents->x + extents->width/2., + extents->y + extents->height/2.); + } else { + tx = ty = 0; + _cairo_matrix_to_pixman_matrix (&pattern->base.matrix, + &pixman_transform, + extents->x + extents->width/2., + extents->y + extents->height/2.); + } + + if (! pixman_image_set_transform (pixman_image, &pixman_transform)) { + pixman_image_unref (pixman_image); + return NULL; + } + } + *ix = tx; + *iy = ty; + + { + pixman_repeat_t pixman_repeat; + + switch (pattern->base.extend) { + default: + case CAIRO_EXTEND_NONE: + pixman_repeat = PIXMAN_REPEAT_NONE; + break; + case CAIRO_EXTEND_REPEAT: + pixman_repeat = PIXMAN_REPEAT_NORMAL; + break; + case CAIRO_EXTEND_REFLECT: + pixman_repeat = PIXMAN_REPEAT_REFLECT; + break; + case CAIRO_EXTEND_PAD: + pixman_repeat = PIXMAN_REPEAT_PAD; + break; + } + + pixman_image_set_repeat (pixman_image, pixman_repeat); + } + + return pixman_image; +} + +struct acquire_source_cleanup { + cairo_surface_t *surface; + cairo_image_surface_t *image; + void *image_extra; +}; + +static void +_acquire_source_cleanup (pixman_image_t *pixman_image, + void *closure) +{ + struct acquire_source_cleanup *data = closure; + + _cairo_surface_release_source_image (data->surface, + data->image, + data->image_extra); + free (data); +} + +static cairo_filter_t +sampled_area (const cairo_surface_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + cairo_rectangle_int_t *sample) +{ + cairo_filter_t filter; + double x1, x2, y1, y2; + double pad; + + x1 = extents->x; + y1 = extents->y; + x2 = extents->x + (int) extents->width; + y2 = extents->y + (int) extents->height; + + _cairo_matrix_transform_bounding_box (&pattern->base.matrix, + &x1, &y1, &x2, &y2, + NULL); + + filter = _cairo_pattern_analyze_filter (&pattern->base, &pad); + sample->x = floor (x1 - pad); + sample->y = floor (y1 - pad); + sample->width = ceil (x2 + pad) - sample->x; + sample->height = ceil (y2 + pad) - sample->y; + + return filter; +} + +static uint16_t +expand_channel (uint16_t v, uint32_t bits) +{ + int offset = 16 - bits; + while (offset > 0) { + v |= v >> bits; + offset -= bits; + bits += bits; + } + return v; +} + +static pixman_image_t * +_pixel_to_solid (cairo_image_surface_t *image, int x, int y) +{ + uint32_t pixel; + pixman_color_t color; + + switch (image->format) { + default: + case CAIRO_FORMAT_INVALID: + ASSERT_NOT_REACHED; + return NULL; + + case CAIRO_FORMAT_A1: + pixel = *(uint8_t *) (image->data + y * image->stride + x/8); + return pixel & (1 << (x&7)) ? _pixman_white_image () : _pixman_transparent_image (); + + case CAIRO_FORMAT_A8: + color.alpha = *(uint8_t *) (image->data + y * image->stride + x); + color.alpha |= color.alpha << 8; + if (color.alpha == 0) + return _pixman_transparent_image (); + + color.red = color.green = color.blue = 0; + return pixman_image_create_solid_fill (&color); + + case CAIRO_FORMAT_RGB16_565: + pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x); + if (pixel == 0) + return _pixman_black_image (); + if (pixel == 0xffff) + return _pixman_white_image (); + + color.alpha = 0xffff; + color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5); + color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6); + color.blue = expand_channel ((pixel & 0x1f) << 11, 5); + return pixman_image_create_solid_fill (&color); + + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x); + color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff; + if (color.alpha == 0) + return _pixman_transparent_image (); + if (pixel == 0xffffffff) + return _pixman_white_image (); + if (color.alpha == 0xffff && (pixel & 0xffffff) == 0) + return _pixman_black_image (); + + color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00); + color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00); + color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00); + return pixman_image_create_solid_fill (&color); + } +} + +static pixman_image_t * +_pixman_image_for_surface (const cairo_surface_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + int *ix, int *iy) +{ + pixman_image_t *pixman_image; + cairo_rectangle_int_t sample; + cairo_extend_t extend; + cairo_filter_t filter; + double tx, ty; + + tx = pattern->base.matrix.x0; + ty = pattern->base.matrix.y0; + + extend = pattern->base.extend; + filter = sampled_area (pattern, extents, &sample); + + pixman_image = NULL; + if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE && + (! is_mask || ! pattern->base.has_component_alpha || + (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0)) + { + cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface; + cairo_surface_type_t type; + + if (source->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) + source = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) pattern->surface)->target; + + type = source->base.backend->type; + if (type == CAIRO_SURFACE_TYPE_IMAGE) { + if (extend != CAIRO_EXTEND_NONE && + sample.x >= 0 && + sample.y >= 0 && + sample.x + sample.width <= source->width && + sample.y + sample.height <= source->height) + { + extend = CAIRO_EXTEND_NONE; + } + + if (sample.width == 1 && sample.height == 1) { + if (sample.x < 0 || + sample.y < 0 || + sample.x >= source->width || + sample.y >= source->height) + { + if (extend == CAIRO_EXTEND_NONE) + return _pixman_transparent_image (); + } + else + { + return _pixel_to_solid (source, sample.x, sample.y); + } + } + + /* avoid allocating a 'pattern' image if we can reuse the original */ + if (extend == CAIRO_EXTEND_NONE && + _cairo_matrix_is_translation (&pattern->base.matrix) && + _nearest_sample (filter, &tx, &ty)) + { + *ix = tx; + *iy = ty; + return pixman_image_ref (source->pixman_image); + } + + pixman_image = pixman_image_create_bits (source->pixman_format, + source->width, + source->height, + (uint32_t *) source->data, + source->stride); + if (unlikely (pixman_image == NULL)) + return NULL; + } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub; + cairo_bool_t is_contained = FALSE; + + sub = (cairo_surface_subsurface_t *) source; + source = (cairo_image_surface_t *) sub->target; + + if (sample.x >= 0 && + sample.y >= 0 && + sample.x + sample.width <= sub->extents.width && + sample.y + sample.height <= sub->extents.height) + { + is_contained = TRUE; + } + + if (sample.width == 1 && sample.height == 1) { + if (is_contained) { + return _pixel_to_solid (source, + sub->extents.x + sample.x, + sub->extents.y + sample.y); + } else { + if (extend == CAIRO_EXTEND_NONE) + return _pixman_transparent_image (); + } + } + + if (is_contained && + _cairo_matrix_is_translation (&pattern->base.matrix) && + _nearest_sample (filter, &tx, &ty)) + { + *ix = tx + sub->extents.x; + *iy = ty + sub->extents.y; + return pixman_image_ref (source->pixman_image); + } + + /* Avoid sub-byte offsets, force a copy in that case. */ + if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) { + pixman_image = pixman_image_create_bits (source->pixman_format, + sub->extents.width, + sub->extents.height, + (uint32_t *) (source->data + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8 + sub->extents.y * source->stride), + source->stride); + if (unlikely (pixman_image == NULL)) + return NULL; + } + } + } + + if (pixman_image == NULL) { + struct acquire_source_cleanup *cleanup; + cairo_image_surface_t *image; + void *extra; + cairo_status_t status; + + status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra); + if (unlikely (status)) + return NULL; + + if (sample.width == 1 && sample.height == 1) { + if (sample.x < 0 || + sample.y < 0 || + sample.x >= image->width || + sample.y >= image->height) + { + if (extend == CAIRO_EXTEND_NONE) { + pixman_image = _pixman_transparent_image (); + _cairo_surface_release_source_image (pattern->surface, image, extra); + return pixman_image; + } + } + else + { + pixman_image = _pixel_to_solid (image, sample.x, sample.y); + _cairo_surface_release_source_image (pattern->surface, image, extra); + return pixman_image; + } + } + + pixman_image = pixman_image_create_bits (image->pixman_format, + image->width, + image->height, + (uint32_t *) image->data, + image->stride); + if (unlikely (pixman_image == NULL)) { + _cairo_surface_release_source_image (pattern->surface, image, extra); + return NULL; + } + + cleanup = malloc (sizeof (*cleanup)); + if (unlikely (cleanup == NULL)) { + _cairo_surface_release_source_image (pattern->surface, image, extra); + pixman_image_unref (pixman_image); + return NULL; + } + + cleanup->surface = pattern->surface; + cleanup->image = image; + cleanup->image_extra = extra; + pixman_image_set_destroy_function (pixman_image, + _acquire_source_cleanup, cleanup); + } + + if (! _cairo_matrix_is_translation (&pattern->base.matrix) || + ! _nearest_sample (filter, &tx, &ty)) + { + pixman_transform_t pixman_transform; + cairo_matrix_t m; + + m = pattern->base.matrix; + if (m.x0 != 0. || m.y0 != 0.) { + cairo_matrix_t inv; + cairo_status_t status; + double x, y; + + /* pixman also limits the [xy]_offset to 16 bits so evenly + * spread the bits between the two. + */ + inv = m; + status = cairo_matrix_invert (&inv); + assert (status == CAIRO_STATUS_SUCCESS); + + x = floor (inv.x0 / 2); + y = floor (inv.y0 / 2); + tx = -x; + ty = -y; + cairo_matrix_init_translate (&inv, x, y); + cairo_matrix_multiply (&m, &inv, &m); + } else { + tx = ty = 0; + } + + _cairo_matrix_to_pixman_matrix (&m, &pixman_transform, + extents->x + extents->width/2., + extents->y + extents->height/2.); + if (! pixman_image_set_transform (pixman_image, &pixman_transform)) { + pixman_image_unref (pixman_image); + return NULL; + } + } + *ix = tx; + *iy = ty; + + if (_cairo_matrix_has_unity_scale (&pattern->base.matrix) && + tx == pattern->base.matrix.x0 && + ty == pattern->base.matrix.y0) + { + pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0); + } + else + { + pixman_filter_t pixman_filter; + + switch (filter) { + case CAIRO_FILTER_FAST: + pixman_filter = PIXMAN_FILTER_FAST; + break; + case CAIRO_FILTER_GOOD: + pixman_filter = PIXMAN_FILTER_GOOD; + break; + case CAIRO_FILTER_BEST: + pixman_filter = PIXMAN_FILTER_BEST; + break; + case CAIRO_FILTER_NEAREST: + pixman_filter = PIXMAN_FILTER_NEAREST; + break; + case CAIRO_FILTER_BILINEAR: + pixman_filter = PIXMAN_FILTER_BILINEAR; + break; + case CAIRO_FILTER_GAUSSIAN: + /* XXX: The GAUSSIAN value has no implementation in cairo + * whatsoever, so it was really a mistake to have it in the + * API. We could fix this by officially deprecating it, or + * else inventing semantics and providing an actual + * implementation for it. */ + default: + pixman_filter = PIXMAN_FILTER_BEST; + } + + pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0); + } + + { + pixman_repeat_t pixman_repeat; + + switch (extend) { + default: + case CAIRO_EXTEND_NONE: + pixman_repeat = PIXMAN_REPEAT_NONE; + break; + case CAIRO_EXTEND_REPEAT: + pixman_repeat = PIXMAN_REPEAT_NORMAL; + break; + case CAIRO_EXTEND_REFLECT: + pixman_repeat = PIXMAN_REPEAT_REFLECT; + break; + case CAIRO_EXTEND_PAD: + pixman_repeat = PIXMAN_REPEAT_PAD; + break; + } + + pixman_image_set_repeat (pixman_image, pixman_repeat); + } + + if (pattern->base.has_component_alpha) + pixman_image_set_component_alpha (pixman_image, TRUE); + + return pixman_image; +} + +static pixman_image_t * +_pixman_image_for_pattern (const cairo_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + int *tx, int *ty) +{ + *tx = *ty = 0; + + if (pattern == NULL) + return _pixman_white_image (); + + switch (pattern->type) { + default: + ASSERT_NOT_REACHED; + case CAIRO_PATTERN_TYPE_SOLID: + return _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern); + + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_LINEAR: + return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern, + extents, tx, ty); + + case CAIRO_PATTERN_TYPE_SURFACE: + return _pixman_image_for_surface ((const cairo_surface_pattern_t *) pattern, + is_mask, extents, tx, ty); + } +} + +static cairo_status_t +_cairo_image_surface_fixup_unbounded (cairo_image_surface_t *dst, + const cairo_composite_rectangles_t *rects, + cairo_clip_t *clip) +{ + pixman_image_t *mask = NULL; + pixman_box32_t boxes[4]; + int i, mask_x = 0, mask_y = 0, n_boxes = 0; + + if (clip != NULL) { + cairo_surface_t *clip_surface; + int clip_x, clip_y; + + clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y); + if (unlikely (clip_surface->status)) + return clip_surface->status; + + mask = ((cairo_image_surface_t *) clip_surface)->pixman_image; + mask_x = -clip_x; + mask_y = -clip_y; + } else { + if (rects->bounded.width == rects->unbounded.width && + rects->bounded.height == rects->unbounded.height) + { + return CAIRO_STATUS_SUCCESS; + } + } + + /* wholly unbounded? */ + if (rects->bounded.width == 0 || rects->bounded.height == 0) { + int x = rects->unbounded.x; + int y = rects->unbounded.y; + int width = rects->unbounded.width; + int height = rects->unbounded.height; + + if (mask != NULL) { + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + mask, NULL, dst->pixman_image, + x + mask_x, y + mask_y, + 0, 0, + x, y, + width, height); + } else { + pixman_color_t color = { 0, }; + pixman_box32_t box = { x, y, x + width, y + height }; + + if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR, + dst->pixman_image, + &color, + 1, &box)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + return CAIRO_STATUS_SUCCESS; + } + + /* top */ + if (rects->bounded.y != rects->unbounded.y) { + boxes[n_boxes].x1 = rects->unbounded.x; + boxes[n_boxes].y1 = rects->unbounded.y; + boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width; + boxes[n_boxes].y2 = rects->bounded.y; + n_boxes++; + } + + /* left */ + if (rects->bounded.x != rects->unbounded.x) { + boxes[n_boxes].x1 = rects->unbounded.x; + boxes[n_boxes].y1 = rects->bounded.y; + boxes[n_boxes].x2 = rects->bounded.x; + boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height; + n_boxes++; + } + + /* right */ + if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) { + boxes[n_boxes].x1 = rects->bounded.x + rects->bounded.width; + boxes[n_boxes].y1 = rects->bounded.y; + boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width; + boxes[n_boxes].y2 = rects->bounded.y + rects->bounded.height; + n_boxes++; + } + + /* bottom */ + if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) { + boxes[n_boxes].x1 = rects->unbounded.x; + boxes[n_boxes].y1 = rects->bounded.y + rects->bounded.height; + boxes[n_boxes].x2 = rects->unbounded.x + rects->unbounded.width; + boxes[n_boxes].y2 = rects->unbounded.y + rects->unbounded.height; + n_boxes++; + } + + if (mask != NULL) { + for (i = 0; i < n_boxes; i++) { + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + mask, NULL, dst->pixman_image, + boxes[i].x1 + mask_x, boxes[i].y1 + mask_y, + 0, 0, + boxes[i].x1, boxes[i].y1, + boxes[i].x2 - boxes[i].x1, boxes[i].y2 - boxes[i].y1); + } + } else { + pixman_color_t color = { 0, }; + + if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR, + dst->pixman_image, + &color, + n_boxes, + boxes)) + { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } } return CAIRO_STATUS_SUCCESS; } +static cairo_status_t +_cairo_image_surface_fixup_unbounded_boxes (cairo_image_surface_t *dst, + const cairo_composite_rectangles_t *extents, + cairo_region_t *clip_region, + cairo_boxes_t *boxes) +{ + cairo_boxes_t clear; + cairo_box_t box; + cairo_status_t status; + struct _cairo_boxes_chunk *chunk; + int i; + + if (boxes->num_boxes <= 1 && clip_region == NULL) + return _cairo_image_surface_fixup_unbounded (dst, extents, NULL); + + _cairo_boxes_init (&clear); + + box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width); + box.p1.y = _cairo_fixed_from_int (extents->unbounded.y); + box.p2.x = _cairo_fixed_from_int (extents->unbounded.x); + box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height); + + if (clip_region == NULL) { + cairo_boxes_t tmp; + + _cairo_boxes_init (&tmp); + + status = _cairo_boxes_add (&tmp, &box); + assert (status == CAIRO_STATUS_SUCCESS); + + tmp.chunks.next = &boxes->chunks; + tmp.num_boxes += boxes->num_boxes; + + status = _cairo_bentley_ottmann_tessellate_boxes (&tmp, + CAIRO_FILL_RULE_WINDING, + &clear); + + tmp.chunks.next = NULL; + } else { + pixman_box32_t *pbox; + + pbox = pixman_region32_rectangles (&clip_region->rgn, &i); + _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i); + + status = _cairo_boxes_add (&clear, &box); + assert (status == CAIRO_STATUS_SUCCESS); + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + status = _cairo_boxes_add (&clear, &chunk->base[i]); + if (unlikely (status)) { + _cairo_boxes_fini (&clear); + return status; + } + } + } + + status = _cairo_bentley_ottmann_tessellate_boxes (&clear, + CAIRO_FILL_RULE_WINDING, + &clear); + } + + if (likely (status == CAIRO_STATUS_SUCCESS)) { + for (chunk = &clear.chunks; chunk != NULL; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x); + int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y); + int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x); + int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y); + + pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t), + PIXMAN_FORMAT_BPP (dst->pixman_format), + x1, y1, x2 - x1, y2 - y1, + 0); + } + } + } + + _cairo_boxes_fini (&clear); + + return status; +} + +static cairo_bool_t +can_reduce_alpha_op (cairo_operator_t op) +{ + int iop = op; + switch (iop) { + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_ADD: + return TRUE; + default: + return FALSE; + } +} + +static cairo_bool_t +reduce_alpha_op (cairo_image_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *pattern) +{ + return dst->base.is_clear && + dst->base.content == CAIRO_CONTENT_ALPHA && + _cairo_pattern_is_opaque_solid (pattern) && + can_reduce_alpha_op (op); +} + +/* low level compositor */ +typedef cairo_status_t +(*image_draw_func_t) (void *closure, + pixman_image_t *dst, + pixman_format_code_t dst_format, + cairo_operator_t op, + const cairo_pattern_t *src, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region); + +static pixman_image_t * +_create_composite_mask_pattern (cairo_clip_t *clip, + image_draw_func_t draw_func, + void *draw_closure, + cairo_image_surface_t *dst, + const cairo_rectangle_int_t *extents) +{ + cairo_region_t *clip_region = NULL; + pixman_image_t *mask; + cairo_status_t status; + cairo_bool_t need_clip_surface = FALSE; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + assert (! _cairo_status_is_error (status)); + + /* The all-clipped state should never propagate this far. */ + assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO); + + need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; + + if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; + } + + mask = pixman_image_create_bits (PIXMAN_a8, extents->width, extents->height, + NULL, 0); + if (unlikely (mask == NULL)) + return NULL; + + /* Is it worth setting the clip region here? */ + if (clip_region != NULL) { + pixman_bool_t ret; + + pixman_region32_translate (&clip_region->rgn, -extents->x, -extents->y); + ret = pixman_image_set_clip_region32 (mask, &clip_region->rgn); + pixman_region32_translate (&clip_region->rgn, extents->x, extents->y); + + if (! ret) { + pixman_image_unref (mask); + return NULL; + } + } + + status = draw_func (draw_closure, + mask, PIXMAN_a8, + CAIRO_OPERATOR_ADD, NULL, + extents->x, extents->y, + extents, NULL); + if (unlikely (status)) { + pixman_image_unref (mask); + return NULL; + } + + if (need_clip_surface) { + cairo_surface_t *tmp; + + tmp = _cairo_image_surface_create_for_pixman_image (mask, PIXMAN_a8); + if (unlikely (tmp->status)) { + pixman_image_unref (mask); + return NULL; + } + + pixman_image_ref (mask); + + status = _cairo_clip_combine_with_surface (clip, tmp, extents->x, extents->y); + cairo_surface_destroy (tmp); + if (unlikely (status)) { + pixman_image_unref (mask); + return NULL; + } + } + + if (clip_region != NULL) + pixman_image_set_clip_region (mask, NULL); + + return mask; +} + +/* Handles compositing with a clip surface when the operator allows + * us to combine the clip with the mask + */ +static cairo_status_t +_clip_and_composite_with_mask (cairo_clip_t *clip, + cairo_operator_t op, + const cairo_pattern_t *pattern, + image_draw_func_t draw_func, + void *draw_closure, + cairo_image_surface_t *dst, + const cairo_rectangle_int_t *extents) +{ + pixman_image_t *mask; + + mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents); + if (unlikely (mask == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (pattern == NULL) { + if (dst->pixman_format == PIXMAN_a8) { + pixman_image_composite32 (_pixman_operator (op), + mask, NULL, dst->pixman_image, + 0, 0, 0, 0, + extents->x, extents->y, + extents->width, extents->height); + } else { + pixman_image_t *src; + + src = _pixman_white_image (); + if (unlikely (src == NULL)) { + pixman_image_unref (mask); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pixman_image_composite32 (_pixman_operator (op), + src, mask, dst->pixman_image, + 0, 0, 0, 0, + extents->x, extents->y, + extents->width, extents->height); + pixman_image_unref (src); + } + } else { + pixman_image_t *src; + int src_x, src_y; + + src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y); + if (unlikely (src == NULL)) { + pixman_image_unref (mask); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pixman_image_composite32 (_pixman_operator (op), + src, mask, dst->pixman_image, + extents->x + src_x, extents->y + src_y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + pixman_image_unref (src); + } + + pixman_image_unref (mask); + + return CAIRO_STATUS_SUCCESS; +} + +/* Handles compositing with a clip surface when we have to do the operation + * in two pieces and combine them together. + */ +static cairo_status_t +_clip_and_composite_combine (cairo_clip_t *clip, + cairo_operator_t op, + const cairo_pattern_t *src, + image_draw_func_t draw_func, + void *draw_closure, + cairo_image_surface_t *dst, + const cairo_rectangle_int_t *extents) +{ + pixman_image_t *tmp; + cairo_surface_t *clip_surface; + int clip_x, clip_y; + cairo_status_t status; + + tmp = pixman_image_create_bits (dst->pixman_format, + extents->width, extents->height, + NULL, 0); + if (unlikely (tmp == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (src == NULL) { + status = (*draw_func) (draw_closure, + tmp, dst->pixman_format, + CAIRO_OPERATOR_ADD, NULL, + extents->x, extents->y, + extents, NULL); + } else { + /* Initialize the temporary surface from the destination surface */ + if (! dst->base.is_clear) { + pixman_image_composite32 (PIXMAN_OP_SRC, + dst->pixman_image, NULL, tmp, + extents->x, extents->y, + 0, 0, + 0, 0, + extents->width, extents->height); + } + + status = (*draw_func) (draw_closure, + tmp, dst->pixman_format, + op, src, + extents->x, extents->y, + extents, NULL); + } + if (unlikely (status)) + goto CLEANUP_SURFACE; + + assert (clip->path != NULL); + clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y); + if (unlikely (clip_surface->status)) + goto CLEANUP_SURFACE; + + if (! dst->base.is_clear) { +#if PIXMAN_HAS_OP_LERP + pixman_image_composite32 (PIXMAN_OP_LERP, + tmp, + ((cairo_image_surface_t *) clip_surface)->pixman_image, + dst->pixman_image, + 0, 0, + extents->x - clip_x, + extents->y - clip_y, + extents->x, extents->y, + extents->width, extents->height); +#else + /* Punch the clip out of the destination */ + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + ((cairo_image_surface_t *) clip_surface)->pixman_image, + NULL, dst->pixman_image, + extents->x - clip_x, + extents->y - clip_y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + + /* Now add the two results together */ + pixman_image_composite32 (PIXMAN_OP_ADD, + tmp, + ((cairo_image_surface_t *) clip_surface)->pixman_image, + dst->pixman_image, + 0, 0, + extents->x - clip_x, + extents->y - clip_y, + extents->x, extents->y, + extents->width, extents->height); +#endif + } else { + pixman_image_composite32 (PIXMAN_OP_SRC, + tmp, + ((cairo_image_surface_t *) clip_surface)->pixman_image, + dst->pixman_image, + 0, 0, + extents->x - clip_x, + extents->y - clip_y, + extents->x, extents->y, + extents->width, extents->height); + } + + CLEANUP_SURFACE: + pixman_image_unref (tmp); + + return status; +} + +/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's + * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip)) + */ +static cairo_status_t +_clip_and_composite_source (cairo_clip_t *clip, + const cairo_pattern_t *pattern, + image_draw_func_t draw_func, + void *draw_closure, + cairo_image_surface_t *dst, + const cairo_rectangle_int_t *extents) +{ + pixman_image_t *mask, *src; + int src_x, src_y; + + if (pattern == NULL) { + cairo_region_t *clip_region; + cairo_status_t status; + + status = draw_func (draw_closure, + dst->pixman_image, dst->pixman_format, + CAIRO_OPERATOR_SOURCE, NULL, + extents->x, extents->y, + extents, NULL); + if (unlikely (status)) + return status; + + if (_cairo_clip_get_region (clip, &clip_region) == CAIRO_INT_STATUS_UNSUPPORTED) + status = _cairo_clip_combine_with_surface (clip, &dst->base, 0, 0); + + return status; + } + + /* Create a surface that is mask IN clip */ + mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents); + if (unlikely (mask == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y); + if (unlikely (src == NULL)) { + pixman_image_unref (mask); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + if (! dst->base.is_clear) { +#if PIXMAN_HAS_OP_LERP + pixman_image_composite32 (PIXMAN_OP_LERP, + src, mask, dst->pixman_image, + extents->x + src_x, extents->y + src_y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); +#else + /* Compute dest' = dest OUT (mask IN clip) */ + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + mask, NULL, dst->pixman_image, + 0, 0, 0, 0, + extents->x, extents->y, + extents->width, extents->height); + + /* Now compute (src IN (mask IN clip)) ADD dest' */ + pixman_image_composite32 (PIXMAN_OP_ADD, + src, mask, dst->pixman_image, + extents->x + src_x, extents->y + src_y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); +#endif + } else { + pixman_image_composite32 (PIXMAN_OP_SRC, + src, mask, dst->pixman_image, + extents->x + src_x, extents->y + src_y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + } + + pixman_image_unref (src); + pixman_image_unref (mask); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_clip_and_composite (cairo_image_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + image_draw_func_t draw_func, + void *draw_closure, + cairo_composite_rectangles_t*extents, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_region_t *clip_region = NULL; + cairo_bool_t need_clip_surface = FALSE; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + return CAIRO_STATUS_SUCCESS; + if (unlikely (_cairo_status_is_error (status))) + return status; + + need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; + + if (clip_region != NULL) { + cairo_rectangle_int_t rect; + cairo_bool_t is_empty; + + cairo_region_get_extents (clip_region, &rect); + is_empty = ! _cairo_rectangle_intersect (&extents->unbounded, &rect); + if (unlikely (is_empty)) + return CAIRO_STATUS_SUCCESS; + + is_empty = ! _cairo_rectangle_intersect (&extents->bounded, &rect); + if (unlikely (is_empty && extents->is_bounded)) + return CAIRO_STATUS_SUCCESS; + + if (cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; + } + } + + if (clip_region != NULL) { + status = _cairo_image_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + return status; + } + + if (reduce_alpha_op (dst, op, src)) { + op = CAIRO_OPERATOR_ADD; + src = NULL; + } + + if (op == CAIRO_OPERATOR_SOURCE) { + status = _clip_and_composite_source (clip, src, + draw_func, draw_closure, + dst, &extents->bounded); + } else { + if (op == CAIRO_OPERATOR_CLEAR) { + src = NULL; + op = CAIRO_OPERATOR_DEST_OUT; + } + + if (need_clip_surface) { + if (extents->is_bounded) { + status = _clip_and_composite_with_mask (clip, op, src, + draw_func, draw_closure, + dst, &extents->bounded); + } else { + status = _clip_and_composite_combine (clip, op, src, + draw_func, draw_closure, + dst, &extents->bounded); + } + } else { + status = draw_func (draw_closure, + dst->pixman_image, dst->pixman_format, + op, src, + 0, 0, + &extents->bounded, + clip_region); + } + } + + if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) { + status = _cairo_image_surface_fixup_unbounded (dst, extents, + need_clip_surface ? clip : NULL); + } + + if (clip_region != NULL) + _cairo_image_surface_unset_clip_region (dst); + + return status; +} + +#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768) +#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767) + +static cairo_bool_t +_line_exceeds_16_16 (const cairo_line_t *line) +{ + return + line->p1.x <= CAIRO_FIXED_16_16_MIN || + line->p1.x >= CAIRO_FIXED_16_16_MAX || + + line->p2.x <= CAIRO_FIXED_16_16_MIN || + line->p2.x >= CAIRO_FIXED_16_16_MAX || + + line->p1.y <= CAIRO_FIXED_16_16_MIN || + line->p1.y >= CAIRO_FIXED_16_16_MAX || + + line->p2.y <= CAIRO_FIXED_16_16_MIN || + line->p2.y >= CAIRO_FIXED_16_16_MAX; +} + +static void +_project_line_x_onto_16_16 (const cairo_line_t *line, + cairo_fixed_t top, + cairo_fixed_t bottom, + pixman_line_fixed_t *out) +{ + cairo_point_double_t p1, p2; + double m; + + p1.x = _cairo_fixed_to_double (line->p1.x); + p1.y = _cairo_fixed_to_double (line->p1.y); + + p2.x = _cairo_fixed_to_double (line->p2.x); + p2.y = _cairo_fixed_to_double (line->p2.y); + + m = (p2.x - p1.x) / (p2.y - p1.y); + out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y)); + out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y)); +} + + +typedef struct { + cairo_trapezoid_t *traps; + int num_traps; + cairo_antialias_t antialias; +} composite_traps_info_t; + +static void +_pixman_image_add_traps (pixman_image_t *image, + int dst_x, int dst_y, + composite_traps_info_t *info) +{ + cairo_trapezoid_t *t = info->traps; + int num_traps = info->num_traps; + while (num_traps--) { + pixman_trapezoid_t trap; + + /* top/bottom will be clamped to surface bounds */ + trap.top = _cairo_fixed_to_16_16 (t->top); + trap.bottom = _cairo_fixed_to_16_16 (t->bottom); + + /* However, all the other coordinates will have been left untouched so + * as not to introduce numerical error. Recompute them if they + * exceed the 16.16 limits. + */ + if (unlikely (_line_exceeds_16_16 (&t->left))) { + _project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left); + trap.left.p1.y = trap.top; + trap.left.p2.y = trap.bottom; + } else { + trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x); + trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y); + trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x); + trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y); + } + + if (unlikely (_line_exceeds_16_16 (&t->right))) { + _project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right); + trap.right.p1.y = trap.top; + trap.right.p2.y = trap.bottom; + } else { + trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x); + trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y); + trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x); + trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y); + } + + pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y); + + t++; + } +} + +static cairo_status_t +_composite_traps (void *closure, + pixman_image_t *dst, + pixman_format_code_t dst_format, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) +{ + composite_traps_info_t *info = closure; + pixman_image_t *src, *mask; + pixman_format_code_t format; + int src_x = 0, src_y = 0; + cairo_status_t status; + + /* Special case adding trapezoids onto a mask surface; we want to avoid + * creating an intermediate temporary mask unnecessarily. + * + * We make the assumption here that the portion of the trapezoids + * contained within the surface is bounded by [dst_x,dst_y,width,height]; + * the Cairo core code passes bounds based on the trapezoid extents. + */ + format = info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8; + if (dst_format == format && + (pattern == NULL || + (op == CAIRO_OPERATOR_ADD && _cairo_pattern_is_opaque_solid (pattern)))) + { + _pixman_image_add_traps (dst, dst_x, dst_y, info); + return CAIRO_STATUS_SUCCESS; + } + + src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + mask = pixman_image_create_bits (format, extents->width, extents->height, + NULL, 0); + if (unlikely (mask == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_SOURCE; + } + + _pixman_image_add_traps (mask, extents->x, extents->y, info); + pixman_image_composite32 (_pixman_operator (op), + src, mask, dst, + extents->x + src_x, extents->y + src_y, + 0, 0, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + + pixman_image_unref (mask); + + status = CAIRO_STATUS_SUCCESS; + CLEANUP_SOURCE: + pixman_image_unref (src); + + return status; +} + +static inline uint32_t +color_to_uint32 (const cairo_color_t *color) +{ + return + (color->alpha_short >> 8 << 24) | + (color->red_short >> 8 << 16) | + (color->green_short & 0xff00) | + (color->blue_short >> 8); +} + +static inline cairo_bool_t +color_to_pixel (const cairo_color_t *color, + pixman_format_code_t format, + uint32_t *pixel) +{ + uint32_t c; + + if (!(format == PIXMAN_a8r8g8b8 || + format == PIXMAN_x8r8g8b8 || + format == PIXMAN_a8b8g8r8 || + format == PIXMAN_x8b8g8r8 || + format == PIXMAN_b8g8r8a8 || + format == PIXMAN_b8g8r8x8 || + format == PIXMAN_r5g6b5 || + format == PIXMAN_b5g6r5 || + format == PIXMAN_a8)) + { + return FALSE; + } + + c = color_to_uint32 (color); + + if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) { + c = ((c & 0xff000000) >> 0) | + ((c & 0x00ff0000) >> 16) | + ((c & 0x0000ff00) >> 0) | + ((c & 0x000000ff) << 16); + } + + if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) { + c = ((c & 0xff000000) >> 24) | + ((c & 0x00ff0000) >> 8) | + ((c & 0x0000ff00) << 8) | + ((c & 0x000000ff) << 24); + } + + if (format == PIXMAN_a8) { + c = c >> 24; + } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) { + c = ((((c) >> 3) & 0x001f) | + (((c) >> 5) & 0x07e0) | + (((c) >> 8) & 0xf800)); + } + + *pixel = c; + return TRUE; +} + +static inline cairo_bool_t +pattern_to_pixel (const cairo_solid_pattern_t *solid, + cairo_operator_t op, + pixman_format_code_t format, + uint32_t *pixel) +{ + if (op == CAIRO_OPERATOR_CLEAR) { + *pixel = 0; + return TRUE; + } + + if (solid->base.type != CAIRO_PATTERN_TYPE_SOLID) + return FALSE; + + if (op == CAIRO_OPERATOR_OVER) { + if (solid->color.alpha_short >= 0xff00) + op = CAIRO_OPERATOR_SOURCE; + } + + if (op != CAIRO_OPERATOR_SOURCE) + return FALSE; + + return color_to_pixel (&solid->color, format, pixel); +} + +typedef struct _fill_span { + cairo_span_renderer_t base; + + uint8_t *mask_data; + pixman_image_t *src, *dst, *mask; +} fill_span_renderer_t; + +static cairo_status_t +_fill_span (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + fill_span_renderer_t *renderer = abstract_renderer; + uint8_t *row; + unsigned i; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + row = renderer->mask_data - spans[0].x; + for (i = 0; i < num_spans - 1; i++) { + /* We implement setting the most common single pixel wide + * span case to avoid the overhead of a memset call. + * Open coding setting longer spans didn't show a + * noticeable improvement over memset. + */ + if (spans[i+1].x == spans[i].x + 1) { + row[spans[i].x] = spans[i].coverage; + } else { + memset (row + spans[i].x, + spans[i].coverage, + spans[i+1].x - spans[i].x); + } + } + + do { + pixman_image_composite32 (PIXMAN_OP_OVER, + renderer->src, renderer->mask, renderer->dst, + 0, 0, 0, 0, + spans[0].x, y++, + spans[i].x - spans[0].x, 1); + } while (--height); + + return CAIRO_STATUS_SUCCESS; +} + +/* avoid using region code to re-validate boxes */ +static cairo_status_t +_fill_unaligned_boxes (cairo_image_surface_t *dst, + const cairo_pattern_t *pattern, + uint32_t pixel, + const cairo_boxes_t *boxes, + const cairo_composite_rectangles_t *extents) +{ + uint8_t buf[CAIRO_STACK_BUFFER_SIZE]; + fill_span_renderer_t renderer; + cairo_rectangular_scan_converter_t converter; + const struct _cairo_boxes_chunk *chunk; + cairo_status_t status; + int i; + + /* XXX + * using composite for fill: + * spiral-box-nonalign-evenodd-fill.512 2201957 2.202 + * spiral-box-nonalign-nonzero-fill.512 336726 0.337 + * spiral-box-pixalign-evenodd-fill.512 352256 0.352 + * spiral-box-pixalign-nonzero-fill.512 147056 0.147 + * using fill: + * spiral-box-nonalign-evenodd-fill.512 3174565 3.175 + * spiral-box-nonalign-nonzero-fill.512 182710 0.183 + * spiral-box-pixalign-evenodd-fill.512 353863 0.354 + * spiral-box-pixalign-nonzero-fill.512 147402 0.147 + * + * cairo-perf-trace seems to favour using fill. + */ + + renderer.base.render_rows = _fill_span; + renderer.dst = dst->pixman_image; + + if ((unsigned) extents->bounded.width <= sizeof (buf)) { + renderer.mask = pixman_image_create_bits (PIXMAN_a8, + extents->bounded.width, 1, + (uint32_t *) buf, + sizeof (buf)); + } else { + renderer.mask = pixman_image_create_bits (PIXMAN_a8, + extents->bounded.width, 1, + NULL, 0); + } + if (unlikely (renderer.mask == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + renderer.mask_data = (uint8_t *) pixman_image_get_data (renderer.mask); + + renderer.src = _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern); + if (unlikely (renderer.src == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_MASK; + } + + _cairo_rectangular_scan_converter_init (&converter, &extents->bounded); + + /* first blit any aligned part of the boxes */ + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *box = chunk->base; + + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_ceil (box[i].p1.x); + int y1 = _cairo_fixed_integer_ceil (box[i].p1.y); + int x2 = _cairo_fixed_integer_floor (box[i].p2.x); + int y2 = _cairo_fixed_integer_floor (box[i].p2.y); + + if (x2 > x1 && y2 > y1) { + cairo_box_t b; + + pixman_fill ((uint32_t *) dst->data, + dst->stride / sizeof (uint32_t), + PIXMAN_FORMAT_BPP (dst->pixman_format), + x1, y1, x2 - x1, y2 - y1, + pixel); + + /* top */ + if (! _cairo_fixed_is_integer (box[i].p1.y)) { + b.p1.x = box[i].p1.x; + b.p1.y = box[i].p1.y; + b.p2.x = box[i].p2.x; + b.p2.y = _cairo_fixed_from_int (y1); + + status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1); + if (unlikely (status)) + goto CLEANUP_CONVERTER; + } + + /* left */ + if (! _cairo_fixed_is_integer (box[i].p1.x)) { + b.p1.x = box[i].p1.x; + b.p1.y = box[i].p1.y; + b.p2.x = _cairo_fixed_from_int (x1); + b.p2.y = box[i].p2.y; + + status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1); + if (unlikely (status)) + goto CLEANUP_CONVERTER; + } + + /* right */ + if (! _cairo_fixed_is_integer (box[i].p2.x)) { + b.p1.x = _cairo_fixed_from_int (x2); + b.p1.y = box[i].p1.y; + b.p2.x = box[i].p2.x; + b.p2.y = box[i].p2.y; + + status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1); + if (unlikely (status)) + goto CLEANUP_CONVERTER; + } + + /* bottom */ + if (! _cairo_fixed_is_integer (box[i].p2.y)) { + b.p1.x = box[i].p1.x; + b.p1.y = _cairo_fixed_from_int (y2); + b.p2.x = box[i].p2.x; + b.p2.y = box[i].p2.y; + + status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1); + if (unlikely (status)) + goto CLEANUP_CONVERTER; + } + } else { + status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1); + if (unlikely (status)) + goto CLEANUP_CONVERTER; + } + } + } + + status = converter.base.generate (&converter.base, &renderer.base); + + CLEANUP_CONVERTER: + converter.base.destroy (&converter.base); + pixman_image_unref (renderer.src); + CLEANUP_MASK: + pixman_image_unref (renderer.mask); + + return status; +} + +typedef struct _cairo_image_surface_span_renderer { + cairo_span_renderer_t base; + + uint8_t *mask_data; + uint32_t mask_stride; +} cairo_image_surface_span_renderer_t; + +cairo_status_t +_cairo_image_surface_span (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_surface_span_renderer_t *renderer = abstract_renderer; + uint8_t *row; + unsigned i; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + /* XXX will it be quicker to repeat the sparse memset, + * or perform a simpler memcpy? + * The fairly dense spiral benchmarks suggests that the sparse + * memset is a win there as well. + */ + row = renderer->mask_data + y * renderer->mask_stride; + do { + for (i = 0; i < num_spans - 1; i++) { + if (! spans[i].coverage) + continue; + + /* We implement setting rendering the most common single + * pixel wide span case to avoid the overhead of a memset + * call. Open coding setting longer spans didn't show a + * noticeable improvement over memset. */ + if (spans[i+1].x == spans[i].x + 1) { + row[spans[i].x] = spans[i].coverage; + } else { + memset (row + spans[i].x, + spans[i].coverage, + spans[i+1].x - spans[i].x); + } + } + row += renderer->mask_stride; + } while (--height); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_composite_unaligned_boxes (cairo_image_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *pattern, + const cairo_boxes_t *boxes, + const cairo_composite_rectangles_t *extents) +{ + uint8_t buf[CAIRO_STACK_BUFFER_SIZE]; + cairo_image_surface_span_renderer_t renderer; + cairo_rectangular_scan_converter_t converter; + pixman_image_t *mask, *src; + cairo_status_t status; + const struct _cairo_boxes_chunk *chunk; + int i, src_x, src_y; + + i = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8) * extents->bounded.height; + if ((unsigned) i <= sizeof (buf)) { + mask = pixman_image_create_bits (PIXMAN_a8, + extents->bounded.width, + extents->bounded.height, + (uint32_t *) buf, + CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8)); + memset (buf, 0, i); + } else { + mask = pixman_image_create_bits (PIXMAN_a8, + extents->bounded.width, + extents->bounded.height, + NULL, 0); + } + if (unlikely (mask == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + renderer.base.render_rows = _cairo_image_surface_span; + renderer.mask_stride = pixman_image_get_stride (mask); + renderer.mask_data = (uint8_t *) pixman_image_get_data (mask); + renderer.mask_data -= extents->bounded.y * renderer.mask_stride + extents->bounded.x; + + _cairo_rectangular_scan_converter_init (&converter, &extents->bounded); + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *box = chunk->base; + + for (i = 0; i < chunk->count; i++) { + status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1); + if (unlikely (status)) + goto CLEANUP; + } + } + + status = converter.base.generate (&converter.base, &renderer.base); + if (unlikely (status)) + goto CLEANUP; + + src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y); + if (unlikely (src == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP; + } + + pixman_image_composite32 (_pixman_operator (op), + src, mask, dst->pixman_image, + extents->bounded.x + src_x, extents->bounded.y + src_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + pixman_image_unref (src); + + CLEANUP: + converter.base.destroy (&converter.base); + pixman_image_unref (mask); + + return status; +} + +static cairo_status_t +_composite_boxes (cairo_image_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_boxes_t *boxes, + cairo_antialias_t antialias, + cairo_clip_t *clip, + const cairo_composite_rectangles_t *extents) +{ + cairo_region_t *clip_region = NULL; + cairo_bool_t need_clip_mask = FALSE; + cairo_status_t status; + struct _cairo_boxes_chunk *chunk; + uint32_t pixel; + int i; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED; + if (need_clip_mask && + (op == CAIRO_OPERATOR_SOURCE || ! extents->is_bounded)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; + } + + if (antialias != CAIRO_ANTIALIAS_NONE) { + if (! boxes->is_pixel_aligned) { + if (need_clip_mask) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, + dst->pixman_format, &pixel)) + { + return _fill_unaligned_boxes (dst, pattern, pixel, boxes, extents); + } + else + { + return _composite_unaligned_boxes (dst, op, pattern, boxes, extents); + } + } + } + + status = CAIRO_STATUS_SUCCESS; + if (! need_clip_mask && + pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, dst->pixman_format, + &pixel)) + { + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + cairo_box_t *box = chunk->base; + + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_round_down (box[i].p1.x); + int y1 = _cairo_fixed_integer_round_down (box[i].p1.y); + int x2 = _cairo_fixed_integer_round_down (box[i].p2.x); + int y2 = _cairo_fixed_integer_round_down (box[i].p2.y); + + if (x2 == x1 || y2 == y1) + continue; + + pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t), + PIXMAN_FORMAT_BPP (dst->pixman_format), + x1, y1, x2 - x1, y2 - y1, + pixel); + } + } + } + else + { + pixman_image_t *src = NULL, *mask = NULL; + int src_x, src_y, mask_x = 0, mask_y = 0; + pixman_op_t pixman_op = _pixman_operator (op); + + if (need_clip_mask) { + cairo_surface_t *clip_surface; + int clip_x, clip_y; + + clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y); + if (unlikely (clip_surface->status)) + return clip_surface->status; + + mask_x = -clip_x; + mask_y = -clip_y; + + if (op == CAIRO_OPERATOR_CLEAR) { + pattern = NULL; + pixman_op = PIXMAN_OP_OUT_REVERSE; + } + + mask = ((cairo_image_surface_t *) clip_surface)->pixman_image; + } + + if (pattern != NULL) { + src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded, &src_x, &src_y); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else { + src = mask; + src_x = mask_x; + src_y = mask_y; + mask = NULL; + } + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *box = chunk->base; + + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_round_down (box[i].p1.x); + int y1 = _cairo_fixed_integer_round_down (box[i].p1.y); + int x2 = _cairo_fixed_integer_round_down (box[i].p2.x); + int y2 = _cairo_fixed_integer_round_down (box[i].p2.y); + + if (x2 == x1 || y2 == y1) + continue; + + pixman_image_composite32 (pixman_op, + src, mask, dst->pixman_image, + x1 + src_x, y1 + src_y, + x1 + mask_x, y1 + mask_y, + x1, y1, + x2 - x1, y2 - y1); + } + } + + if (pattern != NULL) + pixman_image_unref (src); + + if (! extents->is_bounded) { + status = + _cairo_image_surface_fixup_unbounded_boxes (dst, extents, + clip_region, boxes); + } + } + + return status; +} + +static cairo_status_t +_clip_and_composite_boxes (cairo_image_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_boxes_t *boxes, + cairo_antialias_t antialias, + cairo_composite_rectangles_t *extents, + cairo_clip_t *clip) +{ + cairo_traps_t traps; + cairo_status_t status; + composite_traps_info_t info; + + if (boxes->num_boxes == 0 && extents->is_bounded) + return CAIRO_STATUS_SUCCESS; + + /* Use a fast path if the boxes are pixel aligned */ + status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + /* Otherwise render via a mask and composite in the usual fashion. */ + status = _cairo_traps_init_boxes (&traps, boxes); + if (unlikely (status)) + return status; + + info.num_traps = traps.num_traps; + info.traps = traps.traps; + info.antialias = antialias; + status = _clip_and_composite (dst, op, src, + _composite_traps, &info, + extents, clip); + + _cairo_traps_fini (&traps); + return status; +} + +static cairo_bool_t +_mono_edge_is_vertical (const cairo_line_t *line) +{ + return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x); +} + +static cairo_bool_t +_traps_are_pixel_aligned (cairo_traps_t *traps, + cairo_antialias_t antialias) +{ + int i; + + if (antialias == CAIRO_ANTIALIAS_NONE) { + for (i = 0; i < traps->num_traps; i++) { + if (! _mono_edge_is_vertical (&traps->traps[i].left) || + ! _mono_edge_is_vertical (&traps->traps[i].right)) + { + traps->maybe_region = FALSE; + return FALSE; + } + } + } else { + for (i = 0; i < traps->num_traps; i++) { + if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x || + traps->traps[i].right.p1.x != traps->traps[i].right.p2.x || + ! _cairo_fixed_is_integer (traps->traps[i].top) || + ! _cairo_fixed_is_integer (traps->traps[i].bottom) || + ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) || + ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x)) + { + traps->maybe_region = FALSE; + return FALSE; + } + } + } + + return TRUE; +} + +static void +_boxes_for_traps (cairo_boxes_t *boxes, + cairo_traps_t *traps, + cairo_antialias_t antialias) +{ + int i; + + _cairo_boxes_init (boxes); + + boxes->num_boxes = traps->num_traps; + boxes->chunks.base = (cairo_box_t *) traps->traps; + boxes->chunks.count = traps->num_traps; + boxes->chunks.size = traps->num_traps; + + if (antialias != CAIRO_ANTIALIAS_NONE) { + for (i = 0; i < traps->num_traps; i++) { + /* Note the traps and boxes alias so we need to take the local copies first. */ + cairo_fixed_t x1 = traps->traps[i].left.p1.x; + cairo_fixed_t x2 = traps->traps[i].right.p1.x; + cairo_fixed_t y1 = traps->traps[i].top; + cairo_fixed_t y2 = traps->traps[i].bottom; + + boxes->chunks.base[i].p1.x = x1; + boxes->chunks.base[i].p1.y = y1; + boxes->chunks.base[i].p2.x = x2; + boxes->chunks.base[i].p2.y = y2; + + if (boxes->is_pixel_aligned) { + boxes->is_pixel_aligned = + _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) && + _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2); + } + } + } else { + boxes->is_pixel_aligned = TRUE; + + for (i = 0; i < traps->num_traps; i++) { + /* Note the traps and boxes alias so we need to take the local copies first. */ + cairo_fixed_t x1 = traps->traps[i].left.p1.x; + cairo_fixed_t x2 = traps->traps[i].right.p1.x; + cairo_fixed_t y1 = traps->traps[i].top; + cairo_fixed_t y2 = traps->traps[i].bottom; + + /* round down here to match Pixman's behavior when using traps. */ + boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1); + boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1); + boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2); + boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2); + } + } +} + +static cairo_status_t +_clip_and_composite_trapezoids (cairo_image_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_traps_t *traps, + cairo_antialias_t antialias, + cairo_composite_rectangles_t *extents, + cairo_clip_t *clip) +{ + composite_traps_info_t info; + cairo_bool_t need_clip_surface = FALSE; + cairo_status_t status; + + if (traps->num_traps == 0 && extents->is_bounded) + return CAIRO_STATUS_SUCCESS; + + if (clip != NULL) { + cairo_region_t *clip_region; + + status = _cairo_clip_get_region (clip, &clip_region); + need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (traps->has_intersections) { + if (traps->is_rectangular) + status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING); + else if (traps->is_rectilinear) + status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING); + else + status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING); + if (unlikely (status)) + return status; + } + + /* Use a fast path if the trapezoids consist of a simple region, + * but we can only do this if we do not have a clip surface, or can + * substitute the mask with the clip. + */ + if (traps->maybe_region && _traps_are_pixel_aligned (traps, antialias) && + (! need_clip_surface || + (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE))) + { + cairo_boxes_t boxes; + + _boxes_for_traps (&boxes, traps, antialias); + return _clip_and_composite_boxes (dst, op, src, + &boxes, antialias, + extents, clip); + } + + /* No fast path, exclude self-intersections and clip trapezoids. */ + /* Otherwise render the trapezoids to a mask and composite in the usual + * fashion. + */ + info.traps = traps->traps; + info.num_traps = traps->num_traps; + info.antialias = antialias; + return _clip_and_composite (dst, op, src, + _composite_traps, &info, + extents, clip); +} + +static cairo_clip_path_t * +_clip_get_single_path (cairo_clip_t *clip) +{ + cairo_clip_path_t *iter = clip->path; + cairo_clip_path_t *path = NULL; + + do { + if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) { + if (path != NULL) + return FALSE; + + path = iter; + } + iter = iter->prev; + } while (iter != NULL); + + return path; +} + +/* high level image interface */ + +static cairo_int_status_t +_cairo_image_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + cairo_image_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; + cairo_clip_path_t *clip_path; + cairo_clip_t local_clip; + cairo_bool_t have_clip = FALSE; + cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; + int num_boxes = ARRAY_LENGTH (boxes_stack); + cairo_status_t status; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_paint (&extents, + &rect, + op, source, + clip); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_extents (clip, &extents)) + clip = NULL; + + if (clip != NULL) { + clip = _cairo_clip_init_copy (&local_clip, clip); + have_clip = TRUE; + } + + status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); + if (unlikely (status)) { + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; + } + + /* If the clip cannot be reduced to a set of boxes, we will need to + * use a clipmask. Paint is special as it is the only operation that + * does not implicitly use a mask, so we may be able to reduce this + * operation to a fill... + */ + if (clip != NULL && + extents.is_bounded && + (clip_path = _clip_get_single_path (clip)) != NULL) + { + status = _cairo_image_surface_fill (surface, op, source, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias, + NULL); + } + else + { + cairo_boxes_t boxes; + + _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes); + status = _clip_and_composite_boxes (surface, op, source, + &boxes, CAIRO_ANTIALIAS_DEFAULT, + &extents, clip); + } + + if (clip_boxes != boxes_stack) + free (clip_boxes); + + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; +} + +static cairo_status_t +_composite_mask (void *closure, + pixman_image_t *dst, + pixman_format_code_t dst_format, + cairo_operator_t op, + const cairo_pattern_t *src_pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) +{ + const cairo_pattern_t *mask_pattern = closure; + pixman_image_t *src, *mask = NULL; + int src_x = 0, src_y = 0; + int mask_x = 0, mask_y = 0; + + if (src_pattern != NULL) { + src = _pixman_image_for_pattern (src_pattern, FALSE, extents, &src_x, &src_y); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + mask = _pixman_image_for_pattern (mask_pattern, TRUE, extents, &mask_x, &mask_y); + if (unlikely (mask == NULL)) { + pixman_image_unref (src); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + if (mask_pattern->has_component_alpha) + pixman_image_set_component_alpha (mask, TRUE); + } else { + src = _pixman_image_for_pattern (mask_pattern, FALSE, extents, &src_x, &src_y); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pixman_image_composite32 (_pixman_operator (op), src, mask, dst, + extents->x + src_x, extents->y + src_y, + extents->x + mask_x, extents->y + mask_y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + + if (mask != NULL) + pixman_image_unref (mask); + pixman_image_unref (src); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_image_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) +{ + cairo_image_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; + cairo_clip_t local_clip; + cairo_bool_t have_clip = FALSE; + cairo_status_t status; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_mask (&extents, + &rect, + op, source, mask, clip); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_extents (clip, &extents)) + clip = NULL; + + if (clip != NULL && extents.is_bounded) { + clip = _cairo_clip_init_copy (&local_clip, clip); + status = _cairo_clip_rectangle (clip, &extents.bounded); + if (unlikely (status)) { + _cairo_clip_fini (&local_clip); + return status; + } + + have_clip = TRUE; + } + + status = _clip_and_composite (surface, op, source, + _composite_mask, (void *) mask, + &extents, clip); + + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; +} + +typedef struct { + cairo_polygon_t *polygon; + cairo_fill_rule_t fill_rule; + cairo_antialias_t antialias; +} composite_spans_info_t; + +//#define USE_BOTOR_SCAN_CONVERTER +static cairo_status_t +_composite_spans (void *closure, + pixman_image_t *dst, + pixman_format_code_t dst_format, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) +{ + uint8_t mask_buf[CAIRO_STACK_BUFFER_SIZE]; + composite_spans_info_t *info = closure; + cairo_image_surface_span_renderer_t renderer; +#if USE_BOTOR_SCAN_CONVERTER + cairo_box_t box; + cairo_botor_scan_converter_t converter; +#else + cairo_scan_converter_t *converter; +#endif + pixman_image_t *mask; + cairo_status_t status; + +#if USE_BOTOR_SCAN_CONVERTER + box.p1.x = _cairo_fixed_from_int (extents->x); + box.p1.y = _cairo_fixed_from_int (extents->y); + box.p2.x = _cairo_fixed_from_int (extents->x + extents->width); + box.p2.y = _cairo_fixed_from_int (extents->y + extents->height); + _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule); + status = converter.base.add_polygon (&converter.base, info->polygon); +#else + converter = _cairo_tor_scan_converter_create (extents->x, extents->y, + extents->x + extents->width, + extents->y + extents->height, + info->fill_rule); + status = converter->add_polygon (converter, info->polygon); +#endif + if (unlikely (status)) + goto CLEANUP_CONVERTER; + + /* TODO: support rendering to A1 surfaces (or: go add span + * compositing to pixman.) */ + + if (pattern == NULL && + dst_format == PIXMAN_a8 && + op == CAIRO_OPERATOR_SOURCE) + { + mask = dst; + dst = NULL; + } + else + { + int stride = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->width, 8); + uint8_t *data = mask_buf; + + if (extents->height * stride <= (int) sizeof (mask_buf)) + memset (data, 0, extents->height * stride); + else + data = NULL, stride = 0; + + mask = pixman_image_create_bits (PIXMAN_a8, + extents->width, + extents->height, + (uint32_t *) data, + stride); + if (unlikely (mask == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_CONVERTER; + } + } + + renderer.base.render_rows = _cairo_image_surface_span; + renderer.mask_stride = pixman_image_get_stride (mask); + renderer.mask_data = (uint8_t *) pixman_image_get_data (mask); + if (dst != NULL) + renderer.mask_data -= extents->y * renderer.mask_stride + extents->x; + else + renderer.mask_data -= dst_y * renderer.mask_stride + dst_x; + +#if USE_BOTOR_SCAN_CONVERTER + status = converter.base.generate (&converter.base, &renderer.base); +#else + status = converter->generate (converter, &renderer.base); +#endif + if (unlikely (status)) + goto CLEANUP_RENDERER; + + if (dst != NULL) { + pixman_image_t *src; + int src_x, src_y; + + src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y); + if (unlikely (src == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_RENDERER; + } + + pixman_image_composite32 (_pixman_operator (op), src, mask, dst, + extents->x + src_x, extents->y + src_y, + 0, 0, /* mask.x, mask.y */ + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + pixman_image_unref (src); + } + + CLEANUP_RENDERER: + if (dst != NULL) + pixman_image_unref (mask); + CLEANUP_CONVERTER: +#if USE_BOTOR_SCAN_CONVERTER + converter.base.destroy (&converter.base); +#else + converter->destroy (converter); +#endif + return status; +} + +static cairo_status_t +_clip_and_composite_polygon (cairo_image_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, + cairo_composite_rectangles_t *extents, + cairo_clip_t *clip) +{ + cairo_status_t status; + + if (polygon->num_edges == 0) { + cairo_traps_t traps; + + if (extents->is_bounded) + return CAIRO_STATUS_SUCCESS; + + _cairo_traps_init (&traps); + status = _clip_and_composite_trapezoids (dst, op, src, + &traps, antialias, + extents, clip); + _cairo_traps_fini (&traps); + + return status; + } + + _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask); + if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask)) + return CAIRO_STATUS_SUCCESS; + + if (antialias != CAIRO_ANTIALIAS_NONE) { + composite_spans_info_t info; + + info.polygon = polygon; + info.fill_rule = fill_rule; + info.antialias = antialias; + + status = _clip_and_composite (dst, op, src, + _composite_spans, &info, + extents, clip); + } else { + cairo_traps_t traps; + + _cairo_traps_init (&traps); + + /* Fall back to trapezoid fills. */ + status = _cairo_bentley_ottmann_tessellate_polygon (&traps, + polygon, + fill_rule); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _clip_and_composite_trapezoids (dst, op, src, + &traps, antialias, + extents, clip); + } + + _cairo_traps_fini (&traps); + } + + return status; +} + +static cairo_int_status_t +_cairo_image_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_image_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; + cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; + int num_boxes = ARRAY_LENGTH (boxes_stack); + cairo_clip_t local_clip; + cairo_bool_t have_clip = FALSE; + cairo_status_t status; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_stroke (&extents, + &rect, + op, source, + path, style, ctm, + clip); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_extents (clip, &extents)) + clip = NULL; + + if (clip != NULL) { + clip = _cairo_clip_init_copy (&local_clip, clip); + have_clip = TRUE; + } + + status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); + if (unlikely (status)) { + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; + } + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (path->is_rectilinear) { + cairo_boxes_t boxes; + + _cairo_boxes_init (&boxes); + _cairo_boxes_limit (&boxes, clip_boxes, num_boxes); + + status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, + style, + ctm, + &boxes); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _clip_and_composite_boxes (surface, op, source, + &boxes, antialias, + &extents, clip); + } + + _cairo_boxes_fini (&boxes); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + cairo_polygon_t polygon; + + _cairo_polygon_init (&polygon); + _cairo_polygon_limit (&polygon, clip_boxes, num_boxes); + + status = _cairo_path_fixed_stroke_to_polygon (path, + style, + ctm, ctm_inverse, + tolerance, + &polygon); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _clip_and_composite_polygon (surface, op, source, &polygon, + CAIRO_FILL_RULE_WINDING, antialias, + &extents, clip); + } + + _cairo_polygon_fini (&polygon); + } + + if (clip_boxes != boxes_stack) + free (clip_boxes); + + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; +} + +static cairo_int_status_t +_cairo_image_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_image_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; + cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; + cairo_clip_t local_clip; + cairo_bool_t have_clip = FALSE; + int num_boxes = ARRAY_LENGTH (boxes_stack); + cairo_status_t status; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_fill (&extents, + &rect, + op, source, path, + clip); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_extents (clip, &extents)) + clip = NULL; + + if (extents.is_bounded && clip != NULL) { + cairo_clip_path_t *clip_path; + + if (((clip_path = _clip_get_single_path (clip)) != NULL) && + _cairo_path_fixed_equal (&clip_path->path, path)) + { + clip = NULL; + } + } + + if (clip != NULL) { + clip = _cairo_clip_init_copy (&local_clip, clip); + have_clip = TRUE; + } + + status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); + if (unlikely (status)) { + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; + } + + if (_cairo_path_fixed_is_rectilinear_fill (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init (&boxes); + _cairo_boxes_limit (&boxes, clip_boxes, num_boxes); + + status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, + fill_rule, + &boxes); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _clip_and_composite_boxes (surface, op, source, + &boxes, antialias, + &extents, clip); + } + + _cairo_boxes_fini (&boxes); + } else { + cairo_polygon_t polygon; + + assert (! path->is_empty_fill); + + _cairo_polygon_init (&polygon); + _cairo_polygon_limit (&polygon, clip_boxes, num_boxes); + + status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _clip_and_composite_polygon (surface, op, source, &polygon, + fill_rule, antialias, + &extents, clip); + } + + _cairo_polygon_fini (&polygon); + } + + if (clip_boxes != boxes_stack) + free (clip_boxes); + + if (have_clip) + _cairo_clip_fini (&local_clip); + + return status; +} + +typedef struct { + cairo_scaled_font_t *font; + cairo_glyph_t *glyphs; + int num_glyphs; +} composite_glyphs_info_t; + +static cairo_status_t +_composite_glyphs_via_mask (void *closure, + pixman_image_t *dst, + pixman_format_code_t dst_format, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) +{ + composite_glyphs_info_t *info = closure; + cairo_scaled_font_t *font = info->font; + cairo_glyph_t *glyphs = info->glyphs; + int num_glyphs = info->num_glyphs; + pixman_image_t *mask = NULL; + pixman_image_t *src; + pixman_image_t *white; + pixman_format_code_t mask_format = 0; /* silence gcc */ + cairo_status_t status; + int src_x, src_y; + int i; + + src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + white = _pixman_white_image (); + if (unlikely (white == NULL)) { + pixman_image_unref (src); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + _cairo_scaled_font_freeze_cache (font); + + for (i = 0; i < num_glyphs; i++) { + int x, y; + cairo_image_surface_t *glyph_surface; + cairo_scaled_glyph_t *scaled_glyph; + + status = _cairo_scaled_glyph_lookup (font, glyphs[i].index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + &scaled_glyph); + + if (unlikely (status)) + goto CLEANUP; + + glyph_surface = scaled_glyph->surface; + + if (glyph_surface->width == 0 || glyph_surface->height == 0) + continue; + + /* To start, create the mask using the format from the first + * glyph. Later we'll deal with different formats. */ + if (mask == NULL) { + mask_format = glyph_surface->pixman_format; + mask = pixman_image_create_bits (mask_format, + extents->width, extents->height, + NULL, 0); + if (unlikely (mask == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP; + } + + if (PIXMAN_FORMAT_RGB (mask_format)) + pixman_image_set_component_alpha (mask, TRUE); + } + + /* If we have glyphs of different formats, we "upgrade" the mask + * to the wider of the formats. */ + if (glyph_surface->pixman_format != mask_format && + PIXMAN_FORMAT_BPP (mask_format) < + PIXMAN_FORMAT_BPP (glyph_surface->pixman_format)) + { + pixman_image_t *new_mask; + + mask_format = glyph_surface->pixman_format; + new_mask = pixman_image_create_bits (mask_format, + extents->width, extents->height, + NULL, 0); + if (unlikely (new_mask == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP; + } + + pixman_image_composite32 (PIXMAN_OP_SRC, + white, mask, new_mask, + 0, 0, 0, 0, 0, 0, + extents->width, extents->height); + + pixman_image_unref (mask); + mask = new_mask; + if (PIXMAN_FORMAT_RGB (mask_format)) + pixman_image_set_component_alpha (mask, TRUE); + } + + /* round glyph locations to the nearest pixel */ + /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ + x = _cairo_lround (glyphs[i].x - + glyph_surface->base.device_transform.x0); + y = _cairo_lround (glyphs[i].y - + glyph_surface->base.device_transform.y0); + if (glyph_surface->pixman_format == mask_format) { + pixman_image_composite32 (PIXMAN_OP_ADD, + glyph_surface->pixman_image, NULL, mask, + 0, 0, 0, 0, + x - extents->x, y - extents->y, + glyph_surface->width, + glyph_surface->height); + } else { + pixman_image_composite32 (PIXMAN_OP_ADD, + white, glyph_surface->pixman_image, mask, + 0, 0, 0, 0, + x - extents->x, y - extents->y, + glyph_surface->width, + glyph_surface->height); + } + } + + pixman_image_composite32 (_pixman_operator (op), + src, mask, dst, + extents->x + src_x, extents->y + src_y, + 0, 0, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + +CLEANUP: + _cairo_scaled_font_thaw_cache (font); + if (mask != NULL) + pixman_image_unref (mask); + pixman_image_unref (src); + pixman_image_unref (white); + + return status; +} + +static cairo_status_t +_composite_glyphs (void *closure, + pixman_image_t *dst, + pixman_format_code_t dst_format, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) +{ + composite_glyphs_info_t *info = closure; + cairo_scaled_glyph_t *glyph_cache[64]; + pixman_op_t pixman_op = _pixman_operator (op); + pixman_image_t *src = NULL; + int src_x = 0, src_y = 0; + cairo_status_t status; + int i; + + if (pattern != NULL) { + src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y); + src_x -= dst_x; + src_y -= dst_y; + } else { + src = _pixman_white_image (); + } + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memset (glyph_cache, 0, sizeof (glyph_cache)); + status = CAIRO_STATUS_SUCCESS; + + _cairo_scaled_font_freeze_cache (info->font); + for (i = 0; i < info->num_glyphs; i++) { + int x, y; + cairo_image_surface_t *glyph_surface; + cairo_scaled_glyph_t *scaled_glyph; + unsigned long glyph_index = info->glyphs[i].index; + int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache); + + scaled_glyph = glyph_cache[cache_index]; + if (scaled_glyph == NULL || + _cairo_scaled_glyph_index (scaled_glyph) != glyph_index) + { + status = _cairo_scaled_glyph_lookup (info->font, glyph_index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + &scaled_glyph); + + if (unlikely (status)) + break; + + glyph_cache[cache_index] = scaled_glyph; + } + + glyph_surface = scaled_glyph->surface; + if (glyph_surface->width && glyph_surface->height) { + int x1, y1, x2, y2; + + /* round glyph locations to the nearest pixel */ + /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ + x = _cairo_lround (info->glyphs[i].x - + glyph_surface->base.device_transform.x0); + y = _cairo_lround (info->glyphs[i].y - + glyph_surface->base.device_transform.y0); + + x1 = x; + if (x1 < extents->x) + x1 = extents->x; + x2 = x + glyph_surface->width; + if (x2 > extents->x + extents->width) + x2 = extents->x + extents->width; + + y1 = y; + if (y1 < extents->y) + y1 = extents->y; + y2 = y + glyph_surface->height; + if (y2 > extents->y + extents->height) + y2 = extents->y + extents->height; + + pixman_image_composite32 (pixman_op, + src, glyph_surface->pixman_image, dst, + x1 + src_x, y1 + src_y, + x1 - x, y1 - y, + x1 - dst_x, y1 - dst_y, + x2 - x1, y2 - y1); + } + } + _cairo_scaled_font_thaw_cache (info->font); + + pixman_image_unref (src); + + return status; +} + +static cairo_int_status_t +_cairo_image_surface_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip, + int *num_remaining) +{ + cairo_image_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; + composite_glyphs_info_t glyph_info; + cairo_clip_t local_clip; + cairo_bool_t have_clip = FALSE; + cairo_bool_t overlap; + cairo_status_t status; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_glyphs (&extents, + &rect, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, + &overlap); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_rectangle (clip, &extents.mask)) + clip = NULL; + + if (clip != NULL && extents.is_bounded) { + clip = _cairo_clip_init_copy (&local_clip, clip); + status = _cairo_clip_rectangle (clip, &extents.bounded); + if (unlikely (status)) + return status; + + have_clip = TRUE; + } + + glyph_info.font = scaled_font; + glyph_info.glyphs = glyphs; + glyph_info.num_glyphs = num_glyphs; + + status = _clip_and_composite (surface, op, source, + overlap || extents.is_bounded == 0 ? _composite_glyphs_via_mask : _composite_glyphs, + &glyph_info, + &extents, clip); + + if (have_clip) + _cairo_clip_fini (&local_clip); + + *num_remaining = 0; + return status; +} + +static cairo_bool_t +_cairo_image_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_image_surface_t *surface = abstract_surface; + + rectangle->x = 0; + rectangle->y = 0; + rectangle->width = surface->width; + rectangle->height = surface->height; + + return TRUE; +} + +static void +_cairo_image_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + _cairo_font_options_init_default (options); + + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON); + _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON); +} + +/* legacy interface kept for compatibility until surface-fallback is removed */ +static cairo_status_t +_cairo_image_surface_acquire_dest_image (void *abstract_surface, + cairo_rectangle_int_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_int_t *image_rect_out, + void **image_extra) +{ + cairo_image_surface_t *surface = abstract_surface; + + image_rect_out->x = 0; + image_rect_out->y = 0; + image_rect_out->width = surface->width; + image_rect_out->height = surface->height; + + *image_out = surface; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_image_surface_release_dest_image (void *abstract_surface, + cairo_rectangle_int_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_int_t *image_rect, + void *image_extra) +{ +} + +static cairo_status_t +_cairo_image_surface_clone_similar (void *abstract_surface, + cairo_surface_t *src, + int src_x, + int src_y, + int width, + int height, + int *clone_offset_x, + int *clone_offset_y, + cairo_surface_t **clone_out) +{ + cairo_image_surface_t *surface = abstract_surface; + + if (src->backend == surface->base.backend) { + *clone_offset_x = *clone_offset_y = 0; + *clone_out = cairo_surface_reference (src); + + return CAIRO_STATUS_SUCCESS; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static cairo_int_status_t _cairo_image_surface_composite (cairo_operator_t op, const cairo_pattern_t *src_pattern, @@ -1115,91 +4178,88 @@ _cairo_image_surface_composite (cairo_operator_t op, unsigned int height, cairo_region_t *clip_region) { - cairo_surface_attributes_t src_attr, mask_attr; - cairo_image_surface_t *dst = abstract_dst; - cairo_image_surface_t *src; - cairo_image_surface_t *mask; - cairo_int_status_t status; + cairo_image_surface_t *dst = abstract_dst; + cairo_composite_rectangles_t extents; + pixman_image_t *src; + int src_offset_x, src_offset_y; + cairo_status_t status; - status = _cairo_image_surface_set_clip_region (dst, clip_region); - if (unlikely (status)) - return status; - - status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern, - &dst->base, - src_x, src_y, - mask_x, mask_y, - width, height, - CAIRO_PATTERN_ACQUIRE_NONE, - (cairo_surface_t **) &src, - (cairo_surface_t **) &mask, - &src_attr, &mask_attr); - if (unlikely (status)) - return status; - - status = _cairo_image_surface_set_attributes (src, &src_attr, - dst_x + width / 2., - dst_y + height / 2.); - if (unlikely (status)) - goto CLEANUP_SURFACES; - - /* we sometimes get destinations with transforms. - * we're not equiped to deal with this */ - { - static const pixman_transform_t id = { - {{ pixman_fixed_1, 0, 0 }, - { 0, pixman_fixed_1, 0 }, - { 0, 0, pixman_fixed_1 }} - }; - pixman_image_set_transform (dst->pixman_image, &id); - } - - if (mask) { - status = _cairo_image_surface_set_attributes (mask, &mask_attr, - dst_x + width / 2., - dst_y + height / 2.); + if (clip_region != NULL) { + status = _cairo_image_surface_set_clip_region (dst, clip_region); if (unlikely (status)) - goto CLEANUP_SURFACES; + return status; + } - pixman_image_composite (_pixman_operator (op), - src->pixman_image, - mask->pixman_image, - dst->pixman_image, - src_x + src_attr.x_offset, - src_y + src_attr.y_offset, - mask_x + mask_attr.x_offset, - mask_y + mask_attr.y_offset, - dst_x, dst_y, - width, height); + extents.source.x = src_x; + extents.source.y = src_y; + extents.source.width = width; + extents.source.height = height; + + extents.mask.x = mask_x; + extents.mask.y = mask_y; + extents.mask.width = width; + extents.mask.height = height; + + extents.bounded.x = dst_x; + extents.bounded.y = dst_y; + extents.bounded.width = width; + extents.bounded.height = height; + + extents.unbounded.x = 0; + extents.unbounded.y = 0; + extents.unbounded.width = dst->width; + extents.unbounded.height = dst->height; + + if (clip_region != NULL) { + cairo_rectangle_int_t rect; + + cairo_region_get_extents (clip_region, &rect); + if (! _cairo_rectangle_intersect (&extents.unbounded, &rect)) + return CAIRO_STATUS_SUCCESS; + } + + extents.is_bounded = _cairo_operator_bounded_by_either (op); + + src = _pixman_image_for_pattern (src_pattern, FALSE, &extents.source, &src_offset_x, &src_offset_y); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = CAIRO_STATUS_SUCCESS; + if (mask_pattern != NULL) { + pixman_image_t *mask; + int mask_offset_x, mask_offset_y; + + mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents.mask, &mask_offset_x, &mask_offset_y); + if (unlikely (mask == NULL)) { + pixman_image_unref (src); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pixman_image_composite32 (_pixman_operator (op), + src, mask, dst->pixman_image, + src_x + src_offset_x, + src_y + src_offset_y, + mask_x + mask_offset_x, + mask_y + mask_offset_y, + dst_x, dst_y, width, height); + + pixman_image_unref (mask); } else { - pixman_image_composite (_pixman_operator (op), - src->pixman_image, - NULL, - dst->pixman_image, - src_x + src_attr.x_offset, - src_y + src_attr.y_offset, - 0, 0, - dst_x, dst_y, - width, height); + pixman_image_composite32 (_pixman_operator (op), + src, NULL, dst->pixman_image, + src_x + src_offset_x, + src_y + src_offset_y, + 0, 0, + dst_x, dst_y, width, height); } - if (! _cairo_operator_bounded_by_source (op)) { - status = _cairo_surface_composite_fixup_unbounded (&dst->base, - &src_attr, src->width, src->height, - mask ? &mask_attr : NULL, - mask ? mask->width : 0, - mask ? mask->height : 0, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, width, height, - clip_region); - } + pixman_image_unref (src); - CLEANUP_SURFACES: - if (mask) - _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr); + if (! extents.is_bounded) + status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL); - _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr); + if (clip_region != NULL) + _cairo_image_surface_unset_clip_region (dst); return status; } @@ -1214,8 +4274,8 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, cairo_image_surface_t *surface = abstract_surface; pixman_color_t pixman_color; - pixman_rectangle16_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (pixman_rectangle16_t)]; - pixman_rectangle16_t *pixman_rects = stack_rects; + pixman_box32_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)]; + pixman_box32_t *pixman_boxes = stack_boxes; int i; cairo_int_status_t status; @@ -1228,75 +4288,35 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface, pixman_color.blue = color->blue_short; pixman_color.alpha = color->alpha_short; - status = _cairo_image_surface_set_clip_region (surface, NULL); - assert (status == CAIRO_STATUS_SUCCESS); - - if (num_rects > ARRAY_LENGTH (stack_rects)) { - pixman_rects = _cairo_malloc_ab (num_rects, sizeof (pixman_rectangle16_t)); - if (unlikely (pixman_rects == NULL)) + if (num_rects > ARRAY_LENGTH (stack_boxes)) { + pixman_boxes = _cairo_malloc_ab (num_rects, sizeof (pixman_box32_t)); + if (unlikely (pixman_boxes == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } for (i = 0; i < num_rects; i++) { - pixman_rects[i].x = rects[i].x; - pixman_rects[i].y = rects[i].y; - pixman_rects[i].width = rects[i].width; - pixman_rects[i].height = rects[i].height; + pixman_boxes[i].x1 = rects[i].x; + pixman_boxes[i].y1 = rects[i].y; + pixman_boxes[i].x2 = rects[i].x + rects[i].width; + pixman_boxes[i].y2 = rects[i].y + rects[i].height; } - /* XXX: pixman_fill_region() should be implemented */ status = CAIRO_STATUS_SUCCESS; - if (! pixman_image_fill_rectangles (_pixman_operator (op), - surface->pixman_image, - &pixman_color, - num_rects, - pixman_rects)) + if (! pixman_image_fill_boxes (_pixman_operator (op), + surface->pixman_image, + &pixman_color, + num_rects, + pixman_boxes)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); } - if (pixman_rects != stack_rects) - free (pixman_rects); + if (pixman_boxes != stack_boxes) + free (pixman_boxes); return status; } -static pixman_format_code_t -_pixman_mask_format_from_antialias (cairo_antialias_t antialias) -{ - if (antialias == CAIRO_ANTIALIAS_NONE) - return PIXMAN_a1; - return PIXMAN_a8; -} - -static void -_pixman_add_trapezoids (pixman_image_t *image, - int dst_x, int dst_y, - const cairo_trapezoid_t *traps, - int num_traps) -{ - while (num_traps--) { - pixman_trapezoid_t trap; - - trap.top = _cairo_fixed_to_16_16 (traps->top); - trap.bottom = _cairo_fixed_to_16_16 (traps->bottom); - - trap.left.p1.x = _cairo_fixed_to_16_16 (traps->left.p1.x); - trap.left.p1.y = _cairo_fixed_to_16_16 (traps->left.p1.y); - trap.left.p2.x = _cairo_fixed_to_16_16 (traps->left.p2.x); - trap.left.p2.y = _cairo_fixed_to_16_16 (traps->left.p2.y); - - trap.right.p1.x = _cairo_fixed_to_16_16 (traps->right.p1.x); - trap.right.p1.y = _cairo_fixed_to_16_16 (traps->right.p1.y); - trap.right.p2.x = _cairo_fixed_to_16_16 (traps->right.p2.x); - trap.right.p2.y = _cairo_fixed_to_16_16 (traps->right.p2.y); - - pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y); - - traps++; - } -} - static cairo_int_status_t _cairo_image_surface_composite_trapezoids (cairo_operator_t op, const cairo_pattern_t *pattern, @@ -1312,11 +4332,11 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, int num_traps, cairo_region_t *clip_region) { - cairo_surface_attributes_t attributes; cairo_image_surface_t *dst = abstract_dst; - cairo_image_surface_t *src; - cairo_int_status_t status; - pixman_image_t *mask; + cairo_composite_rectangles_t extents; + cairo_pattern_union_t source_pattern; + composite_traps_info_t info; + cairo_status_t status; if (height == 0 || width == 0) return CAIRO_STATUS_SUCCESS; @@ -1324,101 +4344,83 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op, if (CAIRO_INJECT_FAULT ()) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - /* Special case adding trapezoids onto a mask surface; we want to avoid - * creating an intermediate temporary mask unnecessarily. - * - * We make the assumption here that the portion of the trapezoids - * contained within the surface is bounded by [dst_x,dst_y,width,height]; - * the Cairo core code passes bounds based on the trapezoid extents. - * - * Currently the check clip_region == NULL is needed for correct - * functioning, since pixman_add_trapezoids() doesn't obey the - * surface clip, which is a libpixman bug , but there's no harm in - * falling through to the general case when the surface is clipped - * since libpixman would have to generate an intermediate mask anyways. - */ - if (op == CAIRO_OPERATOR_ADD && - clip_region == NULL && - _cairo_pattern_is_opaque_solid (pattern) && - dst->base.content == CAIRO_CONTENT_ALPHA && - antialias != CAIRO_ANTIALIAS_NONE) - { - _pixman_add_trapezoids (dst->pixman_image, 0, 0, traps, num_traps); - return CAIRO_STATUS_SUCCESS; + extents.source.x = src_x; + extents.source.y = src_y; + extents.source.width = width; + extents.source.height = height; + + extents.mask.x = dst_x; + extents.mask.y = dst_y; + extents.mask.width = width; + extents.mask.height = height; + + extents.bounded.x = dst_x; + extents.bounded.y = dst_y; + extents.bounded.width = width; + extents.bounded.height = height; + + extents.unbounded.x = 0; + extents.unbounded.y = 0; + extents.unbounded.width = dst->width; + extents.unbounded.height = dst->height; + + if (clip_region != NULL) { + cairo_rectangle_int_t rect; + + cairo_region_get_extents (clip_region, &rect); + if (! _cairo_rectangle_intersect (&extents.unbounded, &rect)) + return CAIRO_STATUS_SUCCESS; } - status = _cairo_image_surface_set_clip_region (dst, clip_region); - if (unlikely (status)) - return status; + extents.is_bounded = _cairo_operator_bounded_by_either (op); - status = _cairo_pattern_acquire_surface (pattern, &dst->base, - src_x, src_y, width, height, - CAIRO_PATTERN_ACQUIRE_NONE, - (cairo_surface_t **) &src, - &attributes); - if (unlikely (status)) - return status; - - status = _cairo_image_surface_set_attributes (src, &attributes, - dst_x + width / 2., - dst_y + height / 2.); - if (unlikely (status)) - goto CLEANUP_SOURCE; - - mask = pixman_image_create_bits (_pixman_mask_format_from_antialias (antialias), - width, height, NULL, 0); - if (unlikely (mask == NULL)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto CLEANUP_SOURCE; + if (clip_region != NULL) { + status = _cairo_image_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + return status; } - _pixman_add_trapezoids (mask, dst_x, dst_y, traps, num_traps); + _cairo_pattern_init_static_copy (&source_pattern.base, pattern); + cairo_matrix_translate (&source_pattern.base.matrix, + src_x - extents.bounded.x, + src_y - extents.bounded.y); - pixman_image_composite (_pixman_operator (op), - src->pixman_image, - mask, - dst->pixman_image, - src_x + attributes.x_offset, - src_y + attributes.y_offset, - 0, 0, - dst_x, dst_y, - width, height); + info.traps = traps; + info.num_traps = num_traps; + info.antialias = antialias; + status = _composite_traps (&info, + dst->pixman_image, + dst->pixman_format, + op, + &source_pattern.base, + 0, 0, + &extents.bounded, + clip_region); - pixman_image_unref (mask); + if (status == CAIRO_STATUS_SUCCESS && ! extents.is_bounded) + status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL); - if (! _cairo_operator_bounded_by_mask (op)) { - status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base, - &attributes, - src->width, src->height, - width, height, - src_x, src_y, - 0, 0, - dst_x, dst_y, width, height, - clip_region); - } - - CLEANUP_SOURCE: - _cairo_pattern_release_surface (pattern, &src->base, &attributes); + if (clip_region != NULL) + _cairo_image_surface_unset_clip_region (dst); return status; } -typedef struct _cairo_image_surface_span_renderer { +typedef struct _legacy_image_surface_span_renderer { cairo_span_renderer_t base; cairo_operator_t op; const cairo_pattern_t *pattern; cairo_antialias_t antialias; + cairo_region_t *clip_region; + pixman_image_t *mask; uint8_t *mask_data; uint32_t mask_stride; - cairo_image_surface_t *src; - cairo_surface_attributes_t src_attributes; - cairo_image_surface_t *mask; cairo_image_surface_t *dst; cairo_composite_rectangles_t composite_rectangles; -} cairo_image_surface_span_renderer_t; +} legacy_image_surface_span_renderer_t; void _cairo_image_surface_span_render_row ( @@ -1462,7 +4464,7 @@ _cairo_image_surface_span_renderer_render_rows ( const cairo_half_open_span_t *spans, unsigned num_spans) { - cairo_image_surface_span_renderer_t *renderer = abstract_renderer; + legacy_image_surface_span_renderer_t *renderer = abstract_renderer; while (height--) _cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride); return CAIRO_STATUS_SUCCESS; @@ -1471,17 +4473,11 @@ _cairo_image_surface_span_renderer_render_rows ( static void _cairo_image_surface_span_renderer_destroy (void *abstract_renderer) { - cairo_image_surface_span_renderer_t *renderer = abstract_renderer; - if (!renderer) return; + legacy_image_surface_span_renderer_t *renderer = abstract_renderer; + if (renderer == NULL) + return; - if (renderer->src != NULL) { - _cairo_pattern_release_surface (renderer->pattern, - &renderer->src->base, - &renderer->src_attributes); - } - - if (renderer->mask != NULL) - cairo_surface_destroy (&renderer->mask->base); + pixman_image_unref (renderer->mask); free (renderer); } @@ -1489,48 +4485,41 @@ _cairo_image_surface_span_renderer_destroy (void *abstract_renderer) static cairo_status_t _cairo_image_surface_span_renderer_finish (void *abstract_renderer) { - cairo_image_surface_span_renderer_t *renderer = abstract_renderer; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + legacy_image_surface_span_renderer_t *renderer = abstract_renderer; + cairo_composite_rectangles_t *rects = &renderer->composite_rectangles; + cairo_image_surface_t *dst = renderer->dst; + pixman_image_t *src; + int src_x, src_y; + cairo_status_t status; - if (renderer->src == NULL || renderer->mask == NULL) - return CAIRO_STATUS_SUCCESS; - - status = cairo_surface_status (&renderer->mask->base); - if (status == CAIRO_STATUS_SUCCESS) { - cairo_composite_rectangles_t *rects = &renderer->composite_rectangles; - cairo_image_surface_t *src = renderer->src; - cairo_image_surface_t *dst = renderer->dst; - cairo_surface_attributes_t *src_attributes = &renderer->src_attributes; - int width = rects->width; - int height = rects->height; - - pixman_image_composite (_pixman_operator (renderer->op), - src->pixman_image, - renderer->mask->pixman_image, - dst->pixman_image, - rects->src.x + src_attributes->x_offset, - rects->src.y + src_attributes->y_offset, - 0, 0, /* mask.x, mask.y */ - rects->dst.x, rects->dst.y, - width, height); - - if (! _cairo_operator_bounded_by_mask (renderer->op)) { - status = _cairo_surface_composite_shape_fixup_unbounded ( - &dst->base, - src_attributes, - src->width, src->height, - width, height, - rects->src.x, rects->src.y, - 0, 0, /* mask.x, mask.y */ - rects->dst.x, rects->dst.y, - width, height, - dst->clip_region); - } + if (renderer->clip_region != NULL) { + status = _cairo_image_surface_set_clip_region (dst, renderer->clip_region); + if (unlikely (status)) + return status; } - if (status != CAIRO_STATUS_SUCCESS) - return _cairo_span_renderer_set_error (abstract_renderer, - status); - return CAIRO_STATUS_SUCCESS; + + src = _pixman_image_for_pattern (renderer->pattern, FALSE, &rects->bounded, &src_x, &src_y); + if (src == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = CAIRO_STATUS_SUCCESS; + pixman_image_composite32 (_pixman_operator (renderer->op), + src, + renderer->mask, + dst->pixman_image, + rects->bounded.x + src_x, + rects->bounded.y + src_y, + 0, 0, + rects->bounded.x, rects->bounded.y, + rects->bounded.width, rects->bounded.height); + + if (! rects->is_bounded) + status = _cairo_image_surface_fixup_unbounded (dst, rects, NULL); + + if (renderer->clip_region != NULL) + _cairo_image_surface_unset_clip_region (dst); + + return status; } static cairo_bool_t @@ -1555,16 +4544,10 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op, cairo_region_t *clip_region) { cairo_image_surface_t *dst = abstract_dst; - cairo_image_surface_span_renderer_t *renderer = calloc(1, sizeof(*renderer)); - cairo_status_t status; - int width = rects->width; - int height = rects->height; + legacy_image_surface_span_renderer_t *renderer; - status = _cairo_image_surface_set_clip_region (dst, clip_region); - if (unlikely (status)) - return _cairo_span_renderer_create_in_error (status); - - if (renderer == NULL) + renderer = calloc(1, sizeof(*renderer)); + if (unlikely (renderer == NULL)) return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY); renderer->base.destroy = _cairo_image_surface_span_renderer_destroy; @@ -1574,67 +4557,27 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op, renderer->pattern = pattern; renderer->antialias = antialias; renderer->dst = dst; + renderer->clip_region = clip_region; renderer->composite_rectangles = *rects; - status = _cairo_pattern_acquire_surface ( - renderer->pattern, &renderer->dst->base, - rects->src.x, rects->src.y, - width, height, - CAIRO_PATTERN_ACQUIRE_NONE, - (cairo_surface_t **) &renderer->src, - &renderer->src_attributes); - if (status) - goto unwind; - - status = _cairo_image_surface_set_attributes ( - renderer->src, &renderer->src_attributes, - rects->dst.x + width/2, rects->dst.y + height/2); - if (status) - goto unwind; - /* TODO: support rendering to A1 surfaces (or: go add span * compositing to pixman.) */ - renderer->mask = (cairo_image_surface_t *) - cairo_image_surface_create (CAIRO_FORMAT_A8, - width, height); - - status = cairo_surface_status (&renderer->mask->base); - - unwind: - if (status != CAIRO_STATUS_SUCCESS) { - _cairo_image_surface_span_renderer_destroy (renderer); - return _cairo_span_renderer_create_in_error (status); + renderer->mask = pixman_image_create_bits (PIXMAN_a8, + rects->bounded.width, + rects->bounded.height, + NULL, 0); + if (renderer->mask == NULL) { + free (renderer); + return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY); } - renderer->mask_data = renderer->mask->data - rects->mask.x - rects->mask.y * renderer->mask->stride; - renderer->mask_stride = renderer->mask->stride; + renderer->mask_stride = pixman_image_get_stride (renderer->mask); + renderer->mask_data = (uint8_t *) pixman_image_get_data (renderer->mask) - rects->bounded.x - rects->bounded.y * renderer->mask_stride; + return &renderer->base; } -static cairo_bool_t -_cairo_image_surface_get_extents (void *abstract_surface, - cairo_rectangle_int_t *rectangle) -{ - cairo_image_surface_t *surface = abstract_surface; - - rectangle->x = 0; - rectangle->y = 0; - rectangle->width = surface->width; - rectangle->height = surface->height; - - return TRUE; -} - -static void -_cairo_image_surface_get_font_options (void *abstract_surface, - cairo_font_options_t *options) -{ - _cairo_font_options_init_default (options); - - cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON); -} - /** * _cairo_surface_is_image: * @surface: a #cairo_surface_t @@ -1663,6 +4606,7 @@ const cairo_surface_backend_t _cairo_image_surface_backend = { _cairo_image_surface_composite_trapezoids, _cairo_image_surface_create_span_renderer, _cairo_image_surface_check_span_renderer, + NULL, /* copy_page */ NULL, /* show_page */ _cairo_image_surface_get_extents, @@ -1673,11 +4617,12 @@ const cairo_surface_backend_t _cairo_image_surface_backend = { NULL, /* font_fini */ NULL, /* glyph_fini */ - NULL, /* paint */ - NULL, /* mask */ - NULL, /* stroke */ - NULL, /* fill */ - NULL, /* show_glyphs */ + _cairo_image_surface_paint, + _cairo_image_surface_mask, + _cairo_image_surface_stroke, + _cairo_image_surface_fill, + _cairo_image_surface_glyphs, + NULL, /* show_text_glyphs */ NULL, /* snapshot */ NULL, /* is_similar */ }; @@ -1685,11 +4630,20 @@ const cairo_surface_backend_t _cairo_image_surface_backend = { /* A convenience function for when one needs to coerce an image * surface to an alternate format. */ cairo_image_surface_t * -_cairo_image_surface_coerce (cairo_image_surface_t *surface, - cairo_format_t format) +_cairo_image_surface_coerce (cairo_image_surface_t *surface) +{ + return _cairo_image_surface_coerce_to_format (surface, + _cairo_format_from_content (surface->base.content)); + +} + +/* A convenience function for when one needs to coerce an image + * surface to an alternate format. */ +cairo_image_surface_t * +_cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface, + cairo_format_t format) { cairo_image_surface_t *clone; - cairo_surface_pattern_t pattern; cairo_status_t status; status = surface->base.status; @@ -1704,17 +4658,13 @@ _cairo_image_surface_coerce (cairo_image_surface_t *surface, if (unlikely (clone->base.status)) return clone; - _cairo_pattern_init_for_surface (&pattern, &surface->base); - status = _cairo_surface_paint (&clone->base, - CAIRO_OPERATOR_SOURCE, - &pattern.base, - NULL); - _cairo_pattern_fini (&pattern.base); - - if (unlikely (status)) { - cairo_surface_destroy (&clone->base); - return (cairo_image_surface_t *)_cairo_surface_create_in_error (status); - } + pixman_image_composite32 (PIXMAN_OP_SRC, + surface->pixman_image, NULL, clone->pixman_image, + 0, 0, + 0, 0, + 0, 0, + surface->width, surface->height); + clone->base.is_clear = FALSE; clone->base.device_transform = surface->base.device_transform; diff --git a/gfx/cairo/cairo/src/cairo-list-private.h b/gfx/cairo/cairo/src/cairo-list-private.h index b8254bb74dc2..ddfd0a4c6d44 100644 --- a/gfx/cairo/cairo/src/cairo-list-private.h +++ b/gfx/cairo/cairo/src/cairo-list-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -73,19 +73,38 @@ typedef struct _cairo_list { &pos->member != (head); \ pos = cairo_list_entry(pos->member.prev, type, member)) +#define cairo_list_foreach_entry_reverse_safe(pos, n, type, head, member) \ + for (pos = cairo_list_entry((head)->prev, type, member),\ + n = cairo_list_entry (pos->member.prev, type, member);\ + &pos->member != (head); \ + pos = n, n = cairo_list_entry (n->member.prev, type, member)) + #ifdef CAIRO_LIST_DEBUG static inline void +_cairo_list_validate (const cairo_list_t *link) +{ + assert (link->next->prev == link); + assert (link->prev->next == link); +} +static inline void cairo_list_validate (const cairo_list_t *head) { cairo_list_t *link; - cairo_list_foreach (link, head) { - assert (link->next->prev == link); - assert (link->prev->next == link); - } + cairo_list_foreach (link, head) + _cairo_list_validate (link); +} +static inline cairo_bool_t +cairo_list_is_empty (const cairo_list_t *head); +static inline void +cairo_list_validate_is_empty (const cairo_list_t *head) +{ + assert (head->next == NULL || (cairo_list_is_empty (head) && head->next == head->prev)); } #else +#define _cairo_list_validate(link) #define cairo_list_validate(head) +#define cairo_list_validate_is_empty(head) #endif static inline void @@ -110,6 +129,7 @@ static inline void cairo_list_add (cairo_list_t *entry, cairo_list_t *head) { cairo_list_validate (head); + cairo_list_validate_is_empty (entry); __cairo_list_add (entry, head, head->next); cairo_list_validate (head); } @@ -118,6 +138,7 @@ static inline void cairo_list_add_tail (cairo_list_t *entry, cairo_list_t *head) { cairo_list_validate (head); + cairo_list_validate_is_empty (entry); __cairo_list_add (entry, head->prev, head); cairo_list_validate (head); } @@ -157,10 +178,8 @@ cairo_list_move_tail (cairo_list_t *entry, cairo_list_t *head) static inline void cairo_list_swap (cairo_list_t *entry, cairo_list_t *other) { - cairo_list_validate (head); __cairo_list_add (entry, other->prev, other->next); cairo_list_init (other); - cairo_list_validate (head); } static inline cairo_bool_t @@ -186,4 +205,11 @@ cairo_list_is_empty (const cairo_list_t *head) return head->next == head; } +static inline cairo_bool_t +cairo_list_is_singular (const cairo_list_t *head) +{ + cairo_list_validate (head); + return head->next == head || head->next == head->prev; +} + #endif /* CAIRO_LIST_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-lzw.c b/gfx/cairo/cairo/src/cairo-lzw.c index a4fdf738f6fe..de7f99983763 100644 --- a/gfx/cairo/cairo/src/cairo-lzw.c +++ b/gfx/cairo/cairo/src/cairo-lzw.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -35,6 +35,7 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" typedef struct _lzw_buf { cairo_status_t status; diff --git a/gfx/cairo/cairo/src/cairo-malloc-private.h b/gfx/cairo/cairo/src/cairo-malloc-private.h index 082480826daf..e5776abd0c34 100644 --- a/gfx/cairo/cairo/src/cairo-malloc-private.h +++ b/gfx/cairo/cairo/src/cairo-malloc-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-matrix.c b/gfx/cairo/cairo/src/cairo-matrix.c index bf20ee4fc124..2536ebffddc2 100644 --- a/gfx/cairo/cairo/src/cairo-matrix.c +++ b/gfx/cairo/cairo/src/cairo-matrix.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -34,9 +34,8 @@ * Carl D. Worth */ -#define _GNU_SOURCE - #include "cairoint.h" +#include "cairo-error-private.h" #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE) #define ISFINITE(x) isfinite (x) @@ -44,6 +43,29 @@ #define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */ #endif +/** + * SECTION:cairo-matrix + * @Title: cairo_matrix_t + * @Short_Description: Generic matrix operations + * @See_Also: #cairo_t + * + * #cairo_matrix_t is used throughout cairo to convert between different + * coordinate spaces. A #cairo_matrix_t holds an affine transformation, + * such as a scale, rotation, shear, or a combination of these. + * The transformation of a point (x,y) + * is given by: + * + * + * x_new = xx * x + xy * y + x0; + * y_new = yx * x + yy * y + y0; + * + * + * The current transformation matrix of a #cairo_t, represented as a + * #cairo_matrix_t, defines the transformation from user-space + * coordinates to device-space coordinates. See cairo_get_matrix() and + * cairo_set_matrix(). + */ + static void _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar); @@ -579,6 +601,15 @@ _cairo_matrix_is_invertible (const cairo_matrix_t *matrix) return ISFINITE (det) && det != 0.; } +cairo_bool_t +_cairo_matrix_is_scale_0 (const cairo_matrix_t *matrix) +{ + return matrix->xx == 0. && + matrix->xy == 0. && + matrix->yx == 0. && + matrix->yy == 0.; +} + double _cairo_matrix_compute_determinant (const cairo_matrix_t *matrix) { @@ -916,7 +947,7 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, * that point. */ - if (_cairo_matrix_is_translation (matrix)) + if (_cairo_matrix_has_unity_scale (matrix)) return; /* Note: If we can't invert the transformation, skip the adjustment. */ diff --git a/gfx/cairo/cairo/src/cairo-misc.c b/gfx/cairo/cairo/src/cairo-misc.c index 56c7d0b5e6a8..603725955813 100644 --- a/gfx/cairo/cairo/src/cairo-misc.c +++ b/gfx/cairo/cairo/src/cairo-misc.c @@ -15,7 +15,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -39,10 +39,31 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" COMPILE_TIME_ASSERT (CAIRO_STATUS_LAST_STATUS < CAIRO_INT_STATUS_UNSUPPORTED); COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127); +/** + * SECTION:cairo-status + * @Title: Error handling + * @Short_Description: Decoding cairo's status + * @See_Also: cairo_status(), cairo_surface_status(), cairo_pattern_status(), + * cairo_font_face_status(), cairo_scaled_font_status(), + * cairo_region_status() + * + * Cairo uses a single status type to represent all kinds of errors. A status + * value of %CAIRO_STATUS_SUCCESS represents no error and has an integer value + * of zero. All other status values represent an error. + * + * Cairo's error handling is designed to be easy to use and safe. All major + * cairo objects retain an error status internally which + * can be queried anytime by the users using cairo*_status() calls. In + * the mean time, it is safe to call all cairo functions normally even if the + * underlying object is in an error status. This means that no error handling + * code is required before or after each individual cairo function call. + */ + /* Public stuff */ /** @@ -125,6 +146,10 @@ cairo_status_to_string (cairo_status_t status) return "invalid value (typically too big) for the size of the input (surface, pattern, etc.)"; case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: return "user-font method not implemented"; + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: + return "the device type is not appropriate for the operation"; + case CAIRO_STATUS_DEVICE_ERROR: + return "an operation to the device caused an unspecified error"; default: case CAIRO_STATUS_LAST_STATUS: return ""; @@ -416,7 +441,49 @@ _cairo_operator_bounded_by_source (cairo_operator_t op) return FALSE; } +uint32_t +_cairo_operator_bounded_by_either (cairo_operator_t op) +{ + switch (op) { + default: + ASSERT_NOT_REACHED; + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE; + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + return CAIRO_OPERATOR_BOUND_BY_MASK; + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_ATOP: + return 0; + } +} + +#if DISABLE_SOME_FLOATING_POINT /* This function is identical to the C99 function lround(), except that it * performs arithmetic rounding (floor(d + .5) instead of away-from-zero rounding) and * has a valid input range of (INT_MIN, INT_MAX] instead of @@ -627,6 +694,64 @@ _cairo_lround (double d) #undef MSW #undef LSW } +#endif + +/* Convert a 32-bit IEEE single precision floating point number to a + * 'half' representation (s10.5) + */ +uint16_t +_cairo_half_from_float (float f) +{ + union { + uint32_t ui; + float f; + } u; + int s, e, m; + + u.f = f; + s = (u.ui >> 16) & 0x00008000; + e = ((u.ui >> 23) & 0x000000ff) - (127 - 15); + m = u.ui & 0x007fffff; + if (e <= 0) { + if (e < -10) { + /* underflow */ + return 0; + } + + m = (m | 0x00800000) >> (1 - e); + + /* round to nearest, round 0.5 up. */ + if (m & 0x00001000) + m += 0x00002000; + return s | (m >> 13); + } else if (e == 0xff - (127 - 15)) { + if (m == 0) { + /* infinity */ + return s | 0x7c00; + } else { + /* nan */ + m >>= 13; + return s | 0x7c00 | m | (m == 0); + } + } else { + /* round to nearest, round 0.5 up. */ + if (m & 0x00001000) { + m += 0x00002000; + + if (m & 0x00800000) { + m = 0; + e += 1; + } + } + + if (e > 30) { + /* overflow -> infinity */ + return s | 0x7c00; + } + + return s | (e << 10) | (m >> 13); + } +} #ifdef _WIN32 diff --git a/gfx/cairo/cairo/src/cairo-mutex-impl-private.h b/gfx/cairo/cairo/src/cairo-mutex-impl-private.h index 06938b5a5f6e..25223f3eac0b 100644 --- a/gfx/cairo/cairo/src/cairo-mutex-impl-private.h +++ b/gfx/cairo/cairo/src/cairo-mutex-impl-private.h @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -168,6 +168,13 @@ # define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex) # define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0 +# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1 + + typedef int cairo_recursive_mutex_impl_t; + +# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) +# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER 0 + #elif defined(_WIN32) /******************************************************/ #define WIN32_LEAN_AND_MEAN @@ -221,6 +228,7 @@ # include typedef pthread_mutex_t cairo_mutex_impl_t; + typedef pthread_mutex_t cairo_recursive_mutex_impl_t; # define CAIRO_MUTEX_IMPL_PTHREAD 1 #if HAVE_LOCKDEP @@ -239,11 +247,31 @@ #endif # define CAIRO_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER +# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1 +# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) do { \ + pthread_mutexattr_t attr; \ + pthread_mutexattr_init (&attr); \ + pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); \ + pthread_mutex_init (&(mutex), &attr); \ + pthread_mutexattr_destroy (&attr); \ +} while (0) +# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP #else /**********************************************************************/ # error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support." +#endif + +/* By default mutex implementations are assumed to be recursive */ +#if ! CAIRO_MUTEX_HAS_RECURSIVE_IMPL + +# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1 + + typedef cairo_mutex_impl_t cairo_recursive_mutex_impl_t; + +# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) CAIRO_MUTEX_IMPL_INIT(mutex) +# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER #endif diff --git a/gfx/cairo/cairo/src/cairo-mutex-list-private.h b/gfx/cairo/cairo/src/cairo-mutex-list-private.h index 2f483163a7de..5827667f4ad0 100644 --- a/gfx/cairo/cairo/src/cairo-mutex-list-private.h +++ b/gfx/cairo/cairo/src/cairo-mutex-list-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,6 +38,9 @@ CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock) +CAIRO_MUTEX_DECLARE (_cairo_image_solid_cache_mutex) + +CAIRO_MUTEX_DECLARE (_cairo_error_mutex) CAIRO_MUTEX_DECLARE (_cairo_toy_font_face_mutex) CAIRO_MUTEX_DECLARE (_cairo_intern_string_mutex) CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex) @@ -52,6 +55,10 @@ CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex) CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex) #endif +#if CAIRO_HAS_XCB_SURFACE +CAIRO_MUTEX_DECLARE (_cairo_xcb_connections_mutex) +#endif + #if CAIRO_HAS_GL_SURFACE CAIRO_MUTEX_DECLARE (_cairo_gl_context_mutex) #endif diff --git a/gfx/cairo/cairo/src/cairo-mutex-private.h b/gfx/cairo/cairo/src/cairo-mutex-private.h index a3a7271f2dfb..61a7160a066c 100644 --- a/gfx/cairo/cairo/src/cairo-mutex-private.h +++ b/gfx/cairo/cairo/src/cairo-mutex-private.h @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-mutex-type-private.h b/gfx/cairo/cairo/src/cairo-mutex-type-private.h index adf17bbedc5d..e8c493985c9c 100644 --- a/gfx/cairo/cairo/src/cairo-mutex-type-private.h +++ b/gfx/cairo/cairo/src/cairo-mutex-type-private.h @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -44,7 +44,7 @@ #include "cairo-compiler-private.h" #include "cairo-mutex-impl-private.h" -/* Only the following three are mandatory at this point */ +/* Only the following four are mandatory at this point */ #ifndef CAIRO_MUTEX_IMPL_LOCK # error "CAIRO_MUTEX_IMPL_LOCK not defined. Check cairo-mutex-impl-private.h." #endif @@ -54,6 +54,9 @@ #ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER # error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined. Check cairo-mutex-impl-private.h." #endif +#ifndef CAIRO_RECURSIVE_MUTEX_IMPL_INIT +# error "CAIRO_RECURSIVE_MUTEX_IMPL_INIT not defined. Check cairo-mutex-impl-private.h." +#endif /* make sure implementations don't fool us: we decide these ourself */ @@ -156,6 +159,7 @@ #ifndef CAIRO_MUTEX_DEBUG typedef cairo_mutex_impl_t cairo_mutex_t; +typedef cairo_recursive_mutex_impl_t cairo_recursive_mutex_t; #else # define cairo_mutex_t cairo_mutex_impl_t #endif @@ -168,6 +172,9 @@ typedef cairo_mutex_impl_t cairo_mutex_t; #define CAIRO_MUTEX_FINI CAIRO_MUTEX_IMPL_FINI #define CAIRO_MUTEX_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER +#define CAIRO_RECURSIVE_MUTEX_INIT CAIRO_RECURSIVE_MUTEX_IMPL_INIT +#define CAIRO_RECURSIVE_MUTEX_NIL_INITIALIZER CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER + #ifndef CAIRO_MUTEX_IS_LOCKED # define CAIRO_MUTEX_IS_LOCKED(name) 1 #endif diff --git a/gfx/cairo/cairo/src/cairo-mutex.c b/gfx/cairo/cairo/src/cairo-mutex.c index 5b6a6e150281..0a31dced3e1b 100644 --- a/gfx/cairo/cairo/src/cairo-mutex.c +++ b/gfx/cairo/cairo/src/cairo-mutex.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-observer.c b/gfx/cairo/cairo/src/cairo-observer.c new file mode 100644 index 000000000000..7c7b69c91f0a --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-observer.c @@ -0,0 +1,50 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2010 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +void +_cairo_observers_notify (cairo_list_t *observers, void *arg) +{ + cairo_observer_t *obs, *next; + + cairo_list_foreach_entry_safe (obs, next, + cairo_observer_t, + observers, link) + { + obs->callback (obs, arg); + } +} diff --git a/gfx/cairo/cairo/src/cairo-os2-private.h b/gfx/cairo/cairo/src/cairo-os2-private.h index 6c8e8f48b05b..829dd3c8d41f 100644 --- a/gfx/cairo/cairo/src/cairo-os2-private.h +++ b/gfx/cairo/cairo/src/cairo-os2-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-os2-surface.c b/gfx/cairo/cairo/src/cairo-os2-surface.c index 379cb25592b7..b9758281dca0 100644 --- a/gfx/cairo/cairo/src/cairo-os2-surface.c +++ b/gfx/cairo/cairo/src/cairo-os2-surface.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -39,6 +39,7 @@ #include "cairoint.h" #include "cairo-os2-private.h" +#include "cairo-error-private.h" #if CAIRO_HAS_FC_FONT #include @@ -782,7 +783,7 @@ cairo_os2_surface_create (HPS hps_client_window, 0, FALSE)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR); goto error_exit; } @@ -791,7 +792,7 @@ cairo_os2_surface_create (HPS hps_client_window, 0, FALSE)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR); goto error_exit; } @@ -829,6 +830,7 @@ cairo_os2_surface_create (HPS hps_client_window, /* Initialize base surface */ _cairo_surface_init (&local_os2_surface->base, &cairo_os2_surface_backend, + NULL, /* device */ _cairo_content_from_format (CAIRO_FORMAT_ARGB32)); /* Successful exit */ diff --git a/gfx/cairo/cairo/src/cairo-os2.h b/gfx/cairo/cairo/src/cairo-os2.h index cbb342b09ec1..d23f2dec42ad 100644 --- a/gfx/cairo/cairo/src/cairo-os2.h +++ b/gfx/cairo/cairo/src/cairo-os2.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-output-stream-private.h b/gfx/cairo/cairo/src/cairo-output-stream-private.h index 5243d21806b5..edaabbe78e51 100644 --- a/gfx/cairo/cairo/src/cairo-output-stream-private.h +++ b/gfx/cairo/cairo/src/cairo-output-stream-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -175,7 +175,7 @@ _cairo_memory_stream_length (cairo_output_stream_t *stream); cairo_private cairo_status_t _cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream, unsigned char **data_out, - unsigned int *length_out); + unsigned long *length_out); cairo_private cairo_output_stream_t * _cairo_null_stream_create (void); diff --git a/gfx/cairo/cairo/src/cairo-output-stream.c b/gfx/cairo/cairo/src/cairo-output-stream.c index 8616e4c2b1b3..1aabe821afa4 100644 --- a/gfx/cairo/cairo/src/cairo-output-stream.c +++ b/gfx/cairo/cairo/src/cairo-output-stream.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,6 +37,7 @@ #include "cairoint.h" #include "cairo-output-stream-private.h" +#include "cairo-error-private.h" #include "cairo-compiler-private.h" #include @@ -694,7 +695,7 @@ _cairo_memory_stream_create (void) cairo_status_t _cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream, unsigned char **data_out, - unsigned int *length_out) + unsigned long *length_out) { memory_stream_t *stream; cairo_status_t status; diff --git a/gfx/cairo/cairo/src/cairo-paginated-private.h b/gfx/cairo/cairo/src/cairo-paginated-private.h index 33358b98ea33..42badbfdfe1e 100644 --- a/gfx/cairo/cairo/src/cairo-paginated-private.h +++ b/gfx/cairo/cairo/src/cairo-paginated-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-paginated-surface-private.h b/gfx/cairo/cairo/src/cairo-paginated-surface-private.h index a494e581d164..ebf4b3424920 100644 --- a/gfx/cairo/cairo/src/cairo-paginated-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-paginated-surface-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -57,7 +57,6 @@ typedef struct _cairo_paginated_surface { cairo_surface_t *recording_surface; int page_num; - cairo_bool_t page_is_blank; } cairo_paginated_surface_t; #endif /* CAIRO_PAGINATED_SURFACE_H */ diff --git a/gfx/cairo/cairo/src/cairo-paginated-surface.c b/gfx/cairo/cairo/src/cairo-paginated-surface.c index dff5e8313502..af4790e7ea99 100644 --- a/gfx/cairo/cairo/src/cairo-paginated-surface.c +++ b/gfx/cairo/cairo/src/cairo-paginated-surface.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -48,6 +48,7 @@ #include "cairo-paginated-surface-private.h" #include "cairo-recording-surface-private.h" #include "cairo-analysis-surface-private.h" +#include "cairo-error-private.h" static const cairo_surface_backend_t cairo_paginated_surface_backend; @@ -101,7 +102,9 @@ _cairo_paginated_surface_create (cairo_surface_t *target, goto FAIL; } - _cairo_surface_init (&surface->base, &cairo_paginated_surface_backend, + _cairo_surface_init (&surface->base, + &cairo_paginated_surface_backend, + NULL, /* device */ content); /* Override surface->base.type with target's type so we don't leak @@ -119,7 +122,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target, goto FAIL_CLEANUP_SURFACE; surface->page_num = 1; - surface->page_is_blank = TRUE; + surface->base.is_clear = TRUE; return &surface->base; @@ -154,9 +157,11 @@ _cairo_paginated_surface_finish (void *abstract_surface) cairo_paginated_surface_t *surface = abstract_surface; cairo_status_t status = CAIRO_STATUS_SUCCESS; - if (surface->page_is_blank == FALSE || surface->page_num == 1) { - cairo_surface_show_page (abstract_surface); - status = cairo_surface_status (abstract_surface); + if (! surface->base.is_clear || surface->page_num == 1) { + /* Bypass some of the sanity checking in cairo-surface.c, as we + * know that the surface is finished... + */ + status = _cairo_paginated_surface_show_page (surface); } /* XXX We want to propagate any errors from destroy(), but those are not @@ -164,11 +169,10 @@ _cairo_paginated_surface_finish (void *abstract_surface) * and check the status afterwards. However, we can only call finish() * on the target, if we own it. */ - if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1) { + if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1) cairo_surface_finish (surface->target); - if (status == CAIRO_STATUS_SUCCESS) - status = cairo_surface_status (surface->target); - } + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_surface_status (surface->target); cairo_surface_destroy (surface->target); cairo_surface_finish (surface->recording_surface); @@ -272,17 +276,17 @@ _paint_fallback_image (cairo_paginated_surface_t *surface, * filtering (if possible) to avoid introducing potential artifacts. */ pattern.base.filter = CAIRO_FILTER_NEAREST; - status = _cairo_clip_init_rectangle (&clip, rect); - if (unlikely (status)) - goto CLEANUP_IMAGE; - - status = _cairo_surface_paint (surface->target, - CAIRO_OPERATOR_SOURCE, - &pattern.base, &clip); - - _cairo_clip_reset (&clip); + _cairo_clip_init (&clip); + status = _cairo_clip_rectangle (&clip, rect); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _cairo_surface_paint (surface->target, + CAIRO_OPERATOR_SOURCE, + &pattern.base, &clip); + } + _cairo_clip_fini (&clip); _cairo_pattern_fini (&pattern.base); + CLEANUP_IMAGE: cairo_surface_destroy (image); @@ -357,6 +361,7 @@ _paint_page (cairo_paginated_surface_t *surface) CAIRO_PAGINATED_MODE_RENDER); status = _cairo_recording_surface_replay_region (surface->recording_surface, + NULL, surface->target, CAIRO_RECORDING_REGION_NATIVE); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); @@ -471,16 +476,18 @@ _cairo_paginated_surface_show_page (void *abstract_surface) if (unlikely (status)) return status; - cairo_surface_destroy (surface->recording_surface); + if (! surface->base.finished) { + cairo_surface_destroy (surface->recording_surface); - surface->recording_surface = _create_recording_surface_for_target (surface->target, - surface->content); - status = surface->recording_surface->status; - if (unlikely (status)) - return status; + surface->recording_surface = _create_recording_surface_for_target (surface->target, + surface->content); + status = surface->recording_surface->status; + if (unlikely (status)) + return status; - surface->page_num++; - surface->page_is_blank = TRUE; + surface->page_num++; + surface->base.is_clear = TRUE; + } return CAIRO_STATUS_SUCCESS; } @@ -511,12 +518,6 @@ _cairo_paginated_surface_paint (void *abstract_surface, { cairo_paginated_surface_t *surface = abstract_surface; - /* Optimize away erasing of nothing. */ - if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR) - return CAIRO_STATUS_SUCCESS; - - surface->page_is_blank = FALSE; - return _cairo_surface_paint (surface->recording_surface, op, source, clip); } @@ -529,12 +530,6 @@ _cairo_paginated_surface_mask (void *abstract_surface, { cairo_paginated_surface_t *surface = abstract_surface; - /* Optimize away erasing of nothing. */ - if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR) - return CAIRO_STATUS_SUCCESS; - - surface->page_is_blank = FALSE; - return _cairo_surface_mask (surface->recording_surface, op, source, mask, clip); } @@ -543,21 +538,15 @@ _cairo_paginated_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) { cairo_paginated_surface_t *surface = abstract_surface; - /* Optimize away erasing of nothing. */ - if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR) - return CAIRO_STATUS_SUCCESS; - - surface->page_is_blank = FALSE; - return _cairo_surface_stroke (surface->recording_surface, op, source, path, style, ctm, ctm_inverse, @@ -577,12 +566,6 @@ _cairo_paginated_surface_fill (void *abstract_surface, { cairo_paginated_surface_t *surface = abstract_surface; - /* Optimize away erasing of nothing. */ - if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR) - return CAIRO_STATUS_SUCCESS; - - surface->page_is_blank = FALSE; - return _cairo_surface_fill (surface->recording_surface, op, source, path, fill_rule, tolerance, antialias, @@ -613,12 +596,6 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface, { cairo_paginated_surface_t *surface = abstract_surface; - /* Optimize away erasing of nothing. */ - if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR) - return CAIRO_STATUS_SUCCESS; - - surface->page_is_blank = FALSE; - return _cairo_surface_show_text_glyphs (surface->recording_surface, op, source, utf8, utf8_len, glyphs, num_glyphs, diff --git a/gfx/cairo/cairo/src/cairo-path-bounds.c b/gfx/cairo/cairo/src/cairo-path-bounds.c index d3bc449a984d..b7766494e316 100644 --- a/gfx/cairo/cairo/src/cairo-path-bounds.c +++ b/gfx/cairo/cairo/src/cairo-path-bounds.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -35,6 +35,7 @@ */ #include "cairoint.h" +#include "cairo-path-fixed-private.h" typedef struct cairo_path_bounder { cairo_point_t current_point; @@ -134,26 +135,6 @@ _cairo_path_bounder_curve_to (void *closure, } } -static cairo_status_t -_cairo_path_bounder_curve_to_cp (void *closure, - const cairo_point_t *b, - const cairo_point_t *c, - const cairo_point_t *d) -{ - cairo_path_bounder_t *bounder = closure; - - if (bounder->has_initial_point) { - _cairo_path_bounder_add_point (bounder, &bounder->current_point); - bounder->has_initial_point = FALSE; - } - - _cairo_path_bounder_add_point (bounder, b); - _cairo_path_bounder_add_point (bounder, c); - _cairo_path_bounder_add_point (bounder, d); - - return CAIRO_STATUS_SUCCESS; -} - static cairo_status_t _cairo_path_bounder_close_path (void *closure) { @@ -168,21 +149,8 @@ void _cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path, cairo_rectangle_int_t *extents) { - cairo_path_bounder_t bounder; - cairo_status_t status; - - _cairo_path_bounder_init (&bounder); - - status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, - _cairo_path_bounder_move_to, - _cairo_path_bounder_line_to, - _cairo_path_bounder_curve_to_cp, - _cairo_path_bounder_close_path, - &bounder); - assert (status == CAIRO_STATUS_SUCCESS); - - if (bounder.has_point) { - _cairo_box_round_to_rectangle (&bounder.extents, extents); + if (path->extents.p1.x < path->extents.p2.x) { + _cairo_box_round_to_rectangle (&path->extents, extents); } else { extents->x = extents->y = 0; extents->width = extents->height = 0; @@ -199,15 +167,20 @@ _cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path, cairo_path_bounder_t bounder; cairo_status_t status; - _cairo_path_bounder_init (&bounder); + if (! path->has_curve_to) { + bounder.extents = path->extents; + bounder.has_point = path->extents.p1.x < path->extents.p2.x; + } else { + _cairo_path_bounder_init (&bounder); - status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, - _cairo_path_bounder_move_to, - _cairo_path_bounder_line_to, - _cairo_path_bounder_curve_to, - _cairo_path_bounder_close_path, - &bounder); - assert (status == CAIRO_STATUS_SUCCESS); + status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, + _cairo_path_bounder_move_to, + _cairo_path_bounder_line_to, + _cairo_path_bounder_curve_to, + _cairo_path_bounder_close_path, + &bounder); + assert (status == CAIRO_STATUS_SUCCESS); + } if (bounder.has_point) { _cairo_box_round_to_rectangle (&bounder.extents, extents); @@ -226,14 +199,19 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path, cairo_path_bounder_t bounder; cairo_status_t status; - _cairo_path_bounder_init (&bounder); + if (! path->has_curve_to) { + bounder.extents = path->extents; + bounder.has_point = path->extents.p1.x < path->extents.p2.x; + } else { + _cairo_path_bounder_init (&bounder); - status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD, - _cairo_path_bounder_move_to, - _cairo_path_bounder_line_to, - _cairo_path_bounder_close_path, - &bounder, tolerance); - assert (status == CAIRO_STATUS_SUCCESS); + status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD, + _cairo_path_bounder_move_to, + _cairo_path_bounder_line_to, + _cairo_path_bounder_close_path, + &bounder, tolerance); + assert (status == CAIRO_STATUS_SUCCESS); + } if (bounder.has_point) { _cairo_box_round_to_rectangle (&bounder.extents, extents); @@ -246,22 +224,44 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path, /* Adjusts the fill extents (above) by the device-space pen. */ void _cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path, - cairo_stroke_style_t *style, + const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, cairo_rectangle_int_t *extents) { cairo_path_bounder_t bounder; cairo_status_t status; - _cairo_path_bounder_init (&bounder); + if (! path->has_curve_to) { + bounder.extents = path->extents; - status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, - _cairo_path_bounder_move_to, - _cairo_path_bounder_line_to, - _cairo_path_bounder_curve_to, - _cairo_path_bounder_close_path, - &bounder); - assert (status == CAIRO_STATUS_SUCCESS); + /* include trailing move-to for degenerate segments */ + if (path->has_last_move_point) { + const cairo_point_t *point = &path->last_move_point; + + if (point->x < bounder.extents.p1.x) + bounder.extents.p1.x = point->x; + if (point->y < bounder.extents.p1.y) + bounder.extents.p1.y = point->y; + + if (point->x > bounder.extents.p2.x) + bounder.extents.p2.x = point->x; + if (point->y > bounder.extents.p2.y) + bounder.extents.p2.y = point->y; + } + + bounder.has_point = bounder.extents.p1.x <= bounder.extents.p2.x; + bounder.has_initial_point = FALSE; + } else { + _cairo_path_bounder_init (&bounder); + + status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, + _cairo_path_bounder_move_to, + _cairo_path_bounder_line_to, + _cairo_path_bounder_curve_to, + _cairo_path_bounder_close_path, + &bounder); + assert (status == CAIRO_STATUS_SUCCESS); + } if (bounder.has_point) { double dx, dy; @@ -294,12 +294,12 @@ _cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path, } cairo_status_t -_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, - const cairo_matrix_t *ctm, - const cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_rectangle_int_t *extents) +_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_rectangle_int_t *extents) { cairo_traps_t traps; cairo_box_t bbox; @@ -322,14 +322,18 @@ _cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path, return status; } -void -_cairo_path_fixed_bounds (const cairo_path_fixed_t *path, - double *x1, double *y1, - double *x2, double *y2) +cairo_bool_t +_cairo_path_fixed_extents (const cairo_path_fixed_t *path, + cairo_box_t *box) { cairo_path_bounder_t bounder; cairo_status_t status; + if (! path->has_curve_to) { + *box = path->extents; + return path->extents.p1.x <= path->extents.p2.x; + } + _cairo_path_bounder_init (&bounder); status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD, @@ -340,15 +344,6 @@ _cairo_path_fixed_bounds (const cairo_path_fixed_t *path, &bounder); assert (status == CAIRO_STATUS_SUCCESS); - if (bounder.has_point) { - *x1 = _cairo_fixed_to_double (bounder.extents.p1.x); - *y1 = _cairo_fixed_to_double (bounder.extents.p1.y); - *x2 = _cairo_fixed_to_double (bounder.extents.p2.x); - *y2 = _cairo_fixed_to_double (bounder.extents.p2.y); - } else { - *x1 = 0.0; - *y1 = 0.0; - *x2 = 0.0; - *y2 = 0.0; - } + *box = bounder.extents; + return bounder.has_point; } diff --git a/gfx/cairo/cairo/src/cairo-path-fill.c b/gfx/cairo/cairo/src/cairo-path-fill.c index 037b8078ea05..24aaa3969c56 100644 --- a/gfx/cairo/cairo/src/cairo-path-fill.c +++ b/gfx/cairo/cairo/src/cairo-path-fill.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -35,6 +35,8 @@ */ #include "cairoint.h" +#include "cairo-boxes-private.h" +#include "cairo-error-private.h" #include "cairo-path-fixed-private.h" #include "cairo-region-private.h" @@ -141,7 +143,8 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path, return CAIRO_STATUS_SUCCESS; _cairo_polygon_init (&polygon); - _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits); + if (traps->num_limits) + _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits); status = _cairo_path_fixed_fill_to_polygon (path, tolerance, @@ -217,11 +220,8 @@ _cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_ CLEANUP_TRAPS: _cairo_traps_fini (&traps); - if (unlikely (status)) { /* XXX _cairo_region_create_in_error() */ - region = cairo_region_create (); - if (likely (region->status) == CAIRO_STATUS_SUCCESS) - region->status = status; - } + if (unlikely (status)) + region = _cairo_region_create_in_error (status); return region; } @@ -391,3 +391,75 @@ _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path, return CAIRO_INT_STATUS_UNSUPPORTED; } } + +static cairo_status_t +_cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + cairo_boxes_t *boxes) +{ + cairo_polygon_t polygon; + cairo_status_t status; + + _cairo_polygon_init (&polygon); + if (boxes->num_limits) { + _cairo_polygon_limit (&polygon, boxes->limits, boxes->num_limits); + boxes->num_limits = 0; + } + + /* tolerance will be ignored as the path is rectilinear */ + status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = + _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (&polygon, + fill_rule, + boxes); + } + + _cairo_polygon_fini (&polygon); + + return status; +} + +cairo_status_t +_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + cairo_boxes_t *boxes) +{ + cairo_path_fixed_iter_t iter; + cairo_status_t status; + cairo_box_t box; + + if (_cairo_path_fixed_is_box (path, &box)) + return _cairo_boxes_add (boxes, &box); + + _cairo_path_fixed_iter_init (&iter, path); + while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) { + if (box.p1.y == box.p2.y || box.p1.x == box.p2.x) + continue; + + if (box.p1.y > box.p2.y) { + cairo_fixed_t t; + + t = box.p1.y; + box.p1.y = box.p2.y; + box.p2.y = t; + + t = box.p1.x; + box.p1.x = box.p2.x; + box.p2.x = t; + } + + status = _cairo_boxes_add (boxes, &box); + if (unlikely (status)) + return status; + } + + if (_cairo_path_fixed_iter_at_end (&iter)) + return _cairo_bentley_ottmann_tessellate_boxes (boxes, fill_rule, boxes); + + /* path is not rectangular, try extracting clipped rectilinear edges */ + _cairo_boxes_clear (boxes); + return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path, + fill_rule, + boxes); +} diff --git a/gfx/cairo/cairo/src/cairo-path-fixed-private.h b/gfx/cairo/cairo/src/cairo-path-fixed-private.h index 08b7a0623255..42e64eda35c4 100644 --- a/gfx/cairo/cairo/src/cairo-path-fixed-private.h +++ b/gfx/cairo/cairo/src/cairo-path-fixed-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -61,9 +61,10 @@ typedef char cairo_path_op_t; typedef struct _cairo_path_buf { cairo_list_t link; - unsigned int buf_size; unsigned int num_ops; + unsigned int size_ops; unsigned int num_points; + unsigned int size_points; cairo_path_op_t *op; cairo_point_t *points; @@ -80,15 +81,17 @@ struct _cairo_path_fixed { cairo_point_t last_move_point; cairo_point_t current_point; unsigned int has_current_point : 1; + unsigned int has_last_move_point : 1; unsigned int has_curve_to : 1; unsigned int is_rectilinear : 1; unsigned int maybe_fill_region : 1; unsigned int is_empty_fill : 1; + cairo_box_t extents; + cairo_path_buf_fixed_t buf; }; - cairo_private void _cairo_path_fixed_translate (cairo_path_fixed_t *path, cairo_fixed_t offx, diff --git a/gfx/cairo/cairo/src/cairo-path-fixed.c b/gfx/cairo/cairo/src/cairo-path-fixed.c index 34de6a37bd77..eea8630bd445 100644 --- a/gfx/cairo/cairo/src/cairo-path-fixed.c +++ b/gfx/cairo/cairo/src/cairo-path-fixed.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,6 +38,7 @@ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-path-fixed-private.h" #include "cairo-slope-private.h" @@ -52,7 +53,7 @@ _cairo_path_fixed_add_buf (cairo_path_fixed_t *path, cairo_path_buf_t *buf); static cairo_path_buf_t * -_cairo_path_buf_create (int buf_size); +_cairo_path_buf_create (int size_ops, int size_points); static void _cairo_path_buf_destroy (cairo_path_buf_t *buf); @@ -88,18 +89,23 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path) path->buf.base.num_ops = 0; path->buf.base.num_points = 0; - path->buf.base.buf_size = CAIRO_PATH_BUF_SIZE; + path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op); + path->buf.base.size_points = ARRAY_LENGTH (path->buf.points); path->buf.base.op = path->buf.op; path->buf.base.points = path->buf.points; path->current_point.x = 0; path->current_point.y = 0; path->last_move_point = path->current_point; + path->has_last_move_point = FALSE; path->has_current_point = FALSE; path->has_curve_to = FALSE; path->is_rectilinear = TRUE; path->maybe_fill_region = TRUE; path->is_empty_fill = TRUE; + + path->extents.p1.x = path->extents.p1.y = INT_MAX; + path->extents.p2.x = path->extents.p2.y = INT_MIN; } cairo_status_t @@ -107,7 +113,7 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, const cairo_path_fixed_t *other) { cairo_path_buf_t *buf, *other_buf; - unsigned int num_points, num_ops, buf_size; + unsigned int num_points, num_ops; VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t))); @@ -115,18 +121,22 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, path->buf.base.op = path->buf.op; path->buf.base.points = path->buf.points; + path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op); + path->buf.base.size_points = ARRAY_LENGTH (path->buf.points); path->current_point = other->current_point; path->last_move_point = other->last_move_point; + path->has_last_move_point = other->has_last_move_point; path->has_current_point = other->has_current_point; path->has_curve_to = other->has_curve_to; path->is_rectilinear = other->is_rectilinear; path->maybe_fill_region = other->maybe_fill_region; path->is_empty_fill = other->is_empty_fill; + path->extents = other->extents; + path->buf.base.num_ops = other->buf.base.num_ops; path->buf.base.num_points = other->buf.base.num_points; - path->buf.base.buf_size = other->buf.base.buf_size; memcpy (path->buf.op, other->buf.base.op, other->buf.base.num_ops * sizeof (other->buf.op[0])); memcpy (path->buf.points, other->buf.points, @@ -141,9 +151,8 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, num_points += other_buf->num_points; } - buf_size = MAX (num_ops, (num_points + 1) / 2); - if (buf_size) { - buf = _cairo_path_buf_create (buf_size); + if (num_ops) { + buf = _cairo_path_buf_create (num_ops, num_points); if (unlikely (buf == NULL)) { _cairo_path_fixed_fini (path); return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -175,6 +184,8 @@ _cairo_path_fixed_hash (const cairo_path_fixed_t *path) const cairo_path_buf_t *buf; int num_points, num_ops; + hash = _cairo_hash_bytes (hash, &path->extents, sizeof (path->extents)); + num_ops = num_points = 0; cairo_path_foreach_buf_start (buf, path) { hash = _cairo_hash_bytes (hash, buf->op, @@ -230,21 +241,25 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a, return FALSE; } - num_ops_a = num_points_a = 0; - if (a != NULL) { - cairo_path_foreach_buf_start (buf_a, a) { - num_ops_a += buf_a->num_ops; - num_points_a += buf_a->num_points; - } cairo_path_foreach_buf_end (buf_a, a); + if (a->extents.p1.x != b->extents.p1.x || + a->extents.p1.y != b->extents.p1.y || + a->extents.p2.x != b->extents.p2.x || + a->extents.p2.y != b->extents.p2.y) + { + return FALSE; } + num_ops_a = num_points_a = 0; + cairo_path_foreach_buf_start (buf_a, a) { + num_ops_a += buf_a->num_ops; + num_points_a += buf_a->num_points; + } cairo_path_foreach_buf_end (buf_a, a); + num_ops_b = num_points_b = 0; - if (b != NULL) { - cairo_path_foreach_buf_start (buf_b, b) { - num_ops_b += buf_b->num_ops; - num_points_b += buf_b->num_points; - } cairo_path_foreach_buf_end (buf_b, b); - } + cairo_path_foreach_buf_start (buf_b, b) { + num_ops_b += buf_b->num_ops; + num_points_b += buf_b->num_points; + } cairo_path_foreach_buf_end (buf_b, b); if (num_ops_a == 0 && num_ops_b == 0) return TRUE; @@ -252,8 +267,6 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a, if (num_ops_a != num_ops_b || num_points_a != num_points_b) return FALSE; - assert (a != NULL && b != NULL); - buf_a = cairo_path_head (a); num_points_a = buf_a->num_points; num_ops_a = buf_a->num_ops; @@ -364,6 +377,21 @@ _cairo_path_last_op (cairo_path_fixed_t *path) return buf->op[buf->num_ops - 1]; } +static inline void +_cairo_path_fixed_extents_add (cairo_path_fixed_t *path, + const cairo_point_t *point) +{ + if (point->x < path->extents.p1.x) + path->extents.p1.x = point->x; + if (point->y < path->extents.p1.y) + path->extents.p1.y = point->y; + + if (point->x > path->extents.p2.x) + path->extents.p2.x = point->x; + if (point->y > path->extents.p2.y) + path->extents.p2.y = point->y; +} + cairo_status_t _cairo_path_fixed_move_to (cairo_path_fixed_t *path, cairo_fixed_t x, @@ -402,6 +430,7 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path, path->current_point = point; path->last_move_point = point; + path->has_last_move_point = TRUE; path->has_current_point = TRUE; return CAIRO_STATUS_SUCCESS; @@ -510,6 +539,11 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path, } path->current_point = point; + if (path->has_last_move_point) { + _cairo_path_fixed_extents_add (path, &path->last_move_point); + path->has_last_move_point = FALSE; + } + _cairo_path_fixed_extents_add (path, &point); return CAIRO_STATUS_SUCCESS; } @@ -556,6 +590,15 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path, path->is_rectilinear = FALSE; path->maybe_fill_region = FALSE; + /* coarse bounds */ + if (path->has_last_move_point) { + _cairo_path_fixed_extents_add (path, &path->last_move_point); + path->has_last_move_point = FALSE; + } + _cairo_path_fixed_extents_add (path, &point[0]); + _cairo_path_fixed_extents_add (path, &point[1]); + _cairo_path_fixed_extents_add (path, &point[2]); + return CAIRO_STATUS_SUCCESS; } @@ -640,10 +683,10 @@ _cairo_path_fixed_add (cairo_path_fixed_t *path, { cairo_path_buf_t *buf = cairo_path_tail (path); - if (buf->num_ops + 1 > buf->buf_size || - buf->num_points + num_points > 2 * buf->buf_size) + if (buf->num_ops + 1 > buf->size_ops || + buf->num_points + num_points > buf->size_points) { - buf = _cairo_path_buf_create (buf->buf_size * 2); + buf = _cairo_path_buf_create (buf->num_ops * 2, buf->num_points * 2); if (unlikely (buf == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -689,25 +732,23 @@ _cairo_path_fixed_add_buf (cairo_path_fixed_t *path, cairo_list_add_tail (&buf->link, &cairo_path_head (path)->link); } +COMPILE_TIME_ASSERT (sizeof (cairo_path_op_t) == 1); static cairo_path_buf_t * -_cairo_path_buf_create (int buf_size) +_cairo_path_buf_create (int size_ops, int size_points) { cairo_path_buf_t *buf; - /* adjust buf_size to ensure that buf->points is naturally aligned */ - buf_size += sizeof (double) - - ((buf_size + sizeof (cairo_path_buf_t)) & (sizeof (double)-1)); - buf = _cairo_malloc_ab_plus_c (buf_size, - sizeof (cairo_path_op_t) + - 2 * sizeof (cairo_point_t), - sizeof (cairo_path_buf_t)); + /* adjust size_ops to ensure that buf->points is naturally aligned */ + size_ops += sizeof (double) - ((sizeof (cairo_path_buf_t) + size_ops) % sizeof (double)); + buf = _cairo_malloc_ab_plus_c (size_points, sizeof (cairo_point_t), size_ops + sizeof (cairo_path_buf_t)); if (buf) { buf->num_ops = 0; buf->num_points = 0; - buf->buf_size = buf_size; + buf->size_ops = size_ops; + buf->size_points = size_points; buf->op = (cairo_path_op_t *) (buf + 1); - buf->points = (cairo_point_t *) (buf->op + buf_size); + buf->points = (cairo_point_t *) (buf->op + size_ops); } return buf; @@ -906,6 +947,12 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path, buf->points[i].y += offy; } } cairo_path_foreach_buf_end (buf, path); + + path->extents.p1.x = _cairo_fixed_mul (scalex, path->extents.p1.x) + offx; + path->extents.p2.x = _cairo_fixed_mul (scalex, path->extents.p2.x) + offx; + + path->extents.p1.y = _cairo_fixed_mul (scaley, path->extents.p1.y) + offy; + path->extents.p2.y = _cairo_fixed_mul (scaley, path->extents.p2.y) + offy; } void @@ -926,9 +973,9 @@ _cairo_path_fixed_translate (cairo_path_fixed_t *path, } path->last_move_point.x += offx; - path->last_move_point.y += offx; + path->last_move_point.y += offy; path->current_point.x += offx; - path->current_point.y += offx; + path->current_point.y += offy; cairo_path_foreach_buf_start (buf, path) { for (i = 0; i < buf->num_points; i++) { @@ -936,6 +983,11 @@ _cairo_path_fixed_translate (cairo_path_fixed_t *path, buf->points[i].y += offy; } } cairo_path_foreach_buf_end (buf, path); + + path->extents.p1.x += offx; + path->extents.p1.y += offy; + path->extents.p2.x += offx; + path->extents.p2.y += offy; } /** @@ -959,14 +1011,22 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path, if (matrix->yx == 0.0 && matrix->xy == 0.0) { /* Fast path for the common case of scale+transform */ - _cairo_path_fixed_offset_and_scale (path, - _cairo_fixed_from_double (matrix->x0), - _cairo_fixed_from_double (matrix->y0), - _cairo_fixed_from_double (matrix->xx), - _cairo_fixed_from_double (matrix->yy)); + if (matrix->xx == 1. && matrix->yy == 1.) { + _cairo_path_fixed_translate (path, + _cairo_fixed_from_double (matrix->x0), + _cairo_fixed_from_double (matrix->y0)); + } else { + _cairo_path_fixed_offset_and_scale (path, + _cairo_fixed_from_double (matrix->x0), + _cairo_fixed_from_double (matrix->y0), + _cairo_fixed_from_double (matrix->xx), + _cairo_fixed_from_double (matrix->yy)); + } return; } + path->extents.p1.x = path->extents.p1.y = INT_MAX; + path->extents.p2.x = path->extents.p2.y = INT_MIN; path->maybe_fill_region = FALSE; cairo_path_foreach_buf_start (buf, path) { for (i = 0; i < buf->num_points; i++) { @@ -977,6 +1037,9 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path, buf->points[i].x = _cairo_fixed_from_double (dx); buf->points[i].y = _cairo_fixed_from_double (dy); + + /* XXX need to eliminate surplus move-to's? */ + _cairo_path_fixed_extents_add (path, &buf->points[i]); } } cairo_path_foreach_buf_end (buf, path); } diff --git a/gfx/cairo/cairo/src/cairo-path-in-fill.c b/gfx/cairo/cairo/src/cairo-path-in-fill.c index 2fa865054d57..b344f529da33 100644 --- a/gfx/cairo/cairo/src/cairo-path-in-fill.c +++ b/gfx/cairo/cairo/src/cairo-path-in-fill.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-path-private.h b/gfx/cairo/cairo/src/cairo-path-private.h index a24eaa4927fb..61b4060fa869 100644 --- a/gfx/cairo/cairo/src/cairo-path-private.h +++ b/gfx/cairo/cairo/src/cairo-path-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-path-stroke.c b/gfx/cairo/cairo/src/cairo-path-stroke.c index 6e1986a9751b..505b6ab6a51b 100644 --- a/gfx/cairo/cairo/src/cairo-path-stroke.c +++ b/gfx/cairo/cairo/src/cairo-path-stroke.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -39,6 +39,8 @@ #define _BSD_SOURCE /* for hypot() */ #include "cairoint.h" +#include "cairo-boxes-private.h" +#include "cairo-error-private.h" #include "cairo-path-fixed-private.h" #include "cairo-slope-private.h" @@ -51,12 +53,11 @@ typedef struct _cairo_stroker_dash { double dash_offset; const double *dashes; - double approximate_dashes[2]; unsigned int num_dashes; } cairo_stroker_dash_t; typedef struct cairo_stroker { - cairo_stroke_style_t *style; + cairo_stroke_style_t style; const cairo_matrix_t *ctm; const cairo_matrix_t *ctm_inverse; @@ -138,39 +139,29 @@ _cairo_stroker_dash_step (cairo_stroker_dash_t *dash, double step) static void _cairo_stroker_dash_init (cairo_stroker_dash_t *dash, - const cairo_stroke_style_t *style, - const cairo_matrix_t *ctm, - double tolerance) + const cairo_stroke_style_t *style) { dash->dashed = style->dash != NULL; if (! dash->dashed) return; - if (_cairo_stroke_style_dash_can_approximate (style, ctm, tolerance)) { - _cairo_stroke_style_dash_approximate (style, ctm, tolerance, - &dash->dash_offset, - dash->approximate_dashes, - &dash->num_dashes); - dash->dashes = dash->approximate_dashes; - } else { - dash->dashes = style->dash; - dash->num_dashes = style->num_dashes; - dash->dash_offset = style->dash_offset; - } + dash->dashes = style->dash; + dash->num_dashes = style->num_dashes; + dash->dash_offset = style->dash_offset; _cairo_stroker_dash_start (dash); } static cairo_status_t _cairo_stroker_init (cairo_stroker_t *stroker, - cairo_stroke_style_t *stroke_style, + const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance) { cairo_status_t status; - stroker->style = stroke_style; + stroker->style = *stroke_style; stroker->ctm = ctm; stroker->ctm_inverse = ctm_inverse; stroker->tolerance = tolerance; @@ -190,7 +181,7 @@ _cairo_stroker_init (cairo_stroker_t *stroker, stroker->has_first_face = FALSE; stroker->has_initial_sub_path = FALSE; - _cairo_stroker_dash_init (&stroker->dash, stroke_style, ctm, tolerance); + _cairo_stroker_dash_init (&stroker->dash, stroke_style); stroker->add_external_edge = NULL; @@ -213,7 +204,7 @@ _cairo_stroker_limit (cairo_stroker_t *stroker, * of the bounds but which might generate rendering that's within bounds. */ - _cairo_stroke_style_max_distance_from_path (stroker->style, stroker->ctm, + _cairo_stroke_style_max_distance_from_path (&stroker->style, stroker->ctm, &dx, &dy); fdx = _cairo_fixed_from_double (dx); @@ -456,7 +447,7 @@ _cairo_stroker_join (cairo_stroker_t *stroker, outpt = &out->cw; } - switch (stroker->style->line_join) { + switch (stroker->style.line_join) { case CAIRO_LINE_JOIN_ROUND: /* construct a fan around the common midpoint */ return _tessellate_fan (stroker, @@ -470,7 +461,7 @@ _cairo_stroker_join (cairo_stroker_t *stroker, /* dot product of incoming slope vector with outgoing slope vector */ double in_dot_out = -in->usr_vector.x * out->usr_vector.x + -in->usr_vector.y * out->usr_vector.y; - double ml = stroker->style->miter_limit; + double ml = stroker->style.miter_limit; /* Check the miter limit -- lines meeting at an acute angle * can generate long miters, the limit converts them to bevel @@ -665,7 +656,7 @@ static cairo_status_t _cairo_stroker_add_cap (cairo_stroker_t *stroker, const cairo_stroke_face_t *f) { - switch (stroker->style->line_cap) { + switch (stroker->style.line_cap) { case CAIRO_LINE_CAP_ROUND: { cairo_slope_t slope; @@ -687,8 +678,8 @@ _cairo_stroker_add_cap (cairo_stroker_t *stroker, dx = f->usr_vector.x; dy = f->usr_vector.y; - dx *= stroker->style->line_width / 2.0; - dy *= stroker->style->line_width / 2.0; + dx *= stroker->style.line_width / 2.0; + dy *= stroker->style.line_width / 2.0; cairo_matrix_transform_distance (stroker->ctm, &dx, &dy); fvector.dx = _cairo_fixed_from_double (dx); fvector.dy = _cairo_fixed_from_double (dy); @@ -826,13 +817,13 @@ _compute_face (const cairo_point_t *point, cairo_slope_t *dev_slope, */ if (stroker->ctm_det_positive) { - face_dx = - slope_dy * (stroker->style->line_width / 2.0); - face_dy = slope_dx * (stroker->style->line_width / 2.0); + face_dx = - slope_dy * (stroker->style.line_width / 2.0); + face_dy = slope_dx * (stroker->style.line_width / 2.0); } else { - face_dx = slope_dy * (stroker->style->line_width / 2.0); - face_dy = - slope_dx * (stroker->style->line_width / 2.0); + face_dx = slope_dy * (stroker->style.line_width / 2.0); + face_dy = - slope_dx * (stroker->style.line_width / 2.0); } /* back to device space */ @@ -866,7 +857,7 @@ _cairo_stroker_add_caps (cairo_stroker_t *stroker) if (stroker->has_initial_sub_path && ! stroker->has_first_face && ! stroker->has_current_face - && stroker->style->line_cap == CAIRO_LINE_JOIN_ROUND) + && stroker->style.line_cap == CAIRO_LINE_JOIN_ROUND) { /* pick an arbitrary slope to use */ double dx = 1.0, dy = 0.0; @@ -1231,8 +1222,8 @@ _cairo_stroker_curve_to (void *closure, /* Temporarily modify the stroker to use round joins to guarantee * smooth stroked curves. */ - line_join_save = stroker->style->line_join; - stroker->style->line_join = CAIRO_LINE_JOIN_ROUND; + line_join_save = stroker->style.line_join; + stroker->style.line_join = CAIRO_LINE_JOIN_ROUND; status = _cairo_spline_decompose (&spline, stroker->tolerance); if (unlikely (status)) @@ -1258,7 +1249,7 @@ _cairo_stroker_curve_to (void *closure, stroker->current_face = face; } - stroker->style->line_join = line_join_save; + stroker->style.line_join = line_join_save; return CAIRO_STATUS_SUCCESS; } @@ -1299,9 +1290,9 @@ _cairo_stroker_close_path (void *closure) cairo_status_t _cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_status_t (*add_triangle) (void *closure, const cairo_point_t triangle[3]), @@ -1350,7 +1341,7 @@ BAIL: cairo_status_t _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, + const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, @@ -1394,7 +1385,7 @@ BAIL: cairo_status_t _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, + const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, @@ -1418,14 +1409,15 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path, } _cairo_polygon_init (&polygon); - _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits); + if (traps->num_limits) + _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits); status = _cairo_path_fixed_stroke_to_polygon (path, - stroke_style, - ctm, - ctm_inverse, - tolerance, - &polygon); + stroke_style, + ctm, + ctm_inverse, + tolerance, + &polygon); if (unlikely (status)) goto BAIL; @@ -1449,11 +1441,12 @@ typedef struct _segment_t { } segment_t; typedef struct _cairo_rectilinear_stroker { - cairo_stroke_style_t *stroke_style; + const cairo_stroke_style_t *stroke_style; const cairo_matrix_t *ctm; cairo_fixed_t half_line_width; - cairo_traps_t *traps; + cairo_bool_t do_traps; + void *container; cairo_point_t current_point; cairo_point_t first_point; cairo_bool_t open_sub_path; @@ -1484,27 +1477,60 @@ _cairo_rectilinear_stroker_limit (cairo_rectilinear_stroker_t *stroker, stroker->bounds.p2.y += stroker->half_line_width; } -static void +static cairo_bool_t _cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker, - cairo_stroke_style_t *stroke_style, + const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, - cairo_traps_t *traps) + cairo_bool_t do_traps, + void *container) { + /* This special-case rectilinear stroker only supports + * miter-joined lines (not curves) and a translation-only matrix + * (though it could probably be extended to support a matrix with + * uniform, integer scaling). + * + * It also only supports horizontal and vertical line_to + * elements. But we don't catch that here, but instead return + * UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any + * non-rectilinear line_to is encountered. + */ + if (stroke_style->line_join != CAIRO_LINE_JOIN_MITER) + return FALSE; + + /* If the miter limit turns right angles into bevels, then we + * can't use this optimization. Remember, the ratio is + * 1/sin(ɸ/2). So the cutoff is 1/sin(π/4.0) or ⎷2, + * which we round for safety. */ + if (stroke_style->miter_limit < M_SQRT2) + return FALSE; + + if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT || + stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE)) + { + return FALSE; + } + + if (! _cairo_matrix_has_unity_scale (ctm)) + return FALSE; + stroker->stroke_style = stroke_style; stroker->ctm = ctm; stroker->half_line_width = _cairo_fixed_from_double (stroke_style->line_width / 2.0); - stroker->traps = traps; stroker->open_sub_path = FALSE; stroker->segments = stroker->segments_embedded; stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded); stroker->num_segments = 0; - /* Assume 2*EPSILON tolerance */ - _cairo_stroker_dash_init (&stroker->dash, stroke_style, ctm, _cairo_fixed_to_double (2 * CAIRO_FIXED_EPSILON)); + _cairo_stroker_dash_init (&stroker->dash, stroke_style); stroker->has_bounds = FALSE; + + stroker->do_traps = do_traps; + stroker->container = container; + + return TRUE; } static void @@ -1663,7 +1689,16 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker) b->x += half_line_width; } - status = _cairo_traps_tessellate_rectangle (stroker->traps, a, b); + if (stroker->do_traps) { + status = _cairo_traps_tessellate_rectangle (stroker->container, a, b); + } else { + cairo_box_t box; + + box.p1 = *a; + box.p2 = *b; + + status = _cairo_boxes_add (stroker->container, &box); + } if (unlikely (status)) return status; } @@ -1729,8 +1764,16 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st p2.x += half_line_width; } - status = _cairo_traps_tessellate_rectangle (stroker->traps, - &p1, &p2); + if (stroker->do_traps) { + status = _cairo_traps_tessellate_rectangle (stroker->container, &p1, &p2); + } else { + cairo_box_t box; + + box.p1 = p1; + box.p2 = p2; + + status = _cairo_boxes_add (stroker->container, &box); + } if (unlikely (status)) return status; } @@ -1783,7 +1826,16 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st if (a->x == b->x && a->y == b->y) continue; - status = _cairo_traps_tessellate_rectangle (stroker->traps, a, b); + if (stroker->do_traps) { + status = _cairo_traps_tessellate_rectangle (stroker->container, a, b); + } else { + cairo_box_t box; + + box.p1 = *a; + box.p2 = *b; + + status = _cairo_boxes_add (stroker->container, &box); + } if (unlikely (status)) return status; } @@ -1978,45 +2030,22 @@ _cairo_rectilinear_stroker_close_path (void *closure) cairo_int_status_t _cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, + const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, cairo_traps_t *traps) { cairo_rectilinear_stroker_t rectilinear_stroker; cairo_int_status_t status; - /* This special-case rectilinear stroker only supports - * miter-joined lines (not curves) and a translation-only matrix - * (though it could probably be extended to support a matrix with - * uniform, integer scaling). - * - * It also only supports horizontal and vertical line_to - * elements. But we don't catch that here, but instead return - * UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any - * non-rectilinear line_to is encountered. - */ assert (path->is_rectilinear); - if (stroke_style->line_join != CAIRO_LINE_JOIN_MITER) - return CAIRO_INT_STATUS_UNSUPPORTED; - /* If the miter limit turns right angles into bevels, then we - * can't use this optimization. Remember, the ratio is - * 1/sin(ɸ/2). So the cutoff is 1/sin(π/4.0) or ⎷2, - * which we round for safety. */ - if (stroke_style->miter_limit < M_SQRT2) - return CAIRO_INT_STATUS_UNSUPPORTED; - if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT || - stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE)) + if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker, + stroke_style, ctm, + TRUE, traps)) { return CAIRO_INT_STATUS_UNSUPPORTED; } - if (! _cairo_matrix_has_unity_scale (ctm)) - return CAIRO_INT_STATUS_UNSUPPORTED; - _cairo_rectilinear_stroker_init (&rectilinear_stroker, - stroke_style, - ctm, - traps); if (traps->num_limits) { _cairo_rectilinear_stroker_limit (&rectilinear_stroker, traps->limits, @@ -2052,3 +2081,63 @@ BAIL: return status; } + +cairo_int_status_t +_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + cairo_boxes_t *boxes) +{ + cairo_rectilinear_stroker_t rectilinear_stroker; + cairo_int_status_t status; + + assert (path->is_rectilinear); + + if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker, + stroke_style, ctm, + FALSE, boxes)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (boxes->num_limits) { + _cairo_rectilinear_stroker_limit (&rectilinear_stroker, + boxes->limits, + boxes->num_limits); + } + + status = _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cairo_rectilinear_stroker_move_to, + rectilinear_stroker.dash.dashed ? + _cairo_rectilinear_stroker_line_to_dashed : + _cairo_rectilinear_stroker_line_to, + NULL, + _cairo_rectilinear_stroker_close_path, + &rectilinear_stroker); + if (unlikely (status)) + goto BAIL; + + if (rectilinear_stroker.dash.dashed) + status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker); + else + status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker); + if (unlikely (status)) + goto BAIL; + + /* As we incrementally tessellate, we do not eliminate self-intersections */ + status = _cairo_bentley_ottmann_tessellate_boxes (boxes, + CAIRO_FILL_RULE_WINDING, + boxes); + if (unlikely (status)) + goto BAIL; + + _cairo_rectilinear_stroker_fini (&rectilinear_stroker); + + return CAIRO_STATUS_SUCCESS; + +BAIL: + _cairo_rectilinear_stroker_fini (&rectilinear_stroker); + _cairo_boxes_clear (boxes); + return status; +} diff --git a/gfx/cairo/cairo/src/cairo-path.c b/gfx/cairo/cairo/src/cairo-path.c index 054450544d8f..28182c0e4003 100644 --- a/gfx/cairo/cairo/src/cairo-path.c +++ b/gfx/cairo/cairo/src/cairo-path.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,9 +37,19 @@ #include "cairoint.h" #include "cairo-private.h" +#include "cairo-error-private.h" #include "cairo-path-private.h" #include "cairo-path-fixed-private.h" +/** + * SECTION:cairo-paths + * @Title: Paths + * @Short_Description: Creating paths and manipulating path data + * + * Paths are the most basic drawing tools and are primarily used to implicitly + * generate simple masks. + */ + static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 }; /* Closure for path interpretation. */ diff --git a/gfx/cairo/cairo/src/cairo-pattern.c b/gfx/cairo/cairo/src/cairo-pattern.c index 048ad667ff9b..1e83bf4c92d7 100644 --- a/gfx/cairo/cairo/src/cairo-pattern.c +++ b/gfx/cairo/cairo/src/cairo-pattern.c @@ -29,6 +29,29 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" +#include "cairo-freed-pool-private.h" + +/** + * SECTION:cairo-pattern + * @Title: cairo_pattern_t + * @Short_Description: Sources for drawing + * @See_Also: #cairo_t, #cairo_surface_t + * + * #cairo_pattern_t is the paint with which cairo draws. + * The primary use of patterns is as the source for all cairo drawing + * operations, although they can also be used as masks, that is, as the + * brush too. + * + * A cairo pattern is created by using one of the many constructors, + * of the form cairo_pattern_create_type() + * or implicitly through + * cairo_set_source_type() functions. + */ + +#if HAS_FREED_POOL +static freed_pool_t freed_pattern_pool[4]; +#endif static const cairo_solid_pattern_t _cairo_pattern_nil = { { CAIRO_PATTERN_TYPE_SOLID, /* type */ @@ -59,7 +82,28 @@ const cairo_solid_pattern_t _cairo_pattern_black = { CAIRO_FILTER_DEFAULT, /* filter */ CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */ { 0., 0., 0., 1., 0, 0, 0, 0xffff },/* color (double rgba, short rgba) */ - CAIRO_CONTENT_COLOR, /* content */ +}; + +const cairo_solid_pattern_t _cairo_pattern_clear = { + { CAIRO_PATTERN_TYPE_SOLID, /* type */ + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + CAIRO_STATUS_SUCCESS, /* status */ + { 0, 0, 0, NULL }, /* user_data */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + CAIRO_FILTER_DEFAULT, /* filter */ + CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */ + { 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */ +}; + +const cairo_solid_pattern_t _cairo_pattern_white = { + { CAIRO_PATTERN_TYPE_SOLID, /* type */ + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + CAIRO_STATUS_SUCCESS, /* status */ + { 0, 0, 0, NULL }, /* user_data */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + CAIRO_FILTER_DEFAULT, /* filter */ + CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */ + { 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */ }; /** @@ -329,23 +373,6 @@ _cairo_pattern_fini (cairo_pattern_t *pattern) #endif } -void -_cairo_pattern_fini_snapshot (cairo_pattern_t *pattern) -{ - /* XXX this is quite ugly, but currently necessary to break the circular - * references with snapshot-cow and the recording-surface. - * This operation remains safe only whilst _cairo_surface_snapshot() is - * not public... - */ - if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { - cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) pattern; - - cairo_surface_finish (spat->surface); - } - - _cairo_pattern_fini (pattern); -} - cairo_status_t _cairo_pattern_create_copy (cairo_pattern_t **pattern_out, const cairo_pattern_t *other) @@ -390,15 +417,10 @@ _cairo_pattern_create_copy (cairo_pattern_t **pattern_out, void _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, - const cairo_color_t *color, - cairo_content_t content) + const cairo_color_t *color) { - if (content == CAIRO_CONTENT_COLOR_ALPHA && CAIRO_COLOR_IS_OPAQUE (color)) - content = CAIRO_CONTENT_COLOR; - _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID); pattern->color = *color; - pattern->content = content; } void @@ -455,106 +477,13 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, pattern->r2 = _cairo_fixed_from_double (fabs (radius1)); } -/* We use a small freed pattern cache here, because we don't want to - * constantly reallocate simple colors. */ -#define MAX_PATTERN_CACHE_SIZE 4 -typedef struct { - void *pool[MAX_PATTERN_CACHE_SIZE]; - int top; -} freed_pool_t; - -static freed_pool_t freed_pattern_pool[4]; - -static void * -_atomic_fetch (void **slot) -{ - return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL); -} - -static cairo_bool_t -_atomic_store (void **slot, void *pattern) -{ - return _cairo_atomic_ptr_cmpxchg (slot, NULL, pattern) == NULL; -} - -static void * -_freed_pattern_get (freed_pool_t *pool) -{ - cairo_pattern_t *pattern; - int i; - - i = pool->top - 1; - if (i < 0) - i = 0; - - pattern = _atomic_fetch (&pool->pool[i]); - if (likely (pattern != NULL)) { - pool->top = i; - return pattern; - } - - /* either empty or contended */ - for (i = ARRAY_LENGTH (pool->pool); i--;) { - pattern = _atomic_fetch (&pool->pool[i]); - if (pattern != NULL) { - pool->top = i; - return pattern; - } - } - - /* empty */ - pool->top = 0; - return NULL; -} - -static void -_freed_pattern_put (freed_pool_t *pool, - cairo_pattern_t *pattern) -{ - int i = pool->top; - - if (likely (i < ARRAY_LENGTH (pool->pool) && - _atomic_store (&pool->pool[i], pattern))) - { - pool->top = i + 1; - return; - } - - /* either full or contended */ - for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) { - if (_atomic_store (&pool->pool[i], pattern)) { - pool->top = i + 1; - return; - } - } - - /* full */ - pool->top = ARRAY_LENGTH (pool->pool); - free (pattern); -} - -static void -_freed_patterns_reset (void) -{ - int i, j; - - for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++) { - freed_pool_t *pool = &freed_pattern_pool[i]; - for (j = 0; j < ARRAY_LENGTH (pool->pool); j++) { - free (pool->pool[j]); - pool->pool[j] = NULL; - } - } -} - cairo_pattern_t * -_cairo_pattern_create_solid (const cairo_color_t *color, - cairo_content_t content) +_cairo_pattern_create_solid (const cairo_color_t *color) { cairo_solid_pattern_t *pattern; pattern = - _freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]); + _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]); if (unlikely (pattern == NULL)) { /* None cached, need to create a new pattern. */ pattern = malloc (sizeof (cairo_solid_pattern_t)); @@ -564,7 +493,7 @@ _cairo_pattern_create_solid (const cairo_color_t *color, } } - _cairo_pattern_init_solid (pattern, color, content); + _cairo_pattern_init_solid (pattern, color); CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1); return &pattern->base; @@ -580,7 +509,7 @@ _cairo_pattern_create_in_error (cairo_status_t status) CAIRO_MUTEX_INITIALIZE (); - pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR); + pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK); if (pattern->status == CAIRO_STATUS_SUCCESS) status = _cairo_pattern_set_error (pattern, status); @@ -620,7 +549,7 @@ cairo_pattern_create_rgb (double red, double green, double blue) CAIRO_MUTEX_INITIALIZE (); - return _cairo_pattern_create_solid (&color, CAIRO_CONTENT_COLOR); + return _cairo_pattern_create_solid (&color); } slim_hidden_def (cairo_pattern_create_rgb); @@ -660,7 +589,7 @@ cairo_pattern_create_rgba (double red, double green, double blue, CAIRO_MUTEX_INITIALIZE (); - return _cairo_pattern_create_solid (&color, CAIRO_CONTENT_COLOR_ALPHA); + return _cairo_pattern_create_solid (&color); } slim_hidden_def (cairo_pattern_create_rgba); @@ -693,7 +622,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface) return _cairo_pattern_create_in_error (surface->status); pattern = - _freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]); + _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]); if (unlikely (pattern == NULL)) { pattern = malloc (sizeof (cairo_surface_pattern_t)); if (unlikely (pattern == NULL)) { @@ -743,7 +672,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1) cairo_linear_pattern_t *pattern; pattern = - _freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]); + _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]); if (unlikely (pattern == NULL)) { pattern = malloc (sizeof (cairo_linear_pattern_t)); if (unlikely (pattern == NULL)) { @@ -795,7 +724,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, cairo_radial_pattern_t *pattern; pattern = - _freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]); + _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]); if (unlikely (pattern == NULL)) { pattern = malloc (sizeof (cairo_radial_pattern_t)); if (unlikely (pattern == NULL)) { @@ -899,7 +828,7 @@ cairo_pattern_destroy (cairo_pattern_t *pattern) _cairo_pattern_fini (pattern); /* maintain a small cache of freed patterns */ - _freed_pattern_put (&freed_pattern_pool[type], pattern); + _freed_pool_put (&freed_pattern_pool[type], pattern); } slim_hidden_def (cairo_pattern_destroy); @@ -1592,14 +1521,14 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat break; } - pixman_image_composite (PIXMAN_OP_SRC, - pixman_image, - NULL, - image->pixman_image, - x, y, - 0, 0, - 0, 0, - width, height); + pixman_image_composite32 (PIXMAN_OP_SRC, + pixman_image, + NULL, + image->pixman_image, + x, y, + 0, 0, + 0, 0, + width, height); pixman_image_unref (pixman_image); @@ -1628,7 +1557,6 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat #define MAX_SURFACE_CACHE_SIZE 16 static struct { struct _cairo_pattern_solid_surface_cache{ - cairo_content_t content; cairo_color_t color; cairo_surface_t *surface; } cache[MAX_SURFACE_CACHE_SIZE]; @@ -1641,13 +1569,13 @@ _cairo_pattern_solid_surface_matches ( const cairo_solid_pattern_t *pattern, cairo_surface_t *dst) { - if (cache->content != pattern->content) + if (cairo_surface_get_content (cache->surface) != _cairo_color_get_content (&pattern->color)) return FALSE; if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1) return FALSE; - if (! _cairo_surface_is_similar (cache->surface, dst, pattern->content)) + if (! _cairo_surface_is_similar (cache->surface, dst)) return FALSE; return TRUE; @@ -1736,8 +1664,7 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt goto UNLOCK; } - if (unlikely (! _cairo_surface_is_similar (surface, - dst, pattern->content))) + if (unlikely (! _cairo_surface_is_similar (surface, dst))) { /* In the rare event of a substitute surface being returned, * don't cache the fallback. @@ -1753,7 +1680,6 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt to_destroy = solid_surface_cache.cache[i].surface; solid_surface_cache.cache[i].surface = surface; solid_surface_cache.cache[i].color = pattern->color; - solid_surface_cache.cache[i].content = pattern->content; DONE: *out = cairo_surface_reference (solid_surface_cache.cache[i].surface); @@ -1800,6 +1726,151 @@ _cairo_pattern_reset_solid_surface_cache (void) CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock); } +static void +_extents_to_linear_parameter (const cairo_linear_pattern_t *linear, + const cairo_rectangle_int_t *extents, + double t[2]) +{ + double t0, tdx, tdy; + double p1x, p1y, pdx, pdy, invsqnorm; + + p1x = _cairo_fixed_to_double (linear->p1.x); + p1y = _cairo_fixed_to_double (linear->p1.y); + pdx = _cairo_fixed_to_double (linear->p2.x) - p1x; + pdy = _cairo_fixed_to_double (linear->p2.y) - p1y; + invsqnorm = 1.0 / (pdx * pdx + pdy * pdy); + pdx *= invsqnorm; + pdy *= invsqnorm; + + t0 = (extents->x - p1x) * pdx + (extents->y - p1y) * pdy; + tdx = extents->width * pdx; + tdy = extents->height * pdy; + + t[0] = t[1] = t0; + if (tdx < 0) + t[0] += tdx; + else + t[1] += tdx; + + if (tdy < 0) + t[0] += tdy; + else + t[1] += tdy; +} + +static cairo_bool_t +_linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear) +{ + return linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y; +} + +static cairo_bool_t +_radial_pattern_is_degenerate (const cairo_radial_pattern_t *radial) +{ + return radial->r1 == radial->r2 && + (radial->r1 == 0 /* && radial->r2 == 0 */ || + (radial->c1.x == radial->c2.x && radial->c1.y == radial->c2.y)); +} + +static cairo_bool_t +_gradient_is_clear (const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *extents) +{ + unsigned int i; + + assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || + gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); + + if (gradient->n_stops == 0 || + (gradient->base.extend == CAIRO_EXTEND_NONE && + gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset)) + return TRUE; + + /* Check if the extents intersect the drawn part of the pattern. */ + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + if (gradient->base.extend == CAIRO_EXTEND_NONE) { + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; + /* EXTEND_NONE degenerate linear gradients are clear */ + if (_linear_pattern_is_degenerate (linear)) + return TRUE; + + if (extents != NULL) { + double t[2]; + _extents_to_linear_parameter (linear, extents, t); + if ((t[0] <= 0.0 && t[1] <= 0.0) || (t[0] >= 1.0 && t[1] >= 1.0)) + return TRUE; + } + } + } else { + cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient; + /* degenerate radial gradients are clear */ + if (_radial_pattern_is_degenerate (radial) && FALSE) + return TRUE; + /* TODO: check actual intersection */ + } + + for (i = 0; i < gradient->n_stops; i++) + if (! CAIRO_COLOR_IS_CLEAR (&gradient->stops[i].color)) + return FALSE; + + return TRUE; +} + +/** + * _cairo_gradient_pattern_is_solid + * + * Convenience function to determine whether a gradient pattern is + * a solid color within the given extents. In this case the color + * argument is initialized to the color the pattern represents. + * This functions doesn't handle completely transparent gradients, + * thus it should be called only after _cairo_pattern_is_clear has + * returned FALSE. + * + * Return value: %TRUE if the pattern is a solid color. + **/ +cairo_bool_t +_cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *extents, + cairo_color_t *color) +{ + unsigned int i; + + assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || + gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); + + /* TODO: radial, degenerate linear */ + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + if (gradient->base.extend == CAIRO_EXTEND_NONE) { + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; + double t[2]; + + /* We already know that the pattern is not clear, thus if some + * part of it is clear, the whole is not solid. + */ + + if (extents == NULL) + return FALSE; + + _extents_to_linear_parameter (linear, extents, t); + if (t[0] < 0.0 || t[1] > 1.0) + return FALSE; + } + } + + for (i = 1; i < gradient->n_stops; i++) + if (! _cairo_color_stop_equal (&gradient->stops[0].color, + &gradient->stops[i].color)) + return FALSE; + + _cairo_color_init_rgba (color, + gradient->stops[0].color.red, + gradient->stops[0].color.green, + gradient->stops[0].color.blue, + gradient->stops[0].color.alpha); + + return TRUE; +} + /** * _cairo_pattern_is_opaque_solid * @@ -1825,10 +1896,78 @@ _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern) } static cairo_bool_t -_gradient_is_opaque (const cairo_gradient_pattern_t *gradient) +_surface_is_opaque (const cairo_surface_pattern_t *pattern, + const cairo_rectangle_int_t *r) +{ + if (pattern->surface->content & CAIRO_CONTENT_ALPHA) + return FALSE; + + if (pattern->base.extend != CAIRO_EXTEND_NONE) + return TRUE; + + if (r != NULL) { + cairo_rectangle_int_t extents; + + if (! _cairo_surface_get_extents (pattern->surface, &extents)) + return TRUE; + + if (r->x >= extents.x && + r->y >= extents.y && + r->x + r->width <= extents.x + extents.width && + r->y + r->height <= extents.y + extents.height) + { + return TRUE; + } + } + + return FALSE; +} + +static cairo_bool_t +_surface_is_clear (const cairo_surface_pattern_t *pattern) +{ + cairo_rectangle_int_t extents; + + if (_cairo_surface_get_extents (pattern->surface, &extents) && + (extents.width == 0 || extents.height == 0)) + return TRUE; + + return pattern->surface->is_clear && + pattern->surface->content & CAIRO_CONTENT_ALPHA; +} + +static cairo_bool_t +_gradient_is_opaque (const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *extents) { unsigned int i; + assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || + gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); + + if (gradient->n_stops == 0 || + (gradient->base.extend == CAIRO_EXTEND_NONE && + gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset)) + return FALSE; + + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + if (gradient->base.extend == CAIRO_EXTEND_NONE) { + double t[2]; + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; + + /* EXTEND_NONE degenerate radial gradients are clear */ + if (_linear_pattern_is_degenerate (linear)) + return FALSE; + + if (extents == NULL) + return FALSE; + + _extents_to_linear_parameter (linear, extents, t); + if (t[0] < 0.0 || t[1] > 1.0) + return FALSE; + } + } + for (i = 0; i < gradient->n_stops; i++) if (! CAIRO_COLOR_IS_OPAQUE (&gradient->stops[i].color)) return FALSE; @@ -1846,7 +1985,8 @@ _gradient_is_opaque (const cairo_gradient_pattern_t *gradient) * Return value: %TRUE if the pattern is a opaque. **/ cairo_bool_t -_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern) +_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern, + const cairo_rectangle_int_t *extents) { const cairo_pattern_union_t *pattern; @@ -1858,10 +1998,33 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern) case CAIRO_PATTERN_TYPE_SOLID: return _cairo_pattern_is_opaque_solid (abstract_pattern); case CAIRO_PATTERN_TYPE_SURFACE: - return cairo_surface_get_content (pattern->surface.surface) == CAIRO_CONTENT_COLOR; + return _surface_is_opaque (&pattern->surface, extents); case CAIRO_PATTERN_TYPE_LINEAR: case CAIRO_PATTERN_TYPE_RADIAL: - return _gradient_is_opaque (&pattern->gradient.base); + return _gradient_is_opaque (&pattern->gradient.base, extents); + } + + ASSERT_NOT_REACHED; + return FALSE; +} + +cairo_bool_t +_cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern) +{ + const cairo_pattern_union_t *pattern; + + if (abstract_pattern->has_component_alpha) + return FALSE; + + pattern = (cairo_pattern_union_t *) abstract_pattern; + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color); + case CAIRO_PATTERN_TYPE_SURFACE: + return _surface_is_clear (&pattern->surface); + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + return _gradient_is_clear (&pattern->gradient.base, NULL); } ASSERT_NOT_REACHED; @@ -1882,7 +2045,7 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern) * the filter radius, so we just guess base on what we know that * backends do currently (see bug #10508) */ -static cairo_filter_t +cairo_filter_t _cairo_pattern_analyze_filter (const cairo_pattern_t *pattern, double *pad_out) { @@ -2206,21 +2369,6 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat return status; } -static void -_init_solid_for_color_stop (cairo_solid_pattern_t *solid, - const cairo_color_t *color) -{ - cairo_color_t premult; - - /* Color stops aren't premultiplied, so fix that here */ - _cairo_color_init_rgba (&premult, - color->red, - color->green, - color->blue, - color->alpha); - _cairo_pattern_init_solid (solid, &premult, CAIRO_CONTENT_COLOR_ALPHA); -} - /** * _cairo_pattern_acquire_surface: * @pattern: a #cairo_pattern_t @@ -2252,98 +2400,36 @@ _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern, cairo_surface_t **surface_out, cairo_surface_attributes_t *attributes) { - cairo_status_t status; - if (unlikely (pattern->status)) { *surface_out = NULL; return pattern->status; } switch (pattern->type) { - case CAIRO_PATTERN_TYPE_SOLID: { - cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern; + case CAIRO_PATTERN_TYPE_SOLID: + return _cairo_pattern_acquire_surface_for_solid ((cairo_solid_pattern_t *) pattern, + dst, x, y, width, height, + surface_out, + attributes); - status = _cairo_pattern_acquire_surface_for_solid (src, dst, - x, y, width, height, + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + return _cairo_pattern_acquire_surface_for_gradient ((cairo_gradient_pattern_t *) pattern, + dst, x, y, width, height, + surface_out, + attributes); + + case CAIRO_PATTERN_TYPE_SURFACE: + return _cairo_pattern_acquire_surface_for_surface ((cairo_surface_pattern_t *) pattern, + dst, x, y, width, height, + flags, surface_out, attributes); - } break; - case CAIRO_PATTERN_TYPE_LINEAR: - case CAIRO_PATTERN_TYPE_RADIAL: { - cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern; - /* XXX The gradient->solid conversion code should now be redundant. */ - - /* fast path for gradients with less than 2 color stops */ - if (src->n_stops < 2) - { - cairo_solid_pattern_t solid; - - if (src->n_stops) { - _init_solid_for_color_stop (&solid, &src->stops->color); - } else { - _cairo_pattern_init_solid (&solid, - CAIRO_COLOR_TRANSPARENT, - CAIRO_CONTENT_ALPHA); - } - - status = _cairo_pattern_acquire_surface_for_solid (&solid, dst, - x, y, - width, height, - surface_out, - attributes); - } - else - { - unsigned int i; - - /* Is the gradient a uniform colour? - * Happens more often than you would believe. - */ - for (i = 1; i < src->n_stops; i++) { - if (! _cairo_color_equal (&src->stops[0].color, - &src->stops[i].color)) - { - break; - } - } - if (i == src->n_stops) { - cairo_solid_pattern_t solid; - - _init_solid_for_color_stop (&solid, &src->stops->color); - - status = - _cairo_pattern_acquire_surface_for_solid (&solid, dst, - x, y, - width, height, - surface_out, - attributes); - } else { - status = - _cairo_pattern_acquire_surface_for_gradient (src, dst, - x, y, - width, height, - surface_out, - attributes); - } - } - } break; - case CAIRO_PATTERN_TYPE_SURFACE: { - cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern; - - status = _cairo_pattern_acquire_surface_for_surface (src, dst, - x, y, - width, height, - flags, - surface_out, - attributes); - } break; default: ASSERT_NOT_REACHED; - status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); } - - return status; } /** @@ -2401,8 +2487,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src, combined = src_solid->color; _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha); - _cairo_pattern_init_solid (&src_tmp.solid, &combined, - src_solid->content | mask_solid->content); + _cairo_pattern_init_solid (&src_tmp.solid, &combined); src = &src_tmp.base; mask = NULL; @@ -2452,7 +2537,6 @@ void _cairo_pattern_get_extents (const cairo_pattern_t *pattern, cairo_rectangle_int_t *extents) { - cairo_matrix_t imatrix; double x1, y1, x2, y2; cairo_status_t status; @@ -2539,6 +2623,9 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, if (pattern->extend != CAIRO_EXTEND_NONE) goto UNBOUNDED; + if (linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y) + goto EMPTY; + if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.) goto UNBOUNDED; @@ -2562,14 +2649,21 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, ASSERT_NOT_REACHED; } - imatrix = pattern->matrix; - status = cairo_matrix_invert (&imatrix); - /* cairo_pattern_set_matrix ensures the matrix is invertible */ - assert (status == CAIRO_STATUS_SUCCESS); + if (_cairo_matrix_is_translation (&pattern->matrix)) { + x1 -= pattern->matrix.x0; x2 -= pattern->matrix.x0; + y1 -= pattern->matrix.y0; y2 -= pattern->matrix.y0; + } else { + cairo_matrix_t imatrix; - _cairo_matrix_transform_bounding_box (&imatrix, - &x1, &y1, &x2, &y2, - NULL); + imatrix = pattern->matrix; + status = cairo_matrix_invert (&imatrix); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + _cairo_matrix_transform_bounding_box (&imatrix, + &x1, &y1, &x2, &y2, + NULL); + } x1 = floor (x1); if (x1 < CAIRO_RECT_INT_MIN) @@ -2607,7 +2701,6 @@ _cairo_solid_pattern_hash (unsigned long hash, { const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; - hash = _cairo_hash_bytes (hash, &solid->content, sizeof (solid->content)); hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color)); return hash; @@ -2635,23 +2728,20 @@ _cairo_gradient_color_stops_hash (unsigned long hash, return hash; } -static unsigned long +unsigned long _cairo_linear_pattern_hash (unsigned long hash, - const cairo_pattern_t *pattern) + const cairo_linear_pattern_t *linear) { - const cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern; - hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1)); hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2)); return _cairo_gradient_color_stops_hash (hash, &linear->base); } -static unsigned long -_cairo_radial_pattern_hash (unsigned long hash, const cairo_pattern_t *pattern) +unsigned long +_cairo_radial_pattern_hash (unsigned long hash, + const cairo_radial_pattern_t *radial) { - const cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern; - hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1)); hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1)); hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2)); @@ -2696,9 +2786,9 @@ _cairo_pattern_hash (const cairo_pattern_t *pattern) case CAIRO_PATTERN_TYPE_SOLID: return _cairo_solid_pattern_hash (hash, pattern); case CAIRO_PATTERN_TYPE_LINEAR: - return _cairo_linear_pattern_hash (hash, pattern); + return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern); case CAIRO_PATTERN_TYPE_RADIAL: - return _cairo_radial_pattern_hash (hash, pattern); + return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern); case CAIRO_PATTERN_TYPE_SURFACE: return _cairo_surface_pattern_hash (hash, pattern); default: @@ -2750,9 +2840,6 @@ _cairo_solid_pattern_equal (const cairo_pattern_t *A, const cairo_solid_pattern_t *a = (cairo_solid_pattern_t *) A; const cairo_solid_pattern_t *b = (cairo_solid_pattern_t *) B; - if (a->content != b->content) - return FALSE; - return _cairo_color_equal (&a->color, &b->color); } @@ -2768,20 +2855,17 @@ _cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a, for (n = 0; n < a->n_stops; n++) { if (a->stops[n].offset != b->stops[n].offset) return FALSE; - if (! _cairo_color_equal (&a->stops[n].color, &b->stops[n].color)) + if (! _cairo_color_stop_equal (&a->stops[n].color, &b->stops[n].color)) return FALSE; } return TRUE; } -static cairo_bool_t -_cairo_linear_pattern_equal (const cairo_pattern_t *A, - const cairo_pattern_t *B) +cairo_bool_t +_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a, + const cairo_linear_pattern_t *b) { - const cairo_linear_pattern_t *a = (cairo_linear_pattern_t *) A; - const cairo_linear_pattern_t *b = (cairo_linear_pattern_t *) B; - if (a->p1.x != b->p1.x) return FALSE; @@ -2797,13 +2881,10 @@ _cairo_linear_pattern_equal (const cairo_pattern_t *A, return _cairo_gradient_color_stops_equal (&a->base, &b->base); } -static cairo_bool_t -_cairo_radial_pattern_equal (const cairo_pattern_t *A, - const cairo_pattern_t *B) +cairo_bool_t +_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a, + const cairo_radial_pattern_t *b) { - const cairo_radial_pattern_t *a = (cairo_radial_pattern_t *) A; - const cairo_radial_pattern_t *b = (cairo_radial_pattern_t *) B; - if (a->c1.x != b->c1.x) return FALSE; @@ -2865,9 +2946,11 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b) case CAIRO_PATTERN_TYPE_SOLID: return _cairo_solid_pattern_equal (a, b); case CAIRO_PATTERN_TYPE_LINEAR: - return _cairo_linear_pattern_equal (a, b); + return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a, + (cairo_linear_pattern_t *) b); case CAIRO_PATTERN_TYPE_RADIAL: - return _cairo_radial_pattern_equal (a, b); + return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a, + (cairo_radial_pattern_t *) b); case CAIRO_PATTERN_TYPE_SURFACE: return _cairo_surface_pattern_equal (a, b); default: @@ -3131,6 +3214,12 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern, void _cairo_pattern_reset_static_data (void) { - _freed_patterns_reset (); +#if HAS_FREED_POOL + int i; + + for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++) + _freed_pool_reset (&freed_pattern_pool[i]); +#endif + _cairo_pattern_reset_solid_surface_cache (); } diff --git a/gfx/cairo/cairo/src/cairo-pdf-operators-private.h b/gfx/cairo/cairo/src/cairo-pdf-operators-private.h index 4ef0fcaeba46..67d1cc2331b9 100644 --- a/gfx/cairo/cairo/src/cairo-pdf-operators-private.h +++ b/gfx/cairo/cairo/src/cairo-pdf-operators-private.h @@ -15,7 +15,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -82,6 +82,7 @@ typedef struct _cairo_pdf_operators { double cur_y; int hex_width; int num_glyphs; + double glyph_buf_x_pos; cairo_pdf_glyph_t glyphs[PDF_GLYPH_BUFFER_SIZE]; /* PDF line style */ @@ -132,16 +133,16 @@ _cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators, cairo_fill_rule_t fill_rule); cairo_private cairo_int_status_t -_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, - cairo_stroke_style_t *style, - double scale); +_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, + const cairo_stroke_style_t *style, + double scale); cairo_private cairo_int_status_t -_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, +_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse); + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse); cairo_private cairo_int_status_t _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, @@ -149,12 +150,12 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, cairo_fill_rule_t fill_rule); cairo_private cairo_int_status_t -_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators, +_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators, cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse); + cairo_fill_rule_t fill_rule, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse); cairo_private cairo_int_status_t _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators, diff --git a/gfx/cairo/cairo/src/cairo-pdf-operators.c b/gfx/cairo/cairo/src/cairo-pdf-operators.c index 2bfb5f44c9ea..f60fbef30645 100644 --- a/gfx/cairo/cairo/src/cairo-pdf-operators.c +++ b/gfx/cairo/cairo/src/cairo-pdf-operators.c @@ -15,7 +15,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -43,6 +43,7 @@ #if CAIRO_HAS_PDF_OPERATORS +#include "cairo-error-private.h" #include "cairo-pdf-operators-private.h" #include "cairo-path-fixed-private.h" #include "cairo-output-stream-private.h" @@ -499,14 +500,14 @@ _cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators, } switch (fill_rule) { + default: + ASSERT_NOT_REACHED; case CAIRO_FILL_RULE_WINDING: pdf_operator = "W"; break; case CAIRO_FILL_RULE_EVEN_ODD: pdf_operator = "W*"; break; - default: - ASSERT_NOT_REACHED; } _cairo_output_stream_printf (pdf_operators->stream, @@ -549,9 +550,9 @@ _cairo_pdf_line_join (cairo_line_join_t join) } cairo_int_status_t -_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, - cairo_stroke_style_t *style, - double scale) +_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, + const cairo_stroke_style_t *style, + double scale) { double *dash = style->dash; int num_dashes = style->num_dashes; @@ -706,12 +707,12 @@ _cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale) } static cairo_int_status_t -_cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, - const char *pdf_operator) +_cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + const char *pdf_operator) { cairo_status_t status; cairo_matrix_t m, path_transform; @@ -797,11 +798,11 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, } cairo_int_status_t -_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, - cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse) +_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse) { return _cairo_pdf_operators_emit_stroke (pdf_operators, path, @@ -833,14 +834,14 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, return status; switch (fill_rule) { + default: + ASSERT_NOT_REACHED; case CAIRO_FILL_RULE_WINDING: pdf_operator = "f"; break; case CAIRO_FILL_RULE_EVEN_ODD: pdf_operator = "f*"; break; - default: - ASSERT_NOT_REACHED; } _cairo_output_stream_printf (pdf_operators->stream, @@ -851,24 +852,24 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, } cairo_int_status_t -_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators, +_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators, cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse) + cairo_fill_rule_t fill_rule, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse) { const char *operator; switch (fill_rule) { + default: + ASSERT_NOT_REACHED; case CAIRO_FILL_RULE_WINDING: operator = "B"; break; case CAIRO_FILL_RULE_EVEN_ODD: operator = "B*"; break; - default: - ASSERT_NOT_REACHED; } return _cairo_pdf_operators_emit_stroke (pdf_operators, @@ -989,6 +990,7 @@ _cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators) } pdf_operators->num_glyphs = 0; + pdf_operators->glyph_buf_x_pos = pdf_operators->cur_x; status2 = _cairo_output_stream_destroy (word_wrap_stream); if (status == CAIRO_STATUS_SUCCESS) status = status2; @@ -1011,6 +1013,7 @@ _cairo_pdf_operators_add_glyph (cairo_pdf_operators_t *pdf_operators pdf_operators->glyphs[pdf_operators->num_glyphs].x_position = x_position; pdf_operators->glyphs[pdf_operators->num_glyphs].glyph_index = glyph->subset_glyph_index; pdf_operators->glyphs[pdf_operators->num_glyphs].x_advance = x; + pdf_operators->glyph_buf_x_pos += x; pdf_operators->num_glyphs++; if (pdf_operators->num_glyphs == PDF_GLYPH_BUFFER_SIZE) return _cairo_pdf_operators_flush_glyphs (pdf_operators); @@ -1035,6 +1038,7 @@ _cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t *pdf_operators, pdf_operators->text_matrix = *matrix; pdf_operators->cur_x = 0; pdf_operators->cur_y = 0; + pdf_operators->glyph_buf_x_pos = 0; _cairo_output_stream_printf (pdf_operators->stream, "%f %f %f %f %f %f Tm\n", pdf_operators->text_matrix.xx, @@ -1090,6 +1094,7 @@ _cairo_pdf_operators_set_text_position (cairo_pdf_operators_t *pdf_operators, translate.y0); pdf_operators->cur_x = 0; pdf_operators->cur_y = 0; + pdf_operators->glyph_buf_x_pos = 0; pdf_operators->cairo_to_pdftext = pdf_operators->text_matrix; status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext); @@ -1139,6 +1144,7 @@ _cairo_pdf_operators_begin_text (cairo_pdf_operators_t *pdf_operators) pdf_operators->in_text_object = TRUE; pdf_operators->num_glyphs = 0; + pdf_operators->glyph_buf_x_pos = 0; return _cairo_output_stream_get_status (pdf_operators->stream); } @@ -1243,7 +1249,7 @@ _cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operator * PDF consumers that do not handle very large position * adjustments in TJ. */ - if (fabs(x - pdf_operators->cur_x) > 10 || + if (fabs(x - pdf_operators->glyph_buf_x_pos) > 10 || fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE) { status = _cairo_pdf_operators_flush_glyphs (pdf_operators); @@ -1380,8 +1386,7 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators, status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse); if (status == CAIRO_STATUS_INVALID_MATRIX) return CAIRO_STATUS_SUCCESS; - if (unlikely (status)) - return status; + assert (status == CAIRO_STATUS_SUCCESS); pdf_operators->is_new_text_object = FALSE; if (pdf_operators->in_text_object == FALSE) { diff --git a/gfx/cairo/cairo/src/cairo-pdf-surface-private.h b/gfx/cairo/cairo/src/cairo-pdf-surface-private.h index 5c28f70ca955..221418ec9bab 100644 --- a/gfx/cairo/cairo/src/cairo-pdf-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-pdf-surface-private.h @@ -15,7 +15,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -95,10 +95,9 @@ typedef enum _cairo_pdf_operation { PDF_SHOW_GLYPHS } cairo_pdf_operation_t; -typedef struct _cairo_pdf_smask_group -{ - double width; - double height; +typedef struct _cairo_pdf_smask_group { + double width; + double height; cairo_pdf_resource_t group_res; cairo_pdf_operation_t operation; cairo_pattern_t *source; @@ -106,10 +105,10 @@ typedef struct _cairo_pdf_smask_group cairo_pattern_t *mask; cairo_path_fixed_t path; cairo_fill_rule_t fill_rule; - cairo_stroke_style_t *style; + cairo_stroke_style_t style; cairo_matrix_t ctm; cairo_matrix_t ctm_inverse; - char *utf8; + char *utf8; int utf8_len; cairo_glyph_t *glyphs; int num_glyphs; diff --git a/gfx/cairo/cairo/src/cairo-pdf-surface.c b/gfx/cairo/cairo/src/cairo-pdf-surface.c index a1be10a08db4..09bd42ea0d71 100644 --- a/gfx/cairo/cairo/src/cairo-pdf-surface.c +++ b/gfx/cairo/cairo/src/cairo-pdf-surface.c @@ -15,7 +15,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -45,12 +45,15 @@ #include "cairo-pdf-surface-private.h" #include "cairo-pdf-operators-private.h" #include "cairo-analysis-surface-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-error-private.h" #include "cairo-image-info-private.h" #include "cairo-recording-surface-private.h" #include "cairo-output-stream-private.h" #include "cairo-paginated-private.h" #include "cairo-scaled-font-subsets-private.h" #include "cairo-surface-clipper-private.h" +#include "cairo-surface-subsurface-private.h" #include "cairo-type3-glyph-surface-private.h" #include @@ -112,6 +115,23 @@ * XObject instead of using an indirect object. */ +/** + * SECTION:cairo-pdf + * @Title: PDF Surfaces + * @Short_Description: Rendering PDF documents + * @See_Also: #cairo_surface_t + * + * The PDF surface is used to render cairo graphics to Adobe + * PDF files and is a multi-page vector surface backend. + */ + +/** + * CAIRO_HAS_PDF_SURFACE: + * + * Defined if the PDF surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + */ + static const cairo_pdf_version_t _cairo_pdf_versions[] = { CAIRO_PDF_VERSION_1_4, @@ -303,7 +323,9 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } - _cairo_surface_init (&surface->base, &cairo_pdf_surface_backend, + _cairo_surface_init (&surface->base, + &cairo_pdf_surface_backend, + NULL, /* device */ CAIRO_CONTENT_COLOR_ALPHA); surface->output = output; @@ -482,30 +504,49 @@ _cairo_surface_is_pdf (cairo_surface_t *surface) /* If the abstract_surface is a paginated surface, and that paginated * surface's target is a pdf_surface, then set pdf_surface to that - * target. Otherwise return %CAIRO_STATUS_SURFACE_TYPE_MISMATCH. + * target. Otherwise return FALSE. */ -static cairo_status_t +static cairo_bool_t _extract_pdf_surface (cairo_surface_t *surface, cairo_pdf_surface_t **pdf_surface) { cairo_surface_t *target; + cairo_status_t status_ignored; if (surface->status) - return surface->status; + return FALSE; + if (surface->finished) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } - if (! _cairo_surface_is_paginated (surface)) - return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + if (! _cairo_surface_is_paginated (surface)) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } target = _cairo_paginated_surface_get_target (surface); - if (target->status) - return target->status; + if (target->status) { + status_ignored = _cairo_surface_set_error (surface, + target->status); + return FALSE; + } + if (target->finished) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } - if (! _cairo_surface_is_pdf (target)) - return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + if (! _cairo_surface_is_pdf (target)) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } *pdf_surface = (cairo_pdf_surface_t *) target; - - return CAIRO_STATUS_SUCCESS; + return TRUE; } /** @@ -528,13 +569,9 @@ cairo_pdf_surface_restrict_to_version (cairo_surface_t *abstract_surface, cairo_pdf_version_t version) { cairo_pdf_surface_t *surface = NULL; /* hide compiler warning */ - cairo_status_t status; - status = _extract_pdf_surface (abstract_surface, &surface); - if (status) { - status = _cairo_surface_set_error (abstract_surface, status); + if (! _extract_pdf_surface (abstract_surface, &surface)) return; - } if (version < CAIRO_PDF_VERSION_LAST) surface->pdf_version = version; @@ -608,13 +645,9 @@ cairo_pdf_surface_set_size (cairo_surface_t *surface, double height_in_points) { cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */ - cairo_status_t status; - status = _extract_pdf_surface (surface, &pdf_surface); - if (unlikely (status)) { - status = _cairo_surface_set_error (surface, status); + if (! _extract_pdf_surface (surface, &pdf_surface)) return; - } _cairo_pdf_surface_set_size_internal (pdf_surface, width_in_points, @@ -1008,10 +1041,10 @@ _cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key) } static cairo_int_status_t -_get_jpx_image_info (cairo_surface_t *source, - cairo_image_info_t *info, - const unsigned char **mime_data, - unsigned int *mime_data_length) +_get_jpx_image_info (cairo_surface_t *source, + cairo_image_info_t *info, + const unsigned char **mime_data, + unsigned long *mime_data_length) { cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2, mime_data, mime_data_length); @@ -1022,10 +1055,10 @@ _get_jpx_image_info (cairo_surface_t *source, } static cairo_int_status_t -_get_jpeg_image_info (cairo_surface_t *source, +_get_jpeg_image_info (cairo_surface_t *source, cairo_image_info_t *info, const unsigned char **mime_data, - unsigned int *mime_data_length) + unsigned long *mime_data_length) { cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, mime_data, mime_data_length); @@ -1044,20 +1077,28 @@ _get_source_surface_size (cairo_surface_t *source, cairo_rectangle_int_t extents; cairo_image_info_t info; const unsigned char *mime_data; - unsigned int mime_data_length; + unsigned long mime_data_length; - if (_cairo_surface_is_recording (source)) { - cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) source; - cairo_box_t bbox; + if (source->type == CAIRO_SURFACE_TYPE_RECORDING) { + if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source; - status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL); - if (unlikely (status)) - return status; + *width = sub->extents.width; + *height = sub->extents.height; - _cairo_box_round_to_rectangle (&bbox, &extents); + } else { + cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) source; + cairo_box_t bbox; - *width = extents.width; - *height = extents.height; + status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL); + if (unlikely (status)) + return status; + + _cairo_box_round_to_rectangle (&bbox, &extents); + + *width = extents.width; + *height = extents.height; + } return CAIRO_STATUS_SUCCESS; } @@ -1136,6 +1177,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface, src_surface.surface = cairo_surface_reference (source); surface_entry->surface_res = _cairo_pdf_surface_new_object (surface); if (surface_entry->surface_res.id == 0) { + cairo_surface_destroy (source); free (surface_entry); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -1145,6 +1187,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface, status = _cairo_array_append (&surface->page_surfaces, &src_surface); if (unlikely (status)) { + cairo_surface_destroy (source); free (surface_entry); return status; } @@ -1176,25 +1219,6 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface, return CAIRO_STATUS_SUCCESS; } - if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || - pattern->type == CAIRO_PATTERN_TYPE_RADIAL) - { - cairo_gradient_pattern_t *gradient; - - gradient = (cairo_gradient_pattern_t *) pattern; - - /* Gradients with zero stops do not produce any output */ - if (gradient->n_stops == 0) - return CAIRO_INT_STATUS_NOTHING_TO_DO; - - /* Gradients with one stop are the same as solid colors */ - if (gradient->n_stops == 1) { - pattern_res->id = 0; - gstate_res->id = 0; - return CAIRO_STATUS_SUCCESS; - } - } - status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern); if (unlikely (status)) return status; @@ -1209,8 +1233,9 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface, /* gradient patterns require an smask object to implement transparency */ if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || - pattern->type == CAIRO_PATTERN_TYPE_RADIAL) { - if (_cairo_pattern_is_opaque (pattern) == FALSE) { + pattern->type == CAIRO_PATTERN_TYPE_RADIAL) + { + if (_cairo_pattern_is_opaque (pattern, extents) == FALSE) { pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface); if (pdf_pattern.gstate_res.id == 0) { cairo_pattern_destroy (pdf_pattern.pattern); @@ -1219,14 +1244,14 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface, } } - pdf_pattern.width = surface->width; + pdf_pattern.width = surface->width; pdf_pattern.height = surface->height; if (extents != NULL) { pdf_pattern.extents = *extents; } else { pdf_pattern.extents.x = 0; pdf_pattern.extents.y = 0; - pdf_pattern.extents.width = surface->width; + pdf_pattern.extents.width = surface->width; pdf_pattern.extents.height = surface->height; } @@ -1979,7 +2004,7 @@ _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface, { cairo_status_t status; const unsigned char *mime_data; - unsigned int mime_data_length; + unsigned long mime_data_length; cairo_image_info_t info; if (surface->pdf_version < CAIRO_PDF_VERSION_1_5) @@ -2020,7 +2045,7 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, { cairo_status_t status; const unsigned char *mime_data; - unsigned int mime_data_length; + unsigned long mime_data_length; cairo_image_info_t info; cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, @@ -2237,7 +2262,67 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, surface->height); } - status = _cairo_recording_surface_replay_region (recording_surface, &surface->base, + status = _cairo_recording_surface_replay_region (recording_surface, + NULL, + &surface->base, + CAIRO_RECORDING_REGION_NATIVE); + assert (status != CAIRO_INT_STATUS_UNSUPPORTED); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_close_content_stream (surface); + + _cairo_pdf_surface_set_size_internal (surface, + old_width, + old_height); + surface->paginated_mode = old_paginated_mode; + + return status; +} + +static cairo_status_t +_cairo_pdf_surface_emit_recording_subsurface (cairo_pdf_surface_t *surface, + cairo_surface_t *recording_surface, + const cairo_rectangle_int_t *extents, + cairo_pdf_resource_t resource) +{ + double old_width, old_height; + cairo_paginated_mode_t old_paginated_mode; + cairo_status_t status; + int alpha = 0; + + old_width = surface->width; + old_height = surface->height; + old_paginated_mode = surface->paginated_mode; + + _cairo_pdf_surface_set_size_internal (surface, + extents->width, + extents->height); + /* Patterns are emitted after fallback images. The paginated mode + * needs to be set to _RENDER while the recording surface is replayed + * back to this surface. + */ + surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER; + _cairo_pdf_group_resources_clear (&surface->resources); + status = _cairo_pdf_surface_open_content_stream (surface, &resource, TRUE); + if (unlikely (status)) + return status; + + if (cairo_surface_get_content (recording_surface) == CAIRO_CONTENT_COLOR) { + status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\n", + alpha, + surface->width, + surface->height); + } + + status = _cairo_recording_surface_replay_region (recording_surface, + extents, + &surface->base, CAIRO_RECORDING_REGION_NATIVE); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); if (unlikely (status)) @@ -2257,10 +2342,18 @@ static cairo_status_t _cairo_pdf_surface_emit_surface (cairo_pdf_surface_t *surface, cairo_pdf_source_surface_t *src_surface) { - if (_cairo_surface_is_recording (src_surface->surface)) { - return _cairo_pdf_surface_emit_recording_surface (surface, - src_surface->surface, - src_surface->hash_entry->surface_res); + if (src_surface->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + if (src_surface->surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) src_surface->surface; + return _cairo_pdf_surface_emit_recording_subsurface (surface, + sub->target, + &sub->extents, + src_surface->hash_entry->surface_res); + } else { + return _cairo_pdf_surface_emit_recording_surface (surface, + src_surface->surface, + src_surface->hash_entry->surface_res); + } } else { return _cairo_pdf_surface_emit_image_surface (surface, src_surface->surface, @@ -2287,7 +2380,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, char draw_surface[200]; if (pattern->base.extend == CAIRO_EXTEND_PAD && - ! _cairo_surface_is_recording (pattern->surface)) + pattern->surface->type != CAIRO_SURFACE_TYPE_RECORDING) { status = _cairo_pdf_surface_emit_padded_image_surface (surface, pdf_pattern, @@ -2418,7 +2511,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, if (unlikely (status)) return status; - if (_cairo_surface_is_recording (pattern->surface)) { + if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { snprintf(draw_surface, sizeof (draw_surface), "/x%d Do\n", @@ -2715,11 +2808,11 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, stops[n_stops-1].offset = 1.0; } - if (n_stops == 2) { + if (n_stops <= 2) { /* no need for stitched function */ status = cairo_pdf_surface_emit_rgb_linear_function (surface, &stops[0], - &stops[1], + &stops[n_stops - 1], color_function); if (unlikely (status)) goto BAIL; @@ -2727,7 +2820,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, if (emit_alpha) { status = cairo_pdf_surface_emit_alpha_linear_function (surface, &stops[0], - &stops[1], + &stops[n_stops - 1], alpha_function); if (unlikely (status)) goto BAIL; @@ -3289,7 +3382,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d); cairo_matrix_translate (&pdf_p2d, 0.0, height); cairo_matrix_scale (&pdf_p2d, 1.0, -1.0); - if (! _cairo_surface_is_recording (source->surface)) + if (source->surface->type != CAIRO_SURFACE_TYPE_RECORDING) cairo_matrix_scale (&pdf_p2d, width, height); status = _cairo_pdf_operators_flush (&surface->pdf_operators); @@ -3353,15 +3446,6 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface, solid_color = &solid->color; } - if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || - pattern->type == CAIRO_PATTERN_TYPE_RADIAL) - { - cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; - - if (gradient->n_stops == 1) - solid_color = &gradient->stops[0].color; - } - if (solid_color != NULL) { if (surface->current_pattern_is_solid_color == FALSE || surface->current_color_red != solid_color->red || @@ -3792,6 +3876,8 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface, return _cairo_pdf_surface_close_stream (surface); } +#define PDF_UNITS_PER_EM 1000 + static cairo_status_t _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset, @@ -3856,18 +3942,19 @@ _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface, " /ItalicAngle 0\n" " /Ascent %ld\n" " /Descent %ld\n" - " /CapHeight 500\n" + " /CapHeight %ld\n" " /StemV 80\n" " /StemH 80\n" " /FontFile3 %u 0 R\n" ">>\n" "endobj\n", - subset->x_min, - subset->y_min, - subset->x_max, - subset->y_max, - subset->ascent, - subset->descent, + (long)(subset->x_min*PDF_UNITS_PER_EM), + (long)(subset->y_min*PDF_UNITS_PER_EM), + (long)(subset->x_max*PDF_UNITS_PER_EM), + (long)(subset->y_max*PDF_UNITS_PER_EM), + (long)(subset->ascent*PDF_UNITS_PER_EM), + (long)(subset->descent*PDF_UNITS_PER_EM), + (long)(subset->y_max*PDF_UNITS_PER_EM), stream.id); cidfont_dict = _cairo_pdf_surface_new_object (surface); @@ -3893,8 +3980,8 @@ _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface, for (i = 0; i < font_subset->num_glyphs; i++) _cairo_output_stream_printf (surface->output, - " %d", - subset->widths[i]); + " %ld", + (long)(subset->widths[i]*PDF_UNITS_PER_EM)); _cairo_output_stream_printf (surface->output, " ]]\n" @@ -4031,7 +4118,7 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, " /ItalicAngle 0\n" " /Ascent %ld\n" " /Descent %ld\n" - " /CapHeight 500\n" + " /CapHeight %ld\n" " /StemV 80\n" " /StemH 80\n" " /FontFile %u 0 R\n" @@ -4040,12 +4127,13 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, descriptor.id, tag, subset->base_font, - subset->x_min, - subset->y_min, - subset->x_max, - subset->y_max, - subset->ascent, - subset->descent, + (long)(subset->x_min*PDF_UNITS_PER_EM), + (long)(subset->y_min*PDF_UNITS_PER_EM), + (long)(subset->x_max*PDF_UNITS_PER_EM), + (long)(subset->y_max*PDF_UNITS_PER_EM), + (long)(subset->ascent*PDF_UNITS_PER_EM), + (long)(subset->descent*PDF_UNITS_PER_EM), + (long)(subset->y_max*PDF_UNITS_PER_EM), stream.id); _cairo_pdf_surface_update_object (surface, subset_resource); @@ -4066,8 +4154,8 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, for (i = 0; i < font_subset->num_glyphs; i++) _cairo_output_stream_printf (surface->output, - " %d", - subset->widths[i]); + " %ld", + (long)(subset->widths[i]*PDF_UNITS_PER_EM)); _cairo_output_stream_printf (surface->output, " ]\n"); @@ -4129,8 +4217,6 @@ _cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t *surface, return status; } -#define PDF_UNITS_PER_EM 1000 - static cairo_status_t _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, cairo_scaled_font_subset_t *font_subset) @@ -4888,7 +4974,7 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface, case PDF_STROKE: status = _cairo_pdf_operators_stroke (&surface->pdf_operators, &group->path, - group->style, + &group->style, &group->ctm, &group->ctm_inverse); break; @@ -5087,7 +5173,7 @@ _surface_pattern_supported (cairo_surface_pattern_t *pattern) { cairo_extend_t extend; - if (_cairo_surface_is_recording (pattern->surface)) + if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) return TRUE; if (pattern->surface->backend->acquire_source_image == NULL) @@ -5211,7 +5297,8 @@ _pdf_operator_supported (cairo_operator_t op) static cairo_int_status_t _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface, cairo_operator_t op, - const cairo_pattern_t *pattern) + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) { if (surface->force_fallbacks && surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) @@ -5226,7 +5313,7 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface, if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; - if ( _cairo_surface_is_recording (surface_pattern->surface)) { + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { if (pattern->extend == CAIRO_EXTEND_PAD) return CAIRO_INT_STATUS_UNSUPPORTED; else @@ -5244,8 +5331,8 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface, if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; - if (_cairo_surface_is_recording (surface_pattern->surface)) { - if (_cairo_pattern_is_opaque (pattern)) { + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + if (_cairo_pattern_is_opaque (pattern, extents)) { return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; } else { /* FIXME: The analysis surface does not yet have @@ -5264,7 +5351,7 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface, } } - if (_cairo_pattern_is_opaque (pattern)) + if (_cairo_pattern_is_opaque (pattern, extents)) return CAIRO_STATUS_SUCCESS; else return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; @@ -5276,12 +5363,10 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface, static cairo_bool_t _cairo_pdf_surface_operation_supported (cairo_pdf_surface_t *surface, cairo_operator_t op, - const cairo_pattern_t *pattern) + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) { - if (_cairo_pdf_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED) - return TRUE; - else - return FALSE; + return _cairo_pdf_surface_analyze_operation (surface, op, pattern, extents) != CAIRO_INT_STATUS_UNSUPPORTED; } static cairo_int_status_t @@ -5311,17 +5396,32 @@ _cairo_pdf_surface_paint (void *abstract_surface, cairo_status_t status; cairo_pdf_smask_group_t *group; cairo_pdf_resource_t pattern_res, gstate_res; - cairo_rectangle_int_t extents; + cairo_composite_rectangles_t extents; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_paint (&extents, + &rect, + op, source, clip); + if (unlikely (status)) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; + + return status; + } if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { - return _cairo_pdf_surface_analyze_operation (surface, op, source); + return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) { status = _cairo_pdf_surface_start_fallback (surface); if (unlikely (status)) return status; } - assert (_cairo_pdf_surface_operation_supported (surface, op, source)); + assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded)); status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) @@ -5336,8 +5436,8 @@ _cairo_pdf_surface_paint (void *abstract_surface, return status; if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - source->extend == CAIRO_EXTEND_NONE) { - + source->extend == CAIRO_EXTEND_NONE) + { _cairo_output_stream_printf (surface->output, "q\n"); status = _cairo_pdf_surface_paint_surface_pattern (surface, (cairo_surface_pattern_t *) source); @@ -5348,15 +5448,10 @@ _cairo_pdf_surface_paint (void *abstract_surface, return _cairo_output_stream_get_status (surface->output); } - status = _cairo_surface_paint_extents (&surface->base, - op, source, clip, - &extents); - if (unlikely (status)) - return status; - pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, + &extents.bounded, &pattern_res, &gstate_res); if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) return CAIRO_STATUS_SUCCESS; @@ -5421,18 +5516,34 @@ _cairo_pdf_surface_mask (void *abstract_surface, cairo_pdf_surface_t *surface = abstract_surface; cairo_pdf_smask_group_t *group; cairo_status_t status; + cairo_composite_rectangles_t extents; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_mask (&extents, + &rect, + op, source, mask, clip); + if (unlikely (status)) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; + + return status; + } if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { cairo_status_t source_status, mask_status; - source_status = _cairo_pdf_surface_analyze_operation (surface, op, source); + source_status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); if (_cairo_status_is_error (source_status)) return source_status; if (mask->has_component_alpha) { mask_status = CAIRO_INT_STATUS_UNSUPPORTED; } else { - mask_status = _cairo_pdf_surface_analyze_operation (surface, op, mask); + mask_status = _cairo_pdf_surface_analyze_operation (surface, op, mask, &extents.bounded); if (_cairo_status_is_error (mask_status)) return mask_status; } @@ -5445,8 +5556,8 @@ _cairo_pdf_surface_mask (void *abstract_surface, return status; } - assert (_cairo_pdf_surface_operation_supported (surface, op, source)); - assert (_cairo_pdf_surface_operation_supported (surface, op, mask)); + assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded)); + assert (_cairo_pdf_surface_operation_supported (surface, op, mask, &extents.bounded)); status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) @@ -5508,39 +5619,62 @@ _cairo_pdf_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; - cairo_status_t status; cairo_pdf_smask_group_t *group; cairo_pdf_resource_t pattern_res, gstate_res; - cairo_rectangle_int_t extents; + cairo_composite_rectangles_t extents; + cairo_status_t status; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_stroke (&extents, + &rect, + op, source, + path, style, ctm, + clip); + if (unlikely (status)) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; + + return status; + } + + /* use the more accurate extents */ + if (extents.is_bounded) { + status = _cairo_path_fixed_stroke_extents (path, style, + ctm, ctm_inverse, + tolerance, + &extents.mask); + if (unlikely (status)) + return status; + + if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask)) + return CAIRO_STATUS_SUCCESS; + } if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _cairo_pdf_surface_analyze_operation (surface, op, source); + return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); - assert (_cairo_pdf_surface_operation_supported (surface, op, source)); + assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded)); status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _cairo_surface_stroke_extents (&surface->base, - op, source, path, - style, ctm, ctm_inverse, - tolerance, antialias, - clip, &extents); - if (unlikely (status)) - return status; - pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, + &extents.bounded, &pattern_res, &gstate_res); if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) return CAIRO_STATUS_SUCCESS; @@ -5569,7 +5703,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface, return status; } - group->style = style; + group->style = *style; group->ctm = *ctm; group->ctm_inverse = *ctm_inverse; status = _cairo_pdf_surface_add_smask_group (surface, group); @@ -5629,17 +5763,44 @@ _cairo_pdf_surface_fill (void *abstract_surface, cairo_status_t status; cairo_pdf_smask_group_t *group; cairo_pdf_resource_t pattern_res, gstate_res; - cairo_rectangle_int_t extents; + cairo_composite_rectangles_t extents; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_fill (&extents, + &rect, + op, source, path, + clip); + if (unlikely (status)) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; + + return status; + } + + /* use the more accurate extents */ + if (extents.is_bounded) { + _cairo_path_fixed_fill_extents (path, + fill_rule, + tolerance, + &extents.mask); + + if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask)) + return CAIRO_STATUS_SUCCESS; + } if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { - return _cairo_pdf_surface_analyze_operation (surface, op, source); + return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) { status = _cairo_pdf_surface_start_fallback (surface); if (unlikely (status)) return status; } - assert (_cairo_pdf_surface_operation_supported (surface, op, source)); + assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded)); status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) @@ -5650,8 +5811,8 @@ _cairo_pdf_surface_fill (void *abstract_surface, return status; if (source->type == CAIRO_PATTERN_TYPE_SURFACE && - source->extend == CAIRO_EXTEND_NONE) { - + source->extend == CAIRO_EXTEND_NONE) + { status = _cairo_pdf_operators_flush (&surface->pdf_operators); if (unlikely (status)) return status; @@ -5672,16 +5833,10 @@ _cairo_pdf_surface_fill (void *abstract_surface, return _cairo_output_stream_get_status (surface->output); } - status = _cairo_surface_fill_extents (&surface->base, - op, source, path, fill_rule, - tolerance, antialias, - clip, &extents); - if (unlikely (status)) - return status; - pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, + &extents.bounded, &pattern_res, &gstate_res); if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) return CAIRO_STATUS_SUCCESS; @@ -5749,21 +5904,21 @@ _cairo_pdf_surface_fill (void *abstract_surface, } static cairo_int_status_t -_cairo_pdf_surface_fill_stroke (void *abstract_surface, - cairo_operator_t fill_op, - const cairo_pattern_t *fill_source, - cairo_fill_rule_t fill_rule, - double fill_tolerance, - cairo_antialias_t fill_antialias, - cairo_path_fixed_t *path, - cairo_operator_t stroke_op, - const cairo_pattern_t *stroke_source, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *stroke_ctm, - cairo_matrix_t *stroke_ctm_inverse, - double stroke_tolerance, - cairo_antialias_t stroke_antialias, - cairo_clip_t *clip) +_cairo_pdf_surface_fill_stroke (void *abstract_surface, + cairo_operator_t fill_op, + const cairo_pattern_t *fill_source, + cairo_fill_rule_t fill_rule, + double fill_tolerance, + cairo_antialias_t fill_antialias, + cairo_path_fixed_t *path, + cairo_operator_t stroke_op, + const cairo_pattern_t *stroke_source, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, + double stroke_tolerance, + cairo_antialias_t stroke_antialias, + cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; cairo_status_t status; @@ -5783,8 +5938,8 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface, /* PDF rendering of fill-stroke is not the same as cairo when * either the fill or stroke is not opaque. */ - if ( !_cairo_pattern_is_opaque (fill_source) || - !_cairo_pattern_is_opaque (stroke_source)) + if ( !_cairo_pattern_is_opaque (fill_source, NULL) || + !_cairo_pattern_is_opaque (stroke_source, NULL)) { return CAIRO_INT_STATUS_UNSUPPORTED; } @@ -5888,30 +6043,44 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, cairo_clip_t *clip) { cairo_pdf_surface_t *surface = abstract_surface; - cairo_status_t status; cairo_pdf_smask_group_t *group; cairo_pdf_resource_t pattern_res, gstate_res; - cairo_rectangle_int_t extents; + cairo_composite_rectangles_t extents; + cairo_bool_t overlap; + cairo_status_t status; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_glyphs (&extents, + &rect, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, + &overlap); + if (unlikely (status)) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; + + return status; + } if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _cairo_pdf_surface_analyze_operation (surface, op, source); + return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); - assert (_cairo_pdf_surface_operation_supported (surface, op, source)); + assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded)); status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _cairo_surface_glyphs_extents (&surface->base, op, source, - glyphs, num_glyphs, - scaled_font, - clip, &extents); - if (unlikely (status)) - return status; - pattern_res.id = 0; gstate_res.id = 0; - status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents, + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, + &extents.bounded, &pattern_res, &gstate_res); if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) return CAIRO_STATUS_SUCCESS; @@ -5997,7 +6166,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface, * be in a separate text object otherwise overlapping text * from separate calls to show_glyphs will not composite with * each other. */ - if (! _cairo_pattern_is_opaque (source)) { + if (! _cairo_pattern_is_opaque (source, &extents.bounded)) { status = _cairo_pdf_operators_flush (&surface->pdf_operators); if (unlikely (status)) return status; diff --git a/gfx/cairo/cairo/src/cairo-pdf.h b/gfx/cairo/cairo/src/cairo-pdf.h index c0de5386fb0d..50460ccdfbdc 100644 --- a/gfx/cairo/cairo/src/cairo-pdf.h +++ b/gfx/cairo/cairo/src/cairo-pdf.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-pen.c b/gfx/cairo/cairo/src/cairo-pen.c index cfb67cae467b..e71f7b561b41 100644 --- a/gfx/cairo/cairo/src/cairo-pen.c +++ b/gfx/cairo/cairo/src/cairo-pen.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,6 +38,7 @@ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-slope-private.h" static int diff --git a/gfx/cairo/cairo/src/cairo-png.c b/gfx/cairo/cairo/src/cairo-png.c index d4f04760baa6..41a33d75338f 100644 --- a/gfx/cairo/cairo/src/cairo-png.c +++ b/gfx/cairo/cairo/src/cairo-png.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,12 +37,32 @@ */ #include "cairoint.h" + +#include "cairo-error-private.h" #include "cairo-output-stream-private.h" #include #include #include +/** + * SECTION:cairo-png + * @Title: PNG Support + * @Short_Description: Reading and writing PNG images + * @See_Also: #cairo_surface_t + * + * The PNG functions allow reading PNG images into image surfaces, and writing + * any surface to a PNG file. + */ + +/** + * CAIRO_HAS_PNG_FUNCTIONS: + * + * Defined if the PNG functions are available. + * This macro can be used to conditionally compile code using the cairo + * PNG functions. + */ + struct png_read_closure_t { cairo_read_func_t read_func; void *closure; @@ -170,14 +190,10 @@ write_png (cairo_surface_t *surface, /* Handle the various fallback formats (e.g. low bit-depth XServers) * by coercing them to a simpler format using pixman. */ - if (image->format == CAIRO_FORMAT_INVALID) { - clone = _cairo_image_surface_coerce (image, - _cairo_format_from_content (image->base.content)); - status = clone->base.status; - if (unlikely (status)) - goto BAIL1; - } else - clone = image; + clone = _cairo_image_surface_coerce (image); + status = clone->base.status; + if (unlikely (status)) + goto BAIL1; rows = _cairo_malloc_ab (clone->height, sizeof (png_byte*)); if (unlikely (rows == NULL)) { @@ -232,6 +248,8 @@ write_png (cairo_surface_t *surface, png_set_packswap (png); #endif break; + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_RGB16_565: default: status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT); goto BAIL4; @@ -277,8 +295,7 @@ BAIL4: BAIL3: free (rows); BAIL2: - if (clone != image) - cairo_surface_destroy (&clone->base); + cairo_surface_destroy (&clone->base); BAIL1: _cairo_surface_release_source_image (surface, image, image_extra); @@ -512,7 +529,7 @@ read_png (struct png_read_closure_t *png_closure) cairo_format_t format; cairo_status_t status; unsigned char *mime_data; - unsigned int mime_data_length; + unsigned long mime_data_length; png_closure->png_data = _cairo_memory_stream_create (); diff --git a/gfx/cairo/cairo/src/cairo-polygon.c b/gfx/cairo/cairo/src/cairo-polygon.c index 9cb76e557bc4..64fef47e1e4e 100644 --- a/gfx/cairo/cairo/src/cairo-polygon.c +++ b/gfx/cairo/cairo/src/cairo-polygon.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -36,6 +36,7 @@ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-slope-private.h" void @@ -139,7 +140,7 @@ _add_edge (cairo_polygon_t *polygon, assert (top < bottom); - if (polygon->num_edges == polygon->edges_size) { + if (unlikely (polygon->num_edges == polygon->edges_size)) { if (! _cairo_polygon_grow (polygon)) return; } @@ -196,7 +197,20 @@ _add_clipped_edge (cairo_polygon_t *polygon, if (bottom <= limits->p1.y) continue; - if (p1->x <= limits->p1.x && p2->x <= limits->p1.x) + if (p1->x >= limits->p1.x && p2->x >= limits->p1.x && + p1->x <= limits->p2.x && p2->x <= limits->p2.x) + { + top_y = top; + if (top_y < limits->p1.y) + top_y = limits->p1.y; + + bot_y = bottom; + if (bot_y > limits->p2.y) + bot_y = limits->p2.y; + + _add_edge (polygon, p1, p2, top_y, bot_y, dir); + } + else if (p1->x <= limits->p1.x && p2->x <= limits->p1.x) { p[0].x = limits->p1.x; p[0].y = limits->p1.y; @@ -228,19 +242,6 @@ _add_clipped_edge (cairo_polygon_t *polygon, _add_edge (polygon, &p[0], &p[1], top_y, bot_y, dir); } - else if (p1->x >= limits->p1.x && p2->x >= limits->p1.x && - p1->x <= limits->p2.x && p2->x <= limits->p2.x) - { - top_y = top; - if (top_y < limits->p1.y) - top_y = limits->p1.y; - - bot_y = bottom; - if (bot_y > limits->p2.y) - bot_y = limits->p2.y; - - _add_edge (polygon, p1, p2, top_y, bot_y, dir); - } else { int left_y, right_y; diff --git a/gfx/cairo/cairo/src/cairo-private.h b/gfx/cairo/cairo/src/cairo-private.h index a60a6aa361dd..901a69a31952 100644 --- a/gfx/cairo/cairo/src/cairo-private.h +++ b/gfx/cairo/cairo/src/cairo-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-ps-surface-private.h b/gfx/cairo/cairo/src/cairo-ps-surface-private.h index 3dc000802dc5..a5a8cd0dae3d 100644 --- a/gfx/cairo/cairo/src/cairo-ps-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-ps-surface-private.h @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-ps-surface.c b/gfx/cairo/cairo/src/cairo-ps-surface.c index d0a26c5eb0e8..4e7fb132ba10 100644 --- a/gfx/cairo/cairo/src/cairo-ps-surface.c +++ b/gfx/cairo/cairo/src/cairo-ps-surface.c @@ -15,7 +15,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -58,10 +58,13 @@ #include "cairo-ps.h" #include "cairo-ps-surface-private.h" #include "cairo-pdf-operators-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-error-private.h" #include "cairo-scaled-font-subsets-private.h" #include "cairo-paginated-private.h" #include "cairo-recording-surface-private.h" #include "cairo-surface-clipper-private.h" +#include "cairo-surface-subsurface-private.h" #include "cairo-output-stream-private.h" #include "cairo-type3-glyph-surface-private.h" #include "cairo-image-info-private.h" @@ -85,6 +88,23 @@ #define ctime_r(T, BUF) ctime (T) #endif +/** + * SECTION:cairo-ps + * @Title: PostScript Surfaces + * @Short_Description: Rendering PostScript documents + * @See_Also: #cairo_surface_t + * + * The PostScript surface is used to render cairo graphics to Adobe + * PostScript files and is a multi-page vector surface backend. + */ + +/** + * CAIRO_HAS_PS_SURFACE: + * + * Defined if the PostScript surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + */ + static const cairo_surface_backend_t cairo_ps_surface_backend; static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend; @@ -254,8 +274,6 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface) "/S { stroke } bind def\n" "/f { fill } bind def\n" "/f* { eofill } bind def\n" - "/B { fill stroke } bind def\n" - "/B* { eofill stroke } bind def\n" "/n { newpath } bind def\n" "/W { clip } bind def\n" "/W* { eoclip } bind def\n" @@ -531,6 +549,7 @@ _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_sub break; } + cairo_surface_finish (type3_surface); cairo_surface_destroy (type3_surface); return status; @@ -615,6 +634,7 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, font_bbox.p2.y = bbox.p2.y; } } + cairo_surface_finish (type3_surface); cairo_surface_destroy (type3_surface); if (unlikely (status)) return status; @@ -703,28 +723,23 @@ _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface) _cairo_ps_surface_analyze_user_font_subset, surface); if (unlikely (status)) - goto BAIL; + return status; status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets, _cairo_ps_surface_emit_unscaled_font_subset, surface); if (unlikely (status)) - goto BAIL; + return status; status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets, _cairo_ps_surface_emit_scaled_font_subset, surface); if (unlikely (status)) - goto BAIL; + return status; - status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets, - _cairo_ps_surface_emit_scaled_font_subset, - surface); -BAIL: - _cairo_scaled_font_subsets_destroy (surface->font_subsets); - surface->font_subsets = NULL; - - return status; + return _cairo_scaled_font_subsets_foreach_user (surface->font_subsets, + _cairo_ps_surface_emit_scaled_font_subset, + surface); } static cairo_status_t @@ -878,12 +893,13 @@ _cairo_ps_surface_get_page_media (cairo_ps_surface_t *surface) page->name = strdup (page_name); } else { snprintf (buf, sizeof (buf), "%dx%dmm", - _cairo_lround (surface->width * 25.4/72), - _cairo_lround (surface->height * 25.4/72)); + (int) _cairo_lround (surface->width * 25.4/72), + (int) _cairo_lround (surface->height * 25.4/72)); page->name = strdup (buf); } if (unlikely (page->name == NULL)) { + free (page); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); return NULL; } @@ -909,7 +925,9 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, goto CLEANUP; } - _cairo_surface_init (&surface->base, &cairo_ps_surface_backend, + _cairo_surface_init (&surface->base, + &cairo_ps_surface_backend, + NULL, /* device */ CAIRO_CONTENT_COLOR_ALPHA); surface->final_stream = stream; @@ -951,6 +969,11 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, surface->use_string_datasource = FALSE; surface->current_pattern_is_solid_color = FALSE; + surface->page_bbox.x = 0; + surface->page_bbox.y = 0; + surface->page_bbox.width = width; + surface->page_bbox.height = height; + _cairo_surface_clipper_init (&surface->clipper, _cairo_ps_surface_clipper_intersect_clip_path); @@ -1087,30 +1110,54 @@ _cairo_surface_is_ps (cairo_surface_t *surface) /* If the abstract_surface is a paginated surface, and that paginated * surface's target is a ps_surface, then set ps_surface to that - * target. Otherwise return %CAIRO_STATUS_SURFACE_TYPE_MISMATCH. + * target. Otherwise return FALSE. */ -static cairo_status_t +static cairo_bool_t _extract_ps_surface (cairo_surface_t *surface, + cairo_bool_t set_error_on_failure, cairo_ps_surface_t **ps_surface) { cairo_surface_t *target; + cairo_status_t status_ignored; if (surface->status) - return surface->status; + return FALSE; + if (surface->finished) { + if (set_error_on_failure) + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } - if (! _cairo_surface_is_paginated (surface)) - return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + if (! _cairo_surface_is_paginated (surface)) { + if (set_error_on_failure) + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } target = _cairo_paginated_surface_get_target (surface); - if (target->status) - return target->status; + if (target->status) { + if (set_error_on_failure) + status_ignored = _cairo_surface_set_error (surface, target->status); + return FALSE; + } + if (target->finished) { + if (set_error_on_failure) + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } - if (! _cairo_surface_is_ps (target)) - return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + if (! _cairo_surface_is_ps (target)) { + if (set_error_on_failure) + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } *ps_surface = (cairo_ps_surface_t *) target; - - return CAIRO_STATUS_SUCCESS; + return TRUE; } /** @@ -1134,13 +1181,9 @@ cairo_ps_surface_restrict_to_level (cairo_surface_t *surface, cairo_ps_level_t level) { cairo_ps_surface_t *ps_surface = NULL; - cairo_status_t status; - status = _extract_ps_surface (surface, &ps_surface); - if (unlikely (status)) { - status = _cairo_surface_set_error (surface, status); + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) return; - } if (level < CAIRO_PS_LEVEL_LAST) ps_surface->ps_level = level; @@ -1209,13 +1252,9 @@ cairo_ps_surface_set_eps (cairo_surface_t *surface, cairo_bool_t eps) { cairo_ps_surface_t *ps_surface = NULL; - cairo_status_t status; - status = _extract_ps_surface (surface, &ps_surface); - if (unlikely (status)) { - status = _cairo_surface_set_error (surface, status); + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) return; - } ps_surface->eps = eps; } @@ -1234,13 +1273,9 @@ cairo_public cairo_bool_t cairo_ps_surface_get_eps (cairo_surface_t *surface) { cairo_ps_surface_t *ps_surface = NULL; - cairo_status_t status; - status = _extract_ps_surface (surface, &ps_surface); - if (unlikely (status)) { - status = _cairo_surface_set_error (surface, status); + if (! _extract_ps_surface (surface, FALSE, &ps_surface)) return FALSE; - } return ps_surface->eps; } @@ -1268,13 +1303,9 @@ cairo_ps_surface_set_size (cairo_surface_t *surface, double height_in_points) { cairo_ps_surface_t *ps_surface = NULL; - cairo_status_t status; - status = _extract_ps_surface (surface, &ps_surface); - if (unlikely (status)) { - status = _cairo_surface_set_error (surface, status); + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) return; - } ps_surface->width = width_in_points; ps_surface->height = height_in_points; @@ -1379,11 +1410,8 @@ cairo_ps_surface_dsc_comment (cairo_surface_t *surface, cairo_status_t status; char *comment_copy; - status = _extract_ps_surface (surface, &ps_surface); - if (unlikely (status)) { - status = _cairo_surface_set_error (surface, status); + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) return; - } /* A couple of sanity checks on the comment value. */ if (comment == NULL) { @@ -1431,18 +1459,12 @@ void cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface) { cairo_ps_surface_t *ps_surface = NULL; - cairo_status_t status; - status = _extract_ps_surface (surface, &ps_surface); - if (unlikely (status)) { - status = _cairo_surface_set_error (surface, status); + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) return; - } if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments) - { ps_surface->dsc_comment_target = &ps_surface->dsc_setup_comments; - } } /** @@ -1466,13 +1488,9 @@ void cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface) { cairo_ps_surface_t *ps_surface = NULL; - cairo_status_t status; - status = _extract_ps_surface (surface, &ps_surface); - if (unlikely (status)) { - status = _cairo_surface_set_error (surface, status); + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) return; - } if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments || ps_surface->dsc_comment_target == &ps_surface->dsc_setup_comments) @@ -1489,6 +1507,10 @@ _cairo_ps_surface_finish (void *abstract_surface) int i, num_comments; char **comments; + status = surface->base.status; + if (unlikely (status)) + goto CLEANUP; + _cairo_ps_surface_emit_header (surface); status = _cairo_ps_surface_emit_font_subsets (surface); @@ -1502,6 +1524,8 @@ _cairo_ps_surface_finish (void *abstract_surface) _cairo_ps_surface_emit_footer (surface); CLEANUP: + _cairo_scaled_font_subsets_destroy (surface->font_subsets); + status2 = _cairo_output_stream_destroy (surface->stream); if (status == CAIRO_STATUS_SUCCESS) status = status2; @@ -1648,7 +1672,7 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t static cairo_bool_t surface_pattern_supported (const cairo_surface_pattern_t *pattern) { - if (_cairo_surface_is_recording (pattern->surface)) + if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) return TRUE; if (pattern->surface->backend->acquire_source_image == NULL) @@ -1658,7 +1682,7 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern) * don't think it's worth the extra code to support it. */ /* XXX: Need to write this function here... - content = cairo_surface_get_content (pattern->surface); + content = pattern->surface->content; if (content == CAIRO_CONTENT_ALPHA) return FALSE; */ @@ -1739,7 +1763,8 @@ pattern_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern) static cairo_int_status_t _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, cairo_operator_t op, - const cairo_pattern_t *pattern) + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) { if (surface->force_fallbacks && surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) @@ -1758,7 +1783,7 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; - if ( _cairo_surface_is_recording (surface_pattern->surface)) { + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { if (pattern->extend == CAIRO_EXTEND_PAD) return CAIRO_INT_STATUS_UNSUPPORTED; else @@ -1785,7 +1810,7 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, surface_pattern); } - if (_cairo_pattern_is_opaque (pattern)) + if (_cairo_pattern_is_opaque (pattern, extents)) return CAIRO_STATUS_SUCCESS; return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; @@ -1794,12 +1819,10 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, static cairo_bool_t _cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface, cairo_operator_t op, - const cairo_pattern_t *pattern) + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) { - if (_cairo_ps_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED) - return TRUE; - else - return FALSE; + return _cairo_ps_surface_analyze_operation (surface, op, pattern, extents) != CAIRO_INT_STATUS_UNSUPPORTED; } /* The "standard" implementation limit for PostScript string sizes is @@ -1971,55 +1994,38 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface, cairo_image_surface_t *image, cairo_image_surface_t **opaque_image) { - const cairo_color_t *background_color; cairo_surface_t *opaque; cairo_surface_pattern_t pattern; cairo_status_t status; - if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) - background_color = CAIRO_COLOR_WHITE; - else - background_color = CAIRO_COLOR_BLACK; - opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24, image->width, image->height); - if (opaque->status) + if (unlikely (opaque->status)) return opaque->status; - _cairo_pattern_init_for_surface (&pattern, &image->base); - - status = _cairo_surface_fill_rectangle (opaque, - CAIRO_OPERATOR_SOURCE, - background_color, - 0, 0, - image->width, image->height); - if (unlikely (status)) - goto fail; - - status = _cairo_surface_composite (CAIRO_OPERATOR_OVER, - &pattern.base, - NULL, - opaque, - 0, 0, - 0, 0, - 0, 0, - image->width, - image->height, + if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) { + status = _cairo_surface_paint (opaque, + CAIRO_OPERATOR_SOURCE, + &_cairo_pattern_white.base, NULL); - if (unlikely (status)) - goto fail; + if (unlikely (status)) { + cairo_surface_destroy (opaque); + return status; + } + } + _cairo_pattern_init_for_surface (&pattern, &image->base); + pattern.base.filter = CAIRO_FILTER_NEAREST; + status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL); _cairo_pattern_fini (&pattern.base); + if (unlikely (status)) { + cairo_surface_destroy (opaque); + return status; + } + *opaque_image = (cairo_image_surface_t *) opaque; - return CAIRO_STATUS_SUCCESS; - -fail: - _cairo_pattern_fini (&pattern.base); - cairo_surface_destroy (opaque); - - return status; } static cairo_status_t @@ -2321,7 +2327,7 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface, { cairo_status_t status; const unsigned char *mime_data; - unsigned int mime_data_length; + unsigned long mime_data_length; cairo_image_info_t info; cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, @@ -2445,7 +2451,7 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface, &surface->cairo_to_ps); _cairo_output_stream_printf (surface->stream, " q\n"); - if (cairo_surface_get_content (recording_surface) == CAIRO_CONTENT_COLOR) { + if (recording_surface->content == CAIRO_CONTENT_COLOR) { surface->content = CAIRO_CONTENT_COLOR; _cairo_output_stream_printf (surface->stream, " 0 g %d %d %d %d rectfill\n", @@ -2455,7 +2461,81 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface, surface->page_bbox.height); } - status = _cairo_recording_surface_replay_region (recording_surface, &surface->base, + status = _cairo_recording_surface_replay_region (recording_surface, + NULL, + &surface->base, + CAIRO_RECORDING_REGION_NATIVE); + assert (status != CAIRO_INT_STATUS_UNSUPPORTED); + if (unlikely (status)) + return status; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->stream, " Q\n"); + surface->content = old_content; + surface->width = old_width; + surface->height = old_height; + surface->page_bbox = old_page_bbox; + surface->current_pattern_is_solid_color = FALSE; + _cairo_pdf_operators_reset (&surface->pdf_operators); + surface->cairo_to_ps = old_cairo_to_ps; + + _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators, + &surface->cairo_to_ps); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface, + cairo_surface_t *recording_surface, + const cairo_rectangle_int_t *extents) +{ + double old_width, old_height; + cairo_matrix_t old_cairo_to_ps; + cairo_content_t old_content; + cairo_rectangle_int_t old_page_bbox; + cairo_status_t status; + + old_content = surface->content; + old_width = surface->width; + old_height = surface->height; + old_page_bbox = surface->page_bbox; + old_cairo_to_ps = surface->cairo_to_ps; + +#if DEBUG_PS + _cairo_output_stream_printf (surface->stream, + "%% _cairo_ps_surface_emit_recording_subsurface (%d, %d), (%d, %d)\n", + extents->x, extents->y, + extents->width, extents->height); +#endif + + surface->page_bbox.x = surface->page_bbox.y = 0; + surface->page_bbox.width = surface->width = extents->width; + surface->page_bbox.height = surface->height = extents->height; + + surface->current_pattern_is_solid_color = FALSE; + _cairo_pdf_operators_reset (&surface->pdf_operators); + cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height); + _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators, + &surface->cairo_to_ps); + _cairo_output_stream_printf (surface->stream, " q\n"); + + if (recording_surface->content == CAIRO_CONTENT_COLOR) { + surface->content = CAIRO_CONTENT_COLOR; + _cairo_output_stream_printf (surface->stream, + " 0 g %d %d %d %d rectfill\n", + surface->page_bbox.x, + surface->page_bbox.y, + surface->page_bbox.width, + surface->page_bbox.height); + } + + status = _cairo_recording_surface_replay_region (recording_surface, + extents, + &surface->base, CAIRO_RECORDING_REGION_NATIVE); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); if (unlikely (status)) @@ -2539,18 +2619,25 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, surface->acquired_image = NULL; surface->image = NULL; - if (_cairo_surface_is_recording (pattern->surface)) { - cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) pattern->surface; - cairo_box_t bbox; - cairo_rectangle_int_t extents; + if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + if (pattern->surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) pattern->surface; - status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL); - if (unlikely (status)) - return status; + *width = sub->extents.width; + *height = sub->extents.height; + } else { + cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) pattern->surface; + cairo_box_t bbox; + cairo_rectangle_int_t extents; - _cairo_box_round_to_rectangle (&bbox, &extents); - *width = extents.width; - *height =extents.height; + status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL); + if (unlikely (status)) + return status; + + _cairo_box_round_to_rectangle (&bbox, &extents); + *width = extents.width; + *height = extents.height; + } return CAIRO_STATUS_SUCCESS; } else { status = _cairo_surface_acquire_source_image (pattern->surface, @@ -2572,9 +2659,11 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, x = -rect.x; y = -rect.y; - pad_image = _cairo_image_surface_create_with_content (pattern->surface->content, - rect.width, - rect.height); + pad_image = + _cairo_image_surface_create_with_pixman_format (NULL, + surface->acquired_image->pixman_format, + rect.width, rect.height, + 0); if (pad_image->status) { status = pad_image->status; goto BAIL; @@ -2583,16 +2672,10 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface, _cairo_pattern_init_for_surface (&pad_pattern, &surface->acquired_image->base); cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y); pad_pattern.base.extend = CAIRO_EXTEND_PAD; - status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, - &pad_pattern.base, - NULL, - pad_image, - 0, 0, - 0, 0, - 0, 0, - rect.width, - rect.height, - NULL); + status = _cairo_surface_paint (pad_image, + CAIRO_OPERATOR_SOURCE, + &pad_pattern.base, + NULL); _cairo_pattern_fini (&pad_pattern.base); if (unlikely (status)) { if (pad_image != &surface->acquired_image->base) @@ -2624,10 +2707,15 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface, { cairo_status_t status; - if (_cairo_surface_is_recording (pattern->surface)) { - cairo_surface_t *recording_surface = pattern->surface; + if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + cairo_surface_t *source = pattern->surface; - status = _cairo_ps_surface_emit_recording_surface (surface, recording_surface); + if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source; + status = _cairo_ps_surface_emit_recording_subsurface (surface, sub->target, &sub->extents); + } else { + status = _cairo_ps_surface_emit_recording_surface (surface, source); + } } else { if (pattern->base.extend != CAIRO_EXTEND_PAD) { status = _cairo_ps_surface_emit_jpeg_image (surface, pattern->surface, @@ -2650,7 +2738,7 @@ _cairo_ps_surface_release_surface (cairo_ps_surface_t *surface, if (surface->image != surface->acquired_image) cairo_surface_destroy (&surface->image->base); - if (! _cairo_surface_is_recording (pattern->surface)) { + if (pattern->surface->type != CAIRO_SURFACE_TYPE_RECORDING) { _cairo_surface_release_source_image (pattern->surface, surface->acquired_image, surface->image_extra); @@ -3058,7 +3146,10 @@ _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface, _cairo_output_stream_printf (surface->stream, "/CairoFunction\n"); - if (n_stops == 2) { + if (n_stops == 1) { + /* work around single stop gradients */ + _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[0]); + } else if (n_stops == 2) { /* no need for stitched function */ _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]); } else { @@ -3120,22 +3211,6 @@ _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface, double first_stop, last_stop; int repeat_begin = 0, repeat_end = 1; - if (pattern->base.n_stops == 0) - return CAIRO_INT_STATUS_NOTHING_TO_DO; - - if (pattern->base.n_stops == 1) { - cairo_solid_pattern_t solid; - - _cairo_pattern_init_solid (&solid, - &pattern->base.stops[0].color, - CAIRO_CONTENT_COLOR_ALPHA); - _cairo_ps_surface_emit_solid_pattern (surface, - &solid); - _cairo_pattern_fini (&solid.base); - - return CAIRO_STATUS_SUCCESS; - } - extend = cairo_pattern_get_extend (&pattern->base.base); pat_to_ps = pattern->base.base.matrix; @@ -3260,22 +3335,6 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface, cairo_extend_t extend; cairo_status_t status; - if (pattern->base.n_stops == 0) - return CAIRO_INT_STATUS_NOTHING_TO_DO; - - if (pattern->base.n_stops == 1) { - cairo_solid_pattern_t solid; - - _cairo_pattern_init_solid (&solid, - &pattern->base.stops[0].color, - CAIRO_CONTENT_COLOR_ALPHA); - _cairo_ps_surface_emit_solid_pattern (surface, - &solid); - _cairo_pattern_fini (&solid.base); - - return CAIRO_STATUS_SUCCESS; - } - extend = cairo_pattern_get_extend (&pattern->base.base); pat_to_ps = pattern->base.base.matrix; @@ -3434,28 +3493,33 @@ _cairo_ps_surface_paint (void *abstract_surface, { cairo_ps_surface_t *surface = abstract_surface; cairo_output_stream_t *stream = surface->stream; - cairo_rectangle_int_t extents; + cairo_composite_rectangles_t extents; cairo_status_t status; - if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _cairo_ps_surface_analyze_operation (surface, op, source); + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; - assert (_cairo_ps_surface_operation_supported (surface, op, source)); + status = _cairo_composite_rectangles_init_for_paint (&extents, + &rect, + op, source, clip); + if (unlikely (status)) + return status; + + if (! _cairo_rectangle_intersect (&extents.bounded, &surface->page_bbox)) + return CAIRO_STATUS_SUCCESS; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) + return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded); + + assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded)); #if DEBUG_PS _cairo_output_stream_printf (stream, "%% _cairo_ps_surface_paint\n"); #endif - status = _cairo_surface_paint_extents (&surface->base, - op, source, clip, - &extents); - if (unlikely (status)) - return status; - - if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox)) - return CAIRO_STATUS_SUCCESS; - status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; @@ -3471,22 +3535,19 @@ _cairo_ps_surface_paint (void *abstract_surface, _cairo_output_stream_printf (stream, "q\n"); status = _cairo_ps_surface_paint_surface (surface, (cairo_surface_pattern_t *) source, - &extents, op); + &extents.bounded, op); if (unlikely (status)) return status; _cairo_output_stream_printf (stream, "Q\n"); } else { - status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; - + status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op); if (unlikely (status)) return status; _cairo_output_stream_printf (stream, "%d %d %d %d rectfill\n", - extents.x, extents.y, - extents.width, extents.height); + extents.bounded.x, extents.bounded.y, + extents.bounded.width, extents.bounded.height); } return CAIRO_STATUS_SUCCESS; @@ -3497,47 +3558,62 @@ _cairo_ps_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) { cairo_ps_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; cairo_int_status_t status; - cairo_rectangle_int_t extents; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_stroke (&extents, + &rect, + op, source, + path, style, ctm, + clip); + if (unlikely (status)) + return status; + + if (! _cairo_rectangle_intersect (&extents.bounded, &surface->page_bbox)) + return CAIRO_STATUS_SUCCESS; + + /* use the more accurate extents */ + if (extents.is_bounded) { + status = _cairo_path_fixed_stroke_extents (path, style, + ctm, ctm_inverse, + tolerance, + &extents.mask); + if (unlikely (status)) + return status; + + if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask)) + return CAIRO_STATUS_SUCCESS; + } + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _cairo_ps_surface_analyze_operation (surface, op, source); + return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded); - assert (_cairo_ps_surface_operation_supported (surface, op, source)); + assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded)); #if DEBUG_PS _cairo_output_stream_printf (surface->stream, "%% _cairo_ps_surface_stroke\n"); #endif - status = _cairo_surface_stroke_extents (&surface->base, - op, source, - path, style, - ctm, ctm_inverse, - tolerance, antialias, - clip, &extents); - if (unlikely (status)) - return status; - - if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox)) - return CAIRO_STATUS_SUCCESS; - status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; - + status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op); if (unlikely (status)) return status; @@ -3559,13 +3635,39 @@ _cairo_ps_surface_fill (void *abstract_surface, cairo_clip_t *clip) { cairo_ps_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; cairo_int_status_t status; - cairo_rectangle_int_t extents; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_fill (&extents, + &rect, + op, source, path, + clip); + if (unlikely (status)) + return status; + + if (! _cairo_rectangle_intersect (&extents.bounded, &surface->page_bbox)) + return CAIRO_STATUS_SUCCESS; + + /* use the more accurate extents */ + if (extents.is_bounded) { + _cairo_path_fixed_fill_extents (path, + fill_rule, + tolerance, + &extents.mask); + + if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask)) + return CAIRO_STATUS_SUCCESS; + } if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _cairo_ps_surface_analyze_operation (surface, op, source); + return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded); - assert (_cairo_ps_surface_operation_supported (surface, op, source)); + assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded)); #if DEBUG_PS _cairo_output_stream_printf (surface->stream, @@ -3576,17 +3678,6 @@ _cairo_ps_surface_fill (void *abstract_surface, if (unlikely (status)) return status; - status = _cairo_surface_fill_extents (&surface->base, - op, source, - path, fill_rule, - tolerance, antialias, - clip, &extents); - if (unlikely (status)) - return status; - - if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox)) - return CAIRO_STATUS_SUCCESS; - status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; @@ -3605,17 +3696,14 @@ _cairo_ps_surface_fill (void *abstract_surface, status = _cairo_ps_surface_paint_surface (surface, (cairo_surface_pattern_t *) source, - &extents, op); + &extents.bounded, op); if (unlikely (status)) return status; _cairo_output_stream_printf (surface->stream, "Q\n"); _cairo_pdf_operators_reset (&surface->pdf_operators); } else { - status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; - + status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op); if (unlikely (status)) return status; @@ -3638,41 +3726,40 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface, int *remaining_glyphs) { cairo_ps_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; + cairo_bool_t overlap; cairo_status_t status; - cairo_rectangle_int_t extents; + + cairo_rectangle_int_t rect; + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + status = _cairo_composite_rectangles_init_for_glyphs (&extents, + &rect, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, + &overlap); + if (unlikely (status)) + return status; if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) - return _cairo_ps_surface_analyze_operation (surface, op, source); + return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded); - assert (_cairo_ps_surface_operation_supported (surface, op, source)); + assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded)); #if DEBUG_PS _cairo_output_stream_printf (surface->stream, "%% _cairo_ps_surface_show_glyphs\n"); #endif - if (num_glyphs <= 0) - return CAIRO_STATUS_SUCCESS; - - status = _cairo_surface_glyphs_extents (&surface->base, - op, source, - glyphs, num_glyphs, - scaled_font, - clip, &extents); - if (unlikely (status)) - return status; - - if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox)) - return CAIRO_STATUS_SUCCESS; - status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op); - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - return CAIRO_STATUS_SUCCESS; - + status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op); if (unlikely (status)) return status; @@ -3726,7 +3813,7 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface, surface->page_bbox.x = x1; surface->page_bbox.y = y1; - surface->page_bbox.width = x2 - x1; + surface->page_bbox.width = x2 - x1; surface->page_bbox.height = y2 - y1; _cairo_output_stream_printf (surface->stream, diff --git a/gfx/cairo/cairo/src/cairo-ps.h b/gfx/cairo/cairo/src/cairo-ps.h index 8a2cb58b1b26..fd1d21deba0f 100644 --- a/gfx/cairo/cairo/src/cairo-ps.h +++ b/gfx/cairo/cairo/src/cairo-ps.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-qt-surface.cpp b/gfx/cairo/cairo/src/cairo-qt-surface.cpp index 7093dd9976da..81200033baed 100644 --- a/gfx/cairo/cairo/src/cairo-qt-surface.cpp +++ b/gfx/cairo/cairo/src/cairo-qt-surface.cpp @@ -45,6 +45,7 @@ #include "cairo-ft.h" #include "cairo-qt.h" +#include "cairo-error-private.h" #include @@ -304,7 +305,7 @@ _qmatrix_from_cairo_matrix (const cairo_matrix_t& m) /** Path conversion **/ typedef struct _qpainter_path_transform { QPainterPath path; - cairo_matrix_t *ctm_inverse; + const cairo_matrix_t *ctm_inverse; } qpainter_path_data; /* cairo path -> execute in context */ @@ -372,7 +373,7 @@ _cairo_path_to_qpainterpath_close_path (void *closure) static inline QPainterPath path_to_qt (cairo_path_fixed_t *path, - cairo_matrix_t *ctm_inverse = NULL) + const cairo_matrix_t *ctm_inverse = NULL) { qpainter_path_data data; cairo_status_t status; @@ -1016,7 +1017,7 @@ struct PatternToBrushConverter { struct PatternToPenConverter { PatternToPenConverter (const cairo_pattern_t *source, - cairo_stroke_style_t *style) : + const cairo_stroke_style_t *style) : mBrushConverter(source) { Qt::PenJoinStyle join = Qt::MiterJoin; @@ -1304,9 +1305,9 @@ _cairo_qt_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) @@ -1567,6 +1568,7 @@ cairo_qt_surface_create (QPainter *painter) _cairo_surface_init (&qs->base, &cairo_qt_surface_backend, + NULL, CAIRO_CONTENT_COLOR_ALPHA); _cairo_surface_clipper_init (&qs->clipper, @@ -1605,6 +1607,7 @@ cairo_qt_surface_create_with_qimage (cairo_format_t format, _cairo_surface_init (&qs->base, &cairo_qt_surface_backend, + NULL, _cairo_content_from_format (format)); _cairo_surface_clipper_init (&qs->clipper, @@ -1672,7 +1675,7 @@ cairo_qt_surface_create_with_qpixmap (cairo_content_t content, if (content == CAIRO_CONTENT_COLOR_ALPHA) pixmap->fill(Qt::transparent); - _cairo_surface_init (&qs->base, &cairo_qt_surface_backend, content); + _cairo_surface_init (&qs->base, &cairo_qt_surface_backend, NULL, content); _cairo_surface_clipper_init (&qs->clipper, _cairo_qt_surface_clipper_intersect_clip_path); diff --git a/gfx/cairo/cairo/src/cairo-qt.h b/gfx/cairo/cairo/src/cairo-qt.h index d16087dd7e5a..c20bbb18d0b8 100644 --- a/gfx/cairo/cairo/src/cairo-qt.h +++ b/gfx/cairo/cairo/src/cairo-qt.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -41,10 +41,10 @@ #if CAIRO_HAS_QT_SURFACE -#if defined(__cplusplus) +#include +#include -class QPainter; -class QImage; +CAIRO_BEGIN_DECLS cairo_public cairo_surface_t * cairo_qt_surface_create (QPainter *painter); @@ -74,11 +74,7 @@ cairo_qt_surface_get_image (cairo_surface_t *surface); cairo_public QImage * cairo_qt_surface_get_qimage (cairo_surface_t *surface); -#else /* ! __cplusplus */ - -# warning cairo-qt only exports a C++ interface - -#endif /* __cplusplus */ +CAIRO_END_DECLS #else /* CAIRO_HAS_QT_SURFACE */ diff --git a/gfx/cairo/cairo/src/cairo-quartz-font.c b/gfx/cairo/cairo/src/cairo-quartz-font.c index d342e38df524..2c7e017af035 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-font.c +++ b/gfx/cairo/cairo/src/cairo-quartz-font.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -41,6 +41,26 @@ #include "cairo-quartz.h" #include "cairo-quartz-private.h" +#include "cairo-error-private.h" + +/** + * SECTION:cairo-quartz-fonts + * @Title: Quartz (CGFont) Fonts + * @Short_Description: Font support via CGFont on OS X + * @See_Also: #cairo_font_face_t + * + * The Quartz font backend is primarily used to render text on Apple + * MacOS X systems. The CGFont API is used for the internal + * implementation of the font backend methods. + */ + +/** + * CAIRO_HAS_QUARTZ_FONT: + * + * Defined if the Quartz font backend is available. + * This macro can be used to conditionally compile backend-specific code. + */ + /* CreateWithFontName exists in 10.5, but not in 10.4; CreateWithName isn't public in 10.4 */ static CGFontRef (*CGFontCreateWithFontNamePtr) (CFStringRef) = NULL; static CGFontRef (*CGFontCreateWithNamePtr) (const char *) = NULL; @@ -53,6 +73,8 @@ static CGRect (*CGFontGetFontBBoxPtr) (CGFontRef) = NULL; /* Not public, but present */ static void (*CGFontGetGlyphsForUnicharsPtr) (CGFontRef, const UniChar[], const CGGlyph[], size_t) = NULL; +static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL; +static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL; /* Not public in the least bit */ static CGPathRef (*CGFontGetGlyphPathPtr) (CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph) = NULL; @@ -102,6 +124,9 @@ quartz_font_ensure_symbols(void) CGFontGetDescentPtr = dlsym(RTLD_DEFAULT, "CGFontGetDescent"); CGFontGetLeadingPtr = dlsym(RTLD_DEFAULT, "CGFontGetLeading"); + CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing"); + CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing"); + if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) && CGFontGetGlyphBBoxesPtr && CGFontGetGlyphsForUnicharsPtr && @@ -326,7 +351,8 @@ cairo_quartz_font_face_create_for_cgfont (CGFontRef font) font_face = malloc (sizeof (cairo_quartz_font_face_t)); if (!font_face) { - _cairo_error (CAIRO_STATUS_NO_MEMORY); + cairo_status_t ignore_status; + ignore_status = _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_font_face_t *)&_cairo_font_face_nil; } @@ -365,36 +391,6 @@ _cairo_quartz_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) { return (CGGlyph) index; } -static inline cairo_status_t -_cairo_matrix_to_unit_quartz_matrix (const cairo_matrix_t *m, CGAffineTransform *txout, - double *xout, double *yout) -{ - CGAffineTransform transform; - double xscale, yscale; - cairo_status_t status; - - status = _cairo_matrix_compute_basis_scale_factors (m, &xscale, &yscale, 1); - if (status) - return status; - - transform = CGAffineTransformMake (m->xx, - m->yx, - - m->xy, m->yy, - 0.0f, 0.0f); - if (xout) - *xout = xscale; - if (yout) - *yout = yscale; - - if (xscale) - xscale = 1.0 / xscale; - if (yscale) - yscale = 1.0 / yscale; - - *txout = CGAffineTransformScale (transform, xscale, yscale); - - return CAIRO_STATUS_SUCCESS; -} - static cairo_int_status_t _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font, cairo_scaled_glyph_t *scaled_glyph) @@ -403,7 +399,6 @@ _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font, cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font); cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0}; - CGAffineTransform textMatrix; CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); int advance; CGRect bbox; @@ -490,17 +485,20 @@ static void _cairo_quartz_path_apply_func (void *info, const CGPathElement *el) { cairo_path_fixed_t *path = (cairo_path_fixed_t *) info; + cairo_status_t status; switch (el->type) { case kCGPathElementMoveToPoint: - _cairo_path_fixed_move_to (path, - _cairo_fixed_from_double(el->points[0].x), - _cairo_fixed_from_double(el->points[0].y)); + status = _cairo_path_fixed_move_to (path, + _cairo_fixed_from_double(el->points[0].x), + _cairo_fixed_from_double(el->points[0].y)); + assert(!status); break; case kCGPathElementAddLineToPoint: - _cairo_path_fixed_line_to (path, - _cairo_fixed_from_double(el->points[0].x), - _cairo_fixed_from_double(el->points[0].y)); + status = _cairo_path_fixed_line_to (path, + _cairo_fixed_from_double(el->points[0].x), + _cairo_fixed_from_double(el->points[0].y)); + assert(!status); break; case kCGPathElementAddQuadCurveToPoint: { cairo_fixed_t fx, fy; @@ -510,26 +508,29 @@ _cairo_quartz_path_apply_func (void *info, const CGPathElement *el) x = _cairo_fixed_to_double (fx); y = _cairo_fixed_to_double (fy); - _cairo_path_fixed_curve_to (path, - _cairo_fixed_from_double((x + el->points[0].x * 2.0) / 3.0), - _cairo_fixed_from_double((y + el->points[0].y * 2.0) / 3.0), - _cairo_fixed_from_double((el->points[0].x * 2.0 + el->points[1].x) / 3.0), - _cairo_fixed_from_double((el->points[0].y * 2.0 + el->points[1].y) / 3.0), - _cairo_fixed_from_double(el->points[1].x), - _cairo_fixed_from_double(el->points[1].y)); + status = _cairo_path_fixed_curve_to (path, + _cairo_fixed_from_double((x + el->points[0].x * 2.0) / 3.0), + _cairo_fixed_from_double((y + el->points[0].y * 2.0) / 3.0), + _cairo_fixed_from_double((el->points[0].x * 2.0 + el->points[1].x) / 3.0), + _cairo_fixed_from_double((el->points[0].y * 2.0 + el->points[1].y) / 3.0), + _cairo_fixed_from_double(el->points[1].x), + _cairo_fixed_from_double(el->points[1].y)); } + assert(!status); break; case kCGPathElementAddCurveToPoint: - _cairo_path_fixed_curve_to (path, - _cairo_fixed_from_double(el->points[0].x), - _cairo_fixed_from_double(el->points[0].y), - _cairo_fixed_from_double(el->points[1].x), - _cairo_fixed_from_double(el->points[1].y), - _cairo_fixed_from_double(el->points[2].x), - _cairo_fixed_from_double(el->points[2].y)); + status = _cairo_path_fixed_curve_to (path, + _cairo_fixed_from_double(el->points[0].x), + _cairo_fixed_from_double(el->points[0].y), + _cairo_fixed_from_double(el->points[1].x), + _cairo_fixed_from_double(el->points[1].y), + _cairo_fixed_from_double(el->points[2].x), + _cairo_fixed_from_double(el->points[2].y)); + assert(!status); break; case kCGPathElementCloseSubpath: - _cairo_path_fixed_close_path (path); + status = _cairo_path_fixed_close_path (path); + assert(!status); break; } } @@ -549,14 +550,12 @@ _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font, return CAIRO_STATUS_SUCCESS; } + /* scale(1,-1) * font->base.scale */ textMatrix = CGAffineTransformMake (font->base.scale.xx, - -font->base.scale.yx, + font->base.scale.yx, -font->base.scale.xy, - font->base.scale.yy, - font->base.scale.x0, - font->base.scale.y0); - - textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformMake (1.0, 0.0, 0.0, -1.0, 0.0, 0.0)); + -font->base.scale.yy, + 0, 0); glyphPath = CGFontGetGlyphPathPtr (font_face->cgFont, &textMatrix, 0, glyph); if (!glyphPath) @@ -595,7 +594,6 @@ _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font, double xscale, yscale; double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont); - CGColorSpaceRef gray; CGContextRef cgContext = NULL; CGAffineTransform textMatrix; CGRect glyphRect, glyphRectInt; @@ -630,11 +628,12 @@ _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font, if (status) return status; + /* scale(1,-1) * font->base.scale * scale(1,-1) */ textMatrix = CGAffineTransformMake (font->base.scale.xx, -font->base.scale.yx, -font->base.scale.xy, font->base.scale.yy, - 0.0f, 0.0f); + 0, -0); glyphRect = CGRectMake (bbox.origin.x / emscale, bbox.origin.y / emscale, bbox.size.width / emscale, @@ -667,29 +666,50 @@ _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font, if (surface->base.status) return surface->base.status; - gray = CGColorSpaceCreateDeviceGray (); - cgContext = CGBitmapContextCreate (surface->data, - surface->width, - surface->height, - 8, - surface->stride, - gray, - kCGImageAlphaNone); - CGColorSpaceRelease (gray); + if (surface->width != 0 && surface->height != 0) { + cgContext = CGBitmapContextCreate (surface->data, + surface->width, + surface->height, + 8, + surface->stride, + NULL, + kCGImageAlphaOnly); - CGContextSetFont (cgContext, font_face->cgFont); - CGContextSetFontSize (cgContext, 1.0); - CGContextSetTextMatrix (cgContext, textMatrix); + if (cgContext == NULL) { + cairo_surface_destroy (&surface->base); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } - CGContextClearRect (cgContext, CGRectMake (0.0f, 0.0f, width, height)); + CGContextSetFont (cgContext, font_face->cgFont); + CGContextSetFontSize (cgContext, 1.0); + CGContextSetTextMatrix (cgContext, textMatrix); - if (font->base.options.antialias == CAIRO_ANTIALIAS_NONE) - CGContextSetShouldAntialias (cgContext, false); + switch (font->base.options.antialias) { + case CAIRO_ANTIALIAS_SUBPIXEL: + CGContextSetShouldAntialias (cgContext, TRUE); + CGContextSetShouldSmoothFonts (cgContext, TRUE); + if (CGContextSetAllowsFontSmoothingPtr && + !CGContextGetAllowsFontSmoothingPtr (cgContext)) + CGContextSetAllowsFontSmoothingPtr (cgContext, TRUE); + break; + case CAIRO_ANTIALIAS_NONE: + CGContextSetShouldAntialias (cgContext, FALSE); + break; + case CAIRO_ANTIALIAS_GRAY: + CGContextSetShouldAntialias (cgContext, TRUE); + CGContextSetShouldSmoothFonts (cgContext, FALSE); + break; + case CAIRO_ANTIALIAS_DEFAULT: + default: + /* Don't do anything */ + break; + } - CGContextSetRGBFillColor (cgContext, 1.0, 1.0, 1.0, 1.0); - CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1); + CGContextSetAlpha (cgContext, 1.0); + CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1); - CGContextRelease (cgContext); + CGContextRelease (cgContext); + } cairo_surface_set_device_offset (&surface->base, - glyphOrigin.x, diff --git a/gfx/cairo/cairo/src/cairo-quartz-image-surface.c b/gfx/cairo/cairo/src/cairo-quartz-image-surface.c index b8809d503f50..9a18dd46e5d2 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-image-surface.c +++ b/gfx/cairo/cairo/src/cairo-quartz-image-surface.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -39,6 +39,8 @@ #include "cairo-quartz-image.h" #include "cairo-quartz-private.h" +#include "cairo-error-private.h" + #define SURFACE_ERROR_NO_MEMORY (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY))) #define SURFACE_ERROR_TYPE_MISMATCH (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_SURFACE_TYPE_MISMATCH))) #define SURFACE_ERROR_INVALID_SIZE (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_SIZE))) @@ -260,6 +262,7 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface) _cairo_surface_init (&qisurf->base, &cairo_quartz_image_surface_backend, + NULL, /* device */ _cairo_content_from_format (format)); qisurf->extents.x = qisurf->extents.y = 0; diff --git a/gfx/cairo/cairo/src/cairo-quartz-image.h b/gfx/cairo/cairo/src/cairo-quartz-image.h index 7b9c5de4477e..dae234dacae7 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-image.h +++ b/gfx/cairo/cairo/src/cairo-quartz-image.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h index a7c25db736a3..ca4b2170c331 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-private.h +++ b/gfx/cairo/cairo/src/cairo-quartz-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -44,6 +44,12 @@ #include "cairo-quartz.h" #include "cairo-surface-clipper-private.h" +#ifdef CGFLOAT_DEFINED +typedef CGFloat cairo_quartz_float_t; +#else +typedef float cairo_quartz_float_t; +#endif + typedef struct cairo_quartz_surface { cairo_surface_t base; diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c index 07d3e01e2360..c1eedc266e44 100644 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,6 +38,8 @@ #include "cairoint.h" #include "cairo-quartz-private.h" + +#include "cairo-error-private.h" #include "cairo-surface-clipper-private.h" #include "cairo-gstate-private.h" #include "cairo-private.h" @@ -48,14 +50,6 @@ #define RTLD_DEFAULT ((void *) 0) #endif -/* The 10.5 SDK includes a funky new definition of FloatToFixed which - * causes all sorts of breakage; so reset to old-style definition - */ -#ifdef FloatToFixed -#undef FloatToFixed -#define FloatToFixed(a) ((Fixed)((float)(a) * fixed1)) -#endif - #include #undef QUARTZ_DEBUG @@ -68,6 +62,23 @@ #define IS_EMPTY(s) ((s)->extents.width == 0 || (s)->extents.height == 0) +/** + * SECTION:cairo-quartz + * @Title: Quartz Surfaces + * @Short_Description: Rendering to Quartz surfaces + * @See_Also: #cairo_surface_t + * + * The Quartz surface is used to render cairo graphics targeting the + * Apple OS X Quartz rendering system. + */ + +/** + * CAIRO_HAS_QUARTZ_SURFACE: + * + * Defined if the Quartz surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + */ + /* Here are some of the differences between cairo and CoreGraphics - cairo has only a single source active at once vs. CoreGraphics having separate sources for stroke and fill @@ -93,10 +104,7 @@ enum PrivateCGCompositeMode { }; typedef enum PrivateCGCompositeMode PrivateCGCompositeMode; CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode); -CG_EXTERN void CGContextResetCTM (CGContextRef); CG_EXTERN void CGContextSetCTM (CGContextRef, CGAffineTransform); -CG_EXTERN void CGContextResetClip (CGContextRef); -CG_EXTERN CGSize CGContextGetPatternPhase (CGContextRef); /* We need to work with the 10.3 SDK as well (and 10.3 machines; luckily, 10.3.9 * has all the stuff we care about, just some of it isn't exported in the SDK. @@ -115,22 +123,18 @@ CG_EXTERN CGImageRef CGBitmapContextCreateImage (CGContextRef); #endif /* Some of these are present in earlier versions of the OS than where - * they are public; others are not public at all - * (CGContextReplacePathWithClipPath, many of the getters, etc.) + * they are public; others are not public at all (CGContextCopyPath, + * CGContextReplacePathWithClipPath, many of the getters, etc.) */ static void (*CGContextClipToMaskPtr) (CGContextRef, CGRect, CGImageRef) = NULL; static void (*CGContextDrawTiledImagePtr) (CGContextRef, CGRect, CGImageRef) = NULL; static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL; static void (*CGContextSetShouldAntialiasFontsPtr) (CGContextRef, bool) = NULL; -static bool (*CGContextGetShouldAntialiasFontsPtr) (CGContextRef) = NULL; -static bool (*CGContextGetShouldSmoothFontsPtr) (CGContextRef) = NULL; static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL; static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL; -static void (*CGContextReplacePathWithClipPathPtr) (CGContextRef) = NULL; +static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL; static CGFloat (*CGContextGetAlphaPtr) (CGContextRef) = NULL; -static SInt32 _cairo_quartz_osx_version = 0x0; - static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE; /* @@ -148,6 +152,9 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext, unsigned int width, unsigned int height); +static cairo_bool_t +_cairo_surface_is_quartz (const cairo_surface_t *surface); + /* Load all extra symbols */ static void quartz_ensure_symbols(void) { @@ -158,18 +165,11 @@ static void quartz_ensure_symbols(void) CGContextDrawTiledImagePtr = dlsym(RTLD_DEFAULT, "CGContextDrawTiledImage"); CGContextGetTypePtr = dlsym(RTLD_DEFAULT, "CGContextGetType"); CGContextSetShouldAntialiasFontsPtr = dlsym(RTLD_DEFAULT, "CGContextSetShouldAntialiasFonts"); - CGContextGetShouldAntialiasFontsPtr = dlsym(RTLD_DEFAULT, "CGContextGetShouldAntialiasFonts"); - CGContextGetShouldSmoothFontsPtr = dlsym(RTLD_DEFAULT, "CGContextGetShouldSmoothFonts"); - CGContextReplacePathWithClipPathPtr = dlsym(RTLD_DEFAULT, "CGContextReplacePathWithClipPath"); + CGContextCopyPathPtr = dlsym(RTLD_DEFAULT, "CGContextCopyPath"); CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing"); CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing"); CGContextGetAlphaPtr = dlsym(RTLD_DEFAULT, "CGContextGetAlpha"); - if (Gestalt(gestaltSystemVersion, &_cairo_quartz_osx_version) != noErr) { - // assume 10.4 - _cairo_quartz_osx_version = 0x1040; - } - _cairo_quartz_symbol_lookup_done = TRUE; } @@ -187,14 +187,14 @@ _cairo_quartz_create_cgimage (cairo_format_t format, CGImageRef image = NULL; CGDataProviderRef dataProvider = NULL; CGColorSpaceRef colorSpace = colorSpaceOverride; - CGBitmapInfo bitinfo; + CGBitmapInfo bitinfo = kCGBitmapByteOrder32Host; int bitsPerComponent, bitsPerPixel; switch (format) { case CAIRO_FORMAT_ARGB32: if (colorSpace == NULL) colorSpace = CGColorSpaceCreateDeviceRGB(); - bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; + bitinfo |= kCGImageAlphaPremultipliedFirst; bitsPerComponent = 8; bitsPerPixel = 32; break; @@ -202,7 +202,7 @@ _cairo_quartz_create_cgimage (cairo_format_t format, case CAIRO_FORMAT_RGB24: if (colorSpace == NULL) colorSpace = CGColorSpaceCreateDeviceRGB(); - bitinfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; + bitinfo |= kCGImageAlphaNoneSkipFirst; bitsPerComponent = 8; bitsPerPixel = 32; break; @@ -213,10 +213,14 @@ _cairo_quartz_create_cgimage (cairo_format_t format, break; case CAIRO_FORMAT_A1: +#ifdef WORDS_BIGENDIAN bitsPerComponent = 1; bitsPerPixel = 1; break; +#endif + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_INVALID: default: return NULL; } @@ -234,7 +238,7 @@ _cairo_quartz_create_cgimage (cairo_format_t format, } if (format == CAIRO_FORMAT_A8 || format == CAIRO_FORMAT_A1) { - CGFloat decode[] = {1.0, 0.0}; + cairo_quartz_float_t decode[] = {1.0, 0.0}; image = CGImageMaskCreate (width, height, bitsPerComponent, bitsPerPixel, @@ -305,25 +309,16 @@ _cairo_quartz_verify_surface_size(int width, int height) * Cairo path -> Quartz path conversion helpers */ -typedef struct _quartz_stroke { - CGContextRef cgContext; - cairo_matrix_t *ctm_inverse; -} quartz_stroke_t; - /* cairo path -> execute in context */ static cairo_status_t _cairo_path_to_quartz_context_move_to (void *closure, const cairo_point_t *point) { //ND((stderr, "moveto: %f %f\n", _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y))); - quartz_stroke_t *stroke = (quartz_stroke_t *)closure; double x = _cairo_fixed_to_double (point->x); double y = _cairo_fixed_to_double (point->y); - if (stroke->ctm_inverse) - cairo_matrix_transform_point (stroke->ctm_inverse, &x, &y); - - CGContextMoveToPoint (stroke->cgContext, x, y); + CGContextMoveToPoint (closure, x, y); return CAIRO_STATUS_SUCCESS; } @@ -332,17 +327,10 @@ _cairo_path_to_quartz_context_line_to (void *closure, const cairo_point_t *point) { //ND((stderr, "lineto: %f %f\n", _cairo_fixed_to_double(point->x), _cairo_fixed_to_double(point->y))); - quartz_stroke_t *stroke = (quartz_stroke_t *)closure; double x = _cairo_fixed_to_double (point->x); double y = _cairo_fixed_to_double (point->y); - if (stroke->ctm_inverse) - cairo_matrix_transform_point (stroke->ctm_inverse, &x, &y); - - if (CGContextIsPathEmpty (stroke->cgContext)) - CGContextMoveToPoint (stroke->cgContext, x, y); - else - CGContextAddLineToPoint (stroke->cgContext, x, y); + CGContextAddLineToPoint (closure, x, y); return CAIRO_STATUS_SUCCESS; } @@ -356,7 +344,6 @@ _cairo_path_to_quartz_context_curve_to (void *closure, // _cairo_fixed_to_double(p0->x), _cairo_fixed_to_double(p0->y), // _cairo_fixed_to_double(p1->x), _cairo_fixed_to_double(p1->y), // _cairo_fixed_to_double(p2->x), _cairo_fixed_to_double(p2->y))); - quartz_stroke_t *stroke = (quartz_stroke_t *)closure; double x0 = _cairo_fixed_to_double (p0->x); double y0 = _cairo_fixed_to_double (p0->y); double x1 = _cairo_fixed_to_double (p1->x); @@ -364,13 +351,7 @@ _cairo_path_to_quartz_context_curve_to (void *closure, double x2 = _cairo_fixed_to_double (p2->x); double y2 = _cairo_fixed_to_double (p2->y); - if (stroke->ctm_inverse) { - cairo_matrix_transform_point (stroke->ctm_inverse, &x0, &y0); - cairo_matrix_transform_point (stroke->ctm_inverse, &x1, &y1); - cairo_matrix_transform_point (stroke->ctm_inverse, &x2, &y2); - } - - CGContextAddCurveToPoint (stroke->cgContext, + CGContextAddCurveToPoint (closure, x0, y0, x1, y1, x2, y2); return CAIRO_STATUS_SUCCESS; } @@ -379,22 +360,26 @@ static cairo_status_t _cairo_path_to_quartz_context_close_path (void *closure) { //ND((stderr, "closepath\n")); - quartz_stroke_t *stroke = (quartz_stroke_t *)closure; - CGContextClosePath (stroke->cgContext); + CGContextClosePath (closure); return CAIRO_STATUS_SUCCESS; } -static cairo_status_t +static void _cairo_quartz_cairo_path_to_quartz_context (cairo_path_fixed_t *path, - quartz_stroke_t *stroke) + CGContextRef closure) { - return _cairo_path_fixed_interpret (path, - CAIRO_DIRECTION_FORWARD, - _cairo_path_to_quartz_context_move_to, - _cairo_path_to_quartz_context_line_to, - _cairo_path_to_quartz_context_curve_to, - _cairo_path_to_quartz_context_close_path, - stroke); + cairo_status_t status; + + CGContextBeginPath (closure); + status = _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cairo_path_to_quartz_context_move_to, + _cairo_path_to_quartz_context_line_to, + _cairo_path_to_quartz_context_curve_to, + _cairo_path_to_quartz_context_close_path, + closure); + + assert (status == CAIRO_STATUS_SUCCESS); } /* @@ -614,12 +599,161 @@ _cairo_quartz_cairo_matrix_to_quartz (const cairo_matrix_t *src, dst->ty = src->y0; } +typedef struct { + bool isClipping; + CGGlyph *cg_glyphs; + CGSize *cg_advances; + size_t nglyphs; + CGAffineTransform textTransform; + CGFontRef font; + CGPoint origin; +} unbounded_show_glyphs_t; + +typedef struct { + CGPathRef cgPath; + cairo_fill_rule_t fill_rule; +} unbounded_stroke_fill_t; + +typedef struct { + CGImageRef mask; + CGAffineTransform maskTransform; +} unbounded_mask_t; + +typedef enum { + UNBOUNDED_STROKE_FILL, + UNBOUNDED_SHOW_GLYPHS, + UNBOUNDED_MASK +} unbounded_op_t; + +typedef struct { + unbounded_op_t op; + union { + unbounded_stroke_fill_t stroke_fill; + unbounded_show_glyphs_t show_glyphs; + unbounded_mask_t mask; + } u; +} unbounded_op_data_t; + +static void +_cairo_quartz_fixup_unbounded_operation (cairo_quartz_surface_t *surface, + unbounded_op_data_t *op, + cairo_antialias_t antialias) +{ + CGRect clipBox, clipBoxRound; + CGContextRef cgc; + CGImageRef maskImage; + + /* TODO: handle failure */ + if (!CGContextClipToMaskPtr) + return; + + clipBox = CGContextGetClipBoundingBox (surface->cgContext); + clipBoxRound = CGRectIntegral (clipBox); + + cgc = CGBitmapContextCreate (NULL, + clipBoxRound.size.width, + clipBoxRound.size.height, + 8, + (((size_t) clipBoxRound.size.width) + 15) & (~15), + NULL, + kCGImageAlphaOnly); + + if (!cgc) + return; + + CGContextSetCompositeOperation (cgc, kPrivateCGCompositeCopy); + /* We want to mask out whatever we just rendered, so we fill the + * surface opaque, and then we'll render transparent. + */ + CGContextSetAlpha (cgc, 1.0f); + CGContextFillRect (cgc, CGRectMake (0, 0, clipBoxRound.size.width, clipBoxRound.size.height)); + + CGContextSetCompositeOperation (cgc, kPrivateCGCompositeClear); + CGContextSetShouldAntialias (cgc, (antialias != CAIRO_ANTIALIAS_NONE)); + + CGContextTranslateCTM (cgc, -clipBoxRound.origin.x, -clipBoxRound.origin.y); + + /* We need to either render the path that was given to us, or the glyph op */ + if (op->op == UNBOUNDED_STROKE_FILL) { + CGContextBeginPath (cgc); + CGContextAddPath (cgc, op->u.stroke_fill.cgPath); + + if (op->u.stroke_fill.fill_rule == CAIRO_FILL_RULE_WINDING) + CGContextFillPath (cgc); + else + CGContextEOFillPath (cgc); + } else if (op->op == UNBOUNDED_SHOW_GLYPHS) { + CGContextSetFont (cgc, op->u.show_glyphs.font); + CGContextSetFontSize (cgc, 1.0); + CGContextSetTextMatrix (cgc, CGAffineTransformIdentity); + CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y); + CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform); + + if (op->u.show_glyphs.isClipping) { + /* Note that the comment in show_glyphs about kCGTextClip + * and the text transform still applies here; however, the + * cg_advances we have were already transformed, so we + * don't have to do anything. */ + CGContextSetTextDrawingMode (cgc, kCGTextClip); + CGContextSaveGState (cgc); + } + + CGContextShowGlyphsWithAdvances (cgc, + op->u.show_glyphs.cg_glyphs, + op->u.show_glyphs.cg_advances, + op->u.show_glyphs.nglyphs); + + if (op->u.show_glyphs.isClipping) { + CGContextClearRect (cgc, clipBoxRound); + CGContextRestoreGState (cgc); + } + } else if (op->op == UNBOUNDED_MASK) { + CGAffineTransform ctm = CGContextGetCTM (cgc); + CGContextSaveGState (cgc); + CGContextConcatCTM (cgc, op->u.mask.maskTransform); + CGContextClipToMask (cgc, CGRectMake (0.0f, 0.0f, + CGImageGetWidth(op->u.mask.mask), CGImageGetHeight(op->u.mask.mask)), + op->u.mask.mask); + CGContextSetCTM (cgc, ctm); + CGContextClearRect (cgc, clipBoxRound); + CGContextRestoreGState (cgc); + } + + /* Also mask out the portion of the clipbox that we rounded out, if any */ + if (!CGRectEqualToRect (clipBox, clipBoxRound)) { + CGContextBeginPath (cgc); + CGContextAddRect (cgc, clipBoxRound); + CGContextAddRect (cgc, clipBox); + CGContextEOFillPath (cgc); + } + + maskImage = CGBitmapContextCreateImage (cgc); + CGContextRelease (cgc); + + if (!maskImage) + return; + + /* Then render with the mask */ + CGContextSaveGState (surface->cgContext); + + CGContextSetCompositeOperation (surface->cgContext, kPrivateCGCompositeCopy); + CGContextClipToMaskPtr (surface->cgContext, clipBoxRound, maskImage); + CGImageRelease (maskImage); + + /* Finally, clear out the entire clipping region through our mask */ + CGContextClearRect (surface->cgContext, clipBoxRound); + + CGContextRestoreGState (surface->cgContext); +} + /* * Source -> Quartz setup and finish functions */ static void -ComputeGradientValue (void *info, const CGFloat *in, CGFloat *out) +ComputeGradientValue (void *info, + const cairo_quartz_float_t *in, + cairo_quartz_float_t *out) { double fdist = *in; const cairo_gradient_pattern_t *grad = (cairo_gradient_pattern_t*) info; @@ -650,10 +784,10 @@ ComputeGradientValue (void *info, const CGFloat *in, CGFloat *out) out[2] = grad->stops[i].color.blue; out[3] = grad->stops[i].color.alpha; } else { - float ax = grad->stops[i-1].offset; - float bx = grad->stops[i].offset - ax; - float bp = (fdist - ax)/bx; - float ap = 1.0 - bp; + cairo_quartz_float_t ax = grad->stops[i-1].offset; + cairo_quartz_float_t bx = grad->stops[i].offset - ax; + cairo_quartz_float_t bp = (fdist - ax)/bx; + cairo_quartz_float_t ap = 1.0 - bp; out[0] = grad->stops[i-1].color.red * ap + @@ -670,7 +804,7 @@ ComputeGradientValue (void *info, const CGFloat *in, CGFloat *out) } } -static const CGFloat gradient_output_value_ranges[8] = { +static const cairo_quartz_float_t gradient_output_value_ranges[8] = { 0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f }; static const CGFunctionCallbacks gradient_callbacks = { @@ -687,8 +821,8 @@ static const CGFunctionCallbacks gradient_callbacks = { on the gradient line will pass 0.0 to ComputeGradientValue, which will select the last color stop with position 0, although it should select the first color stop (this matters when there are multiple color stops with - position 0). - + position 0). + Therefore we pass a small negative number as the lower bound of the input range, so this value gets passed into ComputeGradientValue, which will return the color of the first stop. The number should be small because @@ -696,7 +830,7 @@ static const CGFunctionCallbacks gradient_callbacks = { function into an array of fixed size, so if the input range is larger than needed, the resolution of the gradient will be unnecessarily low. */ -static const CGFloat nonrepeating_gradient_input_value_range[2] = { -0.001f, 1.f }; +static const cairo_quartz_float_t nonrepeating_gradient_input_value_range[2] = { -0.001f, 1.f }; static CGFunctionRef CreateGradientFunction (const cairo_gradient_pattern_t *gpat) @@ -758,7 +892,7 @@ CreateRepeatingLinearGradientFunction (cairo_quartz_surface_t *surface, cairo_rectangle_int_t *extents) { cairo_pattern_t *pat; - CGFloat input_value_range[2]; + cairo_quartz_float_t input_value_range[2]; double t_min = 0.; double t_max = 0.; double dx = end->x - start->x; @@ -868,7 +1002,7 @@ CreateRepeatingRadialGradientFunction (cairo_quartz_surface_t *surface, cairo_rectangle_int_t *extents) { cairo_pattern_t *pat; - CGFloat input_value_range[2]; + cairo_quartz_float_t input_value_range[2]; CGPoint *inner; double *inner_radius; CGPoint *outer; @@ -942,8 +1076,8 @@ CreateRepeatingRadialGradientFunction (cairo_quartz_surface_t *surface, input_value_range[0] = t_min; input_value_range[1] = t_max; } else { - input_value_range[0] = -t_max; - input_value_range[1] = -t_min; + input_value_range[0] = 1 - t_max; + input_value_range[1] = 1 - t_min; } if (_cairo_pattern_create_copy (&pat, &gpat->base)) @@ -961,30 +1095,34 @@ CreateRepeatingRadialGradientFunction (cairo_quartz_surface_t *surface, /* Obtain a CGImageRef from a #cairo_surface_t * */ +typedef struct { + cairo_surface_t *surface; + cairo_image_surface_t *image_out; + void *image_extra; +} quartz_source_image_t; + static void DataProviderReleaseCallback (void *info, const void *data, size_t size) { - cairo_surface_t *surface = (cairo_surface_t *) info; - cairo_surface_destroy (surface); + quartz_source_image_t *source_img = info; + _cairo_surface_release_source_image (source_img->surface, source_img->image_out, source_img->image_extra); + free (source_img); } static cairo_status_t _cairo_surface_to_cgimage (cairo_surface_t *source, CGImageRef *image_out) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_surface_type_t stype = cairo_surface_get_type (source); - cairo_image_surface_t *isurf; - CGImageRef image; - void *image_extra; + cairo_status_t status; + quartz_source_image_t *source_img; - if (stype == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) { + if (source->backend && source->backend->type == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) { cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) source; *image_out = CGImageRetain (surface->image); return CAIRO_STATUS_SUCCESS; } - if (stype == CAIRO_SURFACE_TYPE_QUARTZ) { + if (_cairo_surface_is_quartz (source)) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source; if (IS_EMPTY(surface)) { *image_out = NULL; @@ -1003,43 +1141,39 @@ _cairo_surface_to_cgimage (cairo_surface_t *source, } } - if (stype != CAIRO_SURFACE_TYPE_IMAGE) { - status = _cairo_surface_acquire_source_image (source, - &isurf, &image_extra); - if (status) - return status; - } else { - isurf = (cairo_image_surface_t *) source; + source_img = malloc (sizeof (quartz_source_image_t)); + if (source_img == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + source_img->surface = source; + + status = _cairo_surface_acquire_source_image (source_img->surface, &source_img->image_out, &source_img->image_extra); + if (status) { + free (source_img); + return status; } - if (isurf->width == 0 || isurf->height == 0) { + if (source_img->image_out->width == 0 || source_img->image_out->height == 0) { *image_out = NULL; + DataProviderReleaseCallback (source_img, + source_img->image_out->data, + source_img->image_out->height * source_img->image_out->stride); } else { - cairo_image_surface_t *isurf_snap = NULL; + *image_out = _cairo_quartz_create_cgimage (source_img->image_out->format, + source_img->image_out->width, + source_img->image_out->height, + source_img->image_out->stride, + source_img->image_out->data, + TRUE, + NULL, + DataProviderReleaseCallback, + source_img); - isurf_snap = (cairo_image_surface_t*) - _cairo_surface_snapshot (&isurf->base); - if (isurf_snap->base.status) - return isurf_snap->base.status; - - image = _cairo_quartz_create_cgimage (isurf_snap->format, - isurf_snap->width, - isurf_snap->height, - isurf_snap->stride, - isurf_snap->data, - TRUE, - NULL, - DataProviderReleaseCallback, - isurf_snap); - - *image_out = image; - if (image == NULL) + /* TODO: differentiate memory error and unsupported surface type */ + if (*image_out == NULL) status = CAIRO_INT_STATUS_UNSUPPORTED; } - if (&isurf->base != source) - _cairo_surface_release_source_image (source, isurf, image_extra); - return status; } @@ -1109,7 +1243,7 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t SurfacePatternDrawFunc, SurfacePatternReleaseInfoFunc }; SurfacePatternDrawInfo *info; - float rw, rh; + cairo_quartz_float_t rw, rh; cairo_status_t status; cairo_bool_t is_bounded; @@ -1225,11 +1359,6 @@ typedef struct { // Used with DO_PATTERN CGPatternRef pattern; - - // Used for handling unbounded operators - CGLayerRef unboundedLayer; - CGPoint unboundedLayerOffset; - CGContextRef unboundedDestination; } cairo_quartz_drawing_state_t; static void @@ -1365,7 +1494,7 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface, _cairo_fixed_to_double (lpat->p2.y)); if (abspat->extend == CAIRO_EXTEND_NONE || - abspat->extend == CAIRO_EXTEND_PAD) + abspat->extend == CAIRO_EXTEND_PAD) { gradFunc = CreateGradientFunction (&lpat->base); } else { @@ -1619,7 +1748,6 @@ _cairo_quartz_setup_state (cairo_quartz_surface_t *surface, { CGContextRef context = surface->cgContext; cairo_quartz_drawing_state_t state; - cairo_bool_t bounded_op = _cairo_operator_bounded_by_mask (op); cairo_status_t status; state.context = context; @@ -1628,7 +1756,6 @@ _cairo_quartz_setup_state (cairo_quartz_surface_t *surface, state.layer = NULL; state.shading = NULL; state.pattern = NULL; - state.unboundedLayer = NULL; _cairo_quartz_surface_will_change (surface); @@ -1637,6 +1764,8 @@ _cairo_quartz_setup_state (cairo_quartz_surface_t *surface, // pattern (which may be stack allocated) CGContextSaveGState(context); + CGContextSetInterpolationQuality (context, _cairo_quartz_filter_to_quartz (source->filter)); + status = _cairo_quartz_surface_set_cairo_operator (surface, op); if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { state.action = DO_NOTHING; @@ -1647,33 +1776,6 @@ _cairo_quartz_setup_state (cairo_quartz_surface_t *surface, return state; } - if (!bounded_op) { - state.unboundedDestination = context; - - CGRect clipBox = CGContextGetClipBoundingBox (context); - CGRect clipBoxRound = CGRectIntegral (CGRectInset (clipBox, -1, -1)); - state.unboundedLayer = CGLayerCreateWithContext (context, clipBoxRound.size, NULL); - if (!state.unboundedLayer) { - state.action = DO_UNSUPPORTED; - return state; - } - - context = CGLayerGetContext (state.unboundedLayer); - if (!context) { - state.action = DO_UNSUPPORTED; - return state; - } - state.context = context; - // No need to save state here, since this context won't be used later - CGContextTranslateCTM (context, -clipBoxRound.origin.x, -clipBoxRound.origin.y); - - state.unboundedLayerOffset = clipBoxRound.origin; - - CGContextSetCompositeOperation (context, kPrivateCGCompositeCopy); - } - - CGContextSetInterpolationQuality (context, _cairo_quartz_filter_to_quartz (source->filter)); - if (source->type == CAIRO_PATTERN_TYPE_SOLID) { cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; @@ -1705,7 +1807,7 @@ _cairo_quartz_setup_state (cairo_quartz_surface_t *surface, } if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { - if (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque (source) && + if (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque (source, NULL) && CGContextGetAlphaPtr && CGContextGetAlphaPtr (surface->cgContext) == 1.0) { // Quartz won't touch pixels outside the bounds of the @@ -1728,42 +1830,33 @@ _cairo_quartz_setup_state (cairo_quartz_surface_t *surface, /** * 1) Tears down internal state used to draw the source - * 2) Does CGContextRestoreGState on the state saved by _cairo_quartz_setup_state + * 2) Does CGContextRestoreGState(state->context) */ static void _cairo_quartz_teardown_state (cairo_quartz_drawing_state_t *state) { if (state->image) { - CGImageRelease (state->image); + CGImageRelease(state->image); } if (state->imageSurface) { - cairo_surface_destroy (state->imageSurface); + cairo_surface_destroy(state->imageSurface); } if (state->shading) { - CGShadingRelease (state->shading); + CGShadingRelease(state->shading); } if (state->pattern) { - CGPatternRelease (state->pattern); + CGPatternRelease(state->pattern); } - if (state->unboundedLayer) { - // Copy the layer back to the destination - CGContextDrawLayerAtPoint (state->unboundedDestination, - state->unboundedLayerOffset, - state->unboundedLayer); - CGContextRestoreGState (state->unboundedDestination); - CGLayerRelease (state->unboundedLayer); - } else { - CGContextRestoreGState (state->context); - } + CGContextRestoreGState(state->context); } static void -_cairo_quartz_draw_image (cairo_quartz_drawing_state_t *state) +_cairo_quartz_draw_image (cairo_quartz_drawing_state_t *state, cairo_operator_t op) { assert (state && ((state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE)) || @@ -1788,6 +1881,16 @@ _cairo_quartz_draw_image (cairo_quartz_drawing_state_t *state) } else { CGContextDrawImage (state->context, state->imageRect, state->image); } + + /* disable this EXTEND_NONE correctness code because we use this path + * for both EXTEND_NONE and EXTEND_PAD */ + if (0 && !_cairo_operator_bounded_by_source (op)) { + CGContextBeginPath (state->context); + CGContextAddRect (state->context, state->imageRect); + CGContextAddRect (state->context, CGContextGetClipBoundingBox (state->context)); + CGContextSetRGBFillColor (state->context, 0, 0, 0, 0); + CGContextEOFillPath (state->context); + } } } @@ -2115,7 +2218,7 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } - if (src->backend->type == CAIRO_SURFACE_TYPE_QUARTZ) { + if (_cairo_surface_is_quartz (src)) { cairo_quartz_surface_t *qsurf = (cairo_quartz_surface_t *) src; if (IS_EMPTY(qsurf)) { @@ -2181,32 +2284,10 @@ _cairo_quartz_surface_get_extents (void *abstract_surface, } static cairo_int_status_t -_cairo_quartz_surface_paint_internal (cairo_quartz_surface_t *surface, - cairo_quartz_drawing_state_t *state) -{ - if (state->action == DO_SOLID || state->action == DO_PATTERN) { - CGContextFillRect (state->context, CGRectMake(surface->extents.x, - surface->extents.y, - surface->extents.width, - surface->extents.height)); - } else if (state->action == DO_SHADING) { - CGContextConcatCTM (state->context, state->transform); - CGContextDrawShading (state->context, state->shading); - } else if (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE || - state->action == DO_LAYER) { - _cairo_quartz_draw_image (state); - } else if (state->action != DO_NOTHING) { - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_quartz_surface_paint (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_clip_t *clip) +_cairo_quartz_surface_paint_cg (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -2223,7 +2304,20 @@ _cairo_quartz_surface_paint (void *abstract_surface, state = _cairo_quartz_setup_state (surface, source, op, NULL); - rv = _cairo_quartz_surface_paint_internal (surface, &state); + if (state.action == DO_SOLID || state.action == DO_PATTERN) { + CGContextFillRect (state.context, CGRectMake(surface->extents.x, + surface->extents.y, + surface->extents.width, + surface->extents.height)); + } else if (state.action == DO_SHADING) { + CGContextConcatCTM (state.context, state.transform); + CGContextDrawShading (state.context, state.shading); + } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || + state.action == DO_LAYER) { + _cairo_quartz_draw_image (&state, op); + } else if (state.action != DO_NOTHING) { + rv = CAIRO_INT_STATUS_UNSUPPORTED; + } _cairo_quartz_teardown_state (&state); @@ -2251,19 +2345,46 @@ _cairo_quartz_source_needs_extents (const cairo_pattern_t *source) } static cairo_int_status_t -_cairo_quartz_surface_fill (void *abstract_surface, +_cairo_quartz_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias, cairo_clip_t *clip) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_int_status_t rv; + cairo_image_surface_t *image; + + rv = _cairo_quartz_surface_paint_cg (abstract_surface, + op, + source, + clip); + + if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED)) + return rv; + + rv = _cairo_quartz_get_image (surface, &image); + if (rv == CAIRO_STATUS_SUCCESS) { + rv = _cairo_surface_paint (&image->base, op, source, clip); + cairo_surface_destroy (&image->base); + } + + return rv; +} + +static cairo_int_status_t +_cairo_quartz_surface_fill_cg (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; cairo_quartz_drawing_state_t state; - quartz_stroke_t stroke; + CGPathRef path_for_unbounded = NULL; ND((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type)); @@ -2288,13 +2409,10 @@ _cairo_quartz_surface_fill (void *abstract_surface, CGContextSetShouldAntialias (state.context, (antialias != CAIRO_ANTIALIAS_NONE)); - CGContextBeginPath (state.context); + _cairo_quartz_cairo_path_to_quartz_context (path, state.context); - stroke.cgContext = state.context; - stroke.ctm_inverse = NULL; - rv = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke); - if (rv) - goto BAIL; + if (!_cairo_operator_bounded_by_mask(op) && CGContextCopyPathPtr) + path_for_unbounded = CGContextCopyPathPtr (state.context); if (state.action == DO_SOLID || state.action == DO_PATTERN) { if (fill_rule == CAIRO_FILL_RULE_WINDING) @@ -2319,35 +2437,81 @@ _cairo_quartz_surface_fill (void *abstract_surface, else CGContextEOClip (state.context); - _cairo_quartz_draw_image (&state); + _cairo_quartz_draw_image (&state, op); } else if (state.action != DO_NOTHING) { rv = CAIRO_INT_STATUS_UNSUPPORTED; } - BAIL: _cairo_quartz_teardown_state (&state); + if (path_for_unbounded) { + unbounded_op_data_t ub; + ub.op = UNBOUNDED_STROKE_FILL; + ub.u.stroke_fill.cgPath = path_for_unbounded; + ub.u.stroke_fill.fill_rule = fill_rule; + + _cairo_quartz_fixup_unbounded_operation (surface, &ub, antialias); + CGPathRelease (path_for_unbounded); + } + ND((stderr, "-- fill\n")); return rv; } static cairo_int_status_t -_cairo_quartz_surface_stroke (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, - double tolerance, - cairo_antialias_t antialias, - cairo_clip_t *clip) +_cairo_quartz_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_int_status_t rv; + cairo_image_surface_t *image; + + rv = _cairo_quartz_surface_fill_cg (abstract_surface, + op, + source, + path, + fill_rule, + tolerance, + antialias, + clip); + + if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED)) + return rv; + + rv = _cairo_quartz_get_image (surface, &image); + if (rv == CAIRO_STATUS_SUCCESS) { + rv = _cairo_surface_fill (&image->base, op, source, + path, fill_rule, tolerance, antialias, + clip); + cairo_surface_destroy (&image->base); + } + + return rv; +} + +static cairo_int_status_t +_cairo_quartz_surface_stroke_cg (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; cairo_quartz_drawing_state_t state; - quartz_stroke_t stroke; CGAffineTransform origCTM, strokeTransform; + CGPathRef path_for_unbounded = NULL; ND((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", surface, op, source->type)); @@ -2358,13 +2522,17 @@ _cairo_quartz_surface_stroke (void *abstract_surface, if (unlikely (rv)) return rv; + rv = _cairo_quartz_surface_set_cairo_operator (surface, op); + if (unlikely (rv)) + return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv; + if (_cairo_quartz_source_needs_extents (source)) { - cairo_rectangle_int_t path_extents; - _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &path_extents); - state = _cairo_quartz_setup_state (surface, source, op, &path_extents); + cairo_rectangle_int_t path_extents; + _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &path_extents); + state = _cairo_quartz_setup_state (surface, source, op, &path_extents); } else { - state = _cairo_quartz_setup_state (surface, source, op, NULL); + state = _cairo_quartz_setup_state (surface, source, op, NULL); } // Turning antialiasing off used to cause misrendering with @@ -2380,47 +2548,35 @@ _cairo_quartz_surface_stroke (void *abstract_surface, if (style->dash && style->num_dashes) { #define STATIC_DASH 32 - CGFloat sdash[STATIC_DASH]; - CGFloat *fdash = sdash; - double offset = style->dash_offset; + cairo_quartz_float_t sdash[STATIC_DASH]; + cairo_quartz_float_t *fdash = sdash; unsigned int max_dashes = style->num_dashes; unsigned int k; - if (_cairo_stroke_style_dash_can_approximate (style, ctm, tolerance)) { - double approximate_dashes[2]; - _cairo_stroke_style_dash_approximate (style, ctm, tolerance, - &offset, - approximate_dashes, - &max_dashes); - sdash[0] = approximate_dashes[0]; - sdash[1] = approximate_dashes[1]; - } else { - if (style->num_dashes%2) - max_dashes *= 2; - if (max_dashes > STATIC_DASH) - fdash = _cairo_malloc_ab (max_dashes, sizeof (CGFloat)); - if (fdash == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (style->num_dashes%2) + max_dashes *= 2; + if (max_dashes > STATIC_DASH) + fdash = _cairo_malloc_ab (max_dashes, sizeof (cairo_quartz_float_t)); + if (fdash == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); - for (k = 0; k < max_dashes; k++) - fdash[k] = (CGFloat) style->dash[k % style->num_dashes]; - } - CGContextSetLineDash (state.context, offset, fdash, max_dashes); + for (k = 0; k < max_dashes; k++) + fdash[k] = (cairo_quartz_float_t) style->dash[k % style->num_dashes]; + + CGContextSetLineDash (surface->cgContext, style->dash_offset, fdash, max_dashes); if (fdash != sdash) free (fdash); } else CGContextSetLineDash (state.context, 0, NULL, 0); + + _cairo_quartz_cairo_path_to_quartz_context (path, state.context); + _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform); CGContextConcatCTM (state.context, strokeTransform); - CGContextBeginPath (state.context); - - stroke.cgContext = state.context; - stroke.ctm_inverse = ctm_inverse; - rv = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke); - if (rv) - goto BAIL; + if (!_cairo_operator_bounded_by_mask (op) && CGContextCopyPathPtr) + path_for_unbounded = CGContextCopyPathPtr (state.context); if (state.action == DO_SOLID || state.action == DO_PATTERN) { CGContextStrokePath (state.context); @@ -2430,7 +2586,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface, CGContextClip (state.context); CGContextSetCTM (state.context, origCTM); - _cairo_quartz_draw_image (&state); + _cairo_quartz_draw_image (&state, op); } else if (state.action == DO_SHADING) { CGContextReplacePathWithStrokedPath (state.context); CGContextClip (state.context); @@ -2444,6 +2600,26 @@ _cairo_quartz_surface_stroke (void *abstract_surface, goto BAIL; } + if (path_for_unbounded) { + unbounded_op_data_t ub; + ub.op = UNBOUNDED_STROKE_FILL; + ub.u.stroke_fill.fill_rule = CAIRO_FILL_RULE_WINDING; + + CGContextBeginPath (state.context); + CGContextAddPath (state.context, path_for_unbounded); + CGPathRelease (path_for_unbounded); + + CGContextSaveGState (state.context); + CGContextConcatCTM (state.context, strokeTransform); + CGContextReplacePathWithStrokedPath (state.context); + CGContextRestoreGState (state.context); + + ub.u.stroke_fill.cgPath = CGContextCopyPathPtr (state.context); + + _cairo_quartz_fixup_unbounded_operation (surface, &ub, antialias); + CGPathRelease (ub.u.stroke_fill.cgPath); + } + BAIL: _cairo_quartz_teardown_state (&state); @@ -2451,28 +2627,65 @@ _cairo_quartz_surface_stroke (void *abstract_surface, return rv; } +static cairo_int_status_t +_cairo_quartz_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_int_status_t rv; + cairo_image_surface_t *image; + + rv = _cairo_quartz_surface_stroke_cg (abstract_surface, op, source, + path, style, ctm, ctm_inverse, + tolerance, antialias, + clip); + + if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED)) + return rv; + + rv = _cairo_quartz_get_image (surface, &image); + if (rv == CAIRO_STATUS_SUCCESS) { + rv = _cairo_surface_stroke (&image->base, op, source, + path, style, ctm, ctm_inverse, + tolerance, antialias, + clip); + cairo_surface_destroy (&image->base); + } + + return rv; +} + #if CAIRO_HAS_QUARTZ_FONT static cairo_int_status_t -_cairo_quartz_surface_show_glyphs (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, - int *remaining_glyphs) +_cairo_quartz_surface_show_glyphs_cg (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip, + int *remaining_glyphs) { - CGAffineTransform textTransform, ctm; + CGAffineTransform textTransform, ctm, invTextTransform; #define STATIC_BUF_SIZE 64 CGGlyph glyphs_static[STATIC_BUF_SIZE]; CGSize cg_advances_static[STATIC_BUF_SIZE]; CGGlyph *cg_glyphs = &glyphs_static[0]; CGSize *cg_advances = &cg_advances_static[0]; + cairo_rectangle_int_t glyph_extents; cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; cairo_quartz_drawing_state_t state; - float xprev, yprev; + cairo_quartz_float_t xprev, yprev; int i; CGFontRef cgfref = NULL; @@ -2493,11 +2706,10 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, if (unlikely (rv)) return rv; - if (_cairo_quartz_source_needs_extents (source)) + if (_cairo_quartz_source_needs_extents (source) && + !_cairo_scaled_font_glyph_device_extents (scaled_font, glyphs, num_glyphs, + &glyph_extents, NULL)) { - cairo_rectangle_int_t glyph_extents; - _cairo_scaled_font_glyph_device_extents (scaled_font, glyphs, num_glyphs, - &glyph_extents, NULL); state = _cairo_quartz_setup_state (surface, source, op, &glyph_extents); } else { state = _cairo_quartz_setup_state (surface, source, op, NULL); @@ -2563,20 +2775,21 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, } } - textTransform = CGAffineTransformMake (scaled_font->font_matrix.xx, - scaled_font->font_matrix.yx, - scaled_font->font_matrix.xy, - scaled_font->font_matrix.yy, - 0., 0.); - textTransform = CGAffineTransformScale (textTransform, 1.0, -1.0); - textTransform = CGAffineTransformConcat (CGAffineTransformMake(scaled_font->ctm.xx, - -scaled_font->ctm.yx, - -scaled_font->ctm.xy, - scaled_font->ctm.yy, - 0., 0.), - textTransform); + /* scale(1,-1) * scaled_font->scale */ + textTransform = CGAffineTransformMake (scaled_font->scale.xx, + scaled_font->scale.yx, + -scaled_font->scale.xy, + -scaled_font->scale.yy, + 0, 0); - CGContextSetTextMatrix (state.context, textTransform); + /* scaled_font->scale_inverse * scale(1,-1) */ + invTextTransform = CGAffineTransformMake (scaled_font->scale_inverse.xx, + -scaled_font->scale_inverse.yx, + scaled_font->scale_inverse.xy, + -scaled_font->scale_inverse.yy, + 0.0, 0.0); + + CGContextSetTextMatrix (state.context, CGAffineTransformIdentity); /* Convert our glyph positions to glyph advances. We need n-1 advances, * since the advance at index 0 is applied after glyph 0. */ @@ -2586,35 +2799,18 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, cg_glyphs[0] = glyphs[0].index; for (i = 1; i < num_glyphs; i++) { - float xf = glyphs[i].x; - float yf = glyphs[i].y; + cairo_quartz_float_t xf = glyphs[i].x; + cairo_quartz_float_t yf = glyphs[i].y; cg_glyphs[i] = glyphs[i].index; - cg_advances[i-1].width = xf - xprev; - cg_advances[i-1].height = yf - yprev; + cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform); xprev = xf; yprev = yf; } - if (_cairo_quartz_osx_version >= 0x1050 && isClipping) { - /* If we're clipping, OSX 10.5 (at least as of 10.5.2) has a - * bug (apple bug ID #5834794) where the glyph - * advances/positions are not transformed by the text matrix - * if kCGTextClip is being used. So, we pre-transform here. - * 10.4 does not have this problem (as of 10.4.11). - */ - for (i = 0; i < num_glyphs - 1; i++) - cg_advances[i] = CGSizeApplyAffineTransform(cg_advances[i], textTransform); - } - -#if 0 - for (i = 0; i < num_glyphs; i++) { - ND((stderr, "[%d: %d %f,%f]\n", i, cg_glyphs[i], cg_advances[i].width, cg_advances[i].height)); - } -#endif - /* Translate to the first glyph's position before drawing */ ctm = CGContextGetCTM (state.context); CGContextTranslateCTM (state.context, glyphs[0].x, glyphs[0].y); + CGContextConcatCTM (state.context, textTransform); CGContextShowGlyphsWithAdvances (state.context, cg_glyphs, @@ -2625,7 +2821,7 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface, if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || state.action == DO_LAYER) { - _cairo_quartz_draw_image (&state); + _cairo_quartz_draw_image (&state, op); } else if (state.action == DO_SHADING) { CGContextConcatCTM (state.context, state.transform); CGContextDrawShading (state.context, state.shading); @@ -2637,6 +2833,25 @@ BAIL: _cairo_quartz_teardown_state (&state); + if (rv == CAIRO_STATUS_SUCCESS && + cgfref && + !_cairo_operator_bounded_by_mask (op)) + { + unbounded_op_data_t ub; + ub.op = UNBOUNDED_SHOW_GLYPHS; + + ub.u.show_glyphs.isClipping = isClipping; + ub.u.show_glyphs.cg_glyphs = cg_glyphs; + ub.u.show_glyphs.cg_advances = cg_advances; + ub.u.show_glyphs.nglyphs = num_glyphs; + ub.u.show_glyphs.textTransform = textTransform; + ub.u.show_glyphs.font = cgfref; + ub.u.show_glyphs.origin = CGPointMake (glyphs[0].x, glyphs[0].y); + + _cairo_quartz_fixup_unbounded_operation (surface, &ub, scaled_font->options.antialias); + } + + if (cg_advances != &cg_advances_static[0]) { free (cg_advances); } @@ -2649,6 +2864,43 @@ BAIL: } #endif /* CAIRO_HAS_QUARTZ_FONT */ +static cairo_int_status_t +_cairo_quartz_surface_show_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip, + int *remaining_glyphs) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_int_status_t rv = CAIRO_INT_STATUS_UNSUPPORTED; + cairo_image_surface_t *image; + +#if CAIRO_HAS_QUARTZ_FONT + rv = _cairo_quartz_surface_show_glyphs_cg (abstract_surface, op, source, + glyphs, num_glyphs, + scaled_font, clip, remaining_glyphs); + + if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED)) + return rv; + +#endif + + rv = _cairo_quartz_get_image (surface, &image); + if (rv == CAIRO_STATUS_SUCCESS) { + rv = _cairo_surface_show_text_glyphs (&image->base, op, source, + NULL, 0, + glyphs, num_glyphs, + NULL, 0, 0, + scaled_font, clip); + cairo_surface_destroy (&image->base); + } + + return rv; +} + static cairo_int_status_t _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, cairo_operator_t op, @@ -2661,13 +2913,6 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, cairo_surface_t *pat_surf = mask->surface; cairo_status_t status = CAIRO_STATUS_SUCCESS; CGAffineTransform ctm, mask_matrix; - cairo_quartz_drawing_state_t state; - - if (IS_EMPTY(surface)) - return CAIRO_STATUS_SUCCESS; - - if (op == CAIRO_OPERATOR_DEST) - return CAIRO_STATUS_SUCCESS; status = _cairo_surface_to_cgimage (pat_surf, &img); if (status) @@ -2680,25 +2925,33 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface, rect = CGRectMake (0.0f, 0.0f, CGImageGetWidth (img) , CGImageGetHeight (img)); - state = _cairo_quartz_setup_state (surface, source, op, NULL); + CGContextSaveGState (surface->cgContext); /* ClipToMask is essentially drawing an image, so we need to flip the CTM * to get the image to appear oriented the right way */ - ctm = CGContextGetCTM (state.context); + ctm = CGContextGetCTM (surface->cgContext); _cairo_quartz_cairo_matrix_to_quartz (&mask->base.matrix, &mask_matrix); mask_matrix = CGAffineTransformInvert(mask_matrix); mask_matrix = CGAffineTransformTranslate (mask_matrix, 0.0, CGImageGetHeight (img)); mask_matrix = CGAffineTransformScale (mask_matrix, 1.0, -1.0); - CGContextConcatCTM (state.context, mask_matrix); - CGContextClipToMaskPtr (state.context, rect, img); + CGContextConcatCTM (surface->cgContext, mask_matrix); + CGContextClipToMaskPtr (surface->cgContext, rect, img); - CGContextSetCTM (state.context, ctm); + CGContextSetCTM (surface->cgContext, ctm); - status = _cairo_quartz_surface_paint_internal (surface, &state); + status = _cairo_quartz_surface_paint_cg (surface, op, source, clip); - _cairo_quartz_teardown_state (&state); + CGContextRestoreGState (surface->cgContext); + + if (!_cairo_operator_bounded_by_mask (op)) { + unbounded_op_data_t ub; + ub.op = UNBOUNDED_MASK; + ub.u.mask.mask = img; + ub.u.mask.maskTransform = mask_matrix; + _cairo_quartz_fixup_unbounded_operation (surface, &ub, CAIRO_ANTIALIAS_NONE); + } CGImageRelease (img); @@ -2746,11 +2999,11 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface, } static cairo_int_status_t -_cairo_quartz_surface_mask (void *abstract_surface, - cairo_operator_t op, - const cairo_pattern_t *source, - const cairo_pattern_t *mask, - cairo_clip_t *clip) +_cairo_quartz_surface_mask_cg (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) { cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; @@ -2771,7 +3024,7 @@ _cairo_quartz_surface_mask (void *abstract_surface, cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask; CGContextSetAlpha (surface->cgContext, solid_mask->color.alpha); - rv = _cairo_quartz_surface_paint (surface, op, source, clip); + rv = _cairo_quartz_surface_paint_cg (surface, op, source, clip); CGContextSetAlpha (surface->cgContext, 1.0); return rv; @@ -2796,6 +3049,35 @@ _cairo_quartz_surface_mask (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_quartz_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_int_status_t rv; + cairo_image_surface_t *image; + + rv = _cairo_quartz_surface_mask_cg (abstract_surface, + op, + source, + mask, + clip); + + if (likely (rv != CAIRO_INT_STATUS_UNSUPPORTED)) + return rv; + + rv = _cairo_quartz_get_image (surface, &image); + if (rv == CAIRO_STATUS_SUCCESS) { + rv = _cairo_surface_mask (&image->base, op, source, mask, clip); + cairo_surface_destroy (&image->base); + } + + return rv; +} + static cairo_status_t _cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, cairo_path_fixed_t *path, @@ -2805,8 +3087,6 @@ _cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip { cairo_quartz_surface_t *surface = cairo_container_of (clipper, cairo_quartz_surface_t, clipper); - quartz_stroke_t stroke; - cairo_status_t status; ND((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path)); @@ -2824,17 +3104,9 @@ _cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip CGContextRestoreGState (surface->cgContext); CGContextSaveGState (surface->cgContext); } else { - CGContextBeginPath (surface->cgContext); - stroke.cgContext = surface->cgContext; - stroke.ctm_inverse = NULL; - CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE)); - /* path must not be empty. */ - CGContextMoveToPoint (surface->cgContext, 0, 0); - status = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke); - if (status) - return status; + _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext); if (fill_rule == CAIRO_FILL_RULE_WINDING) CGContextClip (surface->cgContext); @@ -2877,11 +3149,7 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = { _cairo_quartz_surface_mask, _cairo_quartz_surface_stroke, _cairo_quartz_surface_fill, -#if CAIRO_HAS_QUARTZ_FONT _cairo_quartz_surface_show_glyphs, -#else - NULL, /* show_glyphs */ -#endif NULL, /* snapshot */ NULL, /* is_similar */ @@ -2905,8 +3173,10 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext, memset(surface, 0, sizeof(cairo_quartz_surface_t)); - _cairo_surface_init(&surface->base, &cairo_quartz_surface_backend, - content); + _cairo_surface_init (&surface->base, + &cairo_quartz_surface_backend, + NULL, /* device */ + content); _cairo_surface_clipper_init (&surface->clipper, _cairo_quartz_surface_clipper_intersect_clip_path); @@ -3260,12 +3530,17 @@ cairo_quartz_surface_create_for_data (unsigned char *data, CGContextRef cairo_quartz_surface_get_cg_context (cairo_surface_t *surface) { - cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t*)surface; - - if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_QUARTZ) + if (surface && _cairo_surface_is_quartz (surface)) { + cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface; + return quartz->cgContext; + } else return NULL; +} - return quartz->cgContext; +static cairo_bool_t +_cairo_surface_is_quartz (const cairo_surface_t *surface) +{ + return surface->backend == &cairo_quartz_surface_backend; } CGContextRef @@ -3285,12 +3560,12 @@ cairo_quartz_get_cg_context_with_clip (cairo_t *cr) if (clip->all_clipped) { /* Save the state before we set an empty clip rect so that * our previous clip will be restored */ - CGContextSaveGState (quartz->cgContext); /* _cairo_surface_clipper_set_clip doesn't deal with * clip->all_clipped because drawing is normally discarded earlier */ CGRect empty = {{0,0}, {0,0}}; CGContextClipToRect (quartz->cgContext, empty); + CGContextSaveGState (quartz->cgContext); return quartz->cgContext; } diff --git a/gfx/cairo/cairo/src/cairo-quartz.h b/gfx/cairo/cairo/src/cairo-quartz.h index 7d8996a493f3..fef2724f8197 100644 --- a/gfx/cairo/cairo/src/cairo-quartz.h +++ b/gfx/cairo/cairo/src/cairo-quartz.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-recording-surface-private.h b/gfx/cairo/cairo/src/cairo-recording-surface-private.h index f0824f50b488..4ec5f88b47b5 100644 --- a/gfx/cairo/cairo/src/cairo-recording-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-recording-surface-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -132,7 +132,6 @@ typedef struct _cairo_recording_surface { cairo_clip_t clip; cairo_array_t commands; - cairo_surface_t *commands_owner; int replay_start_idx; } cairo_recording_surface_t; @@ -157,6 +156,7 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface, cairo_surface_t *target); cairo_private cairo_status_t _cairo_recording_surface_replay_region (cairo_surface_t *surface, + const cairo_rectangle_int_t *surface_extents, cairo_surface_t *target, cairo_recording_region_type_t region); diff --git a/gfx/cairo/cairo/src/cairo-recording-surface.c b/gfx/cairo/cairo/src/cairo-recording-surface.c index c50b330eec96..79d51e8cc653 100644 --- a/gfx/cairo/cairo/src/cairo-recording-surface.c +++ b/gfx/cairo/cairo/src/cairo-recording-surface.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,7 +37,13 @@ * Adrian Johnson */ -/* A recording surface is a surface that records all drawing operations at +/** + * SECTION:cairo-recording + * @Title: Recording Surfaces + * @Short_Description: Records all drawing operations + * @See_Also: #cairo_surface_t + * + * A recording surface is a surface that records all drawing operations at * the highest level of the surface backend interface, (that is, the * level of paint, mask, stroke, fill, and show_text_glyphs). The recording * surface can then be "replayed" against any target surface by using it @@ -70,12 +76,11 @@ * copy-on-write implementation for _cairo_surface_snapshot. */ -/* XXX Rename to recording surface */ - #include "cairoint.h" #include "cairo-analysis-surface-private.h" -#include "cairo-recording-surface-private.h" #include "cairo-clip-private.h" +#include "cairo-error-private.h" +#include "cairo-recording-surface-private.h" #include "cairo-surface-wrapper-private.h" typedef enum { @@ -85,6 +90,16 @@ typedef enum { static const cairo_surface_backend_t cairo_recording_surface_backend; +/** + * CAIRO_HAS_RECORDING_SURFACE: + * + * Defined if the recording surface backend is available. + * The recording surface backend is always built in. + * This macro was added for completeness in cairo 1.10. + * + * Since: 1.10 + */ + /* Currently all recording surfaces do have a size which should be passed * in as the maximum size of any target surface against which the * recording-surface will ever be replayed. @@ -97,8 +112,8 @@ static const cairo_surface_backend_t cairo_recording_surface_backend; /** * cairo_recording_surface_create: * @content: the content of the recording surface - * @extents_pixels: the extents to record in pixels, can be %NULL to record - * unbounded operations. + * @extents: the extents to record in pixels, can be %NULL to record + * unbounded operations. * * Creates a recording-surface which can be used to record all drawing operations * at the highest level (that is, the level of paint, mask, stroke, fill @@ -109,7 +124,11 @@ static const cairo_surface_backend_t cairo_recording_surface_backend; * necessary objects (paths, patterns, etc.), in order to achieve * accurate replay. * - * Since 1.10 + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * Since: 1.10 **/ cairo_surface_t * cairo_recording_surface_create (cairo_content_t content, @@ -122,10 +141,16 @@ cairo_recording_surface_create (cairo_content_t content, if (unlikely (recording_surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - _cairo_surface_init (&recording_surface->base, &cairo_recording_surface_backend, content); + _cairo_surface_init (&recording_surface->base, + &cairo_recording_surface_backend, + NULL, /* device */ + content); recording_surface->content = content; + recording_surface->unbounded = TRUE; + _cairo_clip_init (&recording_surface->clip); + /* unbounded -> 'infinite' extents */ if (extents != NULL) { recording_surface->extents_pixels = *extents; @@ -136,22 +161,20 @@ cairo_recording_surface_create (cairo_content_t content, recording_surface->extents.width = ceil (extents->x + extents->width) - recording_surface->extents.x; recording_surface->extents.height = ceil (extents->y + extents->height) - recording_surface->extents.y; - status = _cairo_clip_init_rectangle (&recording_surface->clip, &recording_surface->extents); + status = _cairo_clip_rectangle (&recording_surface->clip, + &recording_surface->extents); if (unlikely (status)) { free (recording_surface); return _cairo_surface_create_in_error (status); } recording_surface->unbounded = FALSE; - } else { - recording_surface->unbounded = TRUE; - _cairo_clip_init (&recording_surface->clip); } _cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *)); - recording_surface->commands_owner = NULL; recording_surface->replay_start_idx = 0; + recording_surface->base.is_clear = TRUE; return &recording_surface->base; } @@ -177,59 +200,50 @@ _cairo_recording_surface_finish (void *abstract_surface) cairo_command_t **elements; int i, num_elements; - if (recording_surface->commands_owner) { - cairo_surface_destroy (recording_surface->commands_owner); - return CAIRO_STATUS_SUCCESS; - } - num_elements = recording_surface->commands.num_elements; elements = _cairo_array_index (&recording_surface->commands, 0); for (i = 0; i < num_elements; i++) { cairo_command_t *command = elements[i]; - _cairo_clip_reset (&command->header.clip); - switch (command->header.type) { case CAIRO_COMMAND_PAINT: - _cairo_pattern_fini_snapshot (&command->paint.source.base); - free (command); + _cairo_pattern_fini (&command->paint.source.base); break; case CAIRO_COMMAND_MASK: - _cairo_pattern_fini_snapshot (&command->mask.source.base); - _cairo_pattern_fini_snapshot (&command->mask.mask.base); - free (command); + _cairo_pattern_fini (&command->mask.source.base); + _cairo_pattern_fini (&command->mask.mask.base); break; case CAIRO_COMMAND_STROKE: - _cairo_pattern_fini_snapshot (&command->stroke.source.base); + _cairo_pattern_fini (&command->stroke.source.base); _cairo_path_fixed_fini (&command->stroke.path); _cairo_stroke_style_fini (&command->stroke.style); - free (command); break; case CAIRO_COMMAND_FILL: - _cairo_pattern_fini_snapshot (&command->fill.source.base); + _cairo_pattern_fini (&command->fill.source.base); _cairo_path_fixed_fini (&command->fill.path); - free (command); break; case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: - _cairo_pattern_fini_snapshot (&command->show_text_glyphs.source.base); + _cairo_pattern_fini (&command->show_text_glyphs.source.base); free (command->show_text_glyphs.utf8); free (command->show_text_glyphs.glyphs); free (command->show_text_glyphs.clusters); cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font); - free (command); break; default: ASSERT_NOT_REACHED; } + + _cairo_clip_fini (&command->header.clip); + free (command); } _cairo_array_fini (&recording_surface->commands); - _cairo_clip_reset (&recording_surface->clip); + _cairo_clip_fini (&recording_surface->clip); return CAIRO_STATUS_SUCCESS; } @@ -244,8 +258,7 @@ _cairo_recording_surface_acquire_source_image (void *abstract_surface, cairo_surface_t *image; image = _cairo_surface_has_snapshot (&surface->base, - &_cairo_image_surface_backend, - surface->content); + &_cairo_image_surface_backend); if (image != NULL) { *image_out = (cairo_image_surface_t *) cairo_surface_reference (image); *image_extra = NULL; @@ -268,11 +281,7 @@ _cairo_recording_surface_acquire_source_image (void *abstract_surface, return status; } - status = _cairo_surface_attach_snapshot (&surface->base, image, NULL); - if (unlikely (status)) { - cairo_surface_destroy (image); - return status; - } + _cairo_surface_attach_snapshot (&surface->base, image, NULL); *image_out = (cairo_image_surface_t *) image; *image_extra = NULL; @@ -342,8 +351,9 @@ _cairo_recording_surface_paint (void *abstract_surface, return CAIRO_STATUS_SUCCESS; CLEANUP_SOURCE: - _cairo_pattern_fini_snapshot (&command->source.base); + _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: + _cairo_clip_fini (&command->header.clip); free (command); return status; } @@ -383,10 +393,11 @@ _cairo_recording_surface_mask (void *abstract_surface, return CAIRO_STATUS_SUCCESS; CLEANUP_MASK: - _cairo_pattern_fini_snapshot (&command->mask.base); + _cairo_pattern_fini (&command->mask.base); CLEANUP_SOURCE: - _cairo_pattern_fini_snapshot (&command->source.base); + _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: + _cairo_clip_fini (&command->header.clip); free (command); return status; } @@ -396,9 +407,9 @@ _cairo_recording_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) @@ -444,8 +455,9 @@ _cairo_recording_surface_stroke (void *abstract_surface, CLEANUP_PATH: _cairo_path_fixed_fini (&command->path); CLEANUP_SOURCE: - _cairo_pattern_fini_snapshot (&command->source.base); + _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: + _cairo_clip_fini (&command->header.clip); free (command); return status; } @@ -494,8 +506,9 @@ _cairo_recording_surface_fill (void *abstract_surface, CLEANUP_PATH: _cairo_path_fixed_fini (&command->path); CLEANUP_SOURCE: - _cairo_pattern_fini_snapshot (&command->source.base); + _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: + _cairo_clip_fini (&command->header.clip); free (command); return status; } @@ -587,8 +600,9 @@ _cairo_recording_surface_show_text_glyphs (void *abstract_surface, free (command->glyphs); free (command->clusters); - _cairo_pattern_fini_snapshot (&command->source.base); + _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: + _cairo_clip_fini (&command->header.clip); free (command); return status; } @@ -611,25 +625,37 @@ _cairo_recording_surface_snapshot (void *abstract_other) { cairo_recording_surface_t *other = abstract_other; cairo_recording_surface_t *recording_surface; + cairo_status_t status; recording_surface = malloc (sizeof (cairo_recording_surface_t)); if (unlikely (recording_surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - _cairo_surface_init (&recording_surface->base, &cairo_recording_surface_backend, + _cairo_surface_init (&recording_surface->base, + &cairo_recording_surface_backend, + NULL, /* device */ other->base.content); recording_surface->extents_pixels = other->extents_pixels; recording_surface->extents = other->extents; recording_surface->unbounded = other->unbounded; - recording_surface->replay_start_idx = other->replay_start_idx; recording_surface->content = other->content; - _cairo_array_init_snapshot (&recording_surface->commands, &other->commands); - recording_surface->commands_owner = cairo_surface_reference (&other->base); - _cairo_clip_init_copy (&recording_surface->clip, &other->clip); + /* XXX We should in theory be able to reuse the original array, but we + * need to handle reference cycles during subsurface and self-copy. + */ + recording_surface->replay_start_idx = 0; + recording_surface->base.is_clear = TRUE; + + _cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *)); + status = _cairo_recording_surface_replay (&other->base, &recording_surface->base); + if (unlikely (status)) { + cairo_surface_destroy (&recording_surface->base); + return _cairo_surface_create_in_error (status); + } + return &recording_surface->base; } @@ -782,6 +808,7 @@ _cairo_recording_surface_get_path (cairo_surface_t *surface, #define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL) static cairo_status_t _cairo_recording_surface_replay_internal (cairo_surface_t *surface, + const cairo_rectangle_int_t *surface_extents, cairo_surface_t *target, cairo_recording_replay_type_t type, cairo_recording_region_type_t region) @@ -796,15 +823,25 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface, return surface->status; if (unlikely (target->status)) - return _cairo_surface_set_error (surface, target->status); + return target->status; + + if (unlikely (surface->finished)) + return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + + if (surface->is_clear) + return CAIRO_STATUS_SUCCESS; + + assert (_cairo_surface_is_recording (surface)); _cairo_surface_wrapper_init (&wrapper, target); + _cairo_surface_wrapper_set_extents (&wrapper, surface_extents); recording_surface = (cairo_recording_surface_t *) surface; status = CAIRO_STATUS_SUCCESS; num_elements = recording_surface->commands.num_elements; elements = _cairo_array_index (&recording_surface->commands, 0); + for (i = recording_surface->replay_start_idx; i < num_elements; i++) { cairo_command_t *command = elements[i]; @@ -971,7 +1008,7 @@ cairo_status_t _cairo_recording_surface_replay (cairo_surface_t *surface, cairo_surface_t *target) { - return _cairo_recording_surface_replay_internal (surface, + return _cairo_recording_surface_replay_internal (surface, NULL, target, CAIRO_RECORDING_REPLAY, CAIRO_RECORDING_REGION_ALL); @@ -987,7 +1024,7 @@ cairo_status_t _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface, cairo_surface_t *target) { - return _cairo_recording_surface_replay_internal (surface, + return _cairo_recording_surface_replay_internal (surface, NULL, target, CAIRO_RECORDING_CREATE_REGIONS, CAIRO_RECORDING_REGION_ALL); @@ -995,10 +1032,11 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface, cairo_status_t _cairo_recording_surface_replay_region (cairo_surface_t *surface, + const cairo_rectangle_int_t *surface_extents, cairo_surface_t *target, cairo_recording_region_type_t region) { - return _cairo_recording_surface_replay_internal (surface, + return _cairo_recording_surface_replay_internal (surface, surface_extents, target, CAIRO_RECORDING_REPLAY, region); diff --git a/gfx/cairo/cairo/src/cairo-rectangle.c b/gfx/cairo/cairo/src/cairo-rectangle.c index 40a8bc95c4ba..b94f7d511e1e 100644 --- a/gfx/cairo/cairo/src/cairo-rectangle.c +++ b/gfx/cairo/cairo/src/cairo-rectangle.c @@ -15,7 +15,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -266,24 +266,3 @@ _cairo_box_contains_point (cairo_box_t *box, const cairo_point_t *point) return FALSE; return TRUE; } - -void -_cairo_composite_rectangles_init( - cairo_composite_rectangles_t *rects, - int all_x, - int all_y, - int width, - int height) -{ - rects->src.x = all_x; - rects->src.y = all_y; - rects->mask.x = all_x; - rects->mask.y = all_y; - rects->clip.x = all_x; - rects->clip.y = all_y; - rects->dst.x = all_x; - rects->dst.y = all_y; - - rects->width = width; - rects->height = height; -} diff --git a/gfx/cairo/cairo/src/cairo-rectangular-scan-converter.c b/gfx/cairo/cairo/src/cairo-rectangular-scan-converter.c new file mode 100644 index 000000000000..dab2c151f83a --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-rectangular-scan-converter.c @@ -0,0 +1,723 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-combsort-private.h" +#include "cairo-error-private.h" +#include "cairo-freelist-private.h" +#include "cairo-list-private.h" +#include "cairo-spans-private.h" + +#include + +typedef struct _rectangle { + struct _rectangle *next, *prev; + cairo_fixed_t left, right; + cairo_fixed_t top, bottom; + int32_t top_y, bottom_y; + int dir; +} rectangle_t; + +#define UNROLL3(x) x x x + +/* the parent is always given by index/2 */ +#define PQ_PARENT_INDEX(i) ((i) >> 1) +#define PQ_FIRST_ENTRY 1 + +/* left and right children are index * 2 and (index * 2) +1 respectively */ +#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1) + +typedef struct _pqueue { + int size, max_size; + + rectangle_t **elements; + rectangle_t *elements_embedded[1024]; +} pqueue_t; + +typedef struct { + rectangle_t **start; + pqueue_t stop; + rectangle_t head, tail; + rectangle_t *insert_cursor; + int32_t current_y; + int32_t xmin, xmax; + + struct coverage { + struct cell { + struct cell *prev, *next; + int x, covered, uncovered; + } head, tail, *cursor; + unsigned int count; + cairo_freepool_t pool; + } coverage; + + cairo_half_open_span_t spans_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_half_open_span_t)]; + cairo_half_open_span_t *spans; + unsigned int num_spans; + unsigned int size_spans; + + jmp_buf jmpbuf; +} sweep_line_t; + +static inline int +rectangle_compare_start (const rectangle_t *a, + const rectangle_t *b) +{ + int cmp; + + cmp = a->top_y - b->top_y; + if (cmp) + return cmp; + + return a->left - b->left; +} + +static inline int +rectangle_compare_stop (const rectangle_t *a, + const rectangle_t *b) +{ + return a->bottom_y - b->bottom_y; +} + +static inline void +pqueue_init (pqueue_t *pq) +{ + pq->max_size = ARRAY_LENGTH (pq->elements_embedded); + pq->size = 0; + + pq->elements = pq->elements_embedded; + pq->elements[PQ_FIRST_ENTRY] = NULL; +} + +static inline void +pqueue_fini (pqueue_t *pq) +{ + if (pq->elements != pq->elements_embedded) + free (pq->elements); +} + +static cairo_bool_t +pqueue_grow (pqueue_t *pq) +{ + rectangle_t **new_elements; + pq->max_size *= 2; + + if (pq->elements == pq->elements_embedded) { + new_elements = _cairo_malloc_ab (pq->max_size, + sizeof (rectangle_t *)); + if (unlikely (new_elements == NULL)) + return FALSE; + + memcpy (new_elements, pq->elements_embedded, + sizeof (pq->elements_embedded)); + } else { + new_elements = _cairo_realloc_ab (pq->elements, + pq->max_size, + sizeof (rectangle_t *)); + if (unlikely (new_elements == NULL)) + return FALSE; + } + + pq->elements = new_elements; + return TRUE; +} + +static inline void +pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle) +{ + rectangle_t **elements; + int i, parent; + + if (unlikely (sweep->stop.size + 1 == sweep->stop.max_size)) { + if (unlikely (! pqueue_grow (&sweep->stop))) + longjmp (sweep->jmpbuf, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + elements = sweep->stop.elements; + for (i = ++sweep->stop.size; + i != PQ_FIRST_ENTRY && + rectangle_compare_stop (rectangle, + elements[parent = PQ_PARENT_INDEX (i)]) < 0; + i = parent) + { + elements[i] = elements[parent]; + } + + elements[i] = rectangle; +} + +static inline void +pqueue_pop (pqueue_t *pq) +{ + rectangle_t **elements = pq->elements; + rectangle_t *tail; + int child, i; + + tail = elements[pq->size--]; + if (pq->size == 0) { + elements[PQ_FIRST_ENTRY] = NULL; + return; + } + + for (i = PQ_FIRST_ENTRY; + (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size; + i = child) + { + if (child != pq->size && + rectangle_compare_stop (elements[child+1], + elements[child]) < 0) + { + child++; + } + + if (rectangle_compare_stop (elements[child], tail) >= 0) + break; + + elements[i] = elements[child]; + } + elements[i] = tail; +} + +static inline rectangle_t * +peek_stop (sweep_line_t *sweep) +{ + return sweep->stop.elements[PQ_FIRST_ENTRY]; +} + +CAIRO_COMBSORT_DECLARE (rectangle_sort, rectangle_t *, rectangle_compare_start) + +static void +sweep_line_init (sweep_line_t *sweep) +{ + sweep->head.left = INT_MIN; + sweep->head.next = &sweep->tail; + sweep->tail.left = INT_MAX; + sweep->tail.prev = &sweep->head; + sweep->insert_cursor = &sweep->tail; + + _cairo_freepool_init (&sweep->coverage.pool, sizeof (struct cell)); + + sweep->spans = sweep->spans_stack; + sweep->size_spans = ARRAY_LENGTH (sweep->spans_stack); + + sweep->coverage.head.prev = NULL; + sweep->coverage.head.x = INT_MIN; + sweep->coverage.tail.next = NULL; + sweep->coverage.tail.x = INT_MAX; + + pqueue_init (&sweep->stop); +} + +static void +sweep_line_fini (sweep_line_t *sweep) +{ + _cairo_freepool_fini (&sweep->coverage.pool); + pqueue_fini (&sweep->stop); + + if (sweep->spans != sweep->spans_stack) + free (sweep->spans); +} + +static inline void +add_cell (sweep_line_t *sweep, int x, int covered, int uncovered) +{ + struct cell *cell; + + cell = sweep->coverage.cursor; + if (cell->x > x) { + do { + UNROLL3({ + if (cell->prev->x < x) + break; + cell = cell->prev; + }) + } while (TRUE); + } else { + if (cell->x == x) + goto found; + + do { + UNROLL3({ + cell = cell->next; + if (cell->x >= x) + break; + }) + } while (TRUE); + } + + if (x != cell->x) { + struct cell *c; + + sweep->coverage.count++; + + c = _cairo_freepool_alloc (&sweep->coverage.pool); + if (unlikely (c == NULL)) { + longjmp (sweep->jmpbuf, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + cell->prev->next = c; + c->prev = cell->prev; + c->next = cell; + cell->prev = c; + + c->x = x; + c->covered = 0; + c->uncovered = 0; + + cell = c; + } + +found: + cell->covered += covered; + cell->uncovered += uncovered; + sweep->coverage.cursor = cell; +} + +static inline void +_active_edges_to_spans (sweep_line_t *sweep) +{ + int32_t y = sweep->current_y; + rectangle_t *rectangle; + int coverage, prev_coverage; + int prev_x; + struct cell *cell; + + sweep->num_spans = 0; + if (sweep->head.next == &sweep->tail) + return; + + sweep->coverage.head.next = &sweep->coverage.tail; + sweep->coverage.tail.prev = &sweep->coverage.head; + sweep->coverage.cursor = &sweep->coverage.tail; + sweep->coverage.count = 0; + + /* XXX cell coverage only changes when a rectangle appears or + * disappears. Try only modifying coverage at such times. + */ + for (rectangle = sweep->head.next; + rectangle != &sweep->tail; + rectangle = rectangle->next) + { + int height; + int frac, i; + + if (y == rectangle->bottom_y) { + height = rectangle->bottom & CAIRO_FIXED_FRAC_MASK; + if (height == 0) + continue; + } else + height = CAIRO_FIXED_ONE; + if (y == rectangle->top_y) + height -= rectangle->top & CAIRO_FIXED_FRAC_MASK; + height *= rectangle->dir; + + i = _cairo_fixed_integer_part (rectangle->left), + frac = _cairo_fixed_fractional_part (rectangle->left); + add_cell (sweep, i, + (CAIRO_FIXED_ONE-frac) * height, + frac * height); + + i = _cairo_fixed_integer_part (rectangle->right), + frac = _cairo_fixed_fractional_part (rectangle->right); + add_cell (sweep, i, + -(CAIRO_FIXED_ONE-frac) * height, + -frac * height); + } + + if (2*sweep->coverage.count >= sweep->size_spans) { + unsigned size; + + size = sweep->size_spans; + while (size <= 2*sweep->coverage.count) + size <<= 1; + + if (sweep->spans != sweep->spans_stack) + free (sweep->spans); + + sweep->spans = _cairo_malloc_ab (size, sizeof (cairo_half_open_span_t)); + if (unlikely (sweep->spans == NULL)) + longjmp (sweep->jmpbuf, _cairo_error (CAIRO_STATUS_NO_MEMORY)); + + sweep->size_spans = size; + } + + prev_coverage = coverage = 0; + prev_x = INT_MIN; + for (cell = sweep->coverage.head.next; cell != &sweep->coverage.tail; cell = cell->next) { + if (cell->x != prev_x && coverage != prev_coverage) { + int n = sweep->num_spans++; + sweep->spans[n].x = prev_x; + sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8); + sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8; + prev_coverage = coverage; + } + + coverage += cell->covered; + if (coverage != prev_coverage) { + int n = sweep->num_spans++; + sweep->spans[n].x = cell->x; + sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8); + sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8; + prev_coverage = coverage; + } + coverage += cell->uncovered; + prev_x = cell->x + 1; + } + _cairo_freepool_reset (&sweep->coverage.pool); + + if (sweep->num_spans) { + if (prev_x <= sweep->xmax) { + int n = sweep->num_spans++; + sweep->spans[n].x = prev_x; + sweep->spans[n].coverage = coverage; + } + + if (coverage && prev_x < sweep->xmax) { + int n = sweep->num_spans++; + sweep->spans[n].x = sweep->xmax; + sweep->spans[n].coverage = 0; + } + } +} + +static inline void +sweep_line_delete (sweep_line_t *sweep, + rectangle_t *rectangle) +{ + if (sweep->insert_cursor == rectangle) + sweep->insert_cursor = rectangle->next; + + rectangle->prev->next = rectangle->next; + rectangle->next->prev = rectangle->prev; + + pqueue_pop (&sweep->stop); +} + +static inline void +sweep_line_insert (sweep_line_t *sweep, + rectangle_t *rectangle) +{ + rectangle_t *pos; + + pos = sweep->insert_cursor; + if (pos->left != rectangle->left) { + if (pos->left > rectangle->left) { + do { + UNROLL3({ + if (pos->prev->left < rectangle->left) + break; + pos = pos->prev; + }) + } while (TRUE); + } else { + do { + UNROLL3({ + pos = pos->next; + if (pos->left >= rectangle->left) + break; + }); + } while (TRUE); + } + } + + pos->prev->next = rectangle; + rectangle->prev = pos->prev; + rectangle->next = pos; + pos->prev = rectangle; + sweep->insert_cursor = rectangle; + + pqueue_push (sweep, rectangle); +} + +static void +render_rows (sweep_line_t *sweep_line, + cairo_span_renderer_t *renderer, + int height) +{ + cairo_status_t status; + + _active_edges_to_spans (sweep_line); + + status = renderer->render_rows (renderer, + sweep_line->current_y, height, + sweep_line->spans, + sweep_line->num_spans); + if (unlikely (status)) + longjmp (sweep_line->jmpbuf, status); +} + +static cairo_status_t +generate (cairo_rectangular_scan_converter_t *self, + cairo_span_renderer_t *renderer, + rectangle_t **rectangles) +{ + sweep_line_t sweep_line; + rectangle_t *start, *stop; + cairo_status_t status; + + sweep_line_init (&sweep_line); + sweep_line.xmin = self->xmin; + sweep_line.xmax = self->xmax; + sweep_line.start = rectangles; + if ((status = setjmp (sweep_line.jmpbuf))) + goto BAIL; + + sweep_line.current_y = self->ymin; + start = *sweep_line.start++; + do { + if (start->top_y != sweep_line.current_y) { + render_rows (&sweep_line, renderer, + start->top_y - sweep_line.current_y); + sweep_line.current_y = start->top_y; + } + + do { + sweep_line_insert (&sweep_line, start); + start = *sweep_line.start++; + if (start == NULL) + goto end; + if (start->top_y != sweep_line.current_y) + break; + } while (TRUE); + + render_rows (&sweep_line, renderer, 1); + + stop = peek_stop (&sweep_line); + while (stop->bottom_y == sweep_line.current_y) { + sweep_line_delete (&sweep_line, stop); + stop = peek_stop (&sweep_line); + if (stop == NULL) + break; + } + + sweep_line.current_y++; + + while (stop != NULL && stop->bottom_y < start->top_y) { + if (stop->bottom_y != sweep_line.current_y) { + render_rows (&sweep_line, renderer, + stop->bottom_y - sweep_line.current_y); + sweep_line.current_y = stop->bottom_y; + } + + render_rows (&sweep_line, renderer, 1); + + do { + sweep_line_delete (&sweep_line, stop); + stop = peek_stop (&sweep_line); + } while (stop != NULL && stop->bottom_y == sweep_line.current_y); + + sweep_line.current_y++; + } + } while (TRUE); + + end: + render_rows (&sweep_line, renderer, 1); + + stop = peek_stop (&sweep_line); + while (stop->bottom_y == sweep_line.current_y) { + sweep_line_delete (&sweep_line, stop); + stop = peek_stop (&sweep_line); + if (stop == NULL) + goto out; + } + + sweep_line.current_y++; + + do { + if (stop->bottom_y != sweep_line.current_y) { + render_rows (&sweep_line, renderer, + stop->bottom_y - sweep_line.current_y); + sweep_line.current_y = stop->bottom_y; + } + + render_rows (&sweep_line, renderer, 1); + + do { + sweep_line_delete (&sweep_line, stop); + stop = peek_stop (&sweep_line); + if (stop == NULL) + goto out; + } while (stop->bottom_y == sweep_line.current_y); + + sweep_line.current_y++; + } while (TRUE); + + out: + status = renderer->render_rows (renderer, + sweep_line.current_y, + self->ymax - sweep_line.current_y, + NULL, 0); + + BAIL: + sweep_line_fini (&sweep_line); + + return status; +} + +static cairo_status_t +_cairo_rectangular_scan_converter_generate (void *converter, + cairo_span_renderer_t *renderer) +{ + cairo_rectangular_scan_converter_t *self = converter; + rectangle_t *rectangles_stack[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *)]; + rectangle_t **rectangles; + struct _cairo_rectangular_scan_converter_chunk *chunk; + cairo_status_t status; + int i, j; + + if (unlikely (self->num_rectangles == 0)) { + return renderer->render_rows (renderer, + self->ymin, self->ymax - self->ymin, + NULL, 0); + } + + rectangles = rectangles_stack; + if (unlikely (self->num_rectangles >= ARRAY_LENGTH (rectangles_stack))) { + rectangles = _cairo_malloc_ab (self->num_rectangles + 1, + sizeof (rectangle_t *)); + if (unlikely (rectangles == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + j = 0; + for (chunk = &self->chunks; chunk != NULL; chunk = chunk->next) { + rectangle_t *rectangle; + + rectangle = chunk->base; + for (i = 0; i < chunk->count; i++) + rectangles[j++] = &rectangle[i]; + } + rectangle_sort (rectangles, j); + rectangles[j] = NULL; + + status = generate (self, renderer, rectangles); + + if (rectangles != rectangles_stack) + free (rectangles); + + return status; +} + +static rectangle_t * +_allocate_rectangle (cairo_rectangular_scan_converter_t *self) +{ + rectangle_t *rectangle; + struct _cairo_rectangular_scan_converter_chunk *chunk; + + chunk = self->tail; + if (chunk->count == chunk->size) { + int size; + + size = chunk->size * 2; + chunk->next = _cairo_malloc_ab_plus_c (size, + sizeof (rectangle_t), + sizeof (struct _cairo_rectangular_scan_converter_chunk)); + + if (unlikely (chunk->next == NULL)) + return NULL; + + chunk = chunk->next; + chunk->next = NULL; + chunk->count = 0; + chunk->size = size; + chunk->base = chunk + 1; + self->tail = chunk; + } + + rectangle = chunk->base; + return rectangle + chunk->count++; +} + +cairo_status_t +_cairo_rectangular_scan_converter_add_box (cairo_rectangular_scan_converter_t *self, + const cairo_box_t *box, + int dir) +{ + rectangle_t *rectangle; + + rectangle = _allocate_rectangle (self); + if (unlikely (rectangle == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + rectangle->left = box->p1.x; + rectangle->right = box->p2.x; + rectangle->dir = dir; + + rectangle->top = box->p1.y; + rectangle->top_y = _cairo_fixed_integer_floor (box->p1.y); + rectangle->bottom = box->p2.y; + rectangle->bottom_y = _cairo_fixed_integer_floor (box->p2.y); + assert (rectangle->bottom_y >= rectangle->top_y); + + self->num_rectangles++; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_rectangular_scan_converter_destroy (void *converter) +{ + cairo_rectangular_scan_converter_t *self = converter; + struct _cairo_rectangular_scan_converter_chunk *chunk, *next; + + for (chunk = self->chunks.next; chunk != NULL; chunk = next) { + next = chunk->next; + free (chunk); + } +} + +void +_cairo_rectangular_scan_converter_init (cairo_rectangular_scan_converter_t *self, + const cairo_rectangle_int_t *extents) +{ + self->base.destroy = _cairo_rectangular_scan_converter_destroy; + self->base.add_edge = NULL; + self->base.add_polygon = NULL; + self->base.generate = _cairo_rectangular_scan_converter_generate; + + self->xmin = extents->x; + self->xmax = extents->x + extents->width; + self->ymin = extents->y; + self->ymax = extents->y + extents->height; + + self->chunks.base = self->buf; + self->chunks.next = NULL; + self->chunks.count = 0; + self->chunks.size = sizeof (self->buf) / sizeof (rectangle_t); + self->tail = &self->chunks; + + self->num_rectangles = 0; +} diff --git a/gfx/cairo/cairo/src/cairo-reference-count-private.h b/gfx/cairo/cairo/src/cairo-reference-count-private.h index d6adaad9683f..0cb5695dd063 100644 --- a/gfx/cairo/cairo/src/cairo-reference-count-private.h +++ b/gfx/cairo/cairo/src/cairo-reference-count-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -50,7 +50,6 @@ typedef struct { #define CAIRO_REFERENCE_COUNT_INIT(RC, VALUE) ((RC)->ref_count = (VALUE)) #define CAIRO_REFERENCE_COUNT_GET_VALUE(RC) _cairo_atomic_int_get (&(RC)->ref_count) -#define CAIRO_REFERENCE_COUNT_SET_VALUE(RC, VALUE) _cairo_atomic_int_set (&(RC)->ref_count, (VALUE)) #define CAIRO_REFERENCE_COUNT_INVALID_VALUE ((cairo_atomic_int_t) -1) #define CAIRO_REFERENCE_COUNT_INVALID {CAIRO_REFERENCE_COUNT_INVALID_VALUE} diff --git a/gfx/cairo/cairo/src/cairo-region-private.h b/gfx/cairo/cairo/src/cairo-region-private.h index 507f72e842f0..11070ba768e4 100644 --- a/gfx/cairo/cairo/src/cairo-region-private.h +++ b/gfx/cairo/cairo/src/cairo-region-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -53,6 +53,9 @@ struct _cairo_region { pixman_region32_t rgn; }; +cairo_private cairo_region_t * +_cairo_region_create_in_error (cairo_status_t status); + cairo_private void _cairo_region_init (cairo_region_t *region); diff --git a/gfx/cairo/cairo/src/cairo-region.c b/gfx/cairo/cairo/src/cairo-region.c index 2148fcabbc25..112b1d82423a 100644 --- a/gfx/cairo/cairo/src/cairo-region.c +++ b/gfx/cairo/cairo/src/cairo-region.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,16 +38,78 @@ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-region-private.h" /* XXX need to update pixman headers to be const as appropriate */ #define CONST_CAST (pixman_region32_t *) +/** + * SECTION:cairo-region + * @Title: Regions + * @Short_Description: Representing a pixel-aligned area + * + * Regions are a simple graphical data type representing an area of + * integer-aligned rectangles. They are often used on raster surfaces + * to track areas of interest, such as change or clip areas. + */ + static const cairo_region_t _cairo_region_nil = { CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ CAIRO_STATUS_NO_MEMORY, /* status */ }; +cairo_region_t * +_cairo_region_create_in_error (cairo_status_t status) +{ + switch (status) { + case CAIRO_STATUS_NO_MEMORY: + return (cairo_region_t *) &_cairo_region_nil; + + case CAIRO_STATUS_SUCCESS: + case CAIRO_STATUS_LAST_STATUS: + ASSERT_NOT_REACHED; + /* fall-through */ + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: + case CAIRO_STATUS_INVALID_STATUS: + case CAIRO_STATUS_INVALID_CONTENT: + case CAIRO_STATUS_INVALID_FORMAT: + case CAIRO_STATUS_INVALID_VISUAL: + case CAIRO_STATUS_READ_ERROR: + case CAIRO_STATUS_WRITE_ERROR: + case CAIRO_STATUS_FILE_NOT_FOUND: + case CAIRO_STATUS_TEMP_FILE_ERROR: + case CAIRO_STATUS_INVALID_STRIDE: + case CAIRO_STATUS_INVALID_SIZE: + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: + case CAIRO_STATUS_DEVICE_ERROR: + case CAIRO_STATUS_INVALID_RESTORE: + case CAIRO_STATUS_INVALID_POP_GROUP: + case CAIRO_STATUS_NO_CURRENT_POINT: + case CAIRO_STATUS_INVALID_MATRIX: + case CAIRO_STATUS_NULL_POINTER: + case CAIRO_STATUS_INVALID_STRING: + case CAIRO_STATUS_INVALID_PATH_DATA: + case CAIRO_STATUS_SURFACE_FINISHED: + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: + case CAIRO_STATUS_INVALID_DASH: + case CAIRO_STATUS_INVALID_DSC_COMMENT: + case CAIRO_STATUS_INVALID_INDEX: + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: + case CAIRO_STATUS_FONT_TYPE_MISMATCH: + case CAIRO_STATUS_USER_FONT_IMMUTABLE: + case CAIRO_STATUS_USER_FONT_ERROR: + case CAIRO_STATUS_NEGATIVE_COUNT: + case CAIRO_STATUS_INVALID_CLUSTERS: + case CAIRO_STATUS_INVALID_SLANT: + case CAIRO_STATUS_INVALID_WEIGHT: + case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: + default: + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_region_t *) &_cairo_region_nil; + } +} + /** * _cairo_region_set_error: * @region: a region @@ -144,6 +206,21 @@ cairo_region_create (void) } slim_hidden_def (cairo_region_create); +/** + * cairo_region_create_rectangles: + * @rects: an array of @count rectangles + * @count: number of rectangles + * + * Allocates a new region object containing the union of all given @rects. + * + * Return value: A newly allocated #cairo_region_t. Free with + * cairo_region_destroy(). This function always returns a + * valid pointer; if memory cannot be allocated, then a special + * error object is returned where all operations on the object do nothing. + * You can check for this with cairo_region_status(). + * + * Since: 1.10 + **/ cairo_region_t * cairo_region_create_rectangles (const cairo_rectangle_int_t *rects, int count) @@ -154,17 +231,14 @@ cairo_region_create_rectangles (const cairo_rectangle_int_t *rects, int i; region = _cairo_malloc (sizeof (cairo_region_t)); - if (unlikely (region == NULL)) { - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - return (cairo_region_t *) &_cairo_region_nil; - } + if (unlikely (region == NULL)) + return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); if (count > ARRAY_LENGTH (stack_pboxes)) { pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t)); if (unlikely (pboxes == NULL)) { free (region); - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - return (cairo_region_t *) &_cairo_region_nil; + return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } } @@ -182,8 +256,7 @@ cairo_region_create_rectangles (const cairo_rectangle_int_t *rects, if (unlikely (i == 0)) { free (region); - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - return (cairo_region_t *) &_cairo_region_nil; + return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1); @@ -369,7 +442,7 @@ slim_hidden_def (cairo_region_get_rectangle); /** * cairo_region_get_extents: * @region: a #cairo_region_t - * @rectangle: rectangle into which to store the extents + * @extents: rectangle into which to store the extents * * Gets the bounding rectangle of @region as a #cairo_rectangle_int_t * @@ -491,7 +564,7 @@ slim_hidden_def (cairo_region_subtract_rectangle); * Since: 1.10 **/ cairo_status_t -cairo_region_intersect (cairo_region_t *dst, cairo_region_t *other) +cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other) { if (dst->status) return dst->status; @@ -499,7 +572,7 @@ cairo_region_intersect (cairo_region_t *dst, cairo_region_t *other) if (other->status) return _cairo_region_set_error (dst, other->status); - if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, &other->rgn)) + if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn)) return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_SUCCESS; @@ -554,7 +627,7 @@ slim_hidden_def (cairo_region_intersect_rectangle); **/ cairo_status_t cairo_region_union (cairo_region_t *dst, - cairo_region_t *other) + const cairo_region_t *other) { if (dst->status) return dst->status; @@ -562,7 +635,7 @@ cairo_region_union (cairo_region_t *dst, if (other->status) return _cairo_region_set_error (dst, other->status); - if (! pixman_region32_union (&dst->rgn, &dst->rgn, &other->rgn)) + if (! pixman_region32_union (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn)) return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_SUCCESS; @@ -603,6 +676,86 @@ cairo_region_union_rectangle (cairo_region_t *dst, } slim_hidden_def (cairo_region_union_rectangle); +/** + * cairo_region_xor: + * @dst: a #cairo_region_t + * @other: another #cairo_region_t + * + * Computes the exclusive difference of @dst with @other and places the + * result in @dst. That is, @dst will be set to contain all areas that + * are either in @dst or in @other, but not in both. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * + * Since: 1.10 + **/ +cairo_status_t +cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + pixman_region32_t tmp; + + if (dst->status) + return dst->status; + + if (other->status) + return _cairo_region_set_error (dst, other->status); + + pixman_region32_init (&tmp); + + /* XXX: get an xor function into pixman */ + if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) || + ! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) || + ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp)) + status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); + + pixman_region32_fini (&tmp); + + return status; +} +slim_hidden_def (cairo_region_xor); + +/** + * cairo_region_xor_rectangle: + * @dst: a #cairo_region_t + * @rectangle: a #cairo_rectangle_int_t + * + * Computes the exclusive difference of @dst with @rectangle and places the + * result in @dst. That is, @dst will be set to contain all areas that are + * either in @dst or in @rectangle, but not in both. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * + * Since: 1.10 + **/ +cairo_status_t +cairo_region_xor_rectangle (cairo_region_t *dst, + const cairo_rectangle_int_t *rectangle) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + pixman_region32_t region, tmp; + + if (dst->status) + return dst->status; + + pixman_region32_init_rect (®ion, + rectangle->x, rectangle->y, + rectangle->width, rectangle->height); + pixman_region32_init (&tmp); + + /* XXX: get an xor function into pixman */ + if (! pixman_region32_subtract (&tmp, ®ion, &dst->rgn) || + ! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion) || + ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp)) + status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); + + pixman_region32_fini (&tmp); + pixman_region32_fini (®ion); + + return status; +} +slim_hidden_def (cairo_region_xor_rectangle); + /** * cairo_region_is_empty: * @region: a #cairo_region_t @@ -644,6 +797,16 @@ cairo_region_translate (cairo_region_t *region, } slim_hidden_def (cairo_region_translate); +/** + * cairo_region_overlap_t: + * @CAIRO_REGION_OVERLAP_IN: The contents are entirely inside the region + * @CAIRO_REGION_OVERLAP_OUT: The contents are entirely outside the region + * @CAIRO_REGION_OVERLAP_PART: The contents are partially inside and + * partially outside the region. + * + * Used as the return value for cairo_region_contains_rectangle(). + */ + /** * cairo_region_contains_rectangle: * @region: a #cairo_region_t @@ -712,13 +875,14 @@ slim_hidden_def (cairo_region_contains_point); /** * cairo_region_equal: - * @region_a: a #cairo_region_t - * @region_b: a #cairo_region_t + * @a: a #cairo_region_t or %NULL + * @b: a #cairo_region_t or %NULL * - * Compares whether region_a is equivalent to region_b. + * Compares whether region_a is equivalent to region_b. %NULL as an argument + * is equal to itself, but not to any non-%NULL region. * * Return value: %TRUE if both regions contained the same coverage, - * %FALSE if it is not. + * %FALSE if it is not or any region is in an error status. * * Since: 1.10 **/ diff --git a/gfx/cairo/cairo/src/cairo-rtree-private.h b/gfx/cairo/cairo/src/cairo-rtree-private.h index edb7e3acb820..191c858713ec 100644 --- a/gfx/cairo/cairo/src/cairo-rtree-private.h +++ b/gfx/cairo/cairo/src/cairo-rtree-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -62,7 +62,6 @@ typedef struct _cairo_rtree_node { typedef struct _cairo_rtree { cairo_rtree_node_t root; int min_size; - void (*evict) (void *node); cairo_list_t pinned; cairo_list_t available; cairo_list_t evictable; @@ -98,8 +97,7 @@ _cairo_rtree_init (cairo_rtree_t *rtree, int width, int height, int min_size, - int node_size, - void (*evict) (void *node)); + int node_size); cairo_private cairo_int_status_t _cairo_rtree_insert (cairo_rtree_t *rtree, @@ -113,8 +111,16 @@ _cairo_rtree_evict_random (cairo_rtree_t *rtree, int height, cairo_rtree_node_t **out); -cairo_private void * -_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node); +static inline void * +_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node) +{ + if (! node->pinned) { + cairo_list_move (&node->link, &rtree->pinned); + node->pinned = 1; + } + + return node; +} cairo_private void _cairo_rtree_unpin (cairo_rtree_t *rtree); diff --git a/gfx/cairo/cairo/src/cairo-rtree.c b/gfx/cairo/cairo/src/cairo-rtree.c index d4bdbd4bdaa0..d6e57916ae6f 100644 --- a/gfx/cairo/cairo/src/cairo-rtree.c +++ b/gfx/cairo/cairo/src/cairo-rtree.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -36,6 +36,7 @@ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-rtree-private.h" cairo_rtree_node_t * @@ -79,8 +80,6 @@ _cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node) if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { if (node->owner != NULL) *node->owner = NULL; - if (rtree->evict != NULL) - rtree->evict (node); } else { for (i = 0; i < 4 && node->children[i] != NULL; i++) _cairo_rtree_node_destroy (rtree, node->children[i]); @@ -94,8 +93,6 @@ _cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node) { int i; - assert (node->pinned == FALSE); - do { assert (node->state == CAIRO_RTREE_NODE_DIVIDED); @@ -109,9 +106,7 @@ _cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node) node->children[0] = NULL; node->state = CAIRO_RTREE_NODE_AVAILABLE; cairo_list_move (&node->link, &rtree->available); - - node = node->parent; - } while (node != NULL && ! node->pinned); + } while ((node = node->parent) != NULL); } cairo_status_t @@ -194,8 +189,7 @@ _cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node) node->state = CAIRO_RTREE_NODE_AVAILABLE; cairo_list_move (&node->link, &rtree->available); - if (! node->parent->pinned) - _cairo_rtree_node_collapse (rtree, node->parent); + _cairo_rtree_node_collapse (rtree, node->parent); } cairo_int_status_t @@ -231,9 +225,17 @@ _cairo_rtree_evict_random (cairo_rtree_t *rtree, int height, cairo_rtree_node_t **out) { - cairo_rtree_node_t *node; + cairo_rtree_node_t *node, *next; int i, cnt; + /* propagate pinned from children to root */ + cairo_list_foreach_entry_safe (node, next, cairo_rtree_node_t, + &rtree->pinned, link) + { + if (node->parent != NULL) + _cairo_rtree_pin (rtree, node->parent); + } + cnt = 0; cairo_list_foreach_entry (node, cairo_rtree_node_t, &rtree->evictable, link) @@ -253,8 +255,6 @@ _cairo_rtree_evict_random (cairo_rtree_t *rtree, if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { if (node->owner != NULL) *node->owner = NULL; - if (rtree->evict != NULL) - rtree->evict (node); } else { for (i = 0; i < 4 && node->children[i] != NULL; i++) _cairo_rtree_node_destroy (rtree, node->children[i]); @@ -272,22 +272,6 @@ _cairo_rtree_evict_random (cairo_rtree_t *rtree, return CAIRO_INT_STATUS_UNSUPPORTED; } -void * -_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node) -{ - void *ptr = node; - - while (node->pinned == FALSE) { - cairo_list_move (&node->link, &rtree->pinned); - node->pinned = TRUE; - node = node->parent; - if (node == NULL) - break; - } - - return ptr; -} - void _cairo_rtree_unpin (cairo_rtree_t *rtree) { @@ -343,11 +327,8 @@ _cairo_rtree_init (cairo_rtree_t *rtree, int width, int height, int min_size, - int node_size, - void (*evict) (void *node)) + int node_size) { - rtree->evict = evict; - assert (node_size >= (int) sizeof (cairo_rtree_node_t)); _cairo_freepool_init (&rtree->node_freepool, node_size); @@ -372,8 +353,6 @@ _cairo_rtree_reset (cairo_rtree_t *rtree) if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { if (rtree->root.owner != NULL) *rtree->root.owner = NULL; - if (rtree->evict != NULL) - rtree->evict (&rtree->root); } else { for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) _cairo_rtree_node_destroy (rtree, rtree->root.children[i]); @@ -397,8 +376,6 @@ _cairo_rtree_fini (cairo_rtree_t *rtree) if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { if (rtree->root.owner != NULL) *rtree->root.owner = NULL; - if (rtree->evict != NULL) - rtree->evict (&rtree->root); } else { for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) _cairo_rtree_node_destroy (rtree, rtree->root.children[i]); diff --git a/gfx/cairo/cairo/src/cairo-scaled-font-private.h b/gfx/cairo/cairo/src/cairo-scaled-font-private.h index cdc3c73d2271..029377b17880 100644 --- a/gfx/cairo/cairo/src/cairo-scaled-font-private.h +++ b/gfx/cairo/cairo/src/cairo-scaled-font-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -41,6 +41,7 @@ #include "cairo.h" #include "cairo-types-private.h" +#include "cairo-list-private.h" #include "cairo-mutex-type-private.h" #include "cairo-reference-count-private.h" @@ -107,7 +108,7 @@ struct _cairo_scaled_font { cairo_mutex_t mutex; cairo_hash_table_t *glyphs; - cairo_scaled_glyph_page_t *glyph_pages; + cairo_list_t glyph_pages; cairo_bool_t cache_frozen; cairo_bool_t global_cache_frozen; @@ -121,6 +122,7 @@ struct _cairo_scaled_font { /* font backend managing this scaled font */ const cairo_scaled_font_backend_t *backend; + cairo_list_t link; }; cairo_private void diff --git a/gfx/cairo/cairo/src/cairo-scaled-font-subsets-private.h b/gfx/cairo/cairo/src/cairo-scaled-font-subsets-private.h index 6eb6ce0f0833..b165d9acabe1 100644 --- a/gfx/cairo/cairo/src/cairo-scaled-font-subsets-private.h +++ b/gfx/cairo/cairo/src/cairo-scaled-font-subsets-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -334,9 +334,9 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset typedef struct _cairo_cff_subset { char *font_name; char *ps_name; - int *widths; - long x_min, y_min, x_max, y_max; - long ascent, descent; + double *widths; + double x_min, y_min, x_max, y_max; + double ascent, descent; char *data; unsigned long data_length; } cairo_cff_subset_t; @@ -451,9 +451,9 @@ _cairo_truetype_subset_fini (cairo_truetype_subset_t *truetype_subset); typedef struct _cairo_type1_subset { char *base_font; - int *widths; - long x_min, y_min, x_max, y_max; - long ascent, descent; + double *widths; + double x_min, y_min, x_max, y_max; + double ascent, descent; char *data; unsigned long header_length; unsigned long data_length; diff --git a/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c b/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c index 054782950040..01bc05bfbcb3 100644 --- a/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c +++ b/gfx/cairo/cairo/src/cairo-scaled-font-subsets.c @@ -15,7 +15,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -42,6 +42,7 @@ #define _BSD_SOURCE /* for snprintf(), strdup() */ #include "cairoint.h" +#include "cairo-error-private.h" #if CAIRO_HAS_FONT_SUBSET @@ -400,7 +401,7 @@ _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph, /* No existing mapping. Use the requested mapping */ sub_font_glyph->utf8 = malloc (utf8_len + 1); if (unlikely (sub_font_glyph->utf8 == NULL)) - return CAIRO_STATUS_NO_MEMORY; + return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (sub_font_glyph->utf8, utf8, utf8_len); sub_font_glyph->utf8[utf8_len] = 0; diff --git a/gfx/cairo/cairo/src/cairo-scaled-font.c b/gfx/cairo/cairo/src/cairo-scaled-font.c index e1a89f8b0bac..edac25294a01 100644 --- a/gfx/cairo/cairo/src/cairo-scaled-font.c +++ b/gfx/cairo/cairo/src/cairo-scaled-font.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,9 +38,8 @@ * Chris Wilson */ -#define _GNU_SOURCE - #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-scaled-font-private.h" #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE) @@ -49,6 +48,16 @@ #define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */ #endif +/** + * SECTION:cairo-scaled-font + * @Title: cairo_scaled_font_t + * @Short_Description: Font face at particular size and options + * @See_Also: #cairo_font_face_t, #cairo_matrix_t, #cairo_font_options_t + * + * #cairo_scaled_font_t represents a realization of a font face at a particular + * size and transformation and a certain set of font options. + */ + /* Global Glyph Cache * * We maintain a global pool of glyphs split between all active fonts. This @@ -70,7 +79,7 @@ static cairo_cache_t cairo_scaled_glyph_page_cache; struct _cairo_scaled_glyph_page { cairo_cache_entry_t cache_entry; - struct _cairo_scaled_glyph_page *prev, *next; + cairo_list_t link; unsigned int num_glyphs; cairo_scaled_glyph_t glyphs[CAIRO_SCALED_GLYPH_PAGE_SIZE]; @@ -199,8 +208,10 @@ _cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font, if (scaled_glyph->path != NULL) _cairo_path_fixed_destroy (scaled_glyph->path); - if (scaled_glyph->recording_surface != NULL) + if (scaled_glyph->recording_surface != NULL) { + cairo_surface_finish (scaled_glyph->recording_surface); cairo_surface_destroy (scaled_glyph->recording_surface); + } } #define ZOMBIE 0 @@ -227,7 +238,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = { { 0., 0., 0., 0., 0. }, /* fs_extents */ CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */ NULL, /* glyphs */ - NULL, /* pages */ + { NULL, NULL }, /* pages */ FALSE, /* cache_frozen */ FALSE, /* global_cache_frozen */ NULL, /* surface_backend */ @@ -439,13 +450,7 @@ _cairo_scaled_glyph_page_destroy (void *closure) _cairo_scaled_glyph_fini (scaled_font, &page->glyphs[n]); } - if (page->prev != NULL) - page->prev->next = page->next; - else - scaled_font->glyph_pages = page->next; - - if (page->next != NULL) - page->next->prev = page->prev; + cairo_list_del (&page->link); free (page); } @@ -709,13 +714,12 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, * * Also, the check for == 0. below may be too harsh... */ - if (scaled_font->scale.xx == 0. && scaled_font->scale.xy == 0. && - scaled_font->scale.yx == 0. && scaled_font->scale.yy == 0.) + if (_cairo_matrix_is_scale_0 (&scaled_font->scale)) { cairo_matrix_init (&scaled_font->scale_inverse, 0, 0, 0, 0, -scaled_font->scale.x0, -scaled_font->scale.y0); - else + } else return status; } @@ -723,7 +727,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, if (unlikely (scaled_font->glyphs == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - scaled_font->glyph_pages = NULL; + cairo_list_init (&scaled_font->glyph_pages); scaled_font->cache_frozen = FALSE; scaled_font->global_cache_frozen = FALSE; @@ -743,6 +747,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, scaled_font->surface_private = NULL; scaled_font->backend = backend; + cairo_list_init (&scaled_font->link); return CAIRO_STATUS_SUCCESS; } @@ -779,9 +784,11 @@ _cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font) assert (! scaled_font->cache_frozen); CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex); - while (scaled_font->glyph_pages != NULL) { + while (! cairo_list_is_empty (&scaled_font->glyph_pages)) { _cairo_cache_remove (&cairo_scaled_glyph_page_cache, - &scaled_font->glyph_pages->cache_entry); + &cairo_list_first_entry (&scaled_font->glyph_pages, + cairo_scaled_glyph_page_t, + link)->cache_entry); } CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); } @@ -893,7 +900,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, cairo_status_t status; cairo_scaled_font_map_t *font_map; cairo_font_face_t *original_font_face = font_face; - cairo_scaled_font_t key, *old = NULL, *scaled_font = NULL; + cairo_scaled_font_t key, *old = NULL, *scaled_font = NULL, *dead = NULL; double det; status = font_face->status; @@ -924,6 +931,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, _cairo_scaled_font_matches (scaled_font, font_face, font_matrix, ctm, options)) { + assert (scaled_font->hash_entry.hash != ZOMBIE); assert (! scaled_font->placeholder); if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) { @@ -940,12 +948,19 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, _cairo_hash_table_remove (font_map->hash_table, &scaled_font->hash_entry); scaled_font->hash_entry.hash = ZOMBIE; + dead = scaled_font; + font_map->mru_scaled_font = NULL; if (font_face->backend->get_implementation != NULL) { font_face = font_face->backend->get_implementation (font_face, font_matrix, ctm, options); + if (unlikely (font_face->status)) { + _cairo_scaled_font_map_unlock (); + cairo_scaled_font_destroy (scaled_font); + return _cairo_scaled_font_create_in_error (font_face->status); + } } _cairo_scaled_font_init_key (&key, font_face, @@ -958,6 +973,10 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, font_matrix, ctm, options); + if (unlikely (font_face->status)) { + _cairo_scaled_font_map_unlock (); + return _cairo_scaled_font_create_in_error (font_face->status); + } } _cairo_scaled_font_init_key (&key, font_face, @@ -1039,6 +1058,9 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, if (font_face != original_font_face) cairo_font_face_destroy (font_face); + if (dead != NULL) + cairo_scaled_font_destroy (dead); + status = _cairo_font_face_set_error (font_face, status); return _cairo_scaled_font_create_in_error (status); } @@ -1048,6 +1070,9 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, if (font_face != original_font_face) cairo_font_face_destroy (font_face); + if (dead != NULL) + cairo_scaled_font_destroy (dead); + return scaled_font; } @@ -1074,6 +1099,9 @@ cairo_scaled_font_create (cairo_font_face_t *font_face, if (font_face != original_font_face) cairo_font_face_destroy (font_face); + if (dead != NULL) + cairo_scaled_font_destroy (dead); + if (unlikely (status)) { /* We can't call _cairo_scaled_font_destroy here since it expects * that the font has already been successfully inserted into the @@ -1551,6 +1579,134 @@ ZERO_EXTENTS: } slim_hidden_def (cairo_scaled_font_glyph_extents); +#define GLYPH_LUT_SIZE 64 +static cairo_status_t +cairo_scaled_font_text_to_glyphs_internal_cached (cairo_scaled_font_t *scaled_font, + double x, + double y, + const char *utf8, + cairo_glyph_t *glyphs, + cairo_text_cluster_t **clusters, + int num_chars) +{ + struct glyph_lut_elt { + unsigned long index; + double x_advance; + double y_advance; + } glyph_lut[GLYPH_LUT_SIZE]; + uint32_t glyph_lut_unicode[GLYPH_LUT_SIZE]; + cairo_status_t status; + const char *p; + int i; + + for (i = 0; i < GLYPH_LUT_SIZE; i++) + glyph_lut_unicode[i] = ~0U; + + p = utf8; + for (i = 0; i < num_chars; i++) { + int idx, num_bytes; + uint32_t unicode; + cairo_scaled_glyph_t *scaled_glyph; + struct glyph_lut_elt *glyph_slot; + + num_bytes = _cairo_utf8_get_char_validated (p, &unicode); + p += num_bytes; + + glyphs[i].x = x; + glyphs[i].y = y; + + idx = unicode % ARRAY_LENGTH (glyph_lut); + glyph_slot = &glyph_lut[idx]; + if (glyph_lut_unicode[idx] == unicode) { + glyphs[i].index = glyph_slot->index; + x += glyph_slot->x_advance; + y += glyph_slot->y_advance; + } else { + unsigned long g; + + g = scaled_font->backend->ucs4_to_index (scaled_font, unicode); + status = _cairo_scaled_glyph_lookup (scaled_font, + g, + CAIRO_SCALED_GLYPH_INFO_METRICS, + &scaled_glyph); + if (unlikely (status)) + return status; + + x += scaled_glyph->metrics.x_advance; + y += scaled_glyph->metrics.y_advance; + + glyph_lut_unicode[idx] = unicode; + glyph_slot->index = g; + glyph_slot->x_advance = scaled_glyph->metrics.x_advance; + glyph_slot->y_advance = scaled_glyph->metrics.y_advance; + + glyphs[i].index = g; + } + + if (clusters) { + (*clusters)[i].num_bytes = num_bytes; + (*clusters)[i].num_glyphs = 1; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_scaled_font_text_to_glyphs_internal_uncached (cairo_scaled_font_t *scaled_font, + double x, + double y, + const char *utf8, + cairo_glyph_t *glyphs, + cairo_text_cluster_t **clusters, + int num_chars) +{ + const char *p; + int i; + + p = utf8; + for (i = 0; i < num_chars; i++) { + unsigned long g; + int num_bytes; + uint32_t unicode; + cairo_scaled_glyph_t *scaled_glyph; + cairo_status_t status; + + num_bytes = _cairo_utf8_get_char_validated (p, &unicode); + p += num_bytes; + + glyphs[i].x = x; + glyphs[i].y = y; + + g = scaled_font->backend->ucs4_to_index (scaled_font, unicode); + + /* + * No advance needed for a single character string. So, let's speed up + * one-character strings by skipping glyph lookup. + */ + if (num_chars > 1) { + status = _cairo_scaled_glyph_lookup (scaled_font, + g, + CAIRO_SCALED_GLYPH_INFO_METRICS, + &scaled_glyph); + if (unlikely (status)) + return status; + + x += scaled_glyph->metrics.x_advance; + y += scaled_glyph->metrics.y_advance; + } + + glyphs[i].index = g; + + if (clusters) { + (*clusters)[i].num_bytes = num_bytes; + (*clusters)[i].num_glyphs = 1; + } + } + + return CAIRO_STATUS_SUCCESS; +} + /** * cairo_scaled_font_text_to_glyphs: * @x: X position to place first glyph @@ -1686,6 +1842,7 @@ slim_hidden_def (cairo_scaled_font_glyph_extents); * * Since: 1.8 **/ +#define CACHING_THRESHOLD 16 cairo_status_t cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, double x, @@ -1698,18 +1855,10 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, int *num_clusters, cairo_text_cluster_flags_t *cluster_flags) { - int i; int num_chars = 0; - const char *p; cairo_status_t status; cairo_glyph_t *orig_glyphs; cairo_text_cluster_t *orig_clusters; - struct glyph_lut_elt { - uint32_t unicode; - unsigned long index; - double x_advance; - double y_advance; - } glyph_lut[256]; status = scaled_font->status; if (unlikely (status)) @@ -1847,52 +1996,20 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, *num_clusters = num_chars; } - for (i = 0; i < ARRAY_LENGTH (glyph_lut); i++) - glyph_lut[i].unicode = ~0U; - - p = utf8; - for (i = 0; i < num_chars; i++) { - int num_bytes; - uint32_t unicode; - cairo_scaled_glyph_t *scaled_glyph; - struct glyph_lut_elt *glyph_slot; - - num_bytes = _cairo_utf8_get_char_validated (p, &unicode); - p += num_bytes; - - (*glyphs)[i].x = x; - (*glyphs)[i].y = y; - - glyph_slot = &glyph_lut[unicode % ARRAY_LENGTH (glyph_lut)]; - if (glyph_slot->unicode == unicode) { - (*glyphs)[i].index = glyph_slot->index; - x += glyph_slot->x_advance; - y += glyph_slot->y_advance; - } else { - (*glyphs)[i].index = - (*scaled_font->backend->ucs4_to_index) (scaled_font, unicode); - - status = _cairo_scaled_glyph_lookup (scaled_font, - (*glyphs)[i].index, - CAIRO_SCALED_GLYPH_INFO_METRICS, - &scaled_glyph); - if (unlikely (status)) - goto DONE; - - x += scaled_glyph->metrics.x_advance; - y += scaled_glyph->metrics.y_advance; - - glyph_slot->unicode = unicode; - glyph_slot->index = (*glyphs)[i].index; - glyph_slot->x_advance = scaled_glyph->metrics.x_advance; - glyph_slot->y_advance = scaled_glyph->metrics.y_advance; - } - - if (clusters) { - (*clusters)[i].num_bytes = num_bytes; - (*clusters)[i].num_glyphs = 1; - } - } + if (num_chars > CACHING_THRESHOLD) + status = cairo_scaled_font_text_to_glyphs_internal_cached (scaled_font, + x, y, + utf8, + *glyphs, + clusters, + num_chars); + else + status = cairo_scaled_font_text_to_glyphs_internal_uncached (scaled_font, + x, y, + utf8, + *glyphs, + clusters, + num_chars); DONE: /* error that should be logged on scaled_font happened */ _cairo_scaled_font_thaw_cache (scaled_font); @@ -1928,12 +2045,16 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, slim_hidden_def (cairo_scaled_font_text_to_glyphs); static inline cairo_bool_t -_range_contains_glyph (const cairo_point_int_t *min, - const cairo_point_int_t *max, - int left, int top, - int right, int bottom) +_range_contains_glyph (const cairo_box_t *extents, + cairo_fixed_t left, + cairo_fixed_t top, + cairo_fixed_t right, + cairo_fixed_t bottom) { - return right > min->x && left < max->x && bottom > min->y && top < max->y; + return right > extents->p1.x && + left < extents->p2.x && + bottom > extents->p1.y && + top < extents->p2.y; } /* @@ -1947,10 +2068,10 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font, cairo_bool_t *overlap_out) { cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_point_int_t min = { CAIRO_RECT_INT_MAX, CAIRO_RECT_INT_MAX }; - cairo_point_int_t max = { CAIRO_RECT_INT_MIN, CAIRO_RECT_INT_MIN }; + cairo_box_t box = { { INT_MAX, INT_MAX }, { INT_MIN, INT_MIN }}; cairo_scaled_glyph_t *glyph_cache[64]; cairo_bool_t overlap = overlap_out ? FALSE : TRUE; + cairo_round_glyph_positions_t round_glyph_positions = _cairo_font_options_get_round_glyph_positions (&scaled_font->options); int i; if (unlikely (scaled_font->status)) @@ -1962,9 +2083,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font, for (i = 0; i < num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; - int left, top; - int right, bottom; - int x, y; + cairo_fixed_t x, y, x1, y1, x2, y2; int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache); scaled_glyph = glyph_cache[cache_index]; @@ -1981,35 +2100,35 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font, glyph_cache[cache_index] = scaled_glyph; } - /* XXX glyph images are snapped to pixel locations */ - x = _cairo_lround (glyphs[i].x); - y = _cairo_lround (glyphs[i].y); + if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON) + x = _cairo_fixed_from_int (_cairo_lround (glyphs[i].x)); + else + x = _cairo_fixed_from_double (glyphs[i].x); + x1 = x + scaled_glyph->bbox.p1.x; + x2 = x + scaled_glyph->bbox.p2.x; - left = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); - top = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); - right = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x); - bottom = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y); + if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON) + y = _cairo_fixed_from_int (_cairo_lround (glyphs[i].y)); + else + y = _cairo_fixed_from_double (glyphs[i].y); + y1 = y + scaled_glyph->bbox.p1.y; + y2 = y + scaled_glyph->bbox.p2.y; - if (overlap == FALSE) { - overlap = _range_contains_glyph (&min, &max, - left, top, right, bottom); - } + if (overlap == FALSE) + overlap = _range_contains_glyph (&box, x1, y1, x2, y2); - if (left < min.x) min.x = left; - if (right > max.x) max.x = right; - if (top < min.y) min.y = top; - if (bottom > max.y) max.y = bottom; + if (x1 < box.p1.x) box.p1.x = x1; + if (x2 > box.p2.x) box.p2.x = x2; + if (y1 < box.p1.y) box.p1.y = y1; + if (y2 > box.p2.y) box.p2.y = y2; } _cairo_scaled_font_thaw_cache (scaled_font); if (unlikely (status)) return _cairo_scaled_font_set_error (scaled_font, status); - if (min.x < max.x && min.y < max.y) { - extents->x = min.x; - extents->width = max.x - min.x; - extents->y = min.y; - extents->height = max.y - min.y; + if (box.p1.x < box.p2.x) { + _cairo_box_round_to_rectangle (&box, extents); } else { extents->x = extents->y = 0; extents->width = extents->height = 0; @@ -2076,7 +2195,6 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, cairo_surface_t *mask = NULL; cairo_format_t mask_format = CAIRO_FORMAT_A1; /* shut gcc up */ cairo_surface_pattern_t mask_pattern; - cairo_solid_pattern_t white_pattern; int i; /* These operators aren't interpreted the same way by the backends; @@ -2111,8 +2229,6 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, /* Font display routine either does not exist or failed. */ - _cairo_pattern_init_solid (&white_pattern, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR); - _cairo_scaled_font_freeze_cache (scaled_font); for (i = 0; i < num_glyphs; i++) { @@ -2154,7 +2270,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, case CAIRO_FORMAT_A1: mask_format = glyph_surface->format; break; + case CAIRO_FORMAT_RGB16_565: case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_INVALID: default: ASSERT_NOT_REACHED; mask_format = CAIRO_FORMAT_ARGB32; @@ -2172,8 +2290,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, /* Note that we only upgrade masks, i.e. A1 -> A8 -> ARGB32, so there is * never any component alpha here. */ - status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, - &white_pattern.base, + status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, &mask_pattern.base, new_mask, 0, 0, @@ -2209,7 +2327,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, glyph_pattern.base.has_component_alpha = TRUE; status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, - &white_pattern.base, + &_cairo_pattern_white.base, &glyph_pattern.base, mask, 0, 0, @@ -2243,8 +2361,6 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, CLEANUP_MASK: _cairo_scaled_font_thaw_cache (scaled_font); - _cairo_pattern_fini (&white_pattern.base); - if (mask != NULL) cairo_surface_destroy (mask); return _cairo_scaled_font_set_error (scaled_font, status); @@ -2313,7 +2429,7 @@ _trace_mask_to_path (cairo_image_surface_t *mask, cairo_fixed_t px, py; cairo_status_t status; - mask = _cairo_image_surface_coerce (mask, CAIRO_FORMAT_A1); + mask = _cairo_image_surface_coerce_to_format (mask, CAIRO_FORMAT_A1); status = mask->base.status; if (unlikely (status)) return status; @@ -2490,6 +2606,8 @@ _cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph, scaled_glyph->x_advance = _cairo_lround (device_x_advance); scaled_glyph->y_advance = _cairo_lround (device_y_advance); + + scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_METRICS; } void @@ -2503,6 +2621,11 @@ _cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph, /* sanity check the backend glyph contents */ _cairo_debug_check_image_surface_is_defined (&surface->base); scaled_glyph->surface = surface; + + if (surface != NULL) + scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_SURFACE; + else + scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_SURFACE; } void @@ -2512,7 +2635,13 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph, { if (scaled_glyph->path != NULL) _cairo_path_fixed_destroy (scaled_glyph->path); + scaled_glyph->path = path; + + if (path != NULL) + scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_PATH; + else + scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_PATH; } void @@ -2520,9 +2649,17 @@ _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_font_t *scaled_font, cairo_surface_t *recording_surface) { - if (scaled_glyph->recording_surface != NULL) - cairo_surface_destroy (recording_surface); + if (scaled_glyph->recording_surface != NULL) { + cairo_surface_finish (scaled_glyph->recording_surface); + cairo_surface_destroy (scaled_glyph->recording_surface); + } + scaled_glyph->recording_surface = recording_surface; + + if (recording_surface != NULL) + scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE; + else + scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE; } static cairo_bool_t @@ -2543,10 +2680,14 @@ _cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font, cairo_status_t status; /* only the first page in the list may contain available slots */ - page = scaled_font->glyph_pages; - if (page != NULL && page->num_glyphs < CAIRO_SCALED_GLYPH_PAGE_SIZE) { - *scaled_glyph = &page->glyphs[page->num_glyphs++]; - return CAIRO_STATUS_SUCCESS; + if (! cairo_list_is_empty (&scaled_font->glyph_pages)) { + page = cairo_list_last_entry (&scaled_font->glyph_pages, + cairo_scaled_glyph_page_t, + link); + if (page->num_glyphs < CAIRO_SCALED_GLYPH_PAGE_SIZE) { + *scaled_glyph = &page->glyphs[page->num_glyphs++]; + return CAIRO_STATUS_SUCCESS; + } } page = malloc (sizeof (cairo_scaled_glyph_page_t)); @@ -2584,11 +2725,7 @@ _cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font, return status; } - page->next = scaled_font->glyph_pages; - page->prev = NULL; - if (scaled_font->glyph_pages != NULL) - scaled_font->glyph_pages->prev = page; - scaled_font->glyph_pages = page; + cairo_list_add_tail (&page->link, &scaled_font->glyph_pages); *scaled_glyph = &page->glyphs[page->num_glyphs++]; return CAIRO_STATUS_SUCCESS; @@ -2600,15 +2737,17 @@ _cairo_scaled_font_free_last_glyph (cairo_scaled_font_t *scaled_font, { cairo_scaled_glyph_page_t *page; - page = scaled_font->glyph_pages; - assert (page != NULL && scaled_glyph == &page->glyphs[page->num_glyphs-1]); + assert (! cairo_list_is_empty (&scaled_font->glyph_pages)); + page = cairo_list_last_entry (&scaled_font->glyph_pages, + cairo_scaled_glyph_page_t, + link); + assert (scaled_glyph == &page->glyphs[page->num_glyphs-1]); _cairo_scaled_glyph_fini (scaled_font, scaled_glyph); if (--page->num_glyphs == 0) { _cairo_cache_remove (&cairo_scaled_glyph_page_cache, &page->cache_entry); - assert (scaled_font->glyph_pages != page); } } @@ -2649,6 +2788,8 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph; cairo_scaled_glyph_info_t need_info; + *scaled_glyph_ret = NULL; + if (unlikely (scaled_font->status)) return scaled_font->status; @@ -2663,7 +2804,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, if (scaled_glyph == NULL) { status = _cairo_scaled_font_allocate_glyph (scaled_font, &scaled_glyph); if (unlikely (status)) - goto CLEANUP; + goto err; memset (scaled_glyph, 0, sizeof (cairo_scaled_glyph_t)); _cairo_scaled_glyph_set_index (scaled_glyph, index); @@ -2675,14 +2816,14 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, info | CAIRO_SCALED_GLYPH_INFO_METRICS); if (unlikely (status)) { _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph); - goto CLEANUP; + goto err; } status = _cairo_hash_table_insert (scaled_font->glyphs, &scaled_glyph->hash_entry); if (unlikely (status)) { _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph); - goto CLEANUP; + goto err; } } @@ -2690,69 +2831,29 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, * Check and see if the glyph, as provided, * already has the requested data and amend it if not */ - need_info = 0; - if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0 && - scaled_glyph->surface == NULL) - { - need_info |= CAIRO_SCALED_GLYPH_INFO_SURFACE; - } - - if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 && - scaled_glyph->path == NULL) - { - need_info |= CAIRO_SCALED_GLYPH_INFO_PATH; - } - - if ((info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) != 0 && - scaled_glyph->recording_surface == NULL) - { - need_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE; - } - + need_info = info & ~scaled_glyph->has_info; if (need_info) { status = scaled_font->backend->scaled_glyph_init (scaled_font, scaled_glyph, need_info); if (unlikely (status)) - goto CLEANUP; + goto err; /* Don't trust the scaled_glyph_init() return value, the font * backend may not even know about some of the info. For example, * no backend other than the user-fonts knows about recording-surface * glyph info. */ - - if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0 && - scaled_glyph->surface == NULL) - { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto CLEANUP; - } - - if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 && - scaled_glyph->path == NULL) - { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto CLEANUP; - } - - if ((info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) != 0 && - scaled_glyph->recording_surface == NULL) - { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto CLEANUP; - } + if (info & ~scaled_glyph->has_info) + return CAIRO_INT_STATUS_UNSUPPORTED; } - CLEANUP: - if (unlikely (status)) { - /* It's not an error for the backend to not support the info we want. */ - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - status = _cairo_scaled_font_set_error (scaled_font, status); - *scaled_glyph_ret = NULL; - } else { - *scaled_glyph_ret = scaled_glyph; - } + *scaled_glyph_ret = scaled_glyph; + return CAIRO_STATUS_SUCCESS; +err: + /* It's not an error for the backend to not support the info we want. */ + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + status = _cairo_scaled_font_set_error (scaled_font, status); return status; } diff --git a/gfx/cairo/cairo/src/cairo-script-surface.c b/gfx/cairo/cairo/src/cairo-script-surface.c index ec06364b3388..0f0446d6a210 100644 --- a/gfx/cairo/cairo/src/cairo-script-surface.c +++ b/gfx/cairo/cairo/src/cairo-script-surface.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -47,21 +47,35 @@ #include "cairo-script.h" #include "cairo-analysis-surface-private.h" -#include "cairo-ft-private.h" +#include "cairo-device-private.h" +#include "cairo-error-private.h" #include "cairo-list-private.h" #include "cairo-recording-surface-private.h" #include "cairo-output-stream-private.h" #include "cairo-scaled-font-private.h" #include "cairo-surface-clipper-private.h" +#include "cairo-surface-snapshot-private.h" +#include "cairo-surface-subsurface-private.h" #include "cairo-surface-wrapper-private.h" +#if CAIRO_HAS_FT_FONT +#include "cairo-ft-private.h" +#endif + #include +#ifdef WORDS_BIGENDIAN +#define to_be32(x) x +#else +#define to_be32(x) bswap_32(x) +#endif + #define _cairo_output_stream_puts(S, STR) \ _cairo_output_stream_write ((S), (STR), strlen (STR)) #define static cairo_warn static +typedef struct _cairo_script_context cairo_script_context_t; typedef struct _cairo_script_surface cairo_script_surface_t; typedef struct _cairo_script_implicit_context cairo_script_implicit_context_t; typedef struct _cairo_script_surface_font_private cairo_script_surface_font_private_t; @@ -81,9 +95,8 @@ struct deferred_finish { }; struct _cairo_script_context { - cairo_status_t status; + cairo_device_t base; - int ref; int active; cairo_output_stream_t *stream; @@ -133,13 +146,11 @@ struct _cairo_script_surface { cairo_surface_wrapper_t wrapper; - cairo_script_context_t *ctx; cairo_surface_clipper_t clipper; operand_t operand; cairo_bool_t emitted; cairo_bool_t defined; - cairo_bool_t is_clear; cairo_bool_t active; double width, height; @@ -157,9 +168,6 @@ _cairo_script_surface_create_internal (cairo_script_context_t *ctx, double height, cairo_surface_t *passthrough); -static cairo_status_t -_context_destroy (cairo_script_context_t *ctx); - static void _cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font); @@ -241,6 +249,16 @@ _bitmap_next_id (struct _bitmap *b, return CAIRO_STATUS_SUCCESS; } +static void +_bitmap_fini (struct _bitmap *b) +{ + while (b != NULL) { + struct _bitmap *next = b->next; + free (b); + b = next; + } +} + static const char * _direction_to_string (cairo_bool_t backward) { @@ -370,17 +388,23 @@ _line_join_to_string (cairo_line_join_t line_join) return names[line_join]; } +static inline cairo_script_context_t * +to_context (cairo_script_surface_t *surface) +{ + return (cairo_script_context_t *) surface->base.device; +} + static cairo_bool_t target_is_active (cairo_script_surface_t *surface) { return cairo_list_is_first (&surface->operand.link, - &surface->ctx->operands); + &to_context (surface)->operands); } static void target_push (cairo_script_surface_t *surface) { - cairo_list_move (&surface->operand.link, &surface->ctx->operands); + cairo_list_move (&surface->operand.link, &to_context (surface)->operands); } static int @@ -389,7 +413,7 @@ target_depth (cairo_script_surface_t *surface) cairo_list_t *link; int depth = 0; - cairo_list_foreach (link, &surface->ctx->operands) { + cairo_list_foreach (link, &to_context (surface)->operands) { if (link == &surface->operand.link) break; depth++; @@ -401,7 +425,7 @@ target_depth (cairo_script_surface_t *surface) static void _get_target (cairo_script_surface_t *surface) { - cairo_script_context_t *ctx = surface->ctx; + cairo_script_context_t *ctx = to_context (surface); if (surface->defined) { _cairo_output_stream_printf (ctx->stream, "s%u ", @@ -415,15 +439,14 @@ _get_target (cairo_script_surface_t *surface) _cairo_output_stream_puts (ctx->stream, "/target get exch pop "); } else { if (depth == 1) { - _cairo_output_stream_puts (surface->ctx->stream, + _cairo_output_stream_puts (ctx->stream, "exch\n"); } else { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "%d -1 roll\n", depth); } _cairo_output_stream_puts (ctx->stream, "/target get "); - target_push (surface); } } else { _cairo_output_stream_puts (ctx->stream, "/target get "); @@ -445,11 +468,13 @@ _content_to_string (cairo_content_t content) static cairo_status_t _emit_surface (cairo_script_surface_t *surface) { - _cairo_output_stream_printf (surface->ctx->stream, + cairo_script_context_t *ctx = to_context (surface); + + _cairo_output_stream_printf (ctx->stream, "<< /content //%s", _content_to_string (surface->base.content)); if (surface->width != -1 && surface->height != -1) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " /width %f /height %f", surface->width, surface->height); @@ -460,7 +485,7 @@ _emit_surface (cairo_script_surface_t *surface) surface->base.y_fallback_resolution != CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " /fallback-resolution [%f %f]", surface->base.x_fallback_resolution, surface->base.y_fallback_resolution); @@ -471,14 +496,14 @@ _emit_surface (cairo_script_surface_t *surface) { /* XXX device offset is encoded into the pattern matrices etc. */ if (0) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " /device-offset [%f %f]", surface->base.device_transform.x0, surface->base.device_transform.y0); } } - _cairo_output_stream_puts (surface->ctx->stream, " >> surface context\n"); + _cairo_output_stream_puts (ctx->stream, " >> surface context\n"); surface->emitted = TRUE; return CAIRO_STATUS_SUCCESS; } @@ -486,7 +511,7 @@ _emit_surface (cairo_script_surface_t *surface) static cairo_status_t _emit_context (cairo_script_surface_t *surface) { - cairo_script_context_t *ctx = surface->ctx; + cairo_script_context_t *ctx = to_context (surface); if (target_is_active (surface)) return CAIRO_STATUS_SUCCESS; @@ -562,7 +587,7 @@ _emit_operator (cairo_script_surface_t *surface, surface->cr.current_operator = op; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (to_context (surface)->stream, "//%s set-operator\n", _operator_to_string (op)); return CAIRO_STATUS_SUCCESS; @@ -579,7 +604,7 @@ _emit_fill_rule (cairo_script_surface_t *surface, surface->cr.current_fill_rule = fill_rule; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (to_context (surface)->stream, "//%s set-fill-rule\n", _fill_rule_to_string (fill_rule)); return CAIRO_STATUS_SUCCESS; @@ -601,7 +626,7 @@ _emit_tolerance (cairo_script_surface_t *surface, surface->cr.current_tolerance = tolerance; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (to_context (surface)->stream, "%f set-tolerance\n", tolerance); return CAIRO_STATUS_SUCCESS; @@ -618,7 +643,7 @@ _emit_antialias (cairo_script_surface_t *surface, surface->cr.current_antialias = antialias; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (to_context (surface)->stream, "//%s set-antialias\n", _antialias_to_string (antialias)); @@ -641,7 +666,7 @@ _emit_line_width (cairo_script_surface_t *surface, surface->cr.current_style.line_width = line_width; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (to_context (surface)->stream, "%f set-line-width\n", line_width); return CAIRO_STATUS_SUCCESS; @@ -658,7 +683,7 @@ _emit_line_cap (cairo_script_surface_t *surface, surface->cr.current_style.line_cap = line_cap; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (to_context (surface)->stream, "//%s set-line-cap\n", _line_cap_to_string (line_cap)); return CAIRO_STATUS_SUCCESS; @@ -675,7 +700,7 @@ _emit_line_join (cairo_script_surface_t *surface, surface->cr.current_style.line_join = line_join; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (to_context (surface)->stream, "//%s set-line-join\n", _line_join_to_string (line_join)); return CAIRO_STATUS_SUCCESS; @@ -697,7 +722,7 @@ _emit_miter_limit (cairo_script_surface_t *surface, surface->cr.current_style.miter_limit = miter_limit; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (to_context (surface)->stream, "%f set-miter-limit\n", miter_limit); return CAIRO_STATUS_SUCCESS; @@ -761,13 +786,13 @@ _emit_dash (cairo_script_surface_t *surface, surface->cr.current_style.num_dashes = num_dashes; surface->cr.current_style.dash_offset = offset; - _cairo_output_stream_puts (surface->ctx->stream, "["); + _cairo_output_stream_puts (to_context (surface)->stream, "["); for (n = 0; n < num_dashes; n++) { - _cairo_output_stream_printf (surface->ctx->stream, "%f", dash[n]); + _cairo_output_stream_printf (to_context (surface)->stream, "%f", dash[n]); if (n < num_dashes-1) - _cairo_output_stream_puts (surface->ctx->stream, " "); + _cairo_output_stream_puts (to_context (surface)->stream, " "); } - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (to_context (surface)->stream, "] %f set-dash\n", offset); @@ -811,14 +836,16 @@ _emit_stroke_style (cairo_script_surface_t *surface, static const char * _format_to_string (cairo_format_t format) { - static const char *names[] = { - "ARGB32", /* CAIRO_FORMAT_ARGB32 */ - "RGB24", /* CAIRO_FORMAT_RGB24 */ - "A8", /* CAIRO_FORMAT_A8 */ - "A1" /* CAIRO_FORMAT_A1 */ - }; - assert (format < ARRAY_LENGTH (names)); - return names[format]; + switch (format) { + case CAIRO_FORMAT_ARGB32: return "ARGB32"; + case CAIRO_FORMAT_RGB24: return "RGB24"; + case CAIRO_FORMAT_RGB16_565: return "RGB16_565"; + case CAIRO_FORMAT_A8: return "A8"; + case CAIRO_FORMAT_A1: return "A1"; + case CAIRO_FORMAT_INVALID: return "INVALID"; + } + ASSERT_NOT_REACHED; + return "INVALID"; } static cairo_status_t @@ -826,23 +853,22 @@ _emit_solid_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; + cairo_script_context_t *ctx = to_context (surface); - if (solid->content & CAIRO_CONTENT_ALPHA && - ! CAIRO_COLOR_IS_OPAQUE (&solid->color)) + if (! CAIRO_COLOR_IS_OPAQUE (&solid->color)) { - if (! (solid->content & CAIRO_CONTENT_COLOR) || - ! (surface->base.content & CAIRO_CONTENT_COLOR) || + if (! (surface->base.content & CAIRO_CONTENT_COLOR) || ((solid->color.red_short == 0 || solid->color.red_short == 0xffff) && (solid->color.green_short == 0 || solid->color.green_short == 0xffff) && (solid->color.blue_short == 0 || solid->color.blue_short == 0xffff) )) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "%f a", solid->color.alpha); } else { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "%f %f %f %f rgba", solid->color.red, solid->color.green, @@ -855,13 +881,13 @@ _emit_solid_pattern (cairo_script_surface_t *surface, if (solid->color.red_short == solid->color.green_short && solid->color.red_short == solid->color.blue_short) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "%f g", solid->color.red); } else { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "%f %f %f rgb", solid->color.red, solid->color.green, @@ -896,28 +922,30 @@ static cairo_status_t _emit_linear_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { + cairo_script_context_t *ctx = to_context (surface); cairo_linear_pattern_t *linear; linear = (cairo_linear_pattern_t *) pattern; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "%f %f %f %f linear", _cairo_fixed_to_double (linear->p1.x), _cairo_fixed_to_double (linear->p1.y), _cairo_fixed_to_double (linear->p2.x), _cairo_fixed_to_double (linear->p2.y)); - return _emit_gradient_color_stops (&linear->base, surface->ctx->stream); + return _emit_gradient_color_stops (&linear->base, ctx->stream); } static cairo_status_t _emit_radial_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { + cairo_script_context_t *ctx = to_context (surface); cairo_radial_pattern_t *radial; radial = (cairo_radial_pattern_t *) pattern; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "%f %f %f %f %f %f radial", _cairo_fixed_to_double (radial->c1.x), _cairo_fixed_to_double (radial->c1.y), @@ -925,24 +953,19 @@ _emit_radial_pattern (cairo_script_surface_t *surface, _cairo_fixed_to_double (radial->c2.x), _cairo_fixed_to_double (radial->c2.y), _cairo_fixed_to_double (radial->r2)); - return _emit_gradient_color_stops (&radial->base, surface->ctx->stream); + return _emit_gradient_color_stops (&radial->base, ctx->stream); } static cairo_status_t _emit_recording_surface_pattern (cairo_script_surface_t *surface, - const cairo_pattern_t *pattern) + cairo_recording_surface_t *source) { cairo_script_implicit_context_t old_cr; - cairo_surface_pattern_t *surface_pattern; - cairo_recording_surface_t *source; cairo_script_surface_t *similar; cairo_status_t status; cairo_box_t bbox; cairo_rectangle_int_t rect; - surface_pattern = (cairo_surface_pattern_t *) pattern; - source = (cairo_recording_surface_t *) surface_pattern->surface; - /* first measure the extents */ status = _cairo_recording_surface_get_bbox (source, &bbox, NULL); if (unlikely (status)) @@ -951,7 +974,7 @@ _emit_recording_surface_pattern (cairo_script_surface_t *surface, /* convert to extents so that it matches the public api */ _cairo_box_round_to_rectangle (&bbox, &rect); - similar = _cairo_script_surface_create_internal (surface->ctx, + similar = _cairo_script_surface_create_internal (to_context (surface), source->content, rect.width, rect.height, @@ -960,10 +983,10 @@ _emit_recording_surface_pattern (cairo_script_surface_t *surface, return similar->base.status; cairo_surface_set_device_offset (&similar->base, -rect.x, -rect.y); - surface->is_clear = TRUE; + similar->base.is_clear = TRUE; _get_target (surface); - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (to_context (surface)->stream, "%d %d //%s similar dup context\n", rect.width, rect.height, _content_to_string (source->content)); @@ -983,7 +1006,7 @@ _emit_recording_surface_pattern (cairo_script_surface_t *surface, cairo_list_del (&similar->operand.link); assert (target_is_active (surface)); - _cairo_output_stream_puts (surface->ctx->stream, "pop pattern"); + _cairo_output_stream_puts (to_context (surface)->stream, "pop "); cairo_surface_destroy (&similar->base); return CAIRO_STATUS_SUCCESS; @@ -991,16 +1014,9 @@ _emit_recording_surface_pattern (cairo_script_surface_t *surface, static cairo_status_t _emit_script_surface_pattern (cairo_script_surface_t *surface, - const cairo_pattern_t *pattern) + cairo_script_surface_t *source) { - cairo_surface_pattern_t *surface_pattern; - cairo_script_surface_t *source; - - surface_pattern = (cairo_surface_pattern_t *) pattern; - source = (cairo_script_surface_t *) surface_pattern->surface; - _get_target (source); - _cairo_output_stream_puts (surface->ctx->stream, "pattern"); return CAIRO_STATUS_SUCCESS; } @@ -1031,6 +1047,12 @@ _write_image_surface (cairo_output_stream_t *output, data += stride; } break; + case CAIRO_FORMAT_RGB16_565: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, 2*width); + data += stride; + } + break; case CAIRO_FORMAT_RGB24: for (row = image->height; row--; ) { int col; @@ -1048,6 +1070,7 @@ _write_image_surface (cairo_output_stream_t *output, data += stride; } break; + case CAIRO_FORMAT_INVALID: default: ASSERT_NOT_REACHED; break; @@ -1076,6 +1099,17 @@ _write_image_surface (cairo_output_stream_t *output, data += stride; } break; + case CAIRO_FORMAT_RGB16_565: + for (row = image->height; row--; ) { + uint16_t *src = (uint16_t *) data; + uint16_t *dst = (uint16_t *) rowdata; + int col; + for (col = 0; col < width; col++) + dst[col] = bswap_16 (src[col]); + _cairo_output_stream_write (output, rowdata, 2*width); + data += stride; + } + break; case CAIRO_FORMAT_RGB24: for (row = image->height; row--; ) { uint8_t *src = data; @@ -1101,6 +1135,7 @@ _write_image_surface (cairo_output_stream_t *output, data += stride; } break; + case CAIRO_FORMAT_INVALID: default: ASSERT_NOT_REACHED; break; @@ -1114,19 +1149,20 @@ _write_image_surface (cairo_output_stream_t *output, static cairo_int_status_t _emit_png_surface (cairo_script_surface_t *surface, - cairo_image_surface_t *image) + cairo_image_surface_t *image) { + cairo_script_context_t *ctx = to_context (surface); cairo_output_stream_t *base85_stream; cairo_status_t status; const uint8_t *mime_data; - unsigned int mime_data_length; + unsigned long mime_data_length; cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_PNG, &mime_data, &mime_data_length); if (mime_data == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "<< " "/width %d " "/height %d " @@ -1136,13 +1172,13 @@ _emit_png_surface (cairo_script_surface_t *surface, image->width, image->height, _format_to_string (image->format)); - base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + base85_stream = _cairo_base85_stream_create (ctx->stream); _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); status = _cairo_output_stream_destroy (base85_stream); if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, "~> >> image "); + _cairo_output_stream_puts (ctx->stream, "~> >> image "); return CAIRO_STATUS_SUCCESS; } @@ -1167,18 +1203,19 @@ static cairo_status_t _emit_image_surface (cairo_script_surface_t *surface, cairo_image_surface_t *image) { + cairo_script_context_t *ctx = to_context (surface); cairo_output_stream_t *base85_stream; cairo_output_stream_t *zlib_stream; cairo_status_t status, status2; const uint8_t *mime_data; - unsigned int mime_data_length; + unsigned long mime_data_length; struct def *tag; if (_cairo_user_data_array_get_data (&image->base.user_data, - (cairo_user_data_key_t *) surface->ctx)) + (cairo_user_data_key_t *) ctx)) { - _cairo_output_stream_printf (surface->ctx->stream, - "s%u pattern ", + _cairo_output_stream_printf (ctx->stream, + "s%u ", image->base.unique_id); return CAIRO_STATUS_SUCCESS; } @@ -1191,15 +1228,13 @@ _emit_image_surface (cairo_script_surface_t *surface, uint32_t len; if (image->format == CAIRO_FORMAT_INVALID) { - clone = - _cairo_image_surface_coerce (image, - _cairo_format_from_content (image->base.content)); + clone = _cairo_image_surface_coerce (image); } else { clone = (cairo_image_surface_t *) cairo_surface_reference (&image->base); } - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "<< " "/width %d " "/height %d " @@ -1215,20 +1250,27 @@ _emit_image_surface (cairo_script_surface_t *surface, case CAIRO_FORMAT_A8: len = clone->width; break; + case CAIRO_FORMAT_RGB16_565: + len = clone->width * 2; + break; case CAIRO_FORMAT_RGB24: len = clone->width * 3; break; case CAIRO_FORMAT_ARGB32: len = clone->width * 4; break; + case CAIRO_FORMAT_INVALID: + ASSERT_NOT_REACHED; + break; } len *= clone->height; if (len > 24) { - _cairo_output_stream_puts (surface->ctx->stream, "<|"); + _cairo_output_stream_puts (ctx->stream, "<|"); - base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + base85_stream = _cairo_base85_stream_create (ctx->stream); + len = to_be32 (len); _cairo_output_stream_write (base85_stream, &len, sizeof (len)); zlib_stream = _cairo_deflate_stream_create (base85_stream); @@ -1243,9 +1285,9 @@ _emit_image_surface (cairo_script_surface_t *surface, if (unlikely (status)) return status; } else { - _cairo_output_stream_puts (surface->ctx->stream, "<~"); + _cairo_output_stream_puts (ctx->stream, "<~"); - base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + base85_stream = _cairo_base85_stream_create (ctx->stream); status = _write_image_surface (base85_stream, clone); status2 = _cairo_output_stream_destroy (base85_stream); if (status == CAIRO_STATUS_SUCCESS) @@ -1253,7 +1295,7 @@ _emit_image_surface (cairo_script_surface_t *surface, if (unlikely (status)) return status; } - _cairo_output_stream_puts (surface->ctx->stream, "~> >> image "); + _cairo_output_stream_puts (ctx->stream, "~> >> image "); cairo_surface_destroy (&clone->base); } @@ -1262,103 +1304,150 @@ _emit_image_surface (cairo_script_surface_t *surface, if (unlikely (tag == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - tag->ctx = surface->ctx; + tag->ctx = ctx; tag->tag = image->base.unique_id; tag->user_data = &image->base.user_data; - cairo_list_add (&tag->link, &surface->ctx->defines); + cairo_list_add (&tag->link, &ctx->defines); status = _cairo_user_data_array_set_data (&image->base.user_data, - (cairo_user_data_key_t *) surface->ctx, - tag, _undef); + (cairo_user_data_key_t *) ctx, + tag, _undef); if (unlikely (status)) { free (tag); return status; } - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "dup /s%u exch def ", image->base.unique_id); cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JPEG, &mime_data, &mime_data_length); if (mime_data != NULL) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "\n (%s) <~", CAIRO_MIME_TYPE_JPEG); - base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + base85_stream = _cairo_base85_stream_create (ctx->stream); _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); status = _cairo_output_stream_destroy (base85_stream); if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, "~> set-mime-data\n"); + _cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n"); } cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JP2, &mime_data, &mime_data_length); if (mime_data != NULL) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "\n (%s) <~", CAIRO_MIME_TYPE_JP2); - base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + base85_stream = _cairo_base85_stream_create (ctx->stream); _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); status = _cairo_output_stream_destroy (base85_stream); if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, "~> set-mime-data\n"); + _cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n"); } - _cairo_output_stream_puts (surface->ctx->stream, "pattern"); - return CAIRO_STATUS_SUCCESS; } static cairo_status_t _emit_image_surface_pattern (cairo_script_surface_t *surface, - const cairo_pattern_t *pattern) + cairo_surface_t *source) { - cairo_surface_pattern_t *surface_pattern; + cairo_surface_t *snapshot; cairo_image_surface_t *image; cairo_status_t status; + void *extra; /* XXX keeping a copy is nasty, but we want to hook into the surface's * lifetime. Using a snapshot is a convenient method. */ - surface_pattern = (cairo_surface_pattern_t *) pattern; - image = (cairo_image_surface_t *) - _cairo_surface_snapshot (surface_pattern->surface); - status = _emit_image_surface (surface, image); - cairo_surface_destroy (&image->base); + snapshot = _cairo_surface_snapshot (source); + status = _cairo_surface_acquire_source_image (snapshot, &image, &extra); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _emit_image_surface (surface, image); + _cairo_surface_release_source_image (snapshot, image, extra); + } + cairo_surface_destroy (snapshot); return status; } +static cairo_status_t +_emit_subsurface_pattern (cairo_script_surface_t *surface, + cairo_surface_subsurface_t *sub) +{ + cairo_surface_t *source = sub->target; + cairo_status_t status; + + switch ((int) source->backend->type) { + case CAIRO_SURFACE_TYPE_RECORDING: + status = _emit_recording_surface_pattern (surface, (cairo_recording_surface_t *) source); + break; + case CAIRO_SURFACE_TYPE_SCRIPT: + status = _emit_script_surface_pattern (surface, (cairo_script_surface_t *) source); + break; + default: + status = _emit_image_surface_pattern (surface, source); + break; + } + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (to_context (surface)->stream, + "%d %d %d %d subsurface ", + sub->extents.x, + sub->extents.y, + sub->extents.width, + sub->extents.height); + return CAIRO_STATUS_SUCCESS; +} + static cairo_status_t _emit_surface_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { cairo_surface_pattern_t *surface_pattern; cairo_surface_t *source; + cairo_status_t status; surface_pattern = (cairo_surface_pattern_t *) pattern; source = surface_pattern->surface; - switch ((int) source->type) { + if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) + source = ((cairo_surface_snapshot_t *) source)->target; + + switch ((int) source->backend->type) { case CAIRO_SURFACE_TYPE_RECORDING: - return _emit_recording_surface_pattern (surface, pattern); + status = _emit_recording_surface_pattern (surface, (cairo_recording_surface_t *) source); + break; case CAIRO_SURFACE_TYPE_SCRIPT: - return _emit_script_surface_pattern (surface, pattern); + status = _emit_script_surface_pattern (surface, (cairo_script_surface_t *) source); + break; + case CAIRO_SURFACE_TYPE_SUBSURFACE: + status = _emit_subsurface_pattern (surface, (cairo_surface_subsurface_t *) source); + break; default: - return _emit_image_surface_pattern (surface, pattern); + status = _emit_image_surface_pattern (surface, source); + break; } + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (to_context (surface)->stream, "pattern"); + return CAIRO_STATUS_SUCCESS; } static cairo_status_t _emit_pattern (cairo_script_surface_t *surface, const cairo_pattern_t *pattern) { + cairo_script_context_t *ctx = to_context (surface); cairo_status_t status; cairo_bool_t is_default_extend; cairo_bool_t need_newline = TRUE; @@ -1390,11 +1479,11 @@ _emit_pattern (cairo_script_surface_t *surface, if (! _cairo_matrix_is_identity (&pattern->matrix)) { if (need_newline) { - _cairo_output_stream_puts (surface->ctx->stream, "\n "); + _cairo_output_stream_puts (ctx->stream, "\n "); need_newline = FALSE; } - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " [%f %f %f %f %f %f] set-matrix\n ", pattern->matrix.xx, pattern->matrix.yx, pattern->matrix.xy, pattern->matrix.yy, @@ -1404,27 +1493,27 @@ _emit_pattern (cairo_script_surface_t *surface, /* XXX need to discriminate the user explicitly setting the default */ if (pattern->filter != CAIRO_FILTER_DEFAULT) { if (need_newline) { - _cairo_output_stream_puts (surface->ctx->stream, "\n "); + _cairo_output_stream_puts (ctx->stream, "\n "); need_newline = FALSE; } - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " //%s set-filter\n ", _filter_to_string (pattern->filter)); } if (! is_default_extend ){ if (need_newline) { - _cairo_output_stream_puts (surface->ctx->stream, "\n "); + _cairo_output_stream_puts (ctx->stream, "\n "); need_newline = FALSE; } - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " //%s set-extend\n ", _extend_to_string (pattern->extend)); } if (need_newline) - _cairo_output_stream_puts (surface->ctx->stream, "\n "); + _cairo_output_stream_puts (ctx->stream, "\n "); return CAIRO_STATUS_SUCCESS; } @@ -1438,7 +1527,7 @@ _emit_identity (cairo_script_surface_t *surface, if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) return CAIRO_STATUS_SUCCESS; - _cairo_output_stream_puts (surface->ctx->stream, + _cairo_output_stream_puts (to_context (surface)->stream, "identity set-matrix\n"); *matrix_updated = TRUE; @@ -1479,7 +1568,8 @@ _emit_source (cairo_script_surface_t *surface, if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, + assert (target_is_active (surface)); + _cairo_output_stream_puts (to_context (surface)->stream, " set-source\n"); return CAIRO_STATUS_SUCCESS; } @@ -1539,6 +1629,7 @@ static cairo_status_t _emit_path (cairo_script_surface_t *surface, cairo_path_fixed_t *path) { + cairo_script_context_t *ctx = to_context (surface); cairo_box_t box; cairo_status_t status; @@ -1550,7 +1641,7 @@ _emit_path (cairo_script_surface_t *surface, _cairo_path_fixed_fini (&surface->cr.current_path); - _cairo_output_stream_puts (surface->ctx->stream, "n"); + _cairo_output_stream_puts (ctx->stream, "n"); if (path == NULL) { _cairo_path_fixed_init (&surface->cr.current_path); @@ -1564,7 +1655,7 @@ _emit_path (cairo_script_surface_t *surface, if (unlikely (status)) return status; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " %f %f %f %f rectangle", x1, y1, x2 - x1, y2 - y1); } else { @@ -1580,12 +1671,12 @@ _emit_path (cairo_script_surface_t *surface, _path_line_to, _path_curve_to, _path_close, - surface->ctx->stream); + ctx->stream); if (unlikely (status)) return status; } - _cairo_output_stream_puts (surface->ctx->stream, "\n"); + _cairo_output_stream_puts (ctx->stream, "\n"); return CAIRO_STATUS_SUCCESS; } @@ -1604,6 +1695,7 @@ _emit_scaling_matrix (cairo_script_surface_t *surface, const cairo_matrix_t *ctm, cairo_bool_t *matrix_updated) { + cairo_script_context_t *ctx = to_context (surface); cairo_bool_t was_identity; assert (target_is_active (surface)); @@ -1618,17 +1710,17 @@ _emit_scaling_matrix (cairo_script_surface_t *surface, surface->cr.current_ctm.y0 = 0.; if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) { - _cairo_output_stream_puts (surface->ctx->stream, + _cairo_output_stream_puts (ctx->stream, "identity set-matrix\n"); } else if (was_identity && fabs (ctm->yx) < 1e-5 && fabs (ctm->xy) < 1e-5) { - _cairo_output_stream_printf (surface->ctx->stream, - "%f %f scale\n", - ctm->xx, ctm->yy); + _cairo_output_stream_printf (ctx->stream, + "%f %f scale\n", + ctm->xx, ctm->yy); } else { - _cairo_output_stream_printf (surface->ctx->stream, - "[%f %f %f %f 0 0] set-matrix\n", - ctm->xx, ctm->yx, - ctm->xy, ctm->yy); + _cairo_output_stream_printf (ctx->stream, + "[%f %f %f %f 0 0] set-matrix\n", + ctm->xx, ctm->yx, + ctm->xy, ctm->yy); } return CAIRO_STATUS_SUCCESS; @@ -1638,6 +1730,7 @@ static cairo_status_t _emit_font_matrix (cairo_script_surface_t *surface, const cairo_matrix_t *font_matrix) { + cairo_script_context_t *ctx = to_context (surface); assert (target_is_active (surface)); if (memcmp (&surface->cr.current_font_matrix, @@ -1650,14 +1743,14 @@ _emit_font_matrix (cairo_script_surface_t *surface, surface->cr.current_font_matrix = *font_matrix; if (_cairo_matrix_is_identity (font_matrix)) { - _cairo_output_stream_puts (surface->ctx->stream, + _cairo_output_stream_puts (ctx->stream, "identity set-font-matrix\n"); } else { - _cairo_output_stream_printf (surface->ctx->stream, - "[%f %f %f %f %f %f] set-font-matrix\n", - font_matrix->xx, font_matrix->yx, - font_matrix->xy, font_matrix->yy, - font_matrix->x0, font_matrix->y0); + _cairo_output_stream_printf (ctx->stream, + "[%f %f %f %f %f %f] set-font-matrix\n", + font_matrix->xx, font_matrix->yx, + font_matrix->xy, font_matrix->yy, + font_matrix->x0, font_matrix->y0); } return CAIRO_STATUS_SUCCESS; @@ -1674,12 +1767,18 @@ _cairo_script_surface_create_similar (void *abstract_surface, cairo_script_context_t *ctx; cairo_status_t status; - ctx = other->ctx; + ctx = to_context (other); + + status = cairo_device_acquire (&ctx->base); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); if (! other->emitted) { status = _emit_surface (other); - if (unlikely (status)) + if (unlikely (status)) { + cairo_device_release (&ctx->base); return _cairo_surface_create_in_error (status); + } target_push (other); } @@ -1688,8 +1787,10 @@ _cairo_script_surface_create_similar (void *abstract_surface, passthrough = _cairo_surface_wrapper_create_similar (&other->wrapper, content, width, height); - if (unlikely (passthrough->status)) + if (unlikely (passthrough->status)) { + cairo_device_release (&ctx->base); return passthrough; + } } surface = _cairo_script_surface_create_internal (ctx, @@ -1698,8 +1799,10 @@ _cairo_script_surface_create_similar (void *abstract_surface, passthrough); cairo_surface_destroy (passthrough); - if (unlikely (surface->base.status)) + if (unlikely (surface->base.status)) { + cairo_device_release (&ctx->base); return &surface->base; + } _get_target (other); _cairo_output_stream_printf (ctx->stream, @@ -1709,20 +1812,27 @@ _cairo_script_surface_create_similar (void *abstract_surface, surface->base.unique_id); surface->emitted = TRUE; surface->defined = TRUE; - surface->is_clear = TRUE; + surface->base.is_clear = TRUE; target_push (surface); + cairo_device_release (&ctx->base); return &surface->base; } -static cairo_status_t -_context_destroy (cairo_script_context_t *ctx) +static void +_device_flush (void *abstract_device) { + cairo_script_context_t *ctx = abstract_device; cairo_status_t status; - assert (ctx->ref > 0); - if (--ctx->ref) - return _cairo_output_stream_flush (ctx->stream); + status = _cairo_output_stream_flush (ctx->stream); +} + +static void +_device_destroy (void *abstract_device) +{ + cairo_script_context_t *ctx = abstract_device; + cairo_status_t status; while (! cairo_list_is_empty (&ctx->fonts)) { cairo_script_surface_font_private_t *font; @@ -1731,7 +1841,9 @@ _context_destroy (cairo_script_context_t *ctx) cairo_script_surface_font_private_t, link); cairo_list_del (&font->link); - _cairo_script_surface_scaled_font_fini (font->parent); + if (font->parent->surface_private == font) + font->parent->surface_private = NULL; + free (font); } while (! cairo_list_is_empty (&ctx->defines)) { @@ -1744,11 +1856,12 @@ _context_destroy (cairo_script_context_t *ctx) assert (status == CAIRO_STATUS_SUCCESS); } + _bitmap_fini (ctx->surface_id.next); + _bitmap_fini (ctx->font_id.next); + status = _cairo_output_stream_destroy (ctx->stream); free (ctx); - - return status; } static cairo_status_t @@ -1784,6 +1897,7 @@ static cairo_status_t _cairo_script_surface_finish (void *abstract_surface) { cairo_script_surface_t *surface = abstract_surface; + cairo_script_context_t *ctx = to_context (surface); cairo_status_t status = CAIRO_STATUS_SUCCESS, status2; _cairo_surface_wrapper_fini (&surface->wrapper); @@ -1796,21 +1910,25 @@ _cairo_script_surface_finish (void *abstract_surface) _cairo_path_fixed_fini (&surface->cr.current_path); _cairo_surface_clipper_reset (&surface->clipper); + status = cairo_device_acquire (&ctx->base); + if (unlikely (status)) + return status; + if (surface->emitted) { assert (! surface->active); if (! cairo_list_is_empty (&surface->operand.link)) { - if (! surface->ctx->active) { + if (! ctx->active) { if (target_is_active (surface)) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "pop\n"); } else { int depth = target_depth (surface); if (depth == 1) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "exch pop\n"); } else { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "%d -1 roll pop\n", depth); } @@ -1827,21 +1945,22 @@ _cairo_script_surface_finish (void *abstract_surface) link->operand.type = DEFERRED; cairo_list_swap (&link->operand.link, &surface->operand.link); - cairo_list_add (&link->link, &surface->ctx->deferred); + cairo_list_add (&link->link, &ctx->deferred); } } } if (surface->defined) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "/s%u undef\n", surface->base.unique_id); } } - status2 = _context_destroy (surface->ctx); if (status == CAIRO_STATUS_SUCCESS) - status = status2; + status = _cairo_output_stream_flush (to_context (surface)->stream); + + cairo_device_release (&ctx->base); return status; } @@ -1852,13 +1971,19 @@ _cairo_script_surface_copy_page (void *abstract_surface) cairo_script_surface_t *surface = abstract_surface; cairo_status_t status; - status = _emit_context (surface); + status = cairo_device_acquire (surface->base.device); if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, "copy-page\n"); + status = _emit_context (surface); + if (unlikely (status)) + goto BAIL; - return CAIRO_STATUS_SUCCESS; + _cairo_output_stream_puts (to_context (surface)->stream, "copy-page\n"); + +BAIL: + cairo_device_release (surface->base.device); + return status; } static cairo_int_status_t @@ -1867,13 +1992,19 @@ _cairo_script_surface_show_page (void *abstract_surface) cairo_script_surface_t *surface = abstract_surface; cairo_status_t status; - status = _emit_context (surface); + status = cairo_device_acquire (surface->base.device); if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, "show-page\n"); + status = _emit_context (surface); + if (unlikely (status)) + goto BAIL; - return CAIRO_STATUS_SUCCESS; + _cairo_output_stream_puts (to_context (surface)->stream, "show-page\n"); + +BAIL: + cairo_device_release (surface->base.device); + return status; } static cairo_status_t @@ -1886,6 +2017,7 @@ _cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip cairo_script_surface_t *surface = cairo_container_of (clipper, cairo_script_surface_t, clipper); + cairo_script_context_t *ctx = to_context (surface); cairo_bool_t matrix_updated = FALSE; cairo_status_t status; cairo_box_t box; @@ -1896,7 +2028,7 @@ _cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip if (path == NULL) { if (surface->cr.has_clip) { - _cairo_output_stream_puts (surface->ctx->stream, "reset-clip\n"); + _cairo_output_stream_puts (ctx->stream, "reset-clip\n"); surface->cr.has_clip = FALSE; } return CAIRO_STATUS_SUCCESS; @@ -1938,30 +2070,40 @@ _cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip if (unlikely (status)) return status; - _cairo_output_stream_puts (surface->ctx->stream, "clip+\n"); + _cairo_output_stream_puts (ctx->stream, "clip+\n"); surface->cr.has_clip = TRUE; return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t active (cairo_script_surface_t *surface) { + cairo_status_t status; + + status = cairo_device_acquire (surface->base.device); + if (unlikely (status)) + return status; + if (surface->active++ == 0) - surface->ctx->active++; + to_context (surface)->active++; + + return CAIRO_STATUS_SUCCESS; } static void inactive (cairo_script_surface_t *surface) { - cairo_script_context_t *ctx = surface->ctx; + cairo_script_context_t *ctx = to_context (surface); cairo_list_t sorted; + assert (surface->active > 0); if (--surface->active) - return; + goto DONE; + assert (ctx->active > 0); if (--ctx->active) - return; + goto DONE; cairo_list_init (&sorted); while (! cairo_list_is_empty (&ctx->deferred)) { @@ -2030,6 +2172,9 @@ inactive (cairo_script_surface_t *surface) cairo_list_del (&df->link); free (df); } + +DONE: + cairo_device_release (surface->base.device); } static cairo_int_status_t @@ -2041,43 +2186,41 @@ _cairo_script_surface_paint (void *abstract_surface, cairo_script_surface_t *surface = abstract_surface; cairo_status_t status; - if (op == CAIRO_OPERATOR_CLEAR) { - if (surface->is_clear) - goto DONE; - } - - active (surface); + status = active (surface); + if (unlikely (status)) + return status; status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) - return status; + goto BAIL; status = _emit_context (surface); if (unlikely (status)) - return status; + goto BAIL; status = _emit_source (surface, op, source); if (unlikely (status)) - return status; + goto BAIL; status = _emit_operator (surface, op); if (unlikely (status)) - return status; + goto BAIL; - _cairo_output_stream_puts (surface->ctx->stream, + _cairo_output_stream_puts (to_context (surface)->stream, "paint\n"); - surface->is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL; - inactive (surface); - DONE: if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { return _cairo_surface_wrapper_paint (&surface->wrapper, op, source, clip); } return CAIRO_STATUS_SUCCESS; + +BAIL: + inactive (surface); + return status; } static cairo_int_status_t @@ -2090,53 +2233,51 @@ _cairo_script_surface_mask (void *abstract_surface, cairo_script_surface_t *surface = abstract_surface; cairo_status_t status; - if (op == CAIRO_OPERATOR_CLEAR) { - if (surface->is_clear) - goto DONE; - } - - active (surface); + status = active (surface); + if (unlikely (status)) + return status; status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) - return status; + goto BAIL; status = _emit_context (surface); if (unlikely (status)) - return status; + goto BAIL; status = _emit_source (surface, op, source); if (unlikely (status)) - return status; + goto BAIL; status = _emit_operator (surface, op); if (unlikely (status)) - return status; + goto BAIL; if (_cairo_pattern_equal (source, mask)) { - _cairo_output_stream_puts (surface->ctx->stream, "/source get"); + _cairo_output_stream_puts (to_context (surface)->stream, "/source get"); } else { status = _emit_pattern (surface, mask); if (unlikely (status)) - return status; + goto BAIL; } assert (surface->cr.current_operator == op); - _cairo_output_stream_puts (surface->ctx->stream, + _cairo_output_stream_puts (to_context (surface)->stream, " mask\n"); - surface->is_clear = FALSE; - inactive (surface); - DONE: if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { return _cairo_surface_wrapper_mask (&surface->wrapper, op, source, mask, clip); } return CAIRO_STATUS_SUCCESS; + +BAIL: + inactive (surface); + return status; } static cairo_int_status_t @@ -2144,9 +2285,9 @@ _cairo_script_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) @@ -2155,40 +2296,37 @@ _cairo_script_surface_stroke (void *abstract_surface, cairo_bool_t matrix_updated = FALSE; cairo_status_t status; - if (op == CAIRO_OPERATOR_CLEAR) { - if (surface->is_clear) - goto DONE; - } - - active (surface); + status = active (surface); + if (unlikely (status)) + return status; status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) - return status; + goto BAIL; status = _emit_context (surface); if (unlikely (status)) - return status; + goto BAIL; status = _emit_identity (surface, &matrix_updated); if (unlikely (status)) - return status; + goto BAIL; status = _emit_path (surface, path); if (unlikely (status)) - return status; + goto BAIL; status = _emit_source (surface, op, source); if (unlikely (status)) - return status; + goto BAIL; status = _emit_scaling_matrix (surface, ctm, &matrix_updated); if (unlikely (status)) - return status; + goto BAIL; status = _emit_operator (surface, op); if (unlikely (status)) - return status; + goto BAIL; if (_scaling_matrix_equal (&surface->cr.current_ctm, &surface->cr.current_stroke_matrix)) @@ -2203,25 +2341,22 @@ _cairo_script_surface_stroke (void *abstract_surface, status = _emit_stroke_style (surface, style, matrix_updated); if (unlikely (status)) - return status; + goto BAIL; if (! path->is_rectilinear) { status = _emit_tolerance (surface, tolerance, matrix_updated); if (unlikely (status)) - return status; + goto BAIL; } status = _emit_antialias (surface, antialias); if (unlikely (status)) - return status; + goto BAIL; - _cairo_output_stream_puts (surface->ctx->stream, "stroke+\n"); - - surface->is_clear = FALSE; + _cairo_output_stream_puts (to_context (surface)->stream, "stroke+\n"); inactive (surface); - DONE: if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { return _cairo_surface_wrapper_stroke (&surface->wrapper, op, source, path, @@ -2232,6 +2367,10 @@ _cairo_script_surface_stroke (void *abstract_surface, } return CAIRO_STATUS_SUCCESS; + +BAIL: + inactive (surface); + return status; } static cairo_int_status_t @@ -2249,62 +2388,56 @@ _cairo_script_surface_fill (void *abstract_surface, cairo_status_t status; cairo_box_t box; - if (op == CAIRO_OPERATOR_CLEAR) { - if (surface->is_clear) - goto DONE; - } - - active (surface); + status = active (surface); + if (unlikely (status)) + return status; status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) - return status; + goto BAIL; status = _emit_context (surface); if (unlikely (status)) - return status; + goto BAIL; status = _emit_identity (surface, &matrix_updated); if (unlikely (status)) - return status; + goto BAIL; status = _emit_source (surface, op, source); if (unlikely (status)) - return status; + goto BAIL; if (! _cairo_path_fixed_is_box (path, &box)) { status = _emit_fill_rule (surface, fill_rule); if (unlikely (status)) - return status; + goto BAIL; } if (! path->is_rectilinear) { status = _emit_tolerance (surface, tolerance, matrix_updated); if (unlikely (status)) - return status; + goto BAIL; } if (! path->maybe_fill_region) { status = _emit_antialias (surface, antialias); if (unlikely (status)) - return status; + goto BAIL; } status = _emit_path (surface, path); if (unlikely (status)) - return status; + goto BAIL; status = _emit_operator (surface, op); if (unlikely (status)) - return status; + goto BAIL; - _cairo_output_stream_puts (surface->ctx->stream, "fill+\n"); - - surface->is_clear = FALSE; + _cairo_output_stream_puts (to_context (surface)->stream, "fill+\n"); inactive (surface); - DONE: if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { return _cairo_surface_wrapper_fill (&surface->wrapper, op, source, path, @@ -2315,6 +2448,10 @@ _cairo_script_surface_fill (void *abstract_surface, } return CAIRO_STATUS_SUCCESS; + +BAIL: + inactive (surface); + return status; } static cairo_surface_t * @@ -2373,16 +2510,18 @@ static cairo_status_t _emit_font_options (cairo_script_surface_t *surface, cairo_font_options_t *font_options) { + cairo_script_context_t *ctx = to_context (surface); + if (cairo_font_options_equal (&surface->cr.current_font_options, font_options)) { return CAIRO_STATUS_SUCCESS; } - _cairo_output_stream_printf (surface->ctx->stream, "<<"); + _cairo_output_stream_printf (ctx->stream, "<<"); if (font_options->antialias != surface->cr.current_font_options.antialias) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " /antialias //%s", _antialias_to_string (font_options->antialias)); } @@ -2390,7 +2529,7 @@ _emit_font_options (cairo_script_surface_t *surface, if (font_options->subpixel_order != surface->cr.current_font_options.subpixel_order) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " /subpixel-order //%s", _subpixel_order_to_string (font_options->subpixel_order)); } @@ -2398,7 +2537,7 @@ _emit_font_options (cairo_script_surface_t *surface, if (font_options->hint_style != surface->cr.current_font_options.hint_style) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " /hint-style //%s", _hint_style_to_string (font_options->hint_style)); } @@ -2406,12 +2545,12 @@ _emit_font_options (cairo_script_surface_t *surface, if (font_options->hint_metrics != surface->cr.current_font_options.hint_metrics) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " /hint-metrics //%s", _hint_metrics_to_string (font_options->hint_metrics)); } - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " >> set-font-options\n"); surface->cr.current_font_options = *font_options; @@ -2425,14 +2564,22 @@ _cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font) font_private = scaled_font->surface_private; if (font_private != NULL) { - _cairo_output_stream_printf (font_private->ctx->stream, - "/f%lu undef /sf%lu undef\n", - font_private->id, - font_private->id); + cairo_status_t status; + cairo_device_t *device; - _bitmap_release_id (&font_private->ctx->font_id, font_private->id); - cairo_list_del (&font_private->link); - free (font_private); + status = cairo_device_acquire (device = &font_private->ctx->base); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + _cairo_output_stream_printf (font_private->ctx->stream, + "/f%lu undef /sf%lu undef\n", + font_private->id, + font_private->id); + + _bitmap_release_id (&font_private->ctx->font_id, font_private->id); + cairo_list_del (&font_private->link); + free (font_private); + + cairo_device_release (device); + } scaled_font->surface_private = NULL; } @@ -2442,6 +2589,7 @@ static cairo_status_t _emit_type42_font (cairo_script_surface_t *surface, cairo_scaled_font_t *scaled_font) { + cairo_script_context_t *ctx = to_context (surface); const cairo_scaled_font_backend_t *backend; cairo_script_surface_font_private_t *font_private; cairo_output_stream_t *base85_stream; @@ -2465,14 +2613,18 @@ _emit_type42_font (cairo_script_surface_t *surface, if (unlikely (buf == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - status = backend->load_truetype_table (scaled_font, 0, 0, buf, NULL); + status = backend->load_truetype_table (scaled_font, 0, 0, buf, &size); if (unlikely (status)) { free (buf); return status; } +#if CAIRO_HAS_FT_FONT load_flags = _cairo_ft_scaled_font_get_load_flags (scaled_font); - _cairo_output_stream_printf (surface->ctx->stream, +#else + load_flags = 0; +#endif + _cairo_output_stream_printf (ctx->stream, "<< " "/type 42 " "/index 0 " @@ -2480,8 +2632,8 @@ _emit_type42_font (cairo_script_surface_t *surface, "/source <|", load_flags); - base85_stream = _cairo_base85_stream_create (surface->ctx->stream); - len = size; + base85_stream = _cairo_base85_stream_create (ctx->stream); + len = to_be32 (size); _cairo_output_stream_write (base85_stream, &len, sizeof (len)); zlib_stream = _cairo_deflate_stream_create (base85_stream); @@ -2498,7 +2650,7 @@ _emit_type42_font (cairo_script_surface_t *surface, status = status2; font_private = scaled_font->surface_private; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "~> >> font dup /f%lu exch def set-font-face", font_private->id); @@ -2509,6 +2661,7 @@ static cairo_status_t _emit_scaled_font_init (cairo_script_surface_t *surface, cairo_scaled_font_t *scaled_font) { + cairo_script_context_t *ctx = to_context (surface); cairo_script_surface_font_private_t *font_private; cairo_status_t status; @@ -2516,14 +2669,14 @@ _emit_scaled_font_init (cairo_script_surface_t *surface, if (unlikely (font_private == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - font_private->ctx = surface->ctx; + font_private->ctx = ctx; font_private->parent = scaled_font; font_private->subset_glyph_index = 0; font_private->has_sfnt = TRUE; - cairo_list_add (&font_private->link, &surface->ctx->fonts); + cairo_list_add (&font_private->link, &ctx->fonts); - status = _bitmap_next_id (&surface->ctx->font_id, + status = _bitmap_next_id (&ctx->font_id, &font_private->id); if (unlikely (status)) { free (font_private); @@ -2542,7 +2695,7 @@ _emit_scaled_font_init (cairo_script_surface_t *surface, return status; font_private->has_sfnt = FALSE; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "dict\n" " /type 3 set\n" " /metrics [%f %f %f %f %f] set\n" @@ -2562,6 +2715,7 @@ static cairo_status_t _emit_scaled_font (cairo_script_surface_t *surface, cairo_scaled_font_t *scaled_font) { + cairo_script_context_t *ctx = to_context (surface); cairo_matrix_t matrix; cairo_font_options_t options; cairo_bool_t matrix_updated = FALSE; @@ -2604,11 +2758,11 @@ _emit_scaled_font (cairo_script_surface_t *surface, assert (font_private != NULL); assert (target_is_active (surface)); - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " /scaled-font get /sf%lu exch def\n", font_private->id); } else { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "sf%lu set-scaled-font\n", font_private->id); } @@ -2621,6 +2775,7 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface, cairo_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph) { + cairo_script_context_t *ctx = to_context (surface); cairo_script_surface_font_private_t *font_private; cairo_script_implicit_context_t old_cr; cairo_status_t status; @@ -2630,7 +2785,7 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface, index = ++font_private->subset_glyph_index; scaled_glyph->surface_private = (void *) index; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "%lu <<\n" " /metrics [%f %f %f %f %f %f]\n" " /render {\n", @@ -2643,7 +2798,7 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface, scaled_glyph->fs_metrics.y_advance); if (! _cairo_matrix_is_identity (&scaled_font->scale_inverse)) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "[%f %f %f %f %f %f] transform\n", scaled_font->scale_inverse.xx, scaled_font->scale_inverse.yx, @@ -2659,7 +2814,7 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface, &surface->base); surface->cr = old_cr; - _cairo_output_stream_puts (surface->ctx->stream, "} >> set\n"); + _cairo_output_stream_puts (ctx->stream, "} >> set\n"); return status; } @@ -2669,6 +2824,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, cairo_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph) { + cairo_script_context_t *ctx = to_context (surface); cairo_script_surface_font_private_t *font_private; cairo_status_t status; unsigned long index; @@ -2677,7 +2833,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, index = ++font_private->subset_glyph_index; scaled_glyph->surface_private = (void *) index; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "%lu <<\n" " /metrics [%f %f %f %f %f %f]\n" " /render {\n" @@ -2696,8 +2852,10 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, if (unlikely (status)) return status; + _cairo_output_stream_puts (ctx->stream, "pattern "); + if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "\n [%f %f %f %f %f %f] set-matrix\n", scaled_font->font_matrix.xx, scaled_font->font_matrix.yx, @@ -2706,7 +2864,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, scaled_font->font_matrix.x0, scaled_font->font_matrix.y0); } - _cairo_output_stream_puts (surface->ctx->stream, + _cairo_output_stream_puts (ctx->stream, "mask\n} >> set\n"); return CAIRO_STATUS_SUCCESS; @@ -2722,7 +2880,7 @@ _emit_scaled_glyph_prologue (cairo_script_surface_t *surface, font_private = scaled_font->surface_private; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (to_context (surface)->stream, "f%lu /glyphs get\n", font_private->id); @@ -2814,20 +2972,30 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface, _cairo_scaled_font_thaw_cache (scaled_font); if (have_glyph_prologue) { - _cairo_output_stream_puts (surface->ctx->stream, "pop pop\n"); + _cairo_output_stream_puts (to_context (surface)->stream, "pop pop\n"); } return status; } +static void +to_octal (int value, char *buf, size_t size) +{ + do { + buf[--size] = '0' + (value & 7); + value >>= 3; + } while (size); +} + static void _emit_string_literal (cairo_script_surface_t *surface, const char *utf8, int len) { + cairo_script_context_t *ctx = to_context (surface); char c; const char *end; - _cairo_output_stream_puts (surface->ctx->stream, "("); + _cairo_output_stream_puts (ctx->stream, "("); if (utf8 == NULL) { end = utf8; @@ -2858,25 +3026,21 @@ _emit_string_literal (cairo_script_surface_t *surface, case '(': case ')': ESCAPED_CHAR: - _cairo_output_stream_printf (surface->ctx->stream, "\\%c", c); + _cairo_output_stream_printf (ctx->stream, "\\%c", c); break; default: if (isprint (c) || isspace (c)) { - _cairo_output_stream_printf (surface->ctx->stream, "%c", c); + _cairo_output_stream_printf (ctx->stream, "%c", c); } else { - int octal = 0; - while (c) { - octal *= 10; - octal += c&7; - c /= 8; - } - _cairo_output_stream_printf (surface->ctx->stream, - "\\%03d", octal); + char buf[4] = { '\\' }; + + to_octal (c, buf+1, 3); + _cairo_output_stream_write (ctx->stream, buf, 4); } break; } } - _cairo_output_stream_puts (surface->ctx->stream, ")"); + _cairo_output_stream_puts (ctx->stream, ")"); } static cairo_int_status_t @@ -2894,6 +3058,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, cairo_clip_t *clip) { cairo_script_surface_t *surface = abstract_surface; + cairo_script_context_t *ctx = to_context (surface); cairo_script_surface_font_private_t *font_private; cairo_scaled_glyph_t *scaled_glyph; cairo_matrix_t matrix; @@ -2902,43 +3067,40 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, int n; cairo_output_stream_t *base85_stream = NULL; - if (op == CAIRO_OPERATOR_CLEAR) { - if (surface->is_clear) - goto DONE; - } - - active (surface); + status = active (surface); + if (unlikely (status)) + return status; status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) - return status; + goto BAIL; status = _emit_context (surface); if (unlikely (status)) - return status; + goto BAIL; status = _emit_source (surface, op, source); if (unlikely (status)) - return status; + goto BAIL; status = _emit_scaled_font (surface, scaled_font); if (unlikely (status)) - return status; + goto BAIL; status = _emit_operator (surface, op); if (unlikely (status)) - return status; + goto BAIL; status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs); if (unlikely (status)) - return status; + goto BAIL; /* (utf8) [cx cy [glyphs]] [clusters] backward show_text_glyphs */ /* [cx cy [glyphs]] show_glyphs */ if (utf8 != NULL && clusters != NULL) { _emit_string_literal (surface, utf8, utf8_len); - _cairo_output_stream_puts (surface->ctx->stream, " "); + _cairo_output_stream_puts (ctx->stream, " "); } matrix = surface->cr.current_ctm; @@ -2954,7 +3116,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, _cairo_scaled_font_freeze_cache (scaled_font); font_private = scaled_font->surface_private; - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "[%f %f ", ix, iy); @@ -2969,7 +3131,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, &scaled_glyph); if (unlikely (status)) { _cairo_scaled_font_thaw_cache (scaled_font); - return status; + goto BAIL; } if ((long unsigned) scaled_glyph->surface_private > 256) @@ -2978,10 +3140,10 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, } if (n == num_glyphs) { - _cairo_output_stream_puts (surface->ctx->stream, "<~"); - base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + _cairo_output_stream_puts (ctx->stream, "<~"); + base85_stream = _cairo_base85_stream_create (ctx->stream); } else - _cairo_output_stream_puts (surface->ctx->stream, "["); + _cairo_output_stream_puts (ctx->stream, "["); for (n = 0; n < num_glyphs; n++) { double dx, dy; @@ -2991,7 +3153,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); if (unlikely (status)) - break; + goto BAIL; if (fabs (glyphs[n].x - x) > 1e-5 || fabs (glyphs[n].y - y) > 1e-5) { if (fabs (glyphs[n].y - y) < 1e-5) { @@ -3002,11 +3164,11 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, break; } - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "~> %f <~", glyphs[n].x - x); - base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + base85_stream = _cairo_base85_stream_create (ctx->stream); } else { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " ] %f [ ", glyphs[n].x - x); } @@ -3024,12 +3186,12 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, break; } - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "~> %f %f <~", ix, iy); - base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + base85_stream = _cairo_base85_stream_create (ctx->stream); } else { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " ] %f %f [ ", ix, iy); } @@ -3046,10 +3208,10 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, _cairo_output_stream_write (base85_stream, &c, 1); } else { if (font_private->has_sfnt) - _cairo_output_stream_printf (surface->ctx->stream, " %lu", + _cairo_output_stream_printf (ctx->stream, " %lu", glyphs[n].index); else - _cairo_output_stream_printf (surface->ctx->stream, " %lu", + _cairo_output_stream_printf (ctx->stream, " %lu", (long unsigned) scaled_glyph->surface_private); } @@ -3068,9 +3230,9 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, if (status == CAIRO_STATUS_SUCCESS) status = status2; - _cairo_output_stream_printf (surface->ctx->stream, "~>"); + _cairo_output_stream_printf (ctx->stream, "~>"); } else { - _cairo_output_stream_puts (surface->ctx->stream, " ]"); + _cairo_output_stream_puts (ctx->stream, " ]"); } if (unlikely (status)) return status; @@ -3085,19 +3247,19 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, } if (n < num_clusters) { - _cairo_output_stream_puts (surface->ctx->stream, "] [ "); + _cairo_output_stream_puts (ctx->stream, "] [ "); for (n = 0; n < num_clusters; n++) { - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, "%d %d ", clusters[n].num_bytes, clusters[n].num_glyphs); } - _cairo_output_stream_puts (surface->ctx->stream, "]"); + _cairo_output_stream_puts (ctx->stream, "]"); } else { - _cairo_output_stream_puts (surface->ctx->stream, "] <~"); - base85_stream = _cairo_base85_stream_create (surface->ctx->stream); + _cairo_output_stream_puts (ctx->stream, "] <~"); + base85_stream = _cairo_base85_stream_create (ctx->stream); for (n = 0; n < num_clusters; n++) { uint8_t c[2]; c[0] = clusters[n].num_bytes; @@ -3106,24 +3268,21 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, } status = _cairo_output_stream_destroy (base85_stream); if (unlikely (status)) - return status; + goto BAIL; - _cairo_output_stream_puts (surface->ctx->stream, "~>"); + _cairo_output_stream_puts (ctx->stream, "~>"); } - _cairo_output_stream_printf (surface->ctx->stream, + _cairo_output_stream_printf (ctx->stream, " //%s show-text-glyphs\n", _direction_to_string (backward)); } else { - _cairo_output_stream_puts (surface->ctx->stream, + _cairo_output_stream_puts (ctx->stream, "] show-glyphs\n"); } - surface->is_clear = FALSE; - inactive (surface); - DONE: if (_cairo_surface_wrapper_is_active (&surface->wrapper)){ return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper, op, source, @@ -3136,6 +3295,10 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface, } return CAIRO_STATUS_SUCCESS; + +BAIL: + inactive (surface); + return status; } static cairo_bool_t @@ -3214,8 +3377,7 @@ _cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr) cr->current_antialias = CAIRO_ANTIALIAS_DEFAULT; _cairo_stroke_style_init (&cr->current_style); _cairo_pattern_init_solid (&cr->current_source.solid, - CAIRO_COLOR_BLACK, - CAIRO_CONTENT_COLOR); + CAIRO_COLOR_BLACK); _cairo_path_fixed_init (&cr->current_path); cairo_matrix_init_identity (&cr->current_ctm); cairo_matrix_init_identity (&cr->current_stroke_matrix); @@ -3256,6 +3418,7 @@ _cairo_script_surface_create_internal (cairo_script_context_t *ctx, _cairo_surface_init (&surface->base, &_cairo_script_surface_backend, + &ctx->base, content); _cairo_surface_wrapper_init (&surface->wrapper, passthrough); @@ -3263,15 +3426,11 @@ _cairo_script_surface_create_internal (cairo_script_context_t *ctx, _cairo_surface_clipper_init (&surface->clipper, _cairo_script_surface_clipper_intersect_clip_path); - surface->ctx = ctx; - ctx->ref++; - surface->width = width; surface->height = height; surface->emitted = FALSE; surface->defined = FALSE; - surface->is_clear = FALSE; surface->active = FALSE; surface->operand.type = SURFACE; cairo_list_init (&surface->operand.link); @@ -3281,25 +3440,28 @@ _cairo_script_surface_create_internal (cairo_script_context_t *ctx, return surface; } -static const cairo_script_context_t _nil_context = { - CAIRO_STATUS_NO_MEMORY, - -1 +static const cairo_device_backend_t _cairo_script_device_backend = { + CAIRO_DEVICE_TYPE_SCRIPT, + + NULL, NULL, /* lock, unlock */ + + _device_flush, /* flush */ + NULL, /* finish */ + _device_destroy }; -static cairo_script_context_t * +static cairo_device_t * _cairo_script_context_create_internal (cairo_output_stream_t *stream) { cairo_script_context_t *ctx; ctx = malloc (sizeof (cairo_script_context_t)); - if (unlikely (ctx == NULL)) { - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - return (cairo_script_context_t *) &_nil_context; - } + if (unlikely (ctx == NULL)) + return _cairo_device_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); memset (ctx, 0, sizeof (cairo_script_context_t)); - ctx->status = CAIRO_STATUS_SUCCESS; - ctx->ref = 1; + + _cairo_device_init (&ctx->base, &_cairo_script_device_backend); cairo_list_init (&ctx->operands); cairo_list_init (&ctx->deferred); @@ -3311,39 +3473,43 @@ _cairo_script_context_create_internal (cairo_output_stream_t *stream) _cairo_output_stream_puts (ctx->stream, "%!CairoScript\n"); - return ctx; + return &ctx->base; } -cairo_script_context_t * -cairo_script_context_create (const char *filename) +cairo_device_t * +cairo_script_create (const char *filename) { cairo_output_stream_t *stream; + cairo_status_t status; stream = _cairo_output_stream_create_for_filename (filename); - if (_cairo_output_stream_get_status (stream)) - return (cairo_script_context_t *) &_nil_context; + if ((status = _cairo_output_stream_get_status (stream))) + return _cairo_device_create_in_error (status); return _cairo_script_context_create_internal (stream); } -cairo_script_context_t * -cairo_script_context_create_for_stream (cairo_write_func_t write_func, - void *closure) +cairo_device_t * +cairo_script_create_for_stream (cairo_write_func_t write_func, + void *closure) { cairo_output_stream_t *stream; + cairo_status_t status; stream = _cairo_output_stream_create (write_func, NULL, closure); - if (_cairo_output_stream_get_status (stream)) - return (cairo_script_context_t *) &_nil_context; + if ((status = _cairo_output_stream_get_status (stream))) + return _cairo_device_create_in_error (status); return _cairo_script_context_create_internal (stream); } void -cairo_script_context_write_comment (cairo_script_context_t *context, - const char *comment, - int len) +cairo_script_write_comment (cairo_device_t *device, + const char *comment, + int len) { + cairo_script_context_t *context = (cairo_script_context_t *) device; + if (len < 0) len = strlen (comment); @@ -3353,43 +3519,59 @@ cairo_script_context_write_comment (cairo_script_context_t *context, } void -cairo_script_context_set_mode (cairo_script_context_t *context, - cairo_script_mode_t mode) +cairo_script_set_mode (cairo_device_t *device, + cairo_script_mode_t mode) { + cairo_script_context_t *context = (cairo_script_context_t *) device; + context->mode = mode; } cairo_script_mode_t -cairo_script_context_get_mode (cairo_script_context_t *context) +cairo_script_get_mode (cairo_device_t *device) { + cairo_script_context_t *context = (cairo_script_context_t *) device; + return context->mode; } cairo_surface_t * -cairo_script_surface_create (cairo_script_context_t *context, +cairo_script_surface_create (cairo_device_t *device, cairo_content_t content, double width, double height) { - return &_cairo_script_surface_create_internal (context, + if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_SCRIPT)) + return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + + if (unlikely (device->status)) + return _cairo_surface_create_in_error (device->status); + + return &_cairo_script_surface_create_internal ((cairo_script_context_t *) device, content, width, height, NULL)->base; } cairo_surface_t * -cairo_script_surface_create_for_target (cairo_script_context_t *context, +cairo_script_surface_create_for_target (cairo_device_t *device, cairo_surface_t *target) { cairo_rectangle_int_t extents; + if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_SCRIPT)) + return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + + if (unlikely (device->status)) + return _cairo_surface_create_in_error (device->status); + if (unlikely (target->status)) return _cairo_surface_create_in_error (target->status); if (! _cairo_surface_get_extents (target, &extents)) extents.width = extents.height = -1; - return &_cairo_script_surface_create_internal (context, + return &_cairo_script_surface_create_internal ((cairo_script_context_t *) device, target->content, extents.width, extents.height, @@ -3397,7 +3579,7 @@ cairo_script_surface_create_for_target (cairo_script_context_t *context, } cairo_status_t -cairo_script_from_recording_surface (cairo_script_context_t *context, +cairo_script_from_recording_surface (cairo_device_t *device, cairo_surface_t *recording_surface) { cairo_box_t bbox; @@ -3405,8 +3587,11 @@ cairo_script_from_recording_surface (cairo_script_context_t *context, cairo_surface_t *surface; cairo_status_t status; - if (unlikely (context->status)) - return context->status; + if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_SCRIPT)) + return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + + if (unlikely (device->status)) + return _cairo_error (device->status); if (unlikely (recording_surface->status)) return recording_surface->status; @@ -3421,7 +3606,7 @@ cairo_script_from_recording_surface (cairo_script_context_t *context, _cairo_box_round_to_rectangle (&bbox, &extents); - surface = &_cairo_script_surface_create_internal (context, + surface = &_cairo_script_surface_create_internal ((cairo_script_context_t *) device, recording_surface->content, extents.width, extents.height, @@ -3435,14 +3620,3 @@ cairo_script_from_recording_surface (cairo_script_context_t *context, return status; } - -void -cairo_script_context_destroy (cairo_script_context_t *context) -{ - cairo_status_t status_ignored; - - if (context == NULL || context->ref < 0) - return; - - status_ignored = _context_destroy (context); -} diff --git a/gfx/cairo/cairo/src/cairo-script.h b/gfx/cairo/cairo/src/cairo-script.h index 5af625c1016a..b82230f2f475 100644 --- a/gfx/cairo/cairo/src/cairo-script.h +++ b/gfx/cairo/cairo/src/cairo-script.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -42,48 +42,43 @@ CAIRO_BEGIN_DECLS -typedef struct _cairo_script_context cairo_script_context_t; - typedef enum { CAIRO_SCRIPT_MODE_BINARY, CAIRO_SCRIPT_MODE_ASCII } cairo_script_mode_t; -cairo_public cairo_script_context_t * -cairo_script_context_create (const char *filename); +cairo_public cairo_device_t * +cairo_script_create (const char *filename); -cairo_public cairo_script_context_t * -cairo_script_context_create_for_stream (cairo_write_func_t write_func, - void *closure); +cairo_public cairo_device_t * +cairo_script_create_for_stream (cairo_write_func_t write_func, + void *closure); cairo_public void -cairo_script_context_write_comment (cairo_script_context_t *context, - const char *comment, - int len); +cairo_script_write_comment (cairo_device_t *script, + const char *comment, + int len); cairo_public void -cairo_script_context_set_mode (cairo_script_context_t *context, - cairo_script_mode_t mode); +cairo_script_set_mode (cairo_device_t *script, + cairo_script_mode_t mode); cairo_public cairo_script_mode_t -cairo_script_context_get_mode (cairo_script_context_t *context); - -cairo_public void -cairo_script_context_destroy (cairo_script_context_t *context); +cairo_script_get_mode (cairo_device_t *script); cairo_public cairo_surface_t * -cairo_script_surface_create (cairo_script_context_t *context, +cairo_script_surface_create (cairo_device_t *script, cairo_content_t content, double width, double height); cairo_public cairo_surface_t * -cairo_script_surface_create_for_target (cairo_script_context_t *context, +cairo_script_surface_create_for_target (cairo_device_t *script, cairo_surface_t *target); cairo_public cairo_status_t -cairo_script_from_recording_surface (cairo_script_context_t *context, - cairo_surface_t *recording_surface); +cairo_script_from_recording_surface (cairo_device_t *script, + cairo_surface_t *recording_surface); CAIRO_END_DECLS diff --git a/gfx/cairo/cairo/src/cairo-skia.h b/gfx/cairo/cairo/src/cairo-skia.h index 046599faa312..f62823522478 100644 --- a/gfx/cairo/cairo/src/cairo-skia.h +++ b/gfx/cairo/cairo/src/cairo-skia.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -39,7 +39,7 @@ #include "cairo.h" -#ifdef CAIRO_HAS_SKIA_SURFACE +#if CAIRO_HAS_SKIA_SURFACE CAIRO_BEGIN_DECLS diff --git a/gfx/cairo/cairo/src/cairo-slope-private.h b/gfx/cairo/cairo/src/cairo-slope-private.h index 64f0dde381d1..6a58c9f456d6 100644 --- a/gfx/cairo/cairo/src/cairo-slope-private.h +++ b/gfx/cairo/cairo/src/cairo-slope-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-slope.c b/gfx/cairo/cairo/src/cairo-slope.c index bb3b411e6123..827037f76d52 100644 --- a/gfx/cairo/cairo/src/cairo-slope.c +++ b/gfx/cairo/cairo/src/cairo-slope.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-spans-private.h b/gfx/cairo/cairo/src/cairo-spans-private.h index af3b38ca9e02..00a4df868471 100644 --- a/gfx/cairo/cairo/src/cairo-spans-private.h +++ b/gfx/cairo/cairo/src/cairo-spans-private.h @@ -103,6 +103,54 @@ _cairo_tor_scan_converter_create (int xmin, int ymax, cairo_fill_rule_t fill_rule); +typedef struct _cairo_rectangular_scan_converter { + cairo_scan_converter_t base; + + int xmin, xmax; + int ymin, ymax; + + struct _cairo_rectangular_scan_converter_chunk { + struct _cairo_rectangular_scan_converter_chunk *next; + void *base; + int count; + int size; + } chunks, *tail; + char buf[CAIRO_STACK_BUFFER_SIZE]; + int num_rectangles; +} cairo_rectangular_scan_converter_t; + +cairo_private void +_cairo_rectangular_scan_converter_init (cairo_rectangular_scan_converter_t *self, + const cairo_rectangle_int_t *extents); + +cairo_private cairo_status_t +_cairo_rectangular_scan_converter_add_box (cairo_rectangular_scan_converter_t *self, + const cairo_box_t *box, + int dir); + +typedef struct _cairo_botor_scan_converter { + cairo_scan_converter_t base; + + cairo_box_t extents; + cairo_fill_rule_t fill_rule; + + int xmin, xmax; + + struct _cairo_botor_scan_converter_chunk { + struct _cairo_botor_scan_converter_chunk *next; + void *base; + int count; + int size; + } chunks, *tail; + char buf[CAIRO_STACK_BUFFER_SIZE]; + int num_edges; +} cairo_botor_scan_converter_t; + +cairo_private void +_cairo_botor_scan_converter_init (cairo_botor_scan_converter_t *self, + const cairo_box_t *extents, + cairo_fill_rule_t fill_rule); + /* cairo-spans.c: */ cairo_private cairo_scan_converter_t * @@ -138,16 +186,4 @@ _cairo_surface_composite_polygon (cairo_surface_t *surface, cairo_polygon_t *polygon, cairo_region_t *clip_region); -cairo_private cairo_status_t -_cairo_surface_composite_trapezoids_as_polygon (cairo_surface_t *surface, - cairo_operator_t op, - const cairo_pattern_t *pattern, - cairo_antialias_t antialias, - int src_x, int src_y, - int dst_x, int dst_y, - int width, int height, - cairo_trapezoid_t *traps, - int num_traps, - cairo_region_t *clip_region); - #endif /* CAIRO_SPANS_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-spans.c b/gfx/cairo/cairo/src/cairo-spans.c index 69894c11f50d..a187b899807f 100644 --- a/gfx/cairo/cairo/src/cairo-spans.c +++ b/gfx/cairo/cairo/src/cairo-spans.c @@ -26,6 +26,7 @@ */ #include "cairoint.h" +#include "cairo-composite-rectangles-private.h" #include "cairo-fixed-private.h" static cairo_scan_converter_t * @@ -38,10 +39,10 @@ _create_scan_converter (cairo_fill_rule_t fill_rule, return NULL; } - return _cairo_tor_scan_converter_create (rects->mask.x, - rects->mask.y, - rects->mask.x + rects->width, - rects->mask.y + rects->height, + return _cairo_tor_scan_converter_create (rects->bounded.x, + rects->bounded.y, + rects->bounded.x + rects->bounded.width, + rects->bounded.y + rects->bounded.height, fill_rule); } @@ -83,71 +84,6 @@ _cairo_surface_composite_polygon (cairo_surface_t *surface, return status; } -cairo_status_t -_cairo_surface_composite_trapezoids_as_polygon (cairo_surface_t *surface, - cairo_operator_t op, - const cairo_pattern_t *pattern, - cairo_antialias_t antialias, - int src_x, int src_y, - int dst_x, int dst_y, - int width, int height, - cairo_trapezoid_t *traps, - int num_traps, - cairo_region_t *clip_region) -{ - cairo_span_renderer_t *renderer; - cairo_scan_converter_t *converter; - cairo_composite_rectangles_t rects; - cairo_status_t status; - - rects.src.x = src_x; - rects.src.y = src_y; - rects.dst.x = dst_x; - rects.dst.y = dst_y; - rects.mask.x = dst_x; - rects.mask.y = dst_y; - rects.width = width; - rects.height = height; - - converter = _create_scan_converter (CAIRO_FILL_RULE_WINDING, - antialias, - &rects); - status = converter->status; - if (unlikely (status)) - goto CLEANUP_CONVERTER; - - while (num_traps--) { - status = converter->add_edge (converter, - &traps->left.p1, &traps->left.p2, - traps->top, traps->bottom, 1); - if (unlikely (status)) - goto CLEANUP_CONVERTER; - - status = converter->add_edge (converter, - &traps->right.p1, &traps->right.p2, - traps->top, traps->bottom, -1); - if (unlikely (status)) - goto CLEANUP_CONVERTER; - - traps++; - } - - renderer = _cairo_surface_create_span_renderer (op, pattern, surface, - antialias, &rects, - clip_region); - status = converter->generate (converter, renderer); - if (unlikely (status)) - goto CLEANUP_RENDERER; - - status = renderer->finish (renderer); - - CLEANUP_RENDERER: - renderer->destroy (renderer); - CLEANUP_CONVERTER: - converter->destroy (converter); - return status; -} - static void _cairo_nil_destroy (void *abstract) { @@ -266,6 +202,8 @@ _cairo_scan_converter_create_in_error (cairo_status_t status) case CAIRO_STATUS_NO_MEMORY: RETURN_NIL; case CAIRO_STATUS_INVALID_SIZE: RETURN_NIL; case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: RETURN_NIL; + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_DEVICE_ERROR: RETURN_NIL; default: break; } @@ -374,6 +312,8 @@ _cairo_span_renderer_create_in_error (cairo_status_t status) case CAIRO_STATUS_NO_MEMORY: RETURN_NIL; case CAIRO_STATUS_INVALID_SIZE: RETURN_NIL; case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: RETURN_NIL; + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_DEVICE_ERROR: RETURN_NIL; default: break; } diff --git a/gfx/cairo/cairo/src/cairo-spline.c b/gfx/cairo/cairo/src/cairo-spline.c index 132d9a516ef6..e75ff5ee3260 100644 --- a/gfx/cairo/cairo/src/cairo-spline.c +++ b/gfx/cairo/cairo/src/cairo-spline.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-stroke-style.c b/gfx/cairo/cairo/src/cairo-stroke-style.c index 36afeeb017ee..1513d1f358ed 100644 --- a/gfx/cairo/cairo/src/cairo-stroke-style.c +++ b/gfx/cairo/cairo/src/cairo-stroke-style.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -34,6 +34,7 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" void _cairo_stroke_style_init (cairo_stroke_style_t *style) @@ -52,7 +53,7 @@ _cairo_stroke_style_init (cairo_stroke_style_t *style) cairo_status_t _cairo_stroke_style_init_copy (cairo_stroke_style_t *style, - cairo_stroke_style_t *other) + const cairo_stroke_style_t *other) { if (CAIRO_INJECT_FAULT ()) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -144,6 +145,22 @@ _cairo_stroke_style_dash_period (const cairo_stroke_style_t *style) /* * Coefficient of the linear approximation (minimizing square difference) * of the surface covered by round caps + * + * This can be computed in the following way: + * the area inside the circle with radius w/2 and the region -d/2 <= x <= d/2 is: + * f(w,d) = 2 * integrate (sqrt (w*w/4 - x*x), x, -d/2, d/2) + * The square difference to a generic linear approximation (c*d) in the range (0,w) would be: + * integrate ((f(w,d) - c*d)^2, d, 0, w) + * To minimize this difference it is sufficient to find a solution of the differential with + * respect to c: + * solve ( diff (integrate ((f(w,d) - c*d)^2, d, 0, w), c), c) + * Which leads to c = 9/32*pi*w + * Since we're not interested in the true area, but just in a coverage extimate, + * we always divide the real area by the line width (w). + * The same computation for square caps would be + * f(w,d) = 2 * integrate(w/2, x, -d/2, d/2) + * c = 1*w + * but in this case it would not be an approximation, since f is already linear in d. */ #define ROUND_MINSQ_APPROXIMATION (9*M_PI/32) @@ -222,8 +239,8 @@ _cairo_stroke_style_dash_approximate (const cairo_stroke_style_t *style, scale = tolerance / _cairo_matrix_transformed_circle_major_axis (ctm, 1.0); /* We stop searching for a starting point as soon as the - offset reaches zero. Otherwise when an initial dash - segment shrinks to zero it will be skipped over. */ + * offset reaches zero. Otherwise when an initial dash + * segment shrinks to zero it will be skipped over. */ offset = style->dash_offset; while (offset > 0.0 && offset >= style->dash[i]) { offset -= style->dash[i]; @@ -234,8 +251,60 @@ _cairo_stroke_style_dash_approximate (const cairo_stroke_style_t *style, *num_dashes = 2; - dashes[0] = scale * coverage; - dashes[1] = scale * (1.0 - coverage); + /* + * We want to create a new dash pattern with the same relative coverage, + * but composed of just 2 elements with total length equal to scale. + * Based on the formula in _cairo_stroke_style_dash_stroked: + * scale * coverage = dashes[0] + cap_scale * MIN (dashes[1], line_width) + * = MIN (dashes[0] + cap_scale * (scale - dashes[0]), + * dashes[0] + cap_scale * line_width) = + * = MIN (dashes[0] * (1 - cap_scale) + cap_scale * scale, + * dashes[0] + cap_scale * line_width) + * + * Solving both cases we get: + * dashes[0] = scale * (coverage - cap_scale) / (1 - cap_scale) + * when scale - dashes[0] <= line_width + * dashes[0] = scale * coverage - cap_scale * line_width + * when scale - dashes[0] > line_width. + * + * Comparing the two cases we get: + * second > first + * second > scale * (coverage - cap_scale) / (1 - cap_scale) + * second - cap_scale * second - scale * coverage + scale * cap_scale > 0 + * (scale * coverage - cap_scale * line_width) - cap_scale * second - scale * coverage + scale * cap_scale > 0 + * - line_width - second + scale > 0 + * scale - second > line_width + * which is the condition for the second solution to be the valid one. + * So when second > first, the second solution is the correct one (i.e. + * the solution is always MAX (first, second). + */ + switch (style->line_cap) { + default: + ASSERT_NOT_REACHED; + dashes[0] = 0.0; + break; + + case CAIRO_LINE_CAP_BUTT: + /* Simplified formula (substituting 0 for cap_scale): */ + dashes[0] = scale * coverage; + break; + + case CAIRO_LINE_CAP_ROUND: + dashes[0] = MAX(scale * (coverage - ROUND_MINSQ_APPROXIMATION) / (1.0 - ROUND_MINSQ_APPROXIMATION), + scale * coverage - ROUND_MINSQ_APPROXIMATION * style->line_width); + break; + + case CAIRO_LINE_CAP_SQUARE: + /* + * Special attention is needed to handle the case cap_scale == 1 (since the first solution + * is either indeterminate or -inf in this case). Since dash lengths are always >=0, using + * 0 as first solution always leads to the correct solution. + */ + dashes[0] = MAX(0.0, scale * coverage - style->line_width); + break; + } + + dashes[1] = scale - dashes[0]; *dash_offset = on ? 0.0 : dashes[0]; } diff --git a/gfx/cairo/cairo/src/cairo-supported-features.h b/gfx/cairo/cairo/src/cairo-supported-features.h index 676b61e19cf3..aacbab78181d 100644 --- a/gfx/cairo/cairo/src/cairo-supported-features.h +++ b/gfx/cairo/cairo/src/cairo-supported-features.h @@ -6,13 +6,11 @@ #define CAIRO_HAS_XLIB_SURFACE 1 #define CAIRO_HAS_XLIB_XRENDER_SURFACE 1 -#define CAIRO_HAS_XCB_SHM_FUNCTIONS 1 #define CAIRO_HAS_QUARTZ_SURFACE 1 #define CAIRO_HAS_QUARTZ_FONT 1 #define CAIRO_HAS_WIN32_SURFACE 1 #define CAIRO_HAS_WIN32_FONT 1 #define CAIRO_HAS_PNG_FUNCTIONS 1 -#define CAIRO_HAS_EAGLE_FUNCTIONS 1 #define CAIRO_HAS_EGL_FUNCTIONS 1 #define CAIRO_HAS_GLX_FUNCTIONS 1 #define CAIRO_HAS_FT_FONT 1 @@ -21,9 +19,7 @@ #define CAIRO_HAS_PDF_SURFACE 1 #define CAIRO_HAS_SVG_SURFACE 1 #define CAIRO_HAS_IMAGE_SURFACE 1 -#define CAIRO_HAS_RECORDING_SURFACE 1 -#define CAIRO_HAS_TEE_SURFACE 1 -#define CAIRO_HAS_XML_SURFACE 1 +#define CAIRO_HAS_META_SURFACE 1 #define CAIRO_HAS_USER_FONT 1 #endif diff --git a/gfx/cairo/cairo/src/cairo-surface-clipper-private.h b/gfx/cairo/cairo/src/cairo-surface-clipper-private.h index f3d9de189391..b9ca3cb1cb55 100644 --- a/gfx/cairo/cairo/src/cairo-surface-clipper-private.h +++ b/gfx/cairo/cairo/src/cairo-surface-clipper-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-surface-clipper.c b/gfx/cairo/cairo/src/cairo-surface-clipper.c index 03610d165583..9487300477d4 100644 --- a/gfx/cairo/cairo/src/cairo-surface-clipper.c +++ b/gfx/cairo/cairo/src/cairo-surface-clipper.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -75,8 +75,11 @@ _cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper, if (clip == NULL && clipper->clip.path == NULL) return CAIRO_STATUS_SUCCESS; - if (clip != NULL && clip->path == clipper->clip.path) + if (clip != NULL && clipper->clip.path != NULL && + _cairo_clip_equal (clip, &clipper->clip)) + { return CAIRO_STATUS_SUCCESS; + } /* all clipped out state should never propagate this far */ assert (clip == NULL || clip->path != NULL); diff --git a/gfx/cairo/cairo/src/cairo-surface-fallback-private.h b/gfx/cairo/cairo/src/cairo-surface-fallback-private.h index c63c36e74957..e993de62eb1b 100644 --- a/gfx/cairo/cairo/src/cairo-surface-fallback-private.h +++ b/gfx/cairo/cairo/src/cairo-surface-fallback-private.h @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -59,9 +59,9 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip); diff --git a/gfx/cairo/cairo/src/cairo-surface-fallback.c b/gfx/cairo/cairo/src/cairo-surface-fallback.c index 316558d0be53..51893ee65881 100644 --- a/gfx/cairo/cairo/src/cairo-surface-fallback.c +++ b/gfx/cairo/cairo/src/cairo-surface-fallback.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -40,10 +40,13 @@ #include "cairoint.h" -#include "cairo-surface-fallback-private.h" +#include "cairo-boxes-private.h" #include "cairo-clip-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-error-private.h" #include "cairo-region-private.h" #include "cairo-spans-private.h" +#include "cairo-surface-fallback-private.h" typedef struct { cairo_surface_t *dst; @@ -124,22 +127,19 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern, const cairo_rectangle_int_t *extents) { cairo_surface_t *mask; - cairo_region_t *clip_region = NULL; - cairo_solid_pattern_t solid; + cairo_region_t *clip_region = NULL, *fallback_region = NULL; cairo_status_t status; cairo_bool_t clip_surface = FALSE; if (clip != NULL) { status = _cairo_clip_get_region (clip, &clip_region); - assert (! _cairo_status_is_error (status)); - - /* The all-clipped state should never propagate this far. */ - assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO); + if (unlikely (_cairo_status_is_error (status) || + status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + { + return status; + } clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; - - if (clip_region && cairo_region_num_rectangles (clip_region) == 1) - clip_region = NULL; } /* We need to use solid here, because to use CAIRO_OPERATOR_SOURCE with @@ -154,9 +154,20 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern, if (unlikely (mask->status)) return mask->status; - _cairo_pattern_init_solid (&solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_ALPHA); + if (clip_region && (extents->x || extents->y)) { + fallback_region = cairo_region_copy (clip_region); + status = fallback_region->status; + if (unlikely (status)) + goto CLEANUP_SURFACE; + + cairo_region_translate (fallback_region, + -extents->x, + -extents->y); + clip_region = fallback_region; + } + status = draw_func (draw_closure, CAIRO_OPERATOR_ADD, - &solid.base, mask, + &_cairo_pattern_white.base, mask, extents->x, extents->y, extents, clip_region); @@ -164,11 +175,13 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern, goto CLEANUP_SURFACE; if (clip_surface) - status = _cairo_clip_combine_with_surface (clip, mask, extents); + status = _cairo_clip_combine_with_surface (clip, mask, extents->x, extents->y); _cairo_pattern_init_for_surface (mask_pattern, mask); CLEANUP_SURFACE: + if (fallback_region) + cairo_region_destroy (fallback_region); cairo_surface_destroy (mask); return status; @@ -224,6 +237,7 @@ _clip_and_composite_combine (cairo_clip_t *clip, cairo_surface_pattern_t pattern; cairo_surface_pattern_t clip_pattern; cairo_surface_t *clip_surface; + int clip_x, clip_y; cairo_status_t status; /* We'd be better off here creating a surface identical in format @@ -268,36 +282,35 @@ _clip_and_composite_combine (cairo_clip_t *clip, goto CLEANUP_SURFACE; assert (clip->path != NULL); - clip_surface = _cairo_clip_get_surface (clip, dst); + clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y); if (unlikely (clip_surface->status)) goto CLEANUP_SURFACE; _cairo_pattern_init_for_surface (&clip_pattern, clip_surface); - cairo_surface_destroy (clip_surface); /* Combine that with the clip */ status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_IN, &clip_pattern.base, NULL, intermediate, - extents->x - clip->path->extents.x, - extents->y - clip->path->extents.y, + extents->x - clip_x, + extents->y - clip_y, 0, 0, 0, 0, extents->width, extents->height, NULL); if (unlikely (status)) - goto CLEANUP_SURFACE; + goto CLEANUP_CLIP; /* Punch the clip out of the destination */ status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT, &clip_pattern.base, NULL, dst, - extents->x - clip->path->extents.x, - extents->y - clip->path->extents.y, + extents->x - clip_x, + extents->y - clip_y, 0, 0, extents->x, extents->y, extents->width, extents->height, NULL); if (unlikely (status)) - goto CLEANUP_SURFACE; + goto CLEANUP_CLIP; /* Now add the two results together */ _cairo_pattern_init_for_surface (&pattern, intermediate); @@ -310,8 +323,9 @@ _clip_and_composite_combine (cairo_clip_t *clip, NULL); _cairo_pattern_fini (&pattern.base); - CLEANUP_SURFACE: + CLEANUP_CLIP: _cairo_pattern_fini (&clip_pattern.base); + CLEANUP_SURFACE: cairo_surface_destroy (intermediate); return status; @@ -334,13 +348,13 @@ _clip_and_composite_source (cairo_clip_t *clip, if (clip != NULL) { status = _cairo_clip_get_region (clip, &clip_region); - assert (! _cairo_status_is_error (status)); - if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) - return CAIRO_STATUS_SUCCESS; - + if (unlikely (_cairo_status_is_error (status) || + status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + { + return status; + } } - /* Create a surface that is mask IN clip */ status = _create_composite_mask_pattern (&mask_pattern, clip, @@ -411,7 +425,6 @@ _clip_and_composite (cairo_clip_t *clip, cairo_surface_t *dst, const cairo_rectangle_int_t *extents) { - cairo_solid_pattern_t solid_pattern; cairo_status_t status; if (_cairo_rectangle_empty (extents)) @@ -419,9 +432,7 @@ _clip_and_composite (cairo_clip_t *clip, return CAIRO_STATUS_SUCCESS; if (op == CAIRO_OPERATOR_CLEAR) { - _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - src = &solid_pattern.base; + src = &_cairo_pattern_white.base; op = CAIRO_OPERATOR_DEST_OUT; } @@ -436,9 +447,11 @@ _clip_and_composite (cairo_clip_t *clip, if (clip != NULL) { status = _cairo_clip_get_region (clip, &clip_region); - assert (! _cairo_status_is_error (status)); - if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) - return CAIRO_STATUS_SUCCESS; + if (unlikely (_cairo_status_is_error (status) || + status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + { + return status; + } clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; } @@ -456,7 +469,6 @@ _clip_and_composite (cairo_clip_t *clip, dst, extents); } } else { - status = draw_func (draw_closure, op, src, dst, 0, 0, @@ -479,32 +491,26 @@ _composite_trap_region (cairo_clip_t *clip, const cairo_rectangle_int_t *extents) { cairo_status_t status; - cairo_solid_pattern_t solid_pattern; cairo_surface_pattern_t mask_pattern; cairo_pattern_t *mask = NULL; int mask_x = 0, mask_y =0; if (clip != NULL) { cairo_surface_t *clip_surface = NULL; - const cairo_rectangle_int_t *clip_extents; + int clip_x, clip_y; - clip_surface = _cairo_clip_get_surface (clip, dst); + clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y); if (unlikely (clip_surface->status)) return clip_surface->status; if (op == CAIRO_OPERATOR_CLEAR) { - _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - src = &solid_pattern.base; + src = &_cairo_pattern_white.base; op = CAIRO_OPERATOR_DEST_OUT; } _cairo_pattern_init_for_surface (&mask_pattern, clip_surface); - cairo_surface_destroy (clip_surface); - - clip_extents = _cairo_clip_get_extents (clip); - mask_x = extents->x - clip_extents->x; - mask_y = extents->y - clip_extents->y; + mask_x = extents->x - clip_x; + mask_y = extents->y - clip_y; mask = &mask_pattern.base; } @@ -537,18 +543,34 @@ _composite_traps_draw_func (void *closure, cairo_region_t *clip_region) { cairo_composite_traps_info_t *info = closure; + cairo_status_t status; + cairo_region_t *extents_region = NULL; if (dst_x != 0 || dst_y != 0) _cairo_traps_translate (info->traps, - dst_x, - dst_y); - return _cairo_surface_composite_trapezoids (op, - src, dst, info->antialias, - extents->x, extents->y, - extents->x - dst_x, extents->y - dst_y, - extents->width, extents->height, - info->traps->traps, - info->traps->num_traps, - clip_region); + if (clip_region == NULL && + !_cairo_operator_bounded_by_source (op)) { + extents_region = cairo_region_create_rectangle (extents); + if (unlikely (extents_region->status)) + return extents_region->status; + cairo_region_translate (extents_region, -dst_x, -dst_y); + clip_region = extents_region; + } + + status = _cairo_surface_composite_trapezoids (op, + src, dst, info->antialias, + extents->x, extents->y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + info->traps->traps, + info->traps->num_traps, + clip_region); + + if (extents_region) + cairo_region_destroy (extents_region); + + return status; } enum { @@ -782,13 +804,15 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src, { cairo_region_t *trap_region = NULL; - status = _fill_rectangles (dst, op, src, traps, clip); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + if (_cairo_operator_bounded_by_source (op)) { + status = _fill_rectangles (dst, op, src, traps, clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; - status = _composite_rectangle (dst, op, src, traps, clip); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + status = _composite_rectangle (dst, op, src, traps, clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } status = _cairo_traps_extract_region (traps, &trap_region); if (unlikely (_cairo_status_is_error (status))) @@ -853,171 +877,37 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src, &traps_info, dst, extents); } -typedef struct { - cairo_polygon_t *polygon; - cairo_fill_rule_t fill_rule; - cairo_antialias_t antialias; -} cairo_composite_spans_info_t; - -static cairo_status_t -_composite_spans_draw_func (void *closure, - cairo_operator_t op, - const cairo_pattern_t *src, - cairo_surface_t *dst, - int dst_x, - int dst_y, - const cairo_rectangle_int_t *extents, - cairo_region_t *clip_region) -{ - cairo_composite_rectangles_t rects; - cairo_composite_spans_info_t *info = closure; - - _cairo_composite_rectangles_init (&rects, - extents->x, extents->y, - extents->width, extents->height); - - /* The incoming dst_x/y are where we're pretending the origin of - * the dst surface is -- *not* the offset of a rectangle where - * we'd like to place the result. */ - rects.dst.x -= dst_x; - rects.dst.y -= dst_y; - - return _cairo_surface_composite_polygon (dst, op, src, - info->fill_rule, - info->antialias, - &rects, - info->polygon, - clip_region); -} - -static cairo_status_t -_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip) -{ - if (clip != NULL) { - if (! _cairo_rectangle_intersect (extents, - _cairo_clip_get_extents (clip))) - { - return CAIRO_INT_STATUS_NOTHING_TO_DO; - } - - return _cairo_clip_rectangle (clip, extents); - } else if (_cairo_rectangle_empty (extents)) - return CAIRO_INT_STATUS_NOTHING_TO_DO; - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_bool_t -_clip_contains_rectangle (cairo_clip_t *clip, - const cairo_rectangle_int_t *rect) -{ - cairo_clip_path_t *clip_path; - - clip_path = clip->path; - - if (clip_path->extents.x > rect->x || - clip_path->extents.y > rect->y || - clip_path->extents.x + clip_path->extents.width < rect->x + rect->width || - clip_path->extents.y + clip_path->extents.height < rect->y + rect->height) - { - return FALSE; - } - - do { - cairo_box_t box; - - if (! _cairo_path_fixed_is_box (&clip_path->path, &box)) - return FALSE; - - if (box.p1.x > _cairo_fixed_from_int (rect->x) || - box.p1.y > _cairo_fixed_from_int (rect->y) || - box.p2.x < _cairo_fixed_from_int (rect->x + rect->width) || - box.p2.y < _cairo_fixed_from_int (rect->y + rect->height)) - { - return FALSE; - } - } while ((clip_path = clip_path->prev) != NULL); - - return TRUE; -} - -static inline cairo_status_t -_clip_to_boxes (cairo_clip_t **clip, - const cairo_rectangle_int_t *extents, - cairo_bool_t is_bounded, - cairo_box_t **boxes, - int *num_boxes) -{ - cairo_status_t status; - - if (*clip == NULL) { - status = CAIRO_STATUS_SUCCESS; - goto EXTENTS; - } - - status = _cairo_clip_get_boxes (*clip, boxes, num_boxes); - switch ((int) status) { - case CAIRO_STATUS_SUCCESS: - if (is_bounded) - *clip = NULL; - goto DONE; - - case CAIRO_INT_STATUS_UNSUPPORTED: - status = CAIRO_STATUS_SUCCESS; - goto EXTENTS; - } - - EXTENTS: - _cairo_box_from_rectangle (&(*boxes)[0], extents); - *num_boxes = 1; - DONE: - return status; -} - cairo_status_t _cairo_surface_fallback_paint (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_clip_t *clip) { - cairo_status_t status; - cairo_rectangle_int_t extents; - cairo_bool_t is_bounded; + cairo_composite_rectangles_t extents; + cairo_rectangle_int_t rect; cairo_clip_path_t *clip_path = clip ? clip->path : NULL; - cairo_box_t boxes_stack[32], *boxes = boxes_stack; + cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; + cairo_boxes_t boxes; int num_boxes = ARRAY_LENGTH (boxes_stack); + cairo_status_t status; cairo_traps_t traps; - is_bounded = _cairo_surface_get_extents (surface, &extents); - assert (is_bounded || clip); + if (!_cairo_surface_get_extents (surface, &rect)) + ASSERT_NOT_REACHED; - is_bounded = FALSE; - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_int_t source_extents; + status = _cairo_composite_rectangles_init_for_paint (&extents, + &rect, + op, source, + clip); + if (unlikely (status)) + return status; - _cairo_pattern_get_extents (source, &source_extents); - if (! _cairo_rectangle_intersect (&extents, &source_extents)) - return CAIRO_STATUS_SUCCESS; - - is_bounded = TRUE; - } - - if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents)) + if (_cairo_clip_contains_extents (clip, &extents)) clip = NULL; - status = _rectangle_intersect_clip (&extents, clip); - if (unlikely (status)) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; + status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); + if (unlikely (status)) return status; - } - - status = _clip_to_boxes (&clip, &extents, is_bounded, &boxes, &num_boxes); - if (unlikely (status)) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; - return status; - } /* If the clip cannot be reduced to a set of boxes, we will need to * use a clipmask. Paint is special as it is the only operation that @@ -1035,51 +925,70 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface, NULL); } - status = _cairo_traps_init_boxes (&traps, boxes, num_boxes); + /* meh, surface-fallback is dying anyway... */ + _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes); + status = _cairo_traps_init_boxes (&traps, &boxes); if (unlikely (status)) goto CLEANUP_BOXES; status = _clip_and_composite_trapezoids (source, op, surface, &traps, CAIRO_ANTIALIAS_DEFAULT, - clip, &extents); + clip, + extents.is_bounded ? &extents.bounded : &extents.unbounded); _cairo_traps_fini (&traps); CLEANUP_BOXES: - if (boxes != boxes_stack) - free (boxes); + if (clip_boxes != boxes_stack) + free (clip_boxes); return status; } static cairo_status_t -_cairo_surface_mask_draw_func (void *closure, - cairo_operator_t op, - const cairo_pattern_t *src, - cairo_surface_t *dst, - int dst_x, - int dst_y, +_cairo_surface_mask_draw_func (void *closure, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, const cairo_rectangle_int_t *extents, - cairo_region_t *clip_region) + cairo_region_t *clip_region) { cairo_pattern_t *mask = closure; + cairo_status_t status; + cairo_region_t *extents_region = NULL; + + if (clip_region == NULL && + !_cairo_operator_bounded_by_source (op)) { + extents_region = cairo_region_create_rectangle (extents); + if (unlikely (extents_region->status)) + return extents_region->status; + cairo_region_translate (extents_region, -dst_x, -dst_y); + clip_region = extents_region; + } if (src) { - return _cairo_surface_composite (op, - src, mask, dst, - extents->x, extents->y, - extents->x, extents->y, - extents->x - dst_x, extents->y - dst_y, - extents->width, extents->height, - clip_region); + status = _cairo_surface_composite (op, + src, mask, dst, + extents->x, extents->y, + extents->x, extents->y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + clip_region); } else { - return _cairo_surface_composite (op, - mask, NULL, dst, - extents->x, extents->y, - 0, 0, /* unused */ - extents->x - dst_x, extents->y - dst_y, - extents->width, extents->height, - clip_region); + status = _cairo_surface_composite (op, + mask, NULL, dst, + extents->x, extents->y, + 0, 0, /* unused */ + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + clip_region); } + + if (extents_region) + cairo_region_destroy (extents_region); + + return status; } cairo_status_t @@ -1089,48 +998,33 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface, const cairo_pattern_t *mask, cairo_clip_t *clip) { - cairo_rectangle_int_t extents; - cairo_bool_t is_bounded; + cairo_composite_rectangles_t extents; + cairo_rectangle_int_t rect; cairo_status_t status; - is_bounded = _cairo_surface_get_extents (surface, &extents); - assert (is_bounded || clip); + if (!_cairo_surface_get_extents (surface, &rect)) + ASSERT_NOT_REACHED; - is_bounded = FALSE; - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_int_t source_extents; + status = _cairo_composite_rectangles_init_for_mask (&extents, + &rect, + op, source, mask, clip); + if (unlikely (status)) + return status; - _cairo_pattern_get_extents (source, &source_extents); - if (! _cairo_rectangle_intersect (&extents, &source_extents)) - return CAIRO_STATUS_SUCCESS; - - is_bounded = TRUE; - } - - if (_cairo_operator_bounded_by_mask (op)) { - cairo_rectangle_int_t mask_extents; - - _cairo_pattern_get_extents (mask, &mask_extents); - if (! _cairo_rectangle_intersect (&extents, &mask_extents)) - return CAIRO_STATUS_SUCCESS; - - is_bounded = TRUE; - } - - if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents)) + if (_cairo_clip_contains_extents (clip, &extents)) clip = NULL; - status = _rectangle_intersect_clip (&extents, clip); - if (status) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; - return status; + if (clip != NULL && extents.is_bounded) { + status = _cairo_clip_rectangle (clip, &extents.bounded); + if (unlikely (status)) + return status; } return _clip_and_composite (clip, op, source, _cairo_surface_mask_draw_func, (void *) mask, - surface, &extents); + surface, + extents.is_bounded ? &extents.bounded : &extents.unbounded); } cairo_status_t @@ -1138,69 +1032,44 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) { cairo_polygon_t polygon; cairo_traps_t traps; - cairo_box_t boxes_stack[32], *boxes = boxes_stack; + cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; int num_boxes = ARRAY_LENGTH (boxes_stack); - cairo_rectangle_int_t extents; - cairo_bool_t is_bounded; + cairo_composite_rectangles_t extents; + cairo_rectangle_int_t rect; cairo_status_t status; - is_bounded = _cairo_surface_get_extents (surface, &extents); - assert (is_bounded || clip); + if (!_cairo_surface_get_extents (surface, &rect)) + ASSERT_NOT_REACHED; - is_bounded = FALSE; - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_int_t source_extents; + status = _cairo_composite_rectangles_init_for_stroke (&extents, + &rect, + op, source, + path, stroke_style, ctm, + clip); + if (unlikely (status)) + return status; - _cairo_pattern_get_extents (source, &source_extents); - if (! _cairo_rectangle_intersect (&extents, &source_extents)) - return CAIRO_STATUS_SUCCESS; - - is_bounded = TRUE; - } - - if (_cairo_operator_bounded_by_mask (op)) { - cairo_rectangle_int_t path_extents; - - _cairo_path_fixed_approximate_stroke_extents (path, - stroke_style, ctm, - &path_extents); - if (! _cairo_rectangle_intersect (&extents, &path_extents)) - return CAIRO_STATUS_SUCCESS; - - is_bounded = TRUE; - } - - if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents)) + if (_cairo_clip_contains_extents (clip, &extents)) clip = NULL; - status = _rectangle_intersect_clip (&extents, clip); - if (unlikely (status)) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; + status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); + if (unlikely (status)) return status; - } - - status = _clip_to_boxes (&clip, &extents, is_bounded, &boxes, &num_boxes); - if (unlikely (status)) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; - return status; - } _cairo_polygon_init (&polygon); - _cairo_polygon_limit (&polygon, boxes, num_boxes); + _cairo_polygon_limit (&polygon, clip_boxes, num_boxes); _cairo_traps_init (&traps); - _cairo_traps_limit (&traps, boxes, num_boxes); + _cairo_traps_limit (&traps, clip_boxes, num_boxes); if (path->is_rectilinear) { status = _cairo_path_fixed_stroke_rectilinear_to_traps (path, @@ -1226,26 +1095,11 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, goto DO_TRAPS; if (_cairo_operator_bounded_by_mask (op)) { - cairo_rectangle_int_t polygon_extents; - - _cairo_box_round_to_rectangle (&polygon.extents, &polygon_extents); - if (! _cairo_rectangle_intersect (&extents, &polygon_extents)) + _cairo_box_round_to_rectangle (&polygon.extents, &extents.mask); + if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask)) goto CLEANUP; } - if (_cairo_surface_check_span_renderer (op, source, surface, antialias)) { - cairo_composite_spans_info_t info; - - info.polygon = &polygon; - info.fill_rule = CAIRO_FILL_RULE_WINDING; - info.antialias = antialias; - - status = _clip_and_composite (clip, op, source, - _composite_spans_draw_func, - &info, surface, &extents); - goto CLEANUP; - } - /* Fall back to trapezoid fills. */ status = _cairo_bentley_ottmann_tessellate_polygon (&traps, &polygon, @@ -1256,12 +1110,13 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface, DO_TRAPS: status = _clip_and_composite_trapezoids (source, op, surface, &traps, antialias, - clip, &extents); + clip, + extents.is_bounded ? &extents.bounded : &extents.unbounded); CLEANUP: _cairo_traps_fini (&traps); _cairo_polygon_fini (&polygon); - if (boxes != boxes_stack) - free (boxes); + if (clip_boxes != boxes_stack) + free (clip_boxes); return status; } @@ -1278,67 +1133,35 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, { cairo_polygon_t polygon; cairo_traps_t traps; - cairo_box_t boxes_stack[32], *boxes = boxes_stack; + cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; int num_boxes = ARRAY_LENGTH (boxes_stack); - cairo_rectangle_int_t extents; - cairo_bool_t is_bounded; cairo_bool_t is_rectilinear; + cairo_composite_rectangles_t extents; + cairo_rectangle_int_t rect; cairo_status_t status; - is_bounded = _cairo_surface_get_extents (surface, &extents); - assert (is_bounded || clip); + if (!_cairo_surface_get_extents (surface, &rect)) + ASSERT_NOT_REACHED; - is_bounded = FALSE; - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_int_t source_extents; - - _cairo_pattern_get_extents (source, &source_extents); - if (! _cairo_rectangle_intersect (&extents, &source_extents)) - return CAIRO_STATUS_SUCCESS; - - is_bounded = TRUE; - } - - if (_cairo_operator_bounded_by_mask (op)) { - cairo_rectangle_int_t path_extents; - - _cairo_path_fixed_approximate_fill_extents (path, &path_extents); - if (! _cairo_rectangle_intersect (&extents, &path_extents)) - return CAIRO_STATUS_SUCCESS; - - is_bounded = TRUE; - } - - if (is_bounded) { - if (clip != NULL && _clip_contains_rectangle (clip, &extents)) - clip = NULL; - - if (clip != NULL && clip->path->prev == NULL && - _cairo_path_fixed_equal (&clip->path->path, path)) - { - clip = NULL; - } - } - - status = _rectangle_intersect_clip (&extents, clip); - if (unlikely (status)) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; + status = _cairo_composite_rectangles_init_for_fill (&extents, + &rect, + op, source, path, + clip); + if (unlikely (status)) return status; - } - status = _clip_to_boxes (&clip, &extents, is_bounded, &boxes, &num_boxes); - if (unlikely (status)) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; + if (_cairo_clip_contains_extents (clip, &extents)) + clip = NULL; + + status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); + if (unlikely (status)) return status; - } _cairo_traps_init (&traps); - _cairo_traps_limit (&traps, boxes, num_boxes); + _cairo_traps_limit (&traps, clip_boxes, num_boxes); _cairo_polygon_init (&polygon); - _cairo_polygon_limit (&polygon, boxes, num_boxes); + _cairo_polygon_limit (&polygon, clip_boxes, num_boxes); if (path->is_empty_fill) goto DO_TRAPS; @@ -1363,10 +1186,8 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, goto DO_TRAPS; if (_cairo_operator_bounded_by_mask (op)) { - cairo_rectangle_int_t polygon_extents; - - _cairo_box_round_to_rectangle (&polygon.extents, &polygon_extents); - if (! _cairo_rectangle_intersect (&extents, &polygon_extents)) + _cairo_box_round_to_rectangle (&polygon.extents, &extents.mask); + if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask)) goto CLEANUP; } @@ -1381,20 +1202,6 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, goto CLEANUP; } - - if (_cairo_surface_check_span_renderer (op, source, surface, antialias)) { - cairo_composite_spans_info_t info; - - info.polygon = &polygon; - info.fill_rule = fill_rule; - info.antialias = antialias; - - status = _clip_and_composite (clip, op, source, - _composite_spans_draw_func, - &info, surface, &extents); - goto CLEANUP; - } - /* Fall back to trapezoid fills. */ status = _cairo_bentley_ottmann_tessellate_polygon (&traps, &polygon, @@ -1405,12 +1212,13 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface, DO_TRAPS: status = _clip_and_composite_trapezoids (source, op, surface, &traps, antialias, - clip, &extents); + clip, + extents.is_bounded ? &extents.bounded : &extents.unbounded); CLEANUP: _cairo_traps_fini (&traps); _cairo_polygon_fini (&polygon); - if (boxes != boxes_stack) - free (boxes); + if (clip_boxes != boxes_stack) + free (clip_boxes); return status; } @@ -1433,6 +1241,16 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure { cairo_show_glyphs_info_t *glyph_info = closure; cairo_status_t status; + cairo_region_t *extents_region = NULL; + + if (clip_region == NULL && + !_cairo_operator_bounded_by_source (op)) { + extents_region = cairo_region_create_rectangle (extents); + if (unlikely (extents_region->status)) + return extents_region->status; + cairo_region_translate (extents_region, -dst_x, -dst_y); + clip_region = extents_region; + } /* Modifying the glyph array is fine because we know that this function * will be called only once, and we've already made a copy of the @@ -1457,19 +1275,24 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure glyph_info->glyphs, glyph_info->num_glyphs, clip_region); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; - return _cairo_scaled_font_show_glyphs (glyph_info->font, - op, - src, dst, - extents->x, extents->y, - extents->x - dst_x, - extents->y - dst_y, - extents->width, extents->height, - glyph_info->glyphs, - glyph_info->num_glyphs, - clip_region); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + status = _cairo_scaled_font_show_glyphs (glyph_info->font, + op, + src, dst, + extents->x, extents->y, + extents->x - dst_x, + extents->y - dst_y, + extents->width, extents->height, + glyph_info->glyphs, + glyph_info->num_glyphs, + clip_region); + } + + if (extents_region) + cairo_region_destroy (extents_region); + + return status; } cairo_status_t @@ -1481,50 +1304,31 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, cairo_scaled_font_t *scaled_font, cairo_clip_t *clip) { - cairo_status_t status; - cairo_rectangle_int_t extents; cairo_show_glyphs_info_t glyph_info; - cairo_bool_t is_bounded; + cairo_composite_rectangles_t extents; + cairo_rectangle_int_t rect; + cairo_status_t status; - is_bounded = _cairo_surface_get_extents (surface, &extents); - assert (is_bounded || clip); + if (!_cairo_surface_get_extents (surface, &rect)) + ASSERT_NOT_REACHED; - is_bounded = FALSE; - if (_cairo_operator_bounded_by_source (op)) { - cairo_rectangle_int_t source_extents; - - _cairo_pattern_get_extents (source, &source_extents); - if (! _cairo_rectangle_intersect (&extents, &source_extents)) - return CAIRO_STATUS_SUCCESS; - - is_bounded = TRUE; - } - - if (_cairo_operator_bounded_by_mask (op)) { - cairo_rectangle_int_t glyph_extents; - - status = _cairo_scaled_font_glyph_device_extents (scaled_font, - glyphs, - num_glyphs, - &glyph_extents, + status = _cairo_composite_rectangles_init_for_glyphs (&extents, + &rect, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, NULL); - if (unlikely (status)) - return status; + if (unlikely (status)) + return status; - if (! _cairo_rectangle_intersect (&extents, &glyph_extents)) - return CAIRO_STATUS_SUCCESS; - - is_bounded = TRUE; - } - - if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents)) + if (_cairo_clip_contains_rectangle (clip, &extents.mask)) clip = NULL; - status = _rectangle_intersect_clip (&extents, clip); - if (status) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; - return status; + if (clip != NULL && extents.is_bounded) { + status = _cairo_clip_rectangle (clip, &extents.bounded); + if (unlikely (status)) + return status; } glyph_info.font = scaled_font; @@ -1535,7 +1339,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface, _cairo_surface_old_show_glyphs_draw_func, &glyph_info, surface, - &extents); + extents.is_bounded ? &extents.bounded : &extents.unbounded); } cairo_surface_t * @@ -1603,11 +1407,8 @@ _cairo_surface_fallback_composite (cairo_operator_t op, cairo_status_t status; status = _fallback_init (&state, dst, dst_x, dst_y, width, height); - if (unlikely (status)) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; + if (unlikely (status)) return status; - } /* We know this will never fail with the image backend; but * instead of calling into it directly, we call @@ -1681,11 +1482,8 @@ _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface, } status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1); - if (unlikely (status)) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; + if (unlikely (status)) return status; - } /* If the fetched image isn't at 0,0, we need to offset the rectangles */ @@ -1739,11 +1537,8 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op, cairo_status_t status; status = _fallback_init (&state, dst, dst_x, dst_y, width, height); - if (unlikely (status)) { - if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) - status = CAIRO_STATUS_SUCCESS; + if (unlikely (status)) return status; - } /* If the destination image isn't at 0,0, we need to offset the trapezoids */ @@ -1782,12 +1577,13 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op, width, height, traps, num_traps, clip_region); + FAIL: if (offset_traps != NULL) free (offset_traps); - FAIL: if (fallback_region != NULL) cairo_region_destroy (fallback_region); + _fallback_fini (&state); return status; diff --git a/gfx/cairo/cairo/src/cairo-surface-offset-private.h b/gfx/cairo/cairo/src/cairo-surface-offset-private.h new file mode 100644 index 000000000000..b7877b3de4fe --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-surface-offset-private.h @@ -0,0 +1,95 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_OFFSET_PRIVATE_H +#define CAIRO_SURFACE_OFFSET_PRIVATE_H + +#include "cairo-types-private.h" + +CAIRO_BEGIN_DECLS + +cairo_private cairo_status_t +_cairo_surface_offset_paint (cairo_surface_t *target, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_offset_mask (cairo_surface_t *target, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_offset_stroke (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_offset_fill (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t*source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_offset_glyphs (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_clip_t *clip); + +#endif /* CAIRO_SURFACE_OFFSET_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-surface-offset.c b/gfx/cairo/cairo/src/cairo-surface-offset.c new file mode 100644 index 000000000000..fdbe1a124bed --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-surface-offset.c @@ -0,0 +1,342 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * Copyright © 2007 Adrian Johnson + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-surface-offset-private.h" + +/* A collection of routines to facilitate drawing to an alternate surface. */ + +static void +_copy_transformed_pattern (cairo_pattern_t *pattern, + const cairo_pattern_t *original, + const cairo_matrix_t *ctm_inverse) +{ + _cairo_pattern_init_static_copy (pattern, original); + + if (! _cairo_matrix_is_identity (ctm_inverse)) + _cairo_pattern_transform (pattern, ctm_inverse); +} + +cairo_status_t +_cairo_surface_offset_paint (cairo_surface_t *target, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_clip_t clip_copy, *dev_clip = clip; + cairo_pattern_union_t source_copy; + + if (unlikely (target->status)) + return target->status; + + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + if (x | y) { + cairo_matrix_t m; + + if (clip != NULL) { + cairo_matrix_init_translate (&m, -x, -y); + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); + if (unlikely (status)) + goto FINISH; + + dev_clip = &clip_copy; + } + + cairo_matrix_init_translate (&m, x, y); + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + } + + status = _cairo_surface_paint (target, op, source, dev_clip); + + FINISH: + if (dev_clip != clip) + _cairo_clip_reset (dev_clip); + + return status; +} + +cairo_status_t +_cairo_surface_offset_mask (cairo_surface_t *target, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_clip_t clip_copy, *dev_clip = clip; + cairo_pattern_union_t source_copy; + cairo_pattern_union_t mask_copy; + + if (unlikely (target->status)) + return target->status; + + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + if (x | y) { + cairo_matrix_t m; + + if (clip != NULL) { + cairo_matrix_init_translate (&m, -x, -y); + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); + if (unlikely (status)) + goto FINISH; + + dev_clip = &clip_copy; + } + + cairo_matrix_init_translate (&m, x, y); + _copy_transformed_pattern (&source_copy.base, source, &m); + _copy_transformed_pattern (&mask_copy.base, mask, &m); + source = &source_copy.base; + mask = &mask_copy.base; + } + + status = _cairo_surface_mask (target, op, + source, mask, + dev_clip); + + FINISH: + if (dev_clip != clip) + _cairo_clip_reset (dev_clip); + + return status; +} + +cairo_status_t +_cairo_surface_offset_stroke (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t*stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_path_fixed_t path_copy, *dev_path = path; + cairo_clip_t clip_copy, *dev_clip = clip; + cairo_matrix_t dev_ctm = *ctm; + cairo_matrix_t dev_ctm_inverse = *ctm_inverse; + cairo_pattern_union_t source_copy; + cairo_status_t status; + + if (unlikely (surface->status)) + return surface->status; + + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + if (x | y) { + cairo_matrix_t m; + + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); + if (unlikely (status)) + goto FINISH; + + _cairo_path_fixed_translate (&path_copy, + _cairo_fixed_from_int (-x), + _cairo_fixed_from_int (-y)); + dev_path = &path_copy; + + cairo_matrix_init_translate (&m, -x, -y); + cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); + if (clip != NULL) { + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); + if (unlikely (status)) + goto FINISH; + + dev_clip = &clip_copy; + } + + cairo_matrix_init_translate (&m, x, y); + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse); + } + + status = _cairo_surface_stroke (surface, op, source, + dev_path, stroke_style, + &dev_ctm, &dev_ctm_inverse, + tolerance, antialias, + dev_clip); + + FINISH: + if (dev_path != path) + _cairo_path_fixed_fini (dev_path); + if (dev_clip != clip) + _cairo_clip_reset (dev_clip); + + return status; +} + +cairo_status_t +_cairo_surface_offset_fill (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t*source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_path_fixed_t path_copy, *dev_path = path; + cairo_clip_t clip_copy, *dev_clip = clip; + cairo_pattern_union_t source_copy; + + if (unlikely (surface->status)) + return surface->status; + + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + if (x | y) { + cairo_matrix_t m; + + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); + if (unlikely (status)) + goto FINISH; + + _cairo_path_fixed_translate (&path_copy, + _cairo_fixed_from_int (-x), + _cairo_fixed_from_int (-y)); + dev_path = &path_copy; + + if (clip != NULL) { + cairo_matrix_init_translate (&m, -x, -y); + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); + if (unlikely (status)) + goto FINISH; + + dev_clip = &clip_copy; + } + + cairo_matrix_init_translate (&m, x, y); + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + } + + status = _cairo_surface_fill (surface, op, source, + dev_path, fill_rule, + tolerance, antialias, + dev_clip); + + FINISH: + if (dev_path != path) + _cairo_path_fixed_fini (dev_path); + if (dev_clip != clip) + _cairo_clip_reset (dev_clip); + + return status; +} + +cairo_status_t +_cairo_surface_offset_glyphs (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_clip_t clip_copy, *dev_clip = clip; + cairo_pattern_union_t source_copy; + cairo_glyph_t *dev_glyphs; + int i; + + if (unlikely (surface->status)) + return surface->status; + + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + + dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (dev_glyphs == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + + if (x | y) { + cairo_matrix_t m; + + if (clip != NULL) { + cairo_matrix_init_translate (&m, -x, -y); + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); + if (unlikely (status)) + goto FINISH; + + dev_clip = &clip_copy; + } + + cairo_matrix_init_translate (&m, x, y); + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + + for (i = 0; i < num_glyphs; i++) { + dev_glyphs[i].x -= x; + dev_glyphs[i].y -= y; + } + } + + status = _cairo_surface_show_text_glyphs (surface, op, source, + NULL, 0, + dev_glyphs, num_glyphs, + NULL, 0, 0, + scaled_font, + dev_clip); + + FINISH: + if (dev_clip != clip) + _cairo_clip_reset (dev_clip); + free (dev_glyphs); + + return status; +} diff --git a/gfx/cairo/cairo/src/cairo-surface-private.h b/gfx/cairo/cairo/src/cairo-surface-private.h index e569f18cbf5b..929bc70cb00b 100644 --- a/gfx/cairo/cairo/src/cairo-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-surface-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -41,6 +41,7 @@ #include "cairo.h" #include "cairo-types-private.h" +#include "cairo-list-private.h" #include "cairo-reference-count-private.h" #include "cairo-clip-private.h" @@ -48,6 +49,7 @@ typedef void (*cairo_surface_func_t) (cairo_surface_t *); struct _cairo_surface { const cairo_surface_backend_t *backend; + cairo_device_t *device; /* We allow surfaces to override the backend->type by shoving something * else into surface->type. This is for "wrapper" surfaces that want to @@ -63,6 +65,7 @@ struct _cairo_surface { unsigned finished : 1; unsigned is_clear : 1; unsigned has_font_options : 1; + unsigned owns_device : 1; unsigned permit_subpixel_antialiasing : 1; cairo_user_data_array_t user_data; @@ -70,6 +73,7 @@ struct _cairo_surface { cairo_matrix_t device_transform; cairo_matrix_t device_transform_inverse; + cairo_list_t device_transform_observers; /* The actual resolution of the device, in dots per inch. */ double x_resolution; @@ -85,8 +89,10 @@ struct _cairo_surface { /* A "snapshot" surface is immutable. See _cairo_surface_snapshot. */ cairo_surface_t *snapshot_of; cairo_surface_func_t snapshot_detach; - /* current snapshots of this surface */ - cairo_array_t snapshots; + /* current snapshots of this surface*/ + cairo_list_t snapshots; + /* place upon snapshot list */ + cairo_list_t snapshot; /* * Surface font options, falling back to backend's default options, diff --git a/gfx/cairo/cairo/src/cairo-surface-snapshot-private.h b/gfx/cairo/cairo/src/cairo-surface-snapshot-private.h new file mode 100644 index 000000000000..bbb2bf2a0a9f --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-surface-snapshot-private.h @@ -0,0 +1,48 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_SNAPSHOT_PRIVATE_H +#define CAIRO_SURFACE_SNAPSHOT_PRIVATE_H + +#include "cairo-surface-private.h" + +struct _cairo_surface_snapshot { + cairo_surface_t base; + + cairo_surface_t *target; + cairo_surface_t *clone; +}; + +#endif /* CAIRO_SURFACE_SNAPSHOT_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-surface-snapshot.c b/gfx/cairo/cairo/src/cairo-surface-snapshot.c new file mode 100644 index 000000000000..20cc6b9ade66 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-surface-snapshot.c @@ -0,0 +1,255 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-surface-snapshot-private.h" + +static cairo_status_t +_cairo_surface_snapshot_finish (void *abstract_surface) +{ + cairo_surface_snapshot_t *surface = abstract_surface; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (surface->clone != NULL) { + cairo_surface_finish (surface->clone); + status = surface->clone->status; + + cairo_surface_destroy (surface->clone); + } + + return status; +} + +static cairo_status_t +_cairo_surface_snapshot_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **extra_out) +{ + cairo_surface_snapshot_t *surface = abstract_surface; + + return _cairo_surface_acquire_source_image (surface->target, image_out, extra_out); +} + +static void +_cairo_surface_snapshot_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *extra) +{ + cairo_surface_snapshot_t *surface = abstract_surface; + + _cairo_surface_release_source_image (surface->target, image, extra); +} + +static cairo_bool_t +_cairo_surface_snapshot_get_extents (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_surface_snapshot_t *surface = abstract_surface; + + return _cairo_surface_get_extents (surface->target, extents); +} + +static const cairo_surface_backend_t _cairo_surface_snapshot_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT, + + NULL, /* create similar */ + _cairo_surface_snapshot_finish, + + _cairo_surface_snapshot_acquire_source_image, + _cairo_surface_snapshot_release_source_image, + NULL, NULL, /* acquire, release dest */ + NULL, /* clone similar */ + NULL, /* composite */ + NULL, /* fill rectangles */ + NULL, /* composite trapezoids */ + NULL, /* create span renderer */ + NULL, /* check span renderer */ + NULL, /* copy_page */ + NULL, /* show_page */ + _cairo_surface_snapshot_get_extents, +}; + +static void +_cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface) +{ + cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface; + cairo_image_surface_t *image; + cairo_image_surface_t *clone; + void *extra; + cairo_status_t status; + + /* We need to make an image copy of the original surface since the + * snapshot may exceed the lifetime of the original device, i.e. + * when we later need to use the snapshot the data may have already + * been lost. + */ + + status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra); + if (unlikely (status)) { + snapshot->target = _cairo_surface_create_in_error (status); + status = _cairo_surface_set_error (surface, status); + return; + } + + clone = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format (NULL, + image->pixman_format, + image->width, + image->height, + 0); + if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) { + if (clone->stride == image->stride) { + memcpy (clone->data, image->data, image->stride * image->height); + } else { + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, NULL, clone->pixman_image, + 0, 0, + 0, 0, + 0, 0, + image->width, image->height); + } + clone->base.is_clear = FALSE; + + snapshot->clone = &clone->base; + } else { + snapshot->clone = &clone->base; + status = _cairo_surface_set_error (surface, clone->base.status); + } + + _cairo_surface_release_source_image (snapshot->target, image, extra); + snapshot->target = snapshot->clone; + snapshot->base.type = snapshot->target->type; +} + +/** + * _cairo_surface_snapshot + * @surface: a #cairo_surface_t + * + * Make an immutable reference to @surface. It is an error to call a + * surface-modifying function on the result of this function. The + * resulting 'snapshot' is a lazily copied-on-write surface i.e. it + * remains a reference to the original surface until that surface is + * written to again, at which time a copy is made of the original surface + * and the snapshot then points to that instead. Multiple snapshots of the + * same unmodified surface point to the same copy. + * + * The caller owns the return value and should call + * cairo_surface_destroy() when finished with it. This function will not + * return %NULL, but will return a nil surface instead. + * + * Return value: The snapshot surface. Note that the return surface + * may not necessarily be of the same type as @surface. + **/ +cairo_surface_t * +_cairo_surface_snapshot (cairo_surface_t *surface) +{ + cairo_surface_snapshot_t *snapshot; + cairo_status_t status; + + if (unlikely (surface->status)) + return _cairo_surface_create_in_error (surface->status); + + if (surface->finished) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + if (surface->snapshot_of != NULL) + return cairo_surface_reference (surface); + + if (surface->backend->snapshot != NULL) { + cairo_surface_t *snap; + + snap = _cairo_surface_has_snapshot (surface, surface->backend); + if (snap != NULL) + return cairo_surface_reference (snap); + + snap = surface->backend->snapshot (surface); + if (snap != NULL) { + if (unlikely (snap->status)) + return snap; + + status = _cairo_surface_copy_mime_data (snap, surface); + if (unlikely (status)) { + cairo_surface_destroy (snap); + return _cairo_surface_create_in_error (status); + } + + snap->device_transform = surface->device_transform; + snap->device_transform_inverse = surface->device_transform_inverse; + + _cairo_surface_attach_snapshot (surface, snap, NULL); + + return snap; + } + } + + snapshot = (cairo_surface_snapshot_t *) + _cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend); + if (snapshot != NULL) + return cairo_surface_reference (&snapshot->base); + + snapshot = malloc (sizeof (cairo_surface_snapshot_t)); + if (unlikely (snapshot == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + _cairo_surface_init (&snapshot->base, + &_cairo_surface_snapshot_backend, + NULL, /* device */ + surface->content); + snapshot->base.type = surface->type; + + snapshot->target = surface; + snapshot->clone = NULL; + + status = _cairo_surface_copy_mime_data (&snapshot->base, surface); + if (unlikely (status)) { + cairo_surface_destroy (&snapshot->base); + return _cairo_surface_create_in_error (status); + } + + snapshot->base.device_transform = surface->device_transform; + snapshot->base.device_transform_inverse = surface->device_transform_inverse; + + _cairo_surface_attach_snapshot (surface, + &snapshot->base, + _cairo_surface_snapshot_copy_on_write); + + return &snapshot->base; +} diff --git a/gfx/cairo/cairo/src/cairo-surface-subsurface-private.h b/gfx/cairo/cairo/src/cairo-surface-subsurface-private.h new file mode 100644 index 000000000000..435e1eb83184 --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-surface-subsurface-private.h @@ -0,0 +1,49 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_SUBSURFACE_PRIVATE_H +#define CAIRO_SURFACE_SUBSURFACE_PRIVATE_H + +#include "cairo-surface-private.h" + +struct _cairo_surface_subsurface { + cairo_surface_t base; + + cairo_rectangle_int_t extents; + + cairo_surface_t *target; +}; + +#endif /* CAIRO_SURFACE_SUBSURFACE_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-surface-subsurface.c b/gfx/cairo/cairo/src/cairo-surface-subsurface.c new file mode 100644 index 000000000000..3cf8330248ee --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-surface-subsurface.c @@ -0,0 +1,552 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-recording-surface-private.h" +#include "cairo-surface-offset-private.h" +#include "cairo-surface-subsurface-private.h" + +static const cairo_surface_backend_t _cairo_surface_subsurface_backend; + +static cairo_status_t +_cairo_surface_subsurface_finish (void *abstract_surface) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + + cairo_surface_destroy (surface->target); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_surface_subsurface_create_similar (void *other, + cairo_content_t content, + int width, int height) +{ + cairo_surface_subsurface_t *surface = other; + return surface->target->backend->create_similar (surface->target, content, width, height); +} + +static cairo_int_status_t +_cairo_surface_subsurface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; + cairo_status_t status; + cairo_clip_t target_clip; + + _cairo_clip_init_copy (&target_clip, clip); + status = _cairo_clip_rectangle (&target_clip, &rect); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_surface_offset_paint (surface->target, + -surface->extents.x, -surface->extents.y, + op, source, &target_clip); + CLEANUP: + _cairo_clip_fini (&target_clip); + return status; +} + +static cairo_int_status_t +_cairo_surface_subsurface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; + cairo_status_t status; + cairo_clip_t target_clip; + + _cairo_clip_init_copy (&target_clip, clip); + status = _cairo_clip_rectangle (&target_clip, &rect); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_surface_offset_mask (surface->target, + -surface->extents.x, -surface->extents.y, + op, source, mask, &target_clip); + CLEANUP: + _cairo_clip_fini (&target_clip); + return status; +} + +static cairo_int_status_t +_cairo_surface_subsurface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; + cairo_status_t status; + cairo_clip_t target_clip; + + _cairo_clip_init_copy (&target_clip, clip); + status = _cairo_clip_rectangle (&target_clip, &rect); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_surface_offset_fill (surface->target, + -surface->extents.x, -surface->extents.y, + op, source, path, fill_rule, tolerance, antialias, + &target_clip); + CLEANUP: + _cairo_clip_fini (&target_clip); + return status; +} + +static cairo_int_status_t +_cairo_surface_subsurface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; + cairo_status_t status; + cairo_clip_t target_clip; + + _cairo_clip_init_copy (&target_clip, clip); + status = _cairo_clip_rectangle (&target_clip, &rect); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_surface_offset_stroke (surface->target, + -surface->extents.x, -surface->extents.y, + op, source, path, stroke_style, ctm, ctm_inverse, + tolerance, antialias, + &target_clip); + CLEANUP: + _cairo_clip_fini (&target_clip); + return status; +} + +static cairo_int_status_t +_cairo_surface_subsurface_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip, + int *remaining_glyphs) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; + cairo_status_t status; + cairo_clip_t target_clip; + + _cairo_clip_init_copy (&target_clip, clip); + status = _cairo_clip_rectangle (&target_clip, &rect); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_surface_offset_glyphs (surface->target, + -surface->extents.x, -surface->extents.y, + op, source, + scaled_font, glyphs, num_glyphs, + &target_clip); + *remaining_glyphs = 0; + CLEANUP: + _cairo_clip_fini (&target_clip); + return status; +} + +static cairo_status_t +_cairo_surface_subsurface_flush (void *abstract_surface) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_status_t status; + + status = CAIRO_STATUS_SUCCESS; + if (surface->target->backend->flush != NULL) + status = surface->target->backend->flush (surface->target); + + return status; +} + +static cairo_status_t +_cairo_surface_subsurface_mark_dirty (void *abstract_surface, + int x, int y, + int width, int height) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_status_t status; + + status = CAIRO_STATUS_SUCCESS; + if (surface->target->backend->mark_dirty_rectangle != NULL) { + cairo_rectangle_int_t rect, extents; + + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + + extents.x = extents.y = 0; + extents.width = surface->extents.width; + extents.height = surface->extents.height; + + if (_cairo_rectangle_intersect (&rect, &extents)) { + status = surface->target->backend->mark_dirty_rectangle (surface->target, + rect.x + surface->extents.x, + rect.y + surface->extents.y, + rect.width, rect.height); + } + } + + return status; +} + +static cairo_bool_t +_cairo_surface_subsurface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + + extents->x = 0; + extents->y = 0; + extents->width = surface->extents.width; + extents->height = surface->extents.height; + + return TRUE; +} + +static void +_cairo_surface_subsurface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + + if (surface->target->backend->get_font_options != NULL) + surface->target->backend->get_font_options (surface->target, options); +} + +struct extra { + cairo_image_surface_t *image; + void *image_extra; +}; + +static void +cairo_surface_paint_to_target (cairo_surface_t *target, + cairo_surface_subsurface_t *subsurface) +{ + cairo_t *cr; + + cr = cairo_create (target); + + cairo_set_source_surface (cr, + subsurface->target, + - subsurface->extents.x, + - subsurface->extents.y); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + cairo_destroy (cr); +} + +static cairo_status_t +_cairo_surface_subsurface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **extra_out) +{ + cairo_rectangle_int_t target_extents; + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_image_surface_t *image; + cairo_status_t status; + struct extra *extra; + uint8_t *data; + cairo_bool_t ret; + + if (surface->target->type == CAIRO_SURFACE_TYPE_RECORDING) { + cairo_recording_surface_t *meta = (cairo_recording_surface_t *) surface->target; + cairo_surface_t *snapshot; + + snapshot = _cairo_surface_has_snapshot (&surface->base, + &_cairo_image_surface_backend); + if (snapshot != NULL) { + *image_out = (cairo_image_surface_t *) cairo_surface_reference (snapshot); + *extra_out = NULL; + return CAIRO_STATUS_SUCCESS; + } + + if (! _cairo_surface_has_snapshot (&meta->base, + &_cairo_image_surface_backend)) + { + image = (cairo_image_surface_t *) + _cairo_image_surface_create_with_content (meta->content, + surface->extents.width, + surface->extents.height); + if (unlikely (image->base.status)) + return image->base.status; + + cairo_surface_paint_to_target (&image->base, surface); + + _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL); + + *image_out = image; + *extra_out = NULL; + return CAIRO_STATUS_SUCCESS; + } + } + + extra = malloc (sizeof (struct extra)); + if (unlikely (extra == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_surface_acquire_source_image (surface->target, &extra->image, &extra->image_extra); + if (unlikely (status)) + goto CLEANUP; + + ret = _cairo_surface_get_extents (&extra->image->base, &target_extents); + assert (ret); + + /* only copy if we need to perform sub-byte manipulation */ + if (PIXMAN_FORMAT_BPP (extra->image->pixman_format) >= 8 && + target_extents.x <= surface->extents.x && + target_extents.y <= surface->extents.y && + surface->extents.x + surface->extents.width <= target_extents.x + target_extents.width && + surface->extents.y + surface->extents.height <= target_extents.y + target_extents.height) { + + assert ((PIXMAN_FORMAT_BPP (extra->image->pixman_format) % 8) == 0); + + data = extra->image->data + surface->extents.y * extra->image->stride; + data += PIXMAN_FORMAT_BPP (extra->image->pixman_format) / 8 * surface->extents.x; + + image = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format (data, + extra->image->pixman_format, + surface->extents.width, + surface->extents.height, + extra->image->stride); + if (unlikely ((status = image->base.status))) + goto CLEANUP_IMAGE; + + image->base.is_clear = FALSE; + } else { + image = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format (NULL, + extra->image->pixman_format, + surface->extents.width, + surface->extents.height, + 0); + if (unlikely ((status = image->base.status))) + goto CLEANUP_IMAGE; + + cairo_surface_paint_to_target (&image->base, surface); + } + + *image_out = image; + *extra_out = extra; + return CAIRO_STATUS_SUCCESS; + +CLEANUP_IMAGE: + _cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra); +CLEANUP: + free (extra); + return status; +} + +static void +_cairo_surface_subsurface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *abstract_extra) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + + if (abstract_extra != NULL) { + struct extra *extra = abstract_extra; + + _cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra); + free (extra); + } + + cairo_surface_destroy (&image->base); +} + +static cairo_surface_t * +_cairo_surface_subsurface_snapshot (void *abstract_surface) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_surface_subsurface_t *snapshot; + + snapshot = malloc (sizeof (cairo_surface_subsurface_t)); + if (unlikely (snapshot == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&snapshot->base, + &_cairo_surface_subsurface_backend, + NULL, /* device */ + surface->target->content); + snapshot->target = _cairo_surface_snapshot (surface->target); + if (unlikely (snapshot->target->status)) { + cairo_status_t status; + + status = snapshot->target->status; + free (snapshot); + return _cairo_surface_create_in_error (status); + } + + snapshot->base.type = snapshot->target->type; + snapshot->extents = surface->extents; + + return &snapshot->base; +} + +static const cairo_surface_backend_t _cairo_surface_subsurface_backend = { + CAIRO_SURFACE_TYPE_SUBSURFACE, + _cairo_surface_subsurface_create_similar, + _cairo_surface_subsurface_finish, + + _cairo_surface_subsurface_acquire_source_image, + _cairo_surface_subsurface_release_source_image, + NULL, NULL, /* acquire, release dest */ + NULL, /* clone similar */ + NULL, /* composite */ + NULL, /* fill rectangles */ + NULL, /* composite trapezoids */ + NULL, /* create span renderer */ + NULL, /* check span renderer */ + NULL, /* copy_page */ + NULL, /* show_page */ + _cairo_surface_subsurface_get_extents, + NULL, /* old_show_glyphs */ + _cairo_surface_subsurface_get_font_options, + _cairo_surface_subsurface_flush, + _cairo_surface_subsurface_mark_dirty, + NULL, /* font_fini */ + NULL, /* glyph_fini */ + + _cairo_surface_subsurface_paint, + _cairo_surface_subsurface_mask, + _cairo_surface_subsurface_stroke, + _cairo_surface_subsurface_fill, + _cairo_surface_subsurface_glyphs, + + _cairo_surface_subsurface_snapshot, +}; + +/** + * cairo_surface_create_for_rectangle: + * @target: an existing surface for which the sub-surface will point to + * @x: the x-origin of the sub-surface from the top-left of the target surface (in device-space units) + * @y: the y-origin of the sub-surface from the top-left of the target surface (in device-space units) + * @width: width of the sub-surface (in device-space units) + * @height: height of the sub-surface (in device-space units) + * + * Create a new surface that is a rectangle within the target surface. + * All operations drawn to this surface are then clipped and translated + * onto the target surface. Nothing drawn via this sub-surface outside of + * its bounds is drawn onto the target surface, making this a useful method + * for passing constrained child surfaces to library routines that draw + * directly onto the parent surface, i.e. with no further backend allocations, + * double buffering or copies. + * + * The semantics of subsurfaces have not been finalized yet + * unless the rectangle is in full device units, is contained within + * the extents of the target surface, and the target or subsurface's + * device transforms are not changed. + * + * Return value: a pointer to the newly allocated surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if @other is already in an error state + * or any other error occurs. + * + * Since: 1.10 + **/ +cairo_surface_t * +cairo_surface_create_for_rectangle (cairo_surface_t *target, + double x, double y, + double width, double height) +{ + cairo_surface_subsurface_t *surface; + + if (unlikely (target->status)) + return _cairo_surface_create_in_error (target->status); + if (unlikely (target->finished)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + surface = malloc (sizeof (cairo_surface_subsurface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + assert (_cairo_matrix_is_translation (&target->device_transform)); + x += target->device_transform.x0; + y += target->device_transform.y0; + + _cairo_surface_init (&surface->base, + &_cairo_surface_subsurface_backend, + NULL, /* device */ + target->content); + + /* XXX forced integer alignment */ + surface->extents.x = ceil (x); + surface->extents.y = ceil (y); + surface->extents.width = floor (x + width) - surface->extents.x; + surface->extents.height = floor (y + height) - surface->extents.y; + + if (target->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + /* Maintain subsurfaces as 1-depth */ + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) target; + surface->extents.x += sub->extents.x; + surface->extents.y += sub->extents.y; + target = sub->target; + } + + surface->target = cairo_surface_reference (target); + + return &surface->base; +} +/* XXX observe mark-dirty */ diff --git a/gfx/cairo/cairo/src/cairo-surface-wrapper-private.h b/gfx/cairo/cairo/src/cairo-surface-wrapper-private.h index 658f5786c910..a1f05d386b23 100644 --- a/gfx/cairo/cairo/src/cairo-surface-wrapper-private.h +++ b/gfx/cairo/cairo/src/cairo-surface-wrapper-private.h @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -46,13 +46,18 @@ CAIRO_BEGIN_DECLS struct _cairo_surface_wrapper { cairo_surface_t *target; - /* any other information? */ + cairo_bool_t has_extents; + cairo_rectangle_int_t extents; }; cairo_private void _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper, cairo_surface_t *target); +cairo_private void +_cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper, + const cairo_rectangle_int_t *extents); + cairo_private void _cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper); @@ -85,9 +90,9 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip); @@ -102,9 +107,9 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, cairo_path_fixed_t *path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *stroke_ctm, - cairo_matrix_t *stroke_ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, cairo_clip_t *clip); diff --git a/gfx/cairo/cairo/src/cairo-surface-wrapper.c b/gfx/cairo/cairo/src/cairo-surface-wrapper.c index 05bd33405d1f..fb4b0577af6b 100644 --- a/gfx/cairo/cairo/src/cairo-surface-wrapper.c +++ b/gfx/cairo/cairo/src/cairo-surface-wrapper.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,19 +37,44 @@ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-surface-wrapper-private.h" /* A collection of routines to facilitate surface wrapping */ -static cairo_bool_t -_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper, - cairo_matrix_t *matrix) +static void +_copy_transformed_pattern (cairo_pattern_t *pattern, + const cairo_pattern_t *original, + const cairo_matrix_t *ctm_inverse) { - if (_cairo_matrix_is_identity (&wrapper->target->device_transform)) - return FALSE; + _cairo_pattern_init_static_copy (pattern, original); - *matrix = wrapper->target->device_transform; - return TRUE; + /* apply device_transform first so that it is transformed by ctm_inverse */ + if (original->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern; + cairo_surface_t *surface; + + surface_pattern = (cairo_surface_pattern_t *) original; + surface = surface_pattern->surface; + + if (_cairo_surface_has_device_transform (surface)) + _cairo_pattern_transform (pattern, &surface->device_transform); + } + + if (! _cairo_matrix_is_identity (ctm_inverse)) + _cairo_pattern_transform (pattern, ctm_inverse); +} + +static inline cairo_bool_t +_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper) +{ + return ! _cairo_matrix_is_identity (&wrapper->target->device_transform); +} + +static cairo_bool_t +_cairo_surface_wrapper_needs_extents_transform (cairo_surface_wrapper_t *wrapper) +{ + return wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y); } cairo_status_t @@ -72,56 +97,67 @@ _cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper, _cairo_surface_release_source_image (wrapper->target, image, image_extra); } -static void -_cairo_surface_wrapper_transform_pattern (cairo_surface_wrapper_t *wrapper, - cairo_pattern_t *pattern, - const cairo_pattern_t *original) -{ - _cairo_pattern_init_static_copy (pattern, original); - - if (_cairo_surface_has_device_transform (wrapper->target)) - _cairo_pattern_transform (pattern, - &wrapper->target->device_transform_inverse); -} - cairo_status_t _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_clip_t *clip) + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) { cairo_status_t status; - cairo_matrix_t device_transform; cairo_clip_t clip_copy, *dev_clip = clip; - cairo_pattern_union_t source_pattern; + cairo_pattern_union_t source_copy; + cairo_clip_t target_clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; - if (clip && clip->all_clipped) - return CAIRO_STATUS_SUCCESS; + if (wrapper->has_extents) { + _cairo_clip_init_copy (&target_clip, clip); + status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); + if (unlikely (status)) + goto FINISH; - if (clip != NULL) { - if (_cairo_surface_wrapper_needs_device_transform (wrapper, - &device_transform)) - { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, - &device_transform); + dev_clip = clip = &target_clip; + } + + if (clip && clip->all_clipped) { + status = CAIRO_STATUS_SUCCESS; + goto FINISH; + } + + if (_cairo_surface_wrapper_needs_device_transform (wrapper) || + _cairo_surface_wrapper_needs_extents_transform (wrapper)) + { + cairo_matrix_t m; + + cairo_matrix_init_identity (&m); + + if (_cairo_surface_wrapper_needs_extents_transform (wrapper)) + cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y); + + if (_cairo_surface_wrapper_needs_device_transform (wrapper)) + cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); + + if (clip != NULL) { + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); if (unlikely (status)) goto FINISH; - } else { - _cairo_clip_init_copy (&clip_copy, clip); + dev_clip = &clip_copy; } - dev_clip = &clip_copy; + status = cairo_matrix_invert (&m); + assert (status == CAIRO_STATUS_SUCCESS); + + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; } - _cairo_surface_wrapper_transform_pattern (wrapper, &source_pattern.base, source); - - status = _cairo_surface_paint (wrapper->target, op, &source_pattern.base, dev_clip); + status = _cairo_surface_paint (wrapper->target, op, source, dev_clip); FINISH: + if (wrapper->has_extents) + _cairo_clip_reset (&target_clip); if (dev_clip != clip) _cairo_clip_reset (dev_clip); return status; @@ -135,40 +171,64 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper, cairo_clip_t *clip) { cairo_status_t status; - cairo_matrix_t device_transform; cairo_clip_t clip_copy, *dev_clip = clip; - cairo_pattern_union_t source_pattern, mask_pattern; + cairo_pattern_union_t source_copy; + cairo_pattern_union_t mask_copy; + cairo_clip_t target_clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; - if (clip && clip->all_clipped) - return CAIRO_STATUS_SUCCESS; + if (wrapper->has_extents) { + _cairo_clip_init_copy (&target_clip, clip); + status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); + if (unlikely (status)) + goto FINISH; - if (clip != NULL) { - if (_cairo_surface_wrapper_needs_device_transform (wrapper, - &device_transform)) - { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, - &device_transform); + dev_clip = clip = &target_clip; + } + + if (clip && clip->all_clipped) { + status = CAIRO_STATUS_SUCCESS; + goto FINISH; + } + + if (_cairo_surface_wrapper_needs_device_transform (wrapper) || + _cairo_surface_wrapper_needs_extents_transform (wrapper)) + { + cairo_matrix_t m; + + cairo_matrix_init_identity (&m); + + if (_cairo_surface_wrapper_needs_extents_transform (wrapper)) + cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y); + + if (_cairo_surface_wrapper_needs_device_transform (wrapper)) + cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); + + if (clip != NULL) { + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); if (unlikely (status)) goto FINISH; - } else { - _cairo_clip_init_copy (&clip_copy, clip); + dev_clip = &clip_copy; } - dev_clip = &clip_copy; + status = cairo_matrix_invert (&m); + assert (status == CAIRO_STATUS_SUCCESS); + + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + + _copy_transformed_pattern (&mask_copy.base, mask, &m); + mask = &mask_copy.base; } - _cairo_surface_wrapper_transform_pattern (wrapper, &source_pattern.base, source); - _cairo_surface_wrapper_transform_pattern (wrapper, &mask_pattern.base, mask); - - status = _cairo_surface_mask (wrapper->target, op, - &source_pattern.base, &mask_pattern.base, - dev_clip); + status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip); FINISH: + if (wrapper->has_extents) + _cairo_clip_reset (&target_clip); if (dev_clip != clip) _cairo_clip_reset (dev_clip); return status; @@ -179,62 +239,85 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) { cairo_status_t status; - cairo_matrix_t device_transform; cairo_path_fixed_t path_copy, *dev_path = path; cairo_clip_t clip_copy, *dev_clip = clip; cairo_matrix_t dev_ctm = *ctm; cairo_matrix_t dev_ctm_inverse = *ctm_inverse; - cairo_pattern_union_t source_pattern; + cairo_pattern_union_t source_copy; + cairo_clip_t target_clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; - if (clip && clip->all_clipped) - return CAIRO_STATUS_SUCCESS; + if (wrapper->has_extents) { + _cairo_clip_init_copy (&target_clip, clip); + status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); + if (unlikely (status)) + goto FINISH; - if (_cairo_surface_wrapper_needs_device_transform (wrapper, - &device_transform)) + dev_clip = clip = &target_clip; + } + + if (clip && clip->all_clipped) { + status = CAIRO_STATUS_SUCCESS; + goto FINISH; + } + + if (_cairo_surface_wrapper_needs_device_transform (wrapper) || + _cairo_surface_wrapper_needs_extents_transform (wrapper)) { + cairo_matrix_t m; + + cairo_matrix_init_identity (&m); + + if (_cairo_surface_wrapper_needs_extents_transform (wrapper)) + cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y); + + if (_cairo_surface_wrapper_needs_device_transform (wrapper)) + cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); if (unlikely (status)) goto FINISH; - _cairo_path_fixed_transform (&path_copy, &device_transform); + _cairo_path_fixed_transform (&path_copy, &m); dev_path = &path_copy; if (clip != NULL) { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, - &device_transform); + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); if (unlikely (status)) goto FINISH; dev_clip = &clip_copy; } - cairo_matrix_multiply (&dev_ctm, &dev_ctm, &device_transform); - status = cairo_matrix_invert (&device_transform); + cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); + + status = cairo_matrix_invert (&m); assert (status == CAIRO_STATUS_SUCCESS); - cairo_matrix_multiply (&dev_ctm_inverse, - &device_transform, - &dev_ctm_inverse); - } else { + + cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse); + + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + } + else + { if (clip != NULL) { dev_clip = &clip_copy; _cairo_clip_init_copy (&clip_copy, clip); } } - _cairo_surface_wrapper_transform_pattern (wrapper, &source_pattern.base, source); - - status = _cairo_surface_stroke (wrapper->target, op, &source_pattern.base, + status = _cairo_surface_stroke (wrapper->target, op, source, dev_path, stroke_style, &dev_ctm, &dev_ctm_inverse, tolerance, antialias, @@ -243,6 +326,8 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, FINISH: if (dev_path != path) _cairo_path_fixed_fini (dev_path); + if (wrapper->has_extents) + _cairo_clip_reset (&target_clip); if (dev_clip != clip) _cairo_clip_reset (dev_clip); return status; @@ -258,67 +343,93 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, cairo_path_fixed_t *path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *stroke_ctm, - cairo_matrix_t *stroke_ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, cairo_clip_t *clip) { cairo_status_t status; - cairo_matrix_t device_transform; cairo_path_fixed_t path_copy, *dev_path = path; cairo_clip_t clip_copy, *dev_clip = clip; cairo_matrix_t dev_ctm = *stroke_ctm; cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse; - cairo_pattern_union_t fill_pattern, stroke_pattern; + cairo_pattern_union_t stroke_source_copy; + cairo_pattern_union_t fill_source_copy; + cairo_clip_t target_clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; - if (clip && clip->all_clipped) - return CAIRO_STATUS_SUCCESS; + if (wrapper->has_extents) { + _cairo_clip_init_copy (&target_clip, clip); + status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); + if (unlikely (status)) + goto FINISH; - if (_cairo_surface_wrapper_needs_device_transform (wrapper, - &device_transform)) + dev_clip = clip = &target_clip; + } + + if (clip && clip->all_clipped) { + status = CAIRO_STATUS_SUCCESS; + goto FINISH; + } + + if (_cairo_surface_wrapper_needs_device_transform (wrapper) || + _cairo_surface_wrapper_needs_extents_transform (wrapper)) { + cairo_matrix_t m; + + cairo_matrix_init_identity (&m); + + if (_cairo_surface_wrapper_needs_extents_transform (wrapper)) + cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y); + + if (_cairo_surface_wrapper_needs_device_transform (wrapper)) + cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); if (unlikely (status)) goto FINISH; - _cairo_path_fixed_transform (&path_copy, &device_transform); + _cairo_path_fixed_transform (&path_copy, &m); dev_path = &path_copy; if (clip != NULL) { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, - &device_transform); + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); if (unlikely (status)) goto FINISH; dev_clip = &clip_copy; } - cairo_matrix_multiply (&dev_ctm, &dev_ctm, &device_transform); - status = cairo_matrix_invert (&device_transform); + cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); + + status = cairo_matrix_invert (&m); assert (status == CAIRO_STATUS_SUCCESS); - cairo_matrix_multiply (&dev_ctm_inverse, - &device_transform, - &dev_ctm_inverse); - } else { + + cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse); + + _copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m); + stroke_source = &stroke_source_copy.base; + + _copy_transformed_pattern (&fill_source_copy.base, fill_source, &m); + fill_source = &fill_source_copy.base; + } + else + { if (clip != NULL) { dev_clip = &clip_copy; _cairo_clip_init_copy (&clip_copy, clip); } } - _cairo_surface_wrapper_transform_pattern (wrapper, &fill_pattern.base, fill_source); - _cairo_surface_wrapper_transform_pattern (wrapper, &stroke_pattern.base, stroke_source); - status = _cairo_surface_fill_stroke (wrapper->target, - fill_op, &fill_pattern.base, fill_rule, + fill_op, fill_source, fill_rule, fill_tolerance, fill_antialias, dev_path, - stroke_op, &stroke_pattern.base, + stroke_op, stroke_source, stroke_style, &dev_ctm, &dev_ctm_inverse, stroke_tolerance, stroke_antialias, @@ -327,6 +438,8 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, FINISH: if (dev_path != path) _cairo_path_fixed_fini (dev_path); + if (wrapper->has_extents) + _cairo_clip_reset (&target_clip); if (dev_clip != clip) _cairo_clip_reset (dev_clip); return status; @@ -343,46 +456,71 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, cairo_clip_t *clip) { cairo_status_t status; - cairo_matrix_t device_transform; cairo_path_fixed_t path_copy, *dev_path = path; cairo_clip_t clip_copy, *dev_clip = clip; - cairo_pattern_union_t source_pattern; + cairo_pattern_union_t source_copy; + cairo_clip_t target_clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; - if (clip && clip->all_clipped) - return CAIRO_STATUS_SUCCESS; + if (wrapper->has_extents) { + _cairo_clip_init_copy (&target_clip, clip); + status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); + if (unlikely (status)) + goto FINISH; - if (_cairo_surface_wrapper_needs_device_transform (wrapper, - &device_transform)) + dev_clip = clip = &target_clip; + } + + if (clip && clip->all_clipped) { + status = CAIRO_STATUS_SUCCESS; + goto FINISH; + } + + if (_cairo_surface_wrapper_needs_device_transform (wrapper) || + _cairo_surface_wrapper_needs_extents_transform (wrapper)) { + cairo_matrix_t m; + + cairo_matrix_init_identity (&m); + + if (_cairo_surface_wrapper_needs_extents_transform (wrapper)) + cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y); + + if (_cairo_surface_wrapper_needs_device_transform (wrapper)) + cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); if (unlikely (status)) goto FINISH; - _cairo_path_fixed_transform (&path_copy, &device_transform); + _cairo_path_fixed_transform (&path_copy, &m); dev_path = &path_copy; if (clip != NULL) { - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, - &device_transform); + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); if (unlikely (status)) goto FINISH; dev_clip = &clip_copy; } - } else { + + status = cairo_matrix_invert (&m); + assert (status == CAIRO_STATUS_SUCCESS); + + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + } + else + { if (clip != NULL) { dev_clip = &clip_copy; _cairo_clip_init_copy (&clip_copy, clip); } } - _cairo_surface_wrapper_transform_pattern (wrapper, &source_pattern.base, source); - - status = _cairo_surface_fill (wrapper->target, op, - &source_pattern.base, + status = _cairo_surface_fill (wrapper->target, op, source, dev_path, fill_rule, tolerance, antialias, dev_clip); @@ -390,6 +528,8 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, FINISH: if (dev_path != path) _cairo_path_fixed_fini (dev_path); + if (wrapper->has_extents) + _cairo_clip_reset (&target_clip); if (dev_clip != clip) _cairo_clip_reset (dev_clip); return status; @@ -410,10 +550,10 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, cairo_clip_t *clip) { cairo_status_t status; - cairo_matrix_t device_transform; - cairo_pattern_union_t source_pattern; cairo_clip_t clip_copy, *dev_clip = clip; cairo_glyph_t *dev_glyphs = glyphs; + cairo_pattern_union_t source_copy; + cairo_clip_t target_clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; @@ -421,20 +561,40 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, if (glyphs == NULL || num_glyphs == 0) return CAIRO_STATUS_SUCCESS; - if (clip && clip->all_clipped) - return CAIRO_STATUS_SUCCESS; + if (wrapper->has_extents) { + _cairo_clip_init_copy (&target_clip, clip); + status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); + if (unlikely (status)) + goto FINISH; - if (_cairo_surface_wrapper_needs_device_transform (wrapper, - &device_transform)) + dev_clip = clip = &target_clip; + } + + if (clip && clip->all_clipped) { + status = CAIRO_STATUS_SUCCESS; + goto FINISH; + } + + if (_cairo_surface_wrapper_needs_device_transform (wrapper) || + _cairo_surface_wrapper_needs_extents_transform (wrapper)) { + cairo_matrix_t m; int i; + cairo_matrix_init_identity (&m); + + if (_cairo_surface_wrapper_needs_extents_transform (wrapper)) + cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y); + + if (_cairo_surface_wrapper_needs_device_transform (wrapper)) + cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); + if (clip != NULL) { - dev_clip = &clip_copy; - status = _cairo_clip_init_copy_transformed (&clip_copy, clip, - &device_transform); + status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); if (unlikely (status)) goto FINISH; + + dev_clip = &clip_copy; } dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); @@ -445,30 +605,36 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, for (i = 0; i < num_glyphs; i++) { dev_glyphs[i] = glyphs[i]; - cairo_matrix_transform_point (&device_transform, - &dev_glyphs[i].x, - &dev_glyphs[i].y); + cairo_matrix_transform_point (&m, &dev_glyphs[i].x, &dev_glyphs[i].y); } - } else { + + status = cairo_matrix_invert (&m); + assert (status == CAIRO_STATUS_SUCCESS); + + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + } + else + { if (clip != NULL) { dev_clip = &clip_copy; _cairo_clip_init_copy (&clip_copy, clip); } } - _cairo_surface_wrapper_transform_pattern (wrapper, &source_pattern.base, source); - - status = _cairo_surface_show_text_glyphs (wrapper->target, op, - &source_pattern.base, + status = _cairo_surface_show_text_glyphs (wrapper->target, op, source, utf8, utf8_len, dev_glyphs, num_glyphs, clusters, num_clusters, cluster_flags, scaled_font, dev_clip); + FINISH: if (dev_clip != clip) _cairo_clip_reset (dev_clip); + if (wrapper->has_extents) + _cairo_clip_reset (&target_clip); if (dev_glyphs != glyphs) free (dev_glyphs); return status; @@ -480,17 +646,36 @@ _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper, int width, int height) { - return _cairo_surface_create_similar_solid (wrapper->target, - content, width, height, - CAIRO_COLOR_TRANSPARENT, - TRUE); + return _cairo_surface_create_similar_scratch (wrapper->target, + content, width, height); } cairo_bool_t _cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper, cairo_rectangle_int_t *extents) { - return _cairo_surface_get_extents (wrapper->target, extents); + if (wrapper->has_extents) { + if (_cairo_surface_get_extents (wrapper->target, extents)) + _cairo_rectangle_intersect (extents, &wrapper->extents); + else + *extents = wrapper->extents; + + return TRUE; + } else { + return _cairo_surface_get_extents (wrapper->target, extents); + } +} + +void +_cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper, + const cairo_rectangle_int_t *extents) +{ + if (extents != NULL) { + wrapper->extents = *extents; + wrapper->has_extents = TRUE; + } else { + wrapper->has_extents = FALSE; + } } void @@ -517,6 +702,7 @@ _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper, cairo_surface_t *target) { wrapper->target = cairo_surface_reference (target); + wrapper->has_extents = FALSE; } void diff --git a/gfx/cairo/cairo/src/cairo-surface.c b/gfx/cairo/cairo/src/cairo-surface.c index c3f6f03a7ef7..cb6ada9c7225 100644 --- a/gfx/cairo/cairo/src/cairo-surface.c +++ b/gfx/cairo/cairo/src/cairo-surface.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -40,13 +40,63 @@ #include "cairo-surface-fallback-private.h" #include "cairo-clip-private.h" +#include "cairo-device-private.h" +#include "cairo-error-private.h" #include "cairo-recording-surface-private.h" #include "cairo-region-private.h" #include "cairo-tee-surface-private.h" +/** + * SECTION:cairo-surface + * @Title: cairo_surface_t + * @Short_Description: Base class for surfaces + * @See_Also: #cairo_t, #cairo_pattern_t + * + * #cairo_surface_t is the abstract type representing all different drawing + * targets that cairo can render to. The actual drawings are + * performed using a cairo context. + * + * A cairo surface is created by using backend-specific + * constructors, typically of the form + * cairo_backend_surface_create(). + * + * Most surface types allow accessing the surface without using Cairo + * functions. If you do this, keep in mind that it is mandatory that you call + * cairo_surface_flush() before reading from or writing to the surface and that + * you must use cairo_surface_mark_dirty() after modifying it. + * + * Directly modifying an image surface + * + * void + * modify_image_surface (cairo_surface_t *surface) + * { + * unsigned char *data; + * int width, height, stride; + * + * // flush to ensure all writing to the image was done + * cairo_surface_flush (surface); + * + * // modify the image + * data = cairo_image_surface_get_data (surface); + * width = cairo_image_surface_get_width (surface); + * height = cairo_image_surface_get_height (surface); + * stride = cairo_image_surface_get_stride (surface); + * modify_image_data (data, width, height, stride); + * + * // mark the image dirty so Cairo clears its caches. + * cairo_surface_mark_dirty (surface); + * } + * + * + * Note that for other surface types it might be necessary to acquire the + * surface's device first. See cairo_device_acquire() for a discussion of + * devices. + */ + #define DEFINE_NIL_SURFACE(status, name) \ const cairo_surface_t name = { \ NULL, /* backend */ \ + NULL, /* device */ \ CAIRO_SURFACE_TYPE_IMAGE, /* type */ \ CAIRO_CONTENT_COLOR, /* content */ \ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \ @@ -54,27 +104,28 @@ const cairo_surface_t name = { \ 0, /* unique id */ \ FALSE, /* finished */ \ TRUE, /* is_clear */ \ - FALSE, /* has_font_options */ \ - FALSE, /* permit_subpixel_antialiasing */ \ + FALSE, /* has_font_options */ \ + FALSE, /* owns_device */ \ + FALSE, /* permit_subpixel_antialiasing */ \ { 0, 0, 0, NULL, }, /* user_data */ \ { 0, 0, 0, NULL, }, /* mime_data */ \ { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform */ \ { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform_inverse */ \ + { NULL, NULL }, /* device_transform_observers */ \ 0.0, /* x_resolution */ \ 0.0, /* y_resolution */ \ 0.0, /* x_fallback_resolution */ \ 0.0, /* y_fallback_resolution */ \ NULL, /* snapshot_of */ \ NULL, /* snapshot_detach */ \ - { 0, /* size */ \ - 0, /* num_elements */ \ - 0, /* element_size */ \ - NULL, /* elements */ \ - }, /* snapshots */ \ + { NULL, NULL }, /* snapshots */ \ + { NULL, NULL }, /* snapshot */ \ { CAIRO_ANTIALIAS_DEFAULT, /* antialias */ \ CAIRO_SUBPIXEL_ORDER_DEFAULT, /* subpixel_order */ \ + CAIRO_LCD_FILTER_DEFAULT, /* lcd_filter */ \ CAIRO_HINT_STYLE_DEFAULT, /* hint_style */ \ - CAIRO_HINT_METRICS_DEFAULT /* hint_metrics */ \ + CAIRO_HINT_METRICS_DEFAULT, /* hint_metrics */ \ + CAIRO_ROUND_GLYPH_POS_DEFAULT /* round_glyph_positions */ \ } /* font_options */ \ } @@ -92,6 +143,8 @@ static DEFINE_NIL_SURFACE(CAIRO_STATUS_READ_ERROR, _cairo_surface_nil_read_error static DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_error); static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STRIDE, _cairo_surface_nil_invalid_stride); static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_SIZE, _cairo_surface_nil_invalid_size); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_DEVICE_TYPE_MISMATCH, _cairo_surface_nil_device_type_mismatch); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_DEVICE_ERROR, _cairo_surface_nil_device_error); /** * _cairo_surface_set_error: @@ -117,6 +170,9 @@ cairo_status_t _cairo_surface_set_error (cairo_surface_t *surface, cairo_status_t status) { + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + status = CAIRO_STATUS_SUCCESS; + if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -210,103 +266,66 @@ _cairo_surface_allocate_unique_id (void) #endif } +/** + * cairo_surface_get_device: + * @surface: a #cairo_surface_t + * + * This function returns the device for a @surface. + * See #cairo_device_t. + * + * Return value: The device for @surface or %NULL if the surface does + * not have an associated device. + * + * Since: 1.10 + **/ +cairo_device_t * +cairo_surface_get_device (cairo_surface_t *surface) +{ + if (unlikely (surface->status)) + return _cairo_device_create_in_error (surface->status); + + return surface->device; +} + static cairo_bool_t _cairo_surface_has_snapshots (cairo_surface_t *surface) { - return surface->snapshots.num_elements != 0; + return ! cairo_list_is_empty (&surface->snapshots); +} + +static cairo_bool_t +_cairo_surface_has_mime_data (cairo_surface_t *surface) +{ + return surface->mime_data.num_elements != 0; +} + +static void +_cairo_surface_detach_mime_data (cairo_surface_t *surface) +{ + if (! _cairo_surface_has_mime_data (surface)) + return; + + _cairo_user_data_array_fini (&surface->mime_data); + _cairo_user_data_array_init (&surface->mime_data); } static void _cairo_surface_detach_snapshots (cairo_surface_t *surface) { - cairo_surface_t **snapshots; - unsigned int i; - - if (! _cairo_surface_has_snapshots (surface)) - return; - - /* XXX do something intelligent! */ - - snapshots = _cairo_array_index (&surface->snapshots, 0); - for (i = 0; i < surface->snapshots.num_elements; i++) { - snapshots[i]->snapshot_of = NULL; - - if (snapshots[i]->snapshot_detach != NULL) - snapshots[i]->snapshot_detach (snapshots[i]); - - cairo_surface_destroy (snapshots[i]); + while (_cairo_surface_has_snapshots (surface)) { + _cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots, + cairo_surface_t, + snapshot)); } - surface->snapshots.num_elements = 0; - - assert (! _cairo_surface_has_snapshots (surface)); -} - -cairo_status_t -_cairo_surface_attach_snapshot (cairo_surface_t *surface, - cairo_surface_t *snapshot, - cairo_surface_func_t detach_func) -{ - cairo_status_t status; - - assert (surface != snapshot); - - if (snapshot->snapshot_of != NULL) - _cairo_surface_detach_snapshot (snapshot); - - snapshot->snapshot_of = surface; - snapshot->snapshot_detach = detach_func; - - status = _cairo_array_append (&surface->snapshots, &snapshot); - if (unlikely (status)) - return status; - - cairo_surface_reference (snapshot); - return CAIRO_STATUS_SUCCESS; -} - -cairo_surface_t * -_cairo_surface_has_snapshot (cairo_surface_t *surface, - const cairo_surface_backend_t *backend, - cairo_content_t content) -{ - cairo_surface_t **snapshots; - unsigned int i; - - snapshots = _cairo_array_index (&surface->snapshots, 0); - for (i = 0; i < surface->snapshots.num_elements; i++) { - if (snapshots[i]->backend == backend && - snapshots[i]->content == content) - { - return snapshots[i]; - } - } - - return NULL; } void _cairo_surface_detach_snapshot (cairo_surface_t *snapshot) { - cairo_surface_t *surface; - cairo_surface_t **snapshots; - unsigned int i; - assert (snapshot->snapshot_of != NULL); - surface = snapshot->snapshot_of; - - snapshots = _cairo_array_index (&surface->snapshots, 0); - for (i = 0; i < surface->snapshots.num_elements; i++) { - if (snapshots[i] == snapshot) - break; - } - assert (i < surface->snapshots.num_elements); - - surface->snapshots.num_elements--; - memmove (&snapshots[i], - &snapshots[i+1], - sizeof (cairo_surface_t *)*(surface->snapshots.num_elements - i)); snapshot->snapshot_of = NULL; + cairo_list_del (&snapshot->snapshot); if (snapshot->snapshot_detach != NULL) snapshot->snapshot_detach (snapshot); @@ -314,12 +333,51 @@ _cairo_surface_detach_snapshot (cairo_surface_t *snapshot) cairo_surface_destroy (snapshot); } +void +_cairo_surface_attach_snapshot (cairo_surface_t *surface, + cairo_surface_t *snapshot, + cairo_surface_func_t detach_func) +{ + assert (surface != snapshot); + assert (snapshot->snapshot_of != surface); + + cairo_surface_reference (snapshot); + + if (snapshot->snapshot_of != NULL) + _cairo_surface_detach_snapshot (snapshot); + + snapshot->snapshot_of = surface; + snapshot->snapshot_detach = detach_func; + + cairo_list_add (&snapshot->snapshot, &surface->snapshots); + + assert (_cairo_surface_has_snapshot (surface, snapshot->backend) == snapshot); +} + +cairo_surface_t * +_cairo_surface_has_snapshot (cairo_surface_t *surface, + const cairo_surface_backend_t *backend) +{ + cairo_surface_t *snapshot; + + cairo_list_foreach_entry (snapshot, cairo_surface_t, + &surface->snapshots, snapshot) + { + /* XXX is_similar? */ + if (snapshot->backend == backend) + return snapshot; + } + + return NULL; +} + static cairo_bool_t _cairo_surface_is_writable (cairo_surface_t *surface) { return ! surface->finished && surface->snapshot_of == NULL && - ! _cairo_surface_has_snapshots (surface); + ! _cairo_surface_has_snapshots (surface) && + ! _cairo_surface_has_mime_data (surface); } static void @@ -330,16 +388,19 @@ _cairo_surface_begin_modification (cairo_surface_t *surface) assert (surface->snapshot_of == NULL); _cairo_surface_detach_snapshots (surface); + _cairo_surface_detach_mime_data (surface); } void _cairo_surface_init (cairo_surface_t *surface, const cairo_surface_backend_t *backend, + cairo_device_t *device, cairo_content_t content) { CAIRO_MUTEX_INITIALIZE (); surface->backend = backend; + surface->device = cairo_device_reference (device); surface->content = content; surface->type = backend->type; @@ -348,6 +409,7 @@ _cairo_surface_init (cairo_surface_t *surface, surface->unique_id = _cairo_surface_allocate_unique_id (); surface->finished = FALSE; surface->is_clear = FALSE; + surface->owns_device = (device != NULL); surface->has_font_options = FALSE; surface->permit_subpixel_antialiasing = TRUE; @@ -356,6 +418,7 @@ _cairo_surface_init (cairo_surface_t *surface, cairo_matrix_init_identity (&surface->device_transform); cairo_matrix_init_identity (&surface->device_transform_inverse); + cairo_list_init (&surface->device_transform_observers); surface->x_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT; surface->y_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT; @@ -363,7 +426,7 @@ _cairo_surface_init (cairo_surface_t *surface, surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT; surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT; - _cairo_array_init (&surface->snapshots, sizeof (cairo_surface_t *)); + cairo_list_init (&surface->snapshots); surface->snapshot_of = NULL; } @@ -442,6 +505,8 @@ cairo_surface_create_similar (cairo_surface_t *other, { if (unlikely (other->status)) return _cairo_surface_create_in_error (other->status); + if (unlikely (other->finished)) + return _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED); if (unlikely (! CAIRO_CONTENT_VALID (content))) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); @@ -472,7 +537,7 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other, if (surface == NULL || surface->status) return surface; - _cairo_pattern_init_solid (&pattern, color, content); + _cairo_pattern_init_solid (&pattern, color); status = _cairo_surface_paint (surface, color == CAIRO_COLOR_TRANSPARENT ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE, @@ -499,7 +564,7 @@ _cairo_surface_create_solid_pattern_surface (cairo_surface_t *other, } return _cairo_surface_create_similar_solid (other, - solid_pattern->content, + _cairo_color_get_content (&solid_pattern->color), 1, 1, &solid_pattern->color, FALSE); @@ -583,9 +648,14 @@ cairo_surface_destroy (cairo_surface_t *surface) if (! surface->finished) cairo_surface_finish (surface); + /* paranoid check that nobody took a reference whilst finishing */ + assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)); + _cairo_user_data_array_fini (&surface->user_data); _cairo_user_data_array_fini (&surface->mime_data); - _cairo_array_fini (&surface->snapshots); + + if (surface->owns_device) + cairo_device_destroy (surface->device); free (surface); } @@ -645,7 +715,13 @@ cairo_surface_finish (cairo_surface_t *surface) if (surface->finished) return; + /* update the snapshots *before* we declare the surface as finished */ + _cairo_surface_detach_snapshots (surface); + if (surface->snapshot_of != NULL) + _cairo_surface_detach_snapshot (surface); + cairo_surface_flush (surface); + surface->finished = TRUE; /* call finish even if in error mode */ if (surface->backend->finish) { @@ -653,14 +729,30 @@ cairo_surface_finish (cairo_surface_t *surface) if (unlikely (status)) status = _cairo_surface_set_error (surface, status); } - - surface->finished = TRUE; - - if (surface->snapshot_of != NULL) - _cairo_surface_detach_snapshot (surface); } slim_hidden_def (cairo_surface_finish); +/** + * _cairo_surface_release_device_reference: + * @surface: a #cairo_surface_t + * + * This function makes @surface release the reference to its device. The + * function is intended to be used for avoiding cycling references for + * surfaces that are owned by their device, for example cache surfaces. + * Note that the @surface will still assume that the device is available. + * So it is the caller's responsibility to ensure the device stays around + * until the @surface is destroyed. Just calling cairo_surface_finish() is + * not enough. + **/ +void +_cairo_surface_release_device_reference (cairo_surface_t *surface) +{ + assert (surface->owns_device); + + cairo_device_destroy (surface->device); + surface->owns_device = FALSE; +} + /** * cairo_surface_get_user_data: * @surface: a #cairo_surface_t @@ -727,7 +819,7 @@ void cairo_surface_get_mime_data (cairo_surface_t *surface, const char *mime_type, const unsigned char **data, - unsigned int *length) + unsigned long *length) { cairo_user_data_slot_t *slots; int i, num_slots; @@ -770,10 +862,42 @@ _cairo_mime_data_destroy (void *ptr) free (mime_data); } +/** + * CAIRO_MIME_TYPE_JP2: + * + * The Joint Photographic Experts Group (JPEG) 2000 image coding standard (ISO/IEC 15444-1). + * + * @Since: 1.10 + */ + +/** + * CAIRO_MIME_TYPE_JPEG: + * + * The Joint Photographic Experts Group (JPEG) image coding standard (ISO/IEC 10918-1). + * + * @Since: 1.10 + */ + +/** + * CAIRO_MIME_TYPE_PNG: + * + * The Portable Network Graphics image file format (ISO/IEC 15948). + * + * @Since: 1.10 + */ + +/** + * CAIRO_MIME_TYPE_URI: + * + * URI for an image file (unofficial MIME type). + * + * @Since: 1.10 + */ + /** * cairo_surface_set_mime_data: * @surface: a #cairo_surface_t - * @mime_type: the mime type of the image data + * @mime_type: the MIME type of the image data * @data: the image data to attach to the surface * @length: the length of the image data * @destroy: a #cairo_destroy_func_t which will be called when the @@ -785,6 +909,20 @@ _cairo_mime_data_destroy (void *ptr) * the data from a surface, call this function with same mime type * and %NULL for @data. * + * The attached image (or filename) data can later be used by backends + * which support it (currently: PDF, PS, SVG and Win32 Printing + * surfaces) to emit this data instead of making a snapshot of the + * @surface. This approach tends to be faster and requires less + * memory and disk space. + * + * The recognized MIME types are the following: %CAIRO_MIME_TYPE_JPEG, + * %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI. + * + * See corresponding backend surface docs for details about which MIME + * types it can handle. Caution: the associated MIME data will be + * discarded if you draw on the surface afterwards. Use this function + * with care. + * * Since: 1.10 * * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a @@ -794,7 +932,7 @@ cairo_status_t cairo_surface_set_mime_data (cairo_surface_t *surface, const char *mime_type, const unsigned char *data, - unsigned int length, + unsigned long length, cairo_destroy_func_t destroy, void *closure) { @@ -803,6 +941,8 @@ cairo_surface_set_mime_data (cairo_surface_t *surface, if (unlikely (surface->status)) return surface->status; + if (surface->finished) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); status = _cairo_intern_string (&mime_type, -1); if (unlikely (status)) @@ -898,7 +1038,7 @@ _cairo_surface_set_font_options (cairo_surface_t *surface, if (surface->finished) { status = _cairo_surface_set_error (surface, - CAIRO_STATUS_SURFACE_FINISHED); + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } @@ -953,7 +1093,7 @@ slim_hidden_def (cairo_surface_get_font_options); * @surface: a #cairo_surface_t * * Do any pending drawing for the surface and also restore any - * temporary modification's cairo has made to the surface's + * temporary modifications cairo has made to the surface's * state. This function must be called before switching from * drawing on the surface with cairo to drawing on it directly * with native APIs. If the surface doesn't support direct access, @@ -994,6 +1134,7 @@ cairo_surface_mark_dirty (cairo_surface_t *surface) { cairo_surface_mark_dirty_rectangle (surface, 0, 0, -1, -1); } +slim_hidden_def (cairo_surface_mark_dirty); /** * cairo_surface_mark_dirty_rectangle: @@ -1026,7 +1167,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, assert (surface->snapshot_of == NULL); if (surface->finished) { - status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } @@ -1034,6 +1175,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, * modifying the surface independently of cairo (and thus having to * call mark_dirty()). */ assert (! _cairo_surface_has_snapshots (surface)); + assert (! _cairo_surface_has_mime_data (surface)); surface->is_clear = FALSE; @@ -1084,7 +1226,7 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface, assert (surface->snapshot_of == NULL); if (surface->finished) { - status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } @@ -1099,6 +1241,8 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface, status = cairo_matrix_invert (&surface->device_transform_inverse); /* should always be invertible unless given pathological input */ assert (status == CAIRO_STATUS_SUCCESS); + + _cairo_observers_notify (&surface->device_transform_observers, surface); } /** @@ -1132,7 +1276,7 @@ cairo_surface_set_device_offset (cairo_surface_t *surface, assert (surface->snapshot_of == NULL); if (surface->finished) { - status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } @@ -1145,6 +1289,8 @@ cairo_surface_set_device_offset (cairo_surface_t *surface, status = cairo_matrix_invert (&surface->device_transform_inverse); /* should always be invertible unless given pathological input */ assert (status == CAIRO_STATUS_SUCCESS); + + _cairo_observers_notify (&surface->device_transform_observers, surface); } slim_hidden_def (cairo_surface_set_device_offset); @@ -1217,7 +1363,7 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface, assert (surface->snapshot_of == NULL); if (surface->finished) { - status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + status = _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } @@ -1433,9 +1579,7 @@ _cairo_recording_surface_clone_similar (cairo_surface_t *surface, cairo_surface_t *similar; cairo_status_t status; - similar = _cairo_surface_has_snapshot (src, - surface->backend, - src->content); + similar = _cairo_surface_has_snapshot (src, surface->backend); if (similar != NULL) { *clone_out = cairo_surface_reference (similar); *clone_offset_x = 0; @@ -1446,10 +1590,11 @@ _cairo_recording_surface_clone_similar (cairo_surface_t *surface, if (recorder->unbounded || width*height*8 < recorder->extents.width*recorder->extents.height) { - /* XXX use _solid to perform an initial CLEAR? */ - similar = _cairo_surface_create_similar_scratch (surface, - src->content, - width, height); + similar = _cairo_surface_create_similar_solid (surface, + src->content, + width, height, + CAIRO_COLOR_TRANSPARENT, + FALSE); if (similar == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; if (unlikely (similar->status)) @@ -1478,11 +1623,7 @@ _cairo_recording_surface_clone_similar (cairo_surface_t *surface, return status; } - status = _cairo_surface_attach_snapshot (src, similar, NULL); - if (unlikely (status)) { - cairo_surface_destroy (similar); - return status; - } + _cairo_surface_attach_snapshot (src, similar, NULL); src_x = src_y = 0; } @@ -1598,6 +1739,8 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, if (unlikely (surface->finished)) return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); +#if CAIRO_HAS_TEE_SURFACE + if (src->type == CAIRO_SURFACE_TYPE_TEE) { cairo_surface_t *match; @@ -1608,6 +1751,8 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, src = match; } +#endif + if (surface->backend->clone_similar != NULL) { status = surface->backend->clone_similar (surface, src, src_x, src_y, @@ -1673,95 +1818,6 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, return status; } -/* XXX: Shouldn't really need to do this here. */ -#include "cairo-recording-surface-private.h" - -/** - * _cairo_surface_snapshot - * @surface: a #cairo_surface_t - * - * Make an immutable copy of @surface. It is an error to call a - * surface-modifying function on the result of this function. - * - * The caller owns the return value and should call - * cairo_surface_destroy() when finished with it. This function will not - * return %NULL, but will return a nil surface instead. - * - * Return value: The snapshot surface. Note that the return surface - * may not necessarily be of the same type as @surface. - **/ -cairo_surface_t * -_cairo_surface_snapshot (cairo_surface_t *surface) -{ - cairo_surface_t *snapshot; - cairo_status_t status; - - if (surface->status) - return _cairo_surface_create_in_error (surface->status); - - if (surface->finished) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); - - if (surface->snapshot_of != NULL) - return cairo_surface_reference (surface); - - snapshot = _cairo_surface_has_snapshot (surface, - surface->backend, - surface->content); - if (snapshot != NULL) - return cairo_surface_reference (snapshot); - - if (surface->backend->snapshot != NULL) { - snapshot = surface->backend->snapshot (surface); - if (snapshot != NULL) { - if (unlikely (snapshot->status)) - return snapshot; - - /* Is this surface just a proxy - e.g. paginated surfaces? */ - if (snapshot->backend != surface->backend) { - cairo_surface_t *previous; - - previous = _cairo_surface_has_snapshot (surface, - snapshot->backend, - snapshot->content); - if (previous != NULL) { - cairo_surface_destroy (snapshot); - return cairo_surface_reference (previous); - } - } - } - } - - if (snapshot == NULL) { - snapshot = _cairo_surface_has_snapshot (surface, - &_cairo_image_surface_backend, - surface->content); - if (snapshot != NULL) - return cairo_surface_reference (snapshot); - - snapshot = _cairo_surface_fallback_snapshot (surface); - if (unlikely (snapshot->status)) - return snapshot; - } - - status = _cairo_surface_copy_mime_data (snapshot, surface); - if (unlikely (status)) { - cairo_surface_destroy (snapshot); - return _cairo_surface_create_in_error (status); - } - - snapshot->device_transform = surface->device_transform; - snapshot->device_transform_inverse = surface->device_transform_inverse; - - status = _cairo_surface_attach_snapshot (surface, snapshot, NULL); - if (unlikely (status)) { - cairo_surface_destroy (snapshot); - return _cairo_surface_create_in_error (status); - } - - return snapshot; -} - /** * _cairo_surface_is_similar * @surface_a: a #cairo_surface_t @@ -1779,14 +1835,13 @@ _cairo_surface_snapshot (cairo_surface_t *surface) **/ cairo_bool_t _cairo_surface_is_similar (cairo_surface_t *surface_a, - cairo_surface_t *surface_b, - cairo_content_t content) + cairo_surface_t *surface_b) { if (surface_a->backend != surface_b->backend) return FALSE; if (surface_a->backend->is_similar != NULL) - return surface_a->backend->is_similar (surface_a, surface_b, content); + return surface_a->backend->is_similar (surface_a, surface_b); return TRUE; } @@ -1990,6 +2045,27 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, rects, num_rects)); } +static cairo_status_t +_pattern_has_error (const cairo_pattern_t *pattern) +{ + const cairo_surface_pattern_t *spattern; + + if (unlikely (pattern->status)) + return pattern->status; + + if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) + return CAIRO_STATUS_SUCCESS; + + spattern = (const cairo_surface_pattern_t *) pattern; + if (unlikely (spattern->surface->status)) + return spattern->surface->status; + + if (unlikely (spattern->surface->finished)) + return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + + return CAIRO_STATUS_SUCCESS; +} + cairo_status_t _cairo_surface_paint (cairo_surface_t *surface, cairo_operator_t op, @@ -2004,14 +2080,19 @@ _cairo_surface_paint (cairo_surface_t *surface, if (clip && clip->all_clipped) return CAIRO_STATUS_SUCCESS; - if (op == CAIRO_OPERATOR_CLEAR) { - if (surface->is_clear) - return CAIRO_STATUS_SUCCESS; + if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear) + return CAIRO_STATUS_SUCCESS; - if (clip == NULL) - surface->is_clear = TRUE; + if (op == CAIRO_OPERATOR_OVER && + _cairo_pattern_is_clear (source)) + { + return CAIRO_STATUS_SUCCESS; } + status = _pattern_has_error (source); + if (unlikely (status)) + return status; + _cairo_surface_begin_modification (surface); if (surface->backend->paint != NULL) { @@ -2023,7 +2104,7 @@ _cairo_surface_paint (cairo_surface_t *surface, status = _cairo_surface_fallback_paint (surface, op, source, clip); FINISH: - surface->is_clear &= op == CAIRO_OPERATOR_CLEAR; + surface->is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL; return _cairo_surface_set_error (surface, status); } @@ -2047,12 +2128,26 @@ _cairo_surface_mask (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; /* If the mask is blank, this is just an expensive no-op */ - if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) { - const cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t *) mask; - if (spattern->surface->is_clear) - return CAIRO_STATUS_SUCCESS; + if (_cairo_pattern_is_clear (mask) && + _cairo_operator_bounded_by_mask (op)) + { + return CAIRO_STATUS_SUCCESS; } + if (op == CAIRO_OPERATOR_OVER && + _cairo_pattern_is_clear (source)) + { + return CAIRO_STATUS_SUCCESS; + } + + status = _pattern_has_error (source); + if (unlikely (status)) + return status; + + status = _pattern_has_error (mask); + if (unlikely (status)) + return status; + _cairo_surface_begin_modification (surface); if (surface->backend->mask != NULL) { @@ -2064,7 +2159,7 @@ _cairo_surface_mask (cairo_surface_t *surface, status = _cairo_surface_fallback_mask (surface, op, source, mask, clip); FINISH: - surface->is_clear &= op == CAIRO_OPERATOR_CLEAR; + surface->is_clear = FALSE; return _cairo_surface_set_error (surface, status); } @@ -2079,9 +2174,9 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, cairo_path_fixed_t *path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *stroke_ctm, - cairo_matrix_t *stroke_ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, cairo_clip_t *clip) @@ -2101,6 +2196,14 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; } + status = _pattern_has_error (fill_source); + if (unlikely (status)) + return status; + + status = _pattern_has_error (stroke_source); + if (unlikely (status)) + return status; + _cairo_surface_begin_modification (surface); if (surface->backend->fill_stroke) { @@ -2135,8 +2238,7 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, goto FINISH; FINISH: - surface->is_clear &= fill_op == CAIRO_OPERATOR_CLEAR; - surface->is_clear &= stroke_op == CAIRO_OPERATOR_CLEAR; + surface->is_clear = FALSE; return _cairo_surface_set_error (surface, status); } @@ -2146,9 +2248,9 @@ _cairo_surface_stroke (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) @@ -2164,6 +2266,16 @@ _cairo_surface_stroke (cairo_surface_t *surface, if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear) return CAIRO_STATUS_SUCCESS; + if (op == CAIRO_OPERATOR_OVER && + _cairo_pattern_is_clear (source)) + { + return CAIRO_STATUS_SUCCESS; + } + + status = _pattern_has_error (source); + if (unlikely (status)) + return status; + _cairo_surface_begin_modification (surface); if (surface->backend->stroke != NULL) { @@ -2184,7 +2296,7 @@ _cairo_surface_stroke (cairo_surface_t *surface, clip); FINISH: - surface->is_clear &= op == CAIRO_OPERATOR_CLEAR; + surface->is_clear = FALSE; return _cairo_surface_set_error (surface, status); } @@ -2210,6 +2322,16 @@ _cairo_surface_fill (cairo_surface_t *surface, if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear) return CAIRO_STATUS_SUCCESS; + if (op == CAIRO_OPERATOR_OVER && + _cairo_pattern_is_clear (source)) + { + return CAIRO_STATUS_SUCCESS; + } + + status = _pattern_has_error (source); + if (unlikely (status)) + return status; + _cairo_surface_begin_modification (surface); if (surface->backend->fill != NULL) { @@ -2228,7 +2350,7 @@ _cairo_surface_fill (cairo_surface_t *surface, clip); FINISH: - surface->is_clear &= op == CAIRO_OPERATOR_CLEAR; + surface->is_clear = FALSE; return _cairo_surface_set_error (surface, status); } @@ -2389,14 +2511,14 @@ cairo_surface_show_page (cairo_surface_t *surface) if (surface->status) return; - _cairo_surface_begin_modification (surface); - if (surface->finished) { status_ignored = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); return; } + _cairo_surface_begin_modification (surface); + /* It's fine if some backends don't implement show_page */ if (surface->backend->show_page == NULL) return; @@ -2434,11 +2556,9 @@ cairo_bool_t _cairo_surface_get_extents (cairo_surface_t *surface, cairo_rectangle_int_t *extents) { - cairo_bool_t bounded = FALSE; - - if (unlikely (surface->status || surface->finished)) - return TRUE; + cairo_bool_t bounded; + bounded = FALSE; if (surface->backend->get_extents != NULL) bounded = surface->backend->get_extents (surface, extents); @@ -2585,6 +2705,10 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear) return CAIRO_STATUS_SUCCESS; + status = _pattern_has_error (source); + if (unlikely (status)) + return status; + _cairo_surface_begin_modification (surface); if (_cairo_surface_has_device_transform (surface) && @@ -2681,7 +2805,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, if (dev_scaled_font != scaled_font) cairo_scaled_font_destroy (dev_scaled_font); - surface->is_clear &= op == CAIRO_OPERATOR_CLEAR; + surface->is_clear = FALSE; return _cairo_surface_set_error (surface, status); } @@ -3034,7 +3158,7 @@ _cairo_surface_stroke_extents (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, + const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, @@ -3149,6 +3273,10 @@ _cairo_surface_create_in_error (cairo_status_t status) return (cairo_surface_t *) &_cairo_surface_nil_invalid_stride; case CAIRO_STATUS_INVALID_SIZE: return (cairo_surface_t *) &_cairo_surface_nil_invalid_size; + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: + return (cairo_surface_t *) &_cairo_surface_nil_device_type_mismatch; + case CAIRO_STATUS_DEVICE_ERROR: + return (cairo_surface_t *) &_cairo_surface_nil_device_error; case CAIRO_STATUS_SUCCESS: case CAIRO_STATUS_LAST_STATUS: ASSERT_NOT_REACHED; diff --git a/gfx/cairo/cairo/src/cairo-svg-surface-private.h b/gfx/cairo/cairo/src/cairo-svg-surface-private.h index 64efe7f2a226..ddbf464b1d29 100644 --- a/gfx/cairo/cairo/src/cairo-svg-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-svg-surface-private.h @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-svg-surface.c b/gfx/cairo/cairo/src/cairo-svg-surface.c index fa25b821e2ca..fb612fadf5be 100644 --- a/gfx/cairo/cairo/src/cairo-svg-surface.c +++ b/gfx/cairo/cairo/src/cairo-svg-surface.c @@ -15,7 +15,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -43,6 +43,7 @@ #include "cairoint.h" #include "cairo-svg.h" #include "cairo-analysis-surface-private.h" +#include "cairo-error-private.h" #include "cairo-image-info-private.h" #include "cairo-recording-surface-private.h" #include "cairo-output-stream-private.h" @@ -52,6 +53,23 @@ #include "cairo-surface-clipper-private.h" #include "cairo-svg-surface-private.h" +/** + * SECTION:cairo-svg + * @Title: SVG Surfaces + * @Short_Description: Rendering SVG documents + * @See_Also: #cairo_surface_t + * + * The SVG surface is used to render cairo graphics to + * SVG files and is a multi-page vector surface backend. + */ + +/** + * CAIRO_HAS_SVG_SURFACE: + * + * Defined if the SVG surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + */ + typedef struct cairo_svg_page cairo_svg_page_t; static const int invalid_pattern_id = -1; @@ -65,9 +83,9 @@ static const cairo_svg_version_t _cairo_svg_versions[] = #define CAIRO_SVG_VERSION_LAST ARRAY_LENGTH (_cairo_svg_versions) static void -_cairo_svg_surface_emit_path (cairo_output_stream_t *output, - cairo_path_fixed_t *path, - cairo_matrix_t *ctm_inverse); +_cairo_svg_surface_emit_path (cairo_output_stream_t *output, + cairo_path_fixed_t *path, + const cairo_matrix_t *ctm_inverse); static cairo_bool_t _cairo_svg_version_has_page_set_support (cairo_svg_version_t version) @@ -202,6 +220,22 @@ cairo_svg_surface_create_for_stream (cairo_write_func_t write_func, * Creates a SVG surface of the specified size in points to be written * to @filename. * + * The SVG surface backend recognizes the following MIME types for the + * data attached to a surface (see cairo_surface_set_mime_data()) when + * it is used as a source pattern for drawing on this surface: + * %CAIRO_MIME_TYPE_JPEG, %CAIRO_MIME_TYPE_PNG, + * %CAIRO_MIME_TYPE_URI. If any of them is specified, the SVG backend + * emits a href with the content of MIME data instead of a surface + * snapshot (PNG, Base64-encoded) in the corresponding image tag. + * + * The unofficial MIME type %CAIRO_MIME_TYPE_URI is examined + * first. If present, the URI is emitted as is: assuring the + * correctness of URI is left to the client code. + * + * If %CAIRO_MIME_TYPE_URI is not present, but %CAIRO_MIME_TYPE_JPEG + * or %CAIRO_MIME_TYPE_PNG is specified, the corresponding data is + * Base64-encoded and emitted. + * * Return value: a pointer to the newly created surface. The caller * owns the surface and should call cairo_surface_destroy() when done * with it. @@ -234,30 +268,49 @@ _cairo_surface_is_svg (cairo_surface_t *surface) /* If the abstract_surface is a paginated surface, and that paginated * surface's target is a svg_surface, then set svg_surface to that - * target. Otherwise return %CAIRO_STATUS_SURFACE_TYPE_MISMATCH. + * target. Otherwise return FALSE. */ -static cairo_status_t +static cairo_bool_t _extract_svg_surface (cairo_surface_t *surface, cairo_svg_surface_t **svg_surface) { cairo_surface_t *target; + cairo_status_t status_ignored; if (surface->status) - return surface->status; + return FALSE; + if (surface->finished) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } - if (! _cairo_surface_is_paginated (surface)) - return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + if (! _cairo_surface_is_paginated (surface)) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } target = _cairo_paginated_surface_get_target (surface); - if (target->status) - return target->status; + if (target->status) { + status_ignored = _cairo_surface_set_error (surface, + target->status); + return FALSE; + } + if (target->finished) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } - if (! _cairo_surface_is_svg (target)) - return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + if (! _cairo_surface_is_svg (target)) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } *svg_surface = (cairo_svg_surface_t *) target; - - return CAIRO_STATUS_SUCCESS; + return TRUE; } /** @@ -280,13 +333,9 @@ cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface, cairo_svg_version_t version) { cairo_svg_surface_t *surface = NULL; /* hide compiler warning */ - cairo_status_t status; - status = _extract_svg_surface (abstract_surface, &surface); - if (unlikely (status)) { - status = _cairo_surface_set_error (abstract_surface, status); + if (! _extract_svg_surface (abstract_surface, &surface)) return; - } if (version < CAIRO_SVG_VERSION_LAST) surface->document->svg_version = version; @@ -415,7 +464,9 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document, if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - _cairo_surface_init (&surface->base, &cairo_svg_surface_backend, + _cairo_surface_init (&surface->base, + &cairo_svg_surface_backend, + NULL, /* device */ content); surface->width = width; @@ -589,7 +640,7 @@ _cairo_svg_surface_emit_transform (cairo_output_stream_t *output, typedef struct { cairo_output_stream_t *output; - cairo_matrix_t *ctm_inverse; + const cairo_matrix_t *ctm_inverse; } svg_path_info_t; static cairo_status_t @@ -662,9 +713,9 @@ _cairo_svg_path_close_path (void *closure) } static void -_cairo_svg_surface_emit_path (cairo_output_stream_t *output, - cairo_path_fixed_t *path, - cairo_matrix_t *ctm_inverse) +_cairo_svg_surface_emit_path (cairo_output_stream_t *output, + cairo_path_fixed_t *path, + const cairo_matrix_t *ctm_inverse) { cairo_status_t status; svg_path_info_t info; @@ -733,8 +784,8 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document, if (unlikely (status)) return status; - image = _cairo_image_surface_coerce (scaled_glyph->surface, - CAIRO_FORMAT_A1); + image = _cairo_image_surface_coerce_to_format (scaled_glyph->surface, + CAIRO_FORMAT_A1); status = image->base.status; if (unlikely (status)) return status; @@ -1035,7 +1086,7 @@ _cairo_surface_base64_encode_jpeg (cairo_surface_t *surface, cairo_output_stream_t *output) { const unsigned char *mime_data; - unsigned int mime_data_length; + unsigned long mime_data_length; cairo_image_info_t image_info; base64_write_closure_t info; cairo_status_t status; @@ -1074,7 +1125,7 @@ _cairo_surface_base64_encode_png (cairo_surface_t *surface, cairo_output_stream_t *output) { const unsigned char *mime_data; - unsigned int mime_data_length; + unsigned long mime_data_length; base64_write_closure_t info; cairo_status_t status; @@ -1168,6 +1219,45 @@ _cairo_svg_surface_emit_operator_for_style (cairo_output_stream_t *output, } } +/** + * _cairo_svg_surface_emit_attr_value: + * + * Write the value to output the stream as a sequence of characters, + * while escaping those which have special meaning in the XML + * attribute's value context: & and ". + **/ +static void +_cairo_svg_surface_emit_attr_value (cairo_output_stream_t *stream, + const unsigned char *value, + unsigned int length) +{ + const unsigned char *p; + const unsigned char *q; + unsigned int i; + + /* we'll accumulate non-special chars in [q, p) range */ + p = value; + q = p; + for (i = 0; i < length; i++, p++) { + if (*p == '&' || *p == '"') { + /* flush what's left before special char */ + if (p != q) { + _cairo_output_stream_write (stream, q, p - q); + q = p + 1; + } + + if (*p == '&') + _cairo_output_stream_printf (stream, "&"); + else // p == '"' + _cairo_output_stream_printf (stream, """); + } + } + + /* flush the trailing chars if any */ + if (p != q) + _cairo_output_stream_write (stream, q, p - q); +} + static cairo_status_t _cairo_svg_surface_emit_surface (cairo_svg_document_t *document, cairo_surface_t *surface) @@ -1175,6 +1265,8 @@ _cairo_svg_surface_emit_surface (cairo_svg_document_t *document, cairo_rectangle_int_t extents; cairo_bool_t is_bounded; cairo_status_t status; + const unsigned char *uri; + unsigned long uri_len; if (_cairo_user_data_array_get_data (&surface->user_data, (cairo_user_data_key_t *) document)) @@ -1192,10 +1284,17 @@ _cairo_svg_surface_emit_surface (cairo_svg_document_t *document, _cairo_output_stream_printf (document->xml_node_defs, " xlink:href=\""); - status = _cairo_surface_base64_encode (surface, - document->xml_node_defs); - if (unlikely (status)) - return status; + cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_URI, + &uri, &uri_len); + if (uri != NULL) { + _cairo_svg_surface_emit_attr_value (document->xml_node_defs, + uri, uri_len); + } else { + status = _cairo_surface_base64_encode (surface, + document->xml_node_defs); + if (unlikely (status)) + return status; + } _cairo_output_stream_printf (document->xml_node_defs, "\"/>\n"); @@ -1571,14 +1670,14 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output, else { cairo_bool_t found = FALSE; unsigned int offset_index; - cairo_color_t offset_color_start, offset_color_stop; + cairo_color_stop_t offset_color_start, offset_color_stop; for (i = 0; i < n_stops; i++) { if (stops[i].offset >= -start_offset) { if (i > 0) { if (stops[i].offset != stops[i-1].offset) { double x0, x1; - cairo_color_t *color0, *color1; + cairo_color_stop_t *color0, *color1; x0 = stops[i-1].offset; x1 = stops[i].offset; @@ -1947,7 +2046,7 @@ _cairo_svg_surface_emit_fill_style (cairo_output_stream_t *output, cairo_operator_t op, const cairo_pattern_t *source, cairo_fill_rule_t fill_rule, - cairo_matrix_t *parent_matrix) + const cairo_matrix_t *parent_matrix) { _cairo_output_stream_printf (output, "fill-rule:%s;", @@ -1958,12 +2057,12 @@ _cairo_svg_surface_emit_fill_style (cairo_output_stream_t *output, } static cairo_status_t -_cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output, - cairo_svg_surface_t *surface, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *parent_matrix) +_cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output, + cairo_svg_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *parent_matrix) { cairo_status_t status; const char *line_cap, *line_join; @@ -2045,9 +2144,9 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface, cairo_path_fixed_t *path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *stroke_ctm, - cairo_matrix_t *stroke_ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, cairo_clip_t *clip) @@ -2336,9 +2435,9 @@ _cairo_svg_surface_stroke (void *abstract_dst, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) diff --git a/gfx/cairo/cairo/src/cairo-svg.h b/gfx/cairo/cairo/src/cairo-svg.h index 785133813385..0f739fc04cae 100644 --- a/gfx/cairo/cairo/src/cairo-svg.h +++ b/gfx/cairo/cairo/src/cairo-svg.h @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-system.c b/gfx/cairo/cairo/src/cairo-system.c index 85c74876eb2a..1ff4d078f892 100644 --- a/gfx/cairo/cairo/src/cairo-system.c +++ b/gfx/cairo/cairo/src/cairo-system.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-tee-surface-private.h b/gfx/cairo/cairo/src/cairo-tee-surface-private.h index 258816b59741..a83cfc959db4 100644 --- a/gfx/cairo/cairo/src/cairo-tee-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-tee-surface-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-tee-surface.c b/gfx/cairo/cairo/src/cairo-tee-surface.c index 2dcd5d54d713..bca07716f5b8 100644 --- a/gfx/cairo/cairo/src/cairo-tee-surface.c +++ b/gfx/cairo/cairo/src/cairo-tee-surface.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -40,6 +40,9 @@ #include "cairoint.h" +#include "cairo-tee.h" + +#include "cairo-error-private.h" #include "cairo-tee-surface-private.h" #include "cairo-surface-wrapper-private.h" @@ -298,9 +301,9 @@ _cairo_tee_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) @@ -543,6 +546,7 @@ cairo_tee_surface_create (cairo_surface_t *master) _cairo_surface_init (&surface->base, &cairo_tee_surface_backend, + master->device, master->content); _cairo_surface_wrapper_init (&surface->master, master); @@ -566,6 +570,11 @@ cairo_tee_surface_add (cairo_surface_t *abstract_surface, if (unlikely (abstract_surface->status)) return; + if (unlikely (abstract_surface->finished)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } if (abstract_surface->backend != &cairo_tee_surface_backend) { status = _cairo_surface_set_error (abstract_surface, @@ -598,6 +607,14 @@ cairo_tee_surface_remove (cairo_surface_t *abstract_surface, int n, num_slaves; cairo_status_t status; + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + if (abstract_surface->backend != &cairo_tee_surface_backend) { status = _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); @@ -638,6 +655,8 @@ cairo_tee_surface_index (cairo_surface_t *abstract_surface, if (unlikely (abstract_surface->status)) return _cairo_surface_create_in_error (abstract_surface->status); + if (unlikely (abstract_surface->finished)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); if (abstract_surface->backend != &cairo_tee_surface_backend) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); diff --git a/gfx/cairo/cairo/src/cairo-tee.h b/gfx/cairo/cairo/src/cairo-tee.h new file mode 100644 index 000000000000..9c048c6fe1dc --- /dev/null +++ b/gfx/cairo/cairo/src/cairo-tee.h @@ -0,0 +1,66 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_TEE_H +#define CAIRO_TEE_H + +#include "cairo.h" + +#if CAIRO_HAS_TEE_SURFACE + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_tee_surface_create (cairo_surface_t *master); + +cairo_public void +cairo_tee_surface_add (cairo_surface_t *surface, + cairo_surface_t *target); + +cairo_public void +cairo_tee_surface_remove (cairo_surface_t *surface, + cairo_surface_t *target); + +cairo_public cairo_surface_t * +cairo_tee_surface_index (cairo_surface_t *surface, + int index); + +CAIRO_END_DECLS + +#else /*CAIRO_HAS_TEE_SURFACE*/ +# error Cairo was not compiled with support for the TEE backend +#endif /*CAIRO_HAS_TEE_SURFACE*/ + +#endif /*CAIRO_TEE_H*/ diff --git a/gfx/cairo/cairo/src/cairo-tor-scan-converter.c b/gfx/cairo/cairo/src/cairo-tor-scan-converter.c index 2b9fb1bc707d..dc8dad1c5035 100644 --- a/gfx/cairo/cairo/src/cairo-tor-scan-converter.c +++ b/gfx/cairo/cairo/src/cairo-tor-scan-converter.c @@ -95,6 +95,7 @@ */ #include "cairoint.h" #include "cairo-spans-private.h" +#include "cairo-error-private.h" #include #include @@ -1214,46 +1215,111 @@ active_list_init(struct active_list *active) active_list_reset(active); } -/* Merge the edges in an unsorted list of edges into a sorted - * list. The sort order is edges ascending by edge->x.quo. Returns - * the new head of the sorted list. */ +/* + * Merge two sorted edge lists. + * Input: + * - head_a: The head of the first list. + * - head_b: The head of the second list; head_b cannot be NULL. + * Output: + * Returns the head of the merged list. + * + * Implementation notes: + * To make it fast (in particular, to reduce to an insertion sort whenever + * one of the two input lists only has a single element) we iterate through + * a list until its head becomes greater than the head of the other list, + * then we switch their roles. As soon as one of the two lists is empty, we + * just attach the other one to the current list and exit. + * Writes to memory are only needed to "switch" lists (as it also requires + * attaching to the output list the list which we will be iterating next) and + * to attach the last non-empty list. + */ static struct edge * -merge_unsorted_edges(struct edge *sorted_head, struct edge *unsorted_head) +merge_sorted_edges (struct edge *head_a, struct edge *head_b) { - struct edge **cursor = &sorted_head; - int x; + struct edge *head, **next; - if (sorted_head == NULL) { - sorted_head = unsorted_head; - unsorted_head = unsorted_head->next; - sorted_head->next = NULL; - if (unsorted_head == NULL) - return sorted_head; - } + head = head_a; + next = &head; - do { - struct edge *next = unsorted_head->next; - struct edge *prev = *cursor; - - x = unsorted_head->x.quo; - if (x < prev->x.quo) - cursor = &sorted_head; - - while (1) { - UNROLL3({ - prev = *cursor; - if (NULL == prev || prev->x.quo >= x) - break; - cursor = &prev->next; - }); + while (1) { + while (head_a != NULL && head_a->x.quo <= head_b->x.quo) { + next = &head_a->next; + head_a = head_a->next; } - unsorted_head->next = *cursor; - *cursor = unsorted_head; - unsorted_head = next; - } while (unsorted_head != NULL); + *next = head_b; + if (head_a == NULL) + return head; - return sorted_head; + while (head_b != NULL && head_b->x.quo <= head_a->x.quo) { + next = &head_b->next; + head_b = head_b->next; + } + + *next = head_a; + if (head_b == NULL) + return head; + } +} + +/* + * Sort (part of) a list. + * Input: + * - list: The list to be sorted; list cannot be NULL. + * - limit: Recursion limit. + * Output: + * - head_out: The head of the sorted list containing the first 2^(level+1) elements of the + * input list; if the input list has fewer elements, head_out be a sorted list + * containing all the elements of the input list. + * Returns the head of the list of unprocessed elements (NULL if the sorted list contains + * all the elements of the input list). + * + * Implementation notes: + * Special case single element list, unroll/inline the sorting of the first two elements. + * Some tail recursion is used since we iterate on the bottom-up solution of the problem + * (we start with a small sorted list and keep merging other lists of the same size to it). + */ +static struct edge * +sort_edges (struct edge *list, + unsigned int level, + struct edge **head_out) +{ + struct edge *head_other, *remaining; + unsigned int i; + + head_other = list->next; + + /* Single element list -> return */ + if (head_other == NULL) { + *head_out = list; + return NULL; + } + + /* Unroll the first iteration of the following loop (halves the number of calls to merge_sorted_edges): + * - Initialize remaining to be the list containing the elements after the second in the input list. + * - Initialize *head_out to be the sorted list containing the first two element. + */ + remaining = head_other->next; + if (list->x.quo <= head_other->x.quo) { + *head_out = list; + /* list->next = head_other; */ /* The input list is already like this. */ + head_other->next = NULL; + } else { + *head_out = head_other; + head_other->next = list; + list->next = NULL; + } + + for (i = 0; i < level && remaining; i++) { + /* Extract a sorted list of the same size as *head_out + * (2^(i+1) elements) from the list of remaining elements. */ + remaining = sort_edges (remaining, i, &head_other); + *head_out = merge_sorted_edges (*head_out, head_other); + } + + /* *head_out now contains (at most) 2^(level+1) elements. */ + + return remaining; } /* Test if the edges on the active list can be safely advanced by a @@ -1344,7 +1410,8 @@ active_list_merge_edges_from_polygon( } } if (subrow_edges) { - active->head = merge_unsorted_edges(active->head, subrow_edges); + sort_edges (subrow_edges, UINT_MAX, &subrow_edges); + active->head = merge_sorted_edges (active->head, subrow_edges); active->min_height = min_height; } } @@ -1390,8 +1457,10 @@ active_list_substep_edges( }); } - if (unsorted) - active->head = merge_unsorted_edges(active->head, unsorted); + if (unsorted) { + sort_edges (unsorted, UINT_MAX, &unsorted); + active->head = merge_sorted_edges (active->head, unsorted); + } } inline static glitter_status_t @@ -1563,11 +1632,11 @@ apply_evenodd_fill_rule_and_step_edges (struct active_list *active, winding += right_edge->dir; if ((winding & 1) == 0) { - if (right_edge->next == NULL || - right_edge->next->x.quo != right_edge->x.quo) - { - break; - } + if (right_edge->next == NULL || + right_edge->next->x.quo != right_edge->x.quo) + { + break; + } } if (! right_edge->vertical) { diff --git a/gfx/cairo/cairo/src/cairo-toy-font-face.c b/gfx/cairo/cairo/src/cairo-toy-font-face.c index e7c841a9cf43..4c690da534c1 100644 --- a/gfx/cairo/cairo/src/cairo-toy-font-face.c +++ b/gfx/cairo/cairo/src/cairo-toy-font-face.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -41,6 +41,7 @@ #define _BSD_SOURCE /* for strdup() */ #include "cairoint.h" +#include "cairo-error-private.h" static const cairo_font_face_t _cairo_font_face_null_pointer = { diff --git a/gfx/cairo/cairo/src/cairo-traps.c b/gfx/cairo/cairo/src/cairo-traps.c index 70d4c69e0e13..2fe6684db7dc 100644 --- a/gfx/cairo/cairo/src/cairo-traps.c +++ b/gfx/cairo/cairo/src/cairo-traps.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -39,6 +39,8 @@ #include "cairoint.h" +#include "cairo-boxes-private.h" +#include "cairo-error-private.h" #include "cairo-region-private.h" #include "cairo-slope-private.h" @@ -156,45 +158,45 @@ _cairo_traps_add_trap (cairo_traps_t *traps, **/ cairo_status_t _cairo_traps_init_boxes (cairo_traps_t *traps, - const cairo_box_t *boxes, - int num_boxes) + const cairo_boxes_t *boxes) { cairo_trapezoid_t *trap; + const struct _cairo_boxes_chunk *chunk; _cairo_traps_init (traps); - while (traps->traps_size < num_boxes) { + while (traps->traps_size < boxes->num_boxes) { if (unlikely (! _cairo_traps_grow (traps))) { _cairo_traps_fini (traps); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } } - traps->num_traps = num_boxes; + traps->num_traps = boxes->num_boxes; traps->is_rectilinear = TRUE; traps->is_rectangular = TRUE; + traps->maybe_region = boxes->is_pixel_aligned; trap = &traps->traps[0]; - while (num_boxes--) { - trap->top = boxes->p1.y; - trap->bottom = boxes->p2.y; + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *box; + int i; - trap->left.p1 = boxes->p1; - trap->left.p2.x = boxes->p1.x; - trap->left.p2.y = boxes->p2.y; + box = chunk->base; + for (i = 0; i < chunk->count; i++) { + trap->top = box->p1.y; + trap->bottom = box->p2.y; - trap->right.p1.x = boxes->p2.x; - trap->right.p1.y = boxes->p1.y; - trap->right.p2 = boxes->p2; + trap->left.p1 = box->p1; + trap->left.p2.x = box->p1.x; + trap->left.p2.y = box->p2.y; - if (traps->maybe_region) { - traps->maybe_region = _cairo_fixed_is_integer (boxes->p1.x) && - _cairo_fixed_is_integer (boxes->p1.y) && - _cairo_fixed_is_integer (boxes->p2.x) && - _cairo_fixed_is_integer (boxes->p2.y); + trap->right.p1.x = box->p2.x; + trap->right.p1.y = box->p1.y; + trap->right.p2 = box->p2; + + box++, trap++; } - - trap++, boxes++; } return CAIRO_STATUS_SUCCESS; diff --git a/gfx/cairo/cairo/src/cairo-truetype-subset-private.h b/gfx/cairo/cairo/src/cairo-truetype-subset-private.h index 978256f6b45e..aed60d028240 100644 --- a/gfx/cairo/cairo/src/cairo-truetype-subset-private.h +++ b/gfx/cairo/cairo/src/cairo-truetype-subset-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-truetype-subset.c b/gfx/cairo/cairo/src/cairo-truetype-subset.c index 3a813ee7e942..9bf2f8ffc677 100644 --- a/gfx/cairo/cairo/src/cairo-truetype-subset.c +++ b/gfx/cairo/cairo/src/cairo-truetype-subset.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -42,6 +42,7 @@ #define _BSD_SOURCE /* for snprintf(), strdup() */ #include "cairoint.h" +#include "cairo-error-private.h" #if CAIRO_HAS_FONT_SUBSET diff --git a/gfx/cairo/cairo/src/cairo-type1-fallback.c b/gfx/cairo/cairo/src/cairo-type1-fallback.c index 1023bbdcb28e..b93c42348ba9 100644 --- a/gfx/cairo/cairo/src/cairo-type1-fallback.c +++ b/gfx/cairo/cairo/src/cairo-type1-fallback.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -35,6 +35,7 @@ #define _BSD_SOURCE /* for snprintf(), strdup() */ #include "cairoint.h" +#include "cairo-error-private.h" #if CAIRO_HAS_FONT_SUBSET @@ -726,20 +727,20 @@ _cairo_type1_fallback_init_internal (cairo_type1_subset_t *type1_subset, goto fail1; } - type1_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); + type1_subset->widths = calloc (sizeof (double), font->scaled_font_subset->num_glyphs); if (unlikely (type1_subset->widths == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto fail2; } for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) - type1_subset->widths[i] = font->widths[i]; + type1_subset->widths[i] = (double)font->widths[i]/1000; - type1_subset->x_min = (int) font->x_min; - type1_subset->y_min = (int) font->y_min; - type1_subset->x_max = (int) font->x_max; - type1_subset->y_max = (int) font->y_max; - type1_subset->ascent = (int) font->y_max; - type1_subset->descent = (int) font->y_min; + type1_subset->x_min = (double)font->x_min/1000; + type1_subset->y_min = (double)font->y_min/1000; + type1_subset->x_max = (double)font->x_max/1000; + type1_subset->y_max = (double)font->y_max/1000; + type1_subset->ascent = (double)font->y_max/1000; + type1_subset->descent = (double)font->y_min/1000; length = font->header_size + font->data_size + font->trailer_size; diff --git a/gfx/cairo/cairo/src/cairo-type1-private.h b/gfx/cairo/cairo/src/cairo-type1-private.h index 171c224902de..1630397bca6b 100644 --- a/gfx/cairo/cairo/src/cairo-type1-private.h +++ b/gfx/cairo/cairo/src/cairo-type1-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-type1-subset.c b/gfx/cairo/cairo/src/cairo-type1-subset.c index 7ded39a41081..9c0a2cf10264 100644 --- a/gfx/cairo/cairo/src/cairo-type1-subset.c +++ b/gfx/cairo/cairo/src/cairo-type1-subset.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -41,6 +41,7 @@ #define _BSD_SOURCE /* for snprintf(), strdup() */ #include "cairoint.h" +#include "cairo-error-private.h" #if CAIRO_HAS_FONT_SUBSET @@ -82,7 +83,7 @@ typedef struct _cairo_type1_font_subset { struct { int subset_index; - int width; + double width; char *name; } *glyphs; @@ -565,7 +566,7 @@ cairo_type1_font_subset_get_glyph_names_and_widths (cairo_type1_font_subset_t *f return CAIRO_INT_STATUS_UNSUPPORTED; } - font->glyphs[i].width = font->face->glyph->metrics.horiAdvance; + font->glyphs[i].width = font->face->glyph->linearHoriAdvance / 65536.0; /* 16.16 format */ error = FT_Get_Glyph_Name(font->face, i, buffer, sizeof buffer); if (error != FT_Err_Ok) { @@ -1345,7 +1346,7 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset, if (unlikely (type1_subset->base_font == NULL)) goto fail1; - type1_subset->widths = calloc (sizeof (int), font.num_glyphs); + type1_subset->widths = calloc (sizeof (double), font.num_glyphs); if (unlikely (type1_subset->widths == NULL)) goto fail2; for (i = 0; i < font.base.num_glyphs; i++) { @@ -1355,12 +1356,12 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset, font.glyphs[i].width; } - type1_subset->x_min = font.base.x_min; - type1_subset->y_min = font.base.y_min; - type1_subset->x_max = font.base.x_max; - type1_subset->y_max = font.base.y_max; - type1_subset->ascent = font.base.ascent; - type1_subset->descent = font.base.descent; + type1_subset->x_min = font.base.x_min/1000.0; + type1_subset->y_min = font.base.y_min/1000.0; + type1_subset->x_max = font.base.x_max/1000.0; + type1_subset->y_max = font.base.y_max/1000.0; + type1_subset->ascent = font.base.ascent/1000.0; + type1_subset->descent = font.base.descent/1000.0; length = font.base.header_size + font.base.data_size + diff --git a/gfx/cairo/cairo/src/cairo-type3-glyph-surface-private.h b/gfx/cairo/cairo/src/cairo-type3-glyph-surface-private.h index 0b0010bcca48..b4abcf604306 100644 --- a/gfx/cairo/cairo/src/cairo-type3-glyph-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-type3-glyph-surface-private.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-type3-glyph-surface.c b/gfx/cairo/cairo/src/cairo-type3-glyph-surface.c index 6878bbaae25d..74257d4bf854 100644 --- a/gfx/cairo/cairo/src/cairo-type3-glyph-surface.c +++ b/gfx/cairo/cairo/src/cairo-type3-glyph-surface.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -42,6 +42,7 @@ #include "cairo-output-stream-private.h" #include "cairo-recording-surface-private.h" #include "cairo-analysis-surface-private.h" +#include "cairo-error-private.h" #include "cairo-surface-clipper-private.h" static const cairo_surface_backend_t cairo_type3_glyph_surface_backend; @@ -83,7 +84,9 @@ _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font, if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - _cairo_surface_init (&surface->base, &cairo_type3_glyph_surface_backend, + _cairo_surface_init (&surface->base, + &cairo_type3_glyph_surface_backend, + NULL, /* device */ CAIRO_CONTENT_COLOR_ALPHA); surface->scaled_font = scaled_font; @@ -117,7 +120,7 @@ _cairo_type3_glyph_surface_emit_image (cairo_type3_glyph_surface_t *surface, cairo_status_t status; /* The only image type supported by Type 3 fonts are 1-bit masks */ - image = _cairo_image_surface_coerce (image, CAIRO_FORMAT_A1); + image = _cairo_image_surface_coerce_to_format (image, CAIRO_FORMAT_A1); status = image->base.status; if (unlikely (status)) return status; @@ -232,9 +235,9 @@ _cairo_type3_glyph_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) @@ -288,25 +291,15 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface, cairo_type3_glyph_surface_t *surface = abstract_surface; cairo_int_status_t status; cairo_scaled_font_t *font; - cairo_matrix_t new_ctm, ctm_inverse; - int i; + cairo_matrix_t new_ctm, invert_y_axis; status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); if (unlikely (status)) return status; - for (i = 0; i < num_glyphs; i++) { - cairo_matrix_transform_point (&surface->cairo_to_pdf, - &glyphs[i].x, &glyphs[i].y); - } - - /* We require the matrix to be invertable. */ - ctm_inverse = scaled_font->ctm; - status = cairo_matrix_invert (&ctm_inverse); - if (unlikely (status)) - return CAIRO_INT_STATUS_IMAGE_FALLBACK; - - cairo_matrix_multiply (&new_ctm, &scaled_font->ctm, &ctm_inverse); + cairo_matrix_init_scale (&invert_y_axis, 1, -1); + cairo_matrix_multiply (&new_ctm, &invert_y_axis, &scaled_font->ctm); + cairo_matrix_multiply (&new_ctm, &surface->cairo_to_pdf, &new_ctm); font = cairo_scaled_font_create (scaled_font->font_face, &scaled_font->font_matrix, &new_ctm, @@ -437,7 +430,6 @@ _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface, _cairo_scaled_font_freeze_cache (surface->scaled_font); status = _cairo_scaled_glyph_lookup (surface->scaled_font, glyph_index, - CAIRO_SCALED_GLYPH_INFO_METRICS | CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE, &scaled_glyph); @@ -454,10 +446,7 @@ _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface, if (unlikely (status)) goto cleanup; - status2 = _cairo_pdf_operators_flush (&surface->pdf_operators); - if (status == CAIRO_STATUS_SUCCESS) - status = status2; - + status = _cairo_pdf_operators_flush (&surface->pdf_operators); if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) status = CAIRO_STATUS_SUCCESS; @@ -514,7 +503,7 @@ _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface, status2 = cairo_matrix_invert (&font_matrix_inverse); /* The invertability of font_matrix is tested in - * pdf_operators_show_glyphs before any glyphs are mappped to the + * pdf_operators_show_glyphs before any glyphs are mapped to the * subset. */ assert (status2 == CAIRO_STATUS_SUCCESS); diff --git a/gfx/cairo/cairo/src/cairo-types-private.h b/gfx/cairo/cairo/src/cairo-types-private.h index 3a3b8496273b..93b035d7cf69 100644 --- a/gfx/cairo/cairo/src/cairo-types-private.h +++ b/gfx/cairo/cairo/src/cairo-types-private.h @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -44,18 +44,31 @@ #include "cairo-list-private.h" #include "cairo-reference-count-private.h" +/** + * SECTION:cairo-types + * @Title: Types + * @Short_Description: Generic data types + * + * This section lists generic data types used in the cairo API. + */ + typedef struct _cairo_array cairo_array_t; typedef struct _cairo_backend cairo_backend_t; +typedef struct _cairo_boxes_t cairo_boxes_t; typedef struct _cairo_cache cairo_cache_t; +typedef struct _cairo_composite_rectangles cairo_composite_rectangles_t; typedef struct _cairo_clip cairo_clip_t; typedef struct _cairo_clip_path cairo_clip_path_t; typedef struct _cairo_color cairo_color_t; +typedef struct _cairo_color_stop cairo_color_stop_t; +typedef struct _cairo_device_backend cairo_device_backend_t; typedef struct _cairo_font_face_backend cairo_font_face_backend_t; typedef struct _cairo_gstate cairo_gstate_t; typedef struct _cairo_hash_entry cairo_hash_entry_t; typedef struct _cairo_hash_table cairo_hash_table_t; typedef struct _cairo_image_surface cairo_image_surface_t; typedef struct _cairo_mime_data cairo_mime_data_t; +typedef struct _cairo_observer cairo_observer_t; typedef struct _cairo_output_stream cairo_output_stream_t; typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_t; typedef struct _cairo_path_fixed cairo_path_fixed_t; @@ -64,12 +77,19 @@ typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t; typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t; typedef struct _cairo_solid_pattern cairo_solid_pattern_t; typedef struct _cairo_surface_backend cairo_surface_backend_t; +typedef struct _cairo_surface_snapshot cairo_surface_snapshot_t; +typedef struct _cairo_surface_subsurface cairo_surface_subsurface_t; typedef struct _cairo_surface_wrapper cairo_surface_wrapper_t; typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t; typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t; typedef cairo_array_t cairo_user_data_array_t; +struct _cairo_observer { + cairo_list_t link; + void (*callback) (cairo_observer_t *self, void *arg); +}; + /** * cairo_hash_entry_t: * @@ -117,11 +137,43 @@ struct _cairo_array { cairo_bool_t is_snapshot; }; +/** + * cairo_lcd_filter_t: + * @CAIRO_LCD_FILTER_DEFAULT: Use the default LCD filter for + * font backend and target device + * @CAIRO_LCD_FILTER_NONE: Do not perform LCD filtering + * @CAIRO_LCD_FILTER_INTRA_PIXEL: Intra-pixel filter + * @CAIRO_LCD_FILTER_FIR3: FIR filter with a 3x3 kernel + * @CAIRO_LCD_FILTER_FIR5: FIR filter with a 5x5 kernel + * + * The LCD filter specifies the low-pass filter applied to LCD-optimized + * bitmaps generated with an antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL. + * + * Note: This API was temporarily made available in the public + * interface during the 1.7.x development series, but was made private + * before 1.8. + **/ +typedef enum _cairo_lcd_filter { + CAIRO_LCD_FILTER_DEFAULT, + CAIRO_LCD_FILTER_NONE, + CAIRO_LCD_FILTER_INTRA_PIXEL, + CAIRO_LCD_FILTER_FIR3, + CAIRO_LCD_FILTER_FIR5 +} cairo_lcd_filter_t; + +typedef enum _cairo_round_glyph_positions { + CAIRO_ROUND_GLYPH_POS_DEFAULT, + CAIRO_ROUND_GLYPH_POS_ON, + CAIRO_ROUND_GLYPH_POS_OFF +} cairo_round_glyph_positions_t; + struct _cairo_font_options { cairo_antialias_t antialias; cairo_subpixel_order_t subpixel_order; + cairo_lcd_filter_t lcd_filter; cairo_hint_style_t hint_style; cairo_hint_metrics_t hint_metrics; + cairo_round_glyph_positions_t round_glyph_positions; }; /* XXX: Right now, the _cairo_color structure puts unpremultiplied @@ -142,6 +194,20 @@ struct _cairo_color { unsigned short alpha_short; }; +struct _cairo_color_stop { + /* unpremultiplied */ + double red; + double green; + double blue; + double alpha; + + /* unpremultipled, for convenience */ + uint16_t red_short; + uint16_t green_short; + uint16_t blue_short; + uint16_t alpha_short; +}; + typedef enum _cairo_paginated_mode { CAIRO_PAGINATED_MODE_ANALYZE, /* analyze page regions */ CAIRO_PAGINATED_MODE_RENDER, /* render page contents */ @@ -164,7 +230,8 @@ typedef enum _cairo_int_status { } cairo_int_status_t; typedef enum _cairo_internal_surface_type { - CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED = 0x1000, + CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT = 0x1000, + CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED, CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS, CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED, @@ -209,29 +276,6 @@ typedef struct _cairo_point_int { #define CAIRO_RECT_INT_MIN (INT_MIN >> CAIRO_FIXED_FRAC_BITS) #define CAIRO_RECT_INT_MAX (INT_MAX >> CAIRO_FIXED_FRAC_BITS) -/* Rectangles that take part in a composite operation. - * - * This defines four translations that define which pixels of the - * source pattern, mask, clip and destination surface take part in a - * general composite operation. The idea is that the pixels at - * - * (i,j)+(src.x, src.y) of the source, - * (i,j)+(mask.x, mask.y) of the mask, - * (i,j)+(clip.x, clip.y) of the clip and - * (i,j)+(dst.x, dst.y) of the destination - * - * all combine together to form the result at (i,j)+(dst.x,dst.y), - * for i,j ranging in [0,width) and [0,height) respectively. - */ -typedef struct _cairo_composite_rectangles { - cairo_point_int_t src; - cairo_point_int_t mask; - cairo_point_int_t clip; - cairo_point_int_t dst; - int width; - int height; -} cairo_composite_rectangles_t; - typedef enum _cairo_direction { CAIRO_DIRECTION_FORWARD, CAIRO_DIRECTION_REVERSE @@ -322,7 +366,8 @@ typedef struct _cairo_format_masks { typedef enum { CAIRO_STOCK_WHITE, CAIRO_STOCK_BLACK, - CAIRO_STOCK_TRANSPARENT + CAIRO_STOCK_TRANSPARENT, + CAIRO_STOCK_NUM_COLORS, } cairo_stock_t; typedef enum _cairo_image_transparency { @@ -335,7 +380,7 @@ typedef enum _cairo_image_transparency { struct _cairo_mime_data { cairo_reference_count_t ref_count; unsigned char *data; - unsigned int length; + unsigned long length; cairo_destroy_func_t destroy; void *closure; }; @@ -356,7 +401,6 @@ struct _cairo_pattern { struct _cairo_solid_pattern { cairo_pattern_t base; cairo_color_t color; - cairo_content_t content; }; typedef struct _cairo_surface_pattern { @@ -367,7 +411,7 @@ typedef struct _cairo_surface_pattern { typedef struct _cairo_gradient_stop { double offset; - cairo_color_t color; + cairo_color_stop_t color; } cairo_gradient_stop_t; typedef struct _cairo_gradient_pattern { @@ -411,4 +455,30 @@ typedef union { cairo_gradient_pattern_union_t gradient; } cairo_pattern_union_t; +/* + * A #cairo_unscaled_font_t is just an opaque handle we use in the + * glyph cache. + */ +typedef struct _cairo_unscaled_font { + cairo_hash_entry_t hash_entry; + cairo_reference_count_t ref_count; + const cairo_unscaled_font_backend_t *backend; +} cairo_unscaled_font_t; + +typedef struct _cairo_scaled_glyph { + cairo_hash_entry_t hash_entry; + + cairo_text_extents_t metrics; /* user-space metrics */ + cairo_text_extents_t fs_metrics; /* font-space metrics */ + cairo_box_t bbox; /* device-space bounds */ + int16_t x_advance; /* device-space rounded X advance */ + int16_t y_advance; /* device-space rounded Y advance */ + + unsigned int has_info; + cairo_image_surface_t *surface; /* device-space image */ + cairo_path_fixed_t *path; /* device-space outline */ + cairo_surface_t *recording_surface; /* device-space recording-surface */ + + void *surface_private; /* for the surface backend */ +} cairo_scaled_glyph_t; #endif /* CAIRO_TYPES_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-unicode.c b/gfx/cairo/cairo/src/cairo-unicode.c index b1567d42d6e0..88de39516b6c 100644 --- a/gfx/cairo/cairo/src/cairo-unicode.c +++ b/gfx/cairo/cairo/src/cairo-unicode.c @@ -18,7 +18,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -41,6 +41,7 @@ */ #include "cairoint.h" +#include "cairo-error-private.h" #define UTF8_COMPUTE(Char, Mask, Len) \ if (Char < 128) \ diff --git a/gfx/cairo/cairo/src/cairo-user-font-private.h b/gfx/cairo/cairo/src/cairo-user-font-private.h index 2a39ff97a8e7..d54ef78b44e0 100644 --- a/gfx/cairo/cairo/src/cairo-user-font-private.h +++ b/gfx/cairo/cairo/src/cairo-user-font-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-user-font.c b/gfx/cairo/cairo/src/cairo-user-font.c index 3304392f4501..a524d588fa94 100644 --- a/gfx/cairo/cairo/src/cairo-user-font.c +++ b/gfx/cairo/cairo/src/cairo-user-font.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,6 +38,29 @@ #include "cairo-user-font-private.h" #include "cairo-recording-surface-private.h" #include "cairo-analysis-surface-private.h" +#include "cairo-error-private.h" + +/** + * SECTION:cairo-user-fonts + * @Title:User Fonts + * @Short_Description: Font support with font data provided by the user + * + * The user-font feature allows the cairo user to provide drawings for glyphs + * in a font. This is most useful in implementing fonts in non-standard + * formats, like SVG fonts and Flash fonts, but can also be used by games and + * other application to draw "funky" fonts. + */ + +/** + * CAIRO_HAS_USER_FONT: + * + * Defined if the user font backend is available. + * This macro can be used to conditionally compile backend-specific code. + * The user font backend is always built in versions of cairo that support + * this feature (1.8 and later). + * + * @Since: 1.8 + */ typedef struct _cairo_user_scaled_font_methods { cairo_user_scaled_font_init_func_t init; @@ -74,22 +97,34 @@ typedef struct _cairo_user_scaled_font { /* #cairo_user_scaled_font_t */ -static cairo_t * -_cairo_user_scaled_font_create_recording_context (cairo_user_scaled_font_t *scaled_font) +static cairo_surface_t * +_cairo_user_scaled_font_create_recording_surface (const cairo_user_scaled_font_t *scaled_font) { cairo_content_t content; - cairo_surface_t *recording_surface; - cairo_t *cr; content = scaled_font->base.options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_ALPHA; - recording_surface = cairo_recording_surface_create (content, NULL); - cr = cairo_create (recording_surface); - cairo_surface_destroy (recording_surface); + return cairo_recording_surface_create (content, NULL); +} + + +static cairo_t * +_cairo_user_scaled_font_create_recording_context (const cairo_user_scaled_font_t *scaled_font, + cairo_surface_t *recording_surface) +{ + cairo_t *cr; + + cr = cairo_create (recording_surface); + + if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) { + cairo_matrix_t scale; + scale = scaled_font->base.scale; + scale.x0 = scale.y0 = 0.; + cairo_set_matrix (cr, &scale); + } - cairo_set_matrix (cr, &scaled_font->base.scale); cairo_set_font_size (cr, 1.0); cairo_set_font_options (cr, &scaled_font->base.options); cairo_set_source_rgb (cr, 1., 1., 1.); @@ -112,25 +147,26 @@ _cairo_user_scaled_glyph_init (void *abstract_font, cairo_text_extents_t extents = scaled_font->default_glyph_extents; cairo_t *cr; - cr = _cairo_user_scaled_font_create_recording_context (scaled_font); + if (!face->scaled_font_methods.render_glyph) + return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; - if (face->scaled_font_methods.render_glyph) { + recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font); + + /* special case for 0 rank matrix (as in _cairo_scaled_font_init): empty surface */ + if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) { + cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface); status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font, _cairo_scaled_glyph_index(scaled_glyph), cr, &extents); - } else - status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_status (cr); - if (status == CAIRO_STATUS_SUCCESS) - status = cairo_status (cr); + cairo_destroy (cr); - recording_surface = cairo_surface_reference (cairo_get_target (cr)); - - cairo_destroy (cr); - - if (unlikely (status)) { - cairo_surface_destroy (recording_surface); - return status; + if (unlikely (status)) { + cairo_surface_destroy (recording_surface); + return status; + } } _cairo_scaled_glyph_set_recording_surface (scaled_glyph, @@ -419,9 +455,12 @@ _cairo_user_font_face_scaled_font_create (void *abstract_ /* Give away fontmap lock such that user-font can use other fonts */ status = _cairo_scaled_font_register_placeholder_and_unlock_font_map (&user_scaled_font->base); if (status == CAIRO_STATUS_SUCCESS) { + cairo_surface_t *recording_surface; cairo_t *cr; - cr = _cairo_user_scaled_font_create_recording_context (user_scaled_font); + recording_surface = _cairo_user_scaled_font_create_recording_surface (user_scaled_font); + cr = _cairo_user_scaled_font_create_recording_context (user_scaled_font, recording_surface); + cairo_surface_destroy (recording_surface); status = font_face->scaled_font_methods.init (&user_scaled_font->base, cr, diff --git a/gfx/cairo/cairo/src/cairo-version.c b/gfx/cairo/cairo/src/cairo-version.c index fd7bf7a52bfd..b07b48b37ab6 100644 --- a/gfx/cairo/cairo/src/cairo-version.c +++ b/gfx/cairo/cairo/src/cairo-version.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -44,6 +44,162 @@ #undef CAIRO_VERSION_H #include "cairo-features.h" +/** + * SECTION:cairo-version + * @Title: Version Information + * @Short_Description: Compile-time and run-time version checks. + * + * Cairo has a three-part version number scheme. In this scheme, we use + * even vs. odd numbers to distinguish fixed points in the software + * vs. in-progress development, (such as from git instead of a tar file, + * or as a "snapshot" tar file as opposed to a "release" tar file). + * + * + * _____ Major. Always 1, until we invent a new scheme. + * / ___ Minor. Even/Odd = Release/Snapshot (tar files) or Branch/Head (git) + * | / _ Micro. Even/Odd = Tar-file/git + * | | / + * 1.0.0 + * + * + * Here are a few examples of versions that one might see. + * + * Releases + * -------- + * 1.0.0 - A major release + * 1.0.2 - A subsequent maintenance release + * 1.2.0 - Another major release + * + * Snapshots + * --------- + * 1.1.2 - A snapshot (working toward the 1.2.0 release) + * + * In-progress development (eg. from git) + * -------------------------------------- + * 1.0.1 - Development on a maintenance branch (toward 1.0.2 release) + * 1.1.1 - Development on head (toward 1.1.2 snapshot and 1.2.0 release) + * + * + * + * Compatibility + * + * The API/ABI compatibility guarantees for various versions are as + * follows. First, let's assume some cairo-using application code that is + * successfully using the API/ABI "from" one version of cairo. Then let's + * ask the question whether this same code can be moved "to" the API/ABI + * of another version of cairo. + * + * Moving from a release to any later version (release, snapshot, + * development) is always guaranteed to provide compatibility. + * + * Moving from a snapshot to any later version is not guaranteed to + * provide compatibility, since snapshots may introduce new API that ends + * up being removed before the next release. + * + * Moving from an in-development version (odd micro component) to any + * later version is not guaranteed to provide compatibility. In fact, + * there's not even a guarantee that the code will even continue to work + * with the same in-development version number. This is because these + * numbers don't correspond to any fixed state of the software, but + * rather the many states between snapshots and releases. + * + * + * + * Examining the version + * + * Cairo provides the ability to examine the version at either + * compile-time or run-time and in both a human-readable form as well as + * an encoded form suitable for direct comparison. Cairo also provides the + * macro CAIRO_VERSION_ENCODE() to perform the encoding. + * + * + * Compile-time + * ------------ + * CAIRO_VERSION_STRING Human-readable + * CAIRO_VERSION Encoded, suitable for comparison + * + * Run-time + * -------- + * cairo_version_string() Human-readable + * cairo_version() Encoded, suitable for comparison + * + * + * For example, checking that the cairo version is greater than or equal + * to 1.0.0 could be achieved at compile-time or run-time as follows: + * + * + * ##if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 0, 0) + * printf ("Compiling with suitable cairo version: %s\n", %CAIRO_VERSION_STRING); + * ##endif + * + * if (cairo_version() >= CAIRO_VERSION_ENCODE(1, 0, 0)) + * printf ("Running with suitable cairo version: %s\n", cairo_version_string ()); + * + * + * + */ + +/** + * CAIRO_VERSION: + * + * The version of cairo available at compile-time, encoded using + * CAIRO_VERSION_ENCODE(). + */ + +/** + * CAIRO_VERSION_MAJOR: + * + * The major component of the version of cairo available at compile-time. + */ + +/** + * CAIRO_VERSION_MINOR: + * + * The minor component of the version of cairo available at compile-time. + */ + +/** + * CAIRO_VERSION_MICRO: + * + * The micro component of the version of cairo available at compile-time. + */ + +/** + * CAIRO_VERSION_STRING: + * + * A human-readable string literal containing the version of cairo available + * at compile-time, in the form of "X.Y.Z". + */ + +/** + * CAIRO_VERSION_ENCODE: + * @major: the major component of the version number + * @minor: the minor component of the version number + * @micro: the micro component of the version number + * + * This macro encodes the given cairo version into an integer. The numbers + * returned by %CAIRO_VERSION and cairo_version() are encoded using this macro. + * Two encoded version numbers can be compared as integers. The encoding ensures + * that later versions compare greater than earlier versions. + * + * @Returns: the encoded version. + */ + +/** + * CAIRO_VERSION_STRINGIZE: + * @major: the major component of the version number + * @minor: the minor component of the version number + * @micro: the micro component of the version number + * + * This macro encodes the given cairo version into an string. The numbers + * returned by %CAIRO_VERSION_STRING and cairo_version_string() are encoded using this macro. + * The parameters to this macro must expand to numerical literals. + * + * @Returns: a string literal containing the version. + * + * @Since: 1.8 + */ + /** * cairo_version: * diff --git a/gfx/cairo/cairo/src/cairo-vg-surface.c b/gfx/cairo/cairo/src/cairo-vg-surface.c index 5ca01b6e0e4c..acc3f804bc28 100644 --- a/gfx/cairo/cairo/src/cairo-vg-surface.c +++ b/gfx/cairo/cairo/src/cairo-vg-surface.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,10 +38,11 @@ #include "cairo-vg.h" +#include "cairo-cache-private.h" +#include "cairo-error-private.h" #include "cairo-path-fixed-private.h" #include "cairo-recording-surface-private.h" #include "cairo-surface-clipper-private.h" -#include "cairo-cache-private.h" #include #include @@ -409,7 +410,6 @@ _vg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, cairo_vg_surface_t, clipper); cairo_vg_surface_t *mask; - cairo_solid_pattern_t white; cairo_status_t status; if (path == NULL) { @@ -428,9 +428,9 @@ _vg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, if (unlikely (mask->base.status)) return mask->base.status; - _cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_ALPHA); status = _cairo_surface_fill (&mask->base, - CAIRO_OPERATOR_SOURCE, &white.base, + CAIRO_OPERATOR_SOURCE, + &_cairo_pattern_white.base, path, fill_rule, tolerance, antialias, NULL); if (status) { @@ -958,8 +958,7 @@ _vg_setup_surface_source (cairo_vg_context_t *context, cairo_status_t status; snapshot = _cairo_surface_has_snapshot (spat->surface, - &cairo_vg_surface_backend, - spat->surface->content); + &cairo_vg_surface_backend); if (snapshot != NULL) { clone = (cairo_vg_surface_t *) cairo_surface_reference (snapshot); goto DONE; @@ -983,12 +982,8 @@ _vg_setup_surface_source (cairo_vg_context_t *context, return status; } - status = _cairo_surface_attach_snapshot (spat->surface, &clone->base, - _vg_surface_remove_from_cache); - if (unlikely (status)) { - cairo_surface_destroy (&clone->base); - return status; - } + _cairo_surface_attach_snapshot (spat->surface, &clone->base, + _vg_surface_remove_from_cache); DONE: cairo_surface_destroy (&context->source->base); @@ -1606,6 +1601,7 @@ _vg_surface_create_internal (cairo_vg_context_t *context, _cairo_surface_init (&surface->base, &cairo_vg_surface_backend, + NULL, /* device */ _vg_format_to_content (format)); surface->width = width; diff --git a/gfx/cairo/cairo/src/cairo-vg.h b/gfx/cairo/cairo/src/cairo-vg.h index 98392fc2ddb2..f9a62e51c698 100644 --- a/gfx/cairo/cairo/src/cairo-vg.h +++ b/gfx/cairo/cairo/src/cairo-vg.h @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-wideint-private.h b/gfx/cairo/cairo/src/cairo-wideint-private.h index d1322e342154..b9f8dae64f6b 100644 --- a/gfx/cairo/cairo/src/cairo-wideint-private.h +++ b/gfx/cairo/cairo/src/cairo-wideint-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-wideint-type-private.h b/gfx/cairo/cairo/src/cairo-wideint-type-private.h index c7363c02969b..4c910edf5fab 100644 --- a/gfx/cairo/cairo/src/cairo-wideint-type-private.h +++ b/gfx/cairo/cairo/src/cairo-wideint-type-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-wideint.c b/gfx/cairo/cairo/src/cairo-wideint.c index 2c70d8662e89..78dedcdf0cf0 100644 --- a/gfx/cairo/cairo/src/cairo-wideint.c +++ b/gfx/cairo/cairo/src/cairo-wideint.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -802,7 +802,7 @@ _cairo_int_96by64_32x64_divrem (cairo_int128_t num, cairo_int64_t den) uqr = _cairo_uint_96by64_32x64_divrem (num, nonneg_den); if (_cairo_uint64_eq (uqr.rem, nonneg_den)) { /* bail on overflow. */ - qr.quo = _cairo_uint32s_to_uint64 (0x7FFFFFFF, -1U);; + qr.quo = _cairo_uint32s_to_uint64 (0x7FFFFFFF, -1U); qr.rem = den; return qr; } diff --git a/gfx/cairo/cairo/src/cairo-win32-font.c b/gfx/cairo/cairo/src/cairo-win32-font.c index 3d5489b29e86..940d896647cf 100644 --- a/gfx/cairo/cairo/src/cairo-win32-font.c +++ b/gfx/cairo/cairo/src/cairo-win32-font.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -45,6 +45,7 @@ #include "cairoint.h" #include "cairo-win32-private.h" +#include "cairo-error-private.h" #ifndef SPI_GETFONTSMOOTHINGTYPE #define SPI_GETFONTSMOOTHINGTYPE 0x200a @@ -61,6 +62,23 @@ #define CMAP_TAG 0x70616d63 +/** + * SECTION:cairo-win32-fonts + * @Title: Win32 Fonts + * @Short_Description: Font support for Microsoft Windows + * @See_Also: #cairo_font_face_t + * + * The Microsoft Windows font backend is primarily used to render text on + * Microsoft Windows systems. + */ + +/** + * CAIRO_HAS_WIN32_FONT: + * + * Defined if the Microsoft Windows font backend is available. + * This macro can be used to conditionally compile backend-specific code. + */ + const cairo_scaled_font_backend_t _cairo_win32_scaled_font_backend; typedef struct { @@ -966,7 +984,7 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f extents.height = scaled_font->base.ctm.yy * (font_extents.ascent + font_extents.descent) / scaled_font->y_scale; extents.x_advance = extents.width; extents.y_advance = 0; - } else if (scaled_font->preserve_axes && scaled_font->base.options.hint_style != CAIRO_HINT_METRICS_OFF) { + } else if (scaled_font->preserve_axes && scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { /* If we aren't rotating / skewing the axes, then we get the metrics * from the GDI in device space and convert to font space. */ diff --git a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c index 94a8fd94c138..b95a059b2c77 100644 --- a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c +++ b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -46,6 +46,7 @@ #include "cairoint.h" +#include "cairo-error-private.h" #include "cairo-paginated-private.h" #include "cairo-clip-private.h" @@ -262,7 +263,7 @@ _cairo_win32_printing_surface_analyze_operation (cairo_win32_surface_t *surface, return analyze_surface_pattern_transparency (surface_pattern); } - if (_cairo_pattern_is_opaque (pattern)) + if (_cairo_pattern_is_opaque (pattern, NULL)) return CAIRO_STATUS_SUCCESS; else return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; @@ -284,9 +285,9 @@ _cairo_win32_printing_surface_init_clear_color (cairo_win32_surface_t *surface, cairo_solid_pattern_t *color) { if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) - _cairo_pattern_init_solid (color, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR); + _cairo_pattern_init_solid (color, CAIRO_COLOR_WHITE); else - _cairo_pattern_init_solid (color, CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR); + _cairo_pattern_init_solid (color, CAIRO_COLOR_BLACK); } static COLORREF @@ -438,13 +439,9 @@ _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_surface_t * old_content = surface->content; if (recording_surface->base.content == CAIRO_CONTENT_COLOR) { - cairo_pattern_t *source; - cairo_solid_pattern_t black; - surface->content = CAIRO_CONTENT_COLOR; - _cairo_pattern_init_solid (&black, CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR); - source = (cairo_pattern_t*) &black; - status = _cairo_win32_printing_surface_paint_solid_pattern (surface, source); + status = _cairo_win32_printing_surface_paint_solid_pattern (surface, + &_cairo_pattern_black.base); if (status) return status; } @@ -500,7 +497,7 @@ _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_surface_t * SelectClipPath (surface->dc, RGN_AND); SaveDC (surface->dc); /* Allow clip path to be reset during replay */ - status = _cairo_recording_surface_replay_region (&recording_surface->base, + status = _cairo_recording_surface_replay_region (&recording_surface->base, NULL, &surface->base, CAIRO_RECORDING_REGION_NATIVE); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); @@ -524,11 +521,11 @@ static cairo_int_status_t _cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface, cairo_surface_t *source, const unsigned char **data, - unsigned int *length, + unsigned long *length, cairo_image_info_t *info) { const unsigned char *mime_data; - unsigned int mime_data_length; + unsigned long mime_data_length; cairo_int_status_t status; DWORD result; @@ -562,11 +559,11 @@ static cairo_int_status_t _cairo_win32_printing_surface_check_png (cairo_win32_surface_t *surface, cairo_surface_t *source, const unsigned char **data, - unsigned int *length, + unsigned long *length, cairo_image_info_t *info) { const unsigned char *mime_data; - unsigned int mime_data_length; + unsigned long mime_data_length; cairo_int_status_t status; DWORD result; @@ -614,7 +611,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf RECT clip; const cairo_color_t *background_color; const unsigned char *mime_data; - unsigned int mime_size; + unsigned long mime_size; cairo_image_info_t mime_info; cairo_bool_t use_mime; DWORD mime_type; @@ -680,8 +677,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf } _cairo_pattern_init_solid (&background_pattern, - background_color, - CAIRO_CONTENT_COLOR); + background_color); status = _cairo_surface_paint (opaque_surface, CAIRO_OPERATOR_SOURCE, &background_pattern.base, @@ -791,7 +787,7 @@ _cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t *su } static void -vertex_set_color (TRIVERTEX *vert, cairo_color_t *color) +vertex_set_color (TRIVERTEX *vert, cairo_color_stop_t *color) { /* MSDN says that the range here is 0x0000 .. 0xff00; * that may well be a typo, but just chop the low bits @@ -1161,6 +1157,7 @@ _cairo_win32_printing_surface_get_font_options (void *abstract_ cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); + _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON); } static cairo_int_status_t @@ -1245,9 +1242,9 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *stroke_ctm, - cairo_matrix_t *stroke_ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) @@ -1835,6 +1832,7 @@ cairo_win32_printing_surface_create (HDC hdc) _cairo_win32_printing_surface_init_language_pack (surface); _cairo_surface_init (&surface->base, &cairo_win32_printing_surface_backend, + NULL, /* device */ CAIRO_CONTENT_COLOR_ALPHA); paginated = _cairo_paginated_surface_create (&surface->base, diff --git a/gfx/cairo/cairo/src/cairo-win32-private.h b/gfx/cairo/cairo/src/cairo-win32-private.h index b13b5eb2ec64..6a28f56bffb7 100644 --- a/gfx/cairo/cairo/src/cairo-win32-private.h +++ b/gfx/cairo/cairo/src/cairo-win32-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -49,6 +49,9 @@ #define WIN32_FONT_LOGICAL_SCALE 1 + +CAIRO_BEGIN_DECLS + typedef struct _cairo_win32_surface { cairo_surface_t base; @@ -235,7 +238,6 @@ inline BOOL ModifyWorldTransform(HDC hdc, CONST XFORM * lpxf, DWORD mode) { retu #endif #ifdef CAIRO_HAS_DWRITE_FONT -CAIRO_BEGIN_DECLS cairo_int_status_t _cairo_dwrite_show_glyphs_on_surface(void *surface, @@ -250,6 +252,6 @@ cairo_int_status_t _cairo_dwrite_scaled_font_create_win32_scaled_font(cairo_scaled_font_t *scaled_font, cairo_scaled_font_t **new_font); -CAIRO_END_DECLS #endif /* CAIRO_HAS_DWRITE_FONT */ +CAIRO_END_DECLS #endif /* CAIRO_WIN32_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-win32-surface.c b/gfx/cairo/cairo/src/cairo-win32-surface.c index 0bb1904d84fe..5edff97cb0fc 100644 --- a/gfx/cairo/cairo/src/cairo-win32-surface.c +++ b/gfx/cairo/cairo/src/cairo-win32-surface.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -48,6 +48,8 @@ #include "cairoint.h" #include "cairo-clip-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-error-private.h" #include "cairo-paginated-private.h" #include "cairo-win32-private.h" #include "cairo-scaled-font-subsets-private.h" @@ -74,6 +76,30 @@ #define PELS_72DPI ((LONG)(72. / 0.0254)) +/** + * SECTION:cairo-win32 + * @Title: Win32 Surfaces + * @Short_Description: Microsoft Windows surface support + * @See_Also: #cairo_surface_t + * + * The Microsoft Windows surface is used to render cairo graphics to + * Microsoft Windows windows, bitmaps, and printing device contexts. + * + * The surface returned by cairo_win32_printing_surface_create() is of surface + * type %CAIRO_SURFACE_TYPE_WIN32_PRINTING and is a multi-page vector surface + * type. + * + * The surface returned by the other win32 constructors is of surface type + * %CAIRO_SURFACE_TYPE_WIN32 and is a raster surface type. + */ + +/** + * CAIRO_HAS_WIN32_SURFACE: + * + * Defined if the Microsoft Windows surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + */ + static const cairo_surface_backend_t cairo_win32_surface_backend; /** @@ -96,11 +122,11 @@ _cairo_win32_print_gdi_error (const char *context) NULL, last_error, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR) &lpMsgBuf, + (LPWSTR) &lpMsgBuf, 0, NULL)) { fprintf (stderr, "%s: Unknown GDI error", context); } else { - fprintf (stderr, "%s: %S", context, (char *)lpMsgBuf); + fwprintf (stderr, L"%s: %S", context, (wchar_t *)lpMsgBuf); LocalFree (lpMsgBuf); } @@ -177,6 +203,9 @@ _create_dc_and_bitmap (cairo_win32_surface_t *surface, surface->is_dib = FALSE; switch (format) { + default: + case CAIRO_FORMAT_INVALID: + return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); case CAIRO_FORMAT_ARGB32: case CAIRO_FORMAT_RGB24: num_palette = 0; @@ -338,6 +367,9 @@ _cairo_win32_surface_create_for_dc (HDC original_dc, unsigned char *bits; int rowstride; + if (! CAIRO_FORMAT_VALID (format)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + surface = malloc (sizeof (cairo_win32_surface_t)); if (surface == NULL) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); @@ -369,7 +401,9 @@ _cairo_win32_surface_create_for_dc (HDC original_dc, surface->extents = surface->clip_rect; surface->font_subsets = NULL; - _cairo_surface_init (&surface->base, &cairo_win32_surface_backend, + _cairo_surface_init (&surface->base, + &cairo_win32_surface_backend, + NULL, /* device */ _cairo_content_from_format (format)); return &surface->base; @@ -518,8 +552,8 @@ static void _cairo_win32_convert_ddb_to_dib (cairo_win32_surface_t *surface) { cairo_win32_surface_t *new_surface; - int width = surface->extents.width; - int height = surface->extents.height; + int width = surface->extents.width + surface->extents.x; + int height = surface->extents.height + surface->extents.y; BOOL ok; HBITMAP oldbitmap; @@ -924,7 +958,7 @@ _cairo_win32_surface_composite_inner (cairo_win32_surface_t *src, } else if (!needs_alpha) { /* BitBlt or StretchBlt? */ if (!needs_scale && (dst->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT)) { - if (!BitBlt (dst->dc, + if (!BitBlt (dst->dc, dst_r.x, dst_r.y, dst_r.width, dst_r.height, src->dc, @@ -949,6 +983,8 @@ _cairo_win32_surface_composite_inner (cairo_win32_surface_t *src, return _cairo_win32_print_gdi_error ("StretchBlt"); } } else if (needs_alpha && !needs_scale) { + RECT r = {0, 0, 5000, 5000}; + //FillRect(dst->dc, &r, GetStockObject(DKGRAY_BRUSH)); return _composite_alpha_blend (dst, src, alpha, src_r.x, src_r.y, src_r.width, src_r.height, dst_r.x, dst_r.y, dst_r.width, dst_r.height); @@ -1137,18 +1173,20 @@ _cairo_win32_surface_composite (cairo_operator_t op, if (src_r.x < 0) { src_r.width += src_r.x; - src_r.x = 0; dst_r.width += src_r.x; dst_r.x -= src_r.x; + + src_r.x = 0; } if (src_r.y < 0) { src_r.height += src_r.y; - src_r.y = 0; - dst_r.height += dst_r.y; + dst_r.height += src_r.y; dst_r.y -= src_r.y; + + src_r.y = 0; } if (src_r.x + src_r.width > src_extents.width) { @@ -1751,7 +1789,9 @@ cairo_win32_surface_create_internal (HDC hdc, cairo_format_t format) surface->flags = _cairo_win32_flags_for_dc (surface->dc); - _cairo_surface_init (&surface->base, &cairo_win32_surface_backend, + _cairo_surface_init (&surface->base, + &cairo_win32_surface_backend, + NULL, /* device */ _cairo_content_from_format (format)); return &surface->base; @@ -2026,8 +2066,7 @@ cairo_win32_surface_get_image (cairo_surface_t *surface) static cairo_bool_t _cairo_win32_surface_is_similar (void *surface_a, - void *surface_b, - cairo_content_t content) + void *surface_b) { cairo_win32_surface_t *a = surface_a; cairo_win32_surface_t *b = surface_b; @@ -2098,11 +2137,10 @@ _cairo_win32_surface_span_renderer_finish (void *abstract_renderer) status = dst->image->backend->composite (renderer->op, renderer->pattern, mask_pattern, dst->image, - rects->src.x, - rects->src.y, + rects->bounded.x, rects->bounded.y, 0, 0, /* mask.x, mask.y */ - rects->dst.x, rects->dst.y, - rects->width, rects->height, + rects->bounded.x, rects->bounded.y, + rects->bounded.width, rects->bounded.height, renderer->clip_region); } else { /* otherwise go through the fallback_composite path which @@ -2110,11 +2148,10 @@ _cairo_win32_surface_span_renderer_finish (void *abstract_renderer) status = _cairo_surface_fallback_composite ( renderer->op, renderer->pattern, mask_pattern, &dst->base, - rects->src.x, - rects->src.y, + rects->bounded.x, rects->bounded.y, 0, 0, /* mask.x, mask.y */ - rects->dst.x, rects->dst.y, - rects->width, rects->height, + rects->bounded.x, rects->bounded.y, + rects->bounded.width, rects->bounded.height, renderer->clip_region); } cairo_pattern_destroy (mask_pattern); @@ -2150,8 +2187,8 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op, cairo_win32_surface_t *dst = abstract_dst; cairo_win32_surface_span_renderer_t *renderer; cairo_status_t status; - int width = rects->width; - int height = rects->height; + int width = rects->bounded.width; + int height = rects->bounded.height; renderer = calloc(1, sizeof(*renderer)); if (renderer == NULL) @@ -2181,12 +2218,1948 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op, return _cairo_span_renderer_create_in_error (status); } - renderer->mask_data = renderer->mask->data - rects->mask.x - rects->mask.y * renderer->mask->stride; + renderer->mask_data = renderer->mask->data - rects->bounded.x - rects->bounded.y * renderer->mask->stride; renderer->mask_stride = renderer->mask->stride; return &renderer->base; } +static cairo_int_status_t +_cairo_win32_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + cairo_win32_surface_t *surface = abstract_surface; + + if (surface->image) { + return _cairo_surface_paint (surface->image, op, source, clip); + } + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) +{ + cairo_win32_surface_t *surface = abstract_surface; + + if (surface->image) { + return _cairo_surface_mask (surface->image, op, source, mask, clip); + } + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_win32_surface_t *surface = abstract_surface; + + if (surface->image) { + return _cairo_surface_stroke (surface->image, op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + + } + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_win32_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_win32_surface_t *surface = abstract_surface; + + if (surface->image) { + return _cairo_surface_fill (surface->image, op, source, + path, fill_rule, + tolerance, antialias, + clip); + } + return CAIRO_INT_STATUS_UNSUPPORTED; +} + + +#include "cairoint.h" + +#include "cairo-boxes-private.h" +#include "cairo-clip-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-error-private.h" +#include "cairo-region-private.h" +#include "cairo-spans-private.h" +#include "cairo-surface-fallback-private.h" + +typedef struct { + cairo_surface_t *dst; + cairo_rectangle_int_t extents; + cairo_image_surface_t *image; + cairo_rectangle_int_t image_rect; + void *image_extra; +} fallback_state_t; + +/** + * _fallback_init: + * + * Acquire destination image surface needed for an image-based + * fallback. + * + * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the extents are not + * visible, %CAIRO_STATUS_SUCCESS if some portion is visible and all + * went well, or some error status otherwise. + **/ +static cairo_int_status_t +_fallback_init (fallback_state_t *state, + cairo_surface_t *dst, + int x, + int y, + int width, + int height) +{ + cairo_status_t status; + + state->extents.x = x; + state->extents.y = y; + state->extents.width = width; + state->extents.height = height; + + state->dst = dst; + + status = _cairo_surface_acquire_dest_image (dst, &state->extents, + &state->image, &state->image_rect, + &state->image_extra); + if (unlikely (status)) + return status; + + + /* XXX: This NULL value tucked away in state->image is a rather + * ugly interface. Cleaner would be to push the + * CAIRO_INT_STATUS_NOTHING_TO_DO value down into + * _cairo_surface_acquire_dest_image and its backend + * counterparts. */ + assert (state->image != NULL); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_fallback_fini (fallback_state_t *state) +{ + _cairo_surface_release_dest_image (state->dst, &state->extents, + state->image, &state->image_rect, + state->image_extra); +} + +typedef cairo_status_t +(*cairo_draw_func_t) (void *closure, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region); + +static cairo_status_t +_create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern, + cairo_clip_t *clip, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_t *mask; + cairo_region_t *clip_region = NULL, *fallback_region = NULL; + cairo_status_t status; + cairo_bool_t clip_surface = FALSE; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + if (unlikely (_cairo_status_is_error (status) || + status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + { + return status; + } + + clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* We need to use solid here, because to use CAIRO_OPERATOR_SOURCE with + * a mask (as called via _cairo_surface_mask) triggers assertion failures. + */ + mask = _cairo_surface_create_similar_solid (dst, + CAIRO_CONTENT_ALPHA, + extents->width, + extents->height, + CAIRO_COLOR_TRANSPARENT, + TRUE); + if (unlikely (mask->status)) + return mask->status; + + if (clip_region && (extents->x || extents->y)) { + fallback_region = cairo_region_copy (clip_region); + status = fallback_region->status; + if (unlikely (status)) + goto CLEANUP_SURFACE; + + cairo_region_translate (fallback_region, + -extents->x, + -extents->y); + clip_region = fallback_region; + } + + status = draw_func (draw_closure, CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, mask, + extents->x, extents->y, + extents, + clip_region); + if (unlikely (status)) + goto CLEANUP_SURFACE; + + if (clip_surface) + status = _cairo_clip_combine_with_surface (clip, mask, extents->x, extents->y); + + _cairo_pattern_init_for_surface (mask_pattern, mask); + + CLEANUP_SURFACE: + if (fallback_region) + cairo_region_destroy (fallback_region); + cairo_surface_destroy (mask); + + return status; +} + +/* Handles compositing with a clip surface when the operator allows + * us to combine the clip with the mask + */ +static cairo_status_t +_clip_and_composite_with_mask (cairo_clip_t *clip, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_pattern_t mask_pattern; + cairo_status_t status; + + status = _create_composite_mask_pattern (&mask_pattern, + clip, + draw_func, draw_closure, + dst, extents); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _cairo_surface_composite (op, + src, &mask_pattern.base, dst, + extents->x, extents->y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height, + NULL); + + _cairo_pattern_fini (&mask_pattern.base); + } + + return status; +} + +/* Handles compositing with a clip surface when we have to do the operation + * in two pieces and combine them together. + */ +static cairo_status_t +_clip_and_composite_combine (cairo_clip_t *clip, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_t *intermediate; + cairo_surface_pattern_t pattern; + cairo_surface_pattern_t clip_pattern; + cairo_surface_t *clip_surface; + int clip_x, clip_y; + cairo_status_t status; + + /* We'd be better off here creating a surface identical in format + * to dst, but we have no way of getting that information. Instead + * we ask the backend to create a similar surface of identical content, + * in the belief that the backend will do something useful - like use + * an identical format. For example, the xlib backend will endeavor to + * use a compatible depth to enable core protocol routines. + */ + intermediate = + _cairo_surface_create_similar_scratch (dst, dst->content, + extents->width, + extents->height); + if (intermediate == NULL) { + intermediate = + _cairo_image_surface_create_with_content (dst->content, + extents->width, + extents->width); + } + if (unlikely (intermediate->status)) + return intermediate->status; + + /* Initialize the intermediate surface from the destination surface */ + _cairo_pattern_init_for_surface (&pattern, dst); + status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, + &pattern.base, NULL, intermediate, + extents->x, extents->y, + 0, 0, + 0, 0, + extents->width, extents->height, + NULL); + _cairo_pattern_fini (&pattern.base); + if (unlikely (status)) + goto CLEANUP_SURFACE; + + status = (*draw_func) (draw_closure, op, + src, intermediate, + extents->x, extents->y, + extents, + NULL); + if (unlikely (status)) + goto CLEANUP_SURFACE; + + assert (clip->path != NULL); + clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y); + if (unlikely (clip_surface->status)) + goto CLEANUP_SURFACE; + + _cairo_pattern_init_for_surface (&clip_pattern, clip_surface); + + /* Combine that with the clip */ + status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_IN, + &clip_pattern.base, NULL, intermediate, + extents->x - clip_x, + extents->y - clip_y, + 0, 0, + 0, 0, + extents->width, extents->height, + NULL); + if (unlikely (status)) + goto CLEANUP_CLIP; + + /* Punch the clip out of the destination */ + status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT, + &clip_pattern.base, NULL, dst, + extents->x - clip_x, + extents->y - clip_y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height, + NULL); + if (unlikely (status)) + goto CLEANUP_CLIP; + + /* Now add the two results together */ + _cairo_pattern_init_for_surface (&pattern, intermediate); + status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, + &pattern.base, NULL, dst, + 0, 0, + 0, 0, + extents->x, extents->y, + extents->width, extents->height, + NULL); + _cairo_pattern_fini (&pattern.base); + + CLEANUP_CLIP: + _cairo_pattern_fini (&clip_pattern.base); + CLEANUP_SURFACE: + cairo_surface_destroy (intermediate); + + return status; +} + +/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's + * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip)) + */ +static cairo_status_t +_clip_and_composite_source (cairo_clip_t *clip, + const cairo_pattern_t *src, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_pattern_t mask_pattern; + cairo_region_t *clip_region = NULL; + cairo_status_t status; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + if (unlikely (_cairo_status_is_error (status) || + status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + { + return status; + } + } + + /* Create a surface that is mask IN clip */ + status = _create_composite_mask_pattern (&mask_pattern, + clip, + draw_func, draw_closure, + dst, extents); + if (unlikely (status)) + return status; + + /* Compute dest' = dest OUT (mask IN clip) */ + status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT, + &mask_pattern.base, NULL, dst, + 0, 0, + 0, 0, + extents->x, extents->y, + extents->width, extents->height, + clip_region); + + if (unlikely (status)) + goto CLEANUP_MASK_PATTERN; + + /* Now compute (src IN (mask IN clip)) ADD dest' */ + status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, + src, &mask_pattern.base, dst, + extents->x, extents->y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height, + clip_region); + + CLEANUP_MASK_PATTERN: + _cairo_pattern_fini (&mask_pattern.base); + return status; +} + +static int +_cairo_rectangle_empty (const cairo_rectangle_int_t *rect) +{ + return rect->width == 0 || rect->height == 0; +} + +/** + * _clip_and_composite: + * @clip: a #cairo_clip_t + * @op: the operator to draw with + * @src: source pattern + * @draw_func: function that can be called to draw with the mask onto a surface. + * @draw_closure: data to pass to @draw_func. + * @dst: destination surface + * @extents: rectangle holding a bounding box for the operation; this + * rectangle will be used as the size for the temporary + * surface. + * + * When there is a surface clip, we typically need to create an intermediate + * surface. This function handles the logic of creating a temporary surface + * drawing to it, then compositing the result onto the target surface. + * + * @draw_func is to called to draw the mask; it will be called no more + * than once. + * + * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded. + **/ +static cairo_status_t +_clip_and_composite (cairo_clip_t *clip, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_int_t *extents) +{ + cairo_status_t status; + + if (_cairo_rectangle_empty (extents)) + /* Nothing to do */ + return CAIRO_STATUS_SUCCESS; + + if (op == CAIRO_OPERATOR_CLEAR) { + src = &_cairo_pattern_white.base; + op = CAIRO_OPERATOR_DEST_OUT; + } + + if (op == CAIRO_OPERATOR_SOURCE) { + status = _clip_and_composite_source (clip, + src, + draw_func, draw_closure, + dst, extents); + } else { + cairo_bool_t clip_surface = FALSE; + cairo_region_t *clip_region = NULL; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + if (unlikely (_cairo_status_is_error (status) || + status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + { + return status; + } + + clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (clip_surface) { + if (_cairo_operator_bounded_by_mask (op)) { + status = _clip_and_composite_with_mask (clip, op, + src, + draw_func, draw_closure, + dst, extents); + } else { + status = _clip_and_composite_combine (clip, op, + src, + draw_func, draw_closure, + dst, extents); + } + } else { + status = draw_func (draw_closure, op, + src, dst, + 0, 0, + extents, + clip_region); + } + } + + return status; +} + +/* Composites a region representing a set of trapezoids. + */ +static cairo_status_t +_composite_trap_region (cairo_clip_t *clip, + const cairo_pattern_t *src, + cairo_operator_t op, + cairo_surface_t *dst, + cairo_region_t *trap_region, + const cairo_rectangle_int_t *extents) +{ + cairo_status_t status; + cairo_surface_pattern_t mask_pattern; + cairo_pattern_t *mask = NULL; + int mask_x = 0, mask_y =0; + + if (clip != NULL) { + cairo_surface_t *clip_surface = NULL; + int clip_x, clip_y; + + clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y); + if (unlikely (clip_surface->status)) + return clip_surface->status; + + if (op == CAIRO_OPERATOR_CLEAR) { + src = &_cairo_pattern_white.base; + op = CAIRO_OPERATOR_DEST_OUT; + } + + _cairo_pattern_init_for_surface (&mask_pattern, clip_surface); + mask_x = extents->x - clip_x; + mask_y = extents->y - clip_y; + mask = &mask_pattern.base; + } + + status = _cairo_surface_composite (op, src, mask, dst, + extents->x, extents->y, + mask_x, mask_y, + extents->x, extents->y, + extents->width, extents->height, + trap_region); + + if (mask != NULL) + _cairo_pattern_fini (mask); + + return status; +} + +typedef struct { + cairo_traps_t *traps; + cairo_antialias_t antialias; +} cairo_composite_traps_info_t; + +static cairo_status_t +_composite_traps_draw_func (void *closure, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) +{ + cairo_composite_traps_info_t *info = closure; + cairo_status_t status; + cairo_region_t *extents_region = NULL; + + if (dst_x != 0 || dst_y != 0) + _cairo_traps_translate (info->traps, - dst_x, - dst_y); + + if (clip_region == NULL && + !_cairo_operator_bounded_by_source (op)) { + extents_region = cairo_region_create_rectangle (extents); + if (unlikely (extents_region->status)) + return extents_region->status; + cairo_region_translate (extents_region, -dst_x, -dst_y); + clip_region = extents_region; + } + + status = _cairo_surface_composite_trapezoids (op, + src, dst, info->antialias, + extents->x, extents->y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + info->traps->traps, + info->traps->num_traps, + clip_region); + + if (extents_region) + cairo_region_destroy (extents_region); + + return status; +} + +enum { + HAS_CLEAR_REGION = 0x1, +}; + +static cairo_status_t +_clip_and_composite_region (const cairo_pattern_t *src, + cairo_operator_t op, + cairo_surface_t *dst, + cairo_region_t *trap_region, + cairo_clip_t *clip, + cairo_rectangle_int_t *extents) +{ + cairo_region_t clear_region; + unsigned int has_region = 0; + cairo_status_t status; + + if (! _cairo_operator_bounded_by_mask (op) && clip == NULL) { + /* If we optimize drawing with an unbounded operator to + * _cairo_surface_fill_rectangles() or to drawing with a + * clip region, then we have an additional region to clear. + */ + _cairo_region_init_rectangle (&clear_region, extents); + status = cairo_region_subtract (&clear_region, trap_region); + if (unlikely (status)) + return status; + + if (! cairo_region_is_empty (&clear_region)) + has_region |= HAS_CLEAR_REGION; + } + + if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) && + clip == NULL) + { + const cairo_color_t *color; + + if (op == CAIRO_OPERATOR_CLEAR) + color = CAIRO_COLOR_TRANSPARENT; + else + color = &((cairo_solid_pattern_t *)src)->color; + + /* Solid rectangles special case */ + status = _cairo_surface_fill_region (dst, op, color, trap_region); + } else { + /* For a simple rectangle, we can just use composite(), for more + * rectangles, we have to set a clip region. The cost of rasterizing + * trapezoids is pretty high for most backends currently, so it's + * worthwhile even if a region is needed. + * + * If we have a clip surface, we set it as the mask; this only works + * for bounded operators other than SOURCE; for unbounded operators, + * clip and mask cannot be interchanged. For SOURCE, the operator + * as implemented by the backends is different in its handling + * of the mask then what we want. + * + * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has + * more than rectangle and the destination doesn't support clip + * regions. In that case, we fall through. + */ + status = _composite_trap_region (clip, src, op, dst, + trap_region, extents); + } + + if (has_region & HAS_CLEAR_REGION) { + if (status == CAIRO_STATUS_SUCCESS) { + status = _cairo_surface_fill_region (dst, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &clear_region); + } + _cairo_region_fini (&clear_region); + } + + return status; +} + +/* avoid using region code to re-validate boxes */ +static cairo_status_t +_fill_rectangles (cairo_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_traps_t *traps, + cairo_clip_t *clip) +{ + const cairo_color_t *color; + cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)]; + cairo_rectangle_int_t *rects = stack_rects; + cairo_status_t status; + int i; + + if (! traps->is_rectilinear || ! traps->maybe_region) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* XXX: convert clip region to geometric boxes? */ + if (clip != NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* XXX: fallback for the region_subtract() operation */ + if (! _cairo_operator_bounded_by_mask (op)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! (src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (traps->has_intersections) { + if (traps->is_rectangular) { + status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING); + } else { + status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING); + } + if (unlikely (status)) + return status; + } + + for (i = 0; i < traps->num_traps; i++) { + if (! _cairo_fixed_is_integer (traps->traps[i].top) || + ! _cairo_fixed_is_integer (traps->traps[i].bottom) || + ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) || + ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x)) + { + traps->maybe_region = FALSE; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } + + if (traps->num_traps > ARRAY_LENGTH (stack_rects)) { + rects = _cairo_malloc_ab (traps->num_traps, + sizeof (cairo_rectangle_int_t)); + if (unlikely (rects == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + for (i = 0; i < traps->num_traps; i++) { + int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x); + int y1 = _cairo_fixed_integer_part (traps->traps[i].top); + int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x); + int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom); + + rects[i].x = x1; + rects[i].y = y1; + rects[i].width = x2 - x1; + rects[i].height = y2 - y1; + } + + if (op == CAIRO_OPERATOR_CLEAR) + color = CAIRO_COLOR_TRANSPARENT; + else + color = &((cairo_solid_pattern_t *)src)->color; + + status = _cairo_surface_fill_rectangles (dst, op, color, rects, i); + + if (rects != stack_rects) + free (rects); + + return status; +} + +/* fast-path for very common composite of a single rectangle */ +static cairo_status_t +_composite_rectangle (cairo_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_traps_t *traps, + cairo_clip_t *clip) +{ + cairo_rectangle_int_t rect; + + if (clip != NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (traps->num_traps > 1 || ! traps->is_rectilinear || ! traps->maybe_region) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_fixed_is_integer (traps->traps[0].top) || + ! _cairo_fixed_is_integer (traps->traps[0].bottom) || + ! _cairo_fixed_is_integer (traps->traps[0].left.p1.x) || + ! _cairo_fixed_is_integer (traps->traps[0].right.p1.x)) + { + traps->maybe_region = FALSE; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + rect.x = _cairo_fixed_integer_part (traps->traps[0].left.p1.x); + rect.y = _cairo_fixed_integer_part (traps->traps[0].top); + rect.width = _cairo_fixed_integer_part (traps->traps[0].right.p1.x) - rect.x; + rect.height = _cairo_fixed_integer_part (traps->traps[0].bottom) - rect.y; + + return _cairo_surface_composite (op, src, NULL, dst, + rect.x, rect.y, + 0, 0, + rect.x, rect.y, + rect.width, rect.height, + NULL); +} + +/* Warning: This call modifies the coordinates of traps */ +static cairo_status_t +_clip_and_composite_trapezoids (const cairo_pattern_t *src, + cairo_operator_t op, + cairo_surface_t *dst, + cairo_traps_t *traps, + cairo_antialias_t antialias, + cairo_clip_t *clip, + cairo_rectangle_int_t *extents) +{ + cairo_composite_traps_info_t traps_info; + cairo_region_t *clip_region = NULL; + cairo_bool_t clip_surface = FALSE; + cairo_status_t status; + + if (traps->num_traps == 0 && _cairo_operator_bounded_by_mask (op)) + return CAIRO_STATUS_SUCCESS; + + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + if (unlikely (_cairo_status_is_error (status))) + return status; + if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + return CAIRO_STATUS_SUCCESS; + + clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* Use a fast path if the trapezoids consist of a simple region, + * but we can only do this if we do not have a clip surface, or can + * substitute the mask with the clip. + */ + if (! clip_surface || + (_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE)) + { + cairo_region_t *trap_region = NULL; + + if (_cairo_operator_bounded_by_source (op)) { + status = _fill_rectangles (dst, op, src, traps, clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _composite_rectangle (dst, op, src, traps, clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + status = _cairo_traps_extract_region (traps, &trap_region); + if (unlikely (_cairo_status_is_error (status))) + return status; + + if (trap_region != NULL) { + status = cairo_region_intersect_rectangle (trap_region, extents); + if (unlikely (status)) { + cairo_region_destroy (trap_region); + return status; + } + + if (clip_region != NULL) { + status = cairo_region_intersect (trap_region, clip_region); + if (unlikely (status)) { + cairo_region_destroy (trap_region); + return status; + } + } + + if (_cairo_operator_bounded_by_mask (op)) { + cairo_rectangle_int_t trap_extents; + + cairo_region_get_extents (trap_region, &trap_extents); + if (! _cairo_rectangle_intersect (extents, &trap_extents)) { + cairo_region_destroy (trap_region); + return CAIRO_STATUS_SUCCESS; + } + } + + status = _clip_and_composite_region (src, op, dst, + trap_region, + clip_surface ? clip : NULL, + extents); + cairo_region_destroy (trap_region); + + if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED)) + return status; + } + } + + /* No fast path, exclude self-intersections and clip trapezoids. */ + if (traps->has_intersections) { + if (traps->is_rectangular) + status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING); + else if (traps->is_rectilinear) + status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING); + else + status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING); + if (unlikely (status)) + return status; + } + + /* Otherwise render the trapezoids to a mask and composite in the usual + * fashion. + */ + traps_info.traps = traps; + traps_info.antialias = antialias; + + return _clip_and_composite (clip, op, src, + _composite_traps_draw_func, + &traps_info, dst, extents); +} + +typedef struct { + cairo_polygon_t *polygon; + cairo_fill_rule_t fill_rule; + cairo_antialias_t antialias; +} cairo_composite_spans_info_t; + +static cairo_status_t +_composite_spans_draw_func (void *closure, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) +{ + cairo_composite_rectangles_t rects; + cairo_composite_spans_info_t *info = closure; + + rects.source = *extents; + rects.mask = *extents; + rects.bounded = *extents; + /* The incoming dst_x/y are where we're pretending the origin of + * the dst surface is -- *not* the offset of a rectangle where + * we'd like to place the result. */ + rects.bounded.x -= dst_x; + rects.bounded.y -= dst_y; + rects.unbounded = rects.bounded; + rects.is_bounded = _cairo_operator_bounded_by_either (op); + + return _cairo_surface_composite_polygon (dst, op, src, + info->fill_rule, + info->antialias, + &rects, + info->polygon, + clip_region); +} + +static cairo_status_t +_cairo_win32_surface_span_renderer_composite + (void *closure, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_image_surface_t *mask, + cairo_win32_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (src == NULL || mask == NULL) + return CAIRO_STATUS_SUCCESS; + + status = cairo_surface_status (&mask->base); + if (status == CAIRO_STATUS_SUCCESS) { + cairo_pattern_t *mask_pattern = cairo_pattern_create_for_surface (&mask->base); + /* composite onto the image surface directly if we can */ + if (dst->image) { + GdiFlush(); /* XXX: I'm not sure if this needed or not */ + + status = dst->image->backend->composite (op, + src, mask_pattern, dst->image, + extents->x, extents->y, + 0, 0, /* mask.x, mask.y */ + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + clip_region); + } else { + /* otherwise go through the fallback_composite path which + * will do the appropriate surface acquisition */ + status = _cairo_surface_fallback_composite ( + op, + src, mask_pattern, &dst->base, + extents->x, extents->y, + 0, 0, /* mask.x, mask.y */ + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + clip_region); + } + cairo_pattern_destroy (mask_pattern); + + } + return status; +} +#if 0 +static cairo_span_renderer_t * +_cairo_win32_surface_create_span_renderer (cairo_operator_t op, + const cairo_pattern_t *pattern, + void *abstract_dst, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects, + cairo_region_t *clip_region) +{ + cairo_win32_surface_t *dst = abstract_dst; + cairo_win32_surface_span_renderer_t *renderer; + cairo_status_t status; + int width = rects->bounded.width; + int height = rects->bounded.height; + + renderer = calloc(1, sizeof(*renderer)); + if (renderer == NULL) + return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY); + + renderer->base.destroy = _cairo_win32_surface_span_renderer_destroy; + renderer->base.finish = _cairo_win32_surface_span_renderer_finish; + renderer->base.render_rows = _cairo_win32_surface_span_renderer_render_rows; + renderer->op = op; + renderer->pattern = pattern; + renderer->antialias = antialias; + renderer->dst = dst; + renderer->clip_region = clip_region; + + renderer->composite_rectangles = *rects; + + /* TODO: support rendering to A1 surfaces (or: go add span + * compositing to pixman.) */ + renderer->mask = (cairo_image_surface_t *) + cairo_image_surface_create (CAIRO_FORMAT_A8, + width, height); + + status = cairo_surface_status (&renderer->mask->base); + + if (status != CAIRO_STATUS_SUCCESS) { + _cairo_win32_surface_span_renderer_destroy (renderer); + return _cairo_span_renderer_create_in_error (status); + } + + renderer->mask_data = renderer->mask->data - rects->bounded.x - rects->bounded.y * renderer->mask->stride; + renderer->mask_stride = renderer->mask->stride; + return &renderer->base; +} +#endif + +typedef struct _cairo_image_surface_span_renderer { + cairo_span_renderer_t base; + + uint8_t *mask_data; + uint32_t mask_stride; +} cairo_image_surface_span_renderer_t; + +cairo_status_t +_cairo_image_surface_span (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans); + +static cairo_status_t +_composite_spans (void *closure, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) +{ + cairo_composite_spans_info_t *info = closure; + cairo_image_surface_span_renderer_t renderer; + cairo_scan_converter_t *converter; + cairo_image_surface_t *mask; + cairo_status_t status; + + converter = _cairo_tor_scan_converter_create (extents->x, extents->y, + extents->x + extents->width, + extents->y + extents->height, + info->fill_rule); + status = converter->add_polygon (converter, info->polygon); + if (unlikely (status)) + goto CLEANUP_CONVERTER; + + /* TODO: support rendering to A1 surfaces (or: go add span + * compositing to pixman.) */ + + { + mask = cairo_image_surface_create (CAIRO_FORMAT_A8, + extents->width, + extents->height); + + if (cairo_surface_status(&mask->base)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_CONVERTER; + } + } + + renderer.base.render_rows = _cairo_image_surface_span; + renderer.mask_stride = cairo_image_surface_get_stride (mask); + renderer.mask_data = cairo_image_surface_get_data (mask); + renderer.mask_data -= extents->y * renderer.mask_stride + extents->x; + + status = converter->generate (converter, &renderer.base); + if (unlikely (status)) + goto CLEANUP_RENDERER; + + _cairo_win32_surface_span_renderer_composite + (closure, + op, + src, + mask, + (cairo_win32_surface_t*)dst, // ewwww + dst_x, + dst_y, + extents, + clip_region); +#if 0 + { + pixman_image_t *src; + int src_x, src_y; + + src = _pixman_image_for_pattern (pattern, FALSE, extents, &src_x, &src_y); + if (unlikely (src == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_RENDERER; + } + + pixman_image_composite32 (_pixman_operator (op), src, mask, dst, + extents->x + src_x, extents->y + src_y, + 0, 0, /* mask.x, mask.y */ + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + pixman_image_unref (src); + } +#endif + CLEANUP_RENDERER: + cairo_surface_destroy (mask); + CLEANUP_CONVERTER: + converter->destroy (converter); + return status; +} + + + +cairo_status_t +_cairo_win32_surface_fallback_paint (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + cairo_composite_rectangles_t extents; + cairo_rectangle_int_t rect; + cairo_clip_path_t *clip_path = clip ? clip->path : NULL; + cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; + cairo_boxes_t boxes; + int num_boxes = ARRAY_LENGTH (boxes_stack); + cairo_status_t status; + cairo_traps_t traps; + + if (!_cairo_surface_get_extents (surface, &rect)) + ASSERT_NOT_REACHED; + + status = _cairo_composite_rectangles_init_for_paint (&extents, + &rect, + op, source, + clip); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_extents (clip, &extents)) + clip = NULL; + + status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); + if (unlikely (status)) + return status; + + /* If the clip cannot be reduced to a set of boxes, we will need to + * use a clipmask. Paint is special as it is the only operation that + * does not implicitly use a mask, so we may be able to reduce this + * operation to a fill... + */ + if (clip != NULL && clip_path->prev == NULL && + _cairo_operator_bounded_by_mask (op)) + { + return _cairo_surface_fill (surface, op, source, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias, + NULL); + } + + /* meh, surface-fallback is dying anyway... */ + _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes); + status = _cairo_traps_init_boxes (&traps, &boxes); + if (unlikely (status)) + goto CLEANUP_BOXES; + + status = _clip_and_composite_trapezoids (source, op, surface, + &traps, CAIRO_ANTIALIAS_DEFAULT, + clip, + extents.is_bounded ? &extents.bounded : &extents.unbounded); + _cairo_traps_fini (&traps); + +CLEANUP_BOXES: + if (clip_boxes != boxes_stack) + free (clip_boxes); + + return status; +} + +static cairo_status_t +_cairo_surface_mask_draw_func (void *closure, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) +{ + cairo_pattern_t *mask = closure; + cairo_status_t status; + cairo_region_t *extents_region = NULL; + + if (clip_region == NULL && + !_cairo_operator_bounded_by_source (op)) { + extents_region = cairo_region_create_rectangle (extents); + if (unlikely (extents_region->status)) + return extents_region->status; + cairo_region_translate (extents_region, -dst_x, -dst_y); + clip_region = extents_region; + } + + if (src) { + status = _cairo_surface_composite (op, + src, mask, dst, + extents->x, extents->y, + extents->x, extents->y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + clip_region); + } else { + status = _cairo_surface_composite (op, + mask, NULL, dst, + extents->x, extents->y, + 0, 0, /* unused */ + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height, + clip_region); + } + + if (extents_region) + cairo_region_destroy (extents_region); + + return status; +} + +cairo_status_t +_cairo_win32_surface_fallback_mask (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) +{ + cairo_composite_rectangles_t extents; + cairo_rectangle_int_t rect; + cairo_status_t status; + + if (!_cairo_surface_get_extents (surface, &rect)) + ASSERT_NOT_REACHED; + + status = _cairo_composite_rectangles_init_for_mask (&extents, + &rect, + op, source, mask, clip); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_extents (clip, &extents)) + clip = NULL; + + if (clip != NULL && extents.is_bounded) { + status = _cairo_clip_rectangle (clip, &extents.bounded); + if (unlikely (status)) + return status; + } + + return _clip_and_composite (clip, op, source, + _cairo_surface_mask_draw_func, + (void *) mask, + surface, + extents.is_bounded ? &extents.bounded : &extents.unbounded); +} + +cairo_status_t +_cairo_win32_surface_fallback_stroke (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_polygon_t polygon; + cairo_traps_t traps; + cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; + int num_boxes = ARRAY_LENGTH (boxes_stack); + cairo_composite_rectangles_t extents; + cairo_rectangle_int_t rect; + cairo_status_t status; + + if (!_cairo_surface_get_extents (surface, &rect)) + ASSERT_NOT_REACHED; + + status = _cairo_composite_rectangles_init_for_stroke (&extents, + &rect, + op, source, + path, stroke_style, ctm, + clip); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_extents (clip, &extents)) + clip = NULL; + + status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); + if (unlikely (status)) + return status; + + _cairo_polygon_init (&polygon); + _cairo_polygon_limit (&polygon, clip_boxes, num_boxes); + + _cairo_traps_init (&traps); + _cairo_traps_limit (&traps, clip_boxes, num_boxes); + + if (path->is_rectilinear) { + status = _cairo_path_fixed_stroke_rectilinear_to_traps (path, + stroke_style, + ctm, + &traps); + if (likely (status == CAIRO_STATUS_SUCCESS)) + goto DO_TRAPS; + + if (_cairo_status_is_error (status)) + goto CLEANUP; + } + + status = _cairo_path_fixed_stroke_to_polygon (path, + stroke_style, + ctm, ctm_inverse, + tolerance, + &polygon); + if (unlikely (status)) + goto CLEANUP; + + if (polygon.num_edges == 0) + goto DO_TRAPS; + + if (_cairo_operator_bounded_by_mask (op)) { + _cairo_box_round_to_rectangle (&polygon.extents, &extents.mask); + if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask)) + goto CLEANUP; + } + + if (_cairo_surface_check_span_renderer (op, source, surface, antialias)) { + cairo_composite_spans_info_t info; + + info.polygon = &polygon; + info.fill_rule = CAIRO_FILL_RULE_WINDING; + info.antialias = antialias; + + status = _clip_and_composite (clip, op, source, + _composite_spans, + &info, surface, + extents.is_bounded ? &extents.bounded : &extents.unbounded); + goto CLEANUP; + } + + /* Fall back to trapezoid fills. */ + status = _cairo_bentley_ottmann_tessellate_polygon (&traps, + &polygon, + CAIRO_FILL_RULE_WINDING); + if (unlikely (status)) + goto CLEANUP; + + DO_TRAPS: + status = _clip_and_composite_trapezoids (source, op, surface, + &traps, antialias, + clip, + extents.is_bounded ? &extents.bounded : &extents.unbounded); + CLEANUP: + _cairo_traps_fini (&traps); + _cairo_polygon_fini (&polygon); + if (clip_boxes != boxes_stack) + free (clip_boxes); + + return status; +} + +cairo_status_t +_cairo_win32_surface_fallback_fill (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_polygon_t polygon; + cairo_traps_t traps; + cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack; + int num_boxes = ARRAY_LENGTH (boxes_stack); + cairo_bool_t is_rectilinear; + cairo_composite_rectangles_t extents; + cairo_rectangle_int_t rect; + cairo_status_t status; + + if (!_cairo_surface_get_extents (surface, &rect)) + ASSERT_NOT_REACHED; + + status = _cairo_composite_rectangles_init_for_fill (&extents, + &rect, + op, source, path, + clip); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_extents (clip, &extents)) + clip = NULL; + + status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes); + if (unlikely (status)) + return status; + + _cairo_traps_init (&traps); + _cairo_traps_limit (&traps, clip_boxes, num_boxes); + + _cairo_polygon_init (&polygon); + _cairo_polygon_limit (&polygon, clip_boxes, num_boxes); + + if (_cairo_path_fixed_fill_is_empty (path)) + goto DO_TRAPS; + + is_rectilinear = _cairo_path_fixed_is_rectilinear_fill (path); + if (is_rectilinear) { + status = _cairo_path_fixed_fill_rectilinear_to_traps (path, + fill_rule, + &traps); + if (likely (status == CAIRO_STATUS_SUCCESS)) + goto DO_TRAPS; + + if (_cairo_status_is_error (status)) + goto CLEANUP; + } + + status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); + if (unlikely (status)) + goto CLEANUP; + + if (polygon.num_edges == 0) + goto DO_TRAPS; + + if (_cairo_operator_bounded_by_mask (op)) { + _cairo_box_round_to_rectangle (&polygon.extents, &extents.mask); + if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask)) + goto CLEANUP; + } + + if (is_rectilinear) { + status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps, + &polygon, + fill_rule); + if (likely (status == CAIRO_STATUS_SUCCESS)) + goto DO_TRAPS; + + if (unlikely (_cairo_status_is_error (status))) + goto CLEANUP; + } + + + if (_cairo_surface_check_span_renderer (op, source, surface, antialias)) { + cairo_composite_spans_info_t info; + + info.polygon = &polygon; + info.fill_rule = fill_rule; + info.antialias = antialias; + + status = _clip_and_composite (clip, op, source, + _composite_spans, + &info, surface, + extents.is_bounded ? &extents.bounded : &extents.unbounded); + goto CLEANUP; + } + + /* Fall back to trapezoid fills. */ + status = _cairo_bentley_ottmann_tessellate_polygon (&traps, + &polygon, + fill_rule); + if (unlikely (status)) + goto CLEANUP; + + DO_TRAPS: + status = _clip_and_composite_trapezoids (source, op, surface, + &traps, antialias, + clip, + extents.is_bounded ? &extents.bounded : &extents.unbounded); + CLEANUP: + _cairo_traps_fini (&traps); + _cairo_polygon_fini (&polygon); + if (clip_boxes != boxes_stack) + free (clip_boxes); + + return status; +} + +typedef struct { + cairo_scaled_font_t *font; + cairo_glyph_t *glyphs; + int num_glyphs; +} cairo_show_glyphs_info_t; + +static cairo_status_t +_cairo_surface_old_show_glyphs_draw_func (void *closure, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_surface_t *dst, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_region_t *clip_region) +{ + cairo_show_glyphs_info_t *glyph_info = closure; + cairo_status_t status; + cairo_region_t *extents_region = NULL; + + if (clip_region == NULL && + !_cairo_operator_bounded_by_source (op)) { + extents_region = cairo_region_create_rectangle (extents); + if (unlikely (extents_region->status)) + return extents_region->status; + cairo_region_translate (extents_region, -dst_x, -dst_y); + clip_region = extents_region; + } + + /* Modifying the glyph array is fine because we know that this function + * will be called only once, and we've already made a copy of the + * glyphs in the wrapper. + */ + if (dst_x != 0 || dst_y != 0) { + int i; + + for (i = 0; i < glyph_info->num_glyphs; ++i) { + ((cairo_glyph_t *) glyph_info->glyphs)[i].x -= dst_x; + ((cairo_glyph_t *) glyph_info->glyphs)[i].y -= dst_y; + } + } + + status = _cairo_surface_old_show_glyphs (glyph_info->font, op, src, + dst, + extents->x, extents->y, + extents->x - dst_x, + extents->y - dst_y, + extents->width, + extents->height, + glyph_info->glyphs, + glyph_info->num_glyphs, + clip_region); + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + status = _cairo_scaled_font_show_glyphs (glyph_info->font, + op, + src, dst, + extents->x, extents->y, + extents->x - dst_x, + extents->y - dst_y, + extents->width, extents->height, + glyph_info->glyphs, + glyph_info->num_glyphs, + clip_region); + } + + if (extents_region) + cairo_region_destroy (extents_region); + + return status; +} + +cairo_status_t +_cairo_win32_surface_fallback_show_glyphs (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip) +{ + cairo_show_glyphs_info_t glyph_info; + cairo_composite_rectangles_t extents; + cairo_rectangle_int_t rect; + cairo_status_t status; + + if (!_cairo_surface_get_extents (surface, &rect)) + ASSERT_NOT_REACHED; + + status = _cairo_composite_rectangles_init_for_glyphs (&extents, + &rect, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, + NULL); + if (unlikely (status)) + return status; + + if (_cairo_clip_contains_rectangle (clip, &extents.mask)) + clip = NULL; + + if (clip != NULL && extents.is_bounded) { + status = _cairo_clip_rectangle (clip, &extents.bounded); + if (unlikely (status)) + return status; + } + + glyph_info.font = scaled_font; + glyph_info.glyphs = glyphs; + glyph_info.num_glyphs = num_glyphs; + + return _clip_and_composite (clip, op, source, + _cairo_surface_old_show_glyphs_draw_func, + &glyph_info, + surface, + extents.is_bounded ? &extents.bounded : &extents.unbounded); +} + +cairo_surface_t * +_cairo_win32_surface_fallback_snapshot (cairo_surface_t *surface) +{ + cairo_surface_t *snapshot; + cairo_status_t status; + cairo_format_t format; + cairo_surface_pattern_t pattern; + cairo_image_surface_t *image; + void *image_extra; + + status = _cairo_surface_acquire_source_image (surface, + &image, &image_extra); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + format = image->format; + if (format == CAIRO_FORMAT_INVALID) { + /* Non-standard images formats can be generated when retrieving + * images from unusual xservers, for example. + */ + format = _cairo_format_from_content (image->base.content); + } + snapshot = cairo_image_surface_create (format, + image->width, + image->height); + if (cairo_surface_status (snapshot)) { + _cairo_surface_release_source_image (surface, image, image_extra); + return snapshot; + } + + _cairo_pattern_init_for_surface (&pattern, &image->base); + status = _cairo_surface_paint (snapshot, + CAIRO_OPERATOR_SOURCE, + &pattern.base, + NULL); + _cairo_pattern_fini (&pattern.base); + _cairo_surface_release_source_image (surface, image, image_extra); + if (unlikely (status)) { + cairo_surface_destroy (snapshot); + return _cairo_surface_create_in_error (status); + } + + return snapshot; +} + +cairo_status_t +_cairo_win32_surface_fallback_composite (cairo_operator_t op, + const cairo_pattern_t *src, + const cairo_pattern_t *mask, + cairo_surface_t *dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, + cairo_region_t *clip_region) +{ + fallback_state_t state; + cairo_region_t *fallback_region = NULL; + cairo_status_t status; + + status = _fallback_init (&state, dst, dst_x, dst_y, width, height); + if (unlikely (status)) + return status; + + /* We know this will never fail with the image backend; but + * instead of calling into it directly, we call + * _cairo_surface_composite so that we get the correct device + * offset handling. + */ + + if (clip_region != NULL && (state.image_rect.x || state.image_rect.y)) { + fallback_region = cairo_region_copy (clip_region); + status = fallback_region->status; + if (unlikely (status)) + goto FAIL; + + cairo_region_translate (fallback_region, + -state.image_rect.x, + -state.image_rect.y); + clip_region = fallback_region; + } + + status = _cairo_surface_composite (op, src, mask, + &state.image->base, + src_x, src_y, mask_x, mask_y, + dst_x - state.image_rect.x, + dst_y - state.image_rect.y, + width, height, + clip_region); + FAIL: + if (fallback_region != NULL) + cairo_region_destroy (fallback_region); + _fallback_fini (&state); + + return status; +} + +cairo_status_t +_cairo_win32_surface_fallback_fill_rectangles (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_color_t *color, + cairo_rectangle_int_t *rects, + int num_rects) +{ + fallback_state_t state; + cairo_rectangle_int_t *offset_rects = NULL; + cairo_status_t status; + int x1, y1, x2, y2; + int i; + + assert (surface->snapshot_of == NULL); + + if (num_rects <= 0) + return CAIRO_STATUS_SUCCESS; + + /* Compute the bounds of the rectangles, so that we know what area of the + * destination surface to fetch + */ + x1 = rects[0].x; + y1 = rects[0].y; + x2 = rects[0].x + rects[0].width; + y2 = rects[0].y + rects[0].height; + + for (i = 1; i < num_rects; i++) { + if (rects[i].x < x1) + x1 = rects[i].x; + if (rects[i].y < y1) + y1 = rects[i].y; + + if ((int) (rects[i].x + rects[i].width) > x2) + x2 = rects[i].x + rects[i].width; + if ((int) (rects[i].y + rects[i].height) > y2) + y2 = rects[i].y + rects[i].height; + } + + status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1); + if (unlikely (status)) + return status; + + /* If the fetched image isn't at 0,0, we need to offset the rectangles */ + + if (state.image_rect.x != 0 || state.image_rect.y != 0) { + offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t)); + if (unlikely (offset_rects == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto DONE; + } + + for (i = 0; i < num_rects; i++) { + offset_rects[i].x = rects[i].x - state.image_rect.x; + offset_rects[i].y = rects[i].y - state.image_rect.y; + offset_rects[i].width = rects[i].width; + offset_rects[i].height = rects[i].height; + } + + rects = offset_rects; + } + + status = _cairo_surface_fill_rectangles (&state.image->base, + op, color, + rects, num_rects); + + free (offset_rects); + + DONE: + _fallback_fini (&state); + + return status; +} + +cairo_status_t +_cairo_win32_surface_fallback_composite_trapezoids (cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_surface_t *dst, + cairo_antialias_t antialias, + int src_x, + int src_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height, + cairo_trapezoid_t *traps, + int num_traps, + cairo_region_t *clip_region) +{ + fallback_state_t state; + cairo_region_t *fallback_region = NULL; + cairo_trapezoid_t *offset_traps = NULL; + cairo_status_t status; + + status = _fallback_init (&state, dst, dst_x, dst_y, width, height); + if (unlikely (status)) + return status; + + /* If the destination image isn't at 0,0, we need to offset the trapezoids */ + + if (state.image_rect.x != 0 || state.image_rect.y != 0) { + offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t)); + if (offset_traps == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto FAIL; + } + + _cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps, + - state.image_rect.x, - state.image_rect.y, + 1.0, 1.0); + traps = offset_traps; + + /* similarly we need to adjust the region */ + if (clip_region != NULL) { + fallback_region = cairo_region_copy (clip_region); + status = fallback_region->status; + if (unlikely (status)) + goto FAIL; + + cairo_region_translate (fallback_region, + -state.image_rect.x, + -state.image_rect.y); + clip_region = fallback_region; + } + } + + status = _cairo_surface_composite_trapezoids (op, pattern, + &state.image->base, + antialias, + src_x, src_y, + dst_x - state.image_rect.x, + dst_y - state.image_rect.y, + width, height, + traps, num_traps, + clip_region); + FAIL: + if (offset_traps != NULL) + free (offset_traps); + + if (fallback_region != NULL) + cairo_region_destroy (fallback_region); + + _fallback_fini (&state); + + return status; +} + +cairo_status_t +_cairo_win32_surface_fallback_clone_similar (cairo_surface_t *surface, + cairo_surface_t *src, + int src_x, + int src_y, + int width, + int height, + int *clone_offset_x, + int *clone_offset_y, + cairo_surface_t **clone_out) +{ + cairo_surface_t *new_surface; + cairo_surface_pattern_t pattern; + cairo_status_t status; + + new_surface = _cairo_surface_create_similar_scratch (surface, + src->content, + width, height); + if (new_surface == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (unlikely (new_surface->status)) + return new_surface->status; + + /* We have to copy these here, so that the coordinate spaces are correct */ + new_surface->device_transform = src->device_transform; + new_surface->device_transform_inverse = src->device_transform_inverse; + + _cairo_pattern_init_for_surface (&pattern, src); + cairo_matrix_init_translate (&pattern.base.matrix, src_x, src_y); + pattern.base.filter = CAIRO_FILTER_NEAREST; + + status = _cairo_surface_paint (new_surface, + CAIRO_OPERATOR_SOURCE, + &pattern.base, + NULL); + _cairo_pattern_fini (&pattern.base); + + if (unlikely (status)) { + cairo_surface_destroy (new_surface); + return status; + } + + *clone_offset_x = src_x; + *clone_offset_y = src_y; + *clone_out = new_surface; + return CAIRO_STATUS_SUCCESS; +} static const cairo_surface_backend_t cairo_win32_surface_backend = { CAIRO_SURFACE_TYPE_WIN32, _cairo_win32_surface_create_similar, @@ -2211,10 +4184,10 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = { NULL, /* scaled_font_fini */ NULL, /* scaled_glyph_fini */ - NULL, /* paint */ - NULL, /* mask */ - NULL, /* stroke */ - NULL, /* fill */ + _cairo_win32_surface_fallback_paint, + _cairo_win32_surface_fallback_mask, + _cairo_win32_surface_fallback_stroke, + _cairo_win32_surface_fallback_fill, _cairo_win32_surface_show_glyphs, NULL, /* snapshot */ diff --git a/gfx/cairo/cairo/src/cairo-win32.h b/gfx/cairo/cairo/src/cairo-win32.h index c77866bb93f1..b3af05466fc9 100644 --- a/gfx/cairo/cairo/src/cairo-win32.h +++ b/gfx/cairo/cairo/src/cairo-win32.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-xcb-surface.c b/gfx/cairo/cairo/src/cairo-xcb-surface.c index 8cd82f023f63..6cd1c874806a 100644 --- a/gfx/cairo/cairo/src/cairo-xcb-surface.c +++ b/gfx/cairo/cairo/src/cairo-xcb-surface.c @@ -1,6 +1,7 @@ /* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California + * Copyright © 2009 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -12,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -31,307 +32,234 @@ * California. * * Contributor(s): + * Behdad Esfahbod * Carl D. Worth + * Chris Wilson + * Karl Tomlinson , Mozilla Corporation */ #include "cairoint.h" + #include "cairo-xcb.h" -#include "cairo-xcb-xrender.h" -#include "cairo-clip-private.h" -#include "cairo-list-private.h" -#include "cairo-freelist-private.h" -#include +#include "cairo-xcb-private.h" -#define AllPlanes ((unsigned long)~0L) +#if CAIRO_HAS_XCB_DRM_FUNCTIONS +#include +#endif +#define AllPlanes ((unsigned) -1) +#define CAIRO_ASSUME_PIXMAP 20 +#define XLIB_COORD_MAX 32767 + +#if CAIRO_HAS_XLIB_XCB_FUNCTIONS +slim_hidden_proto (cairo_xcb_surface_create); +slim_hidden_proto (cairo_xcb_surface_create_for_bitmap); slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format); +#endif -/* - * Instead of taking two round trips for each blending request, - * assume that if a particular drawable fails GetImage that it will - * fail for a "while"; use temporary pixmaps to avoid the errors +#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS +#include "drm/cairo-drm-private.h" +#endif + +/** + * SECTION:cairo-xcb + * @Title: XCB Surfaces + * @Short_Description: X Window System rendering using the XCB library + * @See_Also: #cairo_surface_t + * + * The XCB surface is used to render cairo graphics to X Window System + * windows and pixmaps using the XCB library. + * + * Note that the XCB surface automatically takes advantage of the X render + * extension if it is available. */ -#define CAIRO_ASSUME_PIXMAP 20 - -typedef struct cairo_xcb_surface { - cairo_surface_t base; - - xcb_connection_t *dpy; - xcb_screen_t *screen; - - xcb_gcontext_t gc; - xcb_drawable_t drawable; - cairo_bool_t owns_pixmap; - xcb_visualtype_t *visual; - - int use_pixmap; - - int render_major; - int render_minor; - - int width; - int height; - int depth; - - cairo_bool_t have_clip_rects; - xcb_rectangle_t *clip_rects; - int num_clip_rects; - cairo_region_t *clip_region; - - xcb_render_picture_t src_picture, dst_picture; - xcb_render_pictforminfo_t xrender_format; - - cairo_list_t to_be_checked; - cairo_freepool_t cookie_pool; -} cairo_xcb_surface_t; - -typedef struct _cairo_xcb_cookie { - cairo_list_t link; - xcb_void_cookie_t xcb; -} cairo_xcb_cookie_t; - -#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \ - (((surface)->render_major > major) || \ - (((surface)->render_major == major) && ((surface)->render_minor >= minor))) - -#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) -#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) -#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0) - -#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1) -#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1) - -#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2) -#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2) - -#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) -#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) -#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) -#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4) - -#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) -#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) -#define CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10) -#define CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10) - +#if CAIRO_HAS_XCB_SHM_FUNCTIONS static cairo_status_t -_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface); - -static int -_CAIRO_FORMAT_DEPTH (cairo_format_t format) +_cairo_xcb_surface_create_similar_shm (cairo_xcb_surface_t *other, + pixman_format_code_t pixman_format, + int width, int height, + cairo_surface_t **out) { - switch (format) { - case CAIRO_FORMAT_A1: - return 1; - case CAIRO_FORMAT_A8: - return 8; - case CAIRO_FORMAT_RGB24: - return 24; - case CAIRO_FORMAT_ARGB32: + size_t size, stride; + cairo_xcb_shm_info_t *shm_info; + cairo_status_t status; + cairo_surface_t *image; + + stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format)); + size = stride * height; + if (size < CAIRO_XCB_SHM_SMALL_IMAGE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_xcb_connection_allocate_shm_info (other->connection, + size, &shm_info); + if (unlikely (status)) + return status; + + image = _cairo_image_surface_create_with_pixman_format (shm_info->mem, + pixman_format, + width, height, + stride); + status = image->status; + if (unlikely (status)) { + _cairo_xcb_shm_info_destroy (shm_info); + return status; + } + + status = _cairo_user_data_array_set_data (&image->user_data, + (const cairo_user_data_key_t *) other->connection, + shm_info, + (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy); + if (unlikely (status)) { + cairo_surface_destroy (image); + _cairo_xcb_shm_info_destroy (shm_info); + return status; + } + + *out = image; + return CAIRO_STATUS_SUCCESS; +} +#endif + +cairo_surface_t * +_cairo_xcb_surface_create_similar_image (cairo_xcb_surface_t *other, + cairo_content_t content, + int width, int height) +{ + cairo_surface_t *image = NULL; + pixman_format_code_t pixman_format; + + /* XXX choose pixman_format from connection->image_formats */ + switch (content) { + case CAIRO_CONTENT_ALPHA: + pixman_format = PIXMAN_a8; + break; + case CAIRO_CONTENT_COLOR: + pixman_format = PIXMAN_x8r8g8b8; + break; default: - return 32; - } -} - -static cairo_status_t -_cairo_xcb_add_cookie_to_be_checked (cairo_xcb_surface_t *surface, - xcb_void_cookie_t xcb) -{ - cairo_xcb_cookie_t *cookie; - - cookie = _cairo_freepool_alloc (&surface->cookie_pool); - if (unlikely (cookie == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - cookie->xcb = xcb; - cairo_list_add_tail (&cookie->link, &surface->to_be_checked); - - return CAIRO_STATUS_SUCCESS; -} - -static xcb_render_pictforminfo_t * -_CAIRO_FORMAT_TO_XRENDER_FORMAT(xcb_connection_t *dpy, cairo_format_t format) -{ - xcb_pict_standard_t std_format; - switch (format) { - case CAIRO_FORMAT_A1: - std_format = XCB_PICT_STANDARD_A_1; break; - case CAIRO_FORMAT_A8: - std_format = XCB_PICT_STANDARD_A_8; break; - case CAIRO_FORMAT_RGB24: - std_format = XCB_PICT_STANDARD_RGB_24; break; - case CAIRO_FORMAT_ARGB32: - default: - std_format = XCB_PICT_STANDARD_ARGB_32; break; - } - return xcb_render_util_find_standard_format (xcb_render_util_query_formats (dpy), std_format); -} - -static cairo_content_t -_xcb_render_format_to_content (xcb_render_pictforminfo_t *xrender_format) -{ - cairo_bool_t xrender_format_has_alpha; - cairo_bool_t xrender_format_has_color; - - /* This only happens when using a non-Render server. Let's punt - * and say there's no alpha here. */ - if (xrender_format == NULL) - return CAIRO_CONTENT_COLOR; - - xrender_format_has_alpha = (xrender_format->direct.alpha_mask != 0); - xrender_format_has_color = (xrender_format->direct.red_mask != 0 || - xrender_format->direct.green_mask != 0 || - xrender_format->direct.blue_mask != 0); - - if (xrender_format_has_alpha) - if (xrender_format_has_color) - return CAIRO_CONTENT_COLOR_ALPHA; - else - return CAIRO_CONTENT_ALPHA; - else - return CAIRO_CONTENT_COLOR; -} - -static cairo_status_t -_cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface) -{ - if (surface->have_clip_rects) { - xcb_void_cookie_t cookie; - - cookie = xcb_set_clip_rectangles_checked (surface->dpy, - XCB_CLIP_ORDERING_YX_SORTED, surface->gc, - 0, 0, - surface->num_clip_rects, - surface->clip_rects); - - return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); + ASSERT_NOT_REACHED; + case CAIRO_CONTENT_COLOR_ALPHA: + pixman_format = PIXMAN_a8r8g8b8; + break; } - return CAIRO_STATUS_SUCCESS; -} +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + if (other->flags & CAIRO_XCB_HAS_SHM) { + cairo_status_t status; -static cairo_status_t -_cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface) -{ - if (surface->have_clip_rects) { - xcb_void_cookie_t cookie; + status = _cairo_xcb_surface_create_similar_shm (other, + pixman_format, + width, height, + &image); + if (_cairo_status_is_error (status)) + return _cairo_surface_create_in_error (status); + } +#endif - cookie = xcb_render_set_picture_clip_rectangles_checked (surface->dpy, - surface->dst_picture, - 0, 0, - surface->num_clip_rects, - surface->clip_rects); - - return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); + if (image == NULL) { + image = _cairo_image_surface_create_with_pixman_format (NULL, + pixman_format, + width, height, + 0); } - return CAIRO_STATUS_SUCCESS; + return image; } -static cairo_status_t -_cairo_xcb_surface_set_clip_region (void *abstract_surface, - cairo_region_t *region) +cairo_surface_t * +_cairo_xcb_surface_create_similar (void *abstract_other, + cairo_content_t content, + int width, + int height) { - cairo_xcb_surface_t *surface = abstract_surface; - - if (region == surface->clip_region) - return CAIRO_STATUS_SUCCESS; - - cairo_region_destroy (surface->clip_region); - region = cairo_region_reference (region); - - if (surface->clip_rects) { - free (surface->clip_rects); - surface->clip_rects = NULL; - } - - surface->have_clip_rects = FALSE; - surface->num_clip_rects = 0; - - if (region == NULL) { - uint32_t none[] = { XCB_NONE }; - if (surface->gc) - xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none); - - if (surface->xrender_format.id != XCB_NONE && surface->dst_picture) - xcb_render_change_picture (surface->dpy, surface->dst_picture, - XCB_RENDER_CP_CLIP_MASK, none); - } else { - xcb_rectangle_t *rects = NULL; - int n_rects, i; - - n_rects = cairo_region_num_rectangles (region); - - if (n_rects > 0) { - rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t)); - if (rects == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } else { - rects = NULL; - } - - for (i = 0; i < n_rects; i++) { - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (region, i, &rect); - - rects[i].x = rect.x; - rects[i].y = rect.y; - rects[i].width = rect.width; - rects[i].height = rect.height; - } - - surface->have_clip_rects = TRUE; - surface->clip_rects = rects; - surface->num_clip_rects = n_rects; - - if (surface->gc) - _cairo_xcb_surface_set_gc_clip_rects (surface); - - if (surface->dst_picture) - _cairo_xcb_surface_set_picture_clip_rects (surface); - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_surface_t * -_cairo_xcb_surface_create_similar (void *abstract_src, - cairo_content_t content, - int width, - int height) -{ - cairo_xcb_surface_t *src = abstract_src; - xcb_connection_t *dpy = src->dpy; - xcb_pixmap_t pixmap; + cairo_xcb_surface_t *other = abstract_other; cairo_xcb_surface_t *surface; - cairo_format_t format = _cairo_format_from_content (content); - xcb_render_pictforminfo_t *xrender_format; + cairo_xcb_connection_t *connection; + xcb_pixmap_t pixmap; + cairo_status_t status; - /* As a good first approximation, if the display doesn't have COMPOSITE, - * we're better off using image surfaces for all temporary operations - */ - if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) { - return cairo_image_surface_create (format, width, height); + if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) + return NULL; + + if (width <= 0 || height <= 0) + return NULL; + +#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS + if (other->drm != NULL) { + cairo_surface_t *drm; + + drm = _cairo_drm_surface_create_similar (other->drm, content, width, height); + if (drm != NULL) + return drm; + } +#endif + + if ((other->flags & CAIRO_XCB_HAS_RENDER) == 0) + return _cairo_xcb_surface_create_similar_image (other, content, width, height); + + connection = other->connection; + status = _cairo_xcb_connection_acquire (connection); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + status =_cairo_xcb_connection_take_socket (connection); + if (unlikely (status)) { + _cairo_xcb_connection_release (connection); + return _cairo_surface_create_in_error (status); } - pixmap = xcb_generate_id (dpy); - xcb_create_pixmap (dpy, _CAIRO_FORMAT_DEPTH (format), - pixmap, src->drawable, - width <= 0 ? 1 : width, - height <= 0 ? 1 : height); - - xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, format); - /* XXX: what to do if xrender_format is null? */ - surface = (cairo_xcb_surface_t *) - cairo_xcb_surface_create_with_xrender_format (dpy, pixmap, src->screen, - xrender_format, + if (content == other->base.content) { + pixmap = _cairo_xcb_connection_create_pixmap (connection, + other->depth, + other->drawable, width, height); - if (surface->base.status) - return &surface->base; - surface->owns_pixmap = TRUE; + surface = (cairo_xcb_surface_t *) + _cairo_xcb_surface_create_internal (other->screen, + pixmap, TRUE, + other->pixman_format, + other->xrender_format, + width, height); + } else { + cairo_format_t format; + pixman_format_code_t pixman_format; + + /* XXX find a compatible xrender format */ + switch (content) { + case CAIRO_CONTENT_ALPHA: + pixman_format = PIXMAN_a8; + format = CAIRO_FORMAT_A8; + break; + case CAIRO_CONTENT_COLOR: + pixman_format = PIXMAN_x8r8g8b8; + format = CAIRO_FORMAT_RGB24; + break; + default: + ASSERT_NOT_REACHED; + case CAIRO_CONTENT_COLOR_ALPHA: + pixman_format = PIXMAN_a8r8g8b8; + format = CAIRO_FORMAT_ARGB32; + break; + } + + pixmap = _cairo_xcb_connection_create_pixmap (connection, + PIXMAN_FORMAT_DEPTH (pixman_format), + other->drawable, + width, height); + + surface = (cairo_xcb_surface_t *) + _cairo_xcb_surface_create_internal (other->screen, + pixmap, TRUE, + pixman_format, + connection->standard_formats[format], + width, height); + } + + if (unlikely (surface->base.status)) + _cairo_xcb_connection_free_pixmap (connection, pixmap); + + _cairo_xcb_connection_release (connection); return &surface->base; } @@ -340,153 +268,191 @@ static cairo_status_t _cairo_xcb_surface_finish (void *abstract_surface) { cairo_xcb_surface_t *surface = abstract_surface; + cairo_status_t status; - if (surface->dst_picture != XCB_NONE) - xcb_render_free_picture (surface->dpy, surface->dst_picture); + if (surface->fallback != NULL) { + cairo_surface_finish (surface->fallback); + cairo_surface_destroy (surface->fallback); + } - if (surface->src_picture != XCB_NONE) - xcb_render_free_picture (surface->dpy, surface->src_picture); + cairo_list_del (&surface->link); - if (surface->owns_pixmap) - xcb_free_pixmap (surface->dpy, surface->drawable); +#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS + if (surface->drm != NULL) { + cairo_surface_finish (surface->drm); + cairo_surface_destroy (surface->drm); - if (surface->gc != XCB_NONE) - xcb_free_gc (surface->dpy, surface->gc); + xcb_dri2_destroy_drawable (surface->connection->xcb_connection, + surface->drawable); + } +#endif - free (surface->clip_rects); - cairo_region_destroy (surface->clip_region); + status = _cairo_xcb_connection_acquire (surface->connection); + if (status == CAIRO_STATUS_SUCCESS) { + if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) { + if (surface->picture != XCB_NONE) { + _cairo_xcb_connection_render_free_picture (surface->connection, + surface->picture); + } - _cairo_freepool_fini (&surface->cookie_pool); + if (surface->owns_pixmap) + _cairo_xcb_connection_free_pixmap (surface->connection, surface->drawable); + } + _cairo_xcb_connection_release (surface->connection); + } - surface->dpy = NULL; + _cairo_xcb_connection_destroy (surface->connection); + return status; +} + +static void +_destroy_image (pixman_image_t *image, void *data) +{ + free (data); +} + +#if CAIRO_HAS_XCB_SHM_FUNCTIONS +static cairo_int_status_t +_cairo_xcb_surface_create_shm_image (cairo_xcb_surface_t *target, + cairo_image_surface_t **image_out, + cairo_xcb_shm_info_t **shm_info_out) +{ + cairo_image_surface_t *image; + cairo_xcb_shm_info_t *shm_info; + cairo_status_t status; + size_t size, stride; + + if ((target->flags & CAIRO_XCB_HAS_SHM) == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + stride = CAIRO_STRIDE_FOR_WIDTH_BPP (target->width, + PIXMAN_FORMAT_BPP (target->pixman_format)); + size = stride * target->height; + if (size < CAIRO_XCB_SHM_SMALL_IMAGE) { + target->flags &= ~CAIRO_XCB_HAS_SHM; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = _cairo_xcb_connection_allocate_shm_info (target->screen->connection, + size, &shm_info); + if (unlikely (status)) + return status; + + image = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format (shm_info->mem, + target->pixman_format, + target->width, + target->height, + stride); + status = image->base.status; + if (unlikely (status)) { + _cairo_xcb_shm_info_destroy (shm_info); + return status; + } + + status = _cairo_user_data_array_set_data (&image->base.user_data, + (const cairo_user_data_key_t *) target->connection, + shm_info, + (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy); + if (unlikely (status)) { + cairo_surface_destroy (&image->base); + _cairo_xcb_shm_info_destroy (shm_info); + return status; + } + + *image_out = image; + *shm_info_out = shm_info; return CAIRO_STATUS_SUCCESS; } +#endif -static int -_bits_per_pixel(xcb_connection_t *c, int depth) +static cairo_status_t +_get_shm_image (cairo_xcb_surface_t *surface, + cairo_image_surface_t **image_out) { - xcb_format_t *fmt = xcb_setup_pixmap_formats(xcb_get_setup(c)); - xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(xcb_get_setup(c)); +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + cairo_image_surface_t *image; + cairo_xcb_shm_info_t *shm_info; + cairo_status_t status; - for(; fmt != fmtend; ++fmt) - if(fmt->depth == depth) - return fmt->bits_per_pixel; + status = _cairo_xcb_surface_create_shm_image (surface, &image, &shm_info); + if (unlikely (status)) + return status; - if(depth <= 4) - return 4; - if(depth <= 8) - return 8; - if(depth <= 16) - return 16; - return 32; -} - -static int -_bytes_per_line(xcb_connection_t *c, int width, int bpp) -{ - int bitmap_pad = xcb_get_setup(c)->bitmap_format_scanline_pad; - return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3; -} - -static cairo_bool_t -_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format) -{ - switch (masks->bpp) { - case 32: - if (masks->alpha_mask == 0xff000000 && - masks->red_mask == 0x00ff0000 && - masks->green_mask == 0x0000ff00 && - masks->blue_mask == 0x000000ff) - { - *format = CAIRO_FORMAT_ARGB32; - return TRUE; - } - if (masks->alpha_mask == 0x00000000 && - masks->red_mask == 0x00ff0000 && - masks->green_mask == 0x0000ff00 && - masks->blue_mask == 0x000000ff) - { - *format = CAIRO_FORMAT_RGB24; - return TRUE; - } - break; - case 8: - if (masks->alpha_mask == 0xff) - { - *format = CAIRO_FORMAT_A8; - return TRUE; - } - break; - case 1: - if (masks->alpha_mask == 0x1) - { - *format = CAIRO_FORMAT_A1; - return TRUE; - } - break; + if (! surface->base.is_clear) { + status = _cairo_xcb_connection_shm_get_image (surface->connection, + surface->drawable, + 0, 0, + surface->width, + surface->height, + shm_info->shm, + shm_info->offset); + if (unlikely (status)) + return status; + } else { + memset (image->data, 0, image->stride * image->height); } - return FALSE; + + *image_out = image; + return CAIRO_STATUS_SUCCESS; +#else + return CAIRO_INT_STATUS_UNSUPPORTED; +#endif } static cairo_status_t -_get_image_surface (cairo_xcb_surface_t *surface, - cairo_rectangle_int_t *interest_rect, - cairo_image_surface_t **image_out, - cairo_rectangle_int_t *image_rect) +_get_image (cairo_xcb_surface_t *surface, + cairo_bool_t use_shm, + cairo_image_surface_t **image_out) { cairo_image_surface_t *image; - xcb_get_image_reply_t *imagerep; - int bpp, bytes_per_line; - cairo_rectangle_int_t extents; - unsigned char *data; - cairo_format_masks_t masks; - cairo_format_t format; + cairo_xcb_connection_t *connection; + xcb_get_image_reply_t *reply; + cairo_status_t status; - extents.x = 0; - extents.y = 0; - extents.width = surface->width; - extents.height = surface->height; - - if (interest_rect) { - if (! _cairo_rectangle_intersect (&extents, interest_rect)) { - *image_out = NULL; - return CAIRO_STATUS_SUCCESS; - } + if (surface->base.is_clear || surface->deferred_clear) { + image = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format (NULL, + surface->pixman_format, + surface->width, + surface->height, + 0); + *image_out = image; + return image->base.status; } - if (image_rect) - *image_rect = extents; + connection = surface->connection; - /* XXX: This should try to use the XShm extension if available */ + status = _cairo_xcb_connection_acquire (connection); + if (unlikely (status)) + return status; - if (surface->use_pixmap == 0) - { - xcb_generic_error_t *error; + status = _cairo_xcb_connection_take_socket (connection); + if (unlikely (status)) + goto FAIL; - imagerep = xcb_get_image_reply (surface->dpy, - xcb_get_image (surface->dpy, - XCB_IMAGE_FORMAT_Z_PIXMAP, - surface->drawable, - extents.x, extents.y, - extents.width, extents.height, - AllPlanes), - &error); - - /* If we get an error, the surface must have been a window, - * so retry with the safe code path. - */ - if (error) - surface->use_pixmap = CAIRO_ASSUME_PIXMAP; + if (use_shm) { + status = _get_shm_image (surface, image_out); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto FAIL; } - else - { + + if (surface->use_pixmap == 0) { + status = _cairo_xcb_connection_get_image (connection, + surface->drawable, + 0, 0, + surface->width, + surface->height, + &reply); + if (unlikely (status)) + goto FAIL; + } else { surface->use_pixmap--; - imagerep = NULL; + reply = NULL; } - if (!imagerep) - { + if (reply == NULL && ! surface->owns_pixmap) { /* xcb_get_image_t from a window is dangerous because it can * produce errors if the window is unmapped or partially * outside the screen. We could check for errors and @@ -494,1676 +460,786 @@ _get_image_surface (cairo_xcb_surface_t *surface, * temporary pixmap */ xcb_pixmap_t pixmap; - cairo_xcb_cookie_t *cookies[2]; - cairo_status_t status; + xcb_gcontext_t gc; + + gc = _cairo_xcb_screen_get_gc (surface->screen, + surface->drawable, + surface->depth); + pixmap = _cairo_xcb_connection_create_pixmap (connection, + surface->depth, + surface->drawable, + surface->width, + surface->height); + + /* XXX IncludeInferiors? */ + _cairo_xcb_connection_copy_area (connection, + surface->drawable, + pixmap, gc, + 0, 0, + 0, 0, + surface->width, + surface->height); + + _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); + + status = _cairo_xcb_connection_get_image (connection, + pixmap, + 0, 0, + surface->width, + surface->height, + &reply); + _cairo_xcb_connection_free_pixmap (connection, pixmap); - status = _cairo_xcb_surface_ensure_gc (surface); if (unlikely (status)) - return status; - - status = _cairo_freepool_alloc_array (&surface->cookie_pool, - ARRAY_LENGTH (cookies), - (void **) cookies); - if (unlikely (status)) - return status; - - pixmap = xcb_generate_id (surface->dpy); - cookies[0]->xcb = xcb_create_pixmap_checked (surface->dpy, - surface->depth, - pixmap, - surface->drawable, - extents.width, extents.height); - cairo_list_add_tail (&cookies[0]->link, &surface->to_be_checked); - - cookies[1]->xcb = xcb_copy_area_checked (surface->dpy, - surface->drawable, - pixmap, surface->gc, - extents.x, extents.y, - 0, 0, - extents.width, extents.height); - cairo_list_add_tail (&cookies[1]->link, &surface->to_be_checked); - - imagerep = xcb_get_image_reply (surface->dpy, - xcb_get_image (surface->dpy, - XCB_IMAGE_FORMAT_Z_PIXMAP, - pixmap, - extents.x, extents.y, - extents.width, extents.height, - AllPlanes), - 0); - - xcb_free_pixmap (surface->dpy, pixmap); - - } - if (unlikely (imagerep == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - bpp = _bits_per_pixel(surface->dpy, imagerep->depth); - bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp); - - data = _cairo_malloc_ab (surface->height, bytes_per_line); - if (data == NULL) { - free (imagerep); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - - memcpy (data, xcb_get_image_data (imagerep), bytes_per_line * surface->height); - free (imagerep); - - /* - * Compute the pixel format masks from either an xcb_visualtype_t or - * a xcb_render_pctforminfo_t, failing we assume the drawable is an - * alpha-only pixmap as it could only have been created that way - * through the cairo_xlib_surface_create_for_bitmap function. - */ - if (surface->visual) { - masks.bpp = bpp; - masks.alpha_mask = 0; - masks.red_mask = surface->visual->red_mask; - masks.green_mask = surface->visual->green_mask; - masks.blue_mask = surface->visual->blue_mask; - } else if (surface->xrender_format.id != XCB_NONE) { - masks.bpp = bpp; - masks.red_mask = (unsigned long)surface->xrender_format.direct.red_mask << surface->xrender_format.direct.red_shift; - masks.green_mask = (unsigned long)surface->xrender_format.direct.green_mask << surface->xrender_format.direct.green_shift; - masks.blue_mask = (unsigned long)surface->xrender_format.direct.blue_mask << surface->xrender_format.direct.blue_shift; - masks.alpha_mask = (unsigned long)surface->xrender_format.direct.alpha_mask << surface->xrender_format.direct.alpha_shift; - } else { - masks.bpp = bpp; - masks.red_mask = 0; - masks.green_mask = 0; - masks.blue_mask = 0; - if (surface->depth < 32) - masks.alpha_mask = (1 << surface->depth) - 1; - else - masks.alpha_mask = 0xffffffff; - } - - /* - * Prefer to use a standard pixman format instead of the - * general masks case. - */ - if (_CAIRO_MASK_FORMAT (&masks, &format)) { - image = (cairo_image_surface_t *) - cairo_image_surface_create_for_data (data, - format, - extents.width, - extents.height, - bytes_per_line); - if (image->base.status) - goto FAIL; - } else { - /* - * XXX This can't work. We must convert the data to one of the - * supported pixman formats. Pixman needs another function - * which takes data in an arbitrary format and converts it - * to something supported by that library. - */ - image = (cairo_image_surface_t *) - _cairo_image_surface_create_with_masks (data, - &masks, - extents.width, - extents.height, - bytes_per_line); - if (image->base.status) goto FAIL; } - /* Let the surface take ownership of the data */ - _cairo_image_surface_assume_ownership_of_data (image); + if (unlikely (reply == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto FAIL; + } + + /* XXX byte swap */ + /* XXX format conversion */ + assert (reply->depth == surface->depth); + + image = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format + (xcb_get_image_data (reply), + surface->pixman_format, + surface->width, + surface->height, + CAIRO_STRIDE_FOR_WIDTH_BPP (surface->width, + PIXMAN_FORMAT_BPP (surface->pixman_format))); + status = image->base.status; + if (unlikely (status)) { + free (reply); + goto FAIL; + } + + assert (xcb_get_image_data_length (reply) == image->height * image->stride); + + pixman_image_set_destroy_function (image->pixman_image, _destroy_image, reply); + + _cairo_xcb_connection_release (connection); + + /* synchronisation point */ + surface->marked_dirty = FALSE; *image_out = image; return CAIRO_STATUS_SUCCESS; - FAIL: - free (data); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); +FAIL: + _cairo_xcb_connection_release (connection); + return status; } static cairo_status_t -_cairo_xcb_surface_ensure_src_picture (cairo_xcb_surface_t *surface) -{ - if (!surface->src_picture) { - xcb_void_cookie_t cookie; - - surface->src_picture = xcb_generate_id (surface->dpy); - cookie = xcb_render_create_picture_checked (surface->dpy, - surface->src_picture, - surface->drawable, - surface->xrender_format.id, - 0, NULL); - - return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_xcb_surface_ensure_dst_picture (cairo_xcb_surface_t *surface) -{ - if (!surface->dst_picture) { - xcb_void_cookie_t cookie; - - surface->dst_picture = xcb_generate_id (surface->dpy); - cookie = xcb_render_create_picture_checked (surface->dpy, - surface->dst_picture, - surface->drawable, - surface->xrender_format.id, - 0, NULL); - - return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); - } - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t -_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface) -{ - xcb_void_cookie_t cookie; - - if (surface->gc) - return CAIRO_STATUS_SUCCESS; - - surface->gc = xcb_generate_id(surface->dpy); - cookie = xcb_create_gc_checked (surface->dpy, surface->gc, surface->drawable, 0, 0); - _cairo_xcb_surface_set_gc_clip_rects (surface); - - return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); -} - -static cairo_status_t -_draw_image_surface (cairo_xcb_surface_t *surface, - cairo_image_surface_t *image, - int src_x, - int src_y, - int width, - int height, - int dst_x, - int dst_y) -{ - int bpp, bpl; - uint32_t data_len; - uint8_t *data, left_pad=0; - xcb_void_cookie_t cookie; - - /* equivalent of XPutImage(..., src_x,src_y, dst_x,dst_y, width,height); */ - /* XXX: assumes image and surface formats and depths are the same */ - /* XXX: assumes depth is a multiple of 8 (not bitmap) */ - - /* fit src_{x,y,width,height} within image->{0,0,width,height} */ - if (src_x < 0) { - width += src_x; - src_x = 0; - } - if (src_y < 0) { - height += src_y; - src_y = 0; - } - if (width + src_x > image->width) - width = image->width - src_x; - if (height + src_y > image->height) - height = image->height - src_y; - if (width <= 0 || height <= 0) - return CAIRO_STATUS_SUCCESS; - - bpp = _bits_per_pixel(surface->dpy, image->depth); - /* XXX: could use bpl = image->stride? */ - bpl = _bytes_per_line(surface->dpy, image->width, bpp); - - if (src_x == 0 && width == image->width) { - /* can work in-place */ - data_len = height * bpl; - data = image->data + src_y * bpl; - } else { - /* must copy {src_x,src_y,width,height} into new data */ - int line = 0; - uint8_t *data_line, *image_line; - int data_bpl = _bytes_per_line(surface->dpy, width, bpp); - data_len = height * data_bpl; - data_line = data = malloc(data_len); - if (data == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - image_line = image->data + src_y * bpl + (src_x * bpp / 8); - while (line++ < height) { - memcpy(data_line, image_line, data_bpl); - data_line += data_bpl; - image_line += bpl; - } - } - _cairo_xcb_surface_ensure_gc (surface); - cookie = xcb_put_image_checked (surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP, - surface->drawable, surface->gc, - width, height, - dst_x, dst_y, - left_pad, image->depth, - data_len, data); - - if (data < image->data || data >= image->data + image->height * bpl) - free (data); - - return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); -} - -static cairo_status_t -_cairo_xcb_surface_acquire_source_image (void *abstract_surface, - cairo_image_surface_t **image_out, - void **image_extra) +_cairo_xcb_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) { cairo_xcb_surface_t *surface = abstract_surface; cairo_image_surface_t *image; cairo_status_t status; - status = _get_image_surface (surface, NULL, &image, NULL); - if (status) + if (surface->drm != NULL && ! surface->marked_dirty) { + return _cairo_surface_acquire_source_image (surface->drm, + image_out, image_extra); + } + + if (surface->fallback != NULL) { + image = (cairo_image_surface_t *) cairo_surface_reference (surface->fallback); + goto DONE; + } + + image = (cairo_image_surface_t *) + _cairo_surface_has_snapshot (&surface->base, + &_cairo_image_surface_backend); + if (image != NULL) { + image = (cairo_image_surface_t *) cairo_surface_reference (&image->base); + goto DONE; + } + + status = _get_image (surface, FALSE, &image); + if (unlikely (status)) return status; + _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL); + +DONE: *image_out = image; *image_extra = NULL; + return CAIRO_STATUS_SUCCESS; +} +static void +_cairo_xcb_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_xcb_surface_t *surface = abstract_surface; + + if (surface->drm != NULL && ! surface->marked_dirty) { + return _cairo_surface_release_source_image (surface->drm, + image, image_extra); + } + + cairo_surface_destroy (&image->base); +} + +static cairo_bool_t +_cairo_xcb_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_xcb_surface_t *surface = abstract_surface; + + extents->x = extents->y = 0; + extents->width = surface->width; + extents->height = surface->height; + return TRUE; +} + +static void +_cairo_xcb_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + /* XXX copy from xlib */ + _cairo_font_options_init_default (options); + _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON); +} + +static cairo_status_t +_put_shm_image (cairo_xcb_surface_t *surface, + xcb_gcontext_t gc, + cairo_image_surface_t *image) +{ +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + cairo_xcb_shm_info_t *shm_info; + + shm_info = _cairo_user_data_array_get_data (&image->base.user_data, + (const cairo_user_data_key_t *) surface->connection); + if (shm_info == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + shm_info->seqno = + _cairo_xcb_connection_shm_put_image (surface->connection, + surface->drawable, + gc, + surface->width, surface->height, + 0, 0, + image->width, image->height, + 0, 0, + image->depth, + shm_info->shm, + shm_info->offset); + + return CAIRO_STATUS_SUCCESS; +#else + return CAIRO_INT_STATUS_UNSUPPORTED; +#endif +} + +static cairo_status_t +_put_image (cairo_xcb_surface_t *surface, + cairo_image_surface_t *image) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + /* XXX track damaged region? */ + + status = _cairo_xcb_connection_acquire (surface->connection); + if (unlikely (status)) + return status; + + status = _cairo_xcb_connection_take_socket (surface->connection); + if (unlikely (status)) { + _cairo_xcb_connection_release (surface->connection); + return status; + } + + if (image->pixman_format == surface->pixman_format) { + xcb_gcontext_t gc; + + assert (image->width == surface->width); + assert (image->height == surface->height); + assert (image->depth == surface->depth); + assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format))); + + gc = _cairo_xcb_screen_get_gc (surface->screen, + surface->drawable, + surface->depth); + + status = _put_shm_image (surface, gc, image); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + _cairo_xcb_connection_put_image (surface->connection, + surface->drawable, gc, + image->width, image->height, + 0, 0, + image->depth, + image->stride, + image->data); + status = CAIRO_STATUS_SUCCESS; + } + + _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); + } else { + ASSERT_NOT_REACHED; + } + + _cairo_xcb_connection_release (surface->connection); + return status; +} + +static cairo_status_t +_cairo_xcb_surface_flush (void *abstract_surface) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_status_t status; + + if (surface->drm != NULL && ! surface->marked_dirty) + return surface->drm->backend->flush (surface->drm); + + if (likely (surface->fallback == NULL)) { + status = CAIRO_STATUS_SUCCESS; + if (! surface->base.finished && surface->deferred_clear) + status = _cairo_xcb_surface_clear (surface); + + return status; + } + + status = surface->base.status; + if (status == CAIRO_STATUS_SUCCESS && ! surface->base.finished) { + status = cairo_surface_status (surface->fallback); + + if (status == CAIRO_STATUS_SUCCESS) { + status = _put_image (surface, + (cairo_image_surface_t *) surface->fallback); + } + + if (status == CAIRO_STATUS_SUCCESS) { + _cairo_surface_attach_snapshot (&surface->base, + surface->fallback, + cairo_surface_finish); + } + } + + cairo_surface_destroy (surface->fallback); + surface->fallback = NULL; + + return status; +} + +static cairo_status_t +_cairo_xcb_surface_mark_dirty (void *abstract_surface, + int x, int y, + int width, int height) +{ + cairo_xcb_surface_t *surface = abstract_surface; + surface->marked_dirty = TRUE; return CAIRO_STATUS_SUCCESS; } static cairo_surface_t * -_cairo_xcb_surface_snapshot (void *abstract_surface) +_cairo_xcb_surface_map_to_image (cairo_xcb_surface_t *surface) { - cairo_xcb_surface_t *surface = abstract_surface; - cairo_image_surface_t *image; cairo_status_t status; + cairo_image_surface_t *image; - status = _get_image_surface (surface, NULL, &image, NULL); + status = _get_image (surface, TRUE, &image); if (unlikely (status)) return _cairo_surface_create_in_error (status); return &image->base; } -static void -_cairo_xcb_surface_release_source_image (void *abstract_surface, - cairo_image_surface_t *image, - void *image_extra) -{ - cairo_surface_destroy (&image->base); -} - -static cairo_status_t -_cairo_xcb_surface_acquire_dest_image (void *abstract_surface, - cairo_rectangle_int_t *interest_rect, - cairo_image_surface_t **image_out, - cairo_rectangle_int_t *image_rect_out, - void **image_extra) +static cairo_int_status_t +_cairo_xcb_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; - cairo_image_surface_t *image; cairo_status_t status; - status = _get_image_surface (surface, interest_rect, &image, image_rect_out); - if (status) - return status; + if (surface->drm != NULL && ! surface->marked_dirty) + return _cairo_surface_paint (surface->drm, op, source, clip); - *image_out = image; - *image_extra = NULL; - - return CAIRO_STATUS_SUCCESS; -} - -static void -_cairo_xcb_surface_release_dest_image (void *abstract_surface, - cairo_rectangle_int_t *interest_rect, - cairo_image_surface_t *image, - cairo_rectangle_int_t *image_rect, - void *image_extra) -{ - cairo_xcb_surface_t *surface = abstract_surface; - - /* ignore errors */ - _draw_image_surface (surface, image, 0, 0, image->width, image->height, - image_rect->x, image_rect->y); - - cairo_surface_destroy (&image->base); -} - -/* - * Return whether two xcb surfaces share the same - * screen. Both core and Render drawing require this - * when using multiple drawables in an operation. - */ -static cairo_bool_t -_cairo_xcb_surface_same_screen (cairo_xcb_surface_t *dst, - cairo_xcb_surface_t *src) -{ - return dst->dpy == src->dpy && dst->screen == src->screen; -} - -static cairo_status_t -_cairo_xcb_surface_clone_similar (void *abstract_surface, - cairo_surface_t *src, - cairo_content_t content, - int src_x, - int src_y, - int width, - int height, - int *clone_offset_x, - int *clone_offset_y, - cairo_surface_t **clone_out) -{ - cairo_xcb_surface_t *surface = abstract_surface; - cairo_xcb_surface_t *clone; - - if (src->backend == surface->base.backend ) { - cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src; - - if (_cairo_xcb_surface_same_screen(surface, xcb_src)) { - *clone_offset_x = 0; - *clone_offset_y = 0; - *clone_out = cairo_surface_reference (src); - - return CAIRO_STATUS_SUCCESS; - } - } else if (_cairo_surface_is_image (src)) { - cairo_image_surface_t *image_src = (cairo_image_surface_t *)src; - cairo_content_t content = _cairo_content_from_format (image_src->format); - cairo_status_t status; - - if (surface->base.status) - return surface->base.status; - - clone = (cairo_xcb_surface_t *) - _cairo_xcb_surface_create_similar (surface, content, width, height); - if (clone == NULL) - return CAIRO_INT_STATUS_UNSUPPORTED; - if (clone->base.status) - return clone->base.status; - - status = _draw_image_surface (clone, image_src, - src_x, src_y, - width, height, - 0, 0); - if (status) { - cairo_surface_destroy (&clone->base); - return status; - } - - *clone_offset_x = src_x; - *clone_offset_y = src_y; - *clone_out = &clone->base; - - return CAIRO_STATUS_SUCCESS; - } - - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -static cairo_status_t -_cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface, - cairo_matrix_t *matrix) -{ - xcb_render_transform_t xtransform; - xcb_void_cookie_t cookie; - - xtransform.matrix11 = _cairo_fixed_16_16_from_double (matrix->xx); - xtransform.matrix12 = _cairo_fixed_16_16_from_double (matrix->xy); - xtransform.matrix13 = _cairo_fixed_16_16_from_double (matrix->x0); - - xtransform.matrix21 = _cairo_fixed_16_16_from_double (matrix->yx); - xtransform.matrix22 = _cairo_fixed_16_16_from_double (matrix->yy); - xtransform.matrix23 = _cairo_fixed_16_16_from_double (matrix->y0); - - xtransform.matrix31 = 0; - xtransform.matrix32 = 0; - xtransform.matrix33 = 1 << 16; - - if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) - { - static const xcb_render_transform_t identity = { - 1 << 16, 0x00000, 0x00000, - 0x00000, 1 << 16, 0x00000, - 0x00000, 0x00000, 1 << 16 - }; - - if (memcmp (&xtransform, &identity, sizeof (xcb_render_transform_t)) == 0) - return CAIRO_STATUS_SUCCESS; - - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - cookie = xcb_render_set_picture_transform_checked (surface->dpy, - surface->src_picture, - xtransform); - return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); -} - -static cairo_status_t -_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface, - cairo_filter_t filter) -{ - const char *render_filter; - xcb_void_cookie_t cookie; - - if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) - { - if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) - return CAIRO_STATUS_SUCCESS; - - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - switch (filter) { - case CAIRO_FILTER_FAST: - render_filter = "fast"; - break; - case CAIRO_FILTER_GOOD: - render_filter = "good"; - break; - case CAIRO_FILTER_BEST: - render_filter = "best"; - break; - case CAIRO_FILTER_NEAREST: - render_filter = "nearest"; - break; - case CAIRO_FILTER_BILINEAR: - render_filter = "bilinear"; - break; - case CAIRO_FILTER_GAUSSIAN: - default: - render_filter = "best"; - break; - } - - cookie = xcb_render_set_picture_filter_checked (surface->dpy, surface->src_picture, - strlen(render_filter), render_filter, - 0, NULL); - - return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); -} - -static cairo_status_t -_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, cairo_extend_t extend) -{ - uint32_t mask = XCB_RENDER_CP_REPEAT; - uint32_t pa[1]; - xcb_void_cookie_t cookie; - - switch (extend) { - case CAIRO_EXTEND_NONE: - pa[0] = XCB_RENDER_REPEAT_NONE; - break; - - case CAIRO_EXTEND_REPEAT: - pa[0] = XCB_RENDER_REPEAT_NORMAL; - break; - - case CAIRO_EXTEND_REFLECT: - if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - pa[0] = XCB_RENDER_REPEAT_REFLECT; - break; - - case CAIRO_EXTEND_PAD: - if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - pa[0] = XCB_RENDER_REPEAT_PAD; - break; - - default: - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - cookie = xcb_render_change_picture_checked (surface->dpy, surface->src_picture, - mask, pa); - return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); -} - -static cairo_int_status_t -_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface, - cairo_surface_attributes_t *attributes) -{ - cairo_int_status_t status; - - status = _cairo_xcb_surface_ensure_src_picture (surface); - if (status) - return status; - - status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix); - if (status) - return status; - - status = _cairo_xcb_surface_set_repeat (surface, attributes->extend); - if (status) - return status; - - status = _cairo_xcb_surface_set_filter (surface, attributes->filter); - if (status) - return status; - - return CAIRO_STATUS_SUCCESS; -} - -/* Checks whether we can can directly draw from src to dst with - * the core protocol: either with CopyArea or using src as a - * a tile in a GC. - */ -static cairo_bool_t -_surfaces_compatible (cairo_xcb_surface_t *dst, - cairo_xcb_surface_t *src) -{ - /* same screen */ - if (!_cairo_xcb_surface_same_screen (dst, src)) - return FALSE; - - /* same depth (for core) */ - if (src->depth != dst->depth) - return FALSE; - - /* if Render is supported, match picture formats */ - if (src->xrender_format.id != dst->xrender_format.id) - return FALSE; - else if (src->xrender_format.id != XCB_NONE) - return TRUE; - - /* Without Render, match visuals instead */ - if (src->visual == dst->visual) - return TRUE; - - return FALSE; -} - -static cairo_bool_t -_surface_has_alpha (cairo_xcb_surface_t *surface) -{ - if (surface->xrender_format.id != XCB_NONE) { - if (surface->xrender_format.type == XCB_RENDER_PICT_TYPE_DIRECT && - surface->xrender_format.direct.alpha_mask != 0) - return TRUE; - else - return FALSE; - } else { - - /* In the no-render case, we never have alpha */ - return FALSE; - } -} - -/* Returns true if the given operator and source-alpha combination - * requires alpha compositing to complete. - */ -static cairo_bool_t -_operator_needs_alpha_composite (cairo_operator_t op, - cairo_bool_t surface_has_alpha) -{ - if (op == CAIRO_OPERATOR_SOURCE || - (!surface_has_alpha && - (op == CAIRO_OPERATOR_OVER || - op == CAIRO_OPERATOR_ATOP || - op == CAIRO_OPERATOR_IN))) - return FALSE; - - return TRUE; -} - -/* There is a bug in most older X servers with compositing using a - * untransformed repeating source pattern when the source is in off-screen - * video memory, and another with repeated transformed images using a - * general transform matrix. When these bugs could be triggered, we need a - * fallback: in the common case where we have no transformation and the - * source and destination have the same format/visual, we can do the - * operation using the core protocol for the first bug, otherwise, we need - * a software fallback. - * - * We can also often optimize a compositing operation by calling XCopyArea - * for some common cases where there is no alpha compositing to be done. - * We figure that out here as well. - */ -typedef enum { - DO_RENDER, /* use render */ - DO_XCOPYAREA, /* core protocol XCopyArea optimization/fallback */ - DO_XTILE, /* core protocol XSetTile optimization/fallback */ - DO_UNSUPPORTED /* software fallback */ -} composite_operation_t; - -/* Initial check for the render bugs; we need to recheck for the - * offscreen-memory bug after we turn patterns into surfaces, since that - * may introduce a repeating pattern for gradient patterns. We don't need - * to check for the repeat+transform bug because gradient surfaces aren't - * transformed. - * - * All we do here is reject cases where we *know* are going to - * hit the bug and won't be able to use a core protocol fallback. - */ -static composite_operation_t -_categorize_composite_operation (cairo_xcb_surface_t *dst, - cairo_operator_t op, - const cairo_pattern_t *src_pattern, - cairo_bool_t have_mask) - -{ -#if XXX_BUGGY_REPEAT - if (!dst->buggy_repeat) - return DO_RENDER; - - if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE) - { - cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern; - - if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) && - src_pattern->extend == CAIRO_EXTEND_REPEAT) - { - /* This is the case where we have the bug involving - * untransformed repeating source patterns with off-screen - * video memory; reject some cases where a core protocol - * fallback is impossible. - */ - if (have_mask || - !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER)) - return DO_UNSUPPORTED; - - if (_cairo_surface_is_xcb (surface_pattern->surface)) { - cairo_xcb_surface_t *src = (cairo_xcb_surface_t *)surface_pattern->surface; - - if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src)) - return DO_UNSUPPORTED; - - /* If these are on the same screen but otherwise incompatible, - * make a copy as core drawing can't cross depths and doesn't - * work rightacross visuals of the same depth - */ - if (_cairo_xcb_surface_same_screen (dst, src) && - !_surfaces_compatible (dst, src)) - return DO_UNSUPPORTED; - } - } - - /* Check for the other bug involving repeat patterns with general - * transforms. */ - if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) && - src_pattern->extend == CAIRO_EXTEND_REPEAT) - return DO_UNSUPPORTED; - } -#endif - return DO_RENDER; -} - -/* Recheck for composite-repeat once we've turned patterns into Xlib surfaces - * If we end up returning DO_UNSUPPORTED here, we're throwing away work we - * did to turn gradients into a pattern, but most of the time we can handle - * that case with core protocol fallback. - * - * Also check here if we can just use XCopyArea, instead of going through - * Render. - */ -static composite_operation_t -_recategorize_composite_operation (cairo_xcb_surface_t *dst, - cairo_operator_t op, - cairo_xcb_surface_t *src, - cairo_surface_attributes_t *src_attr, - cairo_bool_t have_mask) -{ - cairo_bool_t is_integer_translation = - _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL); - cairo_bool_t needs_alpha_composite = - _operator_needs_alpha_composite (op, _surface_has_alpha (src)); - - if (!have_mask && - is_integer_translation && - src_attr->extend == CAIRO_EXTEND_NONE && - !needs_alpha_composite && - _surfaces_compatible(src, dst)) - { - return DO_XCOPYAREA; - } -#if XXX_BUGGY_REPEAT - if (!dst->buggy_repeat) - return DO_RENDER; - - if (is_integer_translation && - src_attr->extend == CAIRO_EXTEND_REPEAT && - (src->width != 1 || src->height != 1)) - { - if (!have_mask && - !needs_alpha_composite && - _surfaces_compatible (dst, src)) - { - return DO_XTILE; - } - - return DO_UNSUPPORTED; - } -#endif - return DO_RENDER; -} - -static int -_render_operator (cairo_operator_t op) -{ - switch (op) { - case CAIRO_OPERATOR_CLEAR: - return XCB_RENDER_PICT_OP_CLEAR; - case CAIRO_OPERATOR_SOURCE: - return XCB_RENDER_PICT_OP_SRC; - case CAIRO_OPERATOR_DEST: - return XCB_RENDER_PICT_OP_DST; - case CAIRO_OPERATOR_OVER: - return XCB_RENDER_PICT_OP_OVER; - case CAIRO_OPERATOR_DEST_OVER: - return XCB_RENDER_PICT_OP_OVER_REVERSE; - case CAIRO_OPERATOR_IN: - return XCB_RENDER_PICT_OP_IN; - case CAIRO_OPERATOR_DEST_IN: - return XCB_RENDER_PICT_OP_IN_REVERSE; - case CAIRO_OPERATOR_OUT: - return XCB_RENDER_PICT_OP_OUT; - case CAIRO_OPERATOR_DEST_OUT: - return XCB_RENDER_PICT_OP_OUT_REVERSE; - case CAIRO_OPERATOR_ATOP: - return XCB_RENDER_PICT_OP_ATOP; - case CAIRO_OPERATOR_DEST_ATOP: - return XCB_RENDER_PICT_OP_ATOP_REVERSE; - case CAIRO_OPERATOR_XOR: - return XCB_RENDER_PICT_OP_XOR; - case CAIRO_OPERATOR_ADD: - return XCB_RENDER_PICT_OP_ADD; - case CAIRO_OPERATOR_SATURATE: - return XCB_RENDER_PICT_OP_SATURATE; - default: - return XCB_RENDER_PICT_OP_OVER; - } -} - -static cairo_int_status_t -_cairo_xcb_surface_composite (cairo_operator_t op, - const cairo_pattern_t *src_pattern, - const cairo_pattern_t *mask_pattern, - void *abstract_dst, - int src_x, - int src_y, - int mask_x, - int mask_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height, - cairo_region_t *clip_region) -{ - cairo_surface_attributes_t src_attr, mask_attr; - cairo_xcb_surface_t *dst = abstract_dst; - cairo_xcb_surface_t *src; - cairo_xcb_surface_t *mask; - cairo_int_status_t status; - composite_operation_t operation; - int itx, ity; - cairo_bool_t is_integer_translation; - xcb_void_cookie_t cookie; - - if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - operation = _categorize_composite_operation (dst, op, src_pattern, - mask_pattern != NULL); - if (operation == DO_UNSUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; - - status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern, - &dst->base, - src_x, src_y, - mask_x, mask_y, - width, height, - CAIRO_PATTERN_ACQUIRE_NO_REFLECT, - (cairo_surface_t **) &src, - (cairo_surface_t **) &mask, - &src_attr, &mask_attr); - if (status) - return status; - - operation = _recategorize_composite_operation (dst, op, src, &src_attr, - mask_pattern != NULL); - if (operation == DO_UNSUPPORTED) { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto BAIL; - } - - status = _cairo_xcb_surface_set_clip_region (dst, clip_region); - if (unlikely (status)) - goto BAIL; - - status = _cairo_xcb_surface_set_attributes (src, &src_attr); - if (status) - goto BAIL; - - switch (operation) - { - case DO_RENDER: - status = _cairo_xcb_surface_ensure_dst_picture (dst); - if (unlikely (status)) - goto BAIL; - - if (mask) { - status = _cairo_xcb_surface_set_attributes (mask, &mask_attr); - if (unlikely (status)) - goto BAIL; - - cookie = xcb_render_composite_checked (dst->dpy, - _render_operator (op), - src->src_picture, - mask->src_picture, - dst->dst_picture, - src_x + src_attr.x_offset, - src_y + src_attr.y_offset, - mask_x + mask_attr.x_offset, - mask_y + mask_attr.y_offset, - dst_x, dst_y, - width, height); - } else { - static xcb_render_picture_t maskpict = { XCB_NONE }; - - cookie = xcb_render_composite_checked (dst->dpy, - _render_operator (op), - src->src_picture, - maskpict, - dst->dst_picture, - src_x + src_attr.x_offset, - src_y + src_attr.y_offset, - 0, 0, - dst_x, dst_y, - width, height); - } - break; - - case DO_XCOPYAREA: - status = _cairo_xcb_surface_ensure_gc (dst); - if (unlikely (status)) + if (surface->fallback == NULL) { + status = _cairo_xcb_surface_cairo_paint (surface, op, source, clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; - cookie = xcb_copy_area_checked (dst->dpy, - src->drawable, - dst->drawable, - dst->gc, - src_x + src_attr.x_offset, - src_y + src_attr.y_offset, - dst_x, dst_y, - width, height); - break; - - case DO_XTILE: - /* This case is only used for bug fallbacks, though it is theoretically - * applicable to the case where we don't have the RENDER extension as - * well. - * - * We've checked that we have a repeating unscaled source in - * _recategorize_composite_operation. - */ - - status = _cairo_xcb_surface_ensure_gc (dst); - if (unlikely (status)) + status = _cairo_xcb_surface_render_paint (surface, op, source, clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; - is_integer_translation = - _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity); - assert (is_integer_translation == TRUE); - { - uint32_t mask = XCB_GC_FILL_STYLE | XCB_GC_TILE - | XCB_GC_TILE_STIPPLE_ORIGIN_X - | XCB_GC_TILE_STIPPLE_ORIGIN_Y; - uint32_t values[] = { - XCB_FILL_STYLE_TILED, src->drawable, - - (itx + src_attr.x_offset), - - (ity + src_attr.y_offset) - }; - xcb_rectangle_t rect = { dst_x, dst_y, width, height }; - - xcb_change_gc( dst->dpy, dst->gc, mask, values ); - cookie = xcb_poly_fill_rectangle_checked (dst->dpy, - dst->drawable, - dst->gc, - 1, &rect); - } - break; - - case DO_UNSUPPORTED: - default: - ASSERT_NOT_REACHED; + surface->fallback = _cairo_xcb_surface_map_to_image (surface); } - status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie); - if (unlikely (status)) - goto BAIL; - - if (!_cairo_operator_bounded_by_source (op)) { - status = _cairo_surface_composite_fixup_unbounded (&dst->base, - &src_attr, src->width, src->height, - mask ? &mask_attr : NULL, - mask ? mask->width : 0, - mask ? mask->height : 0, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, width, height, - clip_region); - } - - BAIL: - if (mask) - _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr); - - _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr); - - return status; + return _cairo_surface_paint (surface->fallback, op, source, clip); } static cairo_int_status_t -_cairo_xcb_surface_fill_rectangles (void *abstract_surface, - cairo_operator_t op, - const cairo_color_t * color, - cairo_rectangle_int_t *rects, - int num_rects) +_cairo_xcb_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; - xcb_render_color_t render_color; - xcb_rectangle_t static_xrects[16]; - xcb_rectangle_t *xrects = static_xrects; - cairo_status_t status; - xcb_void_cookie_t cookie; - int i; - - 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; - - status = _cairo_xcb_surface_set_clip_region (surface, NULL); - assert (status == CAIRO_STATUS_SUCCESS); - - if (num_rects > ARRAY_LENGTH(static_xrects)) { - xrects = _cairo_malloc_ab (num_rects, sizeof(xcb_rectangle_t)); - if (xrects == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - - for (i = 0; i < num_rects; i++) { - xrects[i].x = rects[i].x; - xrects[i].y = rects[i].y; - xrects[i].width = rects[i].width; - xrects[i].height = rects[i].height; - } - - status = _cairo_xcb_surface_ensure_dst_picture (surface); - if (unlikely (status)) { - if (xrects != static_xrects) - free (xrects); - return status; - } - - cookie = xcb_render_fill_rectangles_checked (surface->dpy, - _render_operator (op), - surface->dst_picture, - render_color, num_rects, xrects); - - if (xrects != static_xrects) - free (xrects); - - return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); -} - -/* Creates an A8 picture of size @width x @height, initialized with @color - */ -static cairo_status_t -_create_a8_picture (cairo_xcb_surface_t *surface, - xcb_render_color_t *color, - int width, - int height, - cairo_bool_t repeat, - xcb_render_picture_t *out) -{ - uint32_t values[] = { TRUE }; - uint32_t mask = repeat ? XCB_RENDER_CP_REPEAT : 0; - - xcb_pixmap_t pixmap; - xcb_render_picture_t picture; - xcb_render_pictforminfo_t *format; - xcb_rectangle_t rect = { 0, 0, width, height }; - - cairo_xcb_cookie_t *cookie[3]; cairo_status_t status; - status = _cairo_freepool_alloc_array (&surface->cookie_pool, - ARRAY_LENGTH (cookie), - (void **) cookie); - if (unlikely (status)) - return status; + if (surface->drm != NULL && ! surface->marked_dirty) + return _cairo_surface_mask (surface->drm, op, source, mask, clip); - pixmap = xcb_generate_id (surface->dpy); - picture = xcb_generate_id (surface->dpy); + if (surface->fallback == NULL) { + status = _cairo_xcb_surface_cairo_mask (surface, + op, source, mask, clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; - cookie[0]->xcb = xcb_create_pixmap_checked (surface->dpy, 8, pixmap, surface->drawable, - width <= 0 ? 1 : width, - height <= 0 ? 1 : height); - cairo_list_add_tail (&cookie[0]->link, &surface->to_be_checked); + status = _cairo_xcb_surface_render_mask (surface, + op, source, mask, clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; - format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (surface->dpy, CAIRO_FORMAT_A8); - cookie[1]->xcb = xcb_render_create_picture_checked (surface->dpy, - picture, pixmap, format->id, - mask, values); - cairo_list_add_tail (&cookie[1]->link, &surface->to_be_checked); - - cookie[2]->xcb = xcb_render_fill_rectangles_checked (surface->dpy, - XCB_RENDER_PICT_OP_SRC, - picture, *color, 1, &rect); - cairo_list_add_tail (&cookie[2]->link, &surface->to_be_checked); - - xcb_free_pixmap (surface->dpy, pixmap); - - *out = picture; - return CAIRO_STATUS_SUCCESS; -} - -/* Creates a temporary mask for the trapezoids covering the area - * [@dst_x, @dst_y, @width, @height] of the destination surface. - */ -static cairo_status_t -_create_trapezoid_mask (cairo_xcb_surface_t *dst, - cairo_trapezoid_t *traps, - int num_traps, - int dst_x, - int dst_y, - int width, - int height, - xcb_render_pictforminfo_t *pict_format, - xcb_render_picture_t *mask_picture_out) -{ - xcb_render_color_t transparent = { 0, 0, 0, 0 }; - xcb_render_color_t solid = { 0xffff, 0xffff, 0xffff, 0xffff }; - xcb_render_picture_t mask_picture, solid_picture; - xcb_render_trapezoid_t *offset_traps; - xcb_void_cookie_t cookie; - cairo_status_t status; - int i; - - /* This would be considerably simpler using XRenderAddTraps(), but since - * we are only using this in the unbounded-operator case, we stick with - * XRenderCompositeTrapezoids, which is available on older versions - * of RENDER rather than conditionalizing. We should still hit an - * optimization that avoids creating another intermediate surface on - * the servers that have XRenderAddTraps(). - */ - status = _create_a8_picture (dst, &transparent, width, height, FALSE, &mask_picture); - if (unlikely (status)) - return status; - - status = _create_a8_picture (dst, &solid, 1, 1, TRUE, &solid_picture); - if (unlikely (status)) { - xcb_render_free_picture (dst->dpy, mask_picture); - return status; + surface->fallback = _cairo_xcb_surface_map_to_image (surface); } - offset_traps = _cairo_malloc_ab (num_traps, sizeof (xcb_render_trapezoid_t)); - if (offset_traps == NULL) { - xcb_render_free_picture (dst->dpy, solid_picture); - xcb_render_free_picture (dst->dpy, mask_picture); - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } - - for (i = 0; i < num_traps; i++) { - offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y; - offset_traps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom) - 0x10000 * dst_y; - offset_traps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x) - 0x10000 * dst_x; - offset_traps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y) - 0x10000 * dst_y; - offset_traps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x) - 0x10000 * dst_x; - offset_traps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y) - 0x10000 * dst_y; - offset_traps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x) - 0x10000 * dst_x; - offset_traps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y) - 0x10000 * dst_y; - offset_traps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x) - 0x10000 * dst_x; - offset_traps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y) - 0x10000 * dst_y; - } - - cookie = xcb_render_trapezoids_checked (dst->dpy, XCB_RENDER_PICT_OP_ADD, - solid_picture, mask_picture, - pict_format->id, - 0, 0, - num_traps, offset_traps); - - xcb_render_free_picture (dst->dpy, solid_picture); - free (offset_traps); - - status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie); - if (unlikely (status)) { - xcb_render_free_picture (dst->dpy, mask_picture); - return status; - } - - *mask_picture_out = mask_picture; - return CAIRO_STATUS_SUCCESS; + return _cairo_surface_mask (surface->fallback, + op, source, mask, + clip); } static cairo_int_status_t -_cairo_xcb_surface_composite_trapezoids (cairo_operator_t op, - const cairo_pattern_t *pattern, - void *abstract_dst, - cairo_antialias_t antialias, - int src_x, - int src_y, - int dst_x, - int dst_y, - unsigned int width, - unsigned int height, - cairo_trapezoid_t *traps, - int num_traps, - cairo_region_t *clip_region) -{ - cairo_surface_attributes_t attributes; - cairo_xcb_surface_t *dst = abstract_dst; - cairo_xcb_surface_t *src; - cairo_int_status_t status; - composite_operation_t operation; - int render_reference_x, render_reference_y; - int render_src_x, render_src_y; - int cairo_format; - xcb_render_pictforminfo_t *render_format; - - if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - operation = _categorize_composite_operation (dst, op, pattern, TRUE); - if (operation == DO_UNSUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; - - status = _cairo_pattern_acquire_surface (pattern, &dst->base, - src_x, src_y, width, height, - CAIRO_PATTERN_ACQUIRE_NO_REFLECT, - (cairo_surface_t **) &src, - &attributes); - if (status) - return status; - - operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE); - if (operation == DO_UNSUPPORTED) { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto BAIL; - } - - switch (antialias) { - case CAIRO_ANTIALIAS_NONE: - cairo_format = CAIRO_FORMAT_A1; - break; - case CAIRO_ANTIALIAS_GRAY: - case CAIRO_ANTIALIAS_SUBPIXEL: - case CAIRO_ANTIALIAS_DEFAULT: - default: - cairo_format = CAIRO_FORMAT_A8; - break; - } - render_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dst->dpy, cairo_format); - /* XXX: what to do if render_format is null? */ - - if (traps[0].left.p1.y < traps[0].left.p2.y) { - render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); - render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y); - } else { - render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x); - render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y); - } - - render_src_x = src_x + render_reference_x - dst_x; - render_src_y = src_y + render_reference_y - dst_y; - - status = _cairo_xcb_surface_ensure_dst_picture (dst); - if (unlikely (status)) - goto BAIL; - - status = _cairo_xcb_surface_set_clip_region (dst, clip_region); - if (unlikely (status)) - goto BAIL; - - status = _cairo_xcb_surface_set_attributes (src, &attributes); - if (status) - goto BAIL; - - if (!_cairo_operator_bounded_by_mask (op)) { - xcb_void_cookie_t cookie; - - /* xcb_render_composite+trapezoids() creates a mask only large enough for the - * trapezoids themselves, but if the operator is unbounded, then we need - * to actually composite all the way out to the bounds, so we create - * the mask and composite ourselves. There actually would - * be benefit to doing this in all cases, since RENDER implementations - * will frequently create a too temporary big mask, ignoring destination - * bounds and clip. (xcb_render_add_traps() could be used to make creating - * the mask somewhat cheaper.) - */ - xcb_render_picture_t mask_picture = 0; /* silence compiler */ - - status = _create_trapezoid_mask (dst, traps, num_traps, - dst_x, dst_y, width, height, - render_format, - &mask_picture); - if (status) - goto BAIL; - - cookie = xcb_render_composite_checked (dst->dpy, - _render_operator (op), - src->src_picture, - mask_picture, - dst->dst_picture, - src_x + attributes.x_offset, - src_y + attributes.y_offset, - 0, 0, - dst_x, dst_y, - width, height); - xcb_render_free_picture (dst->dpy, mask_picture); - - status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie); - if (unlikely (status)) - goto BAIL; - - status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base, - &attributes, src->width, src->height, - width, height, - src_x, src_y, - 0, 0, - dst_x, dst_y, width, height, - clip_region); - - } else { - xcb_render_trapezoid_t xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (xcb_render_trapezoid_t)]; - xcb_render_trapezoid_t *xtraps = xtraps_stack; - xcb_void_cookie_t cookie; - int i; - - if (num_traps > ARRAY_LENGTH(xtraps_stack)) { - xtraps = _cairo_malloc_ab (num_traps, sizeof(xcb_render_trapezoid_t)); - if (xtraps == NULL) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto BAIL; - } - } - - for (i = 0; i < num_traps; i++) { - xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top); - xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom); - xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x); - xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y); - xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x); - xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y); - xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x); - xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y); - xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x); - xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y); - } - - cookie = xcb_render_trapezoids_checked (dst->dpy, - _render_operator (op), - src->src_picture, dst->dst_picture, - render_format->id, - render_src_x + attributes.x_offset, - render_src_y + attributes.y_offset, - num_traps, xtraps); - - if (xtraps != xtraps_stack) - free (xtraps); - - status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie); - } - - BAIL: - _cairo_pattern_release_surface (pattern, &src->base, &attributes); - - return status; -} - -static cairo_bool_t -_cairo_xcb_surface_get_extents (void *abstract_surface, - cairo_rectangle_int_t *rectangle) +_cairo_xcb_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; + cairo_status_t status; - rectangle->x = 0; - rectangle->y = 0; - - rectangle->width = surface->width; - rectangle->height = surface->height; - - return TRUE; -} - -static cairo_status_t -_cairo_xcb_surface_flush (void *abstract_surface) -{ - cairo_xcb_surface_t *surface = abstract_surface; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - - while (! cairo_list_is_empty (&surface->to_be_checked)) { - cairo_xcb_cookie_t *cookie; - xcb_generic_error_t *error; - - cookie = cairo_list_first_entry (&surface->to_be_checked, - cairo_xcb_cookie_t, - link); - - error = xcb_request_check (surface->dpy, cookie->xcb); - if (error != NULL) { -#if 0 - /* XXX */ - fprintf (stderr, "Delayed error detected: %d, major=%d, minor=%d, seqno=%d\n", - error->error_code, - error->major_code, - error->minor_code, - error->sequence); -#endif - if (status == CAIRO_STATUS_SUCCESS) - status = _cairo_error (CAIRO_STATUS_WRITE_ERROR); /* XXX CAIRO_STATUS_CONNECTION_ERROR */ - } - - cairo_list_del (&cookie->link); - _cairo_freepool_free (&surface->cookie_pool, cookie); + if (surface->drm != NULL && ! surface->marked_dirty) { + return _cairo_surface_stroke (surface->drm, + op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); } - return status; + if (surface->fallback == NULL) { + status = _cairo_xcb_surface_cairo_stroke (surface, op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_xcb_surface_render_stroke (surface, op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + surface->fallback = _cairo_xcb_surface_map_to_image (surface); + } + + return _cairo_surface_stroke (surface->fallback, + op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); } -/* XXX: _cairo_xcb_surface_get_font_options */ - -static void -_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font); - -static void -_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, - cairo_scaled_font_t *scaled_font); - static cairo_int_status_t -_cairo_xcb_surface_show_glyphs (void *abstract_dst, - cairo_operator_t op, - const cairo_pattern_t *src_pattern, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, - int *remaining_glyphs); - -static cairo_bool_t -_cairo_xcb_surface_is_similar (void *surface_a, - void *surface_b, - cairo_content_t content) +_cairo_xcb_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) { - cairo_xcb_surface_t *a = surface_a; - cairo_xcb_surface_t *b = surface_b; - xcb_render_pictforminfo_t *xrender_format; + cairo_xcb_surface_t *surface = abstract_surface; + cairo_status_t status; - /* XXX: disable caching by the solid pattern cache until we implement - * display notification to avoid issuing xcb calls from the wrong thread - * or accessing the surface after the Display has been closed. - */ - return FALSE; + if (surface->drm != NULL && ! surface->marked_dirty) { + return _cairo_surface_fill (surface->drm, + op, source, + path, fill_rule, + tolerance, antialias, + clip); + } - if (! _cairo_xcb_surface_same_screen (a, b)) - return FALSE; + if (surface->fallback == NULL) { + status = _cairo_xcb_surface_cairo_fill (surface, op, source, + path, fill_rule, + tolerance, antialias, + clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; - /* now check that the target is a similar format */ - xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (b->dpy, - _cairo_format_from_content (content)); + status = _cairo_xcb_surface_render_fill (surface, op, source, + path, fill_rule, + tolerance, antialias, + clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; - return a->xrender_format.id == xrender_format->id; + surface->fallback = _cairo_xcb_surface_map_to_image (surface); + } + + return _cairo_surface_fill (surface->fallback, + op, source, + path, fill_rule, + tolerance, antialias, + clip); } -/* XXX: move this to the bottom of the file, XCB and Xlib */ +static cairo_int_status_t +_cairo_xcb_surface_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip, + int *num_remaining) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_status_t status; -static const cairo_surface_backend_t cairo_xcb_surface_backend = { + *num_remaining = 0; + + if (surface->drm != NULL && ! surface->marked_dirty) { + return _cairo_surface_show_text_glyphs (surface->drm, + op, source, + NULL, 0, + glyphs, num_glyphs, + NULL, 0, 0, + scaled_font, + clip); + } + + if (surface->fallback == NULL) { + status = _cairo_xcb_surface_cairo_glyphs (surface, + op, source, + scaled_font, glyphs, num_glyphs, + clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_xcb_surface_render_glyphs (surface, + op, source, + scaled_font, glyphs, num_glyphs, + clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + surface->fallback = _cairo_xcb_surface_map_to_image (surface); + } + + return _cairo_surface_show_text_glyphs (surface->fallback, + op, source, + NULL, 0, + glyphs, num_glyphs, + NULL, 0, 0, + scaled_font, + clip); +} + +const cairo_surface_backend_t _cairo_xcb_surface_backend = { CAIRO_SURFACE_TYPE_XCB, _cairo_xcb_surface_create_similar, _cairo_xcb_surface_finish, _cairo_xcb_surface_acquire_source_image, _cairo_xcb_surface_release_source_image, + NULL, NULL, NULL, /* dest acquire/release/clone */ - _cairo_xcb_surface_acquire_dest_image, - _cairo_xcb_surface_release_dest_image, - - _cairo_xcb_surface_clone_similar, - _cairo_xcb_surface_composite, - _cairo_xcb_surface_fill_rectangles, - _cairo_xcb_surface_composite_trapezoids, - NULL, /* create_span_renderer */ - NULL, /* check_span_renderer */ + NULL, /* composite */ + NULL, /* fill */ + NULL, /* trapezoids */ + NULL, /* span */ + NULL, /* check-span */ NULL, /* copy_page */ NULL, /* show_page */ - _cairo_xcb_surface_get_extents, - NULL, /* old_show_glyphs */ - NULL, /* get_font_options */ + NULL, /* old-glyphs */ + _cairo_xcb_surface_get_font_options, + _cairo_xcb_surface_flush, - NULL, /* mark_dirty_rectangle */ + _cairo_xcb_surface_mark_dirty, _cairo_xcb_surface_scaled_font_fini, _cairo_xcb_surface_scaled_glyph_fini, - NULL, /* paint */ - NULL, /* mask */ - NULL, /* stroke */ - NULL, /* fill */ - _cairo_xcb_surface_show_glyphs, - - _cairo_xcb_surface_snapshot, - - _cairo_xcb_surface_is_similar, + _cairo_xcb_surface_paint, + _cairo_xcb_surface_mask, + _cairo_xcb_surface_stroke, + _cairo_xcb_surface_fill, + _cairo_xcb_surface_glyphs, }; -/** - * _cairo_surface_is_xcb: - * @surface: a #cairo_surface_t - * - * Checks if a surface is a #cairo_xcb_surface_t - * - * Return value: True if the surface is an xcb surface - **/ -static cairo_bool_t -_cairo_surface_is_xcb (cairo_surface_t *surface) +#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS +static cairo_surface_t * +_xcb_drm_create_surface_for_drawable (cairo_xcb_connection_t *connection, + cairo_xcb_screen_t *screen, + xcb_drawable_t drawable, + pixman_format_code_t pixman_format, + int width, int height) { - return surface->backend == &cairo_xcb_surface_backend; + uint32_t attachments[] = { XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT }; + xcb_dri2_get_buffers_reply_t *buffers; + xcb_dri2_dri2_buffer_t *buffer; + cairo_surface_t *surface; + + if (! _cairo_drm_size_is_valid (screen->device, width, height)) + return NULL; + + xcb_dri2_create_drawable (connection->xcb_connection, + drawable); + + buffers = xcb_dri2_get_buffers_reply (connection->xcb_connection, + xcb_dri2_get_buffers (connection->xcb_connection, + drawable, 1, + ARRAY_LENGTH (attachments), + attachments), + 0); + if (buffers == NULL) { + xcb_dri2_destroy_drawable (connection->xcb_connection, + drawable); + return NULL; + } + + /* If the drawable is a window, we expect to receive an extra fake front, + * which would involve copying on each flush - contrary to the user + * expectations. But that is likely to be preferable to mixing drm/xcb + * operations. + */ + buffer = xcb_dri2_get_buffers_buffers (buffers); + if (buffers->count == 1 && buffer[0].attachment == XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT) { + assert (buffer[0].cpp == PIXMAN_FORMAT_BPP (pixman_format) / 8); + surface = cairo_drm_surface_create_for_name (screen->device, + buffer[0].name, + _cairo_format_from_pixman_format (pixman_format), + width, height, + buffer[0].pitch); + } else { + xcb_dri2_destroy_drawable (connection->xcb_connection, + drawable); + surface = NULL; + } + free (buffers); + + return surface; } +#else + static cairo_surface_t * -_cairo_xcb_surface_create_internal (xcb_connection_t *dpy, - xcb_drawable_t drawable, - xcb_screen_t *screen, - xcb_visualtype_t *visual, - xcb_render_pictforminfo_t *xrender_format, - int width, - int height, - int depth) +_xcb_drm_create_surface_for_drawable (cairo_xcb_connection_t *connection, + cairo_xcb_screen_t *screen, + xcb_drawable_t drawable, + pixman_format_code_t pixman_format, + int width, int height) +{ + return NULL; +} + +#endif + +cairo_surface_t * +_cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen, + xcb_drawable_t drawable, + cairo_bool_t owns_pixmap, + pixman_format_code_t pixman_format, + xcb_render_pictformat_t xrender_format, + int width, + int height) { cairo_xcb_surface_t *surface; - const xcb_query_extension_reply_t *er; - const xcb_render_query_version_reply_t *r = NULL; surface = malloc (sizeof (cairo_xcb_surface_t)); - if (surface == NULL) + if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - if (xrender_format) { - depth = xrender_format->depth; - } else if (visual) { - xcb_depth_iterator_t depths; - xcb_visualtype_iterator_t visuals; + _cairo_surface_init (&surface->base, + &_cairo_xcb_surface_backend, + &screen->connection->device, + _cairo_content_from_pixman_format (pixman_format)); - /* This is ugly, but we have to walk over all visuals - * for the screen to find the depth. - */ - depths = xcb_screen_allowed_depths_iterator(screen); - for(; depths.rem; xcb_depth_next(&depths)) - { - visuals = xcb_depth_visuals_iterator(depths.data); - for(; visuals.rem; xcb_visualtype_next(&visuals)) - { - if(visuals.data->visual_id == visual->visual_id) - { - depth = depths.data->depth; - goto found; - } - } - } - found: - ; - } - - er = xcb_get_extension_data(dpy, &xcb_render_id); - if(er && er->present) { - r = xcb_render_util_query_version(dpy); - } - if (r) { - surface->render_major = r->major_version; - surface->render_minor = r->minor_version; - } else { - surface->render_major = -1; - surface->render_minor = -1; - } - - if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) { - if (!xrender_format) { - if (visual) { - const xcb_render_query_pict_formats_reply_t *formats; - xcb_render_pictvisual_t *pict_visual; - formats = xcb_render_util_query_formats (dpy); - pict_visual = xcb_render_util_find_visual_format (formats, visual->visual_id); - if (pict_visual) { - xcb_render_pictforminfo_t template; - template.id = pict_visual->format; - xrender_format = xcb_render_util_find_format (formats, XCB_PICT_FORMAT_ID, &template, 0); - } - } else if (depth == 1) { - xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, CAIRO_FORMAT_A1); - } - } - } else { - xrender_format = NULL; - } - - _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend, - _xcb_render_format_to_content (xrender_format)); - - surface->dpy = dpy; - - surface->gc = XCB_NONE; - surface->drawable = drawable; + surface->connection = _cairo_xcb_connection_reference (screen->connection); surface->screen = screen; - surface->owns_pixmap = FALSE; + cairo_list_add (&surface->link, &screen->surfaces); + + surface->fallback = NULL; + + surface->drawable = drawable; + surface->owns_pixmap = owns_pixmap; surface->use_pixmap = 0; - surface->width = width; + + surface->deferred_clear = FALSE; + + surface->width = width; surface->height = height; + surface->depth = PIXMAN_FORMAT_DEPTH (pixman_format); - /* XXX: set buggy_repeat based on ServerVendor and VendorRelease */ + surface->picture = XCB_NONE; - surface->dst_picture = XCB_NONE; - surface->src_picture = XCB_NONE; + surface->pixman_format = pixman_format; + surface->xrender_format = xrender_format; - surface->visual = visual; - surface->xrender_format.id = XCB_NONE; - if (xrender_format) surface->xrender_format = *xrender_format; - surface->depth = depth; + surface->flags = screen->connection->flags; - surface->have_clip_rects = FALSE; - surface->clip_rects = NULL; - surface->num_clip_rects = 0; - surface->clip_region = NULL; - - cairo_list_init (&surface->to_be_checked); - _cairo_freepool_init (&surface->cookie_pool, - sizeof (cairo_xcb_cookie_t)); + surface->marked_dirty = FALSE; + surface->drm = NULL; + if (screen->device != NULL) { + surface->drm = _xcb_drm_create_surface_for_drawable (surface->connection, + surface->screen, + drawable, + pixman_format, + width, height); + } return &surface->base; } static xcb_screen_t * -_cairo_xcb_screen_from_visual (xcb_connection_t *c, xcb_visualtype_t *visual) +_cairo_xcb_screen_from_visual (xcb_connection_t *connection, + xcb_visualtype_t *visual, + int *depth) { xcb_depth_iterator_t d; - xcb_screen_iterator_t s = xcb_setup_roots_iterator(xcb_get_setup(c)); - for (; s.rem; xcb_screen_next(&s)) - { - if (s.data->root_visual == visual->visual_id) + xcb_screen_iterator_t s; + + s = xcb_setup_roots_iterator (xcb_get_setup (connection)); + for (; s.rem; xcb_screen_next (&s)) { + if (s.data->root_visual == visual->visual_id) { + *depth = s.data->root_depth; return s.data; + } d = xcb_screen_allowed_depths_iterator(s.data); - for (; d.rem; xcb_depth_next(&d)) - { - xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator(d.data); - for (; v.rem; xcb_visualtype_next(&v)) - { - if (v.data->visual_id == visual->visual_id) + for (; d.rem; xcb_depth_next (&d)) { + xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data); + + for (; v.rem; xcb_visualtype_next (&v)) { + if (v.data->visual_id == visual->visual_id) { + *depth = d.data->depth; return s.data; + } } } } + return NULL; } -/** - * cairo_xcb_surface_create: - * @c: an XCB connection - * @drawable: an XCB drawable - * @visual: the visual to use for drawing to @drawable. The depth - * of the visual must match the depth of the drawable. - * Currently, only TrueColor visuals are fully supported. - * @width: the current width of @drawable. - * @height: the current height of @drawable. - * - * Creates an XCB surface that draws to the given drawable. - * The way that colors are represented in the drawable is specified - * by the provided visual. - * - * Note: If @drawable is a window, then the function - * cairo_xcb_surface_set_size() must be called whenever the size of the - * window changes. - * - * Return value: the newly created surface - **/ cairo_surface_t * -cairo_xcb_surface_create (xcb_connection_t *c, - xcb_drawable_t drawable, - xcb_visualtype_t *visual, - int width, - int height) +cairo_xcb_surface_create (xcb_connection_t *xcb_connection, + xcb_drawable_t drawable, + xcb_visualtype_t *visual, + int width, + int height) { - xcb_screen_t *screen = _cairo_xcb_screen_from_visual (c, visual); + cairo_xcb_screen_t *screen; + xcb_screen_t *xcb_screen; + cairo_format_masks_t image_masks; + pixman_format_code_t pixman_format; + xcb_render_pictformat_t xrender_format; + int depth; - if (screen == NULL) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL)); + if (xcb_connection_has_error (xcb_connection)) + return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR); - return _cairo_xcb_surface_create_internal (c, drawable, screen, - visual, NULL, - width, height, 0); + if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE); + + xcb_screen = _cairo_xcb_screen_from_visual (xcb_connection, visual, &depth); + if (unlikely (xcb_screen == NULL)) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_VISUAL); + + image_masks.alpha_mask = 0; + image_masks.red_mask = visual->red_mask; + image_masks.green_mask = visual->green_mask; + image_masks.blue_mask = visual->blue_mask; + if (depth > 16) + image_masks.bpp = 32; + else if (depth > 8) + image_masks.bpp = 16; + else if (depth > 1) + image_masks.bpp = 8; + else + image_masks.bpp = 1; + + if (! _pixman_format_from_masks (&image_masks, &pixman_format)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + + screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen); + if (unlikely (screen == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + xrender_format = + _cairo_xcb_connection_get_xrender_format_for_visual (screen->connection, + visual->visual_id); + + return _cairo_xcb_surface_create_internal (screen, drawable, FALSE, + pixman_format, + xrender_format, + width, height); } +#if CAIRO_HAS_XLIB_XCB_FUNCTIONS +slim_hidden_def (cairo_xcb_surface_create); +#endif -/** - * cairo_xcb_surface_create_for_bitmap: - * @c: an XCB connection - * @bitmap: an XCB Pixmap (a depth-1 pixmap) - * @screen: an XCB Screen - * @width: the current width of @bitmap - * @height: the current height of @bitmap - * - * Creates an XCB surface that draws to the given bitmap. - * This will be drawn to as a %CAIRO_FORMAT_A1 object. - * - * Return value: the newly created surface - **/ cairo_surface_t * -cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c, - xcb_pixmap_t bitmap, - xcb_screen_t *screen, - int width, - int height) +cairo_xcb_surface_create_for_bitmap (xcb_connection_t *xcb_connection, + xcb_screen_t *xcb_screen, + xcb_pixmap_t bitmap, + int width, + int height) { - return _cairo_xcb_surface_create_internal (c, bitmap, screen, - NULL, NULL, - width, height, 1); + cairo_xcb_screen_t *screen; + + if (xcb_connection_has_error (xcb_connection)) + return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR); + + if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE); + + screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen); + if (unlikely (screen == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + return _cairo_xcb_surface_create_internal (screen, bitmap, FALSE, + PIXMAN_a1, + screen->connection->standard_formats[CAIRO_FORMAT_A1], + width, height); } +#if CAIRO_HAS_XLIB_XCB_FUNCTIONS +slim_hidden_def (cairo_xcb_surface_create_for_bitmap); +#endif /** * cairo_xcb_surface_create_with_xrender_format: - * @c: an XCB connection + * @connection: an XCB connection * @drawable: an XCB drawable * @screen: the XCB screen associated with @drawable * @format: the picture format to use for drawing to @drawable. The @@ -2182,18 +1258,61 @@ cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c, * Return value: the newly created surface. **/ cairo_surface_t * -cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *c, +cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *xcb_connection, + xcb_screen_t *xcb_screen, xcb_drawable_t drawable, - xcb_screen_t *screen, xcb_render_pictforminfo_t *format, int width, int height) { - return _cairo_xcb_surface_create_internal (c, drawable, screen, - NULL, format, - width, height, 0); + cairo_xcb_screen_t *screen; + cairo_format_masks_t image_masks; + pixman_format_code_t pixman_format; + + if (xcb_connection_has_error (xcb_connection)) + return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR); + + if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE); + + image_masks.alpha_mask = + (unsigned long) format->direct.alpha_mask << format->direct.alpha_shift; + image_masks.red_mask = + (unsigned long) format->direct.red_mask << format->direct.red_shift; + image_masks.green_mask = + (unsigned long) format->direct.green_mask << format->direct.green_shift; + image_masks.blue_mask = + (unsigned long) format->direct.blue_mask << format->direct.blue_shift; +#if 0 + image_masks.bpp = format->depth; +#else + if (format->depth > 16) + image_masks.bpp = 32; + else if (format->depth > 8) + image_masks.bpp = 16; + else if (format->depth > 1) + image_masks.bpp = 8; + else + image_masks.bpp = 1; +#endif + + if (! _pixman_format_from_masks (&image_masks, &pixman_format)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + + screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen); + if (unlikely (screen == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + return _cairo_xcb_surface_create_internal (screen, + drawable, + FALSE, + pixman_format, + format->id, + width, height); } +#if CAIRO_HAS_XLIB_XCB_FUNCTIONS slim_hidden_def (cairo_xcb_surface_create_with_xrender_format); +#endif /** * cairo_xcb_surface_set_size: @@ -2213,618 +1332,37 @@ slim_hidden_def (cairo_xcb_surface_create_with_xrender_format); **/ void cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface, - int width, - int height) + int width, + int height) { - cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) abstract_surface; + cairo_xcb_surface_t *surface; cairo_status_t status_ignored; - if (! _cairo_surface_is_xcb (abstract_surface)) { + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { status_ignored = _cairo_surface_set_error (abstract_surface, - CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } - surface->width = width; + + if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) { + status_ignored = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return; + } + + if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) { + status_ignored = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_INVALID_SIZE)); + return; + } + + surface = (cairo_xcb_surface_t *) abstract_surface; + surface->width = width; surface->height = height; } - -/* - * Glyph rendering support - */ - -typedef struct _cairo_xcb_surface_font_private { - xcb_connection_t *dpy; - xcb_render_glyphset_t glyphset; - cairo_format_t format; - xcb_render_pictforminfo_t *xrender_format; -} cairo_xcb_surface_font_private_t; - -static cairo_status_t -_cairo_xcb_surface_font_init (xcb_connection_t *dpy, - cairo_scaled_font_t *scaled_font, - cairo_format_t format) -{ - cairo_xcb_surface_font_private_t *font_private; - - font_private = malloc (sizeof (cairo_xcb_surface_font_private_t)); - if (!font_private) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - font_private->dpy = dpy; - font_private->format = format; - font_private->xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(dpy, format); - font_private->glyphset = xcb_generate_id(dpy); - - /* XXX checking, adding to CloseDisplay */ - xcb_render_create_glyph_set (dpy, - font_private->glyphset, - font_private->xrender_format->id); - - scaled_font->surface_private = font_private; - scaled_font->surface_backend = &cairo_xcb_surface_backend; - - return CAIRO_STATUS_SUCCESS; -} - -static void -_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font) -{ - cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private; - - if (font_private) { - xcb_render_free_glyph_set (font_private->dpy, font_private->glyphset); - free (font_private); - } -} - -static void -_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, - cairo_scaled_font_t *scaled_font) -{ - cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private; - - if (font_private != NULL && scaled_glyph->surface_private != NULL) { - xcb_render_glyph_t glyph_index = _cairo_scaled_glyph_index(scaled_glyph); - xcb_render_free_glyphs (font_private->dpy, - font_private->glyphset, - 1, &glyph_index); - } -} - -static cairo_bool_t -_native_byte_order_lsb (void) -{ - int x = 1; - - return *((char *) &x) == 1; -} - -static cairo_status_t -_cairo_xcb_surface_add_glyph (cairo_xcb_surface_t *dst, - cairo_scaled_font_t *scaled_font, - cairo_scaled_glyph_t *scaled_glyph) -{ - xcb_render_glyphinfo_t glyph_info; - xcb_render_glyph_t glyph_index; - unsigned char *data; - cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_xcb_surface_font_private_t *font_private; - cairo_image_surface_t *glyph_surface = scaled_glyph->surface; - xcb_void_cookie_t cookie; - - if (scaled_font->surface_private == NULL) { - status = _cairo_xcb_surface_font_init (dst->dpy, scaled_font, - glyph_surface->format); - if (status) - return status; - } - font_private = scaled_font->surface_private; - - /* If the glyph format does not match the font format, then we - * create a temporary surface for the glyph image with the font's - * format. - */ - if (glyph_surface->format != font_private->format) { - cairo_surface_pattern_t pattern; - cairo_surface_t *tmp_surface; - - tmp_surface = cairo_image_surface_create (font_private->format, - glyph_surface->width, - glyph_surface->height); - status = tmp_surface->status; - if (unlikely (status)) - goto BAIL; - - tmp_surface->device_transform = glyph_surface->base.device_transform; - tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse; - - _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base); - status = _cairo_surface_paint (tmp_surface, - CAIRO_OPERATOR_SOURCE, &pattern.base, - NULL); - _cairo_pattern_fini (&pattern.base); - - glyph_surface = (cairo_image_surface_t *) tmp_surface; - - if (unlikely (status)) - goto BAIL; - } - - /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */ - glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0); - glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0); - glyph_info.width = glyph_surface->width; - glyph_info.height = glyph_surface->height; - glyph_info.x_off = 0; - glyph_info.y_off = 0; - - data = glyph_surface->data; - - /* flip formats around */ - switch (scaled_glyph->surface->format) { - case CAIRO_FORMAT_A1: - /* local bitmaps are always stored with bit == byte */ - if (_native_byte_order_lsb() != (xcb_get_setup(dst->dpy)->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) { - int c = glyph_surface->stride * glyph_surface->height; - unsigned char *d; - unsigned char *new, *n; - - new = malloc (c); - if (!new) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto BAIL; - } - n = new; - d = data; - while (c--) - { - char b = *d++; - b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55); - b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33); - b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f); - *n++ = b; - } - data = new; - } - break; - case CAIRO_FORMAT_A8: - break; - case CAIRO_FORMAT_ARGB32: - if (_native_byte_order_lsb() != (xcb_get_setup(dst->dpy)->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) { - unsigned int c = glyph_surface->stride * glyph_surface->height; - unsigned char *d; - unsigned char *new, *n; - - new = malloc (c); - if (new == NULL) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto BAIL; - } - n = new; - d = data; - while (c >= 4) - { - n[3] = d[0]; - n[2] = d[1]; - n[1] = d[2]; - n[0] = d[3]; - d += 4; - n += 4; - c -= 4; - } - data = new; - } - break; - case CAIRO_FORMAT_RGB24: - default: - ASSERT_NOT_REACHED; - break; - } - /* XXX assume X server wants pixman padding. Xft assumes this as well */ - - glyph_index = _cairo_scaled_glyph_index (scaled_glyph); - - cookie = xcb_render_add_glyphs_checked (dst->dpy, font_private->glyphset, - 1, &glyph_index, &glyph_info, - glyph_surface->stride * glyph_surface->height, - data); - - if (data != glyph_surface->data) - free (data); - - status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie); - - BAIL: - if (glyph_surface != scaled_glyph->surface) - cairo_surface_destroy (&glyph_surface->base); - - return status; -} - -#define N_STACK_BUF 1024 - -static cairo_status_t -_cairo_xcb_surface_show_glyphs_8 (cairo_xcb_surface_t *dst, - cairo_operator_t op, - cairo_xcb_surface_t *src, - int src_x_offset, int src_y_offset, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font) -{ - cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private; - xcb_render_util_composite_text_stream_t *stream; - xcb_void_cookie_t cookie; - int i; - int thisX, thisY; - int lastX = 0, lastY = 0; - uint8_t glyph; - - stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0); - - for (i = 0; i < num_glyphs; ++i) { - thisX = _cairo_lround (glyphs[i].x); - thisY = _cairo_lround (glyphs[i].y); - glyph = glyphs[i].index; - xcb_render_util_glyphs_8 (stream, thisX - lastX, thisY - lastY, 1, &glyph); - lastX = thisX; - lastY = thisY; - } - - cookie = xcb_render_util_composite_text_checked (dst->dpy, - _render_operator (op), - src->src_picture, - dst->dst_picture, - font_private->xrender_format->id, - src_x_offset + _cairo_lround (glyphs[0].x), - src_y_offset + _cairo_lround (glyphs[0].y), - stream); - - xcb_render_util_composite_text_free (stream); - - return _cairo_xcb_add_cookie_to_be_checked (dst, cookie); -} - -static cairo_status_t -_cairo_xcb_surface_show_glyphs_16 (cairo_xcb_surface_t *dst, - cairo_operator_t op, - cairo_xcb_surface_t *src, - int src_x_offset, int src_y_offset, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font) -{ - cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private; - xcb_render_util_composite_text_stream_t *stream; - xcb_void_cookie_t cookie; - int i; - int thisX, thisY; - int lastX = 0, lastY = 0; - uint16_t glyph; - - stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0); - - for (i = 0; i < num_glyphs; ++i) { - thisX = _cairo_lround (glyphs[i].x); - thisY = _cairo_lround (glyphs[i].y); - glyph = glyphs[i].index; - xcb_render_util_glyphs_16 (stream, thisX - lastX, thisY - lastY, 1, &glyph); - lastX = thisX; - lastY = thisY; - } - - cookie = xcb_render_util_composite_text_checked (dst->dpy, - _render_operator (op), - src->src_picture, - dst->dst_picture, - font_private->xrender_format->id, - src_x_offset + _cairo_lround (glyphs[0].x), - src_y_offset + _cairo_lround (glyphs[0].y), - stream); - - xcb_render_util_composite_text_free (stream); - - return _cairo_xcb_add_cookie_to_be_checked (dst, cookie); -} - -static cairo_status_t -_cairo_xcb_surface_show_glyphs_32 (cairo_xcb_surface_t *dst, - cairo_operator_t op, - cairo_xcb_surface_t *src, - int src_x_offset, int src_y_offset, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font) -{ - cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private; - xcb_render_util_composite_text_stream_t *stream; - xcb_void_cookie_t cookie; - int i; - int thisX, thisY; - int lastX = 0, lastY = 0; - uint32_t glyph; - - stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0); - - for (i = 0; i < num_glyphs; ++i) { - thisX = _cairo_lround (glyphs[i].x); - thisY = _cairo_lround (glyphs[i].y); - glyph = glyphs[i].index; - xcb_render_util_glyphs_32 (stream, thisX - lastX, thisY - lastY, 1, &glyph); - lastX = thisX; - lastY = thisY; - } - - cookie = xcb_render_util_composite_text_checked (dst->dpy, - _render_operator (op), - src->src_picture, - dst->dst_picture, - font_private->xrender_format->id, - src_x_offset + _cairo_lround (glyphs[0].x), - src_y_offset + _cairo_lround (glyphs[0].y), - stream); - - xcb_render_util_composite_text_free (stream); - - return _cairo_xcb_add_cookie_to_be_checked (dst, cookie); -} - -typedef cairo_status_t (*cairo_xcb_surface_show_glyphs_func_t) - (cairo_xcb_surface_t *, cairo_operator_t, cairo_xcb_surface_t *, int, int, - const cairo_glyph_t *, int, cairo_scaled_font_t *); - -static cairo_bool_t -_cairo_xcb_surface_owns_font (cairo_xcb_surface_t *dst, - cairo_scaled_font_t *scaled_font) -{ - cairo_xcb_surface_font_private_t *font_private; - - font_private = scaled_font->surface_private; - if ((scaled_font->surface_backend != NULL && - scaled_font->surface_backend != &cairo_xcb_surface_backend) || - (font_private != NULL && font_private->dpy != dst->dpy)) - { - return FALSE; - } - - return TRUE; -} - -static cairo_status_t -_cairo_xcb_surface_emit_glyphs (cairo_xcb_surface_t *dst, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - cairo_operator_t op, - cairo_xcb_surface_t *src, - cairo_surface_attributes_t *attributes, - int *remaining_glyphs) -{ - cairo_scaled_glyph_t *scaled_glyph; - int i, o; - unsigned long max_index = 0; - cairo_status_t status; - cairo_glyph_t *output_glyphs; - const cairo_glyph_t *glyphs_chunk; - int glyphs_remaining, chunk_size, max_chunk_size; - cairo_xcb_surface_show_glyphs_func_t show_glyphs_func; - - /* We make a copy of the glyphs so that we can elide any size-zero - * glyphs to workaround an X server bug, (present in at least Xorg - * 7.1 without EXA). */ - output_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); - if (output_glyphs == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - for (i = 0, o = 0; i < num_glyphs; i++) { - if (glyphs[i].index > max_index) - max_index = glyphs[i].index; - status = _cairo_scaled_glyph_lookup (scaled_font, - glyphs[i].index, - CAIRO_SCALED_GLYPH_INFO_SURFACE, - &scaled_glyph); - if (status) { - free (output_glyphs); - return status; - } - - /* Don't put any size-zero glyphs into output_glyphs to avoid - * an X server bug which stops rendering glyphs after the - * first size-zero glyph. */ - if (scaled_glyph->surface->width && scaled_glyph->surface->height) { - output_glyphs[o++] = glyphs[i]; - if (scaled_glyph->surface_private == NULL) { - _cairo_xcb_surface_add_glyph (dst, scaled_font, scaled_glyph); - scaled_glyph->surface_private = (void *) 1; - } - } - } - num_glyphs = o; - - status = _cairo_xcb_surface_ensure_dst_picture (dst); - if (status) { - free (output_glyphs); - return status; - } - - max_chunk_size = xcb_get_maximum_request_length (dst->dpy); - if (max_index < 256) { - /* XXX: these are all the same size! (28) */ - max_chunk_size -= sizeof(xcb_render_composite_glyphs_8_request_t); - show_glyphs_func = _cairo_xcb_surface_show_glyphs_8; - } else if (max_index < 65536) { - max_chunk_size -= sizeof(xcb_render_composite_glyphs_16_request_t); - show_glyphs_func = _cairo_xcb_surface_show_glyphs_16; - } else { - max_chunk_size -= sizeof(xcb_render_composite_glyphs_32_request_t); - show_glyphs_func = _cairo_xcb_surface_show_glyphs_32; - } - /* XXX: I think this is wrong; this is only the header size (2 longs) */ - /* but should also include the glyph (1 long) */ - /* max_chunk_size /= sz_xGlyphElt; */ - max_chunk_size /= 3*sizeof(uint32_t); - - for (glyphs_remaining = num_glyphs, glyphs_chunk = output_glyphs; - glyphs_remaining; - glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size) - { - chunk_size = MIN (glyphs_remaining, max_chunk_size); - - status = show_glyphs_func (dst, op, src, - attributes->x_offset, attributes->y_offset, - glyphs_chunk, chunk_size, scaled_font); - if (status) { - free (output_glyphs); - return status; - } - } - - /* We wouldn't want to leak memory, would we? */ - free(output_glyphs); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_int_status_t -_cairo_xcb_surface_show_glyphs (void *abstract_dst, - cairo_operator_t op, - const cairo_pattern_t *src_pattern, - cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - cairo_clip_t *clip, - int *remaining_glyphs) -{ - cairo_int_status_t status = CAIRO_STATUS_SUCCESS; - cairo_xcb_surface_t *dst = abstract_dst; - - composite_operation_t operation; - cairo_surface_attributes_t attributes; - cairo_xcb_surface_t *src = NULL; - - cairo_solid_pattern_t solid_pattern; - cairo_region_t *clip_region = NULL; - - if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* Just let unbounded operators go through the fallback code - * instead of trying to do the fixups here */ - if (!_cairo_operator_bounded_by_mask (op)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs -- - * the solid source seems to be multiplied by the glyph mask, and - * then the entire thing is copied to the destination surface, - * including the fully transparent "background" of the rectangular - * glyph surface. */ - if (op == CAIRO_OPERATOR_SOURCE && - !CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* We can only use our code if we either have no clip or - * have a real native clip region set. If we're using - * fallback clip masking, we have to go through the full - * fallback path. - */ - if (clip != NULL) { - status = _cairo_clip_get_region (clip, &clip_region); - assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO); - if (status) - return status; - } - - operation = _categorize_composite_operation (dst, op, src_pattern, TRUE); - if (operation == DO_UNSUPPORTED) - return CAIRO_INT_STATUS_UNSUPPORTED; - - if (! _cairo_xcb_surface_owns_font (dst, scaled_font)) - return CAIRO_INT_STATUS_UNSUPPORTED; - - /* After passing all those tests, we're now committed to rendering - * these glyphs or to fail trying. We first upload any glyphs to - * the X server that it doesn't have already, then we draw - * them. We tie into the scaled_font's glyph cache and remove - * glyphs from the X server when they are ejected from the - * scaled_font cache. - */ - - /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore - * the mask (the glyphs). This code below was executed as a side effect - * of going through the _clip_and_composite fallback code for old_show_glyphs, - * so PictOpClear was never used with CompositeText before. - */ - if (op == CAIRO_OPERATOR_CLEAR) { - _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - src_pattern = &solid_pattern.base; - op = CAIRO_OPERATOR_DEST_OUT; - } - - if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) { - status = _cairo_pattern_acquire_surface (src_pattern, &dst->base, - 0, 0, 1, 1, - CAIRO_PATTERN_ACQUIRE_NONE, - (cairo_surface_t **) &src, - &attributes); - } else { - cairo_rectangle_int_t glyph_extents; - - status = _cairo_scaled_font_glyph_device_extents (scaled_font, - glyphs, - num_glyphs, - &glyph_extents, - NULL); - if (status) - goto BAIL; - - status = _cairo_pattern_acquire_surface (src_pattern, &dst->base, - glyph_extents.x, glyph_extents.y, - glyph_extents.width, glyph_extents.height, - CAIRO_PATTERN_ACQUIRE_NO_REFLECT, - (cairo_surface_t **) &src, - &attributes); - } - - if (status) - goto BAIL; - - operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE); - if (operation == DO_UNSUPPORTED) { - status = CAIRO_INT_STATUS_UNSUPPORTED; - goto BAIL; - } - - status = _cairo_xcb_surface_set_clip_region (dst, clip_region); - if (unlikely (status)) - goto BAIL; - - status = _cairo_xcb_surface_set_attributes (src, &attributes); - if (status) - goto BAIL; - - /* Send all unsent glyphs to the server, and count the max of the glyph indices */ - _cairo_scaled_font_freeze_cache (scaled_font); - - if (_cairo_xcb_surface_owns_font (dst, scaled_font)) { - status = _cairo_xcb_surface_emit_glyphs (dst, - glyphs, num_glyphs, - scaled_font, - op, - src, - &attributes, - remaining_glyphs); - } else { - status = CAIRO_INT_STATUS_UNSUPPORTED; - } - _cairo_scaled_font_thaw_cache (scaled_font); - - BAIL: - if (src) - _cairo_pattern_release_surface (src_pattern, &src->base, &attributes); - if (src_pattern == &solid_pattern.base) - _cairo_pattern_fini (&solid_pattern.base); - - return status; -} +#if CAIRO_HAS_XLIB_XCB_FUNCTIONS +slim_hidden_def (cairo_xcb_surface_set_size); +#endif diff --git a/gfx/cairo/cairo/src/cairo-xcb.h b/gfx/cairo/cairo/src/cairo-xcb.h index 1b6d2e69fed2..3f64dcbdc5c9 100644 --- a/gfx/cairo/cairo/src/cairo-xcb.h +++ b/gfx/cairo/cairo/src/cairo-xcb.h @@ -1,6 +1,7 @@ /* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California + * Copyright © 2009 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -12,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -32,6 +33,7 @@ * * Contributor(s): * Carl D. Worth + * Chris Wilson */ #ifndef CAIRO_XCB_H @@ -42,28 +44,49 @@ #if CAIRO_HAS_XCB_SURFACE #include +#include CAIRO_BEGIN_DECLS cairo_public cairo_surface_t * -cairo_xcb_surface_create (xcb_connection_t *c, +cairo_xcb_surface_create (xcb_connection_t *connection, xcb_drawable_t drawable, - xcb_visualtype_t *visual, - int width, - int height); + xcb_visualtype_t *visual, + int width, + int height); cairo_public cairo_surface_t * -cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c, - xcb_pixmap_t bitmap, - xcb_screen_t *screen, - int width, - int height); +cairo_xcb_surface_create_for_bitmap (xcb_connection_t *connection, + xcb_screen_t *screen, + xcb_pixmap_t bitmap, + int width, + int height); + +cairo_public cairo_surface_t * +cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *connection, + xcb_screen_t *screen, + xcb_drawable_t drawable, + xcb_render_pictforminfo_t *format, + int width, + int height); cairo_public void cairo_xcb_surface_set_size (cairo_surface_t *surface, int width, int height); +/* debug interface */ + +cairo_public void +cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device, + int major_version, + int minor_version); + +cairo_public void +cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device, + int major_version, + int minor_version); + CAIRO_END_DECLS #else /* CAIRO_HAS_XCB_SURFACE */ diff --git a/gfx/cairo/cairo/src/cairo-xlib-display.c b/gfx/cairo/cairo/src/cairo-xlib-display.c index e98560dbaa20..139e63149614 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-display.c +++ b/gfx/cairo/cairo/src/cairo-xlib-display.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,33 +37,11 @@ #include "cairo-xlib-private.h" #include "cairo-xlib-xrender-private.h" - #include "cairo-freelist-private.h" +#include "cairo-error-private.h" #include /* For XESetCloseDisplay */ -struct _cairo_xlib_display { - cairo_xlib_display_t *next; - cairo_reference_count_t ref_count; - cairo_mutex_t mutex; - - Display *display; - cairo_xlib_screen_t *screens; - - int render_major; - int render_minor; - XRenderPictFormat *cached_xrender_formats[CAIRO_FORMAT_RGB16_565 + 1]; - - cairo_xlib_job_t *workqueue; - cairo_freelist_t wq_freelist; - - cairo_xlib_hook_t *close_display_hooks; - unsigned int buggy_gradients :1; - unsigned int buggy_pad_reflect :1; - unsigned int buggy_repeat :1; - unsigned int closed :1; -}; - typedef int (*cairo_xlib_error_func_t) (Display *display, XErrorEvent *event); @@ -95,14 +73,11 @@ _cairo_xlib_remove_close_display_hook_internal (cairo_xlib_display_t *display, static void _cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display) { - cairo_xlib_screen_t *screen; - cairo_xlib_hook_t *hook; + cairo_xlib_screen_t *screen; + cairo_xlib_hook_t *hook; - /* call all registered shutdown routines */ - CAIRO_MUTEX_LOCK (display->mutex); - - for (screen = display->screens; screen != NULL; screen = screen->next) - _cairo_xlib_screen_close_display (screen); + cairo_list_foreach_entry (screen, cairo_xlib_screen_t, &display->screens, link) + _cairo_xlib_screen_close_display (display, screen); while (TRUE) { hook = display->close_display_hooks; @@ -111,50 +86,23 @@ _cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display) _cairo_xlib_remove_close_display_hook_internal (display, hook); - CAIRO_MUTEX_UNLOCK (display->mutex); hook->func (display, hook); - CAIRO_MUTEX_LOCK (display->mutex); } display->closed = TRUE; - - CAIRO_MUTEX_UNLOCK (display->mutex); } static void -_cairo_xlib_display_discard_screens (cairo_xlib_display_t *display) +_cairo_xlib_display_finish (void *abstract_display) { - cairo_xlib_screen_t *screens; + cairo_xlib_display_t *display = abstract_display; - CAIRO_MUTEX_LOCK (display->mutex); - screens = display->screens; - display->screens = NULL; - CAIRO_MUTEX_UNLOCK (display->mutex); - - while (screens != NULL) { - cairo_xlib_screen_t *screen = screens; - screens = screen->next; - - _cairo_xlib_screen_destroy (screen); - } + display->display = NULL; } -cairo_xlib_display_t * -_cairo_xlib_display_reference (cairo_xlib_display_t *display) +static void +_cairo_xlib_display_destroy (void *abstract_display) { - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&display->ref_count)); - - _cairo_reference_count_inc (&display->ref_count); - - return display; -} - -void -_cairo_xlib_display_destroy (cairo_xlib_display_t *display) -{ - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&display->ref_count)); - - if (! _cairo_reference_count_dec_and_test (&display->ref_count)) - return; + cairo_xlib_display_t *display = abstract_display; /* destroy all outstanding notifies */ while (display->workqueue != NULL) { @@ -168,7 +116,11 @@ _cairo_xlib_display_destroy (cairo_xlib_display_t *display) } _cairo_freelist_fini (&display->wq_freelist); - CAIRO_MUTEX_FINI (display->mutex); + while (! cairo_list_is_empty (&display->screens)) { + _cairo_xlib_screen_destroy (cairo_list_first_entry (&display->screens, + cairo_xlib_screen_t, + link)); + } free (display); } @@ -179,6 +131,60 @@ _noop_error_handler (Display *display, { return False; /* return value is ignored */ } + +static void +_cairo_xlib_display_notify (cairo_xlib_display_t *display) +{ + cairo_xlib_job_t *jobs, *job, *freelist; + Display *dpy = display->display; + + /* Optimistic atomic pointer read -- don't care if it is wrong due to + * contention as we will check again very shortly. + */ + if (display->workqueue == NULL) + return; + + jobs = display->workqueue; + while (jobs != NULL) { + display->workqueue = NULL; + + /* reverse the list to obtain FIFO order */ + job = NULL; + do { + cairo_xlib_job_t *next = jobs->next; + jobs->next = job; + job = jobs; + jobs = next; + } while (jobs != NULL); + freelist = jobs = job; + + do { + job = jobs; + jobs = job->next; + + switch (job->type){ + case WORK: + job->func.work.notify (dpy, job->func.work.data); + if (job->func.work.destroy != NULL) + job->func.work.destroy (job->func.work.data); + break; + + case RESOURCE: + job->func.resource.notify (dpy, job->func.resource.xid); + break; + } + } while (jobs != NULL); + + do { + job = freelist; + freelist = job->next; + _cairo_freelist_free (&display->wq_freelist, job); + } while (freelist != NULL); + + jobs = display->workqueue; + } +} + static int _cairo_xlib_close_display (Display *dpy, XExtCodes *codes) { @@ -193,19 +199,22 @@ _cairo_xlib_close_display (Display *dpy, XExtCodes *codes) if (display == NULL) return 0; - /* protect the notifies from triggering XErrors */ - XSync (dpy, False); - old_handler = XSetErrorHandler (_noop_error_handler); + if (! cairo_device_acquire (&display->base)) { + /* protect the notifies from triggering XErrors */ + XSync (dpy, False); + old_handler = XSetErrorHandler (_noop_error_handler); - _cairo_xlib_display_notify (display); - _cairo_xlib_call_close_display_hooks (display); - _cairo_xlib_display_discard_screens (display); + _cairo_xlib_display_notify (display); + _cairo_xlib_call_close_display_hooks (display); - /* catch any that arrived before marking the display as closed */ - _cairo_xlib_display_notify (display); + /* catch any that arrived before marking the display as closed */ + _cairo_xlib_display_notify (display); - XSync (dpy, False); - XSetErrorHandler (old_handler); + XSync (dpy, False); + XSetErrorHandler (old_handler); + + cairo_device_release (&display->base); + } /* * Unhook from the global list @@ -223,25 +232,47 @@ _cairo_xlib_close_display (Display *dpy, XExtCodes *codes) CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); assert (display != NULL); - _cairo_xlib_display_destroy (display); + + cairo_device_finish (&display->base); + cairo_device_destroy (&display->base); /* Return value in accordance with requirements of * XESetCloseDisplay */ return 0; } -cairo_status_t -_cairo_xlib_display_get (Display *dpy, - cairo_xlib_display_t **out) +static const cairo_device_backend_t _cairo_xlib_device_backend = { + CAIRO_DEVICE_TYPE_XLIB, + + NULL, + NULL, + + NULL, /* flush */ + _cairo_xlib_display_finish, + _cairo_xlib_display_destroy, +}; + +/** + * cairo_xlib_device_create: + * @dpy: the display to create the device for + * + * Gets the device belonging to @dpy, or creates it if it doesn't exist yet. + * + * Returns: the device belonging to @dpy + **/ +cairo_device_t * +_cairo_xlib_device_create (Display *dpy) { cairo_xlib_display_t *display; cairo_xlib_display_t **prev; + cairo_device_t *device; XExtCodes *codes; const char *env; - cairo_status_t status = CAIRO_STATUS_SUCCESS; static int buggy_repeat_force = -1; + CAIRO_MUTEX_INITIALIZE (); + /* There is an apparent deadlock between this mutex and the * mutex for the display, but it's actually safe. For the * app to call XCloseDisplay() while any other thread is @@ -262,18 +293,14 @@ _cairo_xlib_display_get (Display *dpy, display->next = _cairo_xlib_display_list; _cairo_xlib_display_list = display; } - break; + device = cairo_device_reference (&display->base); + goto UNLOCK; } } - if (display != NULL) { - display = _cairo_xlib_display_reference (display); - goto UNLOCK; - } - display = malloc (sizeof (cairo_xlib_display_t)); if (unlikely (display == NULL)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY); goto UNLOCK; } @@ -304,20 +331,20 @@ _cairo_xlib_display_get (Display *dpy, codes = XAddExtension (dpy); if (unlikely (codes == NULL)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY); free (display); - display = NULL; goto UNLOCK; } + _cairo_device_init (&display->base, &_cairo_xlib_device_backend); + XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display); _cairo_freelist_init (&display->wq_freelist, sizeof (cairo_xlib_job_t)); - CAIRO_REFERENCE_COUNT_INIT (&display->ref_count, 2); /* add one for the CloseDisplay */ - CAIRO_MUTEX_INIT (display->mutex); + cairo_device_reference (&display->base); /* add one for the CloseDisplay */ display->display = dpy; - display->screens = NULL; + cairo_list_init (&display->screens); display->workqueue = NULL; display->close_display_hooks = NULL; display->closed = FALSE; @@ -434,26 +461,24 @@ _cairo_xlib_display_get (Display *dpy, display->next = _cairo_xlib_display_list; _cairo_xlib_display_list = display; + device = &display->base; + UNLOCK: CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); - *out = display; - return status; + return device; } void _cairo_xlib_add_close_display_hook (cairo_xlib_display_t *display, cairo_xlib_hook_t *hook) { - CAIRO_MUTEX_LOCK (display->mutex); hook->prev = NULL; hook->next = display->close_display_hooks; if (hook->next != NULL) hook->next->prev = hook; display->close_display_hooks = hook; - CAIRO_MUTEX_UNLOCK (display->mutex); } -/* display->mutex must be held */ static void _cairo_xlib_remove_close_display_hook_internal (cairo_xlib_display_t *display, cairo_xlib_hook_t *hook) @@ -474,9 +499,7 @@ void _cairo_xlib_remove_close_display_hook (cairo_xlib_display_t *display, cairo_xlib_hook_t *hook) { - CAIRO_MUTEX_LOCK (display->mutex); _cairo_xlib_remove_close_display_hook_internal (display, hook); - CAIRO_MUTEX_UNLOCK (display->mutex); } cairo_status_t @@ -487,7 +510,6 @@ _cairo_xlib_display_queue_resource (cairo_xlib_display_t *display, cairo_xlib_job_t *job; cairo_status_t status = CAIRO_STATUS_NO_MEMORY; - CAIRO_MUTEX_LOCK (display->mutex); if (display->closed == FALSE) { job = _cairo_freelist_alloc (&display->wq_freelist); if (job != NULL) { @@ -501,7 +523,6 @@ _cairo_xlib_display_queue_resource (cairo_xlib_display_t *display, status = CAIRO_STATUS_SUCCESS; } } - CAIRO_MUTEX_UNLOCK (display->mutex); return status; } @@ -515,7 +536,6 @@ _cairo_xlib_display_queue_work (cairo_xlib_display_t *display, cairo_xlib_job_t *job; cairo_status_t status = CAIRO_STATUS_NO_MEMORY; - CAIRO_MUTEX_LOCK (display->mutex); if (display->closed == FALSE) { job = _cairo_freelist_alloc (&display->wq_freelist); if (job != NULL) { @@ -530,66 +550,22 @@ _cairo_xlib_display_queue_work (cairo_xlib_display_t *display, status = CAIRO_STATUS_SUCCESS; } } - CAIRO_MUTEX_UNLOCK (display->mutex); return status; } -void -_cairo_xlib_display_notify (cairo_xlib_display_t *display) +cairo_status_t +_cairo_xlib_display_acquire (cairo_device_t *device, cairo_xlib_display_t **display) { - cairo_xlib_job_t *jobs, *job, *freelist; - Display *dpy = display->display; + cairo_status_t status; - /* Optimistic atomic pointer read -- don't care if it is wrong due to - * contention as we will check again very shortly. - */ - if (display->workqueue == NULL) - return; + status = cairo_device_acquire (device); + if (status) + return status; - CAIRO_MUTEX_LOCK (display->mutex); - jobs = display->workqueue; - while (jobs != NULL) { - display->workqueue = NULL; - CAIRO_MUTEX_UNLOCK (display->mutex); - - /* reverse the list to obtain FIFO order */ - job = NULL; - do { - cairo_xlib_job_t *next = jobs->next; - jobs->next = job; - job = jobs; - jobs = next; - } while (jobs != NULL); - freelist = jobs = job; - - do { - job = jobs; - jobs = job->next; - - switch (job->type){ - case WORK: - job->func.work.notify (dpy, job->func.work.data); - if (job->func.work.destroy != NULL) - job->func.work.destroy (job->func.work.data); - break; - - case RESOURCE: - job->func.resource.notify (dpy, job->func.resource.xid); - break; - } - } while (jobs != NULL); - - CAIRO_MUTEX_LOCK (display->mutex); - do { - job = freelist; - freelist = job->next; - _cairo_freelist_free (&display->wq_freelist, job); - } while (freelist != NULL); - - jobs = display->workqueue; - } - CAIRO_MUTEX_UNLOCK (display->mutex); + *display = (cairo_xlib_display_t *) device; + _cairo_xlib_display_notify (*display); + return status; } XRenderPictFormat * @@ -604,7 +580,6 @@ _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display, return xrender_format; #endif - CAIRO_MUTEX_LOCK (display->mutex); xrender_format = display->cached_xrender_formats[format]; if (xrender_format == NULL) { int pict_format; @@ -630,13 +605,12 @@ _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display, break; } } - if (!visual) { - CAIRO_MUTEX_UNLOCK (display->mutex); + if (!visual) return NULL; - } xrender_format = XRenderFindVisualFormat(display->display, visual); break; } + case CAIRO_FORMAT_INVALID: default: ASSERT_NOT_REACHED; case CAIRO_FORMAT_ARGB32: @@ -647,75 +621,25 @@ _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display, pict_format); display->cached_xrender_formats[format] = xrender_format; } - CAIRO_MUTEX_UNLOCK (display->mutex); return xrender_format; } -Display * -_cairo_xlib_display_get_dpy (cairo_xlib_display_t *display) -{ - return display->display; -} - -void -_cairo_xlib_display_remove_screen (cairo_xlib_display_t *display, - cairo_xlib_screen_t *screen) -{ - cairo_xlib_screen_t **prev; - cairo_xlib_screen_t *list; - - CAIRO_MUTEX_LOCK (display->mutex); - for (prev = &display->screens; (list = *prev); prev = &list->next) { - if (list == screen) { - *prev = screen->next; - break; - } - } - CAIRO_MUTEX_UNLOCK (display->mutex); -} - -cairo_status_t +cairo_xlib_screen_t * _cairo_xlib_display_get_screen (cairo_xlib_display_t *display, - Screen *screen, - cairo_xlib_screen_t **out) + Screen *screen) { - cairo_xlib_screen_t *info = NULL, **prev; + cairo_xlib_screen_t *info; - CAIRO_MUTEX_LOCK (display->mutex); - if (display->closed) { - CAIRO_MUTEX_UNLOCK (display->mutex); - return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); - } - - for (prev = &display->screens; (info = *prev); prev = &(*prev)->next) { + cairo_list_foreach_entry (info, cairo_xlib_screen_t, &display->screens, link) { if (info->screen == screen) { - /* - * MRU the list - */ - if (prev != &display->screens) { - *prev = info->next; - info->next = display->screens; - display->screens = info; - } - break; - } + if (display->screens.next != &info->link) + cairo_list_move (&info->link, &display->screens); + return info; + } } - CAIRO_MUTEX_UNLOCK (display->mutex); - *out = info; - return CAIRO_STATUS_SUCCESS; -} - - -void -_cairo_xlib_display_add_screen (cairo_xlib_display_t *display, - cairo_xlib_screen_t *screen) -{ - CAIRO_MUTEX_LOCK (display->mutex); - screen->next = display->screens; - display->screens = screen; - CAIRO_MUTEX_UNLOCK (display->mutex); + return NULL; } void @@ -727,19 +651,19 @@ _cairo_xlib_display_get_xrender_version (cairo_xlib_display_t *display, } cairo_bool_t -_cairo_xlib_display_has_repeat (cairo_xlib_display_t *display) +_cairo_xlib_display_has_repeat (cairo_device_t *device) { - return ! display->buggy_repeat; + return ! ((cairo_xlib_display_t *) device)->buggy_repeat; } cairo_bool_t -_cairo_xlib_display_has_reflect (cairo_xlib_display_t *display) +_cairo_xlib_display_has_reflect (cairo_device_t *device) { - return ! display->buggy_pad_reflect; + return ! ((cairo_xlib_display_t *) device)->buggy_pad_reflect; } cairo_bool_t -_cairo_xlib_display_has_gradients (cairo_xlib_display_t *display) +_cairo_xlib_display_has_gradients (cairo_device_t *device) { - return ! display->buggy_gradients; + return ! ((cairo_xlib_display_t *) device)->buggy_gradients; } diff --git a/gfx/cairo/cairo/src/cairo-xlib-private.h b/gfx/cairo/cairo/src/cairo-xlib-private.h index afdf6a6bddb4..bd260bc0ed4b 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-private.h +++ b/gfx/cairo/cairo/src/cairo-xlib-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -41,7 +41,9 @@ #include "cairo-xlib-xrender-private.h" #include "cairo-compiler-private.h" -#include "cairo-mutex-private.h" +#include "cairo-device-private.h" +#include "cairo-freelist-type-private.h" +#include "cairo-list-private.h" #include "cairo-reference-count-private.h" #include "cairo-types-private.h" @@ -63,7 +65,30 @@ struct _cairo_xlib_hook { /* size of gray ramp */ #define RAMP_SIZE 16 +struct _cairo_xlib_display { + cairo_device_t base; + + cairo_xlib_display_t *next; + + Display *display; + cairo_list_t screens; + + int render_major; + int render_minor; + XRenderPictFormat *cached_xrender_formats[CAIRO_FORMAT_RGB16_565 + 1]; + + cairo_xlib_job_t *workqueue; + cairo_freelist_t wq_freelist; + + cairo_xlib_hook_t *close_display_hooks; + unsigned int buggy_gradients :1; + unsigned int buggy_pad_reflect :1; + unsigned int buggy_repeat :1; + unsigned int closed :1; +}; + typedef struct _cairo_xlib_visual_info { + cairo_list_t link; VisualID visualid; struct { uint8_t a, r, g, b; } colors[256]; uint8_t cube_to_pseudocolor[CUBE_SIZE][CUBE_SIZE][CUBE_SIZE]; @@ -73,13 +98,10 @@ typedef struct _cairo_xlib_visual_info { } cairo_xlib_visual_info_t; struct _cairo_xlib_screen { - cairo_xlib_screen_t *next; - cairo_reference_count_t ref_count; - cairo_mutex_t mutex; + cairo_list_t link; - cairo_xlib_display_t *display; + cairo_device_t *device; Screen *screen; - cairo_bool_t has_render; cairo_bool_t has_font_options; cairo_font_options_t font_options; @@ -87,39 +109,15 @@ struct _cairo_xlib_screen { GC gc[4]; cairo_atomic_int_t gc_depths; /* 4 x uint8_t */ - cairo_array_t visuals; + cairo_list_t visuals; }; -cairo_private cairo_status_t -_cairo_xlib_display_get (Display *display, cairo_xlib_display_t **out); +cairo_private cairo_device_t * +_cairo_xlib_device_create (Display *display); -cairo_private cairo_xlib_display_t * -_cairo_xlib_display_reference (cairo_xlib_display_t *info); - -cairo_private void -_cairo_xlib_display_destroy (cairo_xlib_display_t *info); - -cairo_private void -_cairo_xlib_display_lock (cairo_xlib_display_t *display); - -cairo_private void -_cairo_xlib_display_unlock (cairo_xlib_display_t *display); - -cairo_private Display * -_cairo_xlib_display_get_dpy (cairo_xlib_display_t *info); - -cairo_private void -_cairo_xlib_display_add_screen (cairo_xlib_display_t *display, - cairo_xlib_screen_t *screen); - -cairo_private cairo_status_t +cairo_private cairo_xlib_screen_t * _cairo_xlib_display_get_screen (cairo_xlib_display_t *display, - Screen *screen, - cairo_xlib_screen_t **out); - -cairo_private void -_cairo_xlib_display_remove_screen (cairo_xlib_display_t *display, - cairo_xlib_screen_t *screen); + Screen *screen); cairo_private void _cairo_xlib_add_close_display_hook (cairo_xlib_display_t *display, cairo_xlib_hook_t *hook); @@ -136,21 +134,22 @@ cairo_private cairo_status_t _cairo_xlib_display_queue_resource (cairo_xlib_display_t *display, cairo_xlib_notify_resource_func notify, XID resource); -cairo_private void -_cairo_xlib_display_notify (cairo_xlib_display_t *display); +cairo_private cairo_status_t +_cairo_xlib_display_acquire (cairo_device_t *device, + cairo_xlib_display_t **display); cairo_private void _cairo_xlib_display_get_xrender_version (cairo_xlib_display_t *display, int *major, int *minor); cairo_private cairo_bool_t -_cairo_xlib_display_has_repeat (cairo_xlib_display_t *display); +_cairo_xlib_display_has_repeat (cairo_device_t *device); cairo_private cairo_bool_t -_cairo_xlib_display_has_reflect (cairo_xlib_display_t *display); +_cairo_xlib_display_has_reflect (cairo_device_t *device); cairo_private cairo_bool_t -_cairo_xlib_display_has_gradients (cairo_xlib_display_t *display); +_cairo_xlib_display_has_gradients (cairo_device_t *device); cairo_private XRenderPictFormat * _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display, @@ -161,21 +160,22 @@ _cairo_xlib_screen_get (Display *dpy, Screen *screen, cairo_xlib_screen_t **out); -cairo_private cairo_xlib_screen_t * -_cairo_xlib_screen_reference (cairo_xlib_screen_t *info); cairo_private void _cairo_xlib_screen_destroy (cairo_xlib_screen_t *info); cairo_private void -_cairo_xlib_screen_close_display (cairo_xlib_screen_t *info); +_cairo_xlib_screen_close_display (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info); cairo_private GC -_cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, +_cairo_xlib_screen_get_gc (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, int depth, Drawable drawable); cairo_private void -_cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info, +_cairo_xlib_screen_put_gc (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, int depth, GC gc); @@ -183,7 +183,8 @@ cairo_private cairo_font_options_t * _cairo_xlib_screen_get_font_options (cairo_xlib_screen_t *info); cairo_private cairo_status_t -_cairo_xlib_screen_get_visual_info (cairo_xlib_screen_t *info, +_cairo_xlib_screen_get_visual_info (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, Visual *visual, cairo_xlib_visual_info_t **out); @@ -194,6 +195,6 @@ _cairo_xlib_visual_info_create (Display *dpy, cairo_xlib_visual_info_t **out); cairo_private void -_cairo_xlib_visual_info_destroy (Display *dpy, cairo_xlib_visual_info_t *info); +_cairo_xlib_visual_info_destroy (cairo_xlib_visual_info_t *info); #endif /* CAIRO_XLIB_PRIVATE_H */ diff --git a/gfx/cairo/cairo/src/cairo-xlib-screen.c b/gfx/cairo/cairo/src/cairo-xlib-screen.c index 09a2a81077d6..a0c3df84092c 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-screen.c +++ b/gfx/cairo/cairo/src/cairo-xlib-screen.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -58,8 +58,9 @@ #include "cairo-xlib-xrender-private.h" #include "cairo-xlib-surface-private.h" +#include "cairo-error-private.h" -#include +#include "cairo-fontconfig-private.h" static int parse_boolean (const char *v) @@ -125,23 +126,6 @@ get_integer_default (Display *dpy, return FALSE; } -#ifndef FC_RGBA_UNKNOWN -#define FC_RGBA_UNKNOWN 0 -#define FC_RGBA_RGB 1 -#define FC_RGBA_BGR 2 -#define FC_RGBA_VRGB 3 -#define FC_RGBA_VBGR 4 -#define FC_RGBA_NONE 5 -#endif - -#ifndef FC_HINT_NONE -#define FC_HINT_NONE 0 -#define FC_HINT_SLIGHT 1 -#define FC_HINT_MEDIUM 2 -#define FC_HINT_FULL 3 -#endif - - static void _cairo_xlib_init_screen_font_options (Display *dpy, cairo_xlib_screen_t *info) @@ -150,13 +134,22 @@ _cairo_xlib_init_screen_font_options (Display *dpy, cairo_bool_t xft_antialias; int xft_hintstyle; int xft_rgba; + int xft_lcdfilter; cairo_antialias_t antialias; cairo_subpixel_order_t subpixel_order; + cairo_lcd_filter_t lcd_filter; cairo_hint_style_t hint_style; if (!get_boolean_default (dpy, "antialias", &xft_antialias)) xft_antialias = TRUE; + if (!get_integer_default (dpy, "lcdfilter", &xft_lcdfilter)) { + /* -1 is an non-existant Fontconfig constant used to differentiate + * the case when no lcdfilter property is available. + */ + xft_lcdfilter = -1; + } + if (!get_boolean_default (dpy, "hinting", &xft_hinting)) xft_hinting = TRUE; @@ -165,16 +158,16 @@ _cairo_xlib_init_screen_font_options (Display *dpy, if (!get_integer_default (dpy, "rgba", &xft_rgba)) { + cairo_xlib_display_t *display = (cairo_xlib_display_t *) info->device; + xft_rgba = FC_RGBA_UNKNOWN; #if RENDER_MAJOR > 0 || RENDER_MINOR >= 6 - if (info->has_render) - { + if (display->render_major > 0 || display->render_minor >= 6) { int render_order = XRenderQuerySubpixelOrder (dpy, XScreenNumberOfScreen (info->screen)); - switch (render_order) - { + switch (render_order) { default: case SubPixelUnknown: xft_rgba = FC_RGBA_UNKNOWN; @@ -239,6 +232,24 @@ _cairo_xlib_init_screen_font_options (Display *dpy, subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; } + switch (xft_lcdfilter) { + case FC_LCD_NONE: + lcd_filter = CAIRO_LCD_FILTER_NONE; + break; + case FC_LCD_DEFAULT: + lcd_filter = CAIRO_LCD_FILTER_FIR5; + break; + case FC_LCD_LIGHT: + lcd_filter = CAIRO_LCD_FILTER_FIR3; + break; + case FC_LCD_LEGACY: + lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL; + break; + default: + lcd_filter = CAIRO_LCD_FILTER_DEFAULT; + break; + } + if (xft_antialias) { if (subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT) antialias = CAIRO_ANTIALIAS_GRAY; @@ -251,70 +262,36 @@ _cairo_xlib_init_screen_font_options (Display *dpy, cairo_font_options_set_hint_style (&info->font_options, hint_style); cairo_font_options_set_antialias (&info->font_options, antialias); cairo_font_options_set_subpixel_order (&info->font_options, subpixel_order); + _cairo_font_options_set_lcd_filter (&info->font_options, lcd_filter); cairo_font_options_set_hint_metrics (&info->font_options, CAIRO_HINT_METRICS_ON); } -cairo_xlib_screen_t * -_cairo_xlib_screen_reference (cairo_xlib_screen_t *info) -{ - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info->ref_count)); - - _cairo_reference_count_inc (&info->ref_count); - - return info; -} - void -_cairo_xlib_screen_close_display (cairo_xlib_screen_t *info) +_cairo_xlib_screen_close_display (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info) { - cairo_xlib_visual_info_t **visuals; Display *dpy; - cairo_atomic_int_t old; int i; - CAIRO_MUTEX_LOCK (info->mutex); - - dpy = _cairo_xlib_display_get_dpy (info->display); - -#if HAS_ATOMIC_OPS - do { - old = _cairo_atomic_int_get (&info->gc_depths); - } while (_cairo_atomic_int_cmpxchg (&info->gc_depths, old, 0) != old); -#else - old = info->gc_depths; - info->gc_depths = 0; -#endif + dpy = display->display; for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { - if ((old >> (8*i)) & 0xff) + if ((info->gc_depths >> (8*i)) & 0xff) XFreeGC (dpy, info->gc[i]); } - - visuals = _cairo_array_index (&info->visuals, 0); - for (i = 0; i < _cairo_array_num_elements (&info->visuals); i++) - _cairo_xlib_visual_info_destroy (dpy, visuals[i]); - _cairo_array_truncate (&info->visuals, 0); - - CAIRO_MUTEX_UNLOCK (info->mutex); + info->gc_depths = 0; } void _cairo_xlib_screen_destroy (cairo_xlib_screen_t *info) { - assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info->ref_count)); + while (! cairo_list_is_empty (&info->visuals)) { + _cairo_xlib_visual_info_destroy (cairo_list_first_entry (&info->visuals, + cairo_xlib_visual_info_t, + link)); + } - if (! _cairo_reference_count_dec_and_test (&info->ref_count)) - return; - - _cairo_xlib_display_remove_screen (info->display, info); - - _cairo_xlib_screen_close_display (info); - - _cairo_xlib_display_destroy (info->display); - - _cairo_array_fini (&info->visuals); - - CAIRO_MUTEX_FINI (info->mutex); + cairo_list_del (&info->link); free (info); } @@ -325,17 +302,22 @@ _cairo_xlib_screen_get (Display *dpy, cairo_xlib_screen_t **out) { cairo_xlib_display_t *display; + cairo_device_t *device; cairo_xlib_screen_t *info; cairo_status_t status; - status = _cairo_xlib_display_get (dpy, &display); - if (likely (status == CAIRO_STATUS_SUCCESS)) - status = _cairo_xlib_display_get_screen (display, screen, &info); + device = _cairo_xlib_device_create (dpy); + status = device->status; if (unlikely (status)) - goto CLEANUP_DISPLAY; + goto CLEANUP_DEVICE; + status = _cairo_xlib_display_acquire (device, &display); + if (unlikely (status)) + goto CLEANUP_DEVICE; + + info = _cairo_xlib_display_get_screen (display, screen); if (info != NULL) { - *out = _cairo_xlib_screen_reference (info); + *out = info; goto CLEANUP_DISPLAY; } @@ -345,133 +327,34 @@ _cairo_xlib_screen_get (Display *dpy, goto CLEANUP_DISPLAY; } - CAIRO_REFERENCE_COUNT_INIT (&info->ref_count, 2); /* Add one for display cache */ - CAIRO_MUTEX_INIT (info->mutex); - info->display = display; + info->device = device; info->screen = screen; - info->has_render = FALSE; info->has_font_options = FALSE; info->gc_depths = 0; memset (info->gc, 0, sizeof (info->gc)); - _cairo_array_init (&info->visuals, - sizeof (cairo_xlib_visual_info_t*)); - - if (screen) { - int event_base, error_base; - - info->has_render = - XRenderQueryExtension (dpy, &event_base, &error_base) && - (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0); - } - - /* Small window of opportunity for two screen infos for the same - * Screen - just wastes a little bit of memory but should not cause - * any corruption. - */ - _cairo_xlib_display_add_screen (display, info); + cairo_list_init (&info->visuals); + cairo_list_add (&info->link, &display->screens); *out = info; - return CAIRO_STATUS_SUCCESS; CLEANUP_DISPLAY: - _cairo_xlib_display_destroy (display); + cairo_device_release (&display->base); + + CLEANUP_DEVICE: + cairo_device_destroy (device); return status; } -#if HAS_ATOMIC_OPS GC -_cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, - int depth, - Drawable drawable) -{ - XGCValues gcv; - cairo_atomic_int_t old, new; - int i; - GC gc; - - do { - gc = NULL; - old = info->gc_depths; - if (old == 0) - break; - - if (((old >> 0) & 0xff) == depth) - i = 0; - else if (((old >> 8) & 0xff) == depth) - i = 1; - else if (((old >> 16) & 0xff) == depth) - i = 2; - else if (((old >> 24) & 0xff) == depth) - i = 3; - else - break; - - gc = info->gc[i]; - new = old & ~(0xff << (8*i)); - } while (_cairo_atomic_int_cmpxchg (&info->gc_depths, old, new) != old); - - if (likely (gc != NULL)) { - (void) _cairo_atomic_ptr_cmpxchg (&info->gc[i], gc, NULL); - return gc; - } - - gcv.graphics_exposures = False; - gcv.fill_style = FillTiled; - return XCreateGC (_cairo_xlib_display_get_dpy (info->display), - drawable, - GCGraphicsExposures | GCFillStyle, &gcv); -} - -void -_cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info, - int depth, - GC gc) -{ - int i, old, new; - - do { - do { - i = -1; - old = info->gc_depths; - - if (((old >> 0) & 0xff) == 0) - i = 0; - else if (((old >> 8) & 0xff) == 0) - i = 1; - else if (((old >> 16) & 0xff) == 0) - i = 2; - else if (((old >> 24) & 0xff) == 0) - i = 3; - else - goto out; - - new = old | (depth << (8*i)); - } while (_cairo_atomic_ptr_cmpxchg (&info->gc[i], NULL, gc) != NULL); - } while (_cairo_atomic_int_cmpxchg (&info->gc_depths, old, new) != old); - - return; - -out: - if (unlikely (_cairo_xlib_display_queue_work (info->display, - (cairo_xlib_notify_func) XFreeGC, - gc, - NULL))) - { - /* leak the server side resource... */ - XFree ((char *) gc); - } -} -#else -GC -_cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, +_cairo_xlib_screen_get_gc (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, int depth, Drawable drawable) { GC gc = NULL; int i; - CAIRO_MUTEX_LOCK (info->mutex); for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { if (((info->gc_depths >> (8*i)) & 0xff) == depth) { info->gc_depths &= ~(0xff << (8*i)); @@ -479,14 +362,13 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, break; } } - CAIRO_MUTEX_UNLOCK (info->mutex); if (gc == NULL) { XGCValues gcv; gcv.graphics_exposures = False; gcv.fill_style = FillTiled; - gc = XCreateGC (_cairo_xlib_display_get_dpy (info->display), + gc = XCreateGC (display->display, drawable, GCGraphicsExposures | GCFillStyle, &gcv); } @@ -495,13 +377,13 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info, } void -_cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info, +_cairo_xlib_screen_put_gc (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, int depth, GC gc) { int i; - CAIRO_MUTEX_LOCK (info->mutex); for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { if (((info->gc_depths >> (8*i)) & 0xff) == 0) break; @@ -513,7 +395,7 @@ _cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info, /* perform random substitution to ensure fair caching over depths */ i = rand () % ARRAY_LENGTH (info->gc); status = - _cairo_xlib_display_queue_work (info->display, + _cairo_xlib_display_queue_work (display, (cairo_xlib_notify_func) XFreeGC, info->gc[i], NULL); @@ -526,88 +408,59 @@ _cairo_xlib_screen_put_gc (cairo_xlib_screen_t *info, info->gc[i] = gc; info->gc_depths &= ~(0xff << (8*i)); info->gc_depths |= depth << (8*i); - CAIRO_MUTEX_UNLOCK (info->mutex); } -#endif cairo_status_t -_cairo_xlib_screen_get_visual_info (cairo_xlib_screen_t *info, - Visual *visual, +_cairo_xlib_screen_get_visual_info (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, + Visual *v, cairo_xlib_visual_info_t **out) { - Display *dpy = _cairo_xlib_display_get_dpy (info->display); - cairo_xlib_visual_info_t **visuals, *ret = NULL; + cairo_xlib_visual_info_t *visual; cairo_status_t status; - int i, n_visuals; - CAIRO_MUTEX_LOCK (info->mutex); - visuals = _cairo_array_index (&info->visuals, 0); - n_visuals = _cairo_array_num_elements (&info->visuals); - for (i = 0; i < n_visuals; i++) { - if (visuals[i]->visualid == visual->visualid) { - ret = visuals[i]; - break; + cairo_list_foreach_entry (visual, + cairo_xlib_visual_info_t, + &info->visuals, + link) + { + if (visual->visualid == v->visualid) { + *out = visual; + return CAIRO_STATUS_SUCCESS; } } - CAIRO_MUTEX_UNLOCK (info->mutex); - if (ret != NULL) { - *out = ret; - return CAIRO_STATUS_SUCCESS; - } - - status = _cairo_xlib_visual_info_create (dpy, + status = _cairo_xlib_visual_info_create (display->display, XScreenNumberOfScreen (info->screen), - visual->visualid, - &ret); + v->visualid, + &visual); if (unlikely (status)) return status; - CAIRO_MUTEX_LOCK (info->mutex); - if (n_visuals != _cairo_array_num_elements (&info->visuals)) { - /* check that another thread has not added our visual */ - int new_visuals = _cairo_array_num_elements (&info->visuals); - visuals = _cairo_array_index (&info->visuals, 0); - for (i = n_visuals; i < new_visuals; i++) { - if (visuals[i]->visualid == visual->visualid) { - _cairo_xlib_visual_info_destroy (dpy, ret); - ret = visuals[i]; - break; - } - } - if (i == new_visuals) - status = _cairo_array_append (&info->visuals, &ret); - } else - status = _cairo_array_append (&info->visuals, &ret); - CAIRO_MUTEX_UNLOCK (info->mutex); - - if (unlikely (status)) { - _cairo_xlib_visual_info_destroy (dpy, ret); - return status; - } - - *out = ret; + cairo_list_add (&visual->link, &info->visuals); + *out = visual; return CAIRO_STATUS_SUCCESS; } cairo_font_options_t * _cairo_xlib_screen_get_font_options (cairo_xlib_screen_t *info) { - if (info->has_font_options) - return &info->font_options; - - CAIRO_MUTEX_LOCK (info->mutex); if (! info->has_font_options) { _cairo_font_options_init_default (&info->font_options); + _cairo_font_options_set_round_glyph_positions (&info->font_options, CAIRO_ROUND_GLYPH_POS_ON); if (info->screen != NULL) { - _cairo_xlib_init_screen_font_options (_cairo_xlib_display_get_dpy (info->display), - info); + cairo_xlib_display_t *display; + + if (! _cairo_xlib_display_acquire (info->device, &display)) { + _cairo_xlib_init_screen_font_options (display->display, + info); + cairo_device_release (&display->base); + } } info->has_font_options = TRUE; } - CAIRO_MUTEX_UNLOCK (info->mutex); return &info->font_options; } diff --git a/gfx/cairo/cairo/src/cairo-xlib-surface-private.h b/gfx/cairo/cairo/src/cairo-xlib-surface-private.h index b30848d57f94..34732b4f660f 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-surface-private.h +++ b/gfx/cairo/cairo/src/cairo-xlib-surface-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -44,8 +44,6 @@ typedef struct _cairo_xlib_surface cairo_xlib_surface_t; struct _cairo_xlib_surface { cairo_surface_t base; - Display *dpy; - cairo_xlib_display_t *display; cairo_xlib_screen_t *screen; cairo_xlib_hook_t close_display_hook; @@ -96,6 +94,7 @@ struct _cairo_xlib_surface { cairo_filter_t filter; cairo_extend_t extend; cairo_bool_t has_component_alpha; + int precision; XTransform xtransform; uint32_t a_mask; diff --git a/gfx/cairo/cairo/src/cairo-xlib-surface.c b/gfx/cairo/cairo/src/cairo-xlib-surface.c index 80ce023be50d..e6e19fed815b 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-surface.c +++ b/gfx/cairo/cairo/src/cairo-xlib-surface.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -50,7 +50,10 @@ #include "cairo-xlib-private.h" #include "cairo-xlib-surface-private.h" #include "cairo-clip-private.h" +#include "cairo-error-private.h" #include "cairo-scaled-font-private.h" +#include "cairo-surface-snapshot-private.h" +#include "cairo-surface-subsurface-private.h" #include "cairo-region-private.h" #include /* for XDestroyImage */ @@ -104,6 +107,46 @@ _x_bread_crumb (Display *dpy, #define X_DEBUG(x) #endif +/** + * SECTION:cairo-xlib + * @Title: XLib Surfaces + * @Short_Description: X Window System rendering using XLib + * @See_Also: #cairo_surface_t + * + * The XLib surface is used to render cairo graphics to X Window System + * windows and pixmaps using the XLib library. + * + * Note that the XLib surface automatically takes advantage of X render extension + * if it is available. + */ + +/** + * CAIRO_HAS_XLIB_SURFACE: + * + * Defined if the Xlib surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + */ + +/** + * SECTION:cairo-xlib-xrender + * @Title: XLib/XRender Backend + * @Short_Description: X Window System rendering using XLib and the X Render extension + * @See_Also: #cairo_surface_t + * + * The XLib surface is used to render cairo graphics to X Window System + * windows and pixmaps using the XLib and Xrender libraries. + * + * Note that the XLib surface automatically takes advantage of X Render extension + * if it is available. + */ + +/** + * CAIRO_HAS_XLIB_XRENDER_SURFACE: + * + * Defined if the XLib/XRender surface functions are available. + * This macro can be used to conditionally compile backend-specific code. + */ + /* Xlib doesn't define a typedef, so define one ourselves */ typedef int (*cairo_xlib_error_func_t) (Display *display, XErrorEvent *event); @@ -117,18 +160,6 @@ _cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen, int height, int depth); -static cairo_status_t -_cairo_xlib_surface_get_gc (cairo_xlib_surface_t *surface, GC *gc); - -static void -_cairo_xlib_surface_put_gc (cairo_xlib_surface_t *surface, GC gc); - -static void -_cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface); - -static void -_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface); - static cairo_bool_t _cairo_surface_is_xlib (cairo_surface_t *surface); @@ -145,10 +176,6 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, cairo_clip_t *clip, int *remaining_glyphs); -/* XXX temporarily used by cairo-qt-surface.c */ -slim_hidden_proto (cairo_xlib_surface_create); -slim_hidden_proto (cairo_xlib_surface_create_with_xrender_format); - /* * Instead of taking two round trips for each blending request, * assume that if a particular drawable fails GetImage that it will @@ -196,11 +223,17 @@ static const XTransform identity = { { static Visual * _visual_for_xrender_format(Screen *screen, - XRenderPictFormat *xrender_format) + XRenderPictFormat *xrender_format) { int d, v; + + /* XXX Consider searching through the list of known cairo_visual_t for + * the reverse mapping. + */ + for (d = 0; d < screen->ndepths; d++) { Depth *d_info = &screen->depths[d]; + if (d_info->depth != xrender_format->depth) continue; @@ -212,11 +245,14 @@ _visual_for_xrender_format(Screen *screen, if (xrender_format->type != PictTypeDirect) continue; break; + case DirectColor: /* Prefer TrueColor to DirectColor. - (XRenderFindVisualFormat considers both TrueColor and - DirectColor Visuals to match the same PictFormat.) */ + * (XRenderFindVisualFormat considers both TrueColor and DirectColor + * Visuals to match the same PictFormat.) + */ continue; + case StaticGray: case GrayScale: case StaticColor: @@ -325,6 +361,7 @@ _cairo_xlib_surface_create_similar (void *abstract_src, cairo_xlib_surface_t *src = abstract_src; XRenderPictFormat *xrender_format; cairo_xlib_surface_t *surface; + cairo_xlib_display_t *display; Pixmap pix; if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) @@ -333,7 +370,8 @@ _cairo_xlib_surface_create_similar (void *abstract_src, if (! CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (src)) return NULL; - _cairo_xlib_display_notify (src->display); + if (_cairo_xlib_display_acquire (src->base.device, &display)) + return NULL; /* If we never found an XRenderFormat or if it isn't compatible * with the content being requested, then we fallback to just @@ -344,7 +382,7 @@ _cairo_xlib_surface_create_similar (void *abstract_src, if ((xrender_format != NULL && _xrender_format_to_content (xrender_format) == content) || (xrender_format = - _cairo_xlib_display_get_xrender_format (src->display, + _cairo_xlib_display_get_xrender_format (display, _cairo_format_from_content (content)))) { Visual *visual; @@ -352,11 +390,10 @@ _cairo_xlib_surface_create_similar (void *abstract_src, /* We've got a compatible XRenderFormat now, which means the * similar surface will match the existing surface as closely in * visual/depth etc. as possible. */ - pix = XCreatePixmap (src->dpy, src->drawable, + pix = XCreatePixmap (display->display, src->drawable, width <= 0 ? 1 : width, height <= 0 ? 1 : height, xrender_format->depth); - visual = NULL; if (xrender_format == src->xrender_format) visual = src->visual; else @@ -378,12 +415,14 @@ _cairo_xlib_surface_create_similar (void *abstract_src, /* No compatabile XRenderFormat, see if we can make an ordinary pixmap, * so that we can still accelerate blits with XCopyArea(). */ - if (content != CAIRO_CONTENT_COLOR) + if (content != CAIRO_CONTENT_COLOR) { + cairo_device_release (&display->base); return NULL; + } depth = DefaultDepthOfScreen (screen); - pix = XCreatePixmap (src->dpy, RootWindowOfScreen (screen), + pix = XCreatePixmap (display->display, RootWindowOfScreen (screen), width <= 0 ? 1 : width, height <= 0 ? 1 : height, depth); @@ -394,17 +433,21 @@ _cairo_xlib_surface_create_similar (void *abstract_src, width, height, depth); #else /* No compatabile XRenderFormat, just say no. */ + cairo_device_release (&display->base); return NULL; #endif } if (unlikely (surface->base.status)) { - XFreePixmap (src->dpy, pix); + XFreePixmap (display->display, pix); + cairo_device_release (&display->base); return &surface->base; } surface->owns_pixmap = TRUE; + cairo_device_release (&display->base); + return &surface->base; } @@ -412,10 +455,14 @@ static cairo_status_t _cairo_xlib_surface_finish (void *abstract_surface) { cairo_xlib_surface_t *surface = abstract_surface; - cairo_xlib_display_t *display = surface->display; - cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_status_t status; + cairo_xlib_display_t *display; - X_DEBUG ((surface->dpy, "finish (drawable=%x)", (unsigned int) surface->drawable)); + X_DEBUG ((display->display, "finish (drawable=%x)", (unsigned int) surface->drawable)); + + status = _cairo_xlib_display_acquire (surface->base.device, &display); + if (unlikely (status)) + return status; if (surface->owns_pixmap) { cairo_status_t status2; @@ -443,28 +490,52 @@ _cairo_xlib_surface_finish (void *abstract_surface) status = status2; } else { if (surface->dst_picture != None) - XRenderFreePicture (surface->dpy, surface->dst_picture); + XRenderFreePicture (display->display, surface->dst_picture); if (surface->src_picture != None) - XRenderFreePicture (surface->dpy, surface->src_picture); + XRenderFreePicture (display->display, surface->src_picture); } if (surface->clip_rects != surface->embedded_clip_rects) free (surface->clip_rects); - if (surface->dpy != NULL) { - _cairo_xlib_remove_close_display_hook (surface->display, + if (display->display != NULL) + _cairo_xlib_remove_close_display_hook (display, &surface->close_display_hook); - surface->dpy = NULL; - } - _cairo_xlib_screen_destroy (surface->screen); + cairo_device_release (&display->base); cairo_region_destroy (surface->clip_region); return status; } +static cairo_status_t +_cairo_xlib_surface_get_gc (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface, + GC *gc) +{ + *gc = _cairo_xlib_screen_get_gc (display, + surface->screen, + surface->depth, + surface->drawable); + if (unlikely (*gc == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_xlib_surface_put_gc (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface, + GC gc) +{ + _cairo_xlib_screen_put_gc (display, + surface->screen, + surface->depth, + gc); +} + static int _noop_error_handler (Display *display, XErrorEvent *event) @@ -751,6 +822,7 @@ _get_image_surface (cairo_xlib_surface_t *surface, cairo_rectangle_int_t extents; pixman_format_code_t pixman_format; cairo_format_masks_t xlib_masks; + cairo_xlib_display_t *display; extents.x = 0; extents.y = 0; @@ -764,6 +836,10 @@ _get_image_surface (cairo_xlib_surface_t *surface, } } + status = _cairo_xlib_display_acquire (surface->base.device, &display); + if (status) + return status; + if (image_rect) *image_rect = extents; @@ -775,7 +851,7 @@ _get_image_surface (cairo_xlib_surface_t *surface, old_handler = XSetErrorHandler (_noop_error_handler); - ximage = XGetImage (surface->dpy, + ximage = XGetImage (display->display, surface->drawable, extents.x, extents.y, extents.width, extents.height, @@ -805,35 +881,37 @@ _get_image_surface (cairo_xlib_surface_t *surface, Pixmap pixmap; GC gc; - status = _cairo_xlib_surface_get_gc (surface, &gc); + status = _cairo_xlib_surface_get_gc (display, surface, &gc); if (unlikely (status)) - return status; + goto BAIL; - pixmap = XCreatePixmap (surface->dpy, + pixmap = XCreatePixmap (display->display, surface->drawable, extents.width <= 0 ? 1 : extents.width, extents.height <= 0 ? 1 : extents.height, surface->depth); if (pixmap) { - XCopyArea (surface->dpy, surface->drawable, pixmap, gc, + XCopyArea (display->display, surface->drawable, pixmap, gc, extents.x, extents.y, extents.width, extents.height, 0, 0); - ximage = XGetImage (surface->dpy, + ximage = XGetImage (display->display, pixmap, 0, 0, extents.width <= 0 ? 1 : extents.width, extents.height <= 0 ? 1 : extents.height, AllPlanes, ZPixmap); - XFreePixmap (surface->dpy, pixmap); + XFreePixmap (display->display, pixmap); } - _cairo_xlib_surface_put_gc (surface, gc); + _cairo_xlib_surface_put_gc (display, surface, gc); - if (ximage == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (ximage == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } } _swap_ximage_to_native (ximage); @@ -918,7 +996,8 @@ _get_image_surface (cairo_xlib_surface_t *surface, } else { format = CAIRO_FORMAT_RGB24; - status = _cairo_xlib_screen_get_visual_info (surface->screen, + status = _cairo_xlib_screen_get_visual_info (display, + surface->screen, surface->visual, &visual_info); if (unlikely (status)) @@ -964,7 +1043,10 @@ _get_image_surface (cairo_xlib_surface_t *surface, } BAIL: - XDestroyImage (ximage); + if (ximage) + XDestroyImage (ximage); + + cairo_device_release (&display->base); if (unlikely (status)) { if (image) { @@ -977,7 +1059,8 @@ _get_image_surface (cairo_xlib_surface_t *surface, } static void -_cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface) +_cairo_xlib_surface_ensure_src_picture (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface) { if (!surface->src_picture) { XRenderPictureAttributes pa; @@ -986,7 +1069,7 @@ _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface) pa.subwindow_mode = IncludeInferiors; mask |= CPSubwindowMode; - surface->src_picture = XRenderCreatePicture (surface->dpy, + surface->src_picture = XRenderCreatePicture (display->display, surface->drawable, surface->xrender_format, mask, &pa); @@ -994,17 +1077,18 @@ _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface) } static void -_cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface) +_cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface) { if (surface->clip_region != NULL) { - XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture, + XRenderSetPictureClipRectangles (display->display, surface->dst_picture, 0, 0, surface->clip_rects, surface->num_clip_rects); } else { XRenderPictureAttributes pa; pa.clip_mask = None; - XRenderChangePicture (surface->dpy, surface->dst_picture, + XRenderChangePicture (display->display, surface->dst_picture, CPClipMask, &pa); } @@ -1012,37 +1096,50 @@ _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface) } static void -_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface) +_cairo_xlib_surface_set_precision (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface, + cairo_antialias_t antialias) +{ + int precision; + + switch (antialias) { + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_GRAY: + precision = PolyModeImprecise; + break; + case CAIRO_ANTIALIAS_NONE: + case CAIRO_ANTIALIAS_SUBPIXEL: + precision = PolyModePrecise; + break; + } + + /* NVidia's driver version 190.42 is much slower when using PolyModeInprecise */ + precision = PolyModePrecise; + + if (surface->precision != precision) { + XRenderPictureAttributes pa; + + pa.poly_mode = precision; + XRenderChangePicture (display->display, surface->dst_picture, + CPPolyMode, &pa); + + surface->precision = precision; + } +} + +static void +_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface) { if (!surface->dst_picture) { - surface->dst_picture = XRenderCreatePicture (surface->dpy, + surface->dst_picture = XRenderCreatePicture (display->display, surface->drawable, surface->xrender_format, 0, NULL); } if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE) - _cairo_xlib_surface_set_picture_clip_rects (surface); -} - -static cairo_status_t -_cairo_xlib_surface_get_gc (cairo_xlib_surface_t *surface, GC *gc) -{ - *gc = _cairo_xlib_screen_get_gc (surface->screen, - surface->depth, - surface->drawable); - if (unlikely (*gc == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - return CAIRO_STATUS_SUCCESS; -} - -static void -_cairo_xlib_surface_put_gc (cairo_xlib_surface_t *surface, GC gc) -{ - _cairo_xlib_screen_put_gc (surface->screen, - surface->depth, - gc); + _cairo_xlib_surface_set_picture_clip_rects (display, surface); } static cairo_status_t @@ -1055,6 +1152,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface, int dst_x, int dst_y) { + cairo_xlib_display_t *display; XImage ximage; cairo_format_masks_t image_masks; int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst; @@ -1076,6 +1174,10 @@ _draw_image_surface (cairo_xlib_surface_t *surface, ximage.blue_mask = surface->b_mask; ximage.xoffset = 0; + status = _cairo_xlib_display_acquire (surface->base.device, &display); + if (unlikely (status)) + return status; + if (!_pixman_format_to_masks (image->pixman_format, &image_masks)) { pixman_format_code_t intermediate_format; @@ -1089,27 +1191,30 @@ _draw_image_surface (cairo_xlib_surface_t *surface, ret = _pixman_format_from_masks (&image_masks, &intermediate_format); assert (ret); + own_data = FALSE; + pixman_image = pixman_image_create_bits (intermediate_format, image->width, image->height, NULL, 0); - if (pixman_image == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (pixman_image == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } - pixman_image_composite (PIXMAN_OP_SRC, - image->pixman_image, - NULL, - pixman_image, - 0, 0, - 0, 0, - 0, 0, - image->width, image->height); + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, + NULL, + pixman_image, + 0, 0, + 0, 0, + 0, 0, + image->width, image->height); ximage.bits_per_pixel = image_masks.bpp; ximage.data = (char *) pixman_image_get_data (pixman_image); ximage.bytes_per_line = pixman_image_get_stride (pixman_image); - own_data = FALSE; ret = XInitImage (&ximage); assert (ret != 0); @@ -1154,8 +1259,11 @@ _draw_image_surface (cairo_xlib_surface_t *surface, ximage.bits_per_pixel); ximage.bytes_per_line = stride; ximage.data = _cairo_malloc_ab (stride, ximage.height); - if (unlikely (ximage.data == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (unlikely (ximage.data == NULL)) { + own_data = FALSE; + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } own_data = TRUE; @@ -1175,7 +1283,8 @@ _draw_image_surface (cairo_xlib_surface_t *surface, _characterize_field (surface->g_mask, &o_g_width, &o_g_shift); _characterize_field (surface->b_mask, &o_b_width, &o_b_shift); } else { - status = _cairo_xlib_screen_get_visual_info (surface->screen, + status = _cairo_xlib_screen_get_visual_info (display, + surface->screen, surface->visual, &visual_info); if (unlikely (status)) @@ -1246,17 +1355,20 @@ _draw_image_surface (cairo_xlib_surface_t *surface, } } - status = _cairo_xlib_surface_get_gc (surface, &gc); + status = _cairo_xlib_surface_get_gc (display, surface, &gc); if (unlikely (status)) goto BAIL; - XPutImage (surface->dpy, surface->drawable, gc, + XPutImage (display->display, surface->drawable, gc, &ximage, src_x, src_y, dst_x, dst_y, width, height); - _cairo_xlib_surface_put_gc (surface, gc); + _cairo_xlib_surface_put_gc (display, surface, gc); BAIL: + + cairo_device_release (&display->base); + if (own_data) free (ximage.data); if (pixman_image) @@ -1274,8 +1386,6 @@ _cairo_xlib_surface_acquire_source_image (void *abstract_surf cairo_image_surface_t *image; cairo_status_t status; - _cairo_xlib_display_notify (surface->display); - status = _get_image_surface (surface, NULL, &image, NULL); if (unlikely (status)) return status; @@ -1293,8 +1403,6 @@ _cairo_xlib_surface_snapshot (void *abstract_surface) cairo_image_surface_t *image; cairo_status_t status; - _cairo_xlib_display_notify (surface->display); - status = _get_image_surface (surface, NULL, &image, NULL); if (unlikely (status)) return _cairo_surface_create_in_error (status); @@ -1321,8 +1429,6 @@ _cairo_xlib_surface_acquire_dest_image (void *abstract_surfac cairo_image_surface_t *image; cairo_status_t status; - _cairo_xlib_display_notify (surface->display); - status = _get_image_surface (surface, interest_rect, &image, image_rect_out); if (unlikely (status)) return status; @@ -1378,8 +1484,6 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface, cairo_xlib_surface_t *clone; cairo_status_t status; - _cairo_xlib_display_notify (surface->display); - if (src->backend == surface->base.backend ) { cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src; @@ -1441,6 +1545,7 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac cairo_image_surface_t *image; cairo_xlib_surface_t *surface = NULL; cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_xlib_display_t *display; int width = ARRAY_LENGTH (dither_pattern[0]); int height = ARRAY_LENGTH (dither_pattern); @@ -1451,16 +1556,21 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac return NULL; image = (cairo_image_surface_t *) - _cairo_image_surface_create_with_content (solid_pattern->content, - width, height); + _cairo_image_surface_create_with_content (_cairo_color_get_content (&solid_pattern->color), + width, height); status = image->base.status; if (unlikely (status)) goto BAIL; - pixmap = XCreatePixmap (other->dpy, + status = _cairo_xlib_display_acquire (other->base.device, &display); + if (unlikely (status)) + goto BAIL; + + pixmap = XCreatePixmap (display->display, other->drawable, width, height, other->depth); + cairo_device_release (&display->base); surface = (cairo_xlib_surface_t *) _cairo_xlib_surface_create_internal (other->screen, @@ -1490,12 +1600,16 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac BAIL: cairo_surface_destroy (&image->base); - if (unlikely (status)) { - if (pixmap != None) - XFreePixmap (other->dpy, pixmap); - cairo_surface_destroy (&surface->base); + if (status) { + if (pixmap != None) { + if (!_cairo_xlib_display_acquire (other->base.device, &display)) { + XFreePixmap (display->display, pixmap); + cairo_device_release (&display->base); + } + } + cairo_surface_destroy (&surface->base); - return _cairo_surface_create_in_error (status); + return _cairo_surface_create_in_error (status); } surface->owns_pixmap = TRUE; @@ -1511,8 +1625,9 @@ _cairo_xlib_surface_can_repaint_solid_pattern_surface (void *abstract_surface, } static cairo_status_t -_cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface, - cairo_matrix_t *matrix, +_cairo_xlib_surface_set_matrix (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface, + const cairo_matrix_t *matrix, double xc, double yc) { @@ -1531,14 +1646,15 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface, if (! CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface)) return UNSUPPORTED ("XRender does not support picture transforms"); - XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform); + XRenderSetPictureTransform (display->display, surface->src_picture, &xtransform); surface->xtransform = xtransform; return CAIRO_STATUS_SUCCESS; } static cairo_status_t -_cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface, +_cairo_xlib_surface_set_filter (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface, cairo_filter_t filter) { const char *render_filter; @@ -1580,7 +1696,7 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface, break; } - XRenderSetPictureFilter (surface->dpy, surface->src_picture, + XRenderSetPictureFilter (display->display, surface->src_picture, (char *) render_filter, NULL, 0); surface->filter = filter; @@ -1646,19 +1762,20 @@ _cairo_xlib_surface_set_component_alpha (cairo_xlib_surface_t *surface, } static cairo_int_status_t -_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, - cairo_surface_attributes_t *attributes, - double xc, - double yc) +_cairo_xlib_surface_set_attributes (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface, + const cairo_surface_attributes_t *attributes, + double xc, + double yc) { cairo_int_status_t status; XRenderPictureAttributes pa; unsigned long mask = 0; - _cairo_xlib_surface_ensure_src_picture (surface); + _cairo_xlib_surface_ensure_src_picture (display, surface); - status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix, - xc, yc); + status = _cairo_xlib_surface_set_matrix (display, surface, + &attributes->matrix, xc, yc); if (unlikely (status)) return status; @@ -1673,12 +1790,12 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface, if (unlikely (status)) return status; - status = _cairo_xlib_surface_set_filter (surface, attributes->filter); + status = _cairo_xlib_surface_set_filter (display, surface, attributes->filter); if (unlikely (status)) return status; if (mask) - XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa); + XRenderChangePicture (display->display, surface->src_picture, mask, &pa); return CAIRO_STATUS_SUCCESS; } @@ -1849,11 +1966,8 @@ _recategorize_composite_operation (cairo_xlib_surface_t *dst, cairo_surface_attributes_t *src_attr, cairo_bool_t have_mask) { - /* Can we use the core protocol? (If _surfaces_compatible, then src and - * dst have the same format and _surface_has_alpha is the same for each.) - */ + /* Can we use the core protocol? */ if (! have_mask && - src->owns_pixmap && _surfaces_compatible (src, dst) && _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) && ! _operator_needs_alpha_composite (op, _surface_has_alpha (dst))) @@ -1952,7 +2066,8 @@ _render_operator (cairo_operator_t op) } static cairo_int_status_t -_cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_surface_t *dst, +_cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display, + cairo_xlib_surface_t *dst, const cairo_pattern_t *pattern, int x, int y, int width, int height, @@ -2014,7 +2129,7 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_surface_t *dst, * XSync call here seems to avoid the issue so I'll keep it here * until it's solved. */ - XSync (dst->dpy, False); + XSync (display->display, False); #endif if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) { @@ -2062,7 +2177,7 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_surface_t *dst, grad.p2.y = _cairo_fixed_to_16_16 (linear->p2.y); } - picture = XRenderCreateLinearGradient (dst->dpy, &grad, + picture = XRenderCreateLinearGradient (display->display, &grad, stops, colors, gradient->n_stops); } else { @@ -2077,7 +2192,7 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_surface_t *dst, grad.outer.y = _cairo_fixed_to_16_16 (radial->c2.y); grad.outer.radius = _cairo_fixed_to_16_16 (radial->r2); - picture = XRenderCreateRadialGradient (dst->dpy, &grad, + picture = XRenderCreateRadialGradient (display->display, &grad, stops, colors, gradient->n_stops); @@ -2090,15 +2205,16 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_surface_t *dst, return _cairo_error (CAIRO_STATUS_NO_MEMORY); /* Wrap the remote Picture in an xlib surface. */ - format = _cairo_xlib_display_get_xrender_format (dst->display, + format = _cairo_xlib_display_get_xrender_format (display, CAIRO_FORMAT_ARGB32); surface = (cairo_xlib_surface_t *) _cairo_xlib_surface_create_internal (dst->screen, None, NULL, format, - 0, 0, 32); + /* what could possibly go wrong? */ + XLIB_COORD_MAX, XLIB_COORD_MAX, 32); if (unlikely (surface->base.status)) { - XRenderFreePicture (dst->dpy, picture); + XRenderFreePicture (display->display, picture); return surface->base.status; } @@ -2131,9 +2247,10 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_surface_t *dst, } static cairo_int_status_t -_cairo_xlib_surface_acquire_pattern_surfaces (cairo_xlib_surface_t *dst, - const cairo_pattern_t *src, - const cairo_pattern_t *mask, +_cairo_xlib_surface_acquire_pattern_surfaces (cairo_xlib_display_t *display, + cairo_xlib_surface_t *dst, + const cairo_pattern_t *src, + const cairo_pattern_t *mask, int src_x, int src_y, int mask_x, @@ -2153,7 +2270,8 @@ _cairo_xlib_surface_acquire_pattern_surfaces (cairo_xlib_surface_t *dst, { cairo_int_status_t status; - status = _cairo_xlib_surface_acquire_pattern_surface (dst, src, + status = _cairo_xlib_surface_acquire_pattern_surface (display, + dst, src, src_x, src_y, width, height, src_out, @@ -2162,7 +2280,8 @@ _cairo_xlib_surface_acquire_pattern_surfaces (cairo_xlib_surface_t *dst, return status; if (mask) { - status = _cairo_xlib_surface_acquire_pattern_surface (dst, mask, + status = _cairo_xlib_surface_acquire_pattern_surface (display, + dst, mask, mask_x, mask_y, width, @@ -2194,6 +2313,108 @@ _cairo_xlib_surface_acquire_pattern_surfaces (cairo_xlib_surface_t *dst, src_attr, mask_attr); } +static cairo_int_status_t +_cairo_xlib_surface_upload(cairo_xlib_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int src_x, int src_y, + int dst_x, int dst_y, + unsigned int width, + unsigned int height, + cairo_region_t *clip_region) +{ + cairo_image_surface_t *image; + cairo_rectangle_int_t extents; + cairo_status_t status; + int tx, ty; + + if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + image = (cairo_image_surface_t *) ((cairo_surface_pattern_t *) pattern)->surface; + if (image->base.type != CAIRO_SURFACE_TYPE_IMAGE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! (op == CAIRO_OPERATOR_SOURCE || + (op == CAIRO_OPERATOR_OVER && + (image->base.content & CAIRO_CONTENT_ALPHA) == 0))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (image->base.backend->type != CAIRO_SURFACE_TYPE_IMAGE) { + if (image->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) { + image = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) image)->target; + extents.x = extents.y = 0; + extents.width = image->width; + extents.height = image->height; + } else if (image->base.backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) image; + image = (cairo_image_surface_t *) sub->target; + src_x += sub->extents.x; + src_y += sub->extents.y; + extents = sub->extents; + } else { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } else { + extents.x = extents.y = 0; + extents.width = image->width; + extents.height = image->height; + } + + if (image->format == CAIRO_FORMAT_INVALID) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (image->depth != surface->depth) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&pattern->matrix, &tx, &ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + src_x += tx; + src_y += ty; + + /* XXX for EXTEND_NONE perform unbounded fixups? */ + if (src_x < extents.x || + src_y < extents.y || + src_x + width > (unsigned) extents.width || + src_y + height > (unsigned) extents.height) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = cairo_device_acquire (surface->base.device); + if (unlikely (status)) + return status; + + if (clip_region != NULL) { + int n, num_rect; + + src_x -= dst_x; + src_y -= dst_y; + + num_rect = cairo_region_num_rectangles (clip_region); + for (n = 0; n < num_rect; n++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (clip_region, n, &rect); + status = _draw_image_surface (surface, image, + rect.x + src_x, rect.y + src_y, + rect.width, rect.height, + rect.x, rect.y); + if (unlikely (status)) + break; + } + } else { + status = _draw_image_surface (surface, image, + src_x, src_y, + width, height, + dst_x, dst_y); + } + + cairo_device_release (surface->base.device); + + return status; +} + static cairo_int_status_t _cairo_xlib_surface_composite (cairo_operator_t op, const cairo_pattern_t *src_pattern, @@ -2213,6 +2434,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, cairo_xlib_surface_t *dst = abstract_dst; cairo_xlib_surface_t *src; cairo_xlib_surface_t *mask; + cairo_xlib_display_t *display; cairo_int_status_t status; composite_operation_t operation; int itx, ity; @@ -2227,12 +2449,25 @@ _cairo_xlib_surface_composite (cairo_operator_t op, if (operation == DO_UNSUPPORTED) return UNSUPPORTED ("unsupported operation"); - X_DEBUG ((dst->dpy, "composite (dst=%x)", (unsigned int) dst->drawable)); + X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable)); - _cairo_xlib_display_notify (dst->display); + if (mask_pattern == NULL) { + /* Can we do a simple upload in-place? */ + status = _cairo_xlib_surface_upload(dst, op, src_pattern, + src_x, src_y, + dst_x, dst_y, + width, height, + clip_region); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + status = _cairo_xlib_display_acquire (dst-> base.device, &display); + if (unlikely (status)) + return status; status = - _cairo_xlib_surface_acquire_pattern_surfaces (dst, + _cairo_xlib_surface_acquire_pattern_surfaces (display, dst, src_pattern, mask_pattern, src_x, src_y, mask_x, mask_y, @@ -2240,7 +2475,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, &src, &mask, &src_attr, &mask_attr); if (unlikely (status)) - return status; + goto BAIL0; /* check for fallback surfaces that we cannot handle ... */ assert (_cairo_surface_is_xlib (&src->base)); @@ -2261,7 +2496,8 @@ _cairo_xlib_surface_composite (cairo_operator_t op, switch (operation) { case DO_RENDER: - status = _cairo_xlib_surface_set_attributes (src, &src_attr, + status = _cairo_xlib_surface_set_attributes (display, + src, &src_attr, dst_x + width / 2., dst_y + height / 2.); if (unlikely (status)) @@ -2271,15 +2507,16 @@ _cairo_xlib_surface_composite (cairo_operator_t op, if (unlikely (status)) goto BAIL; - _cairo_xlib_surface_ensure_dst_picture (dst); + _cairo_xlib_surface_ensure_dst_picture (display, dst); if (mask) { - status = _cairo_xlib_surface_set_attributes (mask, &mask_attr, + status = _cairo_xlib_surface_set_attributes (display, + mask, &mask_attr, dst_x + width / 2., dst_y + height/ 2.); if (unlikely (status)) goto BAIL; - XRenderComposite (dst->dpy, + XRenderComposite (display->display, _render_operator (op), src->src_picture, mask->src_picture, @@ -2291,7 +2528,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, dst_x, dst_y, width, height); } else { - XRenderComposite (dst->dpy, + XRenderComposite (display->display, _render_operator (op), src->src_picture, 0, @@ -2306,7 +2543,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, break; case DO_XCOPYAREA: - status = _cairo_xlib_surface_get_gc (dst, &gc); + status = _cairo_xlib_surface_get_gc (display, dst, &gc); if (unlikely (status)) goto BAIL; @@ -2316,7 +2553,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, assert (is_integer_translation); if (clip_region == NULL) { - XCopyArea (dst->dpy, src->drawable, dst->drawable, gc, + XCopyArea (display->display, src->drawable, dst->drawable, gc, src_x + src_attr.x_offset + itx, src_y + src_attr.y_offset + ity, width, height, @@ -2332,14 +2569,14 @@ _cairo_xlib_surface_composite (cairo_operator_t op, cairo_rectangle_int_t rect; cairo_region_get_rectangle (clip_region, n, &rect); - XCopyArea (dst->dpy, src->drawable, dst->drawable, gc, + XCopyArea (display->display, src->drawable, dst->drawable, gc, rect.x + x, rect.y + y, rect.width, rect.height, rect.x, rect.y); } } - _cairo_xlib_surface_put_gc (dst, gc); + _cairo_xlib_surface_put_gc (display, dst, gc); break; case DO_XTILE: @@ -2351,7 +2588,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op, * _recategorize_composite_operation. */ - status = _cairo_xlib_surface_get_gc (dst, &gc); + status = _cairo_xlib_surface_get_gc (display, dst, &gc); if (unlikely (status)) goto BAIL; @@ -2360,12 +2597,12 @@ _cairo_xlib_surface_composite (cairo_operator_t op, /* This is a pre-condition for DO_XTILE. */ assert (is_integer_translation); - XSetTSOrigin (dst->dpy, gc, + XSetTSOrigin (display->display, gc, - (itx + src_attr.x_offset), - (ity + src_attr.y_offset)); - XSetTile (dst->dpy, gc, src->drawable); + XSetTile (display->display, gc, src->drawable); if (clip_region == NULL) { - XFillRectangle (dst->dpy, dst->drawable, gc, + XFillRectangle (display->display, dst->drawable, gc, dst_x, dst_y, width, height); } else { int n, num_rects; @@ -2375,12 +2612,12 @@ _cairo_xlib_surface_composite (cairo_operator_t op, cairo_rectangle_int_t rect; cairo_region_get_rectangle (clip_region, n, &rect); - XFillRectangle (dst->dpy, dst->drawable, gc, + XFillRectangle (display->display, dst->drawable, gc, rect.x, rect.y, rect.width, rect.height); } } - _cairo_xlib_surface_put_gc (dst, gc); + _cairo_xlib_surface_put_gc (display, dst, gc); break; case DO_UNSUPPORTED: @@ -2405,6 +2642,9 @@ _cairo_xlib_surface_composite (cairo_operator_t op, _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr); + BAIL0: + cairo_device_release (&display->base); + return status; } @@ -2419,16 +2659,21 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface, cairo_solid_pattern_t solid; cairo_surface_t *solid_surface = NULL; cairo_surface_attributes_t attrs; + cairo_xlib_display_t *display; GC gc; int i; - _cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR); + _cairo_pattern_init_solid (&solid, color); - status = _cairo_xlib_surface_get_gc (surface, &gc); + status = _cairo_xlib_display_acquire (surface->base.device, &display); if (unlikely (status)) return status; - X_DEBUG ((surface->dpy, "solid_fill_rectangles (dst=%x)", (unsigned int) surface->drawable)); + status = _cairo_xlib_surface_get_gc (display, surface, &gc); + if (unlikely (status)) + return status; + + X_DEBUG ((display->display, "solid_fill_rectangles (dst=%x)", (unsigned int) surface->drawable)); status = _cairo_pattern_acquire_surface (&solid.base, &surface->base, 0, 0, @@ -2438,27 +2683,30 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface, &solid_surface, &attrs); if (unlikely (status)) { - _cairo_xlib_surface_put_gc (surface, gc); + _cairo_xlib_surface_put_gc (display, surface, gc); + cairo_device_release (&display->base); return status; } assert (_cairo_surface_is_xlib (solid_surface)); - XSetTSOrigin (surface->dpy, gc, + XSetTSOrigin (display->display, gc, - (surface->base.device_transform.x0 + attrs.x_offset), - (surface->base.device_transform.y0 + attrs.y_offset)); - XSetTile (surface->dpy, gc, + XSetTile (display->display, gc, ((cairo_xlib_surface_t *) solid_surface)->drawable); for (i = 0; i < num_rects; i++) { - XFillRectangle (surface->dpy, surface->drawable, gc, + XFillRectangle (display->display, surface->drawable, gc, rects[i].x, rects[i].y, rects[i].width, rects[i].height); } - _cairo_xlib_surface_put_gc (surface, gc); + _cairo_xlib_surface_put_gc (display, surface, gc); _cairo_pattern_release_surface (&solid.base, solid_surface, &attrs); + + cairo_device_release (&display->base); return CAIRO_STATUS_SUCCESS; } @@ -2471,12 +2719,11 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, int num_rects) { cairo_xlib_surface_t *surface = abstract_surface; + cairo_xlib_display_t *display; XRenderColor render_color; cairo_status_t status; int i; - _cairo_xlib_display_notify (surface->display); - if (!CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR (surface, op)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -2492,7 +2739,11 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, return UNSUPPORTED ("no support for FillRectangles with this op"); } - X_DEBUG ((surface->dpy, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable)); + status = _cairo_xlib_display_acquire (surface->base.device, &display); + if (unlikely (status)) + return status; + + X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable)); render_color.red = color->red_short; render_color.green = color->green_short; @@ -2502,12 +2753,12 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, status = _cairo_xlib_surface_set_clip_region (surface, NULL); assert (status == CAIRO_STATUS_SUCCESS); - _cairo_xlib_surface_ensure_dst_picture (surface); + _cairo_xlib_surface_ensure_dst_picture (display, surface); if (num_rects == 1) { /* Take advantage of the protocol compaction that libXrender performs * to amalgamate sequences of XRenderFillRectangle(). */ - XRenderFillRectangle (surface->dpy, + XRenderFillRectangle (display->display, _render_operator (op), surface->dst_picture, &render_color, @@ -2521,8 +2772,10 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, if (num_rects > ARRAY_LENGTH (static_xrects)) { xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle)); - if (unlikely (xrects == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (unlikely (xrects == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } } for (i = 0; i < num_rects; i++) { @@ -2532,7 +2785,7 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, xrects[i].height = rects[i].height; } - XRenderFillRectangles (surface->dpy, + XRenderFillRectangles (display->display, _render_operator (op), surface->dst_picture, &render_color, xrects, num_rects); @@ -2541,7 +2794,9 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, free (xrects); } - return CAIRO_STATUS_SUCCESS; +BAIL: + cairo_device_release (&display->base); + return status; } #define CAIRO_FIXED_16_16_MIN -32768 @@ -2599,6 +2854,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, cairo_surface_attributes_t attributes; cairo_xlib_surface_t *dst = abstract_dst; cairo_xlib_surface_t *src; + cairo_xlib_display_t *display; cairo_int_status_t status; composite_operation_t operation; int render_reference_x, render_reference_y; @@ -2608,8 +2864,6 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, XTrapezoid *xtraps = xtraps_stack; int i; - _cairo_xlib_display_notify (dst->display); - if (! CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) return UNSUPPORTED ("XRender does not support CompositeTrapezoids"); @@ -2617,15 +2871,20 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, if (operation == DO_UNSUPPORTED) return UNSUPPORTED ("unsupported operation"); - X_DEBUG ((dst->dpy, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable)); + status = _cairo_xlib_display_acquire (dst->base.device, &display); + if (unlikely (status)) + return status; - status = _cairo_xlib_surface_acquire_pattern_surface (dst, + X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable)); + + status = _cairo_xlib_surface_acquire_pattern_surface (display, + dst, pattern, src_x, src_y, width, height, &src, &attributes); if (unlikely (status)) - return status; + goto BAIL0; operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE); @@ -2637,7 +2896,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, switch (antialias) { case CAIRO_ANTIALIAS_NONE: pict_format = - _cairo_xlib_display_get_xrender_format (dst->display, + _cairo_xlib_display_get_xrender_format (display, CAIRO_FORMAT_A1); break; case CAIRO_ANTIALIAS_GRAY: @@ -2645,7 +2904,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, case CAIRO_ANTIALIAS_DEFAULT: default: pict_format = - _cairo_xlib_display_get_xrender_format (dst->display, + _cairo_xlib_display_get_xrender_format (display, CAIRO_FORMAT_A8); break; } @@ -2654,9 +2913,11 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, if (unlikely (status)) goto BAIL; - _cairo_xlib_surface_ensure_dst_picture (dst); + _cairo_xlib_surface_ensure_dst_picture (display, dst); + _cairo_xlib_surface_set_precision (display, dst, antialias); - status = _cairo_xlib_surface_set_attributes (src, &attributes, + status = _cairo_xlib_surface_set_attributes (display, + src, &attributes, dst_x + width / 2., dst_y + height / 2.); if (unlikely (status)) @@ -2719,7 +2980,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, render_src_x = src_x + render_reference_x - dst_x; render_src_y = src_y + render_reference_y - dst_y; - XRenderCompositeTrapezoids (dst->dpy, + XRenderCompositeTrapezoids (display->display, _render_operator (op), src->src_picture, dst->dst_picture, pict_format, @@ -2758,6 +3019,8 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, BAIL: _cairo_pattern_release_surface (pattern, &src->base, &attributes); + BAIL0: + cairo_device_release (&display->base); return status; } @@ -2795,30 +3058,9 @@ _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, static cairo_bool_t _cairo_xlib_surface_is_similar (void *surface_a, - void *surface_b, - cairo_content_t content) + void *surface_b) { - cairo_xlib_surface_t *a = surface_a; - cairo_xlib_surface_t *b = surface_b; - XRenderPictFormat *xrender_format = b->xrender_format; - - if (! _cairo_xlib_surface_same_screen (a, b)) - return FALSE; - - /* now inspect the content to check that a is similar to b */ - if (xrender_format == NULL && b->visual != NULL) - xrender_format = XRenderFindVisualFormat (b->dpy, b->visual); - - if (xrender_format == NULL || - _xrender_format_to_content (xrender_format) != content) - { - xrender_format = _cairo_xlib_display_get_xrender_format ( - b->display, - _cairo_format_from_content (content)); - } - - - return a->xrender_format == xrender_format; + return _cairo_xlib_surface_same_screen (surface_a, surface_b); } static const cairo_surface_backend_t cairo_xlib_surface_backend = { @@ -2883,8 +3125,7 @@ _cairo_xlib_surface_detach_display (cairo_xlib_display_t *display, void *data) close_display_hook); Display *dpy; - dpy = surface->dpy; - surface->dpy = NULL; + dpy = display->display; X_DEBUG ((dpy, "detach (drawable=%x)", (unsigned int) surface->drawable)); @@ -2915,8 +3156,8 @@ _cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen, int depth) { cairo_xlib_surface_t *surface; - - CAIRO_MUTEX_INITIALIZE (); + cairo_xlib_display_t *display; + cairo_status_t status; if (depth == 0) { if (xrender_format) { @@ -2958,23 +3199,22 @@ found: if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - surface->dpy = _cairo_xlib_display_get_dpy (screen->display); + status = _cairo_xlib_display_acquire (screen->device, &display); + if (unlikely (status)) { + free (surface); + return _cairo_surface_create_in_error (_cairo_error (status)); + } - /* initialize and hook into the CloseDisplay callback */ - surface->close_display_hook.func = _cairo_xlib_surface_detach_display; - _cairo_xlib_add_close_display_hook (screen->display, - &surface->close_display_hook); - - _cairo_xlib_display_get_xrender_version (screen->display, + _cairo_xlib_display_get_xrender_version (display, &surface->render_major, &surface->render_minor); if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) { if (!xrender_format) { if (visual) { - xrender_format = XRenderFindVisualFormat (surface->dpy, visual); + xrender_format = XRenderFindVisualFormat (display->display, visual); } else if (depth == 1) { xrender_format = - _cairo_xlib_display_get_xrender_format (screen->display, + _cairo_xlib_display_get_xrender_format (display, CAIRO_FORMAT_A1); } } @@ -2984,11 +3224,19 @@ found: surface->render_minor = -1; } - _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend, + /* initialize and hook into the CloseDisplay callback */ + surface->close_display_hook.func = _cairo_xlib_surface_detach_display; + _cairo_xlib_add_close_display_hook (display, + &surface->close_display_hook); + + cairo_device_release (&display->base); + + _cairo_surface_init (&surface->base, + &cairo_xlib_surface_backend, + screen->device, _xrender_format_to_content (xrender_format)); - surface->screen = _cairo_xlib_screen_reference (screen); - surface->display = screen->display; + surface->screen = screen; surface->drawable = drawable; surface->owns_pixmap = FALSE; @@ -2996,17 +3244,17 @@ found: surface->width = width; surface->height = height; - surface->buggy_repeat = ! _cairo_xlib_display_has_repeat (surface->display); + surface->buggy_repeat = ! _cairo_xlib_display_has_repeat (screen->device); if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) { /* so we can use the XTile fallback */ surface->buggy_repeat = TRUE; } - surface->buggy_pad_reflect = ! _cairo_xlib_display_has_reflect (surface->display); + surface->buggy_pad_reflect = ! _cairo_xlib_display_has_reflect (screen->device); if (! CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT (surface)) surface->buggy_pad_reflect = TRUE; - surface->buggy_gradients = ! _cairo_xlib_display_has_gradients (surface->display); + surface->buggy_gradients = ! _cairo_xlib_display_has_gradients (screen->device); if (! CAIRO_SURFACE_RENDER_HAS_GRADIENTS (surface)) surface->buggy_gradients = TRUE; @@ -3019,6 +3267,7 @@ found: surface->filter = CAIRO_FILTER_NEAREST; surface->extend = CAIRO_EXTEND_NONE; surface->has_component_alpha = FALSE; + surface->precision = PolyModePrecise; surface->xtransform = identity; surface->clip_region = NULL; @@ -3122,7 +3371,6 @@ cairo_xlib_surface_create (Display *dpy, { Screen *scr; cairo_xlib_screen_t *screen; - cairo_surface_t *surface; cairo_status_t status; if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) { @@ -3140,14 +3388,10 @@ cairo_xlib_surface_create (Display *dpy, X_DEBUG ((dpy, "create (drawable=%x)", (unsigned int) drawable)); - surface = _cairo_xlib_surface_create_internal (screen, drawable, - visual, NULL, - width, height, 0); - _cairo_xlib_screen_destroy (screen); - - return surface; + return _cairo_xlib_surface_create_internal (screen, drawable, + visual, NULL, + width, height, 0); } -slim_hidden_def (cairo_xlib_surface_create); /** * cairo_xlib_surface_create_for_bitmap: @@ -3170,7 +3414,6 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, int height) { cairo_xlib_screen_t *screen; - cairo_surface_t *surface; cairo_status_t status; if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) @@ -3182,12 +3425,9 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, X_DEBUG ((dpy, "create_for_bitmap (drawable=%x)", (unsigned int) bitmap)); - surface = _cairo_xlib_surface_create_internal (screen, bitmap, - NULL, NULL, - width, height, 1); - _cairo_xlib_screen_destroy (screen); - - return surface; + return _cairo_xlib_surface_create_internal (screen, bitmap, + NULL, NULL, + width, height, 1); } #if CAIRO_HAS_XLIB_XRENDER_SURFACE @@ -3220,9 +3460,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, int height) { cairo_xlib_screen_t *screen; - cairo_surface_t *surface; cairo_status_t status; - Visual *visual; if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE); @@ -3233,17 +3471,10 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, X_DEBUG ((dpy, "create_with_xrender_format (drawable=%x)", (unsigned int) drawable)); - if (format) - visual = _visual_for_xrender_format (scr, format); - - surface = _cairo_xlib_surface_create_internal (screen, drawable, - visual, format, - width, height, 0); - _cairo_xlib_screen_destroy (screen); - - return surface; + return _cairo_xlib_surface_create_internal (screen, drawable, + _visual_for_xrender_format (scr, format), + format, width, height, 0); } -slim_hidden_def (cairo_xlib_surface_create_with_xrender_format); /** * cairo_xlib_surface_get_xrender_format: @@ -3299,15 +3530,23 @@ cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface, cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; cairo_status_t status; + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + if (! _cairo_surface_is_xlib (abstract_surface)) { status = _cairo_surface_set_error (abstract_surface, - CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; } if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) { status = _cairo_surface_set_error (abstract_surface, - CAIRO_STATUS_INVALID_SIZE); + _cairo_error (CAIRO_STATUS_INVALID_SIZE)); return; } @@ -3337,15 +3576,23 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *)abstract_surface; cairo_status_t status; + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + if (! _cairo_surface_is_xlib (abstract_surface)) { status = _cairo_surface_set_error (abstract_surface, - CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; } if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) { status = _cairo_surface_set_error (abstract_surface, - CAIRO_STATUS_INVALID_SIZE); + _cairo_error (CAIRO_STATUS_INVALID_SIZE)); return; } @@ -3354,11 +3601,17 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, return; if (surface->drawable != drawable) { - X_DEBUG ((surface->dpy, "set_drawable (drawable=%x)", (unsigned int) drawable)); + cairo_xlib_display_t *display; + + status = _cairo_xlib_display_acquire (surface->base.device, &display); + if (unlikely (status)) + return; + + X_DEBUG ((display->display, "set_drawable (drawable=%x)", (unsigned int) drawable)); if (surface->dst_picture != None) { status = _cairo_xlib_display_queue_resource ( - surface->display, + display, XRenderFreePicture, surface->dst_picture); if (unlikely (status)) { @@ -3371,7 +3624,7 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, if (surface->src_picture != None) { status = _cairo_xlib_display_queue_resource ( - surface->display, + display, XRenderFreePicture, surface->src_picture); if (unlikely (status)) { @@ -3382,6 +3635,8 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, surface->src_picture = None; } + cairo_device_release (&display->base); + surface->drawable = drawable; } surface->width = width; @@ -3401,14 +3656,12 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, Display * cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface) { - cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; - if (! _cairo_surface_is_xlib (abstract_surface)) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return NULL; } - return surface->dpy; + return ((cairo_xlib_display_t *) abstract_surface->device)->display; } /** @@ -3577,7 +3830,7 @@ typedef struct _cairo_xlib_surface_font_private { cairo_scaled_font_t *scaled_font; cairo_scaled_font_t *grayscale_font; cairo_xlib_hook_t close_display_hook; - cairo_xlib_display_t *display; + cairo_device_t *device; cairo_xlib_font_glyphset_info_t glyphset_info[NUM_GLYPHSETS]; } cairo_xlib_surface_font_private_t; @@ -3602,36 +3855,33 @@ _cairo_xlib_surface_remove_scaled_font (cairo_xlib_display_t *display, CAIRO_MUTEX_UNLOCK (scaled_font->mutex); if (font_private != NULL) { - Display *dpy; int i; - if (font_private->grayscale_font) { - cairo_scaled_font_destroy (font_private->grayscale_font); - } + if (font_private->grayscale_font) { + cairo_scaled_font_destroy (font_private->grayscale_font); + } - dpy = _cairo_xlib_display_get_dpy (display); for (i = 0; i < NUM_GLYPHSETS; i++) { cairo_xlib_font_glyphset_info_t *glyphset_info; glyphset_info = &font_private->glyphset_info[i]; if (glyphset_info->glyphset) - XRenderFreeGlyphSet (dpy, glyphset_info->glyphset); + XRenderFreeGlyphSet (display->display, glyphset_info->glyphset); if (glyphset_info->pending_free_glyphs != NULL) free (glyphset_info->pending_free_glyphs); } - _cairo_xlib_display_destroy (font_private->display); + cairo_device_destroy (font_private->device); free (font_private); } } static cairo_status_t -_cairo_xlib_surface_font_init (Display *dpy, +_cairo_xlib_surface_font_init (cairo_xlib_display_t *display, cairo_scaled_font_t *scaled_font) { cairo_xlib_surface_font_private_t *font_private; - cairo_status_t status; int i; font_private = malloc (sizeof (cairo_xlib_surface_font_private_t)); @@ -3640,16 +3890,12 @@ _cairo_xlib_surface_font_init (Display *dpy, font_private->scaled_font = scaled_font; font_private->grayscale_font = NULL; - status = _cairo_xlib_display_get (dpy, &font_private->display); - if (unlikely (status)) { - free (font_private); - return status; - } + font_private->device = cairo_device_reference (&display->base); /* initialize and hook into the CloseDisplay callback */ font_private->close_display_hook.func = _cairo_xlib_surface_remove_scaled_font; - _cairo_xlib_add_close_display_hook (font_private->display, + _cairo_xlib_add_close_display_hook (display, &font_private->close_display_hook); @@ -3676,6 +3922,7 @@ static void _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font) { cairo_xlib_surface_font_private_t *font_private; + cairo_status_t status; font_private = scaled_font->surface_private; if (font_private != NULL) { @@ -3683,10 +3930,12 @@ _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font) int i; if (font_private->grayscale_font) { - cairo_scaled_font_destroy (font_private->grayscale_font); + cairo_scaled_font_destroy (font_private->grayscale_font); } + status = _cairo_xlib_display_acquire (font_private->device, &display); + if (status) + goto BAIL; - display = font_private->display; _cairo_xlib_remove_close_display_hook (display, &font_private->close_display_hook); @@ -3699,8 +3948,6 @@ _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font) free (glyphset_info->pending_free_glyphs); if (glyphset_info->glyphset) { - cairo_status_t status; - status = _cairo_xlib_display_queue_resource (display, XRenderFreeGlyphSet, glyphset_info->glyphset); @@ -3708,7 +3955,9 @@ _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font) } } - _cairo_xlib_display_destroy (display); + cairo_device_release (&display->base); +BAIL: + cairo_device_destroy (&display->base); free (font_private); } } @@ -3756,10 +4005,16 @@ _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, if (to_free != NULL && to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices)) { - status = _cairo_xlib_display_queue_work (font_private->display, - (cairo_xlib_notify_func) _cairo_xlib_render_free_glyphs, - to_free, - free); + cairo_xlib_display_t *display; + + status = _cairo_xlib_display_acquire (font_private->device, &display); + if (status == CAIRO_STATUS_SUCCESS) { + status = _cairo_xlib_display_queue_work (display, + (cairo_xlib_notify_func) _cairo_xlib_render_free_glyphs, + to_free, + free); + cairo_device_release (&display->base); + } /* XXX cannot propagate failure */ if (unlikely (status)) free (to_free); @@ -3792,6 +4047,18 @@ _native_byte_order_lsb (void) return *((char *) &x) == 1; } +static int +_cairo_xlib_get_glyphset_index_for_format (cairo_format_t format) +{ + if (format == CAIRO_FORMAT_A8) + return GLYPHSET_INDEX_A8; + if (format == CAIRO_FORMAT_A1) + return GLYPHSET_INDEX_A1; + + assert (format == CAIRO_FORMAT_ARGB32); + return GLYPHSET_INDEX_ARGB32; +} + static cairo_xlib_font_glyphset_info_t * _cairo_xlib_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scaled_font, cairo_format_t format) @@ -3800,24 +4067,22 @@ _cairo_xlib_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scale cairo_xlib_font_glyphset_info_t *glyphset_info; int glyphset_index; - switch (format) { - default: - case CAIRO_FORMAT_RGB24: - case CAIRO_FORMAT_ARGB32: glyphset_index = GLYPHSET_INDEX_ARGB32; break; - case CAIRO_FORMAT_A8: glyphset_index = GLYPHSET_INDEX_A8; break; - case CAIRO_FORMAT_A1: glyphset_index = GLYPHSET_INDEX_A1; break; - } - + glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format); font_private = scaled_font->surface_private; glyphset_info = &font_private->glyphset_info[glyphset_index]; if (glyphset_info->glyphset == None) { - cairo_xlib_display_t *display = font_private->display; + cairo_xlib_display_t *display; + + if (_cairo_xlib_display_acquire (font_private->device, &display)) + return NULL; glyphset_info->xrender_format = _cairo_xlib_display_get_xrender_format (display, glyphset_info->format); - glyphset_info->glyphset = XRenderCreateGlyphSet (_cairo_xlib_display_get_dpy (display), + glyphset_info->glyphset = XRenderCreateGlyphSet (display->display, glyphset_info->xrender_format); + + cairo_device_release (&display->base); } return glyphset_info; @@ -3861,13 +4126,7 @@ _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph ( return NULL; if (surface != NULL) { - switch (surface->format) { - default: - case CAIRO_FORMAT_RGB24: - case CAIRO_FORMAT_ARGB32: i = GLYPHSET_INDEX_ARGB32; break; - case CAIRO_FORMAT_A8: i = GLYPHSET_INDEX_A8; break; - case CAIRO_FORMAT_A1: i = GLYPHSET_INDEX_A1; break; - } + i = _cairo_xlib_get_glyphset_index_for_format (surface->format); if (_cairo_xlib_glyphset_info_has_pending_free_glyph ( &font_private->glyphset_info[i], glyph_index)) @@ -3889,7 +4148,7 @@ _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph ( } static cairo_status_t -_cairo_xlib_surface_add_glyph (Display *dpy, +_cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display, cairo_scaled_font_t *scaled_font, cairo_scaled_glyph_t **pscaled_glyph) { @@ -3928,7 +4187,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy, } if (scaled_font->surface_private == NULL) { - status = _cairo_xlib_surface_font_init (dpy, scaled_font); + status = _cairo_xlib_surface_font_init (display, scaled_font); if (unlikely (status)) return status; } @@ -3939,7 +4198,8 @@ _cairo_xlib_surface_add_glyph (Display *dpy, /* XRenderAddGlyph does not handle a glyph surface larger than the extended maximum XRequest size. */ { int len = cairo_format_stride_for_width (glyphset_info->format, glyph_surface->width) * glyph_surface->height; - int max_request_size = (XExtendedMaxRequestSize (dpy) ? XExtendedMaxRequestSize (dpy) : XMaxRequestSize (dpy)) * 4 - + int max_request_size = (XExtendedMaxRequestSize (display->display) ? XExtendedMaxRequestSize (display->display) + : XMaxRequestSize (display->display)) * 4 - sz_xRenderAddGlyphsReq - sz_xGlyphInfo - 8; @@ -4005,10 +4265,10 @@ _cairo_xlib_surface_add_glyph (Display *dpy, data = glyph_surface->data; /* flip formats around */ - switch (scaled_glyph->surface->format) { - case CAIRO_FORMAT_A1: + switch (_cairo_xlib_get_glyphset_index_for_format (scaled_glyph->surface->format)) { + case GLYPHSET_INDEX_A1: /* local bitmaps are always stored with bit == byte */ - if (_native_byte_order_lsb() != (BitmapBitOrder (dpy) == LSBFirst)) { + if (_native_byte_order_lsb() != (BitmapBitOrder (display->display) == LSBFirst)) { int c = glyph_surface->stride * glyph_surface->height; unsigned char *d; unsigned char *new, *n; @@ -4030,10 +4290,10 @@ _cairo_xlib_surface_add_glyph (Display *dpy, data = new; } break; - case CAIRO_FORMAT_A8: + case GLYPHSET_INDEX_A8: break; - case CAIRO_FORMAT_ARGB32: - if (_native_byte_order_lsb() != (ImageByteOrder (dpy) == LSBFirst)) { + case GLYPHSET_INDEX_ARGB32: + if (_native_byte_order_lsb() != (ImageByteOrder (display->display) == LSBFirst)) { unsigned int c = glyph_surface->stride * glyph_surface->height / 4; const uint32_t *d; uint32_t *new, *n; @@ -4046,19 +4306,19 @@ _cairo_xlib_surface_add_glyph (Display *dpy, n = new; d = (uint32_t *) data; do { - *n++ = bswap_32 (*d++); + *n++ = bswap_32 (*d); + d++; } while (--c); data = (uint8_t *) new; } break; - case CAIRO_FORMAT_RGB24: default: ASSERT_NOT_REACHED; break; } /* XXX assume X server wants pixman padding. Xft assumes this as well */ - XRenderAddGlyphs (dpy, glyphset_info->glyphset, + XRenderAddGlyphs (display->display, glyphset_info->glyphset, &glyph_index, &glyph_info, 1, (char *) data, glyph_surface->stride * glyph_surface->height); @@ -4125,7 +4385,8 @@ COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t)); (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y) static cairo_status_t -_emit_glyphs_chunk (cairo_xlib_surface_t *dst, +_emit_glyphs_chunk (cairo_xlib_display_t *display, + cairo_xlib_surface_t *dst, cairo_xlib_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, @@ -4224,7 +4485,7 @@ _emit_glyphs_chunk (cairo_xlib_surface_t *dst, * expected number of xGlyphElts. */ assert (nelt == num_elts); - composite_text_func (dst->dpy, + composite_text_func (display->display, _render_operator (op), src->src_picture, dst->dst_picture, @@ -4246,7 +4507,8 @@ _emit_glyphs_chunk (cairo_xlib_surface_t *dst, #define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4) static cairo_status_t -_cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst, +_cairo_xlib_surface_emit_glyphs (cairo_xlib_display_t *display, + cairo_xlib_surface_t *dst, cairo_xlib_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, @@ -4266,14 +4528,13 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst, int num_elts = 0; int num_out_glyphs = 0; - int max_request_size = XMaxRequestSize (dst->dpy) * 4 + int max_request_size = XMaxRequestSize (display->display) * 4 - MAX (sz_xRenderCompositeGlyphs8Req, MAX(sz_xRenderCompositeGlyphs16Req, sz_xRenderCompositeGlyphs32Req)); int request_size = 0; - _cairo_xlib_surface_ensure_dst_picture (dst); - _cairo_xlib_display_notify (dst->display); + _cairo_xlib_surface_ensure_dst_picture (display, dst); for (i = 0; i < num_glyphs; i++) { int this_x, this_y; @@ -4313,7 +4574,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst, /* Send unsent glyphs to the server */ if (_cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph) == NULL) { - status = _cairo_xlib_surface_add_glyph (dst->dpy, + status = _cairo_xlib_surface_add_glyph (display, scaled_font, &scaled_glyph); if (unlikely (status)) { @@ -4360,7 +4621,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst, */ if (request_size + width > max_request_size - _cairo_sz_xGlyphElt || (this_glyphset_info != glyphset_info)) { - status = _emit_glyphs_chunk (dst, glyphs, i, + status = _emit_glyphs_chunk (display, dst, glyphs, i, scaled_font, op, src, attributes, num_elts, old_width, glyphset_info); if (unlikely (status)) @@ -4403,7 +4664,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst, } if (num_elts) { - status = _emit_glyphs_chunk (dst, glyphs, i, + status = _emit_glyphs_chunk (display, dst, glyphs, i, scaled_font, op, src, attributes, num_elts, width, glyphset_info); } @@ -4424,7 +4685,7 @@ _cairo_xlib_surface_owns_font (cairo_xlib_surface_t *dst, font_private = scaled_font->surface_private; if ((scaled_font->surface_backend != NULL && scaled_font->surface_backend != &cairo_xlib_surface_backend) || - (font_private != NULL && font_private->display != dst->display)) + (font_private != NULL && font_private->device != dst->base.device)) { return FALSE; } @@ -4436,14 +4697,14 @@ _cairo_xlib_surface_owns_font (cairo_xlib_surface_t *dst, * in our surface_private data. */ static cairo_scaled_font_t * -_cairo_xlib_get_grayscale_font (cairo_xlib_surface_t *dst, +_cairo_xlib_get_grayscale_font (cairo_xlib_display_t *display, cairo_scaled_font_t *scaled_font) { cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private; cairo_bool_t needs_font; if (font_private == NULL) { - cairo_status_t status = _cairo_xlib_surface_font_init (dst->dpy, scaled_font); + cairo_status_t status = _cairo_xlib_surface_font_init (display, scaled_font); if (unlikely (status)) return _cairo_scaled_font_create_in_error (status); font_private = scaled_font->surface_private; @@ -4490,13 +4751,11 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_xlib_surface_t *dst = (cairo_xlib_surface_t*) abstract_dst; - composite_operation_t operation; cairo_surface_attributes_t attributes; cairo_xlib_surface_t *src = NULL; cairo_region_t *clip_region = NULL; - - cairo_solid_pattern_t solid_pattern; + cairo_xlib_display_t *display; if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst)) return UNSUPPORTED ("XRender does not support CompositeText"); @@ -4536,12 +4795,17 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, if (! _cairo_xlib_surface_owns_font (dst, scaled_font)) return UNSUPPORTED ("unowned font"); + + status = _cairo_xlib_display_acquire (dst->base.device, &display); + if (unlikely (status)) + return status; + if (!dst->base.permit_subpixel_antialiasing && scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL) { - scaled_font = _cairo_xlib_get_grayscale_font (dst, scaled_font); + scaled_font = _cairo_xlib_get_grayscale_font (display, scaled_font); } - X_DEBUG ((dst->dpy, "show_glyphs (dst=%x)", (unsigned int) dst->drawable)); + X_DEBUG ((display->display, "show_glyphs (dst=%x)", (unsigned int) dst->drawable)); if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1) @@ -4568,7 +4832,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, status = _cairo_xlib_surface_set_clip_region (dst, clip_region); if (unlikely (status)) - return status; + goto BAIL0; /* After passing all those tests, we're now committed to rendering * these glyphs or to fail trying. We first upload any glyphs to @@ -4582,9 +4846,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, * so PictOpClear was never used with CompositeText before. */ if (op == CAIRO_OPERATOR_CLEAR) { - _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE, - CAIRO_CONTENT_COLOR); - src_pattern = &solid_pattern.base; + src_pattern = &_cairo_pattern_white.base; op = CAIRO_OPERATOR_DEST_OUT; } @@ -4615,7 +4877,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, } } - status = _cairo_xlib_surface_acquire_pattern_surface (dst, src_pattern, + status = _cairo_xlib_surface_acquire_pattern_surface (display, + dst, src_pattern, glyph_extents.x, glyph_extents.y, glyph_extents.width, @@ -4632,13 +4895,14 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, goto BAIL1; } - status = _cairo_xlib_surface_set_attributes (src, &attributes, 0, 0); + status = _cairo_xlib_surface_set_attributes (display, src, &attributes, 0, 0); if (unlikely (status)) goto BAIL1; _cairo_scaled_font_freeze_cache (scaled_font); if (_cairo_xlib_surface_owns_font (dst, scaled_font)) { - status = _cairo_xlib_surface_emit_glyphs (dst, + status = _cairo_xlib_surface_emit_glyphs (display, + dst, (cairo_xlib_glyph_t *) glyphs, num_glyphs, scaled_font, @@ -4655,7 +4919,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, if (src) _cairo_pattern_release_surface (src_pattern, &src->base, &attributes); BAIL0: - _cairo_xlib_display_notify (dst->display); + cairo_device_release (&display->base); return status; } diff --git a/gfx/cairo/cairo/src/cairo-xlib-visual.c b/gfx/cairo/cairo/src/cairo-xlib-visual.c index 7dbe86c287b4..e076ed01e45e 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-visual.c +++ b/gfx/cairo/cairo/src/cairo-xlib-visual.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -37,6 +37,8 @@ #include "cairo-xlib-private.h" +#include "cairo-error-private.h" + /* A perceptual distance metric between two colors. No sqrt needed * since the square of the distance is still a valid metric. */ @@ -178,7 +180,7 @@ _cairo_xlib_visual_info_create (Display *dpy, } void -_cairo_xlib_visual_info_destroy (Display *dpy, cairo_xlib_visual_info_t *info) +_cairo_xlib_visual_info_destroy (cairo_xlib_visual_info_t *info) { /* No need for XFreeColors() whilst using DefaultColormap */ free (info); diff --git a/gfx/cairo/cairo/src/cairo-xlib-xrender-private.h b/gfx/cairo/cairo/src/cairo-xlib-xrender-private.h index 63a0ecbdc659..52f41591591a 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-xrender-private.h +++ b/gfx/cairo/cairo/src/cairo-xlib-xrender-private.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -38,13 +38,6 @@ #include -#if CAIRO_HAS_XLIB_XRENDER_SURFACE - -#include "cairo-xlib-xrender.h" - -#include -#include - /* These prototypes are used when defining interfaces missing from the * render headers. As it happens, it is the case that all libxrender * functions take a pointer as first argument. */ @@ -55,6 +48,13 @@ __attribute__((__unused__)) static int _int_consume (void *p, ...) __attribute__((__unused__)) static void _void_consume_free (Display *p, XID n) { } +#if CAIRO_HAS_XLIB_XRENDER_SURFACE + +#include "cairo-xlib-xrender.h" + +#include +#include + /* We require Render >= 0.6. The following defines were only added in * 0.10. Make sure they are defined. */ diff --git a/gfx/cairo/cairo/src/cairo-xlib-xrender.h b/gfx/cairo/cairo/src/cairo-xlib-xrender.h index c1c4c6217292..b34b057de4c8 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-xrender.h +++ b/gfx/cairo/cairo/src/cairo-xlib-xrender.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-xlib.h b/gfx/cairo/cairo/src/cairo-xlib.h index 29e9f100e55d..4ee592ce49c2 100644 --- a/gfx/cairo/cairo/src/cairo-xlib.h +++ b/gfx/cairo/cairo/src/cairo-xlib.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/cairo-xml-surface.c b/gfx/cairo/cairo/src/cairo-xml-surface.c index 25e0bb224a31..b323d03c43cd 100644 --- a/gfx/cairo/cairo/src/cairo-xml-surface.c +++ b/gfx/cairo/cairo/src/cairo-xml-surface.c @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -45,6 +45,8 @@ #include "cairo-xml.h" #include "cairo-clip-private.h" +#include "cairo-device-private.h" +#include "cairo-error-private.h" #include "cairo-output-stream-private.h" #include "cairo-recording-surface-private.h" @@ -52,43 +54,23 @@ typedef struct _cairo_xml_surface cairo_xml_surface_t; -struct _cairo_xml { - cairo_status_t status; - - int ref; +typedef struct _cairo_xml { + cairo_device_t base; cairo_output_stream_t *stream; int indent; -}; +} cairo_xml_t; struct _cairo_xml_surface { cairo_surface_t base; - cairo_xml_t *xml; - double width, height; }; slim_hidden_proto (cairo_xml_for_recording_surface); -static const cairo_xml_t _nil_xml = { - CAIRO_STATUS_NO_MEMORY, - -1 -}; - static const cairo_surface_backend_t _cairo_xml_surface_backend; -static const char * -_direction_to_string (cairo_bool_t backward) -{ - static const char *names[] = { - "FORWARD", - "BACKWARD" - }; - assert (backward < ARRAY_LENGTH (names)); - return names[backward]; -} - static const char * _operator_to_string (cairo_operator_t op) { @@ -221,35 +203,67 @@ _content_to_string (cairo_content_t content) static const char * _format_to_string (cairo_format_t format) { - static const char *names[] = { - "ARGB32", /* CAIRO_FORMAT_ARGB32 */ - "RGB24", /* CAIRO_FORMAT_RGB24 */ - "A8", /* CAIRO_FORMAT_A8 */ - "A1" /* CAIRO_FORMAT_A1 */ - }; - assert (format < ARRAY_LENGTH (names)); - return names[format]; + switch (format) { + case CAIRO_FORMAT_ARGB32: return "ARGB32"; + case CAIRO_FORMAT_RGB24: return "RGB24"; + case CAIRO_FORMAT_RGB16_565: return "RGB16_565"; + case CAIRO_FORMAT_A8: return "A8"; + case CAIRO_FORMAT_A1: return "A1"; + case CAIRO_FORMAT_INVALID: return "INVALID"; + } + ASSERT_NOT_REACHED; + return "INVALID"; } -static cairo_xml_t * +static cairo_status_t +_device_flush (void *abstract_device) +{ + cairo_xml_t *xml = abstract_device; + cairo_status_t status; + + status = _cairo_output_stream_flush (xml->stream); + + return status; +} + +static void +_device_destroy (void *abstract_device) +{ + cairo_xml_t *xml = abstract_device; + cairo_status_t status; + + status = _cairo_output_stream_destroy (xml->stream); + + free (xml); +} + +static const cairo_device_backend_t _cairo_xml_device_backend = { + CAIRO_DEVICE_TYPE_XML, + + NULL, NULL, /* lock, unlock */ + + _device_flush, + NULL, /* finish */ + _device_destroy +}; + +static cairo_device_t * _cairo_xml_create_internal (cairo_output_stream_t *stream) { cairo_xml_t *xml; xml = malloc (sizeof (cairo_xml_t)); - if (unlikely (xml == NULL)) { - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - return (cairo_xml_t *) &_nil_xml; - } + if (unlikely (xml == NULL)) + return _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY); memset (xml, 0, sizeof (cairo_xml_t)); - xml->status = CAIRO_STATUS_SUCCESS; - xml->ref = 1; - xml->indent = 0; + _cairo_device_init (&xml->base, &_cairo_xml_device_backend); + + xml->indent = 0; xml->stream = stream; - return xml; + return &xml->base; } static void @@ -320,22 +334,6 @@ _cairo_xml_printf_end (cairo_xml_t *xml, const char *fmt, ...) _cairo_output_stream_write (xml->stream, "\n", 1); } -static cairo_status_t -_cairo_xml_destroy_internal (cairo_xml_t *xml) -{ - cairo_status_t status; - - assert (xml->ref > 0); - if (--xml->ref) - return _cairo_output_stream_flush (xml->stream); - - status = _cairo_output_stream_destroy (xml->stream); - - free (xml); - - return status; -} - static cairo_surface_t * _cairo_xml_surface_create_similar (void *abstract_surface, cairo_content_t content, @@ -351,14 +349,6 @@ _cairo_xml_surface_create_similar (void *abstract_surface, return cairo_recording_surface_create (content, &extents); } -static cairo_status_t -_cairo_xml_surface_finish (void *abstract_surface) -{ - cairo_xml_surface_t *surface = abstract_surface; - - return _cairo_xml_destroy_internal (surface->xml); -} - static cairo_bool_t _cairo_xml_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) @@ -381,8 +371,8 @@ _cairo_xml_move_to (void *closure, const cairo_point_t *p1) { _cairo_xml_printf_continue (closure, " %f %f m", - _cairo_fixed_to_double (p1->x), - _cairo_fixed_to_double (p1->y)); + _cairo_fixed_to_double (p1->x), + _cairo_fixed_to_double (p1->y)); return CAIRO_STATUS_SUCCESS; } @@ -392,8 +382,8 @@ _cairo_xml_line_to (void *closure, const cairo_point_t *p1) { _cairo_xml_printf_continue (closure, " %f %f l", - _cairo_fixed_to_double (p1->x), - _cairo_fixed_to_double (p1->y)); + _cairo_fixed_to_double (p1->x), + _cairo_fixed_to_double (p1->y)); return CAIRO_STATUS_SUCCESS; } @@ -405,12 +395,13 @@ _cairo_xml_curve_to (void *closure, const cairo_point_t *p3) { _cairo_xml_printf_continue (closure, " %f %f %f %f %f %f c", - _cairo_fixed_to_double (p1->x), - _cairo_fixed_to_double (p1->y), - _cairo_fixed_to_double (p2->x), - _cairo_fixed_to_double (p2->y), - _cairo_fixed_to_double (p3->x), - _cairo_fixed_to_double (p3->y)); + _cairo_fixed_to_double (p1->x), + _cairo_fixed_to_double (p1->y), + _cairo_fixed_to_double (p2->x), + _cairo_fixed_to_double (p2->y), + _cairo_fixed_to_double (p3->x), + _cairo_fixed_to_double (p3->y)); + return CAIRO_STATUS_SUCCESS; } @@ -418,6 +409,7 @@ static cairo_status_t _cairo_xml_close_path (void *closure) { _cairo_xml_printf_continue (closure, " h"); + return CAIRO_STATUS_SUCCESS; } @@ -436,7 +428,7 @@ _cairo_xml_emit_path (cairo_xml_t *xml, _cairo_xml_close_path, xml); assert (status == CAIRO_STATUS_SUCCESS); - _cairo_xml_printf_start (xml, ""); + _cairo_xml_printf_end (xml, ""); } static void @@ -455,12 +447,19 @@ _cairo_xml_emit_double (cairo_xml_t *xml, _cairo_xml_printf (xml, "<%s>%f", node, data, node); } +static cairo_xml_t * +to_xml (cairo_xml_surface_t *surface) +{ + return (cairo_xml_t *) surface->base.device; +} + static cairo_status_t _cairo_xml_surface_emit_clip_path (cairo_xml_surface_t *surface, cairo_clip_path_t *clip_path) { cairo_box_t box; cairo_status_t status; + cairo_xml_t *xml; if (clip_path->prev != NULL) { status = _cairo_xml_surface_emit_clip_path (surface, clip_path->prev); @@ -481,18 +480,20 @@ _cairo_xml_surface_emit_clip_path (cairo_xml_surface_t *surface, } } - _cairo_xml_printf_start (surface->xml, ""); - _cairo_xml_indent (surface->xml, 2); + xml = to_xml (surface); - _cairo_xml_emit_path (surface->xml, &clip_path->path); - _cairo_xml_emit_double (surface->xml, "tolerance", clip_path->tolerance); - _cairo_xml_emit_string (surface->xml, "antialias", + _cairo_xml_printf_start (xml, ""); + _cairo_xml_indent (xml, 2); + + _cairo_xml_emit_path (xml, &clip_path->path); + _cairo_xml_emit_double (xml, "tolerance", clip_path->tolerance); + _cairo_xml_emit_string (xml, "antialias", _antialias_to_string (clip_path->antialias)); - _cairo_xml_emit_string (surface->xml, "fill-rule", + _cairo_xml_emit_string (xml, "fill-rule", _fill_rule_to_string (clip_path->fill_rule)); - _cairo_xml_indent (surface->xml, -2); - _cairo_xml_printf_end (surface->xml, ""); + _cairo_xml_indent (xml, -2); + _cairo_xml_printf_end (xml, ""); return CAIRO_STATUS_SUCCESS; } @@ -624,7 +625,7 @@ _cairo_xml_emit_surface (cairo_xml_t *xml, cairo_status_t status; if (_cairo_surface_is_recording (source)) { - status = cairo_xml_for_recording_surface (xml, source); + status = cairo_xml_for_recording_surface (&xml->base, source); } else { cairo_image_surface_t *image; void *image_extra; @@ -694,7 +695,7 @@ _cairo_xml_surface_paint (void *abstract_surface, cairo_clip_t *clip) { cairo_xml_surface_t *surface = abstract_surface; - cairo_xml_t *xml = surface->xml; + cairo_xml_t *xml = to_xml (surface); cairo_status_t status; _cairo_xml_printf (xml, ""); @@ -724,7 +725,7 @@ _cairo_xml_surface_mask (void *abstract_surface, cairo_clip_t *clip) { cairo_xml_surface_t *surface = abstract_surface; - cairo_xml_t *xml = surface->xml; + cairo_xml_t *xml = to_xml (surface); cairo_status_t status; _cairo_xml_printf (xml, ""); @@ -755,15 +756,15 @@ _cairo_xml_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) { cairo_xml_surface_t *surface = abstract_surface; - cairo_xml_t *xml = surface->xml; + cairo_xml_t *xml = to_xml (surface); cairo_status_t status; _cairo_xml_printf (xml, ""); @@ -794,7 +795,7 @@ _cairo_xml_surface_stroke (void *abstract_surface, _cairo_xml_printf_end (xml, ""); } - _cairo_xml_emit_path (surface->xml, path); + _cairo_xml_emit_path (xml, path); _cairo_xml_emit_double (xml, "tolerance", tolerance); _cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias)); @@ -817,7 +818,7 @@ _cairo_xml_surface_fill (void *abstract_surface, cairo_clip_t *clip) { cairo_xml_surface_t *surface = abstract_surface; - cairo_xml_t *xml = surface->xml; + cairo_xml_t *xml = to_xml (surface); cairo_status_t status; _cairo_xml_printf (xml, ""); @@ -833,7 +834,7 @@ _cairo_xml_surface_fill (void *abstract_surface, if (unlikely (status)) return status; - _cairo_xml_emit_path (surface->xml, path); + _cairo_xml_emit_path (xml, path); _cairo_xml_emit_double (xml, "tolerance", tolerance); _cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias)); _cairo_xml_emit_string (xml, "fill-rule", _fill_rule_to_string (fill_rule)); @@ -957,7 +958,7 @@ _cairo_xml_surface_glyphs (void *abstract_surface, int *remaining_glyphs) { cairo_xml_surface_t *surface = abstract_surface; - cairo_xml_t *xml = surface->xml; + cairo_xml_t *xml = to_xml (surface); cairo_status_t status; int i; @@ -996,7 +997,7 @@ static const cairo_surface_backend_t _cairo_xml_surface_backend = { CAIRO_SURFACE_TYPE_XML, _cairo_xml_surface_create_similar, - _cairo_xml_surface_finish, + NULL, NULL, NULL, /* source image */ NULL, NULL, /* dst image */ NULL, /* clone_similar */ @@ -1033,81 +1034,88 @@ _cairo_xml_surface_backend = { }; static cairo_surface_t * -_cairo_xml_surface_create_internal (cairo_xml_t *xml, +_cairo_xml_surface_create_internal (cairo_device_t *device, cairo_content_t content, double width, double height) { cairo_xml_surface_t *surface; - if (unlikely (xml == NULL)) - return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER)); - surface = malloc (sizeof (cairo_xml_surface_t)); if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); _cairo_surface_init (&surface->base, &_cairo_xml_surface_backend, + device, content); - surface->xml = xml; - xml->ref++; - surface->width = width; surface->height = height; return &surface->base; } -cairo_xml_t * +cairo_device_t * cairo_xml_create (const char *filename) { cairo_output_stream_t *stream; + cairo_status_t status; stream = _cairo_output_stream_create_for_filename (filename); - if (_cairo_output_stream_get_status (stream)) - return (cairo_xml_t *) &_nil_xml; + if ((status = _cairo_output_stream_get_status (stream))) + return _cairo_device_create_in_error (status); return _cairo_xml_create_internal (stream); } -cairo_xml_t * +cairo_device_t * cairo_xml_create_for_stream (cairo_write_func_t write_func, void *closure) { cairo_output_stream_t *stream; + cairo_status_t status; stream = _cairo_output_stream_create (write_func, NULL, closure); - if (_cairo_output_stream_get_status (stream)) - return (cairo_xml_t *) &_nil_xml; + if ((status = _cairo_output_stream_get_status (stream))) + return _cairo_device_create_in_error (status); return _cairo_xml_create_internal (stream); } cairo_surface_t * -cairo_xml_surface_create (cairo_xml_t *xml, +cairo_xml_surface_create (cairo_device_t *device, cairo_content_t content, double width, double height) { - return _cairo_xml_surface_create_internal (xml, content, width, height); + if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML)) + return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + + if (unlikely (device->status)) + return _cairo_surface_create_in_error (device->status); + + return _cairo_xml_surface_create_internal (device, content, width, height); } cairo_status_t -cairo_xml_for_recording_surface (cairo_xml_t *xml, +cairo_xml_for_recording_surface (cairo_device_t *device, cairo_surface_t *recording_surface) { cairo_box_t bbox; cairo_rectangle_int_t extents; cairo_surface_t *surface; + cairo_xml_t *xml; cairo_status_t status; - if (unlikely (xml->status)) - return xml->status; + if (unlikely (device->status)) + return device->status; if (unlikely (recording_surface->status)) return recording_surface->status; + if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML)) + return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + if (unlikely (! _cairo_surface_is_recording (recording_surface))) return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); @@ -1117,13 +1125,15 @@ cairo_xml_for_recording_surface (cairo_xml_t *xml, return status; _cairo_box_round_to_rectangle (&bbox, &extents); - surface = _cairo_xml_surface_create_internal (xml, + surface = _cairo_xml_surface_create_internal (device, recording_surface->content, extents.width, extents.height); if (unlikely (surface->status)) return surface->status; + xml = (cairo_xml_t *) device; + _cairo_xml_printf (xml, "", _content_to_string (recording_surface->content), @@ -1140,14 +1150,3 @@ cairo_xml_for_recording_surface (cairo_xml_t *xml, return status; } slim_hidden_def (cairo_xml_for_recording_surface); - -void -cairo_xml_destroy (cairo_xml_t *xml) -{ - cairo_status_t status_ignored; - - if (xml == NULL || xml->ref < 0) - return; - - status_ignored = _cairo_xml_destroy_internal (xml); -} diff --git a/gfx/cairo/cairo/src/cairo-xml.h b/gfx/cairo/cairo/src/cairo-xml.h index bba8adc04111..9ae76e90aae9 100644 --- a/gfx/cairo/cairo/src/cairo-xml.h +++ b/gfx/cairo/cairo/src/cairo-xml.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -42,25 +42,20 @@ CAIRO_BEGIN_DECLS -typedef struct _cairo_xml cairo_xml_t; - -cairo_public cairo_xml_t * +cairo_public cairo_device_t * cairo_xml_create (const char *filename); -cairo_public cairo_xml_t * +cairo_public cairo_device_t * cairo_xml_create_for_stream (cairo_write_func_t write_func, void *closure); -cairo_public void -cairo_xml_destroy (cairo_xml_t *context); - cairo_public cairo_surface_t * -cairo_xml_surface_create (cairo_xml_t *xml, +cairo_xml_surface_create (cairo_device_t *xml, cairo_content_t content, double width, double height); cairo_public cairo_status_t -cairo_xml_for_recording_surface (cairo_xml_t *context, +cairo_xml_for_recording_surface (cairo_device_t *xml, cairo_surface_t *surface); CAIRO_END_DECLS diff --git a/gfx/cairo/cairo/src/cairo.c b/gfx/cairo/cairo/src/cairo.c index 69ec04ccf486..770669cdc97b 100644 --- a/gfx/cairo/cairo/src/cairo.c +++ b/gfx/cairo/cairo/src/cairo.c @@ -14,7 +14,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -40,8 +40,66 @@ #include "cairo-private.h" #include "cairo-arc-private.h" +#include "cairo-error-private.h" #include "cairo-path-private.h" +/** + * SECTION:cairo + * @Title: cairo_t + * @Short_Description: The cairo drawing context + * @See_Also: #cairo_surface_t + * + * #cairo_t is the main object used when drawing with cairo. To + * draw with cairo, you create a #cairo_t, set the target surface, + * and drawing options for the #cairo_t, create shapes with + * functions like cairo_move_to() and cairo_line_to(), and then + * draw shapes with cairo_stroke() or cairo_fill(). + * + * #cairo_t's can be pushed to a stack via cairo_save(). + * They may then safely be changed, without loosing the current state. + * Use cairo_restore() to restore to the saved state. + */ + +/** + * SECTION:cairo-text + * @Title: text + * @Short_Description: Rendering text and glyphs + * @See_Also: #cairo_font_face_t, #cairo_scaled_font_t, cairo_text_path(), + * cairo_glyph_path() + * + * The functions with text in their name form cairo's + * toy text API. The toy API takes UTF-8 encoded + * text and is limited in its functionality to rendering simple + * left-to-right text with no advanced features. That means for example + * that most complex scripts like Hebrew, Arabic, and Indic scripts are + * out of question. No kerning or correct positioning of diacritical marks + * either. The font selection is pretty limited too and doesn't handle the + * case that the selected font does not cover the characters in the text. + * This set of functions are really that, a toy text API, for testing and + * demonstration purposes. Any serious application should avoid them. + * + * The functions with glyphs in their name form cairo's + * low-level text API. The low-level API relies on + * the user to convert text to a set of glyph indexes and positions. This + * is a very hard problem and is best handled by external libraries, like + * the pangocairo that is part of the Pango text layout and rendering library. + * Pango is available from http://www.pango.org/. + */ + +/** + * SECTION:cairo-transforms + * @Title: Transformations + * @Short_Description: Manipulating the current transformation matrix + * @See_Also: #cairo_matrix_t + * + * The current transformation matrix, ctm, is a + * two-dimensional affine transformation that maps all coordinates and other + * drawing instruments from the user space into the + * surface's canonical coordinate system, also known as the device + * space. + */ + #define CAIRO_TOLERANCE_MINIMUM _cairo_fixed_to_double(1) #if !defined(INFINITY) @@ -59,14 +117,36 @@ static const cairo_t _cairo_nil = { { 0, 0 }, /* last_move_point */ { 0, 0 }, /* current point */ FALSE, /* has_current_point */ + FALSE, /* has_last_move_point */ FALSE, /* has_curve_to */ FALSE, /* is_box */ FALSE, /* maybe_fill_region */ TRUE, /* is_empty_fill */ + { {0, 0}, {0, 0}}, /* extents */ {{{NULL,NULL}}} /* link */ }} }; +static const cairo_t _cairo_nil__null_pointer = { + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + CAIRO_STATUS_NULL_POINTER, /* status */ + { 0, 0, 0, NULL }, /* user_data */ + NULL, /* gstate */ + {{ 0 }, { 0 }}, /* gstate_tail */ + NULL, /* gstate_freelist */ + {{ /* path */ + { 0, 0 }, /* last_move_point */ + { 0, 0 }, /* current point */ + FALSE, /* has_current_point */ + FALSE, /* has_last_move_point */ + FALSE, /* has_curve_to */ + FALSE, /* is_box */ + FALSE, /* maybe_fill_region */ + TRUE, /* is_empty_fill */ + { {0, 0}, {0, 0}}, /* extents */ + {{{NULL,NULL}}} /* link */ + }} +}; #include /** @@ -119,25 +199,9 @@ _cairo_set_error (cairo_t *cr, cairo_status_t status) _cairo_status_set_error (&cr->status, _cairo_error (status)); } -#if defined(_MSC_VER) -#include -#pragma intrinsic(_BitScanForward) -static __forceinline int -ffs(int x) -{ - unsigned long i; - - if (_BitScanForward(&i, x) != 0) - return i + 1; - - return 0; -} -#endif - - -#if CAIRO_NO_MUTEX /* We keep a small stash of contexts to reduce malloc pressure */ #define CAIRO_STASH_SIZE 4 +#if CAIRO_NO_MUTEX static struct { cairo_t pool[CAIRO_STASH_SIZE]; int occupied; @@ -146,24 +210,19 @@ static struct { static cairo_t * _context_get (void) { - int avail, old, new; + int avail; - old = _context_stash.occupied; - avail = ffs (~old) - 1; + avail = ffs (~_context_stash.occupied) - 1; if (avail >= CAIRO_STASH_SIZE) return malloc (sizeof (cairo_t)); - new = old | (1 << avail); - _context_stash.occupied = new; - + _context_stash.occupied |= 1 << avail; return &_context_stash.pool[avail]; } static void _context_put (cairo_t *cr) { - int old, new, avail; - if (cr < &_context_stash.pool[0] || cr >= &_context_stash.pool[CAIRO_STASH_SIZE]) { @@ -171,14 +230,9 @@ _context_put (cairo_t *cr) return; } - avail = ~(1 << (cr - &_context_stash.pool[0])); - old = _context_stash.occupied; - new = old & avail; - _context_stash.occupied = new; + _context_stash.occupied &= ~(1 << (cr - &_context_stash.pool[0])); } #elif HAS_ATOMIC_OPS -/* We keep a small stash of contexts to reduce malloc pressure */ -#define CAIRO_STASH_SIZE 4 static struct { cairo_t pool[CAIRO_STASH_SIZE]; cairo_atomic_int_t occupied; @@ -196,7 +250,7 @@ _context_get (void) return malloc (sizeof (cairo_t)); new = old | (1 << avail); - } while (_cairo_atomic_int_cmpxchg (&_context_stash.occupied, old, new) != old); + } while (! _cairo_atomic_int_cmpxchg (&_context_stash.occupied, old, new)); return &_context_stash.pool[avail]; } @@ -217,13 +271,68 @@ _context_put (cairo_t *cr) do { old = _cairo_atomic_int_get (&_context_stash.occupied); new = old & avail; - } while (_cairo_atomic_int_cmpxchg (&_context_stash.occupied, old, new) != old); + } while (! _cairo_atomic_int_cmpxchg (&_context_stash.occupied, old, new)); } #else #define _context_get() malloc (sizeof (cairo_t)) #define _context_put(cr) free (cr) #endif +/* XXX This should disappear in favour of a common pool of error objects. */ +static cairo_t *_cairo_nil__objects[CAIRO_STATUS_LAST_STATUS + 1]; + +static cairo_t * +_cairo_create_in_error (cairo_status_t status) +{ + cairo_t *cr; + + assert (status != CAIRO_STATUS_SUCCESS); + + /* special case OOM in order to avoid another allocation */ + switch ((int) status) { + case CAIRO_STATUS_NO_MEMORY: + return (cairo_t *) &_cairo_nil; + case CAIRO_STATUS_NULL_POINTER: + return (cairo_t *) &_cairo_nil__null_pointer; + } + + CAIRO_MUTEX_LOCK (_cairo_error_mutex); + cr = _cairo_nil__objects[status]; + if (cr == NULL) { + cr = malloc (sizeof (cairo_t)); + if (unlikely (cr == NULL)) { + CAIRO_MUTEX_UNLOCK (_cairo_error_mutex); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_t *) &_cairo_nil; + } + + *cr = _cairo_nil; + cr->status = status; + _cairo_nil__objects[status] = cr; + } + CAIRO_MUTEX_UNLOCK (_cairo_error_mutex); + + return cr; +} + +void +_cairo_reset_static_data (void) +{ + int status; + + CAIRO_MUTEX_LOCK (_cairo_error_mutex); + for (status = CAIRO_STATUS_SUCCESS; + status <= CAIRO_STATUS_LAST_STATUS; + status++) + { + if (_cairo_nil__objects[status] != NULL) { + free (_cairo_nil__objects[status]); + _cairo_nil__objects[status] = NULL; + } + } + CAIRO_MUTEX_UNLOCK (_cairo_error_mutex); +} + /** * cairo_create: * @target: target surface for the context @@ -253,15 +362,14 @@ cairo_create (cairo_surface_t *target) cairo_t *cr; cairo_status_t status; - /* special case OOM in order to avoid another allocation */ - if (target && target->status == CAIRO_STATUS_NO_MEMORY) - return (cairo_t *) &_cairo_nil; + if (unlikely (target == NULL)) + return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER)); + if (unlikely (target->status)) + return _cairo_create_in_error (target->status); cr = _context_get (); - if (unlikely (cr == NULL)) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - return (cairo_t *) &_cairo_nil; - } + if (unlikely (cr == NULL)) + return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); CAIRO_REFERENCE_COUNT_INIT (&cr->ref_count, 1); @@ -275,8 +383,10 @@ cairo_create (cairo_surface_t *target) cr->gstate_tail[1].next = NULL; status = _cairo_gstate_init (cr->gstate, target); - if (unlikely (status)) - _cairo_set_error (cr, status); + if (unlikely (status)) { + _context_put (cr); + cr = _cairo_create_in_error (status); + } return cr; } @@ -355,6 +465,9 @@ cairo_destroy (cairo_t *cr) _cairo_user_data_array_fini (&cr->user_data); + /* mark the context as invalid to protect against misuse */ + cr->status = CAIRO_STATUS_NULL_POINTER; + _context_put (cr); } slim_hidden_def (cairo_destroy); @@ -556,54 +669,59 @@ cairo_push_group (cairo_t *cr) void cairo_push_group_with_content (cairo_t *cr, cairo_content_t content) { + cairo_surface_t *group_surface; + cairo_clip_t *clip; cairo_status_t status; - cairo_rectangle_int_t extents; - const cairo_rectangle_int_t *clip_extents; - cairo_surface_t *parent_surface, *group_surface = NULL; - cairo_bool_t is_empty; if (unlikely (cr->status)) return; - parent_surface = _cairo_gstate_get_target (cr->gstate); - - /* Get the extents that we'll use in creating our new group surface */ - _cairo_surface_get_extents (parent_surface, &extents); - - if (_cairo_gstate_get_clip (cr->gstate)->all_clipped) { - extents.width = 0; - extents.height = 0; + clip = _cairo_gstate_get_clip (cr->gstate); + if (clip->all_clipped) { + group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); + status = group_surface->status; + if (unlikely (status)) + goto bail; } else { + cairo_surface_t *parent_surface; + const cairo_rectangle_int_t *clip_extents; + cairo_rectangle_int_t extents; + cairo_matrix_t matrix; + cairo_bool_t is_empty; + + parent_surface = _cairo_gstate_get_target (cr->gstate); + + /* Get the extents that we'll use in creating our new group surface */ + is_empty = _cairo_surface_get_extents (parent_surface, &extents); clip_extents = _cairo_clip_get_extents (_cairo_gstate_get_clip (cr->gstate)); if (clip_extents != NULL) - _cairo_rectangle_intersect (&extents, clip_extents); + is_empty = _cairo_rectangle_intersect (&extents, clip_extents); + + group_surface = _cairo_surface_create_similar_solid (parent_surface, + content, + extents.width, + extents.height, + CAIRO_COLOR_TRANSPARENT, + TRUE); + status = group_surface->status; + if (unlikely (status)) + goto bail; + + /* Set device offsets on the new surface so that logically it appears at + * the same location on the parent surface -- when we pop_group this, + * the source pattern will get fixed up for the appropriate target surface + * device offsets, so we want to set our own surface offsets from /that/, + * and not from the device origin. */ + cairo_surface_set_device_offset (group_surface, + parent_surface->device_transform.x0 - extents.x, + parent_surface->device_transform.y0 - extents.y); + + /* If we have a current path, we need to adjust it to compensate for + * the device offset just applied. */ + cairo_matrix_init_translate (&matrix, -extents.x, -extents.y); + _cairo_path_fixed_transform (cr->path, &matrix); } - group_surface = _cairo_surface_create_similar_solid (parent_surface, - content, - extents.width, - extents.height, - CAIRO_COLOR_TRANSPARENT, - TRUE); - - status = group_surface->status; - if (unlikely (status)) - goto bail; - - /* Set device offsets on the new surface so that logically it appears at - * the same location on the parent surface -- when we pop_group this, - * the source pattern will get fixed up for the appropriate target surface - * device offsets, so we want to set our own surface offsets from /that/, - * and not from the device origin. */ - cairo_surface_set_device_offset (group_surface, - parent_surface->device_transform.x0 - extents.x, - parent_surface->device_transform.y0 - extents.y); - - /* If we have a current path, we need to adjust it to compensate for - * the device offset just applied. */ - _cairo_path_fixed_transform (cr->path, - &group_surface->device_transform); - /* create a new gstate for the redirect */ cairo_save (cr); if (unlikely (cr->status)) @@ -644,7 +762,7 @@ cairo_pop_group (cairo_t *cr) { cairo_surface_t *group_surface, *parent_target; cairo_pattern_t *group_pattern; - cairo_matrix_t group_matrix; + cairo_matrix_t group_matrix, device_transform_matrix; cairo_status_t status; if (unlikely (cr->status)) @@ -693,8 +811,10 @@ cairo_pop_group (cairo_t *cr) /* If we have a current path, we need to adjust it to compensate for * the device offset just removed. */ - _cairo_path_fixed_transform (cr->path, - &group_surface->device_transform_inverse); + cairo_matrix_multiply (&device_transform_matrix, + &_cairo_gstate_get_target (cr->gstate)->device_transform, + &group_surface->device_transform_inverse); + _cairo_path_fixed_transform (cr->path, &device_transform_matrix); done: cairo_surface_destroy (group_surface); @@ -880,7 +1000,7 @@ cairo_set_source_rgba (cairo_t *cr, * The @x and @y parameters give the user-space coordinate at which * the surface origin should appear. (The surface origin is its * upper-left corner before any transformation has been applied.) The - * @x and @y patterns are negated and then set as translation values + * @x and @y parameters are negated and then set as translation values * in the pattern matrix. * * Other than the initial translation pattern matrix, as described @@ -2147,12 +2267,13 @@ cairo_paint_with_alpha (cairo_t *cr, return; } - if (CAIRO_ALPHA_IS_ZERO (alpha)) { + if (CAIRO_ALPHA_IS_ZERO (alpha) && + _cairo_operator_bounded_by_mask (cr->gstate->op)) { return; } - _cairo_color_init_rgba (&color, 1., 1., 1., alpha); - _cairo_pattern_init_solid (&pattern, &color, CAIRO_CONTENT_ALPHA); + _cairo_color_init_rgba (&color, 0., 0., 0., alpha); + _cairo_pattern_init_solid (&pattern, &color); status = _cairo_gstate_mask (cr->gstate, &pattern.base); if (unlikely (status)) @@ -3454,7 +3575,6 @@ cairo_show_text_glyphs (cairo_t *cr, { cairo_status_t status; - if (unlikely (cr->status)) return; diff --git a/gfx/cairo/cairo/src/cairo.h b/gfx/cairo/cairo/src/cairo.h index b149bd7ecea3..6abc60016efa 100644 --- a/gfx/cairo/cairo/src/cairo.h +++ b/gfx/cairo/cairo/src/cairo.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -146,6 +146,24 @@ typedef struct _cairo cairo_t; **/ typedef struct _cairo_surface cairo_surface_t; +/** + * cairo_device_t: + * + * A #cairo_device_t represents the driver interface for drawing + * operations to a #cairo_surface_t. There are different subtypes of + * #cairo_device_t for different drawing backends; for example, + * cairo_xcb_device_create() creates a device that wraps the connection + * to an X Windows System using the XCB library. + * + * The type of a device can be queried with cairo_device_get_type(). + * + * Memory management of #cairo_device_t is done with + * cairo_device_reference() and cairo_device_destroy(). + * + * Since: 1.10 + **/ +typedef struct _cairo_device cairo_device_t; + /** * cairo_matrix_t: * @xx: xx component of the affine transformation @@ -250,6 +268,8 @@ typedef struct _cairo_user_data_key { * @CAIRO_STATUS_INVALID_WEIGHT: invalid value for an input #cairo_font_weight_t (Since 1.8) * @CAIRO_STATUS_INVALID_SIZE: invalid value (typically too big) for the size of the input (surface, pattern, etc.) (Since 1.10) * @CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: user-font method not implemented (Since 1.10) + * @CAIRO_STATUS_DEVICE_TYPE_MISMATCH: the device type is not appropriate for the operation (Since 1.10) + * @CAIRO_STATUS_DEVICE_ERROR: an operation to the device caused an unspecified error (Since 1.10) * @CAIRO_STATUS_LAST_STATUS: this is a special value indicating the number of * status values defined in this enumeration. When using this value, note * that the version of cairo at run-time may have additional status values @@ -299,6 +319,8 @@ typedef enum _cairo_status { CAIRO_STATUS_INVALID_WEIGHT, CAIRO_STATUS_INVALID_SIZE, CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, + CAIRO_STATUS_DEVICE_TYPE_MISMATCH, + CAIRO_STATUS_DEVICE_ERROR, CAIRO_STATUS_NO_DEVICE, CAIRO_STATUS_LAST_STATUS @@ -1914,6 +1936,83 @@ cairo_status (cairo_t *cr); cairo_public const char * cairo_status_to_string (cairo_status_t status); +/* Backend device manipulation */ + +cairo_public cairo_device_t * +cairo_device_reference (cairo_device_t *device); + +/** + * cairo_device_type_t: + * @CAIRO_DEVICE_TYPE_DRM: The surface is of type Direct Render Manager + * @CAIRO_DEVICE_TYPE_GL: The surface is of type OpenGL + * @CAIRO_DEVICE_TYPE_SCRIPT: The surface is of type script + * @CAIRO_DEVICE_TYPE_XCB: The surface is of type xcb + * @CAIRO_DEVICE_TYPE_XLIB: The surface is of type xlib + * @CAIRO_DEVICE_TYPE_XML: The surface is of type XML + * cairo_surface_create_for_rectangle() + * + * #cairo_device_type_t is used to describe the type of a given + * device. The devices types are also known as "backends" within cairo. + * + * The device type can be queried with cairo_device_get_type() + * + * The various #cairo_device_t functions can be used with surfaces of + * any type, but some backends also provide type-specific functions + * that must only be called with a device of the appropriate + * type. These functions have names that begin with + * cairo_type_device such as cairo_xcb_device_debug_set_render_version(). + * + * The behavior of calling a type-specific function with a surface of + * the wrong type is undefined. + * + * New entries may be added in future versions. + * + * Since: 1.10 + **/ +typedef enum _cairo_device_type { + CAIRO_DEVICE_TYPE_DRM, + CAIRO_DEVICE_TYPE_GL, + CAIRO_DEVICE_TYPE_SCRIPT, + CAIRO_DEVICE_TYPE_XCB, + CAIRO_DEVICE_TYPE_XLIB, + CAIRO_DEVICE_TYPE_XML +} cairo_device_type_t; + +cairo_public cairo_device_type_t +cairo_device_get_type (cairo_device_t *device); + +cairo_public cairo_status_t +cairo_device_status (cairo_device_t *device); + +cairo_public cairo_status_t +cairo_device_acquire (cairo_device_t *device); + +cairo_public void +cairo_device_release (cairo_device_t *device); + +cairo_public void +cairo_device_flush (cairo_device_t *device); + +cairo_public void +cairo_device_finish (cairo_device_t *device); + +cairo_public void +cairo_device_destroy (cairo_device_t *device); + +cairo_public unsigned int +cairo_device_get_reference_count (cairo_device_t *device); + +cairo_public void * +cairo_device_get_user_data (cairo_device_t *device, + const cairo_user_data_key_t *key); + +cairo_public cairo_status_t +cairo_device_set_user_data (cairo_device_t *device, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy); + + /* Surface manipulation */ cairo_public cairo_surface_t * @@ -1922,6 +2021,13 @@ cairo_surface_create_similar (cairo_surface_t *other, int width, int height); +cairo_public cairo_surface_t * +cairo_surface_create_for_rectangle (cairo_surface_t *target, + double x, + double y, + double width, + double height); + cairo_public cairo_surface_t * cairo_surface_reference (cairo_surface_t *surface); @@ -1931,6 +2037,9 @@ cairo_surface_finish (cairo_surface_t *surface); cairo_public void cairo_surface_destroy (cairo_surface_t *surface); +cairo_public cairo_device_t * +cairo_surface_get_device (cairo_surface_t *surface); + cairo_public unsigned int cairo_surface_get_reference_count (cairo_surface_t *surface); @@ -1962,6 +2071,9 @@ cairo_surface_status (cairo_surface_t *surface); * @CAIRO_SURFACE_TYPE_TEE: The surface is of type 'tee' (a multiplexing surface), since 1.10 * @CAIRO_SURFACE_TYPE_XML: The surface is of type XML (for debugging), since 1.10 * @CAIRO_SURFACE_TYPE_SKIA: The surface is of type Skia, since 1.10 + * @CAIRO_SURFACE_TYPE_SUBSURFACE: The surface is a subsurface created with + * cairo_surface_create_for_rectangle(), since 1.10 + * @CAIRO_SURFACE_TYPE_D2D: The surface is of type Direct2D * * #cairo_surface_type_t is used to describe the type of a given * surface. The surface types are also known as "backends" or "surface @@ -2010,6 +2122,7 @@ typedef enum _cairo_surface_type { CAIRO_SURFACE_TYPE_TEE, CAIRO_SURFACE_TYPE_XML, CAIRO_SURFACE_TYPE_SKIA, + CAIRO_SURFACE_TYPE_SUBSURFACE, CAIRO_SURFACE_TYPE_D2D } cairo_surface_type_t; @@ -2045,18 +2158,19 @@ cairo_surface_set_user_data (cairo_surface_t *surface, #define CAIRO_MIME_TYPE_JPEG "image/jpeg" #define CAIRO_MIME_TYPE_PNG "image/png" #define CAIRO_MIME_TYPE_JP2 "image/jp2" +#define CAIRO_MIME_TYPE_URI "text/x-uri" cairo_public void cairo_surface_get_mime_data (cairo_surface_t *surface, const char *mime_type, const unsigned char **data, - unsigned int *length); + unsigned long *length); cairo_public cairo_status_t cairo_surface_set_mime_data (cairo_surface_t *surface, const char *mime_type, const unsigned char *data, - unsigned int length, + unsigned long length, cairo_destroy_func_t destroy, void *closure); @@ -2129,6 +2243,7 @@ cairo_surface_get_subpixel_antialiasing (cairo_surface_t *surface); /** * cairo_format_t: + * @CAIRO_FORMAT_INVALID: no such format exists or is supported. * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with * alpha in the upper 8 bits, then red, then green, then blue. * The 32-bit quantities are stored native-endian. Pre-multiplied @@ -2145,9 +2260,9 @@ cairo_surface_get_subpixel_antialiasing (cairo_surface_t *surface); * endianess of the platform. On a big-endian machine, the * first pixel is in the uppermost bit, on a little-endian * machine the first pixel is in the least-significant bit. - * @CAIRO_FORMAT_RGB16_565: This format value is deprecated. It has - * never been properly implemented in cairo and should not be used - * by applications. (since 1.2) + * @CAIRO_FORMAT_RGB16_565: each pixel is a 16-bit quantity + * with red in the upper 5 bits, then green in the middle + * 6 bits, and blue in the lower 5 bits. * * #cairo_format_t is used to identify the memory format of * image data. @@ -2155,11 +2270,12 @@ cairo_surface_get_subpixel_antialiasing (cairo_surface_t *surface); * New entries may be added in future versions. **/ typedef enum _cairo_format { - CAIRO_FORMAT_ARGB32, - CAIRO_FORMAT_RGB24, - CAIRO_FORMAT_A8, - CAIRO_FORMAT_A1, - CAIRO_FORMAT_RGB16_565 + CAIRO_FORMAT_INVALID = -1, + CAIRO_FORMAT_ARGB32 = 0, + CAIRO_FORMAT_RGB24 = 1, + CAIRO_FORMAT_A8 = 2, + CAIRO_FORMAT_A1 = 3, + CAIRO_FORMAT_RGB16_565 = 4 } cairo_format_t; cairo_public cairo_surface_t * @@ -2217,23 +2333,6 @@ cairo_recording_surface_ink_extents (cairo_surface_t *surface, double *width, double *height); -/* Tee-surface functions */ - -cairo_public cairo_surface_t * -cairo_tee_surface_create (cairo_surface_t *master); - -cairo_public void -cairo_tee_surface_add (cairo_surface_t *surface, - cairo_surface_t *target); - -cairo_public void -cairo_tee_surface_remove (cairo_surface_t *surface, - cairo_surface_t *target); - -cairo_public cairo_surface_t * -cairo_tee_surface_index (cairo_surface_t *surface, - int index); - /* Pattern creation functions */ cairo_public cairo_pattern_t * @@ -2482,8 +2581,33 @@ cairo_matrix_transform_point (const cairo_matrix_t *matrix, /* Region functions */ +/** + * cairo_region_t: + * + * A #cairo_region_t represents a set of integer-aligned rectangles. + * + * It allows set-theoretical operations like cairo_region_union() and + * cairo_region_intersect() to be performed on them. + * + * Memory management of #cairo_region_t is done with + * cairo_region_reference() and cairo_region_destroy(). + * + * Since: 1.10 + **/ typedef struct _cairo_region cairo_region_t; +/** + * cairo_rectangle_int_t: + * @x: X coordinate of the left side of the rectangle + * @y: Y coordinate of the the top side of the rectangle + * @width: width of the rectangle + * @height: height of the rectangle + * + * A data structure for holding a rectangle with integer coordinates. + * + * Since: 1.10 + **/ + typedef struct _cairo_rectangle_int { int x, y; int width, height; @@ -2509,7 +2633,7 @@ cairo_public cairo_region_t * cairo_region_copy (const cairo_region_t *original); cairo_public cairo_region_t * -cairo_region_reference (cairo_region_t *); +cairo_region_reference (cairo_region_t *region); cairo_public void cairo_region_destroy (cairo_region_t *region); @@ -2528,8 +2652,8 @@ cairo_public int cairo_region_num_rectangles (const cairo_region_t *region); cairo_public void -cairo_region_get_rectangle (const cairo_region_t *region, - int nth_rectangle, +cairo_region_get_rectangle (const cairo_region_t *region, + int nth, cairo_rectangle_int_t *rectangle); cairo_public cairo_bool_t @@ -2553,19 +2677,25 @@ cairo_region_subtract_rectangle (cairo_region_t *dst, const cairo_rectangle_int_t *rectangle); cairo_public cairo_status_t -cairo_region_intersect (cairo_region_t *dst, cairo_region_t *other); +cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other); cairo_public cairo_status_t cairo_region_intersect_rectangle (cairo_region_t *dst, const cairo_rectangle_int_t *rectangle); cairo_public cairo_status_t -cairo_region_union (cairo_region_t *dst, cairo_region_t *other); +cairo_region_union (cairo_region_t *dst, const cairo_region_t *other); cairo_public cairo_status_t cairo_region_union_rectangle (cairo_region_t *dst, const cairo_rectangle_int_t *rectangle); +cairo_public cairo_status_t +cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other); + +cairo_public cairo_status_t +cairo_region_xor_rectangle (cairo_region_t *dst, + const cairo_rectangle_int_t *rectangle); /* Functions to be used while debugging (not intended for use in production code) */ cairo_public void diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h index e0127e8c90f0..594c91d3c588 100644 --- a/gfx/cairo/cairo/src/cairoint.h +++ b/gfx/cairo/cairo/src/cairoint.h @@ -13,7 +13,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -139,33 +139,27 @@ _cairo_win32_tmpfile (void); }) #else #define cairo_container_of(ptr, type, member) \ - (type *)((char *) (ptr) - (char *) &((type *)0)->member) + ((type *)((char *) (ptr) - (char *) &((type *)0)->member)) #endif -/* Size in bytes of buffer to use off the stack per functions. - * Mostly used by text functions. For larger allocations, they'll - * malloc(). */ -#ifndef CAIRO_STACK_BUFFER_SIZE -#define CAIRO_STACK_BUFFER_SIZE (512 * sizeof (int)) -#endif - -#define CAIRO_STACK_ARRAY_LENGTH(T) (CAIRO_STACK_BUFFER_SIZE / sizeof(T)) - #define ASSERT_NOT_REACHED \ do { \ - static const int NOT_REACHED = 0; \ - assert (NOT_REACHED); \ + assert (!"reached"); \ } while (0) #define COMPILE_TIME_ASSERT1(condition, line) \ typedef int compile_time_assertion_at_line_##line##_failed [(condition)?1:-1] #define COMPILE_TIME_ASSERT0(condition, line) COMPILE_TIME_ASSERT1(condition, line) #define COMPILE_TIME_ASSERT(condition) COMPILE_TIME_ASSERT0(condition, __LINE__) +#define CAIRO_ALPHA_IS_CLEAR(alpha) ((alpha) <= ((double)0x00ff / (double)0xffff)) +#define CAIRO_ALPHA_SHORT_IS_CLEAR(alpha) ((alpha) <= 0x00ff) + #define CAIRO_ALPHA_IS_OPAQUE(alpha) ((alpha) >= ((double)0xff00 / (double)0xffff)) #define CAIRO_ALPHA_SHORT_IS_OPAQUE(alpha) ((alpha) >= 0xff00) #define CAIRO_ALPHA_IS_ZERO(alpha) ((alpha) <= 0.0) +#define CAIRO_COLOR_IS_CLEAR(color) CAIRO_ALPHA_SHORT_IS_CLEAR ((color)->alpha_short) #define CAIRO_COLOR_IS_OPAQUE(color) CAIRO_ALPHA_SHORT_IS_OPAQUE ((color)->alpha_short) /* Reverse the bits in a byte with 7 operations (no 64-bit): @@ -305,13 +299,6 @@ cairo_private cairo_bool_t _cairo_box_contains_point (cairo_box_t *box, const cairo_point_t *point) cairo_pure; -cairo_private void -_cairo_composite_rectangles_init (cairo_composite_rectangles_t *rects, - int all_x, - int all_y, - int width, - int height); - /* cairo-array.c structures and functions */ cairo_private void @@ -398,32 +385,6 @@ _cairo_hash_bytes (unsigned long hash, const void *bytes, unsigned int length); -/* - * A #cairo_unscaled_font_t is just an opaque handle we use in the - * glyph cache. - */ -typedef struct _cairo_unscaled_font { - cairo_hash_entry_t hash_entry; - cairo_reference_count_t ref_count; - const cairo_unscaled_font_backend_t *backend; -} cairo_unscaled_font_t; - -typedef struct _cairo_scaled_glyph { - cairo_hash_entry_t hash_entry; - - cairo_text_extents_t metrics; /* user-space metrics */ - cairo_text_extents_t fs_metrics; /* font-space metrics */ - cairo_box_t bbox; /* device-space bounds */ - int16_t x_advance; /* device-space rounded X advance */ - int16_t y_advance; /* device-space rounded Y advance */ - - cairo_image_surface_t *surface; /* device-space image */ - cairo_path_fixed_t *path; /* device-space outline */ - cairo_surface_t *recording_surface; /* device-space recording-surface */ - - void *surface_private; /* for the surface backend */ -} cairo_scaled_glyph_t; - #define _cairo_scaled_glyph_index(g) ((g)->hash_entry.hash) #define _cairo_scaled_glyph_set_index(g, i) ((g)->hash_entry.hash = (i)) @@ -438,6 +399,9 @@ struct _cairo_font_face { const cairo_font_face_backend_t *backend; }; +cairo_private void +_cairo_reset_static_data (void); + cairo_private void _cairo_toy_font_face_reset_static_data (void); @@ -797,9 +761,9 @@ struct _cairo_surface_backend { cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip); @@ -829,8 +793,7 @@ struct _cairo_surface_backend { cairo_bool_t (*is_similar) (void *surface_a, - void *surface_b, - cairo_content_t content); + void *surface_b); cairo_warn cairo_int_status_t (*fill_stroke) (void *surface, @@ -842,9 +805,9 @@ struct _cairo_surface_backend { cairo_path_fixed_t *path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *stroke_ctm, - cairo_matrix_t *stroke_ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, cairo_clip_t *clip); @@ -892,7 +855,6 @@ struct _cairo_image_surface { int depth; pixman_image_t *pixman_image; - cairo_region_t *clip_region; unsigned owns_data : 1; unsigned transparency : 2; @@ -904,8 +866,9 @@ extern const cairo_private cairo_surface_backend_t _cairo_image_surface_backend; #define CAIRO_EXTEND_GRADIENT_DEFAULT CAIRO_EXTEND_PAD #define CAIRO_FILTER_DEFAULT CAIRO_FILTER_GOOD +extern const cairo_private cairo_solid_pattern_t _cairo_pattern_clear; extern const cairo_private cairo_solid_pattern_t _cairo_pattern_black; - +extern const cairo_private cairo_solid_pattern_t _cairo_pattern_white; typedef struct _cairo_surface_attributes { cairo_matrix_t matrix; @@ -1011,303 +974,15 @@ _cairo_round (double r) return floor (r + .5); } +#if DISABLE_SOME_FLOATING_POINT cairo_private int _cairo_lround (double d) cairo_const; +#else +#define _cairo_lround lround +#endif -/* cairo-gstate.c */ -cairo_private cairo_status_t -_cairo_gstate_init (cairo_gstate_t *gstate, - cairo_surface_t *target); - -cairo_private void -_cairo_gstate_fini (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist); - -cairo_private cairo_status_t -_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist); - -cairo_private cairo_bool_t -_cairo_gstate_is_redirected (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child); - -cairo_private cairo_surface_t * -_cairo_gstate_get_target (cairo_gstate_t *gstate); - -cairo_private cairo_surface_t * -_cairo_gstate_get_parent_target (cairo_gstate_t *gstate); - -cairo_private cairo_surface_t * -_cairo_gstate_get_original_target (cairo_gstate_t *gstate); - -cairo_private cairo_clip_t * -_cairo_gstate_get_clip (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_t *source); - -cairo_private cairo_pattern_t * -_cairo_gstate_get_source (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op); - -cairo_private cairo_operator_t -_cairo_gstate_get_operator (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance); - -cairo_private double -_cairo_gstate_get_tolerance (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule); - -cairo_private cairo_fill_rule_t -_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width); - -cairo_private double -_cairo_gstate_get_line_width (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap); - -cairo_private cairo_line_cap_t -_cairo_gstate_get_line_cap (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join); - -cairo_private cairo_line_join_t -_cairo_gstate_get_line_join (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset); - -cairo_private void -_cairo_gstate_get_dash (cairo_gstate_t *gstate, double *dash, int *num_dashes, double *offset); - -cairo_private cairo_status_t -_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit); - -cairo_private double -_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate); - -cairo_private void -_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix); - -cairo_private cairo_status_t -_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty); - -cairo_private cairo_status_t -_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy); - -cairo_private cairo_status_t -_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle); - -cairo_private cairo_status_t -_cairo_gstate_transform (cairo_gstate_t *gstate, - const cairo_matrix_t *matrix); - -cairo_private cairo_status_t -_cairo_gstate_set_matrix (cairo_gstate_t *gstate, - const cairo_matrix_t *matrix); - -cairo_private void -_cairo_gstate_identity_matrix (cairo_gstate_t *gstate); - -cairo_private void -_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y); - -cairo_private void -_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, double *dx, double *dy); - -cairo_private void -_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y); - -cairo_private void -_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, double *dx, double *dy); - -cairo_private void -_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y); - -cairo_private void -_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y); - -cairo_private void -_cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate, - double *x1, double *y1, - double *x2, double *y2, - cairo_bool_t *is_tight); - -cairo_private void -_cairo_gstate_path_extents (cairo_gstate_t *gstate, - cairo_path_fixed_t *path, - double *x1, double *y1, - double *x2, double *y2); - -cairo_private cairo_status_t -_cairo_gstate_paint (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_mask (cairo_gstate_t *gstate, - cairo_pattern_t *mask); - -cairo_private cairo_status_t -_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path); - -cairo_private cairo_status_t -_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path); - -cairo_private cairo_status_t -_cairo_gstate_copy_page (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_show_page (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_stroke_extents (cairo_gstate_t *gstate, - cairo_path_fixed_t *path, - double *x1, double *y1, - double *x2, double *y2); - -cairo_private cairo_status_t -_cairo_gstate_fill_extents (cairo_gstate_t *gstate, - cairo_path_fixed_t *path, - double *x1, double *y1, - double *x2, double *y2); - -cairo_private cairo_status_t -_cairo_gstate_in_stroke (cairo_gstate_t *gstate, - cairo_path_fixed_t *path, - double x, - double y, - cairo_bool_t *inside_ret); - -cairo_private cairo_bool_t -_cairo_gstate_in_fill (cairo_gstate_t *gstate, - cairo_path_fixed_t *path, - double x, - double y); - -cairo_private cairo_bool_t -_cairo_gstate_in_clip (cairo_gstate_t *gstate, - double x, - double y); - -cairo_private cairo_status_t -_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path); - -cairo_private cairo_status_t -_cairo_gstate_reset_clip (cairo_gstate_t *gstate); - -cairo_private cairo_bool_t -_cairo_gstate_clip_extents (cairo_gstate_t *gstate, - double *x1, - double *y1, - double *x2, - double *y2); - -cairo_private cairo_rectangle_list_t* -_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate); - -cairo_private cairo_status_t -_cairo_gstate_show_surface (cairo_gstate_t *gstate, - cairo_surface_t *surface, - double x, - double y, - double width, - double height); - -cairo_private cairo_status_t -_cairo_gstate_select_font_face (cairo_gstate_t *gstate, - const char *family, - cairo_font_slant_t slant, - cairo_font_weight_t weight); - -cairo_private cairo_status_t -_cairo_gstate_set_font_size (cairo_gstate_t *gstate, - double size); - -cairo_private void -_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate, - cairo_matrix_t *matrix); - -cairo_private cairo_status_t -_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate, - const cairo_matrix_t *matrix); - -cairo_private void -_cairo_gstate_get_font_options (cairo_gstate_t *gstate, - cairo_font_options_t *options); - -cairo_private void -_cairo_gstate_set_font_options (cairo_gstate_t *gstate, - const cairo_font_options_t *options); - -cairo_private cairo_status_t -_cairo_gstate_get_font_face (cairo_gstate_t *gstate, - cairo_font_face_t **font_face); - -cairo_private cairo_status_t -_cairo_gstate_get_scaled_font (cairo_gstate_t *gstate, - cairo_scaled_font_t **scaled_font); - -cairo_private cairo_status_t -_cairo_gstate_get_font_extents (cairo_gstate_t *gstate, - cairo_font_extents_t *extents); - -cairo_private cairo_status_t -_cairo_gstate_set_font_face (cairo_gstate_t *gstate, - cairo_font_face_t *font_face); - -cairo_private cairo_status_t -_cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, - double x, - double y, - const char *utf8, - int utf8_len, - cairo_glyph_t **glyphs, - int *num_glyphs, - cairo_text_cluster_t **clusters, - int *num_clusters, - cairo_text_cluster_flags_t *cluster_flags); - -cairo_private cairo_status_t -_cairo_gstate_glyph_extents (cairo_gstate_t *gstate, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_text_extents_t *extents); - -cairo_private cairo_status_t -_cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, - const char *utf8, - int utf8_len, - const cairo_glyph_t *glyphs, - int num_glyphs, - const cairo_text_cluster_t *clusters, - int num_clusters, - cairo_text_cluster_flags_t cluster_flags); - -cairo_private cairo_status_t -_cairo_gstate_glyph_path (cairo_gstate_t *gstate, - const cairo_glyph_t *glyphs, - int num_glyphs, - cairo_path_fixed_t *path); - -cairo_private cairo_status_t -_cairo_gstate_set_antialias (cairo_gstate_t *gstate, - cairo_antialias_t antialias); - -cairo_private cairo_antialias_t -_cairo_gstate_get_antialias (cairo_gstate_t *gstate); +cairo_private uint16_t +_cairo_half_from_float (float f) cairo_const; cairo_private cairo_bool_t _cairo_operator_bounded_by_mask (cairo_operator_t op) cairo_const; @@ -1315,6 +990,13 @@ _cairo_operator_bounded_by_mask (cairo_operator_t op) cairo_const; cairo_private cairo_bool_t _cairo_operator_bounded_by_source (cairo_operator_t op) cairo_const; +enum { + CAIRO_OPERATOR_BOUND_BY_MASK = 1 << 1, + CAIRO_OPERATOR_BOUND_BY_SOURCE = 1 << 2, +}; + +cairo_private uint32_t +_cairo_operator_bounded_by_either (cairo_operator_t op) cairo_const; /* cairo-color.c */ cairo_private const cairo_color_t * _cairo_stock_color (cairo_stock_t stock) cairo_pure; @@ -1360,6 +1042,13 @@ cairo_private cairo_bool_t _cairo_color_equal (const cairo_color_t *color_a, const cairo_color_t *color_b) cairo_pure; +cairo_private cairo_bool_t +_cairo_color_stop_equal (const cairo_color_stop_t *color_a, + const cairo_color_stop_t *color_b) cairo_pure; + +cairo_private cairo_content_t +_cairo_color_get_content (const cairo_color_t *color) cairo_pure; + /* cairo-font-face.c */ extern const cairo_private cairo_font_face_t _cairo_font_face_nil; @@ -1405,6 +1094,20 @@ cairo_private void _cairo_font_options_init_copy (cairo_font_options_t *options, const cairo_font_options_t *other); +cairo_private void +_cairo_font_options_set_lcd_filter (cairo_font_options_t *options, + cairo_lcd_filter_t lcd_filter); + +cairo_private cairo_lcd_filter_t +_cairo_font_options_get_lcd_filter (const cairo_font_options_t *options); + +cairo_private void +_cairo_font_options_set_round_glyph_positions (cairo_font_options_t *options, + cairo_round_glyph_positions_t round); + +cairo_private cairo_round_glyph_positions_t +_cairo_font_options_get_round_glyph_positions (const cairo_font_options_t *options); + /* cairo-hull.c */ cairo_private cairo_status_t _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices); @@ -1528,6 +1231,10 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path, void *closure, double tolerance); +cairo_private cairo_bool_t +_cairo_path_fixed_extents (const cairo_path_fixed_t *path, + cairo_box_t *box); + cairo_private void _cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path, cairo_rectangle_int_t *extents); @@ -1544,23 +1251,18 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path, cairo_private void _cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path, - cairo_stroke_style_t *style, + const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, cairo_rectangle_int_t *extents); cairo_private cairo_status_t _cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path, - cairo_stroke_style_t *style, + const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_rectangle_int_t *extents); -cairo_private void -_cairo_path_fixed_bounds (const cairo_path_fixed_t *path, - double *x1, double *y1, - double *x2, double *y2); - cairo_private void _cairo_path_fixed_transform (cairo_path_fixed_t *path, const cairo_matrix_t *matrix); @@ -1592,6 +1294,11 @@ _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, cairo_traps_t *traps); +cairo_private cairo_status_t +_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + cairo_boxes_t *boxes); + cairo_private cairo_region_t * _cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, @@ -1606,7 +1313,7 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path, /* cairo-path-stroke.c */ cairo_private cairo_status_t _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, + const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, @@ -1614,12 +1321,19 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path, cairo_private cairo_int_status_t _cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, + const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, cairo_traps_t *traps); + +cairo_private cairo_int_status_t +_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + cairo_boxes_t *boxes); + cairo_private cairo_status_t _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, + const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, @@ -1627,9 +1341,9 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path, cairo_private cairo_status_t _cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_status_t (*add_triangle) (void *closure, const cairo_point_t triangle[3]), @@ -1761,7 +1475,7 @@ _cairo_stroke_style_init (cairo_stroke_style_t *style); cairo_private cairo_status_t _cairo_stroke_style_init_copy (cairo_stroke_style_t *style, - cairo_stroke_style_t *other); + const cairo_stroke_style_t *other); cairo_private void _cairo_stroke_style_fini (cairo_stroke_style_t *style); @@ -1835,6 +1549,7 @@ _cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other, cairo_private void _cairo_surface_init (cairo_surface_t *surface, const cairo_surface_backend_t *backend, + cairo_device_t *device, cairo_content_t content); cairo_private void @@ -1901,9 +1616,9 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, cairo_path_fixed_t *path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, - cairo_stroke_style_t *stroke_style, - cairo_matrix_t *stroke_ctm, - cairo_matrix_t *stroke_ctm_inverse, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, cairo_clip_t *clip); @@ -1913,9 +1628,9 @@ _cairo_surface_stroke (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip); @@ -1964,7 +1679,7 @@ _cairo_surface_stroke_extents (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, + const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, @@ -2008,18 +1723,6 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, int ntraps, cairo_region_t *clip_region); -cairo_private cairo_status_t -_cairo_surface_composite_trapezoids_as_polygon (cairo_surface_t *surface, - cairo_operator_t op, - const cairo_pattern_t *pattern, - cairo_antialias_t antialias, - int src_x, int src_y, - int dst_x, int dst_y, - int width, int height, - cairo_trapezoid_t *traps, - int num_traps, - cairo_region_t *clip_region); - cairo_private cairo_span_renderer_t * _cairo_surface_create_span_renderer (cairo_operator_t op, const cairo_pattern_t *pattern, @@ -2072,23 +1775,21 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, cairo_private cairo_surface_t * _cairo_surface_snapshot (cairo_surface_t *surface); -cairo_private cairo_status_t +cairo_private void _cairo_surface_attach_snapshot (cairo_surface_t *surface, cairo_surface_t *snapshot, cairo_surface_func_t detach_func); cairo_private cairo_surface_t * _cairo_surface_has_snapshot (cairo_surface_t *surface, - const cairo_surface_backend_t *backend, - cairo_content_t content); + const cairo_surface_backend_t *backend); cairo_private void _cairo_surface_detach_snapshot (cairo_surface_t *snapshot); cairo_private cairo_bool_t _cairo_surface_is_similar (cairo_surface_t *surface_a, - cairo_surface_t *surface_b, - cairo_content_t content); + cairo_surface_t *surface_b); cairo_private cairo_bool_t _cairo_surface_get_extents (cairo_surface_t *surface, @@ -2158,6 +1859,9 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface, cairo_private cairo_bool_t _cairo_surface_has_device_transform (cairo_surface_t *surface) cairo_pure; +cairo_private void +_cairo_surface_release_device_reference (cairo_surface_t *surface); + /* cairo-image-surface.c */ /* XXX: In cairo 1.2.0 we added a new %CAIRO_FORMAT_RGB16_565 but @@ -2190,8 +1894,8 @@ _cairo_surface_has_device_transform (cairo_surface_t *surface) cairo_pure; * to support it (at least cairo_surface_write_to_png() and a few spots * in cairo-xlib-surface.c--again see -Wswitch-enum). */ -#define CAIRO_FORMAT_INVALID ((unsigned int) -1) -#define CAIRO_FORMAT_VALID(format) ((format) <= CAIRO_FORMAT_RGB16_565) +#define CAIRO_FORMAT_VALID(format) ((format) >= CAIRO_FORMAT_ARGB32 && \ + (format) <= CAIRO_FORMAT_RGB16_565) /* pixman-required stride alignment in bytes. */ #define CAIRO_STRIDE_ALIGNMENT (sizeof (uint32_t)) @@ -2210,13 +1914,22 @@ _cairo_format_bits_per_pixel (cairo_format_t format) cairo_const; cairo_private cairo_format_t _cairo_format_from_content (cairo_content_t content) cairo_const; +cairo_private cairo_format_t +_cairo_format_from_pixman_format (pixman_format_code_t pixman_format); + cairo_private cairo_content_t _cairo_content_from_format (cairo_format_t format) cairo_const; +cairo_private cairo_content_t +_cairo_content_from_pixman_format (pixman_format_code_t pixman_format); + cairo_private cairo_surface_t * _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, pixman_format_code_t pixman_format); +cairo_private pixman_format_code_t +_cairo_format_to_pixman_format_code (cairo_format_t format); + cairo_private cairo_bool_t _pixman_format_from_masks (cairo_format_masks_t *masks, pixman_format_code_t *format_ret); @@ -2225,6 +1938,9 @@ cairo_private cairo_bool_t _pixman_format_to_masks (pixman_format_code_t pixman_format, cairo_format_masks_t *masks); +cairo_private void +_cairo_image_reset_static_data (void); + cairo_private cairo_surface_t * _cairo_image_surface_create_with_pixman_format (unsigned char *data, pixman_format_code_t pixman_format, @@ -2232,31 +1948,21 @@ _cairo_image_surface_create_with_pixman_format (unsigned char *data, int height, int stride); -cairo_private cairo_surface_t * -_cairo_image_surface_create_with_masks (unsigned char *data, - cairo_format_masks_t *format, - int width, - int height, - int stride); - cairo_private cairo_surface_t * _cairo_image_surface_create_with_content (cairo_content_t content, int width, int height); -cairo_private cairo_surface_t * -_cairo_image_surface_create_for_data_with_content (unsigned char *data, - cairo_content_t content, - int width, - int height, - int stride); - cairo_private void _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface); cairo_private cairo_image_surface_t * -_cairo_image_surface_coerce (cairo_image_surface_t *surface, - cairo_format_t format); +_cairo_image_surface_coerce (cairo_image_surface_t *surface); + +cairo_private cairo_image_surface_t * +_cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface, + cairo_format_t format); + cairo_private void _cairo_image_surface_span_render_row (int y, const cairo_half_open_span_t *spans, @@ -2381,6 +2087,9 @@ _cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix, cairo_private cairo_bool_t _cairo_matrix_is_invertible (const cairo_matrix_t *matrix) cairo_pure; +cairo_private cairo_bool_t +_cairo_matrix_is_scale_0 (const cairo_matrix_t *matrix) cairo_pure; + cairo_private double _cairo_matrix_compute_determinant (const cairo_matrix_t *matrix) cairo_pure; @@ -2425,8 +2134,7 @@ _cairo_traps_limit (cairo_traps_t *traps, cairo_private cairo_status_t _cairo_traps_init_boxes (cairo_traps_t *traps, - const cairo_box_t *boxes, - int num_boxes); + const cairo_boxes_t *boxes); cairo_private void _cairo_traps_clear (cairo_traps_t *traps); @@ -2467,10 +2175,20 @@ cairo_private cairo_status_t _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps, cairo_fill_rule_t fill_rule); +cairo_private cairo_status_t +_cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in, + cairo_fill_rule_t fill_rule, + cairo_boxes_t *out); + cairo_private cairo_status_t _cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps, cairo_fill_rule_t fill_rule); +cairo_private cairo_status_t +_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_boxes_t *boxes); + cairo_private int _cairo_traps_contain (const cairo_traps_t *traps, double x, double y); @@ -2517,8 +2235,7 @@ _cairo_pattern_init_snapshot (cairo_pattern_t *pattern, cairo_private void _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, - const cairo_color_t *color, - cairo_content_t content); + const cairo_color_t *color); cairo_private void _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern, @@ -2536,22 +2253,31 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, cairo_private void _cairo_pattern_fini (cairo_pattern_t *pattern); -cairo_private void -_cairo_pattern_fini_snapshot (cairo_pattern_t *pattern); - cairo_private cairo_pattern_t * -_cairo_pattern_create_solid (const cairo_color_t *color, - cairo_content_t content); +_cairo_pattern_create_solid (const cairo_color_t *color); cairo_private void _cairo_pattern_transform (cairo_pattern_t *pattern, const cairo_matrix_t *ctm_inverse); +cairo_private cairo_bool_t +_cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *extents, + cairo_color_t *color); + cairo_private cairo_bool_t _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern); cairo_private cairo_bool_t -_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern); +_cairo_pattern_is_opaque (const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents); + +cairo_private cairo_bool_t +_cairo_pattern_is_clear (const cairo_pattern_t *pattern); + +cairo_private_no_warn cairo_filter_t +_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern, + double *pad_out); enum { CAIRO_PATTERN_ACQUIRE_NONE = 0x0, @@ -2596,9 +2322,25 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern, cairo_private unsigned long _cairo_pattern_hash (const cairo_pattern_t *pattern); +cairo_private unsigned long +_cairo_linear_pattern_hash (unsigned long hash, + const cairo_linear_pattern_t *linear); + +cairo_private unsigned long +_cairo_radial_pattern_hash (unsigned long hash, + const cairo_radial_pattern_t *radial); + +cairo_private cairo_bool_t +_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a, + const cairo_linear_pattern_t *b); + cairo_private unsigned long _cairo_pattern_size (const cairo_pattern_t *pattern); +cairo_private cairo_bool_t +_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a, + const cairo_radial_pattern_t *b); + cairo_private cairo_bool_t _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b); @@ -2643,17 +2385,10 @@ _cairo_utf8_to_utf16 (const char *str, int *items_written); #endif -#define _cairo_status_is_error(status) \ - (status != CAIRO_STATUS_SUCCESS && status <= CAIRO_STATUS_LAST_STATUS) +/* cairo-observer.c */ -cairo_private cairo_status_t -_cairo_error (cairo_status_t status); - -/* hide compiler warnings when discarding the return value */ -#define _cairo_error_throw(status) do { \ - cairo_status_t status__ = _cairo_error (status); \ - (void) status__; \ -} while (0) +cairo_private void +_cairo_observers_notify (cairo_list_t *observers, void *arg); /* Avoid unnecessary PLT entries. */ slim_hidden_proto (cairo_clip_preserve); @@ -2757,6 +2492,7 @@ slim_hidden_proto (cairo_surface_get_type); slim_hidden_proto (cairo_surface_has_show_text_glyphs); slim_hidden_proto (cairo_surface_set_subpixel_antialiasing); slim_hidden_proto (cairo_surface_get_subpixel_antialiasing); +slim_hidden_proto (cairo_surface_mark_dirty); slim_hidden_proto (cairo_surface_mark_dirty_rectangle); slim_hidden_proto_no_warn (cairo_surface_reference); slim_hidden_proto (cairo_surface_set_device_offset); @@ -2799,6 +2535,8 @@ slim_hidden_proto (cairo_region_intersect); slim_hidden_proto (cairo_region_intersect_rectangle); slim_hidden_proto (cairo_region_union); slim_hidden_proto (cairo_region_union_rectangle); +slim_hidden_proto (cairo_region_xor); +slim_hidden_proto (cairo_region_xor_rectangle); #if CAIRO_HAS_PNG_FUNCTIONS @@ -2806,6 +2544,10 @@ slim_hidden_proto (cairo_surface_write_to_png_stream); #endif +cairo_private_no_warn cairo_filter_t +_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern, + double *pad_out); + CAIRO_END_DECLS #include "cairo-mutex-private.h" diff --git a/gfx/cairo/cairo/src/test-fallback-surface.c b/gfx/cairo/cairo/src/test-fallback-surface.c index 3b62e55bb930..66399d4abbb3 100644 --- a/gfx/cairo/cairo/src/test-fallback-surface.c +++ b/gfx/cairo/cairo/src/test-fallback-surface.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -54,6 +54,7 @@ #include "cairoint.h" #include "test-fallback-surface.h" +#include "cairo-error-private.h" typedef struct _test_fallback_surface { cairo_surface_t base; @@ -84,7 +85,9 @@ _cairo_test_fallback_surface_create (cairo_content_t content, return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } - _cairo_surface_init (&surface->base, &test_fallback_surface_backend, + _cairo_surface_init (&surface->base, + &test_fallback_surface_backend, + NULL, /* device */ content); surface->backing = backing; diff --git a/gfx/cairo/cairo/src/test-fallback-surface.h b/gfx/cairo/cairo/src/test-fallback-surface.h index 744b303a1e0c..e70715113956 100644 --- a/gfx/cairo/cairo/src/test-fallback-surface.h +++ b/gfx/cairo/cairo/src/test-fallback-surface.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/cairo/cairo/src/test-paginated-surface.c b/gfx/cairo/cairo/src/test-paginated-surface.c index 164d4a7147f4..e06cbed719cc 100644 --- a/gfx/cairo/cairo/src/test-paginated-surface.c +++ b/gfx/cairo/cairo/src/test-paginated-surface.c @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * @@ -49,6 +49,7 @@ #include "test-paginated-surface.h" +#include "cairo-error-private.h" #include "cairo-paginated-private.h" typedef struct _test_paginated_surface { @@ -75,7 +76,9 @@ _cairo_test_paginated_surface_create (cairo_surface_t *target) if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - _cairo_surface_init (&surface->base, &test_paginated_surface_backend, + _cairo_surface_init (&surface->base, + &test_paginated_surface_backend, + NULL, /* device */ target->content); surface->target = cairo_surface_reference (target); @@ -149,9 +152,9 @@ _test_paginated_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, - cairo_stroke_style_t *style, - cairo_matrix_t *ctm, - cairo_matrix_t *ctm_inverse, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) diff --git a/gfx/cairo/cairo/src/test-paginated-surface.h b/gfx/cairo/cairo/src/test-paginated-surface.h index 76ce6890e74f..2bd98aa5eeee 100644 --- a/gfx/cairo/cairo/src/test-paginated-surface.h +++ b/gfx/cairo/cairo/src/test-paginated-surface.h @@ -12,7 +12,7 @@ * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * diff --git a/gfx/thebes/gfxASurface.cpp b/gfx/thebes/gfxASurface.cpp index 2f3d5bbfce18..64fe7d4428ee 100644 --- a/gfx/thebes/gfxASurface.cpp +++ b/gfx/thebes/gfxASurface.cpp @@ -566,6 +566,7 @@ static const char *sSurfaceNamesForSurfaceType[] = { "explicit/gfx/surface/tee", "explicit/gfx/surface/xml", "explicit/gfx/surface/skia", + "explicit/gfx/surface/subsurface", "explicit/gfx/surface/d2d" }; diff --git a/gfx/thebes/gfxASurface.h b/gfx/thebes/gfxASurface.h index e79a0e365386..960d54ff0af6 100644 --- a/gfx/thebes/gfxASurface.h +++ b/gfx/thebes/gfxASurface.h @@ -98,6 +98,7 @@ public: SurfaceTypeTee, SurfaceTypeXML, SurfaceTypeSkia, + SurfaceTypeSubsurface, SurfaceTypeD2D, SurfaceTypeMax } gfxSurfaceType; diff --git a/gfx/thebes/gfxQPainterSurface.cpp b/gfx/thebes/gfxQPainterSurface.cpp index de12c1ef8652..b95e42d9f780 100644 --- a/gfx/thebes/gfxQPainterSurface.cpp +++ b/gfx/thebes/gfxQPainterSurface.cpp @@ -37,12 +37,10 @@ #include -#include "gfxQPainterSurface.h" - +#include "cairo-features.h" #ifdef CAIRO_HAS_QT_SURFACE -#include "gfxImageSurface.h" - #include "cairo-qt.h" +#include "gfxQPainterSurface.h" gfxQPainterSurface::gfxQPainterSurface(QPainter *painter) { diff --git a/gfx/thebes/gfxTeeSurface.cpp b/gfx/thebes/gfxTeeSurface.cpp index 2da747665618..01ef71ce82c4 100644 --- a/gfx/thebes/gfxTeeSurface.cpp +++ b/gfx/thebes/gfxTeeSurface.cpp @@ -37,14 +37,7 @@ #include "gfxTeeSurface.h" -/* Once cairo in tree is update ensure we remove the ifdef - and just include cairo-tee.h -*/ -#ifdef MOZ_TREE_CAIRO -#include "cairo.h" -#else #include "cairo-tee.h" -#endif gfxTeeSurface::gfxTeeSurface(cairo_surface_t *csurf) { diff --git a/layout/reftests/border-radius/reftest.list b/layout/reftests/border-radius/reftest.list index 64bf5d0a268a..3a391d8f7c72 100644 --- a/layout/reftests/border-radius/reftest.list +++ b/layout/reftests/border-radius/reftest.list @@ -41,20 +41,20 @@ fails-if(Android) == clipping-3.html clipping-3-ref.xhtml # edge of border-radiu # Tests for clipping the contents of replaced elements and overflow!=visible != clipping-4-ref.html clipping-4-notref.html -fails-if(Android) fails-if(cocoaWidget) == clipping-4-canvas.html clipping-4-ref.html +fails-if(cocoaWidget) == clipping-4-canvas.html clipping-4-ref.html fails-if(Android) == clipping-4-image.html clipping-4-ref.html == clipping-4-overflow-hidden.html clipping-4-ref.html == clipping-5-canvas.html clipping-5-refc.html == clipping-5-image.html clipping-5-refi.html == clipping-5-overflow-hidden.html clipping-5-ref.html fails-if(Android) == clipping-5-refi.html clipping-5-ref.html -fails-if(Android) fails-if(cocoaWidget) == clipping-5-refc.html clipping-5-ref.html +fails-if(cocoaWidget) == clipping-5-refc.html clipping-5-ref.html == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html == intersecting-clipping-1-image.html intersecting-clipping-1-refi.html == intersecting-clipping-1-overflow-hidden.html intersecting-clipping-1-ref.html fails-if(Android) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html -fails-if(Android) fails-if(cocoaWidget) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html +fails-if(cocoaWidget) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # Inheritance == inherit-1.html inherit-1-ref.html # border-radius shouldn't inherit diff --git a/layout/reftests/counters/reftest.list b/layout/reftests/counters/reftest.list index 2972b90b1d8e..8a553f1e3632 100644 --- a/layout/reftests/counters/reftest.list +++ b/layout/reftests/counters/reftest.list @@ -60,4 +60,4 @@ == text-boundaries-subpixel.html text-boundaries-subpixel-ref.html == counter-hebrew-test.html counter-hebrew-reference.html == counters-hebrew-test.html counters-hebrew-reference.html -== counter-reset-integer-range.html counter-reset-integer-range-ref.html +fails-if(Android) == counter-reset-integer-range.html counter-reset-integer-range-ref.html diff --git a/layout/reftests/generated-content/reftest.list b/layout/reftests/generated-content/reftest.list index cc913fee78e4..dfd70ed36d15 100644 --- a/layout/reftests/generated-content/reftest.list +++ b/layout/reftests/generated-content/reftest.list @@ -1,4 +1,4 @@ -== display-types-01.html display-types-01-ref.html +fails-if(Android) == display-types-01.html display-types-01-ref.html == dynamic-attr-01.html dynamic-attr-01-ref.html == dynamic-restyle-01.html dynamic-restyle-01-ref.html == floated-01.html floated-01-ref.html