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