gfx/thebes/gfxQuartzNativeDrawing.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "gfxQuartzNativeDrawing.h"
michael@0 7 #include "gfxQuartzSurface.h"
michael@0 8 #include "gfxPlatform.h"
michael@0 9 #include "cairo-quartz.h"
michael@0 10
michael@0 11 // see cairo-quartz-surface.c for the complete list of these
michael@0 12 enum {
michael@0 13 kPrivateCGCompositeSourceOver = 2
michael@0 14 };
michael@0 15
michael@0 16 using namespace mozilla::gfx;
michael@0 17 using namespace mozilla;
michael@0 18
michael@0 19 // private Quartz routine needed here
michael@0 20 extern "C" {
michael@0 21 CG_EXTERN void CGContextSetCompositeOperation(CGContextRef, int);
michael@0 22 }
michael@0 23
michael@0 24 gfxQuartzNativeDrawing::gfxQuartzNativeDrawing(gfxContext* ctx,
michael@0 25 const gfxRect& nativeRect,
michael@0 26 gfxFloat aBackingScale)
michael@0 27 : mContext(ctx)
michael@0 28 , mNativeRect(nativeRect)
michael@0 29 , mBackingScale(aBackingScale)
michael@0 30 {
michael@0 31 mNativeRect.RoundOut();
michael@0 32 }
michael@0 33
michael@0 34 CGContextRef
michael@0 35 gfxQuartzNativeDrawing::BeginNativeDrawing()
michael@0 36 {
michael@0 37 NS_ASSERTION(!mQuartzSurface, "BeginNativeDrawing called when drawing already in progress");
michael@0 38
michael@0 39 gfxPoint deviceOffset;
michael@0 40 nsRefPtr<gfxASurface> surf;
michael@0 41
michael@0 42 if (!mContext->IsCairo()) {
michael@0 43 DrawTarget *dt = mContext->GetDrawTarget();
michael@0 44 if (dt->GetType() == BackendType::COREGRAPHICS) {
michael@0 45 if (dt->IsDualDrawTarget()) {
michael@0 46 IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
michael@0 47 NSToIntFloor(mNativeRect.height * mBackingScale));
michael@0 48
michael@0 49 if (backingSize.IsEmpty())
michael@0 50 return nullptr;
michael@0 51
michael@0 52 mDrawTarget = Factory::CreateDrawTarget(BackendType::COREGRAPHICS, backingSize, SurfaceFormat::B8G8R8A8);
michael@0 53
michael@0 54 Matrix transform;
michael@0 55 transform.Scale(mBackingScale, mBackingScale);
michael@0 56 transform.Translate(-mNativeRect.x, -mNativeRect.y);
michael@0 57
michael@0 58 mDrawTarget->SetTransform(transform);
michael@0 59 dt = mDrawTarget;
michael@0 60 }
michael@0 61
michael@0 62 mCGContext = mBorrowedContext.Init(dt);
michael@0 63 MOZ_ASSERT(mCGContext);
michael@0 64 return mCGContext;
michael@0 65 }
michael@0 66 surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(dt);
michael@0 67 } else {
michael@0 68 surf = mContext->CurrentSurface(&deviceOffset.x, &deviceOffset.y);
michael@0 69 }
michael@0 70 if (!surf || surf->CairoStatus())
michael@0 71 return nullptr;
michael@0 72
michael@0 73 // if this is a native Quartz surface, we don't have to redirect
michael@0 74 // rendering to our own CGContextRef; in most cases, we are able to
michael@0 75 // use the CGContextRef from the surface directly. we can extend
michael@0 76 // this to support offscreen drawing fairly easily in the future.
michael@0 77 if (surf->GetType() == gfxSurfaceType::Quartz &&
michael@0 78 (surf->GetContentType() == gfxContentType::COLOR ||
michael@0 79 (surf->GetContentType() == gfxContentType::COLOR_ALPHA))) {
michael@0 80 mQuartzSurface = static_cast<gfxQuartzSurface*>(surf.get());
michael@0 81 mSurfaceContext = mContext;
michael@0 82
michael@0 83 // grab the CGContextRef
michael@0 84 mCGContext = cairo_quartz_get_cg_context_with_clip(mSurfaceContext->GetCairo());
michael@0 85 if (!mCGContext)
michael@0 86 return nullptr;
michael@0 87
michael@0 88 gfxMatrix m = mContext->CurrentMatrix();
michael@0 89 CGContextTranslateCTM(mCGContext, deviceOffset.x, deviceOffset.y);
michael@0 90
michael@0 91 // I -think- that this context will always have an identity
michael@0 92 // transform (since we don't maintain a transform on it in
michael@0 93 // cairo-land, and instead push/pop as needed)
michael@0 94
michael@0 95 gfxFloat x0 = m.x0;
michael@0 96 gfxFloat y0 = m.y0;
michael@0 97
michael@0 98 // We round x0/y0 if we don't have a scale, because otherwise things get
michael@0 99 // rendered badly
michael@0 100 // XXX how should we be rounding x0/y0?
michael@0 101 if (!m.HasNonTranslationOrFlip()) {
michael@0 102 x0 = floor(x0 + 0.5);
michael@0 103 y0 = floor(y0 + 0.5);
michael@0 104 }
michael@0 105
michael@0 106 CGContextConcatCTM(mCGContext, CGAffineTransformMake(m.xx, m.yx,
michael@0 107 m.xy, m.yy,
michael@0 108 x0, y0));
michael@0 109
michael@0 110 // bug 382049 - need to explicity set the composite operation to sourceOver
michael@0 111 CGContextSetCompositeOperation(mCGContext, kPrivateCGCompositeSourceOver);
michael@0 112 } else {
michael@0 113 nsIntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
michael@0 114 NSToIntFloor(mNativeRect.height * mBackingScale));
michael@0 115 mQuartzSurface = new gfxQuartzSurface(backingSize,
michael@0 116 gfxImageFormat::ARGB32);
michael@0 117 if (mQuartzSurface->CairoStatus())
michael@0 118 return nullptr;
michael@0 119 mSurfaceContext = new gfxContext(mQuartzSurface);
michael@0 120
michael@0 121 // grab the CGContextRef
michael@0 122 mCGContext = cairo_quartz_get_cg_context_with_clip(mSurfaceContext->GetCairo());
michael@0 123 CGContextScaleCTM(mCGContext, mBackingScale, mBackingScale);
michael@0 124 CGContextTranslateCTM(mCGContext, -mNativeRect.X(), -mNativeRect.Y());
michael@0 125 }
michael@0 126
michael@0 127 return mCGContext;
michael@0 128 }
michael@0 129
michael@0 130 void
michael@0 131 gfxQuartzNativeDrawing::EndNativeDrawing()
michael@0 132 {
michael@0 133 NS_ASSERTION(mCGContext, "EndNativeDrawing called without BeginNativeDrawing");
michael@0 134
michael@0 135 if (mBorrowedContext.cg) {
michael@0 136 MOZ_ASSERT(!mContext->IsCairo());
michael@0 137 mBorrowedContext.Finish();
michael@0 138 if (mDrawTarget) {
michael@0 139 DrawTarget *dest = mContext->GetDrawTarget();
michael@0 140 RefPtr<SourceSurface> source = mDrawTarget->Snapshot();
michael@0 141
michael@0 142 IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
michael@0 143 NSToIntFloor(mNativeRect.height * mBackingScale));
michael@0 144
michael@0 145 Matrix oldTransform = dest->GetTransform();
michael@0 146 Matrix newTransform = oldTransform;
michael@0 147 newTransform.Translate(mNativeRect.x, mNativeRect.y);
michael@0 148 newTransform.Scale(1.0f / mBackingScale, 1.0f / mBackingScale);
michael@0 149
michael@0 150 dest->SetTransform(newTransform);
michael@0 151
michael@0 152 dest->DrawSurface(source,
michael@0 153 gfx::Rect(0, 0, backingSize.width, backingSize.height),
michael@0 154 gfx::Rect(0, 0, backingSize.width, backingSize.height));
michael@0 155
michael@0 156
michael@0 157 dest->SetTransform(oldTransform);
michael@0 158 }
michael@0 159 return;
michael@0 160 }
michael@0 161
michael@0 162 cairo_quartz_finish_cg_context_with_clip(mSurfaceContext->GetCairo());
michael@0 163 mQuartzSurface->MarkDirty();
michael@0 164 if (mSurfaceContext != mContext) {
michael@0 165 gfxContextMatrixAutoSaveRestore save(mContext);
michael@0 166
michael@0 167 // Copy back to destination
michael@0 168 mContext->Translate(mNativeRect.TopLeft());
michael@0 169 mContext->Scale(1.0f / mBackingScale, 1.0f / mBackingScale);
michael@0 170 mContext->DrawSurface(mQuartzSurface, mQuartzSurface->GetSize());
michael@0 171 }
michael@0 172 }

mercurial