gfx/thebes/gfxQuartzNativeDrawing.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/thebes/gfxQuartzNativeDrawing.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,172 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "gfxQuartzNativeDrawing.h"
    1.10 +#include "gfxQuartzSurface.h"
    1.11 +#include "gfxPlatform.h"
    1.12 +#include "cairo-quartz.h"
    1.13 +
    1.14 +// see cairo-quartz-surface.c for the complete list of these
    1.15 +enum {
    1.16 +    kPrivateCGCompositeSourceOver = 2
    1.17 +};
    1.18 +
    1.19 +using namespace mozilla::gfx;
    1.20 +using namespace mozilla;
    1.21 +
    1.22 +// private Quartz routine needed here
    1.23 +extern "C" {
    1.24 +    CG_EXTERN void CGContextSetCompositeOperation(CGContextRef, int);
    1.25 +}
    1.26 +
    1.27 +gfxQuartzNativeDrawing::gfxQuartzNativeDrawing(gfxContext* ctx,
    1.28 +                                               const gfxRect& nativeRect,
    1.29 +                                               gfxFloat aBackingScale)
    1.30 +    : mContext(ctx)
    1.31 +    , mNativeRect(nativeRect)
    1.32 +    , mBackingScale(aBackingScale)
    1.33 +{
    1.34 +    mNativeRect.RoundOut();
    1.35 +}
    1.36 +
    1.37 +CGContextRef
    1.38 +gfxQuartzNativeDrawing::BeginNativeDrawing()
    1.39 +{
    1.40 +    NS_ASSERTION(!mQuartzSurface, "BeginNativeDrawing called when drawing already in progress");
    1.41 +
    1.42 +    gfxPoint deviceOffset;
    1.43 +    nsRefPtr<gfxASurface> surf;
    1.44 +
    1.45 +    if (!mContext->IsCairo()) {
    1.46 +      DrawTarget *dt = mContext->GetDrawTarget();
    1.47 +      if (dt->GetType() == BackendType::COREGRAPHICS) {
    1.48 +        if (dt->IsDualDrawTarget()) {
    1.49 +          IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
    1.50 +                              NSToIntFloor(mNativeRect.height * mBackingScale));
    1.51 +
    1.52 +         if (backingSize.IsEmpty())
    1.53 +            return nullptr;
    1.54 +
    1.55 +          mDrawTarget = Factory::CreateDrawTarget(BackendType::COREGRAPHICS, backingSize, SurfaceFormat::B8G8R8A8);
    1.56 +
    1.57 +          Matrix transform;
    1.58 +          transform.Scale(mBackingScale, mBackingScale);
    1.59 +          transform.Translate(-mNativeRect.x, -mNativeRect.y);
    1.60 +
    1.61 +          mDrawTarget->SetTransform(transform);
    1.62 +          dt = mDrawTarget;
    1.63 +        }
    1.64 +
    1.65 +        mCGContext = mBorrowedContext.Init(dt);
    1.66 +        MOZ_ASSERT(mCGContext);
    1.67 +        return mCGContext;
    1.68 +      }
    1.69 +      surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(dt);
    1.70 +    } else {
    1.71 +      surf = mContext->CurrentSurface(&deviceOffset.x, &deviceOffset.y);
    1.72 +    }
    1.73 +    if (!surf || surf->CairoStatus())
    1.74 +        return nullptr;
    1.75 +
    1.76 +    // if this is a native Quartz surface, we don't have to redirect
    1.77 +    // rendering to our own CGContextRef; in most cases, we are able to
    1.78 +    // use the CGContextRef from the surface directly.  we can extend
    1.79 +    // this to support offscreen drawing fairly easily in the future.
    1.80 +    if (surf->GetType() == gfxSurfaceType::Quartz &&
    1.81 +        (surf->GetContentType() == gfxContentType::COLOR ||
    1.82 +         (surf->GetContentType() == gfxContentType::COLOR_ALPHA))) {
    1.83 +        mQuartzSurface = static_cast<gfxQuartzSurface*>(surf.get());
    1.84 +        mSurfaceContext = mContext;
    1.85 +
    1.86 +        // grab the CGContextRef
    1.87 +        mCGContext = cairo_quartz_get_cg_context_with_clip(mSurfaceContext->GetCairo());
    1.88 +        if (!mCGContext)
    1.89 +            return nullptr;
    1.90 +
    1.91 +        gfxMatrix m = mContext->CurrentMatrix();
    1.92 +        CGContextTranslateCTM(mCGContext, deviceOffset.x, deviceOffset.y);
    1.93 +
    1.94 +        // I -think- that this context will always have an identity
    1.95 +        // transform (since we don't maintain a transform on it in
    1.96 +        // cairo-land, and instead push/pop as needed)
    1.97 +
    1.98 +        gfxFloat x0 = m.x0;
    1.99 +        gfxFloat y0 = m.y0;
   1.100 +
   1.101 +        // We round x0/y0 if we don't have a scale, because otherwise things get
   1.102 +        // rendered badly
   1.103 +        // XXX how should we be rounding x0/y0?
   1.104 +        if (!m.HasNonTranslationOrFlip()) {
   1.105 +            x0 = floor(x0 + 0.5);
   1.106 +            y0 = floor(y0 + 0.5);
   1.107 +        }
   1.108 +
   1.109 +        CGContextConcatCTM(mCGContext, CGAffineTransformMake(m.xx, m.yx,
   1.110 +                                                             m.xy, m.yy,
   1.111 +                                                             x0, y0));
   1.112 +
   1.113 +        // bug 382049 - need to explicity set the composite operation to sourceOver
   1.114 +        CGContextSetCompositeOperation(mCGContext, kPrivateCGCompositeSourceOver);
   1.115 +    } else {
   1.116 +        nsIntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
   1.117 +                              NSToIntFloor(mNativeRect.height * mBackingScale));
   1.118 +        mQuartzSurface = new gfxQuartzSurface(backingSize,
   1.119 +                                              gfxImageFormat::ARGB32);
   1.120 +        if (mQuartzSurface->CairoStatus())
   1.121 +            return nullptr;
   1.122 +        mSurfaceContext = new gfxContext(mQuartzSurface);
   1.123 +
   1.124 +        // grab the CGContextRef
   1.125 +        mCGContext = cairo_quartz_get_cg_context_with_clip(mSurfaceContext->GetCairo());
   1.126 +        CGContextScaleCTM(mCGContext, mBackingScale, mBackingScale);
   1.127 +        CGContextTranslateCTM(mCGContext, -mNativeRect.X(), -mNativeRect.Y());
   1.128 +    }
   1.129 +
   1.130 +    return mCGContext;
   1.131 +}
   1.132 +
   1.133 +void
   1.134 +gfxQuartzNativeDrawing::EndNativeDrawing()
   1.135 +{
   1.136 +    NS_ASSERTION(mCGContext, "EndNativeDrawing called without BeginNativeDrawing");
   1.137 +
   1.138 +    if (mBorrowedContext.cg) {
   1.139 +        MOZ_ASSERT(!mContext->IsCairo());
   1.140 +        mBorrowedContext.Finish();
   1.141 +        if (mDrawTarget) {
   1.142 +          DrawTarget *dest = mContext->GetDrawTarget();
   1.143 +          RefPtr<SourceSurface> source = mDrawTarget->Snapshot();
   1.144 +
   1.145 +          IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
   1.146 +                              NSToIntFloor(mNativeRect.height * mBackingScale));
   1.147 +
   1.148 +          Matrix oldTransform = dest->GetTransform();
   1.149 +          Matrix newTransform = oldTransform;
   1.150 +          newTransform.Translate(mNativeRect.x, mNativeRect.y);
   1.151 +          newTransform.Scale(1.0f / mBackingScale, 1.0f / mBackingScale);
   1.152 +
   1.153 +          dest->SetTransform(newTransform);
   1.154 +
   1.155 +          dest->DrawSurface(source,
   1.156 +                            gfx::Rect(0, 0, backingSize.width, backingSize.height),
   1.157 +                            gfx::Rect(0, 0, backingSize.width, backingSize.height));
   1.158 +
   1.159 +
   1.160 +          dest->SetTransform(oldTransform);
   1.161 +        }
   1.162 +        return;
   1.163 +    }
   1.164 +
   1.165 +    cairo_quartz_finish_cg_context_with_clip(mSurfaceContext->GetCairo());
   1.166 +    mQuartzSurface->MarkDirty();
   1.167 +    if (mSurfaceContext != mContext) {
   1.168 +        gfxContextMatrixAutoSaveRestore save(mContext);
   1.169 +
   1.170 +        // Copy back to destination
   1.171 +        mContext->Translate(mNativeRect.TopLeft());
   1.172 +        mContext->Scale(1.0f / mBackingScale, 1.0f / mBackingScale);
   1.173 +        mContext->DrawSurface(mQuartzSurface, mQuartzSurface->GetSize());
   1.174 +    }
   1.175 +}

mercurial