Bug 562334. cairo: Fix cairo_quartz_get_cg_context_with_clip. r=vlad

A problem happens when clip->all_clipped is set and we go to get a clipped
context. Normally backends don't see operations with clip->all_clipped and so
_cairo_surface_clipper_set_clip is designed with the assumption that
clip->all_clipped is never true. I added a work-around by manually setting the
CGContextClip with an empty rectangle, however this caused cairo to be confused
about what the actual clip was.

This patch fixes the problem by adding a new function
cairo_quartz_finish_cg_context_with_clip that is called after we're done with
the native context. It moves the CGContextSave/RestoreGState calls out of
gfxNativeDrawing into cairo and uses them to ensure that the clip remains
consistent with cairo's model of them.
This commit is contained in:
Jeff Muizelaar 2010-04-29 23:19:08 -04:00
parent ef1655d6e9
commit c6adb55bed
4 changed files with 56 additions and 12 deletions

View File

@ -3112,10 +3112,14 @@ cairo_quartz_get_cg_context_with_clip (cairo_t *cr)
if (!clip->path) {
if (clip->all_clipped) {
/* Save the state before we set an empty clip rect so that
* our previous clip will be restored */
/* _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);
CGContextClipToRect (quartz->cgContext, empty);
CGContextSaveGState (quartz->cgContext);
return quartz->cgContext;
}
@ -3125,13 +3129,29 @@ cairo_quartz_get_cg_context_with_clip (cairo_t *cr)
}
status = _cairo_surface_clipper_set_clip (&quartz->clipper, clip);
/* Save the state after we set the clip so that it persists
* after we restore */
CGContextSaveGState (quartz->cgContext);
if (unlikely (status))
return NULL;
return quartz->cgContext;
}
void
cairo_quartz_finish_cg_context_with_clip (cairo_t *cr)
{
cairo_surface_t *surface = cr->gstate->target;
cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t*)surface;
if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_QUARTZ)
return;
CGContextRestoreGState (quartz->cgContext);
}
/* Debug stuff */

View File

@ -60,6 +60,9 @@ cairo_quartz_surface_get_cg_context (cairo_surface_t *surface);
cairo_public CGContextRef
cairo_quartz_get_cg_context_with_clip (cairo_t *cr);
cairo_public void
cairo_quartz_finish_cg_context_with_clip (cairo_t *cr);
#if CAIRO_HAS_QUARTZ_FONT
/*

View File

@ -1,11 +1,11 @@
commit 59038972ece5b3f6754ba8e46ce63718931fa415
commit 857df0583365228150b3319475efc43b22077d06
Author: Jeff Muizelaar <jmuizelaar@mozilla.com>
Date: Tue Apr 20 15:43:54 2010 -0400
native clipping
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index df063bf..14e4092 100644
index df063bf..819e53e 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -39,6 +39,8 @@
@ -17,7 +17,7 @@ index df063bf..14e4092 100644
#include <dlfcn.h>
@@ -3095,6 +3097,41 @@ cairo_quartz_surface_get_cg_context (cairo_surface_t *surface)
@@ -3095,6 +3097,61 @@ cairo_quartz_surface_get_cg_context (cairo_surface_t *surface)
return quartz->cgContext;
}
@ -36,10 +36,14 @@ index df063bf..14e4092 100644
+
+ if (!clip->path) {
+ if (clip->all_clipped) {
+ /* Save the state before we set an empty clip rect so that
+ * our previous clip will be restored */
+
+ /* _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);
+ CGContextClipToRect (quartz->cgContext, empty);
+ CGContextSaveGState (quartz->cgContext);
+
+ return quartz->cgContext;
+ }
@ -49,26 +53,45 @@ index df063bf..14e4092 100644
+ }
+
+ status = _cairo_surface_clipper_set_clip (&quartz->clipper, clip);
+
+ /* Save the state after we set the clip so that it persists
+ * after we restore */
+ CGContextSaveGState (quartz->cgContext);
+
+ if (unlikely (status))
+ return NULL;
+
+ return quartz->cgContext;
+}
+
+void
+cairo_quartz_finish_cg_context_with_clip (cairo_t *cr)
+{
+ cairo_surface_t *surface = cr->gstate->target;
+
+ cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t*)surface;
+
+ if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_QUARTZ)
+ return;
+
+ CGContextRestoreGState (quartz->cgContext);
+}
/* Debug stuff */
diff --git a/src/cairo-quartz.h b/src/cairo-quartz.h
index e8b71ba..7117987 100644
index e8b71ba..aa1cdd2 100644
--- a/src/cairo-quartz.h
+++ b/src/cairo-quartz.h
@@ -57,6 +57,9 @@ cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
@@ -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 CGContextRef
+cairo_quartz_get_cg_context_with_clip (cairo_t *cr);
+
+cairo_public void
+cairo_quartz_finish_cg_context_with_clip (cairo_t *cr);
+
#if CAIRO_HAS_QUARTZ_FONT

View File

@ -39,7 +39,7 @@
#include "gfxQuartzNativeDrawing.h"
#include "gfxQuartzSurface.h"
#include "cairo-quartz.h"
// see cairo-quartz-surface.c for the complete list of these
enum {
kPrivateCGCompositeSourceOver = 2
@ -83,12 +83,11 @@ gfxQuartzNativeDrawing::BeginNativeDrawing()
}
// grab the CGContextRef
mCGContext = mQuartzSurface->GetCGContextWithClip(mContext);
mCGContext = cairo_quartz_get_cg_context_with_clip(mContext->GetCairo());
if (!mCGContext)
return nsnull;
gfxMatrix m = mContext->CurrentMatrix();
CGContextSaveGState(mCGContext);
CGContextTranslateCTM(mCGContext, deviceOffset.x, deviceOffset.y);
// I -think- that this context will always have an identity
@ -121,8 +120,7 @@ gfxQuartzNativeDrawing::EndNativeDrawing()
{
NS_ASSERTION(mQuartzSurface, "EndNativeDrawing called without BeginNativeDrawing");
// we drew directly to a shared CGContextRef; restore previous context state
CGContextRestoreGState(mCGContext);
cairo_quartz_finish_cg_context_with_clip(mContext->GetCairo());
mQuartzSurface->MarkDirty();
mQuartzSurface = nsnull;
}