[cairo-commit] 8 commits - src/cairo.h src/cairoint.h src/cairo-path-fill.c src/cairo-path-fixed.c src/cairo-quartz.h src/cairo-quartz-image-surface.c src/cairo-quartz-private.h src/cairo-quartz-surface.c src/Makefile.am test/buffer-diff.c test/dash-scale-quartz-ref.png test/degenerate-pen.c test/degenerate-pen-ps-argb32-ref.png test/degenerate-pen-ps-ref.png test/degenerate-pen-quartz-ref.png test/degenerate-pen-ref.png test/leaky-dash-quartz-ref.png test/line-width-scale-quartz-ref.png test/mask-alpha-quartz-argb32-ref.png test/mask-quartz-ref.png test/mask-quartz-rgb24-ref.png test/meta-surface-pattern-quartz-ref.png test/meta-surface-pattern-quartz-rgb24-ref.png test/new-sub-path-quartz-ref.png test/over-above-source-quartz-ref.png test/over-above-source-quartz-rgb24-ref.png test/over-around-source-quartz-ref.png test/over-around-source-quartz-rgb24-ref.png test/over-between-source-quartz-ref.png test/over-between-source-quartz-rgb24-ref.png test/rotate-image-surface-paint-quartz-ref.png test/trap-clip-quartz-ref.png
Vladimir Vukicevic
vladimir at kemper.freedesktop.org
Mon Feb 25 18:45:52 PST 2008
dev/null |binary
src/Makefile.am | 2
src/cairo-path-fill.c | 66 --
src/cairo-path-fixed.c | 81 +++
src/cairo-quartz-image-surface.c | 370 +++++++++++++++
src/cairo-quartz-private.h | 31 +
src/cairo-quartz-surface.c | 596 ++++++++++++-------------
src/cairo-quartz.h | 6
src/cairo.h | 4
src/cairoint.h | 9
test/buffer-diff.c | 24 -
test/dash-scale-quartz-ref.png |binary
test/degenerate-pen-ps-ref.png |binary
test/degenerate-pen-quartz-ref.png |binary
test/degenerate-pen-ref.png |binary
test/degenerate-pen.c | 4
test/leaky-dash-quartz-ref.png |binary
test/line-width-scale-quartz-ref.png |binary
test/mask-alpha-quartz-argb32-ref.png |binary
test/mask-quartz-ref.png |binary
test/mask-quartz-rgb24-ref.png |binary
test/meta-surface-pattern-quartz-ref.png |binary
test/meta-surface-pattern-quartz-rgb24-ref.png |binary
test/new-sub-path-quartz-ref.png |binary
test/over-above-source-quartz-ref.png |binary
test/over-above-source-quartz-rgb24-ref.png |binary
test/over-around-source-quartz-ref.png |binary
test/over-around-source-quartz-rgb24-ref.png |binary
test/over-between-source-quartz-ref.png |binary
test/over-between-source-quartz-rgb24-ref.png |binary
test/rotate-image-surface-paint-quartz-ref.png |binary
test/trap-clip-quartz-ref.png |binary
32 files changed, 822 insertions(+), 371 deletions(-)
New commits:
commit 7acfee38b1ac6ef2292d754c7103bd65d58f72d8
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Mon Feb 25 21:44:04 2008 -0500
[atsui] Make default font 'Helvetica'
The previous default font was Monaco, which is a fixed-pitch font; Helvetica
is more inline with the other platform defaults.
diff --git a/src/cairoint.h b/src/cairoint.h
index d24dfa8..099d0d5 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -840,7 +840,7 @@ typedef struct _cairo_traps {
#define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL
#define CAIRO_WIN32_FONT_FAMILY_DEFAULT "Arial"
-#define CAIRO_ATSUI_FONT_FAMILY_DEFAULT "Monaco"
+#define CAIRO_ATSUI_FONT_FAMILY_DEFAULT "Helvetica"
#define CAIRO_FT_FONT_FAMILY_DEFAULT ""
#if CAIRO_HAS_WIN32_FONT
commit 9979f786acaf0ebba1bf97e40aeba66287a3c743
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Mon Feb 25 21:27:33 2008 -0500
[test] update degenerate-pen test
pdiff was hiding a rgb24 failure here, as the test was drawing using
black ink on the default black background. Instead, explicitly fill
the surface with white first.
diff --git a/test/degenerate-pen-ps-argb32-ref.png b/test/degenerate-pen-ps-argb32-ref.png
deleted file mode 100644
index 2c23cd4..0000000
Binary files a/test/degenerate-pen-ps-argb32-ref.png and /dev/null differ
diff --git a/test/degenerate-pen-ps-ref.png b/test/degenerate-pen-ps-ref.png
new file mode 100644
index 0000000..2d0f07b
Binary files /dev/null and b/test/degenerate-pen-ps-ref.png differ
diff --git a/test/degenerate-pen-quartz-ref.png b/test/degenerate-pen-quartz-ref.png
new file mode 100644
index 0000000..cc25b88
Binary files /dev/null and b/test/degenerate-pen-quartz-ref.png differ
diff --git a/test/degenerate-pen-ref.png b/test/degenerate-pen-ref.png
index 539a325..5961ddd 100644
Binary files a/test/degenerate-pen-ref.png and b/test/degenerate-pen-ref.png differ
diff --git a/test/degenerate-pen.c b/test/degenerate-pen.c
index 858949f..4ff50f8 100644
--- a/test/degenerate-pen.c
+++ b/test/degenerate-pen.c
@@ -60,6 +60,10 @@ cairo_test_t test = {
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+
+ cairo_set_source_rgb (cr, 0, 0, 0);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
cairo_translate (cr, PAD, PAD);
commit baec928a69b5b763b30766cddfb1473e4e05fc3c
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Mon Feb 25 21:06:36 2008 -0500
[quartz] More mask fixes -- handle all types via fallback mask image
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index f421347..83c2b81 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1654,6 +1654,52 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
return status;
}
+/* This is somewhat less than ideal, but it gets the job done;
+ * it would be better to avoid calling back into cairo. This
+ * creates a temporary surface to use as the mask.
+ */
+static cairo_int_status_t
+_cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_pattern_t *mask)
+{
+ int width = surface->extents.width - surface->extents.x;
+ int height = surface->extents.height - surface->extents.y;
+
+ cairo_surface_t *gradient_surf = NULL;
+ cairo_t *gradient_surf_cr = NULL;
+
+ cairo_pattern_union_t surface_pattern;
+ cairo_int_status_t status;
+
+ /* Render the gradient to a surface */
+ gradient_surf = cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32,
+ width,
+ height);
+ gradient_surf_cr = cairo_create(gradient_surf);
+ cairo_set_source (gradient_surf_cr, mask);
+ cairo_set_operator (gradient_surf_cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (gradient_surf_cr);
+ status = cairo_status (gradient_surf_cr);
+ cairo_destroy (gradient_surf_cr);
+
+ if (status)
+ goto BAIL;
+
+ _cairo_pattern_init_for_surface (&surface_pattern.surface, gradient_surf);
+
+ status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern.surface);
+
+ _cairo_pattern_fini (&surface_pattern.base);
+
+ BAIL:
+ if (gradient_surf)
+ cairo_surface_destroy (gradient_surf);
+
+ return status;
+}
+
static cairo_int_status_t
_cairo_quartz_surface_mask (void *abstract_surface,
cairo_operator_t op,
@@ -1673,30 +1719,29 @@ _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);
- } else if (CGContextClipToMaskPtr &&
- mask->type == CAIRO_PATTERN_TYPE_SURFACE &&
- mask->extend == CAIRO_EXTEND_NONE) {
- return _cairo_quartz_surface_mask_with_surface (surface, op, source, (cairo_surface_pattern_t *) mask);
- } else {
- /* So, CGContextClipToMask is not present in 10.3.9, so we're
- * doomed; if we have imageData, we can do fallback, otherwise
- * just pretend success.
- */
- if (surface->imageData)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ rv = _cairo_quartz_surface_paint (surface, op, source);
+ CGContextSetAlpha (surface->cgContext, 1.0);
- return CAIRO_STATUS_SUCCESS;
+ return rv;
}
- rv = _cairo_quartz_surface_paint (surface, op, source);
+ /* If we have CGContextClipToMask, we can do more complex masks */
+ if (CGContextClipToMaskPtr) {
+ /* For these, we can skip creating a temporary surface, since we already have one */
+ if (mask->type == CAIRO_PATTERN_TYPE_SURFACE && mask->extend == CAIRO_EXTEND_NONE)
+ return _cairo_quartz_surface_mask_with_surface (surface, op, source, (cairo_surface_pattern_t *) mask);
- if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
- CGContextSetAlpha (surface->cgContext, 1.0);
+ return _cairo_quartz_surface_mask_with_generic (surface, op, source, mask);
}
- ND((stderr, "-- mask\n"));
+ /* So, CGContextClipToMask is not present in 10.3.9, so we're
+ * doomed; if we have imageData, we can do fallback, otherwise
+ * just pretend success.
+ */
+ if (surface->imageData)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- return rv;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
diff --git a/test/mask-quartz-ref.png b/test/mask-quartz-ref.png
new file mode 100644
index 0000000..3925740
Binary files /dev/null and b/test/mask-quartz-ref.png differ
diff --git a/test/mask-quartz-rgb24-ref.png b/test/mask-quartz-rgb24-ref.png
new file mode 100644
index 0000000..b9c57c7
Binary files /dev/null and b/test/mask-quartz-rgb24-ref.png differ
commit 3fcd0be52215e1d8a59560d6b0919fb3f53b7a28
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Mon Feb 25 21:06:35 2008 -0500
Use pdiff only if the pixel difference is less than a limit
diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index 24fdad3..d1b5863 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -42,6 +42,10 @@
#include "buffer-diff.h"
#include "xmalloc.h"
+/* Don't allow any differences greater than this value, even if pdiff
+ * claims that the images are identical */
+#define PERCEPTUAL_DIFF_THRESHOLD 25
+
static void
xunlink (const char *pathname)
{
@@ -152,13 +156,19 @@ compare_surfaces (cairo_surface_t *surface_a,
/* Then, if there are any different pixels, we give the pdiff code
* a crack at the images. If it decides that there are no visually
* discernible differences in any pixels, then we accept this
- * result as good enough. */
- discernible_pixels_changed = pdiff_compare (surface_a, surface_b,
- gamma, luminance, field_of_view);
- if (discernible_pixels_changed == 0) {
- result->pixels_changed = 0;
- cairo_test_log ("But perceptual diff finds no visually discernible difference.\n"
- "Accepting result.\n");
+ * result as good enough.
+ *
+ * Only let pdiff have a crack at the comparison if the max difference
+ * is lower than a threshold, otherwise some problems could be masked.
+ */
+ if (result->max_diff < PERCEPTUAL_DIFF_THRESHOLD) {
+ discernible_pixels_changed = pdiff_compare (surface_a, surface_b,
+ gamma, luminance, field_of_view);
+ if (discernible_pixels_changed == 0) {
+ result->pixels_changed = 0;
+ cairo_test_log ("But perceptual diff finds no visually discernible difference.\n"
+ "Accepting result.\n");
+ }
}
}
commit 1dfb1bd45fbe08392e233af67f464b2776de9f19
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Mon Feb 25 21:06:28 2008 -0500
[quartz] update test suite images for quartz
diff --git a/test/dash-scale-quartz-ref.png b/test/dash-scale-quartz-ref.png
new file mode 100644
index 0000000..8fc897b
Binary files /dev/null and b/test/dash-scale-quartz-ref.png differ
diff --git a/test/leaky-dash-quartz-ref.png b/test/leaky-dash-quartz-ref.png
new file mode 100644
index 0000000..8343359
Binary files /dev/null and b/test/leaky-dash-quartz-ref.png differ
diff --git a/test/line-width-scale-quartz-ref.png b/test/line-width-scale-quartz-ref.png
new file mode 100644
index 0000000..7a31539
Binary files /dev/null and b/test/line-width-scale-quartz-ref.png differ
diff --git a/test/mask-alpha-quartz-argb32-ref.png b/test/mask-alpha-quartz-argb32-ref.png
new file mode 100644
index 0000000..a7fdc5f
Binary files /dev/null and b/test/mask-alpha-quartz-argb32-ref.png differ
diff --git a/test/meta-surface-pattern-quartz-ref.png b/test/meta-surface-pattern-quartz-ref.png
new file mode 100644
index 0000000..755f281
Binary files /dev/null and b/test/meta-surface-pattern-quartz-ref.png differ
diff --git a/test/meta-surface-pattern-quartz-rgb24-ref.png b/test/meta-surface-pattern-quartz-rgb24-ref.png
new file mode 100644
index 0000000..b71891e
Binary files /dev/null and b/test/meta-surface-pattern-quartz-rgb24-ref.png differ
diff --git a/test/new-sub-path-quartz-ref.png b/test/new-sub-path-quartz-ref.png
index e9c40b9..4278017 100644
Binary files a/test/new-sub-path-quartz-ref.png and b/test/new-sub-path-quartz-ref.png differ
diff --git a/test/over-above-source-quartz-ref.png b/test/over-above-source-quartz-ref.png
new file mode 100644
index 0000000..79d3c93
Binary files /dev/null and b/test/over-above-source-quartz-ref.png differ
diff --git a/test/over-above-source-quartz-rgb24-ref.png b/test/over-above-source-quartz-rgb24-ref.png
new file mode 100644
index 0000000..38e823e
Binary files /dev/null and b/test/over-above-source-quartz-rgb24-ref.png differ
diff --git a/test/over-around-source-quartz-ref.png b/test/over-around-source-quartz-ref.png
new file mode 100644
index 0000000..417c8a7
Binary files /dev/null and b/test/over-around-source-quartz-ref.png differ
diff --git a/test/over-around-source-quartz-rgb24-ref.png b/test/over-around-source-quartz-rgb24-ref.png
new file mode 100644
index 0000000..3e4d764
Binary files /dev/null and b/test/over-around-source-quartz-rgb24-ref.png differ
diff --git a/test/over-between-source-quartz-ref.png b/test/over-between-source-quartz-ref.png
new file mode 100644
index 0000000..de954d5
Binary files /dev/null and b/test/over-between-source-quartz-ref.png differ
diff --git a/test/over-between-source-quartz-rgb24-ref.png b/test/over-between-source-quartz-rgb24-ref.png
new file mode 100644
index 0000000..97dae07
Binary files /dev/null and b/test/over-between-source-quartz-rgb24-ref.png differ
diff --git a/test/rotate-image-surface-paint-quartz-ref.png b/test/rotate-image-surface-paint-quartz-ref.png
new file mode 100644
index 0000000..0f2f626
Binary files /dev/null and b/test/rotate-image-surface-paint-quartz-ref.png differ
diff --git a/test/trap-clip-quartz-ref.png b/test/trap-clip-quartz-ref.png
index 28f5977..70e5b17 100644
Binary files a/test/trap-clip-quartz-ref.png and b/test/trap-clip-quartz-ref.png differ
commit b439e638087d6e76d14ca42cd59dba3915dcc8e8
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Mon Feb 25 21:06:25 2008 -0500
[quartz] fix mask to correctly take CTM into account
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 917752e..f421347 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -331,10 +331,9 @@ _cairo_quartz_filter_to_quartz (cairo_filter_t filter)
return kCGInterpolationLow;
case CAIRO_FILTER_BEST:
- return kCGInterpolationHigh;
-
case CAIRO_FILTER_GOOD:
case CAIRO_FILTER_BILINEAR:
+ case CAIRO_FILTER_GAUSSIAN:
return kCGInterpolationDefault;
}
@@ -343,7 +342,7 @@ _cairo_quartz_filter_to_quartz (cairo_filter_t filter)
static inline void
_cairo_quartz_cairo_matrix_to_quartz (const cairo_matrix_t *src,
- CGAffineTransform *dst)
+ CGAffineTransform *dst)
{
dst->a = src->xx;
dst->b = src->yx;
@@ -515,33 +514,6 @@ SurfacePatternReleaseInfoFunc (void *ainfo)
free (info);
}
-/* Borrowed from cairo-meta-surface */
-static cairo_status_t
-_init_pattern_with_snapshot (cairo_pattern_t *pattern,
- const cairo_pattern_t *other)
-{
- cairo_status_t status;
-
- status = _cairo_pattern_init_copy (pattern, other);
- if (status)
- return status;
-
- if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
- cairo_surface_pattern_t *surface_pattern =
- (cairo_surface_pattern_t *) pattern;
- cairo_surface_t *surface = surface_pattern->surface;
-
- surface_pattern->surface = _cairo_surface_snapshot (surface);
-
- cairo_surface_destroy (surface);
-
- if (surface_pattern->surface->status)
- return surface_pattern->surface->status;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_int_status_t
_cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t *dest,
cairo_pattern_t *apattern,
@@ -1641,6 +1613,7 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
CGImageRef img;
cairo_surface_t *pat_surf = mask->surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ CGAffineTransform ctm, mask_matrix;
status = _cairo_surface_get_extents (pat_surf, &extents);
if (status)
@@ -1656,13 +1629,16 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
goto BAIL;
}
- rect = CGRectMake (-mask->base.matrix.x0, -mask->base.matrix.y0, extents.width, extents.height);
+ rect = CGRectMake (0.0f, 0.0f, extents.width, extents.height);
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 */
- CGAffineTransform ctm = CGContextGetCTM (surface->cgContext);
+ ctm = CGContextGetCTM (surface->cgContext);
+
+ _cairo_quartz_cairo_matrix_to_quartz (&mask->base.matrix, &mask_matrix);
+ CGContextConcatCTM (surface->cgContext, CGAffineTransformInvert(mask_matrix));
CGContextTranslateCTM (surface->cgContext, 0.0f, rect.size.height);
CGContextScaleCTM (surface->cgContext, 1.0f, -1.0f);
commit a4975ab1173957a293aad8ccac51d1e43cab86da
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Mon Feb 25 21:06:23 2008 -0500
[quartz] Optimize path handling where possible
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index 8e4daca..ba33114 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -214,71 +214,9 @@ static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
cairo_traps_t *traps)
{
- cairo_path_buf_t *buf = &path->buf_head.base;
- int final;
-
- /* Ensure the path has the operators we expect for a rectangular path.
- */
- if (buf == NULL || buf->num_ops < 5)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
- buf->op[1] != CAIRO_PATH_OP_LINE_TO ||
- buf->op[2] != CAIRO_PATH_OP_LINE_TO ||
- buf->op[3] != CAIRO_PATH_OP_LINE_TO)
- {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- /* Now, there are choices. The rectangle might end with a LINE_TO
- * (to the original point), but this isn't required. If it
- * doesn't, then it must end with a CLOSE_PATH. */
- if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) {
- if (buf->points[4].x != buf->points[0].x ||
- buf->points[4].y != buf->points[0].y)
- {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
- } else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) {
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- /* Finally, a trailing CLOSE_PATH or MOVE_TO after the rectangle
- * is fine. But anything more than that means we must return
- * unsupported. */
- final = 5;
- if (final < buf->num_ops &&
- buf->op[final] == CAIRO_PATH_OP_CLOSE_PATH)
- {
- final++;
- }
- if (final < buf->num_ops &&
- buf->op[final] == CAIRO_PATH_OP_MOVE_TO)
- {
- final++;
- }
- if (final < buf->num_ops)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* Now that we've verified the operators, we must ensure that the
- * path coordinates are consistent with a rectangle. There are two
- * choices here. */
- if (buf->points[0].y == buf->points[1].y &&
- buf->points[1].x == buf->points[2].x &&
- buf->points[2].y == buf->points[3].y &&
- buf->points[3].x == buf->points[0].x)
- {
- return _cairo_traps_tessellate_convex_quad (traps,
- buf->points);
- }
-
- if (buf->points[0].x == buf->points[1].x &&
- buf->points[1].y == buf->points[2].y &&
- buf->points[2].x == buf->points[3].x &&
- buf->points[3].y == buf->points[0].y)
- {
+ if (_cairo_path_fixed_is_box (path, NULL)) {
return _cairo_traps_tessellate_convex_quad (traps,
- buf->points);
+ path->buf_head.base.points);
}
return CAIRO_INT_STATUS_UNSUPPORTED;
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index 91b8c0e..5c10d65 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -721,3 +721,84 @@ _cairo_path_fixed_interpret_flat (cairo_path_fixed_t *path,
_cpf_close_path,
&flattener);
}
+
+cairo_bool_t
+_cairo_path_fixed_is_empty (cairo_path_fixed_t *path)
+{
+ if (path->buf_head.base.num_ops == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * Check whether the given path contains a single rectangle.
+ */
+cairo_bool_t
+_cairo_path_fixed_is_box (cairo_path_fixed_t *path,
+ cairo_box_t *box)
+{
+ cairo_path_buf_t *buf = &path->buf_head.base;
+
+ /* We can't have more than one buf for this check */
+ if (buf->next != NULL)
+ return FALSE;
+
+ /* Do we have the right number of ops? */
+ if (buf->num_ops != 5 && buf->num_ops != 6)
+ return FALSE;
+
+ /* Check whether the ops are those that would be used for a rectangle */
+ if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
+ buf->op[1] != CAIRO_PATH_OP_LINE_TO ||
+ buf->op[2] != CAIRO_PATH_OP_LINE_TO ||
+ buf->op[3] != CAIRO_PATH_OP_LINE_TO)
+ {
+ return FALSE;
+ }
+
+ /* Now, there are choices. The rectangle might end with a LINE_TO
+ * (to the original point), but this isn't required. If it
+ * doesn't, then it must end with a CLOSE_PATH. */
+ if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) {
+ if (buf->points[4].x != buf->points[0].x ||
+ buf->points[4].y != buf->points[0].y)
+ return FALSE;
+ } else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) {
+ return FALSE;
+ }
+
+ if (buf->num_ops == 6) {
+ /* A trailing CLOSE_PATH or MOVE_TO is ok */
+ if (buf->op[5] != CAIRO_PATH_OP_MOVE_TO &&
+ buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH)
+ return FALSE;
+ }
+
+ /* Ok, we may have a box, if the points line up */
+ if (buf->points[0].y == buf->points[1].y &&
+ buf->points[1].x == buf->points[2].x &&
+ buf->points[2].y == buf->points[3].y &&
+ buf->points[3].x == buf->points[0].x)
+ {
+ if (box) {
+ box->p1 = buf->points[0];
+ box->p2 = buf->points[2];
+ }
+ return TRUE;
+ }
+
+ if (buf->points[0].x == buf->points[1].x &&
+ buf->points[1].y == buf->points[2].y &&
+ buf->points[2].x == buf->points[3].x &&
+ buf->points[3].y == buf->points[0].y)
+ {
+ if (box) {
+ box->p1 = buf->points[0];
+ box->p2 = buf->points[2];
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index e918ec0..917752e 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1297,6 +1297,7 @@ _cairo_quartz_surface_fill (void *abstract_surface,
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
cairo_quartz_action_t action;
quartz_stroke_t stroke;
+ cairo_box_t box;
ND((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type));
@@ -1306,6 +1307,16 @@ _cairo_quartz_surface_fill (void *abstract_surface,
if (op == CAIRO_OPERATOR_DEST)
return CAIRO_STATUS_SUCCESS;
+ /* Check whether the path would be a no-op */
+ /* XXX handle unbounded ops */
+ if (_cairo_path_fixed_is_empty(path) ||
+ (_cairo_path_fixed_is_box(path, &box) &&
+ box.p1.x == box.p2.x &&
+ box.p1.y == box.p2.y))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
CGContextSaveGState (surface->cgContext);
CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
diff --git a/src/cairoint.h b/src/cairoint.h
index 489cf40..d24dfa8 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1392,6 +1392,13 @@ cairo_private void
_cairo_path_fixed_device_transform (cairo_path_fixed_t *path,
cairo_matrix_t *device_transform);
+cairo_private cairo_bool_t
+_cairo_path_fixed_is_empty (cairo_path_fixed_t *path);
+
+cairo_private cairo_bool_t
+_cairo_path_fixed_is_box (cairo_path_fixed_t *path,
+ cairo_box_t *box);
+
/* cairo_path_fill.c */
cairo_private cairo_status_t
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
commit 63711b1d4a61f21db070f30b9c153d0923cc24bb
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date: Mon Feb 25 21:06:21 2008 -0500
[quartz] Add quartz-image-surface type
diff --git a/src/Makefile.am b/src/Makefile.am
index 525ca66..3656f05 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -178,7 +178,7 @@ backend_pkgconfigs += cairo-xcb.pc
endif
quartz_headers = cairo-quartz.h
-quartz_sources = cairo-quartz-surface.c cairo-quartz-private.h
+quartz_sources = cairo-quartz-surface.c cairo-quartz-image-surface.c cairo-quartz-private.h
cairo_all_sources += $(quartz_headers) $(quartz_sources)
if CAIRO_HAS_QUARTZ_SURFACE
cairo_headers += $(quartz_headers)
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
new file mode 100644
index 0000000..7a6d07d
--- /dev/null
+++ b/src/cairo-quartz-image-surface.c
@@ -0,0 +1,370 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright � 2008 Mozilla 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ *
+ * Contributor(s):
+ * Vladimir Vukicevic <vladimir at mozilla.com>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-quartz-private.h"
+
+#define SURFACE_ERROR_NO_MEMORY (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY)))
+#define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT)))
+
+static void
+DataProviderReleaseCallback (void *info, const void *data, size_t size)
+{
+ cairo_surface_t *surface = (cairo_surface_t *) info;
+ cairo_surface_destroy (surface);
+}
+
+CGImageRef
+_cairo_quartz_create_cgimage (cairo_format_t format,
+ unsigned int width,
+ unsigned int height,
+ unsigned int stride,
+ void *data,
+ cairo_bool_t interpolate,
+ CGColorSpaceRef colorSpaceOverride,
+ CGDataProviderReleaseDataCallback releaseCallback,
+ void *releaseInfo)
+{
+ CGImageRef image = NULL;
+ CGDataProviderRef dataProvider = NULL;
+ CGColorSpaceRef colorSpace = colorSpaceOverride;
+ CGBitmapInfo bitinfo;
+ int bitsPerComponent, bitsPerPixel;
+
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ if (colorSpace == NULL)
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+ bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
+ bitsPerComponent = 8;
+ bitsPerPixel = 32;
+ break;
+
+ case CAIRO_FORMAT_RGB24:
+ if (colorSpace == NULL)
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+ bitinfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
+ bitsPerComponent = 8;
+ bitsPerPixel = 32;
+ break;
+
+ /* XXX -- should use CGImageMaskCreate! */
+ case CAIRO_FORMAT_A8:
+ if (colorSpace == NULL)
+ colorSpace = CGColorSpaceCreateDeviceGray();
+ bitinfo = kCGImageAlphaNone;
+ bitsPerComponent = 8;
+ bitsPerPixel = 8;
+ break;
+
+ case CAIRO_FORMAT_A1:
+ default:
+ return NULL;
+ }
+
+ dataProvider = CGDataProviderCreateWithData (releaseInfo,
+ data,
+ height * stride,
+ releaseCallback);
+
+ if (!dataProvider) {
+ // manually release
+ if (releaseCallback)
+ releaseCallback (releaseInfo, data, height * stride);
+ goto FINISH;
+ }
+
+ image = CGImageCreate (width, height,
+ bitsPerComponent,
+ bitsPerPixel,
+ stride,
+ colorSpace,
+ bitinfo,
+ dataProvider,
+ NULL,
+ interpolate,
+ kCGRenderingIntentDefault);
+
+FINISH:
+
+ CGDataProviderRelease (dataProvider);
+
+ if (colorSpace != colorSpaceOverride)
+ CGColorSpaceRelease (colorSpace);
+
+ return image;
+}
+
+
+static cairo_surface_t *
+_cairo_quartz_image_surface_create_similar (void *asurface,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_surface_t *result;
+ cairo_surface_t *isurf = cairo_image_surface_create (_cairo_format_from_content (content),
+ width,
+ height);
+ if (cairo_surface_status(isurf))
+ return isurf;
+
+ result = cairo_quartz_image_surface_create (isurf);
+ cairo_surface_destroy (isurf);
+
+ return result;
+}
+
+static cairo_status_t
+_cairo_quartz_image_surface_finish (void *asurface)
+{
+ cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
+
+ /* the imageSurface will be destroyed by the data provider's release callback */
+ CGImageRelease (surface->image);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_quartz_image_surface_acquire_source_image (void *asurface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
+
+ *image_out = surface->imageSurface;
+ *image_extra = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_quartz_image_surface_acquire_dest_image (void *asurface,
+ cairo_rectangle_int_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_int_t *image_rect,
+ void **image_extra)
+{
+ cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
+
+ *image_out = surface->imageSurface;
+ *image_rect = surface->extents;
+ *image_extra = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+
+}
+
+static cairo_int_status_t
+_cairo_quartz_image_surface_get_extents (void *asurface,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
+
+ *extents = surface->extents;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* we assume some drawing happened to the image buffer; make sure it's
+ * represented in the CGImage on flush()
+ */
+
+static cairo_status_t
+_cairo_quartz_image_surface_flush (void *asurface)
+{
+ cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
+ CGImageRef oldImage = surface->image;
+ CGImageRef newImage = NULL;
+
+ /* To be released by the ReleaseCallback */
+ cairo_surface_reference ((cairo_surface_t*) surface->imageSurface);
+
+ newImage = _cairo_quartz_create_cgimage (surface->imageSurface->format,
+ surface->imageSurface->width,
+ surface->imageSurface->height,
+ surface->imageSurface->stride,
+ surface->imageSurface->data,
+ FALSE,
+ NULL,
+ DataProviderReleaseCallback,
+ surface->imageSurface);
+
+ surface->image = newImage;
+ CGImageRelease (oldImage);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
+ CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
+ _cairo_quartz_image_surface_create_similar,
+ _cairo_quartz_image_surface_finish,
+ _cairo_quartz_image_surface_acquire_source_image,
+ NULL, /* release_source_image */
+ _cairo_quartz_image_surface_acquire_dest_image,
+ NULL, /* release_dest_image */
+ NULL, /* clone_similar */
+ NULL, /* composite */
+ NULL, /* fill_rectangles */
+ NULL, /* composite_trapezoids */
+ NULL, /* copy_page */
+ NULL, /* show_page */
+ NULL, /* set_clip_region */
+ NULL, /* intersect_clip_path */
+ _cairo_quartz_image_surface_get_extents,
+ NULL, /* old_show_glyphs */
+ NULL, /* get_font_options */
+ _cairo_quartz_image_surface_flush,
+ NULL, /* mark_dirty_rectangle */
+ NULL, /* scaled_font_fini */
+ NULL, /* scaled_glyph_fini */
+
+ NULL, /* paint */
+ NULL, /* mask */
+ NULL, /* stroke */
+ NULL, /* fill */
+ NULL, /* surface_show_glyphs */
+ NULL, /* snapshot */
+ NULL, /* is_similar */
+ NULL, /* reset */
+ NULL /* fill_stroke */
+
+};
+
+/**
+ * cairo_quartz_image_surface_create
+ * @surface: a cairo image surface to wrap with a quartz image surface
+ *
+ * Creates a Quartz surface backed by a CGImageRef that references the
+ * given image surface. The resulting surface can be rendered quickly
+ * when used as a source when rendering to a #cairo_quartz_surface. If
+ * the data in the image surface is every updated, cairo_surface_flush()
+ * must be called on the #cairo_quartz_image_surface to ensure that the
+ * CGImageRef refers to the updated data.
+ *
+ * Return value: the newly created surface.
+ *
+ * Since: 1.6
+ */
+cairo_surface_t *
+cairo_quartz_image_surface_create (cairo_surface_t *surface)
+{
+ cairo_quartz_image_surface_t *qisurf;
+
+ CGImageRef image;
+
+ CGContextRef cgContext;
+ CGColorSpaceRef cgColorspace;
+ CGBitmapInfo bitinfo;
+
+ cairo_image_surface_t *image_surface;
+ int width, height, stride;
+ cairo_format_t format;
+ unsigned char *data;
+
+ if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_IMAGE)
+ return SURFACE_ERROR_NO_MEMORY;
+
+ image_surface = (cairo_image_surface_t*) surface;
+ width = image_surface->width;
+ height = image_surface->height;
+ stride = image_surface->stride;
+ format = image_surface->format;
+ data = image_surface->data;
+
+ if (!_cairo_quartz_verify_surface_size(width, height))
+ return SURFACE_ERROR_NO_MEMORY;
+
+ if (width == 0 || height == 0)
+ return SURFACE_ERROR_NO_MEMORY;
+
+ if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24)
+ return SURFACE_ERROR_INVALID_FORMAT;
+
+ qisurf = malloc(sizeof(cairo_quartz_image_surface_t));
+ if (qisurf == NULL)
+ return SURFACE_ERROR_NO_MEMORY;
+
+ memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t));
+
+ /* In case the create_cgimage fails, this ref will
+ * be released via the callback (which will be called in
+ * case of failure.)
+ */
+ cairo_surface_reference (surface);
+
+ image = _cairo_quartz_create_cgimage (format,
+ width, height,
+ stride,
+ data,
+ FALSE,
+ NULL,
+ DataProviderReleaseCallback,
+ surface);
+
+ if (!image) {
+ free (qisurf);
+ return SURFACE_ERROR_NO_MEMORY;
+ }
+
+ _cairo_surface_init (&qisurf->base,
+ &cairo_quartz_image_surface_backend,
+ _cairo_content_from_format (format));
+
+ qisurf->extents.x = qisurf->extents.y = 0;
+ qisurf->extents.width = width;
+ qisurf->extents.height = height;
+
+ qisurf->image = image;
+ qisurf->imageSurface = image_surface;
+
+ return &qisurf->base;
+}
+
+
+cairo_surface_t *
+cairo_quartz_image_surface_get_image (cairo_surface_t *asurface)
+{
+ cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*) asurface;
+
+ if (cairo_surface_get_type(asurface) != CAIRO_SURFACE_TYPE_QUARTZ_IMAGE)
+ return NULL;
+
+ return (cairo_surface_t*) surface->imageSurface;
+}
diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h
index 52a3d7f..cf26f4f 100644
--- a/src/cairo-quartz-private.h
+++ b/src/cairo-quartz-private.h
@@ -46,11 +46,12 @@
typedef struct cairo_quartz_surface {
cairo_surface_t base;
- void *imageData;
-
CGContextRef cgContext;
CGAffineTransform cgContextBaseCTM;
+ void *imageData;
+ cairo_surface_t *imageSurfaceEquiv;
+
cairo_rectangle_int_t extents;
/* These are stored while drawing operations are in place, set up
@@ -63,7 +64,33 @@ typedef struct cairo_quartz_surface {
CGShadingRef sourceShading;
CGPatternRef sourcePattern;
+
+ CGInterpolationQuality oldInterpolationQuality;
} cairo_quartz_surface_t;
+
+typedef struct cairo_quartz_image_surface {
+ cairo_surface_t base;
+
+ cairo_rectangle_int_t extents;
+
+ CGImageRef image;
+ cairo_image_surface_t *imageSurface;
+} cairo_quartz_image_surface_t;
+
+cairo_bool_t
+_cairo_quartz_verify_surface_size(int width, int height);
+
+CGImageRef
+_cairo_quartz_create_cgimage (cairo_format_t format,
+ unsigned int width,
+ unsigned int height,
+ unsigned int stride,
+ void *data,
+ cairo_bool_t interpolate,
+ CGColorSpaceRef colorSpaceOverride,
+ CGDataProviderReleaseDataCallback releaseCallback,
+ void *releaseInfo);
+
#endif /* CAIRO_HAS_QUARTZ_SURFACE */
#if CAIRO_HAS_ATSUI_FONT
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 9aff1c3..e918ec0 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -34,12 +34,12 @@
* Vladimir Vukicevic <vladimir at mozilla.com>
*/
+#include <dlfcn.h>
+
#include "cairoint.h"
#include "cairo-quartz-private.h"
-#include <dlfcn.h>
-
/* The 10.5 SDK includes a funky new definition of FloatToFixed which
* causes all sorts of breakage; so reset to old-style definition
*/
@@ -140,7 +140,8 @@ static void quartz_ensure_symbols(void)
#define CG_MAX_WIDTH USHRT_MAX
/* is the desired size of the surface within bounds? */
-static cairo_bool_t verify_surface_size(int width, int height)
+cairo_bool_t
+_cairo_quartz_verify_surface_size(int width, int height)
{
/* hmmm, allow width, height == 0 ? */
if (width < 0 || height < 0) {
@@ -295,7 +296,7 @@ _cairo_quartz_cairo_operator_to_quartz (cairo_operator_t op)
return kPrivateCGCompositeCopy;
}
-static CGLineCap
+static inline CGLineCap
_cairo_quartz_cairo_line_cap_to_quartz (cairo_line_cap_t ccap)
{
switch (ccap) {
@@ -307,7 +308,7 @@ _cairo_quartz_cairo_line_cap_to_quartz (cairo_line_cap_t ccap)
return kCGLineCapButt;
}
-static CGLineJoin
+static inline CGLineJoin
_cairo_quartz_cairo_line_join_to_quartz (cairo_line_join_t cjoin)
{
switch (cjoin) {
@@ -319,7 +320,28 @@ _cairo_quartz_cairo_line_join_to_quartz (cairo_line_join_t cjoin)
return kCGLineJoinMiter;
}
-static void
+static inline CGInterpolationQuality
+_cairo_quartz_filter_to_quartz (cairo_filter_t filter)
+{
+ switch (filter) {
+ case CAIRO_FILTER_NEAREST:
+ return kCGInterpolationNone;
+
+ case CAIRO_FILTER_FAST:
+ return kCGInterpolationLow;
+
+ case CAIRO_FILTER_BEST:
+ return kCGInterpolationHigh;
+
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BILINEAR:
+ return kCGInterpolationDefault;
+ }
+
+ return kCGInterpolationDefault;
+}
+
+static inline void
_cairo_quartz_cairo_matrix_to_quartz (const cairo_matrix_t *src,
CGAffineTransform *dst)
{
@@ -393,114 +415,104 @@ CreateGradientFunction (cairo_gradient_pattern_t *gpat)
&callbacks);
}
-/* generic cairo surface -> #cairo_quartz_surface_t function */
-static cairo_int_status_t
-_cairo_quartz_surface_to_quartz (cairo_surface_t *target,
- cairo_surface_t *pat_surf,
- cairo_quartz_surface_t **quartz_surf)
-{
+/* Obtain a CGImageRef from a cairo_surface_t * */
- if (cairo_surface_get_type(pat_surf) != CAIRO_SURFACE_TYPE_QUARTZ) {
- /* XXXtodo/perf don't use clone if the source surface is an image surface! Instead,
- * just create the CGImage directly!
- */
+static CGImageRef
+_cairo_surface_to_cgimage (cairo_surface_t *target,
+ cairo_surface_t *source)
+{
+ cairo_surface_type_t stype = cairo_surface_get_type (source);
+ cairo_image_surface_t *isurf;
+ CGImageRef image, image2;
+ void *image_extra;
- cairo_surface_t *ref_type = target;
- cairo_surface_t *new_surf = NULL;
- cairo_rectangle_int_t rect;
- cairo_status_t status;
+ if (stype == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) {
+ cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) source;
+ return CGImageRetain (surface->image);
+ }
- if (ref_type == NULL)
- ref_type = cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ if (stype == CAIRO_SURFACE_TYPE_QUARTZ) {
+ cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source;
+ image = CGBitmapContextCreateImage (surface->cgContext);
+ if (image)
+ return image;
+ }
- status = _cairo_surface_get_extents (pat_surf, &rect);
+ if (stype != CAIRO_SURFACE_TYPE_IMAGE) {
+ cairo_status_t status =
+ _cairo_surface_acquire_source_image (source, &isurf, &image_extra);
if (status)
- return status;
-
- status = _cairo_surface_clone_similar (ref_type, pat_surf, rect.x, rect.y,
- rect.width, rect.height, &new_surf);
- if (target == NULL)
- cairo_surface_destroy(ref_type);
+ return NULL;
+ } else {
+ isurf = (cairo_image_surface_t *) source;
+ }
- if (status)
- return status;
+ image2 = _cairo_quartz_create_cgimage (isurf->format,
+ isurf->width,
+ isurf->height,
+ isurf->stride,
+ isurf->data,
+ FALSE,
+ NULL, NULL, NULL);
- if (new_surf &&
- cairo_surface_get_type (new_surf) != CAIRO_SURFACE_TYPE_QUARTZ)
- {
- ND((stderr, "got a non-quartz surface, format=%d width=%u height=%u type=%d\n", cairo_surface_get_type (pat_surf), rect.width, rect.height, cairo_surface_get_type (new_surf)));
- cairo_surface_destroy (new_surf);
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
+ image = CGImageCreateCopy (image2);
+ CGImageRelease (image2);
- *quartz_surf = (cairo_quartz_surface_t *) new_surf;
- } else {
- /* If it's a quartz surface, we can try to see if it's a CGBitmapContext;
- * we do this when we call CGBitmapContextCreateImage below.
- */
- cairo_surface_reference (pat_surf);
- *quartz_surf = (cairo_quartz_surface_t*) pat_surf;
- }
+ if ((cairo_surface_t*) isurf != source)
+ _cairo_surface_release_source_image (source, isurf, image_extra);
- return CAIRO_STATUS_SUCCESS;
+ return image;
}
/* Generic #cairo_pattern_t -> CGPattern function */
-static void
-SurfacePatternDrawFunc (void *info, CGContextRef context)
-{
- cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) info;
- cairo_surface_t *pat_surf = spat->surface;
- cairo_int_status_t status;
- cairo_quartz_surface_t *quartz_surf;
- CGImageRef img;
+typedef struct {
+ CGImageRef image;
CGRect imageBounds;
+ cairo_bool_t do_reflect;
+} SurfacePatternDrawInfo;
- status = _cairo_quartz_surface_to_quartz (NULL, pat_surf, &quartz_surf);
- if (status)
- return;
+static void
+SurfacePatternDrawFunc (void *ainfo, CGContextRef context)
+{
+ SurfacePatternDrawInfo *info = (SurfacePatternDrawInfo*) ainfo;
- img = CGBitmapContextCreateImage (quartz_surf->cgContext);
- if (!img) {
- // ... give up.
- ND((stderr, "CGBitmapContextCreateImage failed\n"));
- _cairo_error (CAIRO_STATUS_NO_MEMORY);
- cairo_surface_destroy ((cairo_surface_t*)quartz_surf);
- return;
- }
+ CGContextTranslateCTM (context, 0, info->imageBounds.size.height);
+ CGContextScaleCTM (context, 1, -1);
- /* XXXtodo WHY does this need to be flipped? Writing this stuff
- * to disk shows that in both this path and the path above the source image
- * has an identical orientation, and the destination context at all times has a Y
- * flip. So why do we need to flip in this case?
- */
- if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) {
- CGContextTranslateCTM (context, 0, CGImageGetHeight(img));
- CGContextScaleCTM (context, 1, -1);
- }
-
- imageBounds.size = CGSizeMake (CGImageGetWidth(img), CGImageGetHeight(img));
- imageBounds.origin.x = 0;
- imageBounds.origin.y = 0;
+ CGContextDrawImage (context, info->imageBounds, info->image);
+ if (info->do_reflect) {
+ /* draw 3 more copies of the image, flipped.
+ * DrawImage draws the image according to the current Y-direction into the rectangle given
+ * (imageBounds); at the time of the first DrawImage above, the origin is at the bottom left
+ * of the base image position, and the Y axis is extending upwards.
+ */
- CGContextDrawImage (context, imageBounds, img);
- if (spat->base.extend == CAIRO_EXTEND_REFLECT) {
- /* draw 3 more copies of the image, flipped. */
- CGContextTranslateCTM (context, 0, 2 * imageBounds.size.height);
+ /* Make the y axis extend downwards, and draw a flipped image below */
CGContextScaleCTM (context, 1, -1);
- CGContextDrawImage (context, imageBounds, img);
- CGContextTranslateCTM (context, 2 * imageBounds.size.width, 0);
+ CGContextDrawImage (context, info->imageBounds, info->image);
+
+ /* Shift over to the right, and flip vertically (translation is 2x,
+ * since we'll be flipping and thus rendering the rectangle "backwards"
+ */
+ CGContextTranslateCTM (context, 2 * info->imageBounds.size.width, 0);
CGContextScaleCTM (context, -1, 1);
- CGContextDrawImage (context, imageBounds, img);
- CGContextTranslateCTM (context, 0, 2 * imageBounds.size.height);
+ CGContextDrawImage (context, info->imageBounds, info->image);
+
+ /* Then unflip the Y-axis again, and draw the image above the point. */
CGContextScaleCTM (context, 1, -1);
- CGContextDrawImage (context, imageBounds, img);
+ CGContextDrawImage (context, info->imageBounds, info->image);
+
}
+}
- CGImageRelease (img);
+static void
+SurfacePatternReleaseInfoFunc (void *ainfo)
+{
+ SurfacePatternDrawInfo *info = (SurfacePatternDrawInfo*) ainfo;
- cairo_surface_destroy ((cairo_surface_t*) quartz_surf);
+ CGImageRelease (info->image);
+ free (info);
}
/* Borrowed from cairo-meta-surface */
@@ -532,50 +544,64 @@ _init_pattern_with_snapshot (cairo_pattern_t *pattern,
static cairo_int_status_t
_cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t *dest,
- cairo_pattern_t *abspat,
+ cairo_pattern_t *apattern,
CGPatternRef *cgpat)
{
- cairo_surface_pattern_t *spat;
+ cairo_surface_pattern_t *spattern;
cairo_surface_t *pat_surf;
cairo_rectangle_int_t extents;
+ CGImageRef image;
CGRect pbounds;
CGAffineTransform ptransform, stransform;
CGPatternCallbacks cb = { 0,
SurfacePatternDrawFunc,
- (CGFunctionReleaseInfoCallback) cairo_pattern_destroy };
+ SurfacePatternReleaseInfoFunc };
+ SurfacePatternDrawInfo *info;
float rw, rh;
cairo_status_t status;
- cairo_pattern_union_t *snap_pattern = NULL;
- cairo_pattern_t *target_pattern = abspat;
-
cairo_matrix_t m;
+
/* SURFACE is the only type we'll handle here */
- if (abspat->type != CAIRO_PATTERN_TYPE_SURFACE)
+ if (apattern->type != CAIRO_PATTERN_TYPE_SURFACE)
return CAIRO_INT_STATUS_UNSUPPORTED;
- spat = (cairo_surface_pattern_t *) abspat;
- pat_surf = spat->surface;
+ spattern = (cairo_surface_pattern_t *) apattern;
+ pat_surf = spattern->surface;
status = _cairo_surface_get_extents (pat_surf, &extents);
if (status)
return status;
+ image = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf);
+ if (image == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ info = malloc(sizeof(SurfacePatternDrawInfo));
+ if (!info)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ /* XXX -- if we're printing, we may need to call CGImageCreateCopy to make sure
+ * that the data will stick around for this image when the printer gets to it.
+ * Otherwise, the underlying data store may disappear from under us!
+ *
+ * _cairo_surface_to_cgimage will copy when it converts non-Quartz surfaces,
+ * since the Quartz surfaces have a higher chance of sticking around. If the
+ * source is a quartz image surface, then it's set up to retain a ref to the
+ * image surface that it's backed by.
+ */
+ info->image = image;
+
+ info->imageBounds = CGRectMake (0, 0, extents.width, extents.height);
+
pbounds.origin.x = 0;
pbounds.origin.y = 0;
- // kjs seems to indicate this should work (setting to 0,0 to avoid
- // tiling); however, the pattern CTM scaling ends up being NaN in
- // the pattern draw function if either rw or rh are 0.
- // XXXtodo get pattern drawing working with extend options
- // XXXtodo/perf optimize CAIRO_EXTEND_NONE to a single DrawImage instead of a pattern
- if (spat->base.extend == CAIRO_EXTEND_REFLECT) {
- /* XXX broken; need to emulate by reflecting the image into 4 quadrants
- * and then tiling that
- */
- pbounds.size.width = 2 * extents.width;
- pbounds.size.height = 2 * extents.height;
+ if (spattern->base.extend == CAIRO_EXTEND_REFLECT) {
+ pbounds.size.width = 2.0 * extents.width;
+ pbounds.size.height = 2.0 * extents.height;
+ info->do_reflect = TRUE;
} else {
pbounds.size.width = extents.width;
pbounds.size.height = extents.height;
@@ -583,7 +609,7 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
rw = pbounds.size.width;
rh = pbounds.size.height;
- m = spat->base.matrix;
+ m = spattern->base.matrix;
cairo_matrix_invert(&m);
_cairo_quartz_cairo_matrix_to_quartz (&m, &stransform);
@@ -601,25 +627,14 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
ND((stderr, " context xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", xform.tx, xform.ty, xform.a, xform.b, xform.c, xform.d));
#endif
+ *cgpat = CGPatternCreate (info,
+ pbounds,
+ ptransform,
+ rw, rh,
+ kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */
+ TRUE,
+ &cb);
- /* XXX fixme: only do snapshots if the context is for printing, or get rid of the
- other block if it doesn't fafect performance */
- if (1 /* context is for printing */) {
- snap_pattern = (cairo_pattern_union_t*) malloc(sizeof(cairo_pattern_union_t));
- target_pattern = (cairo_pattern_t*) snap_pattern;
- _init_pattern_with_snapshot (target_pattern, abspat);
- } else {
- cairo_pattern_reference (abspat);
- target_pattern = abspat;
- }
-
- *cgpat = CGPatternCreate (target_pattern,
- pbounds,
- ptransform,
- rw, rh,
- kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */
- TRUE,
- &cb);
return CAIRO_STATUS_SUCCESS;
}
@@ -751,6 +766,9 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
{
assert (!(surface->sourceImage || surface->sourceShading || surface->sourcePattern));
+ surface->oldInterpolationQuality = CGContextGetInterpolationQuality (surface->cgContext);
+ CGContextSetInterpolationQuality (surface->cgContext, _cairo_quartz_filter_to_quartz (source->filter));
+
if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
@@ -785,7 +803,6 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
{
cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) source;
cairo_surface_t *pat_surf = spat->surface;
- cairo_quartz_surface_t *quartz_surf;
CGImageRef img;
cairo_matrix_t m = spat->base.matrix;
cairo_rectangle_int_t extents;
@@ -794,16 +811,7 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
CGRect srcRect;
cairo_fixed_t fw, fh;
- status = _cairo_quartz_surface_to_quartz ((cairo_surface_t *) surface, pat_surf, &quartz_surf);
- if (status)
- return DO_UNSUPPORTED;
-
- surface->sourceImageSurface = (cairo_surface_t *)quartz_surf;
-
- if (IS_EMPTY(quartz_surf))
- return DO_NOTHING;
-
- img = CGBitmapContextCreateImage (quartz_surf->cgContext);
+ img = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf);
if (!img)
return DO_UNSUPPORTED;
@@ -898,6 +906,8 @@ static void
_cairo_quartz_teardown_source (cairo_quartz_surface_t *surface,
cairo_pattern_t *source)
{
+ CGContextSetInterpolationQuality (surface->cgContext, surface->oldInterpolationQuality);
+
if (surface->sourceImage) {
CGImageRelease(surface->sourceImage);
surface->sourceImage = NULL;
@@ -937,6 +947,11 @@ _cairo_quartz_get_image (cairo_quartz_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
+ if (surface->imageSurfaceEquiv) {
+ *image_out = (cairo_image_surface_t*) cairo_surface_reference(surface->imageSurfaceEquiv);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
if (CGBitmapContextGetBitsPerPixel(surface->cgContext) != 0) {
unsigned int stride;
unsigned int bitinfo;
@@ -945,6 +960,7 @@ _cairo_quartz_get_image (cairo_quartz_surface_t *surface,
unsigned int color_comps;
imageData = (unsigned char *) CGBitmapContextGetData(surface->cgContext);
+
#ifdef USE_10_3_WORKAROUNDS
bitinfo = CGBitmapContextGetAlphaInfo (surface->cgContext);
#else
@@ -1029,6 +1045,11 @@ _cairo_quartz_surface_finish (void *abstract_surface)
surface->cgContext = NULL;
+ if (surface->imageSurfaceEquiv) {
+ cairo_surface_destroy (surface->imageSurfaceEquiv);
+ surface->imageSurfaceEquiv = NULL;
+ }
+
if (surface->imageData) {
free (surface->imageData);
surface->imageData = NULL;
@@ -1121,7 +1142,7 @@ _cairo_quartz_surface_create_similar (void *abstract_surface,
return NULL;
// verify width and height of surface
- if (!verify_surface_size(width, height)) {
+ if (!_cairo_quartz_verify_surface_size(width, height)) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
@@ -1131,12 +1152,12 @@ _cairo_quartz_surface_create_similar (void *abstract_surface,
static cairo_status_t
_cairo_quartz_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- cairo_surface_t **clone_out)
+ cairo_surface_t *src,
+ int src_x,
+ int src_y,
+ int width,
+ int height,
+ cairo_surface_t **clone_out)
{
cairo_quartz_surface_t *new_surface = NULL;
cairo_format_t new_format;
@@ -1145,97 +1166,58 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
*clone_out = NULL;
// verify width and height of surface
- if (!verify_surface_size(width, height)) {
+ if (!_cairo_quartz_verify_surface_size(width, height)) {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- if (cairo_surface_get_type(src) == CAIRO_SURFACE_TYPE_QUARTZ) {
+ if (width == 0 || height == 0) {
+ *clone_out = (cairo_surface_t*)
+ _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA,
+ width, height);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (src->backend->type == CAIRO_SURFACE_TYPE_QUARTZ) {
cairo_quartz_surface_t *qsurf = (cairo_quartz_surface_t *) src;
if (IS_EMPTY(qsurf)) {
- *clone_out = (cairo_surface_t*) _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, qsurf->extents.width, qsurf->extents.height);
+ *clone_out = (cairo_surface_t*)
+ _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA,
+ qsurf->extents.width, qsurf->extents.height);
return CAIRO_STATUS_SUCCESS;
}
-
- quartz_image = CGBitmapContextCreateImage (qsurf->cgContext);
- new_format = CAIRO_FORMAT_ARGB32; /* XXX bogus; recover a real format from the image */
- } else if (_cairo_surface_is_image (src)) {
- cairo_image_surface_t *isurf = (cairo_image_surface_t *) src;
- CGDataProviderRef dataProvider;
- CGColorSpaceRef cgColorspace;
- CGBitmapInfo bitinfo;
- int bitsPerComponent, bitsPerPixel;
-
- if (isurf->width == 0 || isurf->height == 0) {
- *clone_out = (cairo_surface_t*) _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA, isurf->width, isurf->height);
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (isurf->format == CAIRO_FORMAT_ARGB32) {
- cgColorspace = CGColorSpaceCreateDeviceRGB();
- bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
- bitsPerComponent = 8;
- bitsPerPixel = 32;
- } else if (isurf->format == CAIRO_FORMAT_RGB24) {
- cgColorspace = CGColorSpaceCreateDeviceRGB();
- bitinfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
- bitsPerComponent = 8;
- bitsPerPixel = 32;
- } else if (isurf->format == CAIRO_FORMAT_A8) {
- cgColorspace = CGColorSpaceCreateDeviceGray();
- bitinfo = kCGImageAlphaNone;
- bitsPerComponent = 8;
- bitsPerPixel = 8;
- } else {
- /* SUPPORT A1, maybe */
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- new_format = isurf->format;
-
- dataProvider = CGDataProviderCreateWithData (NULL,
- isurf->data,
- isurf->height * isurf->stride,
- NULL);
-
- quartz_image = CGImageCreate (isurf->width, isurf->height,
- bitsPerComponent,
- bitsPerPixel,
- isurf->stride,
- cgColorspace,
- bitinfo,
- dataProvider,
- NULL,
- false,
- kCGRenderingIntentDefault);
- CGDataProviderRelease (dataProvider);
- CGColorSpaceRelease (cgColorspace);
- } else {
- return CAIRO_INT_STATUS_UNSUPPORTED;
}
+ quartz_image = _cairo_surface_to_cgimage ((cairo_surface_t*) abstract_surface, src);
if (!quartz_image)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ new_format = CAIRO_FORMAT_ARGB32; /* assumed */
+ if (_cairo_surface_is_image (src)) {
+ new_format = ((cairo_image_surface_t *) src)->format;
+ }
+
new_surface = (cairo_quartz_surface_t *)
- cairo_quartz_surface_create (new_format,
- CGImageGetWidth (quartz_image),
- CGImageGetHeight (quartz_image));
+ cairo_quartz_surface_create (new_format, width, height);
if (!new_surface || new_surface->base.status) {
CGImageRelease (quartz_image);
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+ CGContextSaveGState (new_surface->cgContext);
+
CGContextSetCompositeOperation (new_surface->cgContext,
kPrivateCGCompositeCopy);
- quartz_image_to_png (quartz_image, NULL);
-
+ CGContextTranslateCTM (new_surface->cgContext, -src_x, -src_y);
CGContextDrawImage (new_surface->cgContext,
- CGRectMake (src_x, src_y, width, height),
+ CGRectMake (0, 0, CGImageGetWidth(quartz_image), CGImageGetHeight(quartz_image)),
quartz_image);
- CGImageRelease (quartz_image);
+ CGContextRestoreGState (new_surface->cgContext);
+
+ CGImageRelease (quartz_image);
+
*clone_out = (cairo_surface_t*) new_surface;
return CAIRO_STATUS_SUCCESS;
@@ -1254,8 +1236,8 @@ _cairo_quartz_surface_get_extents (void *abstract_surface,
static cairo_int_status_t
_cairo_quartz_surface_paint (void *abstract_surface,
- cairo_operator_t op,
- cairo_pattern_t *source)
+ cairo_operator_t op,
+ cairo_pattern_t *source)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@@ -1281,17 +1263,11 @@ _cairo_quartz_surface_paint (void *abstract_surface,
} else if (action == DO_SHADING) {
CGContextDrawShading (surface->cgContext, surface->sourceShading);
} else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
- cairo_surface_pattern_t *surface_pattern =
- (cairo_surface_pattern_t *) source;
- cairo_surface_t *pat_surf = surface_pattern->surface;
-
CGContextSaveGState (surface->cgContext);
CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform);
- if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) {
- CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage));
- CGContextScaleCTM (surface->cgContext, 1, -1);
- }
+ CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
+ CGContextScaleCTM (surface->cgContext, 1, -1);
if (action == DO_IMAGE)
CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
@@ -1361,19 +1337,14 @@ _cairo_quartz_surface_fill (void *abstract_surface,
CGContextDrawShading (surface->cgContext, surface->sourceShading);
} else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
- cairo_surface_pattern_t *surface_pattern =
- (cairo_surface_pattern_t *) source;
- cairo_surface_t *pat_surf = surface_pattern->surface;
if (fill_rule == CAIRO_FILL_RULE_WINDING)
CGContextClip (surface->cgContext);
else
CGContextEOClip (surface->cgContext);
CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform);
- if (cairo_surface_get_type(pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) {
- CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage));
- CGContextScaleCTM (surface->cgContext, 1, -1);
- }
+ CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
+ CGContextScaleCTM (surface->cgContext, 1, -1);
if (action == DO_IMAGE)
CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
@@ -1470,10 +1441,8 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
CGContextClip (surface->cgContext);
CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform);
- if (cairo_surface_get_type(((cairo_surface_pattern_t*)source)->surface) == CAIRO_SURFACE_TYPE_QUARTZ) {
- CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage));
- CGContextScaleCTM (surface->cgContext, 1, -1);
- }
+ CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
+ CGContextScaleCTM (surface->cgContext, 1, -1);
if (action == DO_IMAGE)
CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
@@ -1622,10 +1591,8 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform);
- if (cairo_surface_get_type(((cairo_surface_pattern_t*)source)->surface) == CAIRO_SURFACE_TYPE_QUARTZ) {
- CGContextTranslateCTM (surface->cgContext, 0, CGImageGetHeight(surface->sourceImage));
- CGContextScaleCTM (surface->cgContext, 1, -1);
- }
+ CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
+ CGContextScaleCTM (surface->cgContext, 1, -1);
if (action == DO_IMAGE)
CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
@@ -1659,7 +1626,6 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
cairo_surface_pattern_t *mask)
{
cairo_rectangle_int_t extents;
- cairo_quartz_surface_t *quartz_surf;
CGRect rect;
CGImageRef img;
cairo_surface_t *pat_surf = mask->surface;
@@ -1669,37 +1635,43 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
if (status)
return status;
- status = _cairo_quartz_surface_to_quartz (NULL, pat_surf, &quartz_surf);
- if (status)
- return status;
-
// everything would be masked out, so do nothing
- if (IS_EMPTY(quartz_surf))
+ if (extents.width == 0 || extents.height == 0)
goto BAIL;
- img = CGBitmapContextCreateImage (quartz_surf->cgContext);
+ img = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf);
if (!img) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
rect = CGRectMake (-mask->base.matrix.x0, -mask->base.matrix.y0, extents.width, extents.height);
+
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 */
+ CGAffineTransform ctm = CGContextGetCTM (surface->cgContext);
+ CGContextTranslateCTM (surface->cgContext, 0.0f, rect.size.height);
+ CGContextScaleCTM (surface->cgContext, 1.0f, -1.0f);
+
CGContextClipToMaskPtr (surface->cgContext, rect, img);
+
+ CGContextSetCTM (surface->cgContext, ctm);
+
status = _cairo_quartz_surface_paint (surface, op, source);
CGContextRestoreGState (surface->cgContext);
CGImageRelease (img);
BAIL:
- cairo_surface_destroy ((cairo_surface_t*) quartz_surf);
return status;
}
static cairo_int_status_t
_cairo_quartz_surface_mask (void *abstract_surface,
- cairo_operator_t op,
- cairo_pattern_t *source,
- cairo_pattern_t *mask)
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_pattern_t *mask)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@@ -1871,6 +1843,7 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
surface->cgContextBaseCTM = CGContextGetCTM (cgContext);
surface->imageData = NULL;
+ surface->imageSurfaceEquiv = NULL;
return surface;
}
@@ -1953,7 +1926,7 @@ cairo_quartz_surface_create (cairo_format_t format,
int bitsPerComponent;
// verify width and height of surface
- if (!verify_surface_size(width, height))
+ if (!_cairo_quartz_verify_surface_size(width, height))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
if (width == 0 || height == 0) {
@@ -1994,6 +1967,7 @@ cairo_quartz_surface_create (cairo_format_t format,
CGColorSpaceRelease (cgColorspace);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
+
/* zero the memory to match the image surface behaviour */
memset (imageData, 0, height * stride);
@@ -2025,6 +1999,7 @@ cairo_quartz_surface_create (cairo_format_t format,
}
surf->imageData = imageData;
+ surf->imageSurfaceEquiv = cairo_image_surface_create_for_data (imageData, format, width, height, stride);
return (cairo_surface_t *) surf;
}
@@ -2151,4 +2126,3 @@ quartz_surface_to_png (cairo_quartz_surface_t *nq, char *dest)
CGImageRelease(imgref);
#endif
}
-
diff --git a/src/cairo-quartz.h b/src/cairo-quartz.h
index 5d78d39..c0edb0c 100644
--- a/src/cairo-quartz.h
+++ b/src/cairo-quartz.h
@@ -57,6 +57,12 @@ cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
cairo_public CGContextRef
cairo_quartz_surface_get_cg_context (cairo_surface_t *surface);
+cairo_public cairo_surface_t *
+cairo_quartz_image_surface_create (cairo_surface_t *image_surface);
+
+cairo_public cairo_surface_t *
+cairo_quartz_image_surface_get_image (cairo_surface_t *surface);
+
CAIRO_END_DECLS
#else /* CAIRO_HAS_QUARTZ_SURFACE */
diff --git a/src/cairo.h b/src/cairo.h
index 5988f3a..cf14e6f 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1491,6 +1491,7 @@ cairo_surface_status (cairo_surface_t *surface);
* @CAIRO_SURFACE_TYPE_SVG: The surface is of type svg
* @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2
* @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface
+ * @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image
*
* #cairo_surface_type_t is used to describe the type of a given
* surface. The surface types are also known as "backends" or "surface
@@ -1528,7 +1529,8 @@ typedef enum _cairo_surface_type {
CAIRO_SURFACE_TYPE_DIRECTFB,
CAIRO_SURFACE_TYPE_SVG,
CAIRO_SURFACE_TYPE_OS2,
- CAIRO_SURFACE_TYPE_WIN32_PRINTING
+ CAIRO_SURFACE_TYPE_WIN32_PRINTING,
+ CAIRO_SURFACE_TYPE_QUARTZ_IMAGE
} cairo_surface_type_t;
cairo_public cairo_surface_type_t
More information about the cairo-commit
mailing list