gfx/thebes/gfxQuartzNativeDrawing.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial