Bug 892966 - Make gfxQuartzNativeDrawing support Moz2D surfaces. r=jrmuizel

This commit is contained in:
Matt Woodrow 2013-07-12 17:19:29 -04:00
parent 6450d9080b
commit 0debdb2a99
6 changed files with 94 additions and 10 deletions

View File

@ -839,6 +839,8 @@ public:
*/
virtual void *GetNativeSurface(NativeSurfaceType aType) { return NULL; }
virtual bool IsDualDrawTarget() { return false; }
void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
mUserData.Add(key, userData, destroy);
}
@ -1012,11 +1014,28 @@ private:
class BorrowedCGContext
{
public:
BorrowedCGContext(DrawTarget *aDT) : mDT(aDT)
BorrowedCGContext()
: cg(nullptr)
, mDT(nullptr)
{ }
BorrowedCGContext(DrawTarget *aDT)
: mDT(aDT)
{
cg = BorrowCGContextFromDrawTarget(aDT);
}
// We can optionally Init after construction in
// case we don't know what the DT will be at construction
// time.
CGContextRef Init(DrawTarget *aDT)
{
MOZ_ASSERT(!mDT, "Can't initialize twice!");
mDT = aDT;
cg = BorrowCGContextFromDrawTarget(aDT);
return cg;
}
// The caller needs to call Finish if cg is non-null when
// they are done with the context. This is currently explicit
// instead of happening implicitly in the destructor to make

View File

@ -1195,6 +1195,8 @@ BorrowedCGContext::BorrowCGContextFromDrawTarget(DrawTarget *aDT)
// save the state to make it easier for callers to avoid mucking with things
CGContextSaveGState(cg);
CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(cgDT->mTransform));
return cg;
}
return nullptr;

View File

@ -131,6 +131,11 @@ public:
{
return nullptr;
}
virtual bool IsDualDrawTarget()
{
return true;
}
private:
RefPtr<DrawTarget> mA;

View File

@ -8,11 +8,15 @@
#include "gfxQuartzNativeDrawing.h"
#include "gfxQuartzSurface.h"
#include "cairo-quartz.h"
#include "mozilla/gfx/2D.h"
// see cairo-quartz-surface.c for the complete list of these
enum {
kPrivateCGCompositeSourceOver = 2
};
using namespace mozilla::gfx;
using namespace mozilla;
// private Quartz routine needed here
extern "C" {
CG_EXTERN void CGContextSetCompositeOperation(CGContextRef, int);
@ -21,7 +25,9 @@ extern "C" {
gfxQuartzNativeDrawing::gfxQuartzNativeDrawing(gfxContext* ctx,
const gfxRect& nativeRect,
gfxFloat aBackingScale)
: mContext(ctx), mNativeRect(nativeRect), mBackingScale(aBackingScale)
: mContext(ctx)
, mNativeRect(nativeRect)
, mBackingScale(aBackingScale)
{
mNativeRect.RoundOut();
}
@ -31,6 +37,26 @@ gfxQuartzNativeDrawing::BeginNativeDrawing()
{
NS_ASSERTION(!mQuartzSurface, "BeginNativeDrawing called when drawing already in progress");
if (!mContext->IsCairo()) {
DrawTarget *dt = mContext->GetDrawTarget();
if (mContext->GetDrawTarget()->IsDualDrawTarget()) {
IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
NSToIntFloor(mNativeRect.height * mBackingScale));
mDrawTarget = Factory::CreateDrawTarget(BACKEND_COREGRAPHICS, backingSize, FORMAT_B8G8R8A8);
Matrix transform;
transform.Scale(mBackingScale, mBackingScale);
transform.Translate(-mNativeRect.x, -mNativeRect.y);
mDrawTarget->SetTransform(transform);
dt = mDrawTarget;
}
mCGContext = mBorrowedContext.Init(dt);
MOZ_ASSERT(mCGContext);
return mCGContext;
}
gfxPoint deviceOffset;
nsRefPtr<gfxASurface> surf = mContext->CurrentSurface(&deviceOffset.x, &deviceOffset.y);
if (!surf || surf->CairoStatus())
@ -96,7 +122,34 @@ gfxQuartzNativeDrawing::BeginNativeDrawing()
void
gfxQuartzNativeDrawing::EndNativeDrawing()
{
NS_ASSERTION(mQuartzSurface, "EndNativeDrawing called without BeginNativeDrawing");
NS_ASSERTION(mCGContext, "EndNativeDrawing called without BeginNativeDrawing");
if (mBorrowedContext.cg) {
MOZ_ASSERT(!mContext->IsCairo());
mBorrowedContext.Finish();
if (mDrawTarget) {
DrawTarget *dest = mContext->GetDrawTarget();
RefPtr<SourceSurface> source = mDrawTarget->Snapshot();
IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
NSToIntFloor(mNativeRect.height * mBackingScale));
Matrix oldTransform = dest->GetTransform();
Matrix newTransform = oldTransform;
newTransform.Translate(mNativeRect.x, mNativeRect.y);
newTransform.Scale(1.0f / mBackingScale, 1.0f / mBackingScale);
dest->SetTransform(newTransform);
dest->DrawSurface(source,
gfx::Rect(0, 0, backingSize.width, backingSize.height),
gfx::Rect(0, 0, backingSize.width, backingSize.height));
dest->SetTransform(oldTransform);
}
return;
}
cairo_quartz_finish_cg_context_with_clip(mSurfaceContext->GetCairo());
mQuartzSurface->MarkDirty();

View File

@ -56,8 +56,11 @@ private:
gfxQuartzNativeDrawing(const gfxQuartzNativeDrawing&) MOZ_DELETE;
const gfxQuartzNativeDrawing& operator=(const gfxQuartzNativeDrawing&) MOZ_DELETE;
// Final destination context
nsRefPtr<gfxContext> mContext;
mozilla::RefPtr<mozilla::gfx::DrawTarget> mDrawTarget;
mozilla::gfx::BorrowedCGContext mBorrowedContext;
// context that draws to mQuartzSurface; can be different from mContext
// if mContext is not drawing to Quartz
nsRefPtr<gfxContext> mSurfaceContext;

View File

@ -2105,7 +2105,9 @@ nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, const nsIntRect& aRec
nsIntSize size = mResizeIndicatorRect.Size();
mResizerImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) {
ClearRegion(drawTarget, updateRegion);
DrawResizer(static_cast<CGContextRef>(drawTarget->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT)));
gfx::BorrowedCGContext borrow(drawTarget);
DrawResizer(borrow.cg);
borrow.Finish();
});
mResizerImage->Draw(aManager, mResizeIndicatorRect.TopLeft());
@ -2165,9 +2167,8 @@ nsChildView::UpdateTitlebarImageBuffer()
ClearRegion(mTitlebarImageBuffer, dirtyTitlebarRegion);
CGContextRef ctx =
static_cast<CGContextRef>(mTitlebarImageBuffer->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT));
CGContextSaveGState(ctx);
gfx::BorrowedCGContext borrow(mTitlebarImageBuffer);
CGContextRef ctx = borrow.cg;
double scale = BackingScaleFactor();
CGContextScaleCTM(ctx, scale, scale);
@ -2233,7 +2234,7 @@ nsChildView::UpdateTitlebarImageBuffer()
DevPixelsToCocoaPoints(1));
[NSGraphicsContext setCurrentContext:oldContext];
CGContextRestoreGState(ctx);
borrow.Finish();
mUpdatedTitlebarRegion.Or(mUpdatedTitlebarRegion, dirtyTitlebarRegion);
}
@ -2290,8 +2291,9 @@ nsChildView::MaybeDrawRoundedCorners(GLManager* aManager, const nsIntRect& aRect
nsIntSize size(mDevPixelCornerRadius, mDevPixelCornerRadius);
mCornerMaskImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) {
ClearRegion(drawTarget, updateRegion);
DrawTopLeftCornerMask(static_cast<CGContextRef>(drawTarget->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT)),
mDevPixelCornerRadius);
gfx::BorrowedCGContext borrow(drawTarget);
DrawTopLeftCornerMask(borrow.cg, mDevPixelCornerRadius);
borrow.Finish();
});
// Use operator destination in: multiply all 4 channels with source alpha.