gfx/layers/basic/BasicLayerManager.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/layers/basic/BasicLayerManager.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1046 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     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 <stdint.h>                     // for uint32_t
    1.10 +#include <stdlib.h>                     // for rand, RAND_MAX
    1.11 +#include <sys/types.h>                  // for int32_t
    1.12 +#include "BasicContainerLayer.h"        // for BasicContainerLayer
    1.13 +#include "BasicLayersImpl.h"            // for ToData, BasicReadbackLayer, etc
    1.14 +#include "GeckoProfiler.h"              // for PROFILER_LABEL
    1.15 +#include "ImageContainer.h"             // for ImageFactory
    1.16 +#include "Layers.h"                     // for Layer, ContainerLayer, etc
    1.17 +#include "ReadbackLayer.h"              // for ReadbackLayer
    1.18 +#include "ReadbackProcessor.h"          // for ReadbackProcessor
    1.19 +#include "RenderTrace.h"                // for RenderTraceLayers, etc
    1.20 +#include "basic/BasicImplData.h"        // for BasicImplData
    1.21 +#include "basic/BasicLayers.h"          // for BasicLayerManager, etc
    1.22 +#include "gfx3DMatrix.h"                // for gfx3DMatrix
    1.23 +#include "gfxASurface.h"                // for gfxASurface, etc
    1.24 +#include "gfxCachedTempSurface.h"       // for gfxCachedTempSurface
    1.25 +#include "gfxColor.h"                   // for gfxRGBA
    1.26 +#include "gfxContext.h"                 // for gfxContext, etc
    1.27 +#include "gfxImageSurface.h"            // for gfxImageSurface
    1.28 +#include "gfxMatrix.h"                  // for gfxMatrix
    1.29 +#include "gfxPlatform.h"                // for gfxPlatform
    1.30 +#include "gfxPrefs.h"                   // for gfxPrefs
    1.31 +#include "gfxPoint.h"                   // for gfxIntSize, gfxPoint
    1.32 +#include "gfxRect.h"                    // for gfxRect
    1.33 +#include "gfxUtils.h"                   // for gfxUtils
    1.34 +#include "gfx2DGlue.h"                  // for thebes --> moz2d transition
    1.35 +#include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
    1.36 +#include "mozilla/WidgetUtils.h"        // for ScreenRotation
    1.37 +#include "mozilla/gfx/2D.h"             // for DrawTarget
    1.38 +#include "mozilla/gfx/BasePoint.h"      // for BasePoint
    1.39 +#include "mozilla/gfx/BaseRect.h"       // for BaseRect
    1.40 +#include "mozilla/gfx/Matrix.h"         // for Matrix
    1.41 +#include "mozilla/gfx/Rect.h"           // for IntRect, Rect
    1.42 +#include "mozilla/layers/LayersTypes.h"  // for BufferMode::BUFFER_NONE, etc
    1.43 +#include "mozilla/mozalloc.h"           // for operator new
    1.44 +#include "nsAutoPtr.h"                  // for nsRefPtr
    1.45 +#include "nsCOMPtr.h"                   // for already_AddRefed
    1.46 +#include "nsDebug.h"                    // for NS_ASSERTION, etc
    1.47 +#include "nsISupportsImpl.h"            // for gfxContext::Release, etc
    1.48 +#include "nsPoint.h"                    // for nsIntPoint
    1.49 +#include "nsRect.h"                     // for nsIntRect
    1.50 +#include "nsRegion.h"                   // for nsIntRegion, etc
    1.51 +#include "nsTArray.h"                   // for nsAutoTArray
    1.52 +#define PIXMAN_DONT_DEFINE_STDINT
    1.53 +#include "pixman.h"                     // for pixman_f_transform, etc
    1.54 +
    1.55 +class nsIWidget;
    1.56 +
    1.57 +using namespace mozilla::dom;
    1.58 +using namespace mozilla::gfx;
    1.59 +
    1.60 +namespace mozilla {
    1.61 +namespace layers {
    1.62 +
    1.63 +/**
    1.64 + * Clips to the smallest device-pixel-aligned rectangle containing aRect
    1.65 + * in user space.
    1.66 + * Returns true if the clip is "perfect", i.e. we actually clipped exactly to
    1.67 + * aRect.
    1.68 + */
    1.69 +static bool
    1.70 +ClipToContain(gfxContext* aContext, const nsIntRect& aRect)
    1.71 +{
    1.72 +  gfxRect userRect(aRect.x, aRect.y, aRect.width, aRect.height);
    1.73 +  gfxRect deviceRect = aContext->UserToDevice(userRect);
    1.74 +  deviceRect.RoundOut();
    1.75 +
    1.76 +  gfxMatrix currentMatrix = aContext->CurrentMatrix();
    1.77 +  aContext->IdentityMatrix();
    1.78 +  aContext->NewPath();
    1.79 +  aContext->Rectangle(deviceRect);
    1.80 +  aContext->Clip();
    1.81 +  aContext->SetMatrix(currentMatrix);
    1.82 +
    1.83 +  return aContext->DeviceToUser(deviceRect).IsEqualInterior(userRect);
    1.84 +}
    1.85 +
    1.86 +already_AddRefed<gfxContext>
    1.87 +BasicLayerManager::PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
    1.88 +                                     const nsIntRegion& aRegion,
    1.89 +                                     bool* aNeedsClipToVisibleRegion)
    1.90 +{
    1.91 +  // If we need to call PushGroup, we should clip to the smallest possible
    1.92 +  // area first to minimize the size of the temporary surface.
    1.93 +  bool didCompleteClip = ClipToContain(aContext, aRegion.GetBounds());
    1.94 +
    1.95 +  nsRefPtr<gfxContext> result;
    1.96 +  if (aLayer->CanUseOpaqueSurface() &&
    1.97 +      ((didCompleteClip && aRegion.GetNumRects() == 1) ||
    1.98 +       !aContext->CurrentMatrix().HasNonIntegerTranslation())) {
    1.99 +    // If the layer is opaque in its visible region we can push a gfxContentType::COLOR
   1.100 +    // group. We need to make sure that only pixels inside the layer's visible
   1.101 +    // region are copied back to the destination. Remember if we've already
   1.102 +    // clipped precisely to the visible region.
   1.103 +    *aNeedsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1;
   1.104 +    MOZ_ASSERT(!aContext->IsCairo());
   1.105 +    result = PushGroupWithCachedSurface(aContext, gfxContentType::COLOR);
   1.106 +  } else {
   1.107 +    *aNeedsClipToVisibleRegion = false;
   1.108 +    result = aContext;
   1.109 +    if (aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) {
   1.110 +      aContext->PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA);
   1.111 +    } else {
   1.112 +      aContext->PushGroup(gfxContentType::COLOR_ALPHA);
   1.113 +    }
   1.114 +  }
   1.115 +  return result.forget();
   1.116 +}
   1.117 +
   1.118 +static nsIntRect
   1.119 +ToOutsideIntRect(const gfxRect &aRect)
   1.120 +{
   1.121 +  gfxRect r = aRect;
   1.122 +  r.RoundOut();
   1.123 +  return nsIntRect(r.X(), r.Y(), r.Width(), r.Height());
   1.124 +}
   1.125 +
   1.126 +static nsIntRect
   1.127 +ToInsideIntRect(const gfxRect& aRect)
   1.128 +{
   1.129 +  gfxRect r = aRect;
   1.130 +  r.RoundIn();
   1.131 +  return nsIntRect(r.X(), r.Y(), r.Width(), r.Height());
   1.132 +}
   1.133 +
   1.134 +// A context helper for BasicLayerManager::PaintLayer() that holds all the
   1.135 +// painting context together in a data structure so it can be easily passed
   1.136 +// around. It also uses ensures that the Transform and Opaque rect are restored
   1.137 +// to their former state on destruction.
   1.138 +
   1.139 +class PaintLayerContext {
   1.140 +public:
   1.141 +  PaintLayerContext(gfxContext* aTarget, Layer* aLayer,
   1.142 +                    LayerManager::DrawThebesLayerCallback aCallback,
   1.143 +                    void* aCallbackData, ReadbackProcessor* aReadback)
   1.144 +   : mTarget(aTarget)
   1.145 +   , mTargetMatrixSR(aTarget)
   1.146 +   , mLayer(aLayer)
   1.147 +   , mCallback(aCallback)
   1.148 +   , mCallbackData(aCallbackData)
   1.149 +   , mReadback(aReadback)
   1.150 +   , mPushedOpaqueRect(false)
   1.151 +  {}
   1.152 +
   1.153 +  ~PaintLayerContext()
   1.154 +  {
   1.155 +    // Matrix is restored by mTargetMatrixSR
   1.156 +    if (mPushedOpaqueRect)
   1.157 +    {
   1.158 +      ClearOpaqueRect();
   1.159 +    }
   1.160 +  }
   1.161 +
   1.162 +  // Gets the effective transform and returns true if it is a 2D
   1.163 +  // transform.
   1.164 +  bool Setup2DTransform()
   1.165 +  {
   1.166 +    // Will return an identity matrix for 3d transforms.
   1.167 +    return mLayer->GetEffectiveTransform().CanDraw2D(&mTransform);
   1.168 +  }
   1.169 +
   1.170 +  // Applies the effective transform if it's 2D. If it's a 3D transform then
   1.171 +  // it applies an identity.
   1.172 +  void Apply2DTransform()
   1.173 +  {
   1.174 +    mTarget->SetMatrix(ThebesMatrix(mTransform));
   1.175 +  }
   1.176 +
   1.177 +  // Set the opaque rect to match the bounds of the visible region.
   1.178 +  void AnnotateOpaqueRect()
   1.179 +  {
   1.180 +    const nsIntRegion& visibleRegion = mLayer->GetEffectiveVisibleRegion();
   1.181 +    const nsIntRect& bounds = visibleRegion.GetBounds();
   1.182 +
   1.183 +    if (mTarget->IsCairo()) {
   1.184 +      nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
   1.185 +      const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect();
   1.186 +
   1.187 +      // Try to annotate currentSurface with a region of pixels that have been
   1.188 +      // (or will be) painted opaque, if no such region is currently set.
   1.189 +      if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
   1.190 +          (mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
   1.191 +          !mTransform.HasNonAxisAlignedTransform()) {
   1.192 +        currentSurface->SetOpaqueRect(
   1.193 +            mTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
   1.194 +        mPushedOpaqueRect = true;
   1.195 +      }
   1.196 +    } else {
   1.197 +      DrawTarget *dt = mTarget->GetDrawTarget();
   1.198 +      const IntRect& targetOpaqueRect = dt->GetOpaqueRect();
   1.199 +
   1.200 +      // Try to annotate currentSurface with a region of pixels that have been
   1.201 +      // (or will be) painted opaque, if no such region is currently set.
   1.202 +      if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
   1.203 +          (mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
   1.204 +          !mTransform.HasNonAxisAlignedTransform()) {
   1.205 +
   1.206 +        gfx::Rect opaqueRect = dt->GetTransform().TransformBounds(
   1.207 +          gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
   1.208 +        opaqueRect.RoundIn();
   1.209 +        IntRect intOpaqueRect;
   1.210 +        if (opaqueRect.ToIntRect(&intOpaqueRect)) {
   1.211 +          mTarget->GetDrawTarget()->SetOpaqueRect(intOpaqueRect);
   1.212 +          mPushedOpaqueRect = true;
   1.213 +        }
   1.214 +      }
   1.215 +    }
   1.216 +  }
   1.217 +
   1.218 +  // Clear the Opaque rect. Although this doesn't really restore it to it's
   1.219 +  // previous state it will happen on the exit path of the PaintLayer() so when
   1.220 +  // painting is complete the opaque rect qill be clear.
   1.221 +  void ClearOpaqueRect() {
   1.222 +    if (mTarget->IsCairo()) {
   1.223 +      nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
   1.224 +      currentSurface->SetOpaqueRect(gfxRect());
   1.225 +    } else {
   1.226 +      mTarget->GetDrawTarget()->SetOpaqueRect(IntRect());
   1.227 +    }
   1.228 +  }
   1.229 +
   1.230 +  gfxContext* mTarget;
   1.231 +  gfxContextMatrixAutoSaveRestore mTargetMatrixSR;
   1.232 +  Layer* mLayer;
   1.233 +  LayerManager::DrawThebesLayerCallback mCallback;
   1.234 +  void* mCallbackData;
   1.235 +  ReadbackProcessor* mReadback;
   1.236 +  Matrix mTransform;
   1.237 +  bool mPushedOpaqueRect;
   1.238 +};
   1.239 +
   1.240 +BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) :
   1.241 +  mPhase(PHASE_NONE),
   1.242 +  mWidget(aWidget)
   1.243 +  , mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false)
   1.244 +  , mCachedSurfaceInUse(false)
   1.245 +  , mTransactionIncomplete(false)
   1.246 +  , mCompositorMightResample(false)
   1.247 +{
   1.248 +  MOZ_COUNT_CTOR(BasicLayerManager);
   1.249 +  NS_ASSERTION(aWidget, "Must provide a widget");
   1.250 +}
   1.251 +
   1.252 +BasicLayerManager::BasicLayerManager() :
   1.253 +  mPhase(PHASE_NONE),
   1.254 +  mWidget(nullptr)
   1.255 +  , mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false)
   1.256 +  , mCachedSurfaceInUse(false)
   1.257 +  , mTransactionIncomplete(false)
   1.258 +{
   1.259 +  MOZ_COUNT_CTOR(BasicLayerManager);
   1.260 +}
   1.261 +
   1.262 +BasicLayerManager::~BasicLayerManager()
   1.263 +{
   1.264 +  NS_ASSERTION(!InTransaction(), "Died during transaction?");
   1.265 +
   1.266 +  ClearCachedResources();
   1.267 +
   1.268 +  mRoot = nullptr;
   1.269 +
   1.270 +  MOZ_COUNT_DTOR(BasicLayerManager);
   1.271 +}
   1.272 +
   1.273 +void
   1.274 +BasicLayerManager::SetDefaultTarget(gfxContext* aContext)
   1.275 +{
   1.276 +  NS_ASSERTION(!InTransaction(),
   1.277 +               "Must set default target outside transaction");
   1.278 +  mDefaultTarget = aContext;
   1.279 +}
   1.280 +
   1.281 +void
   1.282 +BasicLayerManager::SetDefaultTargetConfiguration(BufferMode aDoubleBuffering, ScreenRotation aRotation)
   1.283 +{
   1.284 +  mDoubleBuffering = aDoubleBuffering;
   1.285 +}
   1.286 +
   1.287 +void
   1.288 +BasicLayerManager::BeginTransaction()
   1.289 +{
   1.290 +  mInTransaction = true;
   1.291 +  mUsingDefaultTarget = true;
   1.292 +  BeginTransactionWithTarget(mDefaultTarget);
   1.293 +}
   1.294 +
   1.295 +already_AddRefed<gfxContext>
   1.296 +BasicLayerManager::PushGroupWithCachedSurface(gfxContext *aTarget,
   1.297 +                                              gfxContentType aContent)
   1.298 +{
   1.299 +  nsRefPtr<gfxContext> ctx;
   1.300 +  // We can't cache Azure DrawTargets at this point.
   1.301 +  if (!mCachedSurfaceInUse && aTarget->IsCairo()) {
   1.302 +    gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
   1.303 +    aTarget->IdentityMatrix();
   1.304 +
   1.305 +    nsRefPtr<gfxASurface> currentSurf = aTarget->CurrentSurface();
   1.306 +    gfxRect clip = aTarget->GetClipExtents();
   1.307 +    clip.RoundOut();
   1.308 +
   1.309 +    ctx = mCachedSurface.Get(aContent, clip, currentSurf);
   1.310 +
   1.311 +    if (ctx) {
   1.312 +      mCachedSurfaceInUse = true;
   1.313 +      /* Align our buffer for the original surface */
   1.314 +      ctx->SetMatrix(saveMatrix.Matrix());
   1.315 +      return ctx.forget();
   1.316 +    }
   1.317 +  }
   1.318 +
   1.319 +  ctx = aTarget;
   1.320 +  ctx->PushGroup(aContent);
   1.321 +  return ctx.forget();
   1.322 +}
   1.323 +
   1.324 +void
   1.325 +BasicLayerManager::PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed)
   1.326 +{
   1.327 +  if (!aTarget)
   1.328 +    return;
   1.329 +  if (aTarget->IsCairo()) {
   1.330 +    nsRefPtr<gfxASurface> current = aPushed->CurrentSurface();
   1.331 +    if (mCachedSurface.IsSurface(current)) {
   1.332 +      gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
   1.333 +      aTarget->IdentityMatrix();
   1.334 +      aTarget->SetSource(current);
   1.335 +      mCachedSurfaceInUse = false;
   1.336 +      return;
   1.337 +    }
   1.338 +  }
   1.339 +  aTarget->PopGroupToSource();
   1.340 +}
   1.341 +
   1.342 +void
   1.343 +BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
   1.344 +{
   1.345 +  mInTransaction = true;
   1.346 +
   1.347 +#ifdef MOZ_LAYERS_HAVE_LOG
   1.348 +  MOZ_LAYERS_LOG(("[----- BeginTransaction"));
   1.349 +  Log();
   1.350 +#endif
   1.351 +
   1.352 +  NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
   1.353 +  mPhase = PHASE_CONSTRUCTION;
   1.354 +  mTarget = aTarget;
   1.355 +}
   1.356 +
   1.357 +static void
   1.358 +TransformIntRect(nsIntRect& aRect, const Matrix& aMatrix,
   1.359 +                 nsIntRect (*aRoundMethod)(const gfxRect&))
   1.360 +{
   1.361 +  Rect gr = Rect(aRect.x, aRect.y, aRect.width, aRect.height);
   1.362 +  gr = aMatrix.TransformBounds(gr);
   1.363 +  aRect = (*aRoundMethod)(ThebesRect(gr));
   1.364 +}
   1.365 +
   1.366 +/**
   1.367 + * This function assumes that GetEffectiveTransform transforms
   1.368 + * all layers to the same coordinate system (the "root coordinate system").
   1.369 + * It can't be used as is by accelerated layers because of intermediate surfaces.
   1.370 + * This must set the hidden flag to true or false on *all* layers in the subtree.
   1.371 + * It also sets the operator for all layers to "OVER", and call
   1.372 + * SetDrawAtomically(false).
   1.373 + * It clears mClipToVisibleRegion on all layers.
   1.374 + * @param aClipRect the cliprect, in the root coordinate system. We assume
   1.375 + * that any layer drawing is clipped to this rect. It is therefore not
   1.376 + * allowed to add to the opaque region outside that rect.
   1.377 + * @param aDirtyRect the dirty rect that will be painted, in the root
   1.378 + * coordinate system. Layers outside this rect should be hidden.
   1.379 + * @param aOpaqueRegion the opaque region covering aLayer, in the
   1.380 + * root coordinate system.
   1.381 + */
   1.382 +enum {
   1.383 +    ALLOW_OPAQUE = 0x01,
   1.384 +};
   1.385 +static void
   1.386 +MarkLayersHidden(Layer* aLayer, const nsIntRect& aClipRect,
   1.387 +                 const nsIntRect& aDirtyRect,
   1.388 +                 nsIntRegion& aOpaqueRegion,
   1.389 +                 uint32_t aFlags)
   1.390 +{
   1.391 +  nsIntRect newClipRect(aClipRect);
   1.392 +  uint32_t newFlags = aFlags;
   1.393 +
   1.394 +  // Allow aLayer or aLayer's descendants to cover underlying layers
   1.395 +  // only if it's opaque.
   1.396 +  if (aLayer->GetOpacity() != 1.0f) {
   1.397 +    newFlags &= ~ALLOW_OPAQUE;
   1.398 +  }
   1.399 +
   1.400 +  {
   1.401 +    const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
   1.402 +    if (clipRect) {
   1.403 +      nsIntRect cr = *clipRect;
   1.404 +      // clipRect is in the container's coordinate system. Get it into the
   1.405 +      // global coordinate system.
   1.406 +      if (aLayer->GetParent()) {
   1.407 +        Matrix tr;
   1.408 +        if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
   1.409 +          // Clip rect is applied after aLayer's transform, i.e., in the coordinate
   1.410 +          // system of aLayer's parent.
   1.411 +          TransformIntRect(cr, tr, ToInsideIntRect);
   1.412 +        } else {
   1.413 +          cr.SetRect(0, 0, 0, 0);
   1.414 +        }
   1.415 +      }
   1.416 +      newClipRect.IntersectRect(newClipRect, cr);
   1.417 +    }
   1.418 +  }
   1.419 +
   1.420 +  BasicImplData* data = ToData(aLayer);
   1.421 +  data->SetOperator(CompositionOp::OP_OVER);
   1.422 +  data->SetClipToVisibleRegion(false);
   1.423 +  data->SetDrawAtomically(false);
   1.424 +
   1.425 +  if (!aLayer->AsContainerLayer()) {
   1.426 +    Matrix transform;
   1.427 +    if (!aLayer->GetEffectiveTransform().CanDraw2D(&transform)) {
   1.428 +      data->SetHidden(false);
   1.429 +      return;
   1.430 +    }
   1.431 +
   1.432 +    nsIntRegion region = aLayer->GetEffectiveVisibleRegion();
   1.433 +    nsIntRect r = region.GetBounds();
   1.434 +    TransformIntRect(r, transform, ToOutsideIntRect);
   1.435 +    r.IntersectRect(r, aDirtyRect);
   1.436 +    data->SetHidden(aOpaqueRegion.Contains(r));
   1.437 +
   1.438 +    // Allow aLayer to cover underlying layers only if aLayer's
   1.439 +    // content is opaque
   1.440 +    if ((aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
   1.441 +        (newFlags & ALLOW_OPAQUE)) {
   1.442 +      nsIntRegionRectIterator it(region);
   1.443 +      while (const nsIntRect* sr = it.Next()) {
   1.444 +        r = *sr;
   1.445 +        TransformIntRect(r, transform, ToInsideIntRect);
   1.446 +
   1.447 +        r.IntersectRect(r, newClipRect);
   1.448 +        aOpaqueRegion.Or(aOpaqueRegion, r);
   1.449 +      }
   1.450 +    }
   1.451 +  } else {
   1.452 +    Layer* child = aLayer->GetLastChild();
   1.453 +    bool allHidden = true;
   1.454 +    for (; child; child = child->GetPrevSibling()) {
   1.455 +      MarkLayersHidden(child, newClipRect, aDirtyRect, aOpaqueRegion, newFlags);
   1.456 +      if (!ToData(child)->IsHidden()) {
   1.457 +        allHidden = false;
   1.458 +      }
   1.459 +    }
   1.460 +    data->SetHidden(allHidden);
   1.461 +  }
   1.462 +}
   1.463 +
   1.464 +/**
   1.465 + * This function assumes that GetEffectiveTransform transforms
   1.466 + * all layers to the same coordinate system (the "root coordinate system").
   1.467 + * MarkLayersHidden must be called before calling this.
   1.468 + * @param aVisibleRect the rectangle of aLayer that is visible (i.e. not
   1.469 + * clipped and in the dirty rect), in the root coordinate system.
   1.470 + */
   1.471 +static void
   1.472 +ApplyDoubleBuffering(Layer* aLayer, const nsIntRect& aVisibleRect)
   1.473 +{
   1.474 +  BasicImplData* data = ToData(aLayer);
   1.475 +  if (data->IsHidden())
   1.476 +    return;
   1.477 +
   1.478 +  nsIntRect newVisibleRect(aVisibleRect);
   1.479 +
   1.480 +  {
   1.481 +    const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
   1.482 +    if (clipRect) {
   1.483 +      nsIntRect cr = *clipRect;
   1.484 +      // clipRect is in the container's coordinate system. Get it into the
   1.485 +      // global coordinate system.
   1.486 +      if (aLayer->GetParent()) {
   1.487 +        Matrix tr;
   1.488 +        if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
   1.489 +          NS_ASSERTION(!ThebesMatrix(tr).HasNonIntegerTranslation(),
   1.490 +                       "Parent can only have an integer translation");
   1.491 +          cr += nsIntPoint(int32_t(tr._31), int32_t(tr._32));
   1.492 +        } else {
   1.493 +          NS_ERROR("Parent can only have an integer translation");
   1.494 +        }
   1.495 +      }
   1.496 +      newVisibleRect.IntersectRect(newVisibleRect, cr);
   1.497 +    }
   1.498 +  }
   1.499 +
   1.500 +  BasicContainerLayer* container =
   1.501 +    static_cast<BasicContainerLayer*>(aLayer->AsContainerLayer());
   1.502 +  // Layers that act as their own backbuffers should be drawn to the destination
   1.503 +  // using OPERATOR_SOURCE to ensure that alpha values in a transparent window
   1.504 +  // are cleared. This can also be faster than OPERATOR_OVER.
   1.505 +  if (!container) {
   1.506 +    data->SetOperator(CompositionOp::OP_SOURCE);
   1.507 +    data->SetDrawAtomically(true);
   1.508 +  } else {
   1.509 +    if (container->UseIntermediateSurface() ||
   1.510 +        !container->ChildrenPartitionVisibleRegion(newVisibleRect)) {
   1.511 +      // We need to double-buffer this container.
   1.512 +      data->SetOperator(CompositionOp::OP_SOURCE);
   1.513 +      container->ForceIntermediateSurface();
   1.514 +    } else {
   1.515 +      // Tell the children to clip to their visible regions so our assumption
   1.516 +      // that they don't paint outside their visible regions is valid!
   1.517 +      for (Layer* child = aLayer->GetFirstChild(); child;
   1.518 +           child = child->GetNextSibling()) {
   1.519 +        ToData(child)->SetClipToVisibleRegion(true);
   1.520 +        ApplyDoubleBuffering(child, newVisibleRect);
   1.521 +      }
   1.522 +    }
   1.523 +  }
   1.524 +}
   1.525 +
   1.526 +void
   1.527 +BasicLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
   1.528 +                                  void* aCallbackData,
   1.529 +                                  EndTransactionFlags aFlags)
   1.530 +{
   1.531 +  mInTransaction = false;
   1.532 +
   1.533 +  EndTransactionInternal(aCallback, aCallbackData, aFlags);
   1.534 +}
   1.535 +
   1.536 +void
   1.537 +BasicLayerManager::AbortTransaction()
   1.538 +{
   1.539 +  NS_ASSERTION(InConstruction(), "Should be in construction phase");
   1.540 +  mPhase = PHASE_NONE;
   1.541 +  mUsingDefaultTarget = false;
   1.542 +  mInTransaction = false;
   1.543 +}
   1.544 +
   1.545 +static uint16_t sFrameCount = 0;
   1.546 +void
   1.547 +BasicLayerManager::RenderDebugOverlay()
   1.548 +{
   1.549 +  if (!gfxPrefs::DrawFrameCounter()) {
   1.550 +    return;
   1.551 +  }
   1.552 +
   1.553 +  profiler_set_frame_number(sFrameCount);
   1.554 +
   1.555 +  uint16_t frameNumber = sFrameCount;
   1.556 +  const uint16_t bitWidth = 3;
   1.557 +  for (size_t i = 0; i < 16; i++) {
   1.558 +
   1.559 +    gfxRGBA bitColor;
   1.560 +    if ((frameNumber >> i) & 0x1) {
   1.561 +      bitColor = gfxRGBA(0, 0, 0, 1.0);
   1.562 +    } else {
   1.563 +      bitColor = gfxRGBA(1.0, 1.0, 1.0, 1.0);
   1.564 +    }
   1.565 +    mTarget->NewPath();
   1.566 +    mTarget->SetColor(bitColor);
   1.567 +    mTarget->Rectangle(gfxRect(bitWidth*i, 0, bitWidth, bitWidth));
   1.568 +    mTarget->Fill();
   1.569 +  }
   1.570 +  // We intentionally overflow at 2^16.
   1.571 +  sFrameCount++;
   1.572 +}
   1.573 +
   1.574 +bool
   1.575 +BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
   1.576 +                                          void* aCallbackData,
   1.577 +                                          EndTransactionFlags aFlags)
   1.578 +{
   1.579 +  PROFILER_LABEL("BasicLayerManager", "EndTransactionInternal");
   1.580 +#ifdef MOZ_LAYERS_HAVE_LOG
   1.581 +  MOZ_LAYERS_LOG(("  ----- (beginning paint)"));
   1.582 +  Log();
   1.583 +#endif
   1.584 +
   1.585 +  NS_ASSERTION(InConstruction(), "Should be in construction phase");
   1.586 +  mPhase = PHASE_DRAWING;
   1.587 +
   1.588 +  RenderTraceLayers(mRoot, "FF00");
   1.589 +
   1.590 +  mTransactionIncomplete = false;
   1.591 +
   1.592 +  if (mRoot) {
   1.593 +    // Need to do this before we call ApplyDoubleBuffering,
   1.594 +    // which depends on correct effective transforms
   1.595 +    mSnapEffectiveTransforms =
   1.596 +      mTarget ? !(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING) : true;
   1.597 +    mRoot->ComputeEffectiveTransforms(mTarget ? Matrix4x4::From2D(ToMatrix(mTarget->CurrentMatrix())) : Matrix4x4());
   1.598 +
   1.599 +    ToData(mRoot)->Validate(aCallback, aCallbackData);
   1.600 +    if (mRoot->GetMaskLayer()) {
   1.601 +      ToData(mRoot->GetMaskLayer())->Validate(aCallback, aCallbackData);
   1.602 +    }
   1.603 +
   1.604 +    if (aFlags & END_NO_COMPOSITE) {
   1.605 +      // Apply pending tree updates before recomputing effective
   1.606 +      // properties.
   1.607 +      mRoot->ApplyPendingUpdatesToSubtree();
   1.608 +    }
   1.609 +  }
   1.610 +
   1.611 +  if (mTarget && mRoot &&
   1.612 +      !(aFlags & END_NO_IMMEDIATE_REDRAW) &&
   1.613 +      !(aFlags & END_NO_COMPOSITE)) {
   1.614 +    nsIntRect clipRect;
   1.615 +
   1.616 +    {
   1.617 +      gfxContextMatrixAutoSaveRestore save(mTarget);
   1.618 +      mTarget->SetMatrix(gfxMatrix());
   1.619 +      clipRect = ToOutsideIntRect(mTarget->GetClipExtents());
   1.620 +    }
   1.621 +
   1.622 +    if (IsRetained()) {
   1.623 +      nsIntRegion region;
   1.624 +      MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE);
   1.625 +      if (mUsingDefaultTarget && mDoubleBuffering != BufferMode::BUFFER_NONE) {
   1.626 +        ApplyDoubleBuffering(mRoot, clipRect);
   1.627 +      }
   1.628 +    }
   1.629 +
   1.630 +    PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
   1.631 +    if (!mRegionToClear.IsEmpty()) {
   1.632 +      AutoSetOperator op(mTarget, gfxContext::OPERATOR_CLEAR);
   1.633 +      nsIntRegionRectIterator iter(mRegionToClear);
   1.634 +      const nsIntRect *r;
   1.635 +      while ((r = iter.Next())) {
   1.636 +        mTarget->NewPath();
   1.637 +        mTarget->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
   1.638 +        mTarget->Fill();
   1.639 +      }
   1.640 +    }
   1.641 +    if (mWidget) {
   1.642 +      FlashWidgetUpdateArea(mTarget);
   1.643 +    }
   1.644 +    RenderDebugOverlay();
   1.645 +    RecordFrame();
   1.646 +    PostPresent();
   1.647 +
   1.648 +    if (!mTransactionIncomplete) {
   1.649 +      // Clear out target if we have a complete transaction.
   1.650 +      mTarget = nullptr;
   1.651 +    }
   1.652 +  }
   1.653 +
   1.654 +#ifdef MOZ_LAYERS_HAVE_LOG
   1.655 +  Log();
   1.656 +  MOZ_LAYERS_LOG(("]----- EndTransaction"));
   1.657 +#endif
   1.658 +
   1.659 +  // Go back to the construction phase if the transaction isn't complete.
   1.660 +  // Layout will update the layer tree and call EndTransaction().
   1.661 +  mPhase = mTransactionIncomplete ? PHASE_CONSTRUCTION : PHASE_NONE;
   1.662 +
   1.663 +  if (!mTransactionIncomplete) {
   1.664 +    // This is still valid if the transaction was incomplete.
   1.665 +    mUsingDefaultTarget = false;
   1.666 +  }
   1.667 +
   1.668 +  NS_ASSERTION(!aCallback || !mTransactionIncomplete,
   1.669 +               "If callback is not null, transaction must be complete");
   1.670 +
   1.671 +  // XXX - We should probably assert here that for an incomplete transaction
   1.672 +  // out target is the default target.
   1.673 +
   1.674 +  return !mTransactionIncomplete;
   1.675 +}
   1.676 +
   1.677 +void
   1.678 +BasicLayerManager::FlashWidgetUpdateArea(gfxContext *aContext)
   1.679 +{
   1.680 +  if (gfxPrefs::WidgetUpdateFlashing()) {
   1.681 +    float r = float(rand()) / RAND_MAX;
   1.682 +    float g = float(rand()) / RAND_MAX;
   1.683 +    float b = float(rand()) / RAND_MAX;
   1.684 +    aContext->SetColor(gfxRGBA(r, g, b, 0.2));
   1.685 +    aContext->Paint();
   1.686 +  }
   1.687 +}
   1.688 +
   1.689 +bool
   1.690 +BasicLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
   1.691 +{
   1.692 +  mInTransaction = false;
   1.693 +
   1.694 +  if (!mRoot) {
   1.695 +    return false;
   1.696 +  }
   1.697 +
   1.698 +  return EndTransactionInternal(nullptr, nullptr, aFlags);
   1.699 +}
   1.700 +
   1.701 +void
   1.702 +BasicLayerManager::SetRoot(Layer* aLayer)
   1.703 +{
   1.704 +  NS_ASSERTION(aLayer, "Root can't be null");
   1.705 +  NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
   1.706 +  NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   1.707 +  mRoot = aLayer;
   1.708 +}
   1.709 +
   1.710 +static pixman_transform
   1.711 +BasicLayerManager_Matrix3DToPixman(const gfx3DMatrix& aMatrix)
   1.712 +{
   1.713 +  pixman_f_transform transform;
   1.714 +
   1.715 +  transform.m[0][0] = aMatrix._11;
   1.716 +  transform.m[0][1] = aMatrix._21;
   1.717 +  transform.m[0][2] = aMatrix._41;
   1.718 +  transform.m[1][0] = aMatrix._12;
   1.719 +  transform.m[1][1] = aMatrix._22;
   1.720 +  transform.m[1][2] = aMatrix._42;
   1.721 +  transform.m[2][0] = aMatrix._14;
   1.722 +  transform.m[2][1] = aMatrix._24;
   1.723 +  transform.m[2][2] = aMatrix._44;
   1.724 +
   1.725 +  pixman_transform result;
   1.726 +  pixman_transform_from_pixman_f_transform(&result, &transform);
   1.727 +
   1.728 +  return result;
   1.729 +}
   1.730 +
   1.731 +static void
   1.732 +PixmanTransform(const gfxImageSurface* aDest,
   1.733 +                RefPtr<DataSourceSurface> aSrc,
   1.734 +                const gfx3DMatrix& aTransform,
   1.735 +                gfxPoint aDestOffset)
   1.736 +{
   1.737 +  IntSize destSize = ToIntSize(aDest->GetSize());
   1.738 +  pixman_image_t* dest = pixman_image_create_bits(aDest->Format() == gfxImageFormat::ARGB32 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
   1.739 +                                                  destSize.width,
   1.740 +                                                  destSize.height,
   1.741 +                                                  (uint32_t*)aDest->Data(),
   1.742 +                                                  aDest->Stride());
   1.743 +
   1.744 +  IntSize srcSize = aSrc->GetSize();
   1.745 +  pixman_image_t* src = pixman_image_create_bits(aSrc->GetFormat() == SurfaceFormat::B8G8R8A8 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
   1.746 +                                                 srcSize.width,
   1.747 +                                                 srcSize.height,
   1.748 +                                                 (uint32_t*)aSrc->GetData(),
   1.749 +                                                 aSrc->Stride());
   1.750 +
   1.751 +  NS_ABORT_IF_FALSE(src && dest, "Failed to create pixman images?");
   1.752 +
   1.753 +  pixman_transform pixTransform = BasicLayerManager_Matrix3DToPixman(aTransform);
   1.754 +  pixman_transform pixTransformInverted;
   1.755 +
   1.756 +  // If the transform is singular then nothing would be drawn anyway, return here
   1.757 +  if (!pixman_transform_invert(&pixTransformInverted, &pixTransform)) {
   1.758 +    return;
   1.759 +  }
   1.760 +  pixman_image_set_transform(src, &pixTransformInverted);
   1.761 +
   1.762 +  pixman_image_composite32(PIXMAN_OP_SRC,
   1.763 +                           src,
   1.764 +                           nullptr,
   1.765 +                           dest,
   1.766 +                           aDestOffset.x,
   1.767 +                           aDestOffset.y,
   1.768 +                           0,
   1.769 +                           0,
   1.770 +                           0,
   1.771 +                           0,
   1.772 +                           destSize.width,
   1.773 +                           destSize.height);
   1.774 +
   1.775 +  pixman_image_unref(dest);
   1.776 +  pixman_image_unref(src);
   1.777 +}
   1.778 +
   1.779 +/**
   1.780 + * Transform a surface using a gfx3DMatrix and blit to the destination if
   1.781 + * it is efficient to do so.
   1.782 + *
   1.783 + * @param aSource       Source surface.
   1.784 + * @param aDest         Desintation context.
   1.785 + * @param aBounds       Area represented by aSource.
   1.786 + * @param aTransform    Transformation matrix.
   1.787 + * @param aDestRect     Output: rectangle in which to draw returned surface on aDest
   1.788 + *                      (same size as aDest). Only filled in if this returns
   1.789 + *                      a surface.
   1.790 + * @return              Transformed surface
   1.791 + */
   1.792 +static already_AddRefed<gfxASurface>
   1.793 +Transform3D(RefPtr<SourceSurface> aSource,
   1.794 +            gfxContext* aDest,
   1.795 +            const gfxRect& aBounds,
   1.796 +            const gfx3DMatrix& aTransform,
   1.797 +            gfxRect& aDestRect)
   1.798 +{
   1.799 +  // Find the transformed rectangle of our layer.
   1.800 +  gfxRect offsetRect = aTransform.TransformBounds(aBounds);
   1.801 +
   1.802 +  // Intersect the transformed layer with the destination rectangle.
   1.803 +  // This is in device space since we have an identity transform set on aTarget.
   1.804 +  aDestRect = aDest->GetClipExtents();
   1.805 +  aDestRect.IntersectRect(aDestRect, offsetRect);
   1.806 +  aDestRect.RoundOut();
   1.807 +
   1.808 +  // Create a surface the size of the transformed object.
   1.809 +  nsRefPtr<gfxASurface> dest = aDest->CurrentSurface();
   1.810 +  nsRefPtr<gfxImageSurface> destImage = new gfxImageSurface(gfxIntSize(aDestRect.width,
   1.811 +                                                                       aDestRect.height),
   1.812 +                                                            gfxImageFormat::ARGB32);
   1.813 +  gfxPoint offset = aDestRect.TopLeft();
   1.814 +
   1.815 +  // Include a translation to the correct origin.
   1.816 +  gfx3DMatrix translation = gfx3DMatrix::Translation(aBounds.x, aBounds.y, 0);
   1.817 +
   1.818 +  // Transform the content and offset it such that the content begins at the origin.
   1.819 +  PixmanTransform(destImage, aSource->GetDataSurface(), translation * aTransform, offset);
   1.820 +
   1.821 +  // If we haven't actually drawn to aDest then return our temporary image so
   1.822 +  // that the caller can do this.
   1.823 +  return destImage.forget();
   1.824 +}
   1.825 +
   1.826 +void
   1.827 +BasicLayerManager::PaintSelfOrChildren(PaintLayerContext& aPaintContext,
   1.828 +                                       gfxContext* aGroupTarget)
   1.829 +{
   1.830 +  BasicImplData* data = ToData(aPaintContext.mLayer);
   1.831 +
   1.832 +  /* Only paint ourself, or our children - This optimization relies on this! */
   1.833 +  Layer* child = aPaintContext.mLayer->GetFirstChild();
   1.834 +  if (!child) {
   1.835 +    if (aPaintContext.mLayer->AsThebesLayer()) {
   1.836 +      data->PaintThebes(aGroupTarget, aPaintContext.mLayer->GetMaskLayer(),
   1.837 +          aPaintContext.mCallback, aPaintContext.mCallbackData,
   1.838 +          aPaintContext.mReadback);
   1.839 +    } else {
   1.840 +      data->Paint(aGroupTarget->GetDrawTarget(),
   1.841 +                  aGroupTarget->GetDeviceOffset(),
   1.842 +                  aPaintContext.mLayer->GetMaskLayer());
   1.843 +    }
   1.844 +  } else {
   1.845 +    ReadbackProcessor readback;
   1.846 +    ContainerLayer* container =
   1.847 +        static_cast<ContainerLayer*>(aPaintContext.mLayer);
   1.848 +    if (IsRetained()) {
   1.849 +      readback.BuildUpdates(container);
   1.850 +    }
   1.851 +    nsAutoTArray<Layer*, 12> children;
   1.852 +    container->SortChildrenBy3DZOrder(children);
   1.853 +    for (uint32_t i = 0; i < children.Length(); i++) {
   1.854 +      PaintLayer(aGroupTarget, children.ElementAt(i), aPaintContext.mCallback,
   1.855 +          aPaintContext.mCallbackData, &readback);
   1.856 +      if (mTransactionIncomplete)
   1.857 +        break;
   1.858 +    }
   1.859 +  }
   1.860 +}
   1.861 +
   1.862 +void
   1.863 +BasicLayerManager::FlushGroup(PaintLayerContext& aPaintContext, bool aNeedsClipToVisibleRegion)
   1.864 +{
   1.865 +  // If we're doing our own double-buffering, we need to avoid drawing
   1.866 +  // the results of an incomplete transaction to the destination surface ---
   1.867 +  // that could cause flicker. Double-buffering is implemented using a
   1.868 +  // temporary surface for one or more container layers, so we need to stop
   1.869 +  // those temporary surfaces from being composited to aTarget.
   1.870 +  // ApplyDoubleBuffering guarantees that this container layer can't
   1.871 +  // intersect any other leaf layers, so if the transaction is not yet marked
   1.872 +  // incomplete, the contents of this container layer are the final contents
   1.873 +  // for the window.
   1.874 +  if (!mTransactionIncomplete) {
   1.875 +    if (aNeedsClipToVisibleRegion) {
   1.876 +      gfxUtils::ClipToRegion(aPaintContext.mTarget,
   1.877 +                             aPaintContext.mLayer->GetEffectiveVisibleRegion());
   1.878 +    }
   1.879 +
   1.880 +    CompositionOp op = GetEffectiveOperator(aPaintContext.mLayer);
   1.881 +    AutoSetOperator setOperator(aPaintContext.mTarget, ThebesOp(op));
   1.882 +
   1.883 +    PaintWithMask(aPaintContext.mTarget, aPaintContext.mLayer->GetEffectiveOpacity(),
   1.884 +                  aPaintContext.mLayer->GetMaskLayer());
   1.885 +  }
   1.886 +}
   1.887 +
   1.888 +void
   1.889 +BasicLayerManager::PaintLayer(gfxContext* aTarget,
   1.890 +                              Layer* aLayer,
   1.891 +                              DrawThebesLayerCallback aCallback,
   1.892 +                              void* aCallbackData,
   1.893 +                              ReadbackProcessor* aReadback)
   1.894 +{
   1.895 +  PROFILER_LABEL("BasicLayerManager", "PaintLayer");
   1.896 +  PaintLayerContext paintLayerContext(aTarget, aLayer, aCallback, aCallbackData, aReadback);
   1.897 +
   1.898 +  // Don't attempt to paint layers with a singular transform, cairo will
   1.899 +  // just throw an error.
   1.900 +  if (aLayer->GetEffectiveTransform().IsSingular()) {
   1.901 +    return;
   1.902 +  }
   1.903 +
   1.904 +  RenderTraceScope trace("BasicLayerManager::PaintLayer", "707070");
   1.905 +
   1.906 +  const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
   1.907 +  BasicContainerLayer* container =
   1.908 +    static_cast<BasicContainerLayer*>(aLayer->AsContainerLayer());
   1.909 +  bool needsGroup = container &&
   1.910 +                    container->UseIntermediateSurface();
   1.911 +  BasicImplData* data = ToData(aLayer);
   1.912 +  bool needsClipToVisibleRegion =
   1.913 +    data->GetClipToVisibleRegion() && !aLayer->AsThebesLayer();
   1.914 +  NS_ASSERTION(needsGroup || !container ||
   1.915 +               container->GetOperator() == CompositionOp::OP_OVER,
   1.916 +               "non-OVER operator should have forced UseIntermediateSurface");
   1.917 +  NS_ASSERTION(!container || !aLayer->GetMaskLayer() ||
   1.918 +               container->UseIntermediateSurface(),
   1.919 +               "ContainerLayer with mask layer should force UseIntermediateSurface");
   1.920 +
   1.921 +  gfxContextAutoSaveRestore contextSR;
   1.922 +  gfxMatrix transform;
   1.923 +  // Will return an identity matrix for 3d transforms, and is handled separately below.
   1.924 +  bool is2D = paintLayerContext.Setup2DTransform();
   1.925 +  NS_ABORT_IF_FALSE(is2D || needsGroup || !aLayer->GetFirstChild(), "Must PushGroup for 3d transforms!");
   1.926 +
   1.927 +  bool needsSaveRestore =
   1.928 +    needsGroup || clipRect || needsClipToVisibleRegion || !is2D;
   1.929 +  if (needsSaveRestore) {
   1.930 +    contextSR.SetContext(aTarget);
   1.931 +
   1.932 +    if (clipRect) {
   1.933 +      aTarget->NewPath();
   1.934 +      aTarget->SnappedRectangle(gfxRect(clipRect->x, clipRect->y, clipRect->width, clipRect->height));
   1.935 +      aTarget->Clip();
   1.936 +    }
   1.937 +  }
   1.938 +
   1.939 +  paintLayerContext.Apply2DTransform();
   1.940 +
   1.941 +  const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
   1.942 +  // If needsGroup is true, we'll clip to the visible region after we've popped the group
   1.943 +  if (needsClipToVisibleRegion && !needsGroup) {
   1.944 +    gfxUtils::ClipToRegion(aTarget, visibleRegion);
   1.945 +    // Don't need to clip to visible region again
   1.946 +    needsClipToVisibleRegion = false;
   1.947 +  }
   1.948 +  
   1.949 +  if (is2D) {
   1.950 +    paintLayerContext.AnnotateOpaqueRect();
   1.951 +  }
   1.952 +
   1.953 +  bool clipIsEmpty = !aTarget || aTarget->GetClipExtents().IsEmpty();
   1.954 +  if (clipIsEmpty) {
   1.955 +    PaintSelfOrChildren(paintLayerContext, aTarget);
   1.956 +    return;
   1.957 +  }
   1.958 +
   1.959 +  if (is2D) {
   1.960 +    if (needsGroup) {
   1.961 +      nsRefPtr<gfxContext> groupTarget = PushGroupForLayer(aTarget, aLayer, aLayer->GetEffectiveVisibleRegion(),
   1.962 +                                      &needsClipToVisibleRegion);
   1.963 +      PaintSelfOrChildren(paintLayerContext, groupTarget);
   1.964 +      PopGroupToSourceWithCachedSurface(aTarget, groupTarget);
   1.965 +      FlushGroup(paintLayerContext, needsClipToVisibleRegion);
   1.966 +    } else {
   1.967 +      PaintSelfOrChildren(paintLayerContext, aTarget);
   1.968 +    }
   1.969 +  } else {
   1.970 +    const nsIntRect& bounds = visibleRegion.GetBounds();
   1.971 +    RefPtr<DrawTarget> untransformedDT =
   1.972 +      gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(bounds.width, bounds.height),
   1.973 +                                                                   SurfaceFormat::B8G8R8A8);
   1.974 +    if (!untransformedDT) {
   1.975 +      return;
   1.976 +    }
   1.977 +
   1.978 +    nsRefPtr<gfxContext> groupTarget = new gfxContext(untransformedDT,
   1.979 +                                                      Point(bounds.x, bounds.y));
   1.980 +
   1.981 +    PaintSelfOrChildren(paintLayerContext, groupTarget);
   1.982 +
   1.983 +    // Temporary fast fix for bug 725886
   1.984 +    // Revert these changes when 725886 is ready
   1.985 +    NS_ABORT_IF_FALSE(untransformedDT,
   1.986 +                      "We should always allocate an untransformed surface with 3d transforms!");
   1.987 +    gfxRect destRect;
   1.988 +#ifdef DEBUG
   1.989 +    if (aLayer->GetDebugColorIndex() != 0) {
   1.990 +      gfxRGBA  color((aLayer->GetDebugColorIndex() & 1) ? 1.0 : 0.0,
   1.991 +                     (aLayer->GetDebugColorIndex() & 2) ? 1.0 : 0.0,
   1.992 +                     (aLayer->GetDebugColorIndex() & 4) ? 1.0 : 0.0,
   1.993 +                     1.0);
   1.994 +
   1.995 +      nsRefPtr<gfxContext> temp = new gfxContext(untransformedDT, Point(bounds.x, bounds.y));
   1.996 +      temp->SetColor(color);
   1.997 +      temp->Paint();
   1.998 +    }
   1.999 +#endif
  1.1000 +    gfx3DMatrix effectiveTransform;
  1.1001 +    gfx::To3DMatrix(aLayer->GetEffectiveTransform(), effectiveTransform);
  1.1002 +    nsRefPtr<gfxASurface> result =
  1.1003 +      Transform3D(untransformedDT->Snapshot(), aTarget, bounds,
  1.1004 +                  effectiveTransform, destRect);
  1.1005 +
  1.1006 +    if (result) {
  1.1007 +      aTarget->SetSource(result, destRect.TopLeft());
  1.1008 +      // Azure doesn't support EXTEND_NONE, so to avoid extending the edges
  1.1009 +      // of the source surface out to the current clip region, clip to
  1.1010 +      // the rectangle of the result surface now.
  1.1011 +      aTarget->NewPath();
  1.1012 +      aTarget->SnappedRectangle(destRect);
  1.1013 +      aTarget->Clip();
  1.1014 +      FlushGroup(paintLayerContext, needsClipToVisibleRegion);
  1.1015 +    }
  1.1016 +  }
  1.1017 +}
  1.1018 +
  1.1019 +void
  1.1020 +BasicLayerManager::ClearCachedResources(Layer* aSubtree)
  1.1021 +{
  1.1022 +  MOZ_ASSERT(!aSubtree || aSubtree->Manager() == this);
  1.1023 +  if (aSubtree) {
  1.1024 +    ClearLayer(aSubtree);
  1.1025 +  } else if (mRoot) {
  1.1026 +    ClearLayer(mRoot);
  1.1027 +  }
  1.1028 +  mCachedSurface.Expire();
  1.1029 +}
  1.1030 +void
  1.1031 +BasicLayerManager::ClearLayer(Layer* aLayer)
  1.1032 +{
  1.1033 +  ToData(aLayer)->ClearCachedResources();
  1.1034 +  for (Layer* child = aLayer->GetFirstChild(); child;
  1.1035 +       child = child->GetNextSibling()) {
  1.1036 +    ClearLayer(child);
  1.1037 +  }
  1.1038 +}
  1.1039 +
  1.1040 +already_AddRefed<ReadbackLayer>
  1.1041 +BasicLayerManager::CreateReadbackLayer()
  1.1042 +{
  1.1043 +  NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
  1.1044 +  nsRefPtr<ReadbackLayer> layer = new BasicReadbackLayer(this);
  1.1045 +  return layer.forget();
  1.1046 +}
  1.1047 +
  1.1048 +}
  1.1049 +}

mercurial