1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "LayerTreeInvalidation.h"
9 #include <stdint.h> // for uint32_t
10 #include "ImageContainer.h" // for ImageContainer
11 #include "ImageLayers.h" // for ImageLayer, etc
12 #include "Layers.h" // for Layer, ContainerLayer, etc
13 #include "Units.h" // for ParentLayerIntRect
14 #include "gfxRect.h" // for gfxRect
15 #include "gfxUtils.h" // for gfxUtils
16 #include "mozilla/ArrayUtils.h" // for ArrayEqual
17 #include "mozilla/gfx/BaseSize.h" // for BaseSize
18 #include "mozilla/gfx/Point.h" // for IntSize
19 #include "mozilla/mozalloc.h" // for operator new, etc
20 #include "nsDataHashtable.h" // for nsDataHashtable
21 #include "nsDebug.h" // for NS_ASSERTION
22 #include "nsHashKeys.h" // for nsPtrHashKey
23 #include "nsISupportsImpl.h" // for Layer::AddRef, etc
24 #include "nsRect.h" // for IntRect
25 #include "nsTArray.h" // for AutoTArray, nsTArray_Impl
26 #include "mozilla/Poison.h"
27 #include "mozilla/layers/ImageHost.h"
28 #include "mozilla/layers/LayerManagerComposite.h"
29 #include "TreeTraversal.h" // for ForEachNode
30 #include "LayersLogging.h"
32 // LayerTreeInvalidation debugging
36 # define LTI_DEEPER(aPrefix) nsPrintfCString("%s ", aPrefix).get()
37 # define LTI_DUMP(rgn, label) \
38 if (!(rgn).IsEmpty()) \
39 printf_stderr("%s%p: " label " portion is %s\n", aPrefix, mLayer.get(), \
40 Stringify(rgn).c_str());
41 # define LTI_LOG(...) printf_stderr(__VA_ARGS__)
43 # define LTI_DEEPER(aPrefix) nullptr
44 # define LTI_DUMP(rgn, label)
48 using namespace mozilla::gfx
;
53 struct LayerPropertiesBase
;
54 UniquePtr
<LayerPropertiesBase
> CloneLayerTreePropertiesInternal(
55 Layer
* aRoot
, bool aIsMask
= false);
58 * Get accumulated transform of from the context creating layer to the
61 static Matrix4x4
GetTransformIn3DContext(Layer
* aLayer
) {
62 Matrix4x4 transform
= aLayer
->GetLocalTransform();
63 for (Layer
* layer
= aLayer
->GetParent(); layer
&& layer
->Extend3DContext();
64 layer
= layer
->GetParent()) {
65 transform
= transform
* layer
->GetLocalTransform();
71 * Get a transform for the given layer depending on extending 3D
74 * @return local transform for layers not participating 3D rendering
75 * context, or the accmulated transform in the context for else.
77 static Matrix4x4Flagged
GetTransformForInvalidation(Layer
* aLayer
) {
78 return (!aLayer
->Is3DContextLeaf() && !aLayer
->Extend3DContext()
79 ? aLayer
->GetLocalTransform()
80 : GetTransformIn3DContext(aLayer
));
83 static IntRect
TransformRect(const IntRect
& aRect
,
84 const Matrix4x4Flagged
& aTransform
) {
85 if (aRect
.IsEmpty()) {
89 Rect
rect(aRect
.X(), aRect
.Y(), aRect
.Width(), aRect
.Height());
90 rect
= aTransform
.TransformAndClipBounds(rect
, Rect::MaxIntRect());
94 if (!rect
.ToIntRect(&intRect
)) {
95 intRect
= IntRect::MaxIntRect();
101 static void AddTransformedRegion(nsIntRegion
& aDest
, const nsIntRegion
& aSource
,
102 const Matrix4x4Flagged
& aTransform
) {
103 for (auto iter
= aSource
.RectIter(); !iter
.Done(); iter
.Next()) {
104 aDest
.Or(aDest
, TransformRect(iter
.Get(), aTransform
));
106 aDest
.SimplifyOutward(20);
109 static void AddRegion(nsIntRegion
& aDest
, const nsIntRegion
& aSource
) {
110 aDest
.Or(aDest
, aSource
);
111 aDest
.SimplifyOutward(20);
114 Maybe
<IntRect
> TransformedBounds(Layer
* aLayer
) {
115 if (aLayer
->Extend3DContext()) {
116 ContainerLayer
* container
= aLayer
->AsContainerLayer();
117 MOZ_ASSERT(container
);
119 for (Layer
* child
= container
->GetFirstChild(); child
;
120 child
= child
->GetNextSibling()) {
121 Maybe
<IntRect
> childBounds
= TransformedBounds(child
);
125 Maybe
<IntRect
> combined
= result
.SafeUnion(childBounds
.value());
127 LTI_LOG("overflowed bounds of container %p accumulating child %p\n",
131 result
= combined
.value();
137 TransformRect(aLayer
->GetLocalVisibleRegion().GetBounds().ToUnknownRect(),
138 GetTransformForInvalidation(aLayer
)));
142 * Walks over this layer, and all descendant layers.
143 * If any of these are a ContainerLayer that reports invalidations to a
144 * PresShell, then report that the entire bounds have changed.
146 static void NotifySubdocumentInvalidation(
147 Layer
* aLayer
, NotifySubDocInvalidationFunc aCallback
) {
148 ForEachNode
<ForwardIterator
>(
150 [aCallback
](Layer
* layer
) {
151 layer
->ClearInvalidRegion();
152 if (layer
->GetMaskLayer()) {
153 NotifySubdocumentInvalidation(layer
->GetMaskLayer(), aCallback
);
155 for (size_t i
= 0; i
< layer
->GetAncestorMaskLayerCount(); i
++) {
156 Layer
* maskLayer
= layer
->GetAncestorMaskLayerAt(i
);
157 NotifySubdocumentInvalidation(maskLayer
, aCallback
);
160 [aCallback
](Layer
* layer
) {
161 ContainerLayer
* container
= layer
->AsContainerLayer();
162 if (container
&& !container
->Extend3DContext()) {
164 container
->GetLocalVisibleRegion().ToUnknownRegion();
165 aCallback(container
, ®ion
);
170 static void SetChildrenChangedRecursive(Layer
* aLayer
) {
171 ForEachNode
<ForwardIterator
>(aLayer
, [](Layer
* layer
) {
172 ContainerLayer
* container
= layer
->AsContainerLayer();
174 container
->SetChildrenChanged(true);
175 container
->SetInvalidCompositeRect(nullptr);
180 struct LayerPropertiesBase
: public LayerProperties
{
181 explicit LayerPropertiesBase(Layer
* aLayer
)
184 mVisibleRegion(mLayer
->Extend3DContext()
186 : mLayer
->GetLocalVisibleRegion().ToUnknownRegion()),
187 mPostXScale(aLayer
->GetPostXScale()),
188 mPostYScale(aLayer
->GetPostYScale()),
189 mOpacity(aLayer
->GetLocalOpacity()),
190 mUseClipRect(!!aLayer
->GetLocalClipRect()) {
191 MOZ_COUNT_CTOR(LayerPropertiesBase
);
192 if (aLayer
->GetMaskLayer()) {
194 CloneLayerTreePropertiesInternal(aLayer
->GetMaskLayer(), true);
196 for (size_t i
= 0; i
< aLayer
->GetAncestorMaskLayerCount(); i
++) {
197 Layer
* maskLayer
= aLayer
->GetAncestorMaskLayerAt(i
);
198 mAncestorMaskLayers
.AppendElement(
199 CloneLayerTreePropertiesInternal(maskLayer
, true));
202 mClipRect
= *aLayer
->GetLocalClipRect();
204 mTransform
= GetTransformForInvalidation(aLayer
);
206 LayerPropertiesBase()
212 mUseClipRect(false) {
213 MOZ_COUNT_CTOR(LayerPropertiesBase
);
215 MOZ_COUNTED_DTOR_OVERRIDE(LayerPropertiesBase
)
218 LayerPropertiesBase(const LayerPropertiesBase
& a
) = delete;
219 LayerPropertiesBase
& operator=(const LayerPropertiesBase
& a
) = delete;
222 bool ComputeDifferences(Layer
* aRoot
, nsIntRegion
& aOutRegion
,
223 NotifySubDocInvalidationFunc aCallback
) override
;
225 void MoveBy(const IntPoint
& aOffset
) override
;
227 bool ComputeChange(const char* aPrefix
, nsIntRegion
& aOutRegion
,
228 NotifySubDocInvalidationFunc aCallback
) {
229 // Bug 1251615: This canary is sometimes hit. We're still not sure why.
231 bool transformChanged
=
232 !mTransform
.FuzzyEqual(GetTransformForInvalidation(mLayer
)) ||
233 mLayer
->GetPostXScale() != mPostXScale
||
234 mLayer
->GetPostYScale() != mPostYScale
;
235 const Maybe
<ParentLayerIntRect
>& otherClip
= mLayer
->GetLocalClipRect();
238 bool ancestorMaskChanged
=
239 mAncestorMaskLayers
.Length() != mLayer
->GetAncestorMaskLayerCount();
240 if (!ancestorMaskChanged
) {
241 for (size_t i
= 0; i
< mAncestorMaskLayers
.Length(); i
++) {
242 if (mLayer
->GetAncestorMaskLayerAt(i
) !=
243 mAncestorMaskLayers
[i
]->mLayer
) {
244 ancestorMaskChanged
= true;
250 // Note that we don't bailout early in general since this function
251 // clears some persistent state at the end. Instead we set an overflow
252 // flag and check it right before returning.
253 bool areaOverflowed
= false;
255 Layer
* otherMask
= mLayer
->GetMaskLayer();
256 if ((mMaskLayer
? mMaskLayer
->mLayer
: nullptr) != otherMask
||
257 ancestorMaskChanged
|| (mUseClipRect
!= !!otherClip
) ||
258 mLayer
->GetLocalOpacity() != mOpacity
|| transformChanged
) {
259 Maybe
<IntRect
> oldBounds
= OldTransformedBounds();
260 Maybe
<IntRect
> newBounds
= NewTransformedBounds();
261 if (oldBounds
&& newBounds
) {
262 LTI_DUMP(oldBounds
.value(), "oldtransform");
263 LTI_DUMP(newBounds
.value(), "newtransform");
264 result
= oldBounds
.value();
265 AddRegion(result
, newBounds
.value());
267 areaOverflowed
= true;
270 // We can't bail out early because we might need to update some internal
274 nsIntRegion internal
;
275 if (!ComputeChangeInternal(aPrefix
, internal
, aCallback
)) {
276 areaOverflowed
= true;
279 LTI_DUMP(internal
, "internal");
280 AddRegion(result
, internal
);
281 LTI_DUMP(mLayer
->GetInvalidRegion().GetRegion(), "invalid");
282 AddTransformedRegion(result
, mLayer
->GetInvalidRegion().GetRegion(),
285 if (mMaskLayer
&& otherMask
) {
287 if (!mMaskLayer
->ComputeChange(aPrefix
, mask
, aCallback
)) {
288 areaOverflowed
= true;
290 LTI_DUMP(mask
, "mask");
291 AddRegion(result
, mask
);
294 for (size_t i
= 0; i
< std::min(mAncestorMaskLayers
.Length(),
295 mLayer
->GetAncestorMaskLayerCount());
298 if (!mAncestorMaskLayers
[i
]->ComputeChange(aPrefix
, mask
, aCallback
)) {
299 areaOverflowed
= true;
301 LTI_DUMP(mask
, "ancestormask");
302 AddRegion(result
, mask
);
305 if (mUseClipRect
&& otherClip
) {
306 if (!mClipRect
.IsEqualInterior(*otherClip
)) {
308 tmp
.Xor(mClipRect
.ToUnknownRect(), otherClip
->ToUnknownRect());
309 LTI_DUMP(tmp
, "clip");
310 AddRegion(result
, tmp
);
314 mLayer
->ClearInvalidRegion();
316 if (areaOverflowed
) {
320 aOutRegion
= std::move(result
);
326 mLayer
->CheckCanary();
329 IntRect
NewTransformedBoundsForLeaf() {
330 return TransformRect(
331 mLayer
->GetLocalVisibleRegion().GetBounds().ToUnknownRect(),
332 GetTransformForInvalidation(mLayer
));
335 IntRect
OldTransformedBoundsForLeaf() {
336 return TransformRect(mVisibleRegion
.GetBounds().ToUnknownRect(),
340 Maybe
<IntRect
> NewTransformedBounds() { return TransformedBounds(mLayer
); }
342 virtual Maybe
<IntRect
> OldTransformedBounds() {
344 TransformRect(mVisibleRegion
.GetBounds().ToUnknownRect(), mTransform
));
347 virtual bool ComputeChangeInternal(const char* aPrefix
,
348 nsIntRegion
& aOutRegion
,
349 NotifySubDocInvalidationFunc aCallback
) {
350 if (mLayer
->AsHostLayer() &&
351 !mLayer
->GetLocalVisibleRegion().ToUnknownRegion().IsEqual(
353 IntRect result
= NewTransformedBoundsForLeaf();
354 result
= result
.Union(OldTransformedBoundsForLeaf());
360 RefPtr
<Layer
> mLayer
;
361 UniquePtr
<LayerPropertiesBase
> mMaskLayer
;
362 nsTArray
<UniquePtr
<LayerPropertiesBase
>> mAncestorMaskLayers
;
363 nsIntRegion mVisibleRegion
;
364 Matrix4x4Flagged mTransform
;
368 ParentLayerIntRect mClipRect
;
370 mozilla::CorruptionCanary mCanary
;
373 struct ContainerLayerProperties
: public LayerPropertiesBase
{
374 explicit ContainerLayerProperties(ContainerLayer
* aLayer
)
375 : LayerPropertiesBase(aLayer
),
376 mPreXScale(aLayer
->GetPreXScale()),
377 mPreYScale(aLayer
->GetPreYScale()) {
378 for (Layer
* child
= aLayer
->GetFirstChild(); child
;
379 child
= child
->GetNextSibling()) {
380 child
->CheckCanary();
381 mChildren
.AppendElement(CloneLayerTreePropertiesInternal(child
));
386 ContainerLayerProperties(const ContainerLayerProperties
& a
) = delete;
387 ContainerLayerProperties
& operator=(const ContainerLayerProperties
& a
) =
391 bool ComputeChangeInternal(const char* aPrefix
, nsIntRegion
& aOutRegion
,
392 NotifySubDocInvalidationFunc aCallback
) override
{
393 // Make sure we got our virtual call right
394 mSubtypeCanary
.Check();
395 ContainerLayer
* container
= mLayer
->AsContainerLayer();
396 nsIntRegion invalidOfLayer
; // Invalid regions of this layer.
397 nsIntRegion result
; // Invliad regions for children only.
399 container
->CheckCanary();
401 bool childrenChanged
= false;
402 bool invalidateWholeLayer
= false;
403 bool areaOverflowed
= false;
404 if (mPreXScale
!= container
->GetPreXScale() ||
405 mPreYScale
!= container
->GetPreYScale()) {
406 Maybe
<IntRect
> oldBounds
= OldTransformedBounds();
407 Maybe
<IntRect
> newBounds
= NewTransformedBounds();
408 if (oldBounds
&& newBounds
) {
409 invalidOfLayer
= oldBounds
.value();
410 AddRegion(invalidOfLayer
, newBounds
.value());
412 areaOverflowed
= true;
414 childrenChanged
= true;
415 invalidateWholeLayer
= true;
417 // Can't bail out early, we need to update the child container layers
420 // A low frame rate is especially visible to users when scrolling, so we
421 // particularly want to avoid unnecessary invalidation at that time. For us
422 // here, that means avoiding unnecessary invalidation of child items when
423 // other children are added to or removed from our container layer, since
424 // that may be caused by children being scrolled in or out of view. We are
425 // less concerned with children changing order.
426 // TODO: Consider how we could avoid unnecessary invalidation when children
427 // change order, and whether the overhead would be worth it.
429 nsDataHashtable
<nsPtrHashKey
<Layer
>, uint32_t> oldIndexMap(
431 for (uint32_t i
= 0; i
< mChildren
.Length(); ++i
) {
432 mChildren
[i
]->CheckCanary();
433 oldIndexMap
.Put(mChildren
[i
]->mLayer
, i
);
436 uint32_t i
= 0; // cursor into the old child list mChildren
437 for (Layer
* child
= container
->GetFirstChild(); child
;
438 child
= child
->GetNextSibling()) {
439 bool invalidateChildsCurrentArea
= false;
440 if (i
< mChildren
.Length()) {
441 uint32_t childsOldIndex
;
442 if (oldIndexMap
.Get(child
, &childsOldIndex
)) {
443 if (childsOldIndex
>= i
) {
444 // Invalidate the old areas of layers that used to be between the
445 // current |child| and the previous |child| that was also in the
446 // old list mChildren (if any of those children have been reordered
447 // rather than removed, we will invalidate their new area when we
448 // encounter them in the new list):
449 for (uint32_t j
= i
; j
< childsOldIndex
; ++j
) {
450 if (Maybe
<IntRect
> bounds
=
451 mChildren
[j
]->OldTransformedBounds()) {
452 LTI_DUMP(bounds
.value(), "reordered child");
453 AddRegion(result
, bounds
.value());
455 areaOverflowed
= true;
457 childrenChanged
|= true;
459 if (childsOldIndex
>= mChildren
.Length()) {
460 MOZ_CRASH("Out of bounds");
462 // Invalidate any regions of the child that have changed:
464 if (!mChildren
[childsOldIndex
]->ComputeChange(LTI_DEEPER(aPrefix
),
465 region
, aCallback
)) {
466 areaOverflowed
= true;
468 i
= childsOldIndex
+ 1;
469 if (!region
.IsEmpty()) {
470 LTI_LOG("%s%p: child %p produced %s\n", aPrefix
, mLayer
.get(),
471 mChildren
[childsOldIndex
]->mLayer
.get(),
472 Stringify(region
).c_str());
473 AddRegion(result
, region
);
474 childrenChanged
|= true;
477 // We've already seen this child in mChildren (which means it must
478 // have been reordered) and invalidated its old area. We need to
479 // invalidate its new area too:
480 invalidateChildsCurrentArea
= true;
484 invalidateChildsCurrentArea
= true;
485 SetChildrenChangedRecursive(child
);
488 // |child| is new, or was reordered to a higher index
489 invalidateChildsCurrentArea
= true;
490 if (!oldIndexMap
.Contains(child
)) {
491 SetChildrenChangedRecursive(child
);
494 if (invalidateChildsCurrentArea
) {
495 LTI_DUMP(child
->GetLocalVisibleRegion().ToUnknownRegion(),
496 "invalidateChildsCurrentArea");
497 if (Maybe
<IntRect
> bounds
= TransformedBounds(child
)) {
498 AddRegion(result
, bounds
.value());
500 areaOverflowed
= true;
503 NotifySubdocumentInvalidation(child
, aCallback
);
505 ClearInvalidations(child
);
508 childrenChanged
|= invalidateChildsCurrentArea
;
511 // Process remaining removed children.
512 while (i
< mChildren
.Length()) {
513 childrenChanged
|= true;
514 if (Maybe
<IntRect
> bounds
= mChildren
[i
]->OldTransformedBounds()) {
515 LTI_DUMP(bounds
.value(), "removed child");
516 AddRegion(result
, bounds
.value());
518 areaOverflowed
= true;
524 aCallback(container
, areaOverflowed
? nullptr : &result
);
527 if (childrenChanged
|| areaOverflowed
) {
528 container
->SetChildrenChanged(true);
531 if (container
->UseIntermediateSurface()) {
532 Maybe
<IntRect
> bounds
;
533 if (!invalidateWholeLayer
&& !areaOverflowed
) {
534 bounds
= Some(result
.GetBounds());
536 // Process changes in the visible region.
537 IntRegion newVisible
=
538 mLayer
->GetLocalVisibleRegion().ToUnknownRegion();
539 if (!newVisible
.IsEqual(mVisibleRegion
)) {
540 newVisible
.XorWith(mVisibleRegion
);
541 bounds
= bounds
->SafeUnion(newVisible
.GetBounds());
544 container
->SetInvalidCompositeRect(bounds
? bounds
.ptr() : nullptr);
547 // Safe to bail out early now, persistent state has been set.
548 if (areaOverflowed
) {
552 if (!mLayer
->Extend3DContext()) {
553 // |result| contains invalid regions only of children.
554 result
.Transform(GetTransformForInvalidation(mLayer
).GetMatrix());
556 // else, effective transforms have applied on children.
558 LTI_DUMP(invalidOfLayer
, "invalidOfLayer");
559 result
.OrWith(invalidOfLayer
);
561 aOutRegion
= std::move(result
);
565 Maybe
<IntRect
> OldTransformedBounds() override
{
566 if (mLayer
->Extend3DContext()) {
568 for (UniquePtr
<LayerPropertiesBase
>& child
: mChildren
) {
569 Maybe
<IntRect
> childBounds
= child
->OldTransformedBounds();
573 Maybe
<IntRect
> combined
= result
.SafeUnion(childBounds
.value());
575 LTI_LOG("overflowed bounds of container %p accumulating child %p\n",
576 this, child
->mLayer
.get());
579 result
= combined
.value();
583 return LayerPropertiesBase::OldTransformedBounds();
586 // The old list of children:
587 mozilla::CorruptionCanary mSubtypeCanary
;
588 nsTArray
<UniquePtr
<LayerPropertiesBase
>> mChildren
;
593 struct ColorLayerProperties
: public LayerPropertiesBase
{
594 explicit ColorLayerProperties(ColorLayer
* aLayer
)
595 : LayerPropertiesBase(aLayer
),
596 mColor(aLayer
->GetColor()),
597 mBounds(aLayer
->GetBounds()) {}
600 ColorLayerProperties(const ColorLayerProperties
& a
) = delete;
601 ColorLayerProperties
& operator=(const ColorLayerProperties
& a
) = delete;
604 bool ComputeChangeInternal(const char* aPrefix
, nsIntRegion
& aOutRegion
,
605 NotifySubDocInvalidationFunc aCallback
) override
{
606 ColorLayer
* color
= static_cast<ColorLayer
*>(mLayer
.get());
608 if (mColor
!= color
->GetColor()) {
609 LTI_DUMP(NewTransformedBoundsForLeaf(), "color");
610 aOutRegion
= NewTransformedBoundsForLeaf();
614 nsIntRegion boundsDiff
;
615 boundsDiff
.Xor(mBounds
, color
->GetBounds());
616 LTI_DUMP(boundsDiff
, "colorbounds");
618 AddTransformedRegion(aOutRegion
, boundsDiff
, mTransform
);
626 static ImageHost
* GetImageHost(Layer
* aLayer
) {
627 HostLayer
* compositor
= aLayer
->AsHostLayer();
629 return static_cast<ImageHost
*>(compositor
->GetCompositableHost());
634 struct ImageLayerProperties
: public LayerPropertiesBase
{
635 explicit ImageLayerProperties(ImageLayer
* aImage
, bool aIsMask
)
636 : LayerPropertiesBase(aImage
),
637 mContainer(aImage
->GetContainer()),
638 mImageHost(GetImageHost(aImage
)),
639 mSamplingFilter(aImage
->GetSamplingFilter()),
640 mScaleToSize(aImage
->GetScaleToSize()),
641 mScaleMode(aImage
->GetScaleMode()),
647 // Mask layers never set the 'last' producer/frame
648 // id, since they never get composited as their own
650 mLastProducerID
= mImageHost
->GetProducerID();
651 mLastFrameID
= mImageHost
->GetFrameID();
653 mLastProducerID
= mImageHost
->GetLastProducerID();
654 mLastFrameID
= mImageHost
->GetLastFrameID();
659 bool ComputeChangeInternal(const char* aPrefix
, nsIntRegion
& aOutRegion
,
660 NotifySubDocInvalidationFunc aCallback
) override
{
661 ImageLayer
* imageLayer
= static_cast<ImageLayer
*>(mLayer
.get());
663 if (!imageLayer
->GetLocalVisibleRegion().ToUnknownRegion().IsEqual(
665 IntRect result
= NewTransformedBoundsForLeaf();
666 result
= result
.Union(OldTransformedBoundsForLeaf());
671 ImageContainer
* container
= imageLayer
->GetContainer();
672 ImageHost
* host
= GetImageHost(imageLayer
);
673 if (mContainer
!= container
||
674 mSamplingFilter
!= imageLayer
->GetSamplingFilter() ||
675 mScaleToSize
!= imageLayer
->GetScaleToSize() ||
676 mScaleMode
!= imageLayer
->GetScaleMode() || host
!= mImageHost
||
677 (host
&& host
->GetProducerID() != mLastProducerID
) ||
678 (host
&& host
->GetFrameID() != mLastFrameID
)) {
680 // Mask layers have an empty visible region, so we have to
681 // use the image size instead.
684 size
= container
->GetCurrentSize();
687 size
= host
->GetImageSize();
689 IntRect
rect(0, 0, size
.width
, size
.height
);
690 LTI_DUMP(rect
, "mask");
691 aOutRegion
= TransformRect(rect
, GetTransformForInvalidation(mLayer
));
694 LTI_DUMP(NewTransformedBoundsForLeaf(), "bounds");
695 aOutRegion
= NewTransformedBoundsForLeaf();
702 RefPtr
<ImageContainer
> mContainer
;
703 RefPtr
<ImageHost
> mImageHost
;
704 SamplingFilter mSamplingFilter
;
705 gfx::IntSize mScaleToSize
;
706 ScaleMode mScaleMode
;
707 int32_t mLastProducerID
;
708 int32_t mLastFrameID
;
712 struct CanvasLayerProperties
: public LayerPropertiesBase
{
713 explicit CanvasLayerProperties(CanvasLayer
* aCanvas
)
714 : LayerPropertiesBase(aCanvas
), mImageHost(GetImageHost(aCanvas
)) {
715 mFrameID
= mImageHost
? mImageHost
->GetFrameID() : -1;
718 bool ComputeChangeInternal(const char* aPrefix
, nsIntRegion
& aOutRegion
,
719 NotifySubDocInvalidationFunc aCallback
) override
{
720 CanvasLayer
* canvasLayer
= static_cast<CanvasLayer
*>(mLayer
.get());
722 ImageHost
* host
= GetImageHost(canvasLayer
);
723 if (host
&& host
->GetFrameID() != mFrameID
) {
724 LTI_DUMP(NewTransformedBoundsForLeaf(), "frameId");
725 aOutRegion
= NewTransformedBoundsForLeaf();
732 RefPtr
<ImageHost
> mImageHost
;
736 UniquePtr
<LayerPropertiesBase
> CloneLayerTreePropertiesInternal(
737 Layer
* aRoot
, bool aIsMask
/* = false */) {
739 return MakeUnique
<LayerPropertiesBase
>();
742 MOZ_ASSERT(!aIsMask
|| aRoot
->GetType() == Layer::TYPE_IMAGE
);
744 aRoot
->CheckCanary();
746 switch (aRoot
->GetType()) {
747 case Layer::TYPE_CONTAINER
:
748 case Layer::TYPE_REF
:
749 return MakeUnique
<ContainerLayerProperties
>(aRoot
->AsContainerLayer());
750 case Layer::TYPE_COLOR
:
751 return MakeUnique
<ColorLayerProperties
>(static_cast<ColorLayer
*>(aRoot
));
752 case Layer::TYPE_IMAGE
:
753 return MakeUnique
<ImageLayerProperties
>(static_cast<ImageLayer
*>(aRoot
),
755 case Layer::TYPE_CANVAS
:
756 return MakeUnique
<CanvasLayerProperties
>(
757 static_cast<CanvasLayer
*>(aRoot
));
758 case Layer::TYPE_DISPLAYITEM
:
759 case Layer::TYPE_READBACK
:
760 case Layer::TYPE_SHADOW
:
761 case Layer::TYPE_PAINTED
:
762 return MakeUnique
<LayerPropertiesBase
>(aRoot
);
765 MOZ_ASSERT_UNREACHABLE("Unexpected root layer type");
766 return MakeUnique
<LayerPropertiesBase
>(aRoot
);
770 UniquePtr
<LayerProperties
> LayerProperties::CloneFrom(Layer
* aRoot
) {
771 return CloneLayerTreePropertiesInternal(aRoot
);
775 void LayerProperties::ClearInvalidations(Layer
* aLayer
) {
776 ForEachNode
<ForwardIterator
>(aLayer
, [](Layer
* layer
) {
777 layer
->ClearInvalidRegion();
778 if (layer
->GetMaskLayer()) {
779 ClearInvalidations(layer
->GetMaskLayer());
781 for (size_t i
= 0; i
< layer
->GetAncestorMaskLayerCount(); i
++) {
782 ClearInvalidations(layer
->GetAncestorMaskLayerAt(i
));
787 bool LayerPropertiesBase::ComputeDifferences(
788 Layer
* aRoot
, nsIntRegion
& aOutRegion
,
789 NotifySubDocInvalidationFunc aCallback
) {
790 NS_ASSERTION(aRoot
, "Must have a layer tree to compare against!");
791 if (mLayer
!= aRoot
) {
793 NotifySubdocumentInvalidation(aRoot
, aCallback
);
795 ClearInvalidations(aRoot
);
797 IntRect bounds
= TransformRect(
798 aRoot
->GetLocalVisibleRegion().GetBounds().ToUnknownRect(),
799 aRoot
->GetLocalTransform());
800 Maybe
<IntRect
> oldBounds
= OldTransformedBounds();
804 Maybe
<IntRect
> result
= bounds
.SafeUnion(oldBounds
.value());
806 LTI_LOG("overflowed bounds computing the union of layers %p and %p\n",
807 mLayer
.get(), aRoot
);
810 aOutRegion
= result
.value();
813 return ComputeChange(" ", aOutRegion
, aCallback
);
816 void LayerPropertiesBase::MoveBy(const IntPoint
& aOffset
) {
817 mTransform
.PostTranslate(aOffset
.x
, aOffset
.y
, 0);
820 } // namespace layers
821 } // namespace mozilla