Line data Source code
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 file,
4 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "LayerTreeInvalidation.h"
7 :
8 : #include <stdint.h> // for uint32_t
9 : #include "ImageContainer.h" // for ImageContainer
10 : #include "ImageLayers.h" // for ImageLayer, etc
11 : #include "Layers.h" // for Layer, ContainerLayer, etc
12 : #include "Units.h" // for ParentLayerIntRect
13 : #include "gfxRect.h" // for gfxRect
14 : #include "gfxUtils.h" // for gfxUtils
15 : #include "mozilla/gfx/BaseSize.h" // for BaseSize
16 : #include "mozilla/gfx/Point.h" // for IntSize
17 : #include "mozilla/mozalloc.h" // for operator new, etc
18 : #include "nsDataHashtable.h" // for nsDataHashtable
19 : #include "nsDebug.h" // for NS_ASSERTION
20 : #include "nsHashKeys.h" // for nsPtrHashKey
21 : #include "nsISupportsImpl.h" // for Layer::AddRef, etc
22 : #include "nsRect.h" // for IntRect
23 : #include "nsTArray.h" // for AutoTArray, nsTArray_Impl
24 : #include "mozilla/Poison.h"
25 : #include "mozilla/layers/ImageHost.h"
26 : #include "mozilla/layers/LayerManagerComposite.h"
27 : #include "TreeTraversal.h" // for ForEachNode
28 : #include "LayersLogging.h"
29 :
30 : // LayerTreeInvalidation debugging
31 : #define LTI_DEBUG 0
32 :
33 : #if LTI_DEBUG
34 : # define LTI_DEEPER(aPrefix) nsPrintfCString("%s ", aPrefix).get()
35 : # define LTI_DUMP(rgn, label) if (!(rgn).IsEmpty()) printf_stderr("%s%p: " label " portion is %s\n", aPrefix, mLayer.get(), Stringify(rgn).c_str());
36 : # define LTI_LOG(...) printf_stderr(__VA_ARGS__)
37 : #else
38 : # define LTI_DEEPER(aPrefix) nullptr
39 : # define LTI_DUMP(rgn, label)
40 : # define LTI_LOG(...)
41 : #endif
42 :
43 : using namespace mozilla::gfx;
44 :
45 : namespace mozilla {
46 : namespace layers {
47 :
48 : struct LayerPropertiesBase;
49 : UniquePtr<LayerPropertiesBase> CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask = false);
50 :
51 : /**
52 : * Get accumulated transform of from the context creating layer to the
53 : * given layer.
54 : */
55 : static Matrix4x4
56 0 : GetTransformIn3DContext(Layer* aLayer) {
57 0 : Matrix4x4 transform = aLayer->GetLocalTransform();
58 0 : for (Layer* layer = aLayer->GetParent();
59 0 : layer && layer->Extend3DContext();
60 : layer = layer->GetParent()) {
61 0 : transform = transform * layer->GetLocalTransform();
62 : }
63 0 : return transform;
64 : }
65 :
66 : /**
67 : * Get a transform for the given layer depending on extending 3D
68 : * context.
69 : *
70 : * @return local transform for layers not participating 3D rendering
71 : * context, or the accmulated transform in the context for else.
72 : */
73 : static Matrix4x4
74 1557 : GetTransformForInvalidation(Layer* aLayer) {
75 1557 : return (!aLayer->Is3DContextLeaf() && !aLayer->Extend3DContext() ?
76 1557 : aLayer->GetLocalTransform() : GetTransformIn3DContext(aLayer));
77 : }
78 :
79 : static IntRect
80 292 : TransformRect(const IntRect& aRect, const Matrix4x4& aTransform)
81 : {
82 292 : if (aRect.IsEmpty()) {
83 119 : return IntRect();
84 : }
85 :
86 173 : Rect rect(aRect.x, aRect.y, aRect.width, aRect.height);
87 173 : rect = aTransform.TransformAndClipBounds(rect, Rect::MaxIntRect());
88 173 : rect.RoundOut();
89 :
90 173 : IntRect intRect;
91 173 : if (!gfxUtils::GfxRectToIntRect(ThebesRect(rect), &intRect)) {
92 0 : return IntRect();
93 : }
94 :
95 173 : return intRect;
96 : }
97 :
98 : static void
99 649 : AddTransformedRegion(nsIntRegion& aDest, const nsIntRegion& aSource, const Matrix4x4& aTransform)
100 : {
101 788 : for (auto iter = aSource.RectIter(); !iter.Done(); iter.Next()) {
102 139 : aDest.Or(aDest, TransformRect(iter.Get(), aTransform));
103 : }
104 649 : aDest.SimplifyOutward(20);
105 649 : }
106 :
107 : static void
108 733 : AddRegion(nsIntRegion& aDest, const nsIntRegion& aSource)
109 : {
110 733 : aDest.Or(aDest, aSource);
111 733 : aDest.SimplifyOutward(20);
112 733 : }
113 :
114 : /**
115 : * Walks over this layer, and all descendant layers.
116 : * If any of these are a ContainerLayer that reports invalidations to a PresShell,
117 : * then report that the entire bounds have changed.
118 : */
119 : static void
120 21 : NotifySubdocumentInvalidation(Layer* aLayer, NotifySubDocInvalidationFunc aCallback)
121 : {
122 42 : ForEachNode<ForwardIterator>(
123 : aLayer,
124 29 : [aCallback] (Layer* layer)
125 0 : {
126 29 : layer->ClearInvalidRegion();
127 29 : if (layer->GetMaskLayer()) {
128 0 : NotifySubdocumentInvalidation(layer->GetMaskLayer(), aCallback);
129 : }
130 29 : for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) {
131 0 : Layer* maskLayer = layer->GetAncestorMaskLayerAt(i);
132 0 : NotifySubdocumentInvalidation(maskLayer, aCallback);
133 : }
134 29 : },
135 29 : [aCallback] (Layer* layer)
136 5 : {
137 29 : ContainerLayer* container = layer->AsContainerLayer();
138 29 : if (container) {
139 5 : aCallback(container, container->GetLocalVisibleRegion().ToUnknownRegion());
140 : }
141 50 : });
142 21 : }
143 :
144 : struct LayerPropertiesBase : public LayerProperties
145 : {
146 633 : explicit LayerPropertiesBase(Layer* aLayer)
147 633 : : mLayer(aLayer)
148 : , mMaskLayer(nullptr)
149 633 : , mVisibleRegion(mLayer->GetLocalVisibleRegion().ToUnknownRegion())
150 633 : , mPostXScale(aLayer->GetPostXScale())
151 633 : , mPostYScale(aLayer->GetPostYScale())
152 633 : , mOpacity(aLayer->GetLocalOpacity())
153 3165 : , mUseClipRect(!!aLayer->GetLocalClipRect())
154 : {
155 633 : MOZ_COUNT_CTOR(LayerPropertiesBase);
156 633 : if (aLayer->GetMaskLayer()) {
157 0 : mMaskLayer = CloneLayerTreePropertiesInternal(aLayer->GetMaskLayer(), true);
158 : }
159 633 : for (size_t i = 0; i < aLayer->GetAncestorMaskLayerCount(); i++) {
160 0 : Layer* maskLayer = aLayer->GetAncestorMaskLayerAt(i);
161 0 : mAncestorMaskLayers.AppendElement(CloneLayerTreePropertiesInternal(maskLayer, true));
162 : }
163 633 : if (mUseClipRect) {
164 108 : mClipRect = *aLayer->GetLocalClipRect();
165 : }
166 633 : mTransform = GetTransformForInvalidation(aLayer);
167 633 : }
168 13 : LayerPropertiesBase()
169 13 : : mLayer(nullptr)
170 13 : , mMaskLayer(nullptr)
171 : {
172 13 : MOZ_COUNT_CTOR(LayerPropertiesBase);
173 13 : }
174 943 : ~LayerPropertiesBase() override
175 1278 : {
176 639 : MOZ_COUNT_DTOR(LayerPropertiesBase);
177 1247 : }
178 :
179 : protected:
180 : LayerPropertiesBase(const LayerPropertiesBase& a) = delete;
181 : LayerPropertiesBase& operator=(const LayerPropertiesBase& a) = delete;
182 :
183 : public:
184 : nsIntRegion ComputeDifferences(Layer* aRoot,
185 : NotifySubDocInvalidationFunc aCallback) override;
186 :
187 : void MoveBy(const IntPoint& aOffset) override;
188 :
189 510 : nsIntRegion ComputeChange(const char* aPrefix,
190 : NotifySubDocInvalidationFunc aCallback)
191 : {
192 : // Bug 1251615: This canary is sometimes hit. We're still not sure why.
193 510 : mCanary.Check();
194 2544 : bool transformChanged = !mTransform.FuzzyEqual(GetTransformForInvalidation(mLayer)) ||
195 2034 : mLayer->GetPostXScale() != mPostXScale ||
196 1014 : mLayer->GetPostYScale() != mPostYScale;
197 510 : const Maybe<ParentLayerIntRect>& otherClip = mLayer->GetLocalClipRect();
198 510 : nsIntRegion result;
199 :
200 510 : bool ancestorMaskChanged = mAncestorMaskLayers.Length() != mLayer->GetAncestorMaskLayerCount();
201 510 : if (!ancestorMaskChanged) {
202 510 : for (size_t i = 0; i < mAncestorMaskLayers.Length(); i++) {
203 0 : if (mLayer->GetAncestorMaskLayerAt(i) != mAncestorMaskLayers[i]->mLayer) {
204 0 : ancestorMaskChanged = true;
205 0 : break;
206 : }
207 : }
208 : }
209 :
210 510 : Layer* otherMask = mLayer->GetMaskLayer();
211 2040 : if ((mMaskLayer ? mMaskLayer->mLayer : nullptr) != otherMask ||
212 510 : ancestorMaskChanged ||
213 1019 : (mUseClipRect != !!otherClip) ||
214 2548 : mLayer->GetLocalOpacity() != mOpacity ||
215 : transformChanged)
216 : {
217 7 : result = OldTransformedBounds();
218 : LTI_DUMP(result, "oldtransform");
219 : LTI_DUMP(NewTransformedBounds(), "newtransform");
220 7 : AddRegion(result, NewTransformedBounds());
221 :
222 : // We can't bail out early because we need to update mChildrenChanged.
223 : }
224 :
225 1020 : nsIntRegion internal = ComputeChangeInternal(aPrefix, aCallback);
226 : LTI_DUMP(internal, "internal");
227 510 : AddRegion(result, internal);
228 : LTI_DUMP(mLayer->GetInvalidRegion().GetRegion(), "invalid");
229 510 : AddTransformedRegion(result, mLayer->GetInvalidRegion().GetRegion(), mTransform);
230 :
231 510 : if (mMaskLayer && otherMask) {
232 0 : nsIntRegion mask = mMaskLayer->ComputeChange(aPrefix, aCallback);
233 : LTI_DUMP(mask, "mask");
234 0 : AddTransformedRegion(result, mask, mTransform);
235 : }
236 :
237 1530 : for (size_t i = 0;
238 1020 : i < std::min(mAncestorMaskLayers.Length(), mLayer->GetAncestorMaskLayerCount());
239 : i++)
240 : {
241 0 : nsIntRegion mask = mAncestorMaskLayers[i]->ComputeChange(aPrefix, aCallback);
242 : LTI_DUMP(mask, "ancestormask");
243 0 : AddTransformedRegion(result, mask, mTransform);
244 : }
245 :
246 510 : if (mUseClipRect && otherClip) {
247 101 : if (!mClipRect.IsEqualInterior(*otherClip)) {
248 6 : nsIntRegion tmp;
249 3 : tmp.Xor(mClipRect.ToUnknownRect(), otherClip->ToUnknownRect());
250 : LTI_DUMP(tmp, "clip");
251 3 : AddRegion(result, tmp);
252 : }
253 : }
254 :
255 510 : mLayer->ClearInvalidRegion();
256 1020 : return result;
257 : }
258 :
259 437 : void CheckCanary()
260 : {
261 437 : mCanary.Check();
262 437 : mLayer->CheckCanary();
263 437 : }
264 :
265 7 : virtual IntRect NewTransformedBounds()
266 : {
267 14 : return TransformRect(mLayer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds(),
268 21 : GetTransformForInvalidation(mLayer));
269 : }
270 :
271 132 : virtual IntRect OldTransformedBounds()
272 : {
273 132 : return TransformRect(mVisibleRegion.ToUnknownRegion().GetBounds(), mTransform);
274 : }
275 :
276 184 : virtual nsIntRegion ComputeChangeInternal(const char* aPrefix,
277 : NotifySubDocInvalidationFunc aCallback)
278 : {
279 184 : return IntRect();
280 : }
281 :
282 : RefPtr<Layer> mLayer;
283 : UniquePtr<LayerPropertiesBase> mMaskLayer;
284 : nsTArray<UniquePtr<LayerPropertiesBase>> mAncestorMaskLayers;
285 : nsIntRegion mVisibleRegion;
286 : Matrix4x4 mTransform;
287 : float mPostXScale;
288 : float mPostYScale;
289 : float mOpacity;
290 : ParentLayerIntRect mClipRect;
291 : bool mUseClipRect;
292 : mozilla::CorruptionCanary mCanary;
293 : };
294 :
295 903 : struct ContainerLayerProperties : public LayerPropertiesBase
296 : {
297 304 : explicit ContainerLayerProperties(ContainerLayer* aLayer)
298 304 : : LayerPropertiesBase(aLayer)
299 304 : , mPreXScale(aLayer->GetPreXScale())
300 608 : , mPreYScale(aLayer->GetPreYScale())
301 : {
302 751 : for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) {
303 447 : child->CheckCanary();
304 447 : mChildren.AppendElement(Move(CloneLayerTreePropertiesInternal(child)));
305 : }
306 304 : }
307 :
308 : protected:
309 : ContainerLayerProperties(const ContainerLayerProperties& a) = delete;
310 : ContainerLayerProperties& operator=(const ContainerLayerProperties& a) = delete;
311 :
312 : public:
313 297 : nsIntRegion ComputeChangeInternal(const char *aPrefix,
314 : NotifySubDocInvalidationFunc aCallback) override
315 : {
316 : // Make sure we got our virtual call right
317 297 : mSubtypeCanary.Check();
318 297 : ContainerLayer* container = mLayer->AsContainerLayer();
319 594 : nsIntRegion invalidOfLayer; // Invalid regions of this layer.
320 297 : nsIntRegion result; // Invliad regions for children only.
321 :
322 297 : container->CheckCanary();
323 :
324 297 : bool childrenChanged = false;
325 297 : bool invalidateWholeLayer = false;
326 594 : if (mPreXScale != container->GetPreXScale() ||
327 297 : mPreYScale != container->GetPreYScale()) {
328 0 : invalidOfLayer = OldTransformedBounds();
329 0 : AddRegion(invalidOfLayer, NewTransformedBounds());
330 0 : childrenChanged = true;
331 0 : invalidateWholeLayer = true;
332 :
333 : // Can't bail out early, we need to update the child container layers
334 : }
335 :
336 : // A low frame rate is especially visible to users when scrolling, so we
337 : // particularly want to avoid unnecessary invalidation at that time. For us
338 : // here, that means avoiding unnecessary invalidation of child items when
339 : // other children are added to or removed from our container layer, since
340 : // that may be caused by children being scrolled in or out of view. We are
341 : // less concerned with children changing order.
342 : // TODO: Consider how we could avoid unnecessary invalidation when children
343 : // change order, and whether the overhead would be worth it.
344 :
345 594 : nsDataHashtable<nsPtrHashKey<Layer>, uint32_t> oldIndexMap(mChildren.Length());
346 734 : for (uint32_t i = 0; i < mChildren.Length(); ++i) {
347 437 : mChildren[i]->CheckCanary();
348 437 : oldIndexMap.Put(mChildren[i]->mLayer, i);
349 : }
350 :
351 297 : uint32_t i = 0; // cursor into the old child list mChildren
352 733 : for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
353 436 : bool invalidateChildsCurrentArea = false;
354 436 : if (i < mChildren.Length()) {
355 : uint32_t childsOldIndex;
356 431 : if (oldIndexMap.Get(child, &childsOldIndex)) {
357 326 : if (childsOldIndex >= i) {
358 : // Invalidate the old areas of layers that used to be between the
359 : // current |child| and the previous |child| that was also in the
360 : // old list mChildren (if any of those children have been reordered
361 : // rather than removed, we will invalidate their new area when we
362 : // encounter them in the new list):
363 326 : for (uint32_t j = i; j < childsOldIndex; ++j) {
364 : LTI_DUMP(mChildren[j]->OldTransformedBounds(), "reordered child");
365 0 : AddRegion(result, mChildren[j]->OldTransformedBounds());
366 0 : childrenChanged |= true;
367 : }
368 326 : if (childsOldIndex >= mChildren.Length()) {
369 0 : MOZ_CRASH("Out of bounds");
370 : }
371 : // Invalidate any regions of the child that have changed:
372 652 : nsIntRegion region = mChildren[childsOldIndex]->ComputeChange(LTI_DEEPER(aPrefix), aCallback);
373 326 : i = childsOldIndex + 1;
374 326 : if (!region.IsEmpty()) {
375 : LTI_LOG("%s%p: child %p produced %s\n", aPrefix, mLayer.get(),
376 : mChildren[childsOldIndex]->mLayer.get(), Stringify(region).c_str());
377 102 : AddRegion(result, region);
378 102 : childrenChanged |= true;
379 : }
380 : } else {
381 : // We've already seen this child in mChildren (which means it must
382 : // have been reordered) and invalidated its old area. We need to
383 : // invalidate its new area too:
384 0 : invalidateChildsCurrentArea = true;
385 : }
386 : } else {
387 : // |child| is new
388 105 : invalidateChildsCurrentArea = true;
389 : }
390 : } else {
391 : // |child| is new, or was reordered to a higher index
392 5 : invalidateChildsCurrentArea = true;
393 : }
394 436 : if (invalidateChildsCurrentArea) {
395 : LTI_DUMP(child->GetLocalVisibleRegion().ToUnknownRegion(), "invalidateChidlsCurrentArea");
396 220 : AddTransformedRegion(result, child->GetLocalVisibleRegion().ToUnknownRegion(),
397 330 : GetTransformForInvalidation(child));
398 110 : if (aCallback) {
399 19 : NotifySubdocumentInvalidation(child, aCallback);
400 : } else {
401 91 : ClearInvalidations(child);
402 : }
403 : }
404 436 : childrenChanged |= invalidateChildsCurrentArea;
405 : }
406 :
407 : // Process remaining removed children.
408 519 : while (i < mChildren.Length()) {
409 111 : childrenChanged |= true;
410 : LTI_DUMP(mChildren[i]->OldTransformedBounds(), "removed child");
411 111 : AddRegion(result, mChildren[i]->OldTransformedBounds());
412 111 : i++;
413 : }
414 :
415 297 : if (aCallback) {
416 77 : aCallback(container, result);
417 : }
418 :
419 297 : if (childrenChanged) {
420 158 : container->SetChildrenChanged(true);
421 : }
422 :
423 297 : if (container->UseIntermediateSurface()) {
424 : IntRect bounds = invalidateWholeLayer
425 0 : ? mLayer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds()
426 0 : : result.GetBounds();
427 0 : container->SetInvalidCompositeRect(bounds);
428 : }
429 :
430 297 : if (!mLayer->Extend3DContext()) {
431 : // |result| contains invalid regions only of children.
432 297 : result.Transform(GetTransformForInvalidation(mLayer));
433 : }
434 : // else, effective transforms have applied on children.
435 :
436 : LTI_DUMP(invalidOfLayer, "invalidOfLayer");
437 297 : result.OrWith(invalidOfLayer);
438 594 : return result;
439 : }
440 :
441 5 : IntRect NewTransformedBounds() override
442 : {
443 5 : if (mLayer->Extend3DContext()) {
444 0 : IntRect result;
445 0 : for (UniquePtr<LayerPropertiesBase>& child : mChildren) {
446 0 : result = result.Union(child->NewTransformedBounds());
447 : }
448 0 : return result;
449 : }
450 :
451 5 : return LayerPropertiesBase::NewTransformedBounds();
452 : }
453 :
454 9 : IntRect OldTransformedBounds() override
455 : {
456 9 : if (mLayer->Extend3DContext()) {
457 0 : IntRect result;
458 0 : for (UniquePtr<LayerPropertiesBase>& child : mChildren) {
459 0 : result = result.Union(child->OldTransformedBounds());
460 : }
461 0 : return result;
462 : }
463 9 : return LayerPropertiesBase::OldTransformedBounds();
464 : }
465 :
466 : // The old list of children:
467 : mozilla::CorruptionCanary mSubtypeCanary;
468 : nsTArray<UniquePtr<LayerPropertiesBase>> mChildren;
469 : float mPreXScale;
470 : float mPreYScale;
471 : };
472 :
473 102 : struct ColorLayerProperties : public LayerPropertiesBase
474 : {
475 35 : explicit ColorLayerProperties(ColorLayer *aLayer)
476 35 : : LayerPropertiesBase(aLayer)
477 35 : , mColor(aLayer->GetColor())
478 70 : , mBounds(aLayer->GetBounds())
479 35 : { }
480 :
481 : protected:
482 : ColorLayerProperties(const ColorLayerProperties& a) = delete;
483 : ColorLayerProperties& operator=(const ColorLayerProperties& a) = delete;
484 :
485 : public:
486 29 : nsIntRegion ComputeChangeInternal(const char* aPrefix,
487 : NotifySubDocInvalidationFunc aCallback) override
488 : {
489 29 : ColorLayer* color = static_cast<ColorLayer*>(mLayer.get());
490 :
491 29 : if (mColor != color->GetColor()) {
492 : LTI_DUMP(NewTransformedBounds(), "color");
493 0 : return NewTransformedBounds();
494 : }
495 :
496 58 : nsIntRegion boundsDiff;
497 29 : boundsDiff.Xor(mBounds, color->GetBounds());
498 : LTI_DUMP(boundsDiff, "colorbounds");
499 :
500 58 : nsIntRegion result;
501 29 : AddTransformedRegion(result, boundsDiff, mTransform);
502 :
503 29 : return result;
504 : }
505 :
506 : Color mColor;
507 : IntRect mBounds;
508 : };
509 :
510 0 : struct BorderLayerProperties : public LayerPropertiesBase
511 : {
512 0 : explicit BorderLayerProperties(BorderLayer *aLayer)
513 0 : : LayerPropertiesBase(aLayer)
514 0 : , mColors(aLayer->GetColors())
515 0 : , mRect(aLayer->GetRect())
516 0 : , mCorners(aLayer->GetCorners())
517 0 : , mWidths(aLayer->GetWidths())
518 0 : { }
519 :
520 : protected:
521 : BorderLayerProperties(const BorderLayerProperties& a) = delete;
522 : BorderLayerProperties& operator=(const BorderLayerProperties& a) = delete;
523 :
524 : public:
525 0 : nsIntRegion ComputeChangeInternal(const char* aPrefix,
526 : NotifySubDocInvalidationFunc aCallback) override
527 : {
528 0 : BorderLayer* border = static_cast<BorderLayer*>(mLayer.get());
529 :
530 0 : if (!border->GetLocalVisibleRegion().ToUnknownRegion().IsEqual(mVisibleRegion)) {
531 0 : IntRect result = NewTransformedBounds();
532 0 : result = result.Union(OldTransformedBounds());
533 0 : return result;
534 : }
535 :
536 0 : if (!PodEqual(&mColors[0], &border->GetColors()[0], 4) ||
537 0 : !PodEqual(&mWidths[0], &border->GetWidths()[0], 4) ||
538 0 : !PodEqual(&mCorners[0], &border->GetCorners()[0], 4) ||
539 0 : !mRect.IsEqualEdges(border->GetRect())) {
540 : LTI_DUMP(NewTransformedBounds(), "bounds");
541 0 : return NewTransformedBounds();
542 : }
543 :
544 0 : return nsIntRegion();
545 : }
546 :
547 : BorderColors mColors;
548 : LayerRect mRect;
549 : BorderCorners mCorners;
550 : BorderWidths mWidths;
551 : };
552 :
553 0 : struct TextLayerProperties : public LayerPropertiesBase
554 : {
555 0 : explicit TextLayerProperties(TextLayer *aLayer)
556 0 : : LayerPropertiesBase(aLayer)
557 0 : , mBounds(aLayer->GetBounds())
558 : , mGlyphs(aLayer->GetGlyphs())
559 0 : , mFont(aLayer->GetScaledFont())
560 0 : { }
561 :
562 : protected:
563 : TextLayerProperties(const TextLayerProperties& a) = delete;
564 : TextLayerProperties& operator=(const TextLayerProperties& a) = delete;
565 :
566 : public:
567 0 : nsIntRegion ComputeChangeInternal(const char* aPrefix,
568 : NotifySubDocInvalidationFunc aCallback) override
569 : {
570 0 : TextLayer* text = static_cast<TextLayer*>(mLayer.get());
571 :
572 0 : if (!text->GetLocalVisibleRegion().ToUnknownRegion().IsEqual(mVisibleRegion)) {
573 0 : IntRect result = NewTransformedBounds();
574 0 : result = result.Union(OldTransformedBounds());
575 0 : return result;
576 : }
577 :
578 0 : if (!mBounds.IsEqualEdges(text->GetBounds()) ||
579 0 : mGlyphs != text->GetGlyphs() ||
580 0 : mFont != text->GetScaledFont()) {
581 : LTI_DUMP(NewTransformedBounds(), "bounds");
582 0 : return NewTransformedBounds();
583 : }
584 :
585 0 : return nsIntRegion();
586 : }
587 :
588 : gfx::IntRect mBounds;
589 : nsTArray<GlyphArray> mGlyphs;
590 : gfx::ScaledFont* mFont;
591 : };
592 :
593 0 : static ImageHost* GetImageHost(Layer* aLayer)
594 : {
595 0 : HostLayer* compositor = aLayer->AsHostLayer();
596 0 : if (compositor) {
597 0 : return static_cast<ImageHost*>(compositor->GetCompositableHost());
598 : }
599 0 : return nullptr;
600 : }
601 :
602 0 : struct ImageLayerProperties : public LayerPropertiesBase
603 : {
604 0 : explicit ImageLayerProperties(ImageLayer* aImage, bool aIsMask)
605 0 : : LayerPropertiesBase(aImage)
606 : , mContainer(aImage->GetContainer())
607 : , mImageHost(GetImageHost(aImage))
608 0 : , mSamplingFilter(aImage->GetSamplingFilter())
609 0 : , mScaleToSize(aImage->GetScaleToSize())
610 0 : , mScaleMode(aImage->GetScaleMode())
611 : , mLastProducerID(-1)
612 : , mLastFrameID(-1)
613 0 : , mIsMask(aIsMask)
614 : {
615 0 : if (mImageHost) {
616 0 : mLastProducerID = mImageHost->GetLastProducerID();
617 0 : mLastFrameID = mImageHost->GetLastFrameID();
618 : }
619 0 : }
620 :
621 0 : nsIntRegion ComputeChangeInternal(const char* aPrefix,
622 : NotifySubDocInvalidationFunc aCallback) override
623 : {
624 0 : ImageLayer* imageLayer = static_cast<ImageLayer*>(mLayer.get());
625 :
626 0 : if (!imageLayer->GetLocalVisibleRegion().ToUnknownRegion().IsEqual(mVisibleRegion)) {
627 0 : IntRect result = NewTransformedBounds();
628 0 : result = result.Union(OldTransformedBounds());
629 0 : return result;
630 : }
631 :
632 0 : ImageContainer* container = imageLayer->GetContainer();
633 0 : ImageHost* host = GetImageHost(imageLayer);
634 0 : if (mContainer != container ||
635 0 : mSamplingFilter != imageLayer->GetSamplingFilter() ||
636 0 : mScaleToSize != imageLayer->GetScaleToSize() ||
637 0 : mScaleMode != imageLayer->GetScaleMode() ||
638 0 : host != mImageHost ||
639 0 : (host && host->GetProducerID() != mLastProducerID) ||
640 0 : (host && host->GetFrameID() != mLastFrameID)) {
641 :
642 0 : if (mIsMask) {
643 : // Mask layers have an empty visible region, so we have to
644 : // use the image size instead.
645 0 : IntSize size;
646 0 : if (container) {
647 0 : size = container->GetCurrentSize();
648 : }
649 0 : if (host) {
650 0 : size = host->GetImageSize();
651 : }
652 0 : IntRect rect(0, 0, size.width, size.height);
653 : LTI_DUMP(rect, "mask");
654 0 : return TransformRect(rect, GetTransformForInvalidation(mLayer));
655 : }
656 : LTI_DUMP(NewTransformedBounds(), "bounds");
657 0 : return NewTransformedBounds();
658 : }
659 :
660 0 : return IntRect();
661 : }
662 :
663 : RefPtr<ImageContainer> mContainer;
664 : RefPtr<ImageHost> mImageHost;
665 : SamplingFilter mSamplingFilter;
666 : gfx::IntSize mScaleToSize;
667 : ScaleMode mScaleMode;
668 : int32_t mLastProducerID;
669 : int32_t mLastFrameID;
670 : bool mIsMask;
671 : };
672 :
673 0 : struct CanvasLayerProperties : public LayerPropertiesBase
674 : {
675 0 : explicit CanvasLayerProperties(CanvasLayer* aCanvas)
676 0 : : LayerPropertiesBase(aCanvas)
677 0 : , mImageHost(GetImageHost(aCanvas))
678 : {
679 0 : mFrameID = mImageHost ? mImageHost->GetFrameID() : -1;
680 0 : }
681 :
682 0 : nsIntRegion ComputeChangeInternal(const char* aPrefix,
683 : NotifySubDocInvalidationFunc aCallback) override
684 : {
685 0 : CanvasLayer* canvasLayer = static_cast<CanvasLayer*>(mLayer.get());
686 :
687 0 : ImageHost* host = GetImageHost(canvasLayer);
688 0 : if (host && host->GetFrameID() != mFrameID) {
689 : LTI_DUMP(NewTransformedBounds(), "frameId");
690 0 : return NewTransformedBounds();
691 : }
692 :
693 0 : return IntRect();
694 : }
695 :
696 : RefPtr<ImageHost> mImageHost;
697 : int32_t mFrameID;
698 : };
699 :
700 : UniquePtr<LayerPropertiesBase>
701 646 : CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask /* = false */)
702 : {
703 646 : if (!aRoot) {
704 13 : return MakeUnique<LayerPropertiesBase>();
705 : }
706 :
707 633 : MOZ_ASSERT(!aIsMask || aRoot->GetType() == Layer::TYPE_IMAGE);
708 :
709 633 : aRoot->CheckCanary();
710 :
711 633 : switch (aRoot->GetType()) {
712 : case Layer::TYPE_CONTAINER:
713 : case Layer::TYPE_REF:
714 304 : return MakeUnique<ContainerLayerProperties>(aRoot->AsContainerLayer());
715 : case Layer::TYPE_COLOR:
716 35 : return MakeUnique<ColorLayerProperties>(static_cast<ColorLayer*>(aRoot));
717 : case Layer::TYPE_IMAGE:
718 0 : return MakeUnique<ImageLayerProperties>(static_cast<ImageLayer*>(aRoot), aIsMask);
719 : case Layer::TYPE_CANVAS:
720 0 : return MakeUnique<CanvasLayerProperties>(static_cast<CanvasLayer*>(aRoot));
721 : case Layer::TYPE_BORDER:
722 0 : return MakeUnique<BorderLayerProperties>(static_cast<BorderLayer*>(aRoot));
723 : case Layer::TYPE_TEXT:
724 0 : return MakeUnique<TextLayerProperties>(static_cast<TextLayer*>(aRoot));
725 : case Layer::TYPE_DISPLAYITEM:
726 : case Layer::TYPE_READBACK:
727 : case Layer::TYPE_SHADOW:
728 : case Layer::TYPE_PAINTED:
729 294 : return MakeUnique<LayerPropertiesBase>(aRoot);
730 : }
731 :
732 0 : MOZ_ASSERT_UNREACHABLE("Unexpected root layer type");
733 : return MakeUnique<LayerPropertiesBase>(aRoot);
734 : }
735 :
736 : /* static */ UniquePtr<LayerProperties>
737 199 : LayerProperties::CloneFrom(Layer* aRoot)
738 : {
739 199 : return CloneLayerTreePropertiesInternal(aRoot);
740 : }
741 :
742 : /* static */ void
743 103 : LayerProperties::ClearInvalidations(Layer *aLayer)
744 : {
745 103 : ForEachNode<ForwardIterator>(
746 : aLayer,
747 123 : [] (Layer* layer)
748 : {
749 123 : layer->ClearInvalidRegion();
750 123 : if (layer->GetMaskLayer()) {
751 0 : ClearInvalidations(layer->GetMaskLayer());
752 : }
753 123 : for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) {
754 0 : ClearInvalidations(layer->GetAncestorMaskLayerAt(i));
755 : }
756 :
757 123 : }
758 103 : );
759 103 : }
760 :
761 : nsIntRegion
762 198 : LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFunc aCallback)
763 : {
764 198 : NS_ASSERTION(aRoot, "Must have a layer tree to compare against!");
765 198 : if (mLayer != aRoot) {
766 14 : if (aCallback) {
767 2 : NotifySubdocumentInvalidation(aRoot, aCallback);
768 : } else {
769 12 : ClearInvalidations(aRoot);
770 : }
771 : IntRect result = TransformRect(
772 28 : aRoot->GetLocalVisibleRegion().ToUnknownRegion().GetBounds(),
773 42 : aRoot->GetLocalTransform());
774 14 : result = result.Union(OldTransformedBounds());
775 14 : return result;
776 : }
777 368 : nsIntRegion invalid = ComputeChange(" ", aCallback);
778 184 : return invalid;
779 : }
780 :
781 : void
782 143 : LayerPropertiesBase::MoveBy(const IntPoint& aOffset)
783 : {
784 143 : mTransform.PostTranslate(aOffset.x, aOffset.y, 0);
785 143 : }
786 :
787 : } // namespace layers
788 : } // namespace mozilla
|