gfx/layers/basic/BasicLayerManager.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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 <stdint.h> // for uint32_t
michael@0 7 #include <stdlib.h> // for rand, RAND_MAX
michael@0 8 #include <sys/types.h> // for int32_t
michael@0 9 #include "BasicContainerLayer.h" // for BasicContainerLayer
michael@0 10 #include "BasicLayersImpl.h" // for ToData, BasicReadbackLayer, etc
michael@0 11 #include "GeckoProfiler.h" // for PROFILER_LABEL
michael@0 12 #include "ImageContainer.h" // for ImageFactory
michael@0 13 #include "Layers.h" // for Layer, ContainerLayer, etc
michael@0 14 #include "ReadbackLayer.h" // for ReadbackLayer
michael@0 15 #include "ReadbackProcessor.h" // for ReadbackProcessor
michael@0 16 #include "RenderTrace.h" // for RenderTraceLayers, etc
michael@0 17 #include "basic/BasicImplData.h" // for BasicImplData
michael@0 18 #include "basic/BasicLayers.h" // for BasicLayerManager, etc
michael@0 19 #include "gfx3DMatrix.h" // for gfx3DMatrix
michael@0 20 #include "gfxASurface.h" // for gfxASurface, etc
michael@0 21 #include "gfxCachedTempSurface.h" // for gfxCachedTempSurface
michael@0 22 #include "gfxColor.h" // for gfxRGBA
michael@0 23 #include "gfxContext.h" // for gfxContext, etc
michael@0 24 #include "gfxImageSurface.h" // for gfxImageSurface
michael@0 25 #include "gfxMatrix.h" // for gfxMatrix
michael@0 26 #include "gfxPlatform.h" // for gfxPlatform
michael@0 27 #include "gfxPrefs.h" // for gfxPrefs
michael@0 28 #include "gfxPoint.h" // for gfxIntSize, gfxPoint
michael@0 29 #include "gfxRect.h" // for gfxRect
michael@0 30 #include "gfxUtils.h" // for gfxUtils
michael@0 31 #include "gfx2DGlue.h" // for thebes --> moz2d transition
michael@0 32 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
michael@0 33 #include "mozilla/WidgetUtils.h" // for ScreenRotation
michael@0 34 #include "mozilla/gfx/2D.h" // for DrawTarget
michael@0 35 #include "mozilla/gfx/BasePoint.h" // for BasePoint
michael@0 36 #include "mozilla/gfx/BaseRect.h" // for BaseRect
michael@0 37 #include "mozilla/gfx/Matrix.h" // for Matrix
michael@0 38 #include "mozilla/gfx/Rect.h" // for IntRect, Rect
michael@0 39 #include "mozilla/layers/LayersTypes.h" // for BufferMode::BUFFER_NONE, etc
michael@0 40 #include "mozilla/mozalloc.h" // for operator new
michael@0 41 #include "nsAutoPtr.h" // for nsRefPtr
michael@0 42 #include "nsCOMPtr.h" // for already_AddRefed
michael@0 43 #include "nsDebug.h" // for NS_ASSERTION, etc
michael@0 44 #include "nsISupportsImpl.h" // for gfxContext::Release, etc
michael@0 45 #include "nsPoint.h" // for nsIntPoint
michael@0 46 #include "nsRect.h" // for nsIntRect
michael@0 47 #include "nsRegion.h" // for nsIntRegion, etc
michael@0 48 #include "nsTArray.h" // for nsAutoTArray
michael@0 49 #define PIXMAN_DONT_DEFINE_STDINT
michael@0 50 #include "pixman.h" // for pixman_f_transform, etc
michael@0 51
michael@0 52 class nsIWidget;
michael@0 53
michael@0 54 using namespace mozilla::dom;
michael@0 55 using namespace mozilla::gfx;
michael@0 56
michael@0 57 namespace mozilla {
michael@0 58 namespace layers {
michael@0 59
michael@0 60 /**
michael@0 61 * Clips to the smallest device-pixel-aligned rectangle containing aRect
michael@0 62 * in user space.
michael@0 63 * Returns true if the clip is "perfect", i.e. we actually clipped exactly to
michael@0 64 * aRect.
michael@0 65 */
michael@0 66 static bool
michael@0 67 ClipToContain(gfxContext* aContext, const nsIntRect& aRect)
michael@0 68 {
michael@0 69 gfxRect userRect(aRect.x, aRect.y, aRect.width, aRect.height);
michael@0 70 gfxRect deviceRect = aContext->UserToDevice(userRect);
michael@0 71 deviceRect.RoundOut();
michael@0 72
michael@0 73 gfxMatrix currentMatrix = aContext->CurrentMatrix();
michael@0 74 aContext->IdentityMatrix();
michael@0 75 aContext->NewPath();
michael@0 76 aContext->Rectangle(deviceRect);
michael@0 77 aContext->Clip();
michael@0 78 aContext->SetMatrix(currentMatrix);
michael@0 79
michael@0 80 return aContext->DeviceToUser(deviceRect).IsEqualInterior(userRect);
michael@0 81 }
michael@0 82
michael@0 83 already_AddRefed<gfxContext>
michael@0 84 BasicLayerManager::PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
michael@0 85 const nsIntRegion& aRegion,
michael@0 86 bool* aNeedsClipToVisibleRegion)
michael@0 87 {
michael@0 88 // If we need to call PushGroup, we should clip to the smallest possible
michael@0 89 // area first to minimize the size of the temporary surface.
michael@0 90 bool didCompleteClip = ClipToContain(aContext, aRegion.GetBounds());
michael@0 91
michael@0 92 nsRefPtr<gfxContext> result;
michael@0 93 if (aLayer->CanUseOpaqueSurface() &&
michael@0 94 ((didCompleteClip && aRegion.GetNumRects() == 1) ||
michael@0 95 !aContext->CurrentMatrix().HasNonIntegerTranslation())) {
michael@0 96 // If the layer is opaque in its visible region we can push a gfxContentType::COLOR
michael@0 97 // group. We need to make sure that only pixels inside the layer's visible
michael@0 98 // region are copied back to the destination. Remember if we've already
michael@0 99 // clipped precisely to the visible region.
michael@0 100 *aNeedsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1;
michael@0 101 MOZ_ASSERT(!aContext->IsCairo());
michael@0 102 result = PushGroupWithCachedSurface(aContext, gfxContentType::COLOR);
michael@0 103 } else {
michael@0 104 *aNeedsClipToVisibleRegion = false;
michael@0 105 result = aContext;
michael@0 106 if (aLayer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA) {
michael@0 107 aContext->PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA);
michael@0 108 } else {
michael@0 109 aContext->PushGroup(gfxContentType::COLOR_ALPHA);
michael@0 110 }
michael@0 111 }
michael@0 112 return result.forget();
michael@0 113 }
michael@0 114
michael@0 115 static nsIntRect
michael@0 116 ToOutsideIntRect(const gfxRect &aRect)
michael@0 117 {
michael@0 118 gfxRect r = aRect;
michael@0 119 r.RoundOut();
michael@0 120 return nsIntRect(r.X(), r.Y(), r.Width(), r.Height());
michael@0 121 }
michael@0 122
michael@0 123 static nsIntRect
michael@0 124 ToInsideIntRect(const gfxRect& aRect)
michael@0 125 {
michael@0 126 gfxRect r = aRect;
michael@0 127 r.RoundIn();
michael@0 128 return nsIntRect(r.X(), r.Y(), r.Width(), r.Height());
michael@0 129 }
michael@0 130
michael@0 131 // A context helper for BasicLayerManager::PaintLayer() that holds all the
michael@0 132 // painting context together in a data structure so it can be easily passed
michael@0 133 // around. It also uses ensures that the Transform and Opaque rect are restored
michael@0 134 // to their former state on destruction.
michael@0 135
michael@0 136 class PaintLayerContext {
michael@0 137 public:
michael@0 138 PaintLayerContext(gfxContext* aTarget, Layer* aLayer,
michael@0 139 LayerManager::DrawThebesLayerCallback aCallback,
michael@0 140 void* aCallbackData, ReadbackProcessor* aReadback)
michael@0 141 : mTarget(aTarget)
michael@0 142 , mTargetMatrixSR(aTarget)
michael@0 143 , mLayer(aLayer)
michael@0 144 , mCallback(aCallback)
michael@0 145 , mCallbackData(aCallbackData)
michael@0 146 , mReadback(aReadback)
michael@0 147 , mPushedOpaqueRect(false)
michael@0 148 {}
michael@0 149
michael@0 150 ~PaintLayerContext()
michael@0 151 {
michael@0 152 // Matrix is restored by mTargetMatrixSR
michael@0 153 if (mPushedOpaqueRect)
michael@0 154 {
michael@0 155 ClearOpaqueRect();
michael@0 156 }
michael@0 157 }
michael@0 158
michael@0 159 // Gets the effective transform and returns true if it is a 2D
michael@0 160 // transform.
michael@0 161 bool Setup2DTransform()
michael@0 162 {
michael@0 163 // Will return an identity matrix for 3d transforms.
michael@0 164 return mLayer->GetEffectiveTransform().CanDraw2D(&mTransform);
michael@0 165 }
michael@0 166
michael@0 167 // Applies the effective transform if it's 2D. If it's a 3D transform then
michael@0 168 // it applies an identity.
michael@0 169 void Apply2DTransform()
michael@0 170 {
michael@0 171 mTarget->SetMatrix(ThebesMatrix(mTransform));
michael@0 172 }
michael@0 173
michael@0 174 // Set the opaque rect to match the bounds of the visible region.
michael@0 175 void AnnotateOpaqueRect()
michael@0 176 {
michael@0 177 const nsIntRegion& visibleRegion = mLayer->GetEffectiveVisibleRegion();
michael@0 178 const nsIntRect& bounds = visibleRegion.GetBounds();
michael@0 179
michael@0 180 if (mTarget->IsCairo()) {
michael@0 181 nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
michael@0 182 const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect();
michael@0 183
michael@0 184 // Try to annotate currentSurface with a region of pixels that have been
michael@0 185 // (or will be) painted opaque, if no such region is currently set.
michael@0 186 if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
michael@0 187 (mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
michael@0 188 !mTransform.HasNonAxisAlignedTransform()) {
michael@0 189 currentSurface->SetOpaqueRect(
michael@0 190 mTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
michael@0 191 mPushedOpaqueRect = true;
michael@0 192 }
michael@0 193 } else {
michael@0 194 DrawTarget *dt = mTarget->GetDrawTarget();
michael@0 195 const IntRect& targetOpaqueRect = dt->GetOpaqueRect();
michael@0 196
michael@0 197 // Try to annotate currentSurface with a region of pixels that have been
michael@0 198 // (or will be) painted opaque, if no such region is currently set.
michael@0 199 if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
michael@0 200 (mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
michael@0 201 !mTransform.HasNonAxisAlignedTransform()) {
michael@0 202
michael@0 203 gfx::Rect opaqueRect = dt->GetTransform().TransformBounds(
michael@0 204 gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
michael@0 205 opaqueRect.RoundIn();
michael@0 206 IntRect intOpaqueRect;
michael@0 207 if (opaqueRect.ToIntRect(&intOpaqueRect)) {
michael@0 208 mTarget->GetDrawTarget()->SetOpaqueRect(intOpaqueRect);
michael@0 209 mPushedOpaqueRect = true;
michael@0 210 }
michael@0 211 }
michael@0 212 }
michael@0 213 }
michael@0 214
michael@0 215 // Clear the Opaque rect. Although this doesn't really restore it to it's
michael@0 216 // previous state it will happen on the exit path of the PaintLayer() so when
michael@0 217 // painting is complete the opaque rect qill be clear.
michael@0 218 void ClearOpaqueRect() {
michael@0 219 if (mTarget->IsCairo()) {
michael@0 220 nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
michael@0 221 currentSurface->SetOpaqueRect(gfxRect());
michael@0 222 } else {
michael@0 223 mTarget->GetDrawTarget()->SetOpaqueRect(IntRect());
michael@0 224 }
michael@0 225 }
michael@0 226
michael@0 227 gfxContext* mTarget;
michael@0 228 gfxContextMatrixAutoSaveRestore mTargetMatrixSR;
michael@0 229 Layer* mLayer;
michael@0 230 LayerManager::DrawThebesLayerCallback mCallback;
michael@0 231 void* mCallbackData;
michael@0 232 ReadbackProcessor* mReadback;
michael@0 233 Matrix mTransform;
michael@0 234 bool mPushedOpaqueRect;
michael@0 235 };
michael@0 236
michael@0 237 BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) :
michael@0 238 mPhase(PHASE_NONE),
michael@0 239 mWidget(aWidget)
michael@0 240 , mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false)
michael@0 241 , mCachedSurfaceInUse(false)
michael@0 242 , mTransactionIncomplete(false)
michael@0 243 , mCompositorMightResample(false)
michael@0 244 {
michael@0 245 MOZ_COUNT_CTOR(BasicLayerManager);
michael@0 246 NS_ASSERTION(aWidget, "Must provide a widget");
michael@0 247 }
michael@0 248
michael@0 249 BasicLayerManager::BasicLayerManager() :
michael@0 250 mPhase(PHASE_NONE),
michael@0 251 mWidget(nullptr)
michael@0 252 , mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false)
michael@0 253 , mCachedSurfaceInUse(false)
michael@0 254 , mTransactionIncomplete(false)
michael@0 255 {
michael@0 256 MOZ_COUNT_CTOR(BasicLayerManager);
michael@0 257 }
michael@0 258
michael@0 259 BasicLayerManager::~BasicLayerManager()
michael@0 260 {
michael@0 261 NS_ASSERTION(!InTransaction(), "Died during transaction?");
michael@0 262
michael@0 263 ClearCachedResources();
michael@0 264
michael@0 265 mRoot = nullptr;
michael@0 266
michael@0 267 MOZ_COUNT_DTOR(BasicLayerManager);
michael@0 268 }
michael@0 269
michael@0 270 void
michael@0 271 BasicLayerManager::SetDefaultTarget(gfxContext* aContext)
michael@0 272 {
michael@0 273 NS_ASSERTION(!InTransaction(),
michael@0 274 "Must set default target outside transaction");
michael@0 275 mDefaultTarget = aContext;
michael@0 276 }
michael@0 277
michael@0 278 void
michael@0 279 BasicLayerManager::SetDefaultTargetConfiguration(BufferMode aDoubleBuffering, ScreenRotation aRotation)
michael@0 280 {
michael@0 281 mDoubleBuffering = aDoubleBuffering;
michael@0 282 }
michael@0 283
michael@0 284 void
michael@0 285 BasicLayerManager::BeginTransaction()
michael@0 286 {
michael@0 287 mInTransaction = true;
michael@0 288 mUsingDefaultTarget = true;
michael@0 289 BeginTransactionWithTarget(mDefaultTarget);
michael@0 290 }
michael@0 291
michael@0 292 already_AddRefed<gfxContext>
michael@0 293 BasicLayerManager::PushGroupWithCachedSurface(gfxContext *aTarget,
michael@0 294 gfxContentType aContent)
michael@0 295 {
michael@0 296 nsRefPtr<gfxContext> ctx;
michael@0 297 // We can't cache Azure DrawTargets at this point.
michael@0 298 if (!mCachedSurfaceInUse && aTarget->IsCairo()) {
michael@0 299 gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
michael@0 300 aTarget->IdentityMatrix();
michael@0 301
michael@0 302 nsRefPtr<gfxASurface> currentSurf = aTarget->CurrentSurface();
michael@0 303 gfxRect clip = aTarget->GetClipExtents();
michael@0 304 clip.RoundOut();
michael@0 305
michael@0 306 ctx = mCachedSurface.Get(aContent, clip, currentSurf);
michael@0 307
michael@0 308 if (ctx) {
michael@0 309 mCachedSurfaceInUse = true;
michael@0 310 /* Align our buffer for the original surface */
michael@0 311 ctx->SetMatrix(saveMatrix.Matrix());
michael@0 312 return ctx.forget();
michael@0 313 }
michael@0 314 }
michael@0 315
michael@0 316 ctx = aTarget;
michael@0 317 ctx->PushGroup(aContent);
michael@0 318 return ctx.forget();
michael@0 319 }
michael@0 320
michael@0 321 void
michael@0 322 BasicLayerManager::PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed)
michael@0 323 {
michael@0 324 if (!aTarget)
michael@0 325 return;
michael@0 326 if (aTarget->IsCairo()) {
michael@0 327 nsRefPtr<gfxASurface> current = aPushed->CurrentSurface();
michael@0 328 if (mCachedSurface.IsSurface(current)) {
michael@0 329 gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
michael@0 330 aTarget->IdentityMatrix();
michael@0 331 aTarget->SetSource(current);
michael@0 332 mCachedSurfaceInUse = false;
michael@0 333 return;
michael@0 334 }
michael@0 335 }
michael@0 336 aTarget->PopGroupToSource();
michael@0 337 }
michael@0 338
michael@0 339 void
michael@0 340 BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
michael@0 341 {
michael@0 342 mInTransaction = true;
michael@0 343
michael@0 344 #ifdef MOZ_LAYERS_HAVE_LOG
michael@0 345 MOZ_LAYERS_LOG(("[----- BeginTransaction"));
michael@0 346 Log();
michael@0 347 #endif
michael@0 348
michael@0 349 NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
michael@0 350 mPhase = PHASE_CONSTRUCTION;
michael@0 351 mTarget = aTarget;
michael@0 352 }
michael@0 353
michael@0 354 static void
michael@0 355 TransformIntRect(nsIntRect& aRect, const Matrix& aMatrix,
michael@0 356 nsIntRect (*aRoundMethod)(const gfxRect&))
michael@0 357 {
michael@0 358 Rect gr = Rect(aRect.x, aRect.y, aRect.width, aRect.height);
michael@0 359 gr = aMatrix.TransformBounds(gr);
michael@0 360 aRect = (*aRoundMethod)(ThebesRect(gr));
michael@0 361 }
michael@0 362
michael@0 363 /**
michael@0 364 * This function assumes that GetEffectiveTransform transforms
michael@0 365 * all layers to the same coordinate system (the "root coordinate system").
michael@0 366 * It can't be used as is by accelerated layers because of intermediate surfaces.
michael@0 367 * This must set the hidden flag to true or false on *all* layers in the subtree.
michael@0 368 * It also sets the operator for all layers to "OVER", and call
michael@0 369 * SetDrawAtomically(false).
michael@0 370 * It clears mClipToVisibleRegion on all layers.
michael@0 371 * @param aClipRect the cliprect, in the root coordinate system. We assume
michael@0 372 * that any layer drawing is clipped to this rect. It is therefore not
michael@0 373 * allowed to add to the opaque region outside that rect.
michael@0 374 * @param aDirtyRect the dirty rect that will be painted, in the root
michael@0 375 * coordinate system. Layers outside this rect should be hidden.
michael@0 376 * @param aOpaqueRegion the opaque region covering aLayer, in the
michael@0 377 * root coordinate system.
michael@0 378 */
michael@0 379 enum {
michael@0 380 ALLOW_OPAQUE = 0x01,
michael@0 381 };
michael@0 382 static void
michael@0 383 MarkLayersHidden(Layer* aLayer, const nsIntRect& aClipRect,
michael@0 384 const nsIntRect& aDirtyRect,
michael@0 385 nsIntRegion& aOpaqueRegion,
michael@0 386 uint32_t aFlags)
michael@0 387 {
michael@0 388 nsIntRect newClipRect(aClipRect);
michael@0 389 uint32_t newFlags = aFlags;
michael@0 390
michael@0 391 // Allow aLayer or aLayer's descendants to cover underlying layers
michael@0 392 // only if it's opaque.
michael@0 393 if (aLayer->GetOpacity() != 1.0f) {
michael@0 394 newFlags &= ~ALLOW_OPAQUE;
michael@0 395 }
michael@0 396
michael@0 397 {
michael@0 398 const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
michael@0 399 if (clipRect) {
michael@0 400 nsIntRect cr = *clipRect;
michael@0 401 // clipRect is in the container's coordinate system. Get it into the
michael@0 402 // global coordinate system.
michael@0 403 if (aLayer->GetParent()) {
michael@0 404 Matrix tr;
michael@0 405 if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
michael@0 406 // Clip rect is applied after aLayer's transform, i.e., in the coordinate
michael@0 407 // system of aLayer's parent.
michael@0 408 TransformIntRect(cr, tr, ToInsideIntRect);
michael@0 409 } else {
michael@0 410 cr.SetRect(0, 0, 0, 0);
michael@0 411 }
michael@0 412 }
michael@0 413 newClipRect.IntersectRect(newClipRect, cr);
michael@0 414 }
michael@0 415 }
michael@0 416
michael@0 417 BasicImplData* data = ToData(aLayer);
michael@0 418 data->SetOperator(CompositionOp::OP_OVER);
michael@0 419 data->SetClipToVisibleRegion(false);
michael@0 420 data->SetDrawAtomically(false);
michael@0 421
michael@0 422 if (!aLayer->AsContainerLayer()) {
michael@0 423 Matrix transform;
michael@0 424 if (!aLayer->GetEffectiveTransform().CanDraw2D(&transform)) {
michael@0 425 data->SetHidden(false);
michael@0 426 return;
michael@0 427 }
michael@0 428
michael@0 429 nsIntRegion region = aLayer->GetEffectiveVisibleRegion();
michael@0 430 nsIntRect r = region.GetBounds();
michael@0 431 TransformIntRect(r, transform, ToOutsideIntRect);
michael@0 432 r.IntersectRect(r, aDirtyRect);
michael@0 433 data->SetHidden(aOpaqueRegion.Contains(r));
michael@0 434
michael@0 435 // Allow aLayer to cover underlying layers only if aLayer's
michael@0 436 // content is opaque
michael@0 437 if ((aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
michael@0 438 (newFlags & ALLOW_OPAQUE)) {
michael@0 439 nsIntRegionRectIterator it(region);
michael@0 440 while (const nsIntRect* sr = it.Next()) {
michael@0 441 r = *sr;
michael@0 442 TransformIntRect(r, transform, ToInsideIntRect);
michael@0 443
michael@0 444 r.IntersectRect(r, newClipRect);
michael@0 445 aOpaqueRegion.Or(aOpaqueRegion, r);
michael@0 446 }
michael@0 447 }
michael@0 448 } else {
michael@0 449 Layer* child = aLayer->GetLastChild();
michael@0 450 bool allHidden = true;
michael@0 451 for (; child; child = child->GetPrevSibling()) {
michael@0 452 MarkLayersHidden(child, newClipRect, aDirtyRect, aOpaqueRegion, newFlags);
michael@0 453 if (!ToData(child)->IsHidden()) {
michael@0 454 allHidden = false;
michael@0 455 }
michael@0 456 }
michael@0 457 data->SetHidden(allHidden);
michael@0 458 }
michael@0 459 }
michael@0 460
michael@0 461 /**
michael@0 462 * This function assumes that GetEffectiveTransform transforms
michael@0 463 * all layers to the same coordinate system (the "root coordinate system").
michael@0 464 * MarkLayersHidden must be called before calling this.
michael@0 465 * @param aVisibleRect the rectangle of aLayer that is visible (i.e. not
michael@0 466 * clipped and in the dirty rect), in the root coordinate system.
michael@0 467 */
michael@0 468 static void
michael@0 469 ApplyDoubleBuffering(Layer* aLayer, const nsIntRect& aVisibleRect)
michael@0 470 {
michael@0 471 BasicImplData* data = ToData(aLayer);
michael@0 472 if (data->IsHidden())
michael@0 473 return;
michael@0 474
michael@0 475 nsIntRect newVisibleRect(aVisibleRect);
michael@0 476
michael@0 477 {
michael@0 478 const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
michael@0 479 if (clipRect) {
michael@0 480 nsIntRect cr = *clipRect;
michael@0 481 // clipRect is in the container's coordinate system. Get it into the
michael@0 482 // global coordinate system.
michael@0 483 if (aLayer->GetParent()) {
michael@0 484 Matrix tr;
michael@0 485 if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
michael@0 486 NS_ASSERTION(!ThebesMatrix(tr).HasNonIntegerTranslation(),
michael@0 487 "Parent can only have an integer translation");
michael@0 488 cr += nsIntPoint(int32_t(tr._31), int32_t(tr._32));
michael@0 489 } else {
michael@0 490 NS_ERROR("Parent can only have an integer translation");
michael@0 491 }
michael@0 492 }
michael@0 493 newVisibleRect.IntersectRect(newVisibleRect, cr);
michael@0 494 }
michael@0 495 }
michael@0 496
michael@0 497 BasicContainerLayer* container =
michael@0 498 static_cast<BasicContainerLayer*>(aLayer->AsContainerLayer());
michael@0 499 // Layers that act as their own backbuffers should be drawn to the destination
michael@0 500 // using OPERATOR_SOURCE to ensure that alpha values in a transparent window
michael@0 501 // are cleared. This can also be faster than OPERATOR_OVER.
michael@0 502 if (!container) {
michael@0 503 data->SetOperator(CompositionOp::OP_SOURCE);
michael@0 504 data->SetDrawAtomically(true);
michael@0 505 } else {
michael@0 506 if (container->UseIntermediateSurface() ||
michael@0 507 !container->ChildrenPartitionVisibleRegion(newVisibleRect)) {
michael@0 508 // We need to double-buffer this container.
michael@0 509 data->SetOperator(CompositionOp::OP_SOURCE);
michael@0 510 container->ForceIntermediateSurface();
michael@0 511 } else {
michael@0 512 // Tell the children to clip to their visible regions so our assumption
michael@0 513 // that they don't paint outside their visible regions is valid!
michael@0 514 for (Layer* child = aLayer->GetFirstChild(); child;
michael@0 515 child = child->GetNextSibling()) {
michael@0 516 ToData(child)->SetClipToVisibleRegion(true);
michael@0 517 ApplyDoubleBuffering(child, newVisibleRect);
michael@0 518 }
michael@0 519 }
michael@0 520 }
michael@0 521 }
michael@0 522
michael@0 523 void
michael@0 524 BasicLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
michael@0 525 void* aCallbackData,
michael@0 526 EndTransactionFlags aFlags)
michael@0 527 {
michael@0 528 mInTransaction = false;
michael@0 529
michael@0 530 EndTransactionInternal(aCallback, aCallbackData, aFlags);
michael@0 531 }
michael@0 532
michael@0 533 void
michael@0 534 BasicLayerManager::AbortTransaction()
michael@0 535 {
michael@0 536 NS_ASSERTION(InConstruction(), "Should be in construction phase");
michael@0 537 mPhase = PHASE_NONE;
michael@0 538 mUsingDefaultTarget = false;
michael@0 539 mInTransaction = false;
michael@0 540 }
michael@0 541
michael@0 542 static uint16_t sFrameCount = 0;
michael@0 543 void
michael@0 544 BasicLayerManager::RenderDebugOverlay()
michael@0 545 {
michael@0 546 if (!gfxPrefs::DrawFrameCounter()) {
michael@0 547 return;
michael@0 548 }
michael@0 549
michael@0 550 profiler_set_frame_number(sFrameCount);
michael@0 551
michael@0 552 uint16_t frameNumber = sFrameCount;
michael@0 553 const uint16_t bitWidth = 3;
michael@0 554 for (size_t i = 0; i < 16; i++) {
michael@0 555
michael@0 556 gfxRGBA bitColor;
michael@0 557 if ((frameNumber >> i) & 0x1) {
michael@0 558 bitColor = gfxRGBA(0, 0, 0, 1.0);
michael@0 559 } else {
michael@0 560 bitColor = gfxRGBA(1.0, 1.0, 1.0, 1.0);
michael@0 561 }
michael@0 562 mTarget->NewPath();
michael@0 563 mTarget->SetColor(bitColor);
michael@0 564 mTarget->Rectangle(gfxRect(bitWidth*i, 0, bitWidth, bitWidth));
michael@0 565 mTarget->Fill();
michael@0 566 }
michael@0 567 // We intentionally overflow at 2^16.
michael@0 568 sFrameCount++;
michael@0 569 }
michael@0 570
michael@0 571 bool
michael@0 572 BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
michael@0 573 void* aCallbackData,
michael@0 574 EndTransactionFlags aFlags)
michael@0 575 {
michael@0 576 PROFILER_LABEL("BasicLayerManager", "EndTransactionInternal");
michael@0 577 #ifdef MOZ_LAYERS_HAVE_LOG
michael@0 578 MOZ_LAYERS_LOG((" ----- (beginning paint)"));
michael@0 579 Log();
michael@0 580 #endif
michael@0 581
michael@0 582 NS_ASSERTION(InConstruction(), "Should be in construction phase");
michael@0 583 mPhase = PHASE_DRAWING;
michael@0 584
michael@0 585 RenderTraceLayers(mRoot, "FF00");
michael@0 586
michael@0 587 mTransactionIncomplete = false;
michael@0 588
michael@0 589 if (mRoot) {
michael@0 590 // Need to do this before we call ApplyDoubleBuffering,
michael@0 591 // which depends on correct effective transforms
michael@0 592 mSnapEffectiveTransforms =
michael@0 593 mTarget ? !(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING) : true;
michael@0 594 mRoot->ComputeEffectiveTransforms(mTarget ? Matrix4x4::From2D(ToMatrix(mTarget->CurrentMatrix())) : Matrix4x4());
michael@0 595
michael@0 596 ToData(mRoot)->Validate(aCallback, aCallbackData);
michael@0 597 if (mRoot->GetMaskLayer()) {
michael@0 598 ToData(mRoot->GetMaskLayer())->Validate(aCallback, aCallbackData);
michael@0 599 }
michael@0 600
michael@0 601 if (aFlags & END_NO_COMPOSITE) {
michael@0 602 // Apply pending tree updates before recomputing effective
michael@0 603 // properties.
michael@0 604 mRoot->ApplyPendingUpdatesToSubtree();
michael@0 605 }
michael@0 606 }
michael@0 607
michael@0 608 if (mTarget && mRoot &&
michael@0 609 !(aFlags & END_NO_IMMEDIATE_REDRAW) &&
michael@0 610 !(aFlags & END_NO_COMPOSITE)) {
michael@0 611 nsIntRect clipRect;
michael@0 612
michael@0 613 {
michael@0 614 gfxContextMatrixAutoSaveRestore save(mTarget);
michael@0 615 mTarget->SetMatrix(gfxMatrix());
michael@0 616 clipRect = ToOutsideIntRect(mTarget->GetClipExtents());
michael@0 617 }
michael@0 618
michael@0 619 if (IsRetained()) {
michael@0 620 nsIntRegion region;
michael@0 621 MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE);
michael@0 622 if (mUsingDefaultTarget && mDoubleBuffering != BufferMode::BUFFER_NONE) {
michael@0 623 ApplyDoubleBuffering(mRoot, clipRect);
michael@0 624 }
michael@0 625 }
michael@0 626
michael@0 627 PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
michael@0 628 if (!mRegionToClear.IsEmpty()) {
michael@0 629 AutoSetOperator op(mTarget, gfxContext::OPERATOR_CLEAR);
michael@0 630 nsIntRegionRectIterator iter(mRegionToClear);
michael@0 631 const nsIntRect *r;
michael@0 632 while ((r = iter.Next())) {
michael@0 633 mTarget->NewPath();
michael@0 634 mTarget->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
michael@0 635 mTarget->Fill();
michael@0 636 }
michael@0 637 }
michael@0 638 if (mWidget) {
michael@0 639 FlashWidgetUpdateArea(mTarget);
michael@0 640 }
michael@0 641 RenderDebugOverlay();
michael@0 642 RecordFrame();
michael@0 643 PostPresent();
michael@0 644
michael@0 645 if (!mTransactionIncomplete) {
michael@0 646 // Clear out target if we have a complete transaction.
michael@0 647 mTarget = nullptr;
michael@0 648 }
michael@0 649 }
michael@0 650
michael@0 651 #ifdef MOZ_LAYERS_HAVE_LOG
michael@0 652 Log();
michael@0 653 MOZ_LAYERS_LOG(("]----- EndTransaction"));
michael@0 654 #endif
michael@0 655
michael@0 656 // Go back to the construction phase if the transaction isn't complete.
michael@0 657 // Layout will update the layer tree and call EndTransaction().
michael@0 658 mPhase = mTransactionIncomplete ? PHASE_CONSTRUCTION : PHASE_NONE;
michael@0 659
michael@0 660 if (!mTransactionIncomplete) {
michael@0 661 // This is still valid if the transaction was incomplete.
michael@0 662 mUsingDefaultTarget = false;
michael@0 663 }
michael@0 664
michael@0 665 NS_ASSERTION(!aCallback || !mTransactionIncomplete,
michael@0 666 "If callback is not null, transaction must be complete");
michael@0 667
michael@0 668 // XXX - We should probably assert here that for an incomplete transaction
michael@0 669 // out target is the default target.
michael@0 670
michael@0 671 return !mTransactionIncomplete;
michael@0 672 }
michael@0 673
michael@0 674 void
michael@0 675 BasicLayerManager::FlashWidgetUpdateArea(gfxContext *aContext)
michael@0 676 {
michael@0 677 if (gfxPrefs::WidgetUpdateFlashing()) {
michael@0 678 float r = float(rand()) / RAND_MAX;
michael@0 679 float g = float(rand()) / RAND_MAX;
michael@0 680 float b = float(rand()) / RAND_MAX;
michael@0 681 aContext->SetColor(gfxRGBA(r, g, b, 0.2));
michael@0 682 aContext->Paint();
michael@0 683 }
michael@0 684 }
michael@0 685
michael@0 686 bool
michael@0 687 BasicLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
michael@0 688 {
michael@0 689 mInTransaction = false;
michael@0 690
michael@0 691 if (!mRoot) {
michael@0 692 return false;
michael@0 693 }
michael@0 694
michael@0 695 return EndTransactionInternal(nullptr, nullptr, aFlags);
michael@0 696 }
michael@0 697
michael@0 698 void
michael@0 699 BasicLayerManager::SetRoot(Layer* aLayer)
michael@0 700 {
michael@0 701 NS_ASSERTION(aLayer, "Root can't be null");
michael@0 702 NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
michael@0 703 NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
michael@0 704 mRoot = aLayer;
michael@0 705 }
michael@0 706
michael@0 707 static pixman_transform
michael@0 708 BasicLayerManager_Matrix3DToPixman(const gfx3DMatrix& aMatrix)
michael@0 709 {
michael@0 710 pixman_f_transform transform;
michael@0 711
michael@0 712 transform.m[0][0] = aMatrix._11;
michael@0 713 transform.m[0][1] = aMatrix._21;
michael@0 714 transform.m[0][2] = aMatrix._41;
michael@0 715 transform.m[1][0] = aMatrix._12;
michael@0 716 transform.m[1][1] = aMatrix._22;
michael@0 717 transform.m[1][2] = aMatrix._42;
michael@0 718 transform.m[2][0] = aMatrix._14;
michael@0 719 transform.m[2][1] = aMatrix._24;
michael@0 720 transform.m[2][2] = aMatrix._44;
michael@0 721
michael@0 722 pixman_transform result;
michael@0 723 pixman_transform_from_pixman_f_transform(&result, &transform);
michael@0 724
michael@0 725 return result;
michael@0 726 }
michael@0 727
michael@0 728 static void
michael@0 729 PixmanTransform(const gfxImageSurface* aDest,
michael@0 730 RefPtr<DataSourceSurface> aSrc,
michael@0 731 const gfx3DMatrix& aTransform,
michael@0 732 gfxPoint aDestOffset)
michael@0 733 {
michael@0 734 IntSize destSize = ToIntSize(aDest->GetSize());
michael@0 735 pixman_image_t* dest = pixman_image_create_bits(aDest->Format() == gfxImageFormat::ARGB32 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
michael@0 736 destSize.width,
michael@0 737 destSize.height,
michael@0 738 (uint32_t*)aDest->Data(),
michael@0 739 aDest->Stride());
michael@0 740
michael@0 741 IntSize srcSize = aSrc->GetSize();
michael@0 742 pixman_image_t* src = pixman_image_create_bits(aSrc->GetFormat() == SurfaceFormat::B8G8R8A8 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
michael@0 743 srcSize.width,
michael@0 744 srcSize.height,
michael@0 745 (uint32_t*)aSrc->GetData(),
michael@0 746 aSrc->Stride());
michael@0 747
michael@0 748 NS_ABORT_IF_FALSE(src && dest, "Failed to create pixman images?");
michael@0 749
michael@0 750 pixman_transform pixTransform = BasicLayerManager_Matrix3DToPixman(aTransform);
michael@0 751 pixman_transform pixTransformInverted;
michael@0 752
michael@0 753 // If the transform is singular then nothing would be drawn anyway, return here
michael@0 754 if (!pixman_transform_invert(&pixTransformInverted, &pixTransform)) {
michael@0 755 return;
michael@0 756 }
michael@0 757 pixman_image_set_transform(src, &pixTransformInverted);
michael@0 758
michael@0 759 pixman_image_composite32(PIXMAN_OP_SRC,
michael@0 760 src,
michael@0 761 nullptr,
michael@0 762 dest,
michael@0 763 aDestOffset.x,
michael@0 764 aDestOffset.y,
michael@0 765 0,
michael@0 766 0,
michael@0 767 0,
michael@0 768 0,
michael@0 769 destSize.width,
michael@0 770 destSize.height);
michael@0 771
michael@0 772 pixman_image_unref(dest);
michael@0 773 pixman_image_unref(src);
michael@0 774 }
michael@0 775
michael@0 776 /**
michael@0 777 * Transform a surface using a gfx3DMatrix and blit to the destination if
michael@0 778 * it is efficient to do so.
michael@0 779 *
michael@0 780 * @param aSource Source surface.
michael@0 781 * @param aDest Desintation context.
michael@0 782 * @param aBounds Area represented by aSource.
michael@0 783 * @param aTransform Transformation matrix.
michael@0 784 * @param aDestRect Output: rectangle in which to draw returned surface on aDest
michael@0 785 * (same size as aDest). Only filled in if this returns
michael@0 786 * a surface.
michael@0 787 * @return Transformed surface
michael@0 788 */
michael@0 789 static already_AddRefed<gfxASurface>
michael@0 790 Transform3D(RefPtr<SourceSurface> aSource,
michael@0 791 gfxContext* aDest,
michael@0 792 const gfxRect& aBounds,
michael@0 793 const gfx3DMatrix& aTransform,
michael@0 794 gfxRect& aDestRect)
michael@0 795 {
michael@0 796 // Find the transformed rectangle of our layer.
michael@0 797 gfxRect offsetRect = aTransform.TransformBounds(aBounds);
michael@0 798
michael@0 799 // Intersect the transformed layer with the destination rectangle.
michael@0 800 // This is in device space since we have an identity transform set on aTarget.
michael@0 801 aDestRect = aDest->GetClipExtents();
michael@0 802 aDestRect.IntersectRect(aDestRect, offsetRect);
michael@0 803 aDestRect.RoundOut();
michael@0 804
michael@0 805 // Create a surface the size of the transformed object.
michael@0 806 nsRefPtr<gfxASurface> dest = aDest->CurrentSurface();
michael@0 807 nsRefPtr<gfxImageSurface> destImage = new gfxImageSurface(gfxIntSize(aDestRect.width,
michael@0 808 aDestRect.height),
michael@0 809 gfxImageFormat::ARGB32);
michael@0 810 gfxPoint offset = aDestRect.TopLeft();
michael@0 811
michael@0 812 // Include a translation to the correct origin.
michael@0 813 gfx3DMatrix translation = gfx3DMatrix::Translation(aBounds.x, aBounds.y, 0);
michael@0 814
michael@0 815 // Transform the content and offset it such that the content begins at the origin.
michael@0 816 PixmanTransform(destImage, aSource->GetDataSurface(), translation * aTransform, offset);
michael@0 817
michael@0 818 // If we haven't actually drawn to aDest then return our temporary image so
michael@0 819 // that the caller can do this.
michael@0 820 return destImage.forget();
michael@0 821 }
michael@0 822
michael@0 823 void
michael@0 824 BasicLayerManager::PaintSelfOrChildren(PaintLayerContext& aPaintContext,
michael@0 825 gfxContext* aGroupTarget)
michael@0 826 {
michael@0 827 BasicImplData* data = ToData(aPaintContext.mLayer);
michael@0 828
michael@0 829 /* Only paint ourself, or our children - This optimization relies on this! */
michael@0 830 Layer* child = aPaintContext.mLayer->GetFirstChild();
michael@0 831 if (!child) {
michael@0 832 if (aPaintContext.mLayer->AsThebesLayer()) {
michael@0 833 data->PaintThebes(aGroupTarget, aPaintContext.mLayer->GetMaskLayer(),
michael@0 834 aPaintContext.mCallback, aPaintContext.mCallbackData,
michael@0 835 aPaintContext.mReadback);
michael@0 836 } else {
michael@0 837 data->Paint(aGroupTarget->GetDrawTarget(),
michael@0 838 aGroupTarget->GetDeviceOffset(),
michael@0 839 aPaintContext.mLayer->GetMaskLayer());
michael@0 840 }
michael@0 841 } else {
michael@0 842 ReadbackProcessor readback;
michael@0 843 ContainerLayer* container =
michael@0 844 static_cast<ContainerLayer*>(aPaintContext.mLayer);
michael@0 845 if (IsRetained()) {
michael@0 846 readback.BuildUpdates(container);
michael@0 847 }
michael@0 848 nsAutoTArray<Layer*, 12> children;
michael@0 849 container->SortChildrenBy3DZOrder(children);
michael@0 850 for (uint32_t i = 0; i < children.Length(); i++) {
michael@0 851 PaintLayer(aGroupTarget, children.ElementAt(i), aPaintContext.mCallback,
michael@0 852 aPaintContext.mCallbackData, &readback);
michael@0 853 if (mTransactionIncomplete)
michael@0 854 break;
michael@0 855 }
michael@0 856 }
michael@0 857 }
michael@0 858
michael@0 859 void
michael@0 860 BasicLayerManager::FlushGroup(PaintLayerContext& aPaintContext, bool aNeedsClipToVisibleRegion)
michael@0 861 {
michael@0 862 // If we're doing our own double-buffering, we need to avoid drawing
michael@0 863 // the results of an incomplete transaction to the destination surface ---
michael@0 864 // that could cause flicker. Double-buffering is implemented using a
michael@0 865 // temporary surface for one or more container layers, so we need to stop
michael@0 866 // those temporary surfaces from being composited to aTarget.
michael@0 867 // ApplyDoubleBuffering guarantees that this container layer can't
michael@0 868 // intersect any other leaf layers, so if the transaction is not yet marked
michael@0 869 // incomplete, the contents of this container layer are the final contents
michael@0 870 // for the window.
michael@0 871 if (!mTransactionIncomplete) {
michael@0 872 if (aNeedsClipToVisibleRegion) {
michael@0 873 gfxUtils::ClipToRegion(aPaintContext.mTarget,
michael@0 874 aPaintContext.mLayer->GetEffectiveVisibleRegion());
michael@0 875 }
michael@0 876
michael@0 877 CompositionOp op = GetEffectiveOperator(aPaintContext.mLayer);
michael@0 878 AutoSetOperator setOperator(aPaintContext.mTarget, ThebesOp(op));
michael@0 879
michael@0 880 PaintWithMask(aPaintContext.mTarget, aPaintContext.mLayer->GetEffectiveOpacity(),
michael@0 881 aPaintContext.mLayer->GetMaskLayer());
michael@0 882 }
michael@0 883 }
michael@0 884
michael@0 885 void
michael@0 886 BasicLayerManager::PaintLayer(gfxContext* aTarget,
michael@0 887 Layer* aLayer,
michael@0 888 DrawThebesLayerCallback aCallback,
michael@0 889 void* aCallbackData,
michael@0 890 ReadbackProcessor* aReadback)
michael@0 891 {
michael@0 892 PROFILER_LABEL("BasicLayerManager", "PaintLayer");
michael@0 893 PaintLayerContext paintLayerContext(aTarget, aLayer, aCallback, aCallbackData, aReadback);
michael@0 894
michael@0 895 // Don't attempt to paint layers with a singular transform, cairo will
michael@0 896 // just throw an error.
michael@0 897 if (aLayer->GetEffectiveTransform().IsSingular()) {
michael@0 898 return;
michael@0 899 }
michael@0 900
michael@0 901 RenderTraceScope trace("BasicLayerManager::PaintLayer", "707070");
michael@0 902
michael@0 903 const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
michael@0 904 BasicContainerLayer* container =
michael@0 905 static_cast<BasicContainerLayer*>(aLayer->AsContainerLayer());
michael@0 906 bool needsGroup = container &&
michael@0 907 container->UseIntermediateSurface();
michael@0 908 BasicImplData* data = ToData(aLayer);
michael@0 909 bool needsClipToVisibleRegion =
michael@0 910 data->GetClipToVisibleRegion() && !aLayer->AsThebesLayer();
michael@0 911 NS_ASSERTION(needsGroup || !container ||
michael@0 912 container->GetOperator() == CompositionOp::OP_OVER,
michael@0 913 "non-OVER operator should have forced UseIntermediateSurface");
michael@0 914 NS_ASSERTION(!container || !aLayer->GetMaskLayer() ||
michael@0 915 container->UseIntermediateSurface(),
michael@0 916 "ContainerLayer with mask layer should force UseIntermediateSurface");
michael@0 917
michael@0 918 gfxContextAutoSaveRestore contextSR;
michael@0 919 gfxMatrix transform;
michael@0 920 // Will return an identity matrix for 3d transforms, and is handled separately below.
michael@0 921 bool is2D = paintLayerContext.Setup2DTransform();
michael@0 922 NS_ABORT_IF_FALSE(is2D || needsGroup || !aLayer->GetFirstChild(), "Must PushGroup for 3d transforms!");
michael@0 923
michael@0 924 bool needsSaveRestore =
michael@0 925 needsGroup || clipRect || needsClipToVisibleRegion || !is2D;
michael@0 926 if (needsSaveRestore) {
michael@0 927 contextSR.SetContext(aTarget);
michael@0 928
michael@0 929 if (clipRect) {
michael@0 930 aTarget->NewPath();
michael@0 931 aTarget->SnappedRectangle(gfxRect(clipRect->x, clipRect->y, clipRect->width, clipRect->height));
michael@0 932 aTarget->Clip();
michael@0 933 }
michael@0 934 }
michael@0 935
michael@0 936 paintLayerContext.Apply2DTransform();
michael@0 937
michael@0 938 const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
michael@0 939 // If needsGroup is true, we'll clip to the visible region after we've popped the group
michael@0 940 if (needsClipToVisibleRegion && !needsGroup) {
michael@0 941 gfxUtils::ClipToRegion(aTarget, visibleRegion);
michael@0 942 // Don't need to clip to visible region again
michael@0 943 needsClipToVisibleRegion = false;
michael@0 944 }
michael@0 945
michael@0 946 if (is2D) {
michael@0 947 paintLayerContext.AnnotateOpaqueRect();
michael@0 948 }
michael@0 949
michael@0 950 bool clipIsEmpty = !aTarget || aTarget->GetClipExtents().IsEmpty();
michael@0 951 if (clipIsEmpty) {
michael@0 952 PaintSelfOrChildren(paintLayerContext, aTarget);
michael@0 953 return;
michael@0 954 }
michael@0 955
michael@0 956 if (is2D) {
michael@0 957 if (needsGroup) {
michael@0 958 nsRefPtr<gfxContext> groupTarget = PushGroupForLayer(aTarget, aLayer, aLayer->GetEffectiveVisibleRegion(),
michael@0 959 &needsClipToVisibleRegion);
michael@0 960 PaintSelfOrChildren(paintLayerContext, groupTarget);
michael@0 961 PopGroupToSourceWithCachedSurface(aTarget, groupTarget);
michael@0 962 FlushGroup(paintLayerContext, needsClipToVisibleRegion);
michael@0 963 } else {
michael@0 964 PaintSelfOrChildren(paintLayerContext, aTarget);
michael@0 965 }
michael@0 966 } else {
michael@0 967 const nsIntRect& bounds = visibleRegion.GetBounds();
michael@0 968 RefPtr<DrawTarget> untransformedDT =
michael@0 969 gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(bounds.width, bounds.height),
michael@0 970 SurfaceFormat::B8G8R8A8);
michael@0 971 if (!untransformedDT) {
michael@0 972 return;
michael@0 973 }
michael@0 974
michael@0 975 nsRefPtr<gfxContext> groupTarget = new gfxContext(untransformedDT,
michael@0 976 Point(bounds.x, bounds.y));
michael@0 977
michael@0 978 PaintSelfOrChildren(paintLayerContext, groupTarget);
michael@0 979
michael@0 980 // Temporary fast fix for bug 725886
michael@0 981 // Revert these changes when 725886 is ready
michael@0 982 NS_ABORT_IF_FALSE(untransformedDT,
michael@0 983 "We should always allocate an untransformed surface with 3d transforms!");
michael@0 984 gfxRect destRect;
michael@0 985 #ifdef DEBUG
michael@0 986 if (aLayer->GetDebugColorIndex() != 0) {
michael@0 987 gfxRGBA color((aLayer->GetDebugColorIndex() & 1) ? 1.0 : 0.0,
michael@0 988 (aLayer->GetDebugColorIndex() & 2) ? 1.0 : 0.0,
michael@0 989 (aLayer->GetDebugColorIndex() & 4) ? 1.0 : 0.0,
michael@0 990 1.0);
michael@0 991
michael@0 992 nsRefPtr<gfxContext> temp = new gfxContext(untransformedDT, Point(bounds.x, bounds.y));
michael@0 993 temp->SetColor(color);
michael@0 994 temp->Paint();
michael@0 995 }
michael@0 996 #endif
michael@0 997 gfx3DMatrix effectiveTransform;
michael@0 998 gfx::To3DMatrix(aLayer->GetEffectiveTransform(), effectiveTransform);
michael@0 999 nsRefPtr<gfxASurface> result =
michael@0 1000 Transform3D(untransformedDT->Snapshot(), aTarget, bounds,
michael@0 1001 effectiveTransform, destRect);
michael@0 1002
michael@0 1003 if (result) {
michael@0 1004 aTarget->SetSource(result, destRect.TopLeft());
michael@0 1005 // Azure doesn't support EXTEND_NONE, so to avoid extending the edges
michael@0 1006 // of the source surface out to the current clip region, clip to
michael@0 1007 // the rectangle of the result surface now.
michael@0 1008 aTarget->NewPath();
michael@0 1009 aTarget->SnappedRectangle(destRect);
michael@0 1010 aTarget->Clip();
michael@0 1011 FlushGroup(paintLayerContext, needsClipToVisibleRegion);
michael@0 1012 }
michael@0 1013 }
michael@0 1014 }
michael@0 1015
michael@0 1016 void
michael@0 1017 BasicLayerManager::ClearCachedResources(Layer* aSubtree)
michael@0 1018 {
michael@0 1019 MOZ_ASSERT(!aSubtree || aSubtree->Manager() == this);
michael@0 1020 if (aSubtree) {
michael@0 1021 ClearLayer(aSubtree);
michael@0 1022 } else if (mRoot) {
michael@0 1023 ClearLayer(mRoot);
michael@0 1024 }
michael@0 1025 mCachedSurface.Expire();
michael@0 1026 }
michael@0 1027 void
michael@0 1028 BasicLayerManager::ClearLayer(Layer* aLayer)
michael@0 1029 {
michael@0 1030 ToData(aLayer)->ClearCachedResources();
michael@0 1031 for (Layer* child = aLayer->GetFirstChild(); child;
michael@0 1032 child = child->GetNextSibling()) {
michael@0 1033 ClearLayer(child);
michael@0 1034 }
michael@0 1035 }
michael@0 1036
michael@0 1037 already_AddRefed<ReadbackLayer>
michael@0 1038 BasicLayerManager::CreateReadbackLayer()
michael@0 1039 {
michael@0 1040 NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
michael@0 1041 nsRefPtr<ReadbackLayer> layer = new BasicReadbackLayer(this);
michael@0 1042 return layer.forget();
michael@0 1043 }
michael@0 1044
michael@0 1045 }
michael@0 1046 }

mercurial