Line data Source code
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
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/DebugOnly.h"
8 :
9 : #include "FrameLayerBuilder.h"
10 :
11 : #include "gfxContext.h"
12 : #include "mozilla/LookAndFeel.h"
13 : #include "mozilla/Maybe.h"
14 : #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
15 : #include "mozilla/gfx/Matrix.h"
16 : #include "ActiveLayerTracker.h"
17 : #include "BasicLayers.h"
18 : #include "ImageContainer.h"
19 : #include "ImageLayers.h"
20 : #include "LayerTreeInvalidation.h"
21 : #include "Layers.h"
22 : #include "LayerUserData.h"
23 : #include "MaskLayerImageCache.h"
24 : #include "UnitTransforms.h"
25 : #include "Units.h"
26 : #include "gfx2DGlue.h"
27 : #include "gfxEnv.h"
28 : #include "gfxUtils.h"
29 : #include "nsAutoPtr.h"
30 : #include "nsAnimationManager.h"
31 : #include "nsDisplayList.h"
32 : #include "nsDocShell.h"
33 : #include "nsIScrollableFrame.h"
34 : #include "nsImageFrame.h"
35 : #include "nsLayoutUtils.h"
36 : #include "nsPresContext.h"
37 : #include "nsPrintfCString.h"
38 : #include "nsSVGIntegrationUtils.h"
39 : #include "nsTransitionManager.h"
40 : #include "mozilla/LayerTimelineMarker.h"
41 :
42 : #include "mozilla/EffectCompositor.h"
43 : #include "mozilla/Move.h"
44 : #include "mozilla/ReverseIterator.h"
45 : #include "mozilla/gfx/2D.h"
46 : #include "mozilla/gfx/Tools.h"
47 : #include "mozilla/layers/ShadowLayers.h"
48 : #include "mozilla/layers/TextureClient.h"
49 : #include "mozilla/layers/TextureWrapperImage.h"
50 : #include "mozilla/layers/WebRenderUserData.h"
51 : #include "mozilla/Unused.h"
52 : #include "GeckoProfiler.h"
53 : #include "LayersLogging.h"
54 : #include "gfxPrefs.h"
55 :
56 : #include <algorithm>
57 : #include <functional>
58 : #include <deque>
59 :
60 : using namespace mozilla::layers;
61 : using namespace mozilla::gfx;
62 :
63 : namespace mozilla {
64 :
65 : class PaintedDisplayItemLayerUserData;
66 :
67 : static nsTHashtable<nsPtrHashKey<DisplayItemData>>* sAliveDisplayItemDatas;
68 :
69 : /**
70 : * The address of gPaintedDisplayItemLayerUserData is used as the user
71 : * data key for PaintedLayers created by FrameLayerBuilder.
72 : * It identifies PaintedLayers used to draw non-layer content, which are
73 : * therefore eligible for recycling. We want display items to be able to
74 : * create their own dedicated PaintedLayers in BuildLayer, if necessary,
75 : * and we wouldn't want to accidentally recycle those.
76 : * The user data is a PaintedDisplayItemLayerUserData.
77 : */
78 : uint8_t gPaintedDisplayItemLayerUserData;
79 : /**
80 : * The address of gColorLayerUserData is used as the user
81 : * data key for ColorLayers created by FrameLayerBuilder.
82 : * The user data is null.
83 : */
84 : uint8_t gColorLayerUserData;
85 : /**
86 : * The address of gImageLayerUserData is used as the user
87 : * data key for ImageLayers created by FrameLayerBuilder.
88 : * The user data is null.
89 : */
90 : uint8_t gImageLayerUserData;
91 : /**
92 : * The address of gLayerManagerUserData is used as the user
93 : * data key for retained LayerManagers managed by FrameLayerBuilder.
94 : * The user data is a LayerManagerData.
95 : */
96 : uint8_t gLayerManagerUserData;
97 : /**
98 : * The address of gMaskLayerUserData is used as the user
99 : * data key for mask layers managed by FrameLayerBuilder.
100 : * The user data is a MaskLayerUserData.
101 : */
102 : uint8_t gMaskLayerUserData;
103 : /**
104 : * The address of gCSSMaskLayerUserData is used as the user
105 : * data key for mask layers of css masking managed by FrameLayerBuilder.
106 : * The user data is a CSSMaskLayerUserData.
107 : */
108 : uint8_t gCSSMaskLayerUserData;
109 :
110 : // a global cache of image containers used for mask layers
111 : static MaskLayerImageCache* gMaskLayerImageCache = nullptr;
112 :
113 0 : static inline MaskLayerImageCache* GetMaskLayerImageCache()
114 : {
115 0 : if (!gMaskLayerImageCache) {
116 0 : gMaskLayerImageCache = new MaskLayerImageCache();
117 : }
118 :
119 0 : return gMaskLayerImageCache;
120 : }
121 :
122 : struct DisplayItemEntry {
123 : DisplayItemEntry(nsDisplayItem* aItem,
124 : DisplayItemEntryType aType)
125 0 : : mItem(aItem)
126 0 : , mType(aType)
127 : {}
128 :
129 : nsDisplayItem* mItem;
130 : DisplayItemEntryType mType;
131 : };
132 :
133 0 : class FLBDisplayItemIterator : protected FlattenedDisplayItemIterator
134 : {
135 : public:
136 0 : FLBDisplayItemIterator(nsDisplayListBuilder* aBuilder,
137 : nsDisplayList* aList,
138 : ContainerState* aState)
139 0 : : FlattenedDisplayItemIterator(aBuilder, aList, false)
140 : , mState(aState)
141 0 : , mStoreMarker(false)
142 : {
143 0 : MOZ_ASSERT(mState);
144 0 : ResolveFlattening();
145 0 : }
146 :
147 0 : DisplayItemEntry GetNextEntry()
148 : {
149 0 : if (!mMarkers.empty()) {
150 0 : DisplayItemEntry entry = mMarkers.front();
151 0 : mMarkers.pop_front();
152 0 : return entry;
153 : }
154 :
155 0 : nsDisplayItem* next = GetNext();
156 0 : return DisplayItemEntry { next, DisplayItemEntryType::ITEM };
157 : }
158 :
159 0 : nsDisplayItem* GetNext()
160 : {
161 : // This function is only supposed to be called if there are no markers set.
162 : // Breaking this invariant can potentially break effect flattening and/or
163 : // display item merging.
164 0 : MOZ_ASSERT(mMarkers.empty());
165 :
166 0 : return FlattenedDisplayItemIterator::GetNext();
167 : }
168 :
169 0 : bool HasNext() const
170 : {
171 0 : return FlattenedDisplayItemIterator::HasNext() || !mMarkers.empty();
172 : }
173 :
174 : nsDisplayItem* PeekNext()
175 : {
176 : return mNext;
177 : }
178 :
179 : private:
180 : bool ShouldFlattenNextItem() override;
181 :
182 0 : void StartNested(nsDisplayItem* aItem) override
183 : {
184 0 : if (!mStoreMarker) {
185 : return;
186 : }
187 :
188 0 : if (aItem->GetType() == DisplayItemType::TYPE_OPACITY) {
189 0 : mMarkers.emplace_back(aItem, DisplayItemEntryType::PUSH_OPACITY);
190 0 : mActiveMarkers.AppendElement(aItem);
191 : }
192 :
193 0 : mStoreMarker = false;
194 : }
195 :
196 0 : void EndNested(nsDisplayItem* aItem) override
197 : {
198 0 : if (mActiveMarkers.IsEmpty() || mActiveMarkers.LastElement() != aItem) {
199 : // Do not emit an end marker if this item did not emit a start marker.
200 : return;
201 : }
202 :
203 0 : if (aItem->GetType() == DisplayItemType::TYPE_OPACITY) {
204 0 : mMarkers.emplace_back(aItem, DisplayItemEntryType::POP_OPACITY);
205 0 : mActiveMarkers.RemoveLastElement();
206 : }
207 : }
208 :
209 : std::deque<DisplayItemEntry> mMarkers;
210 : AutoTArray<nsDisplayItem*, 4> mActiveMarkers;
211 : ContainerState* mState;
212 : bool mStoreMarker;
213 : };
214 :
215 0 : DisplayItemData::DisplayItemData(LayerManagerData* aParent, uint32_t aKey,
216 0 : Layer* aLayer, nsIFrame* aFrame)
217 :
218 : : mRefCnt(0)
219 : , mParent(aParent)
220 : , mLayer(aLayer)
221 : , mDisplayItemKey(aKey)
222 : , mItem(nullptr)
223 : , mUsed(true)
224 : , mIsInvalid(false)
225 : , mReusedItem(false)
226 0 : , mDisconnected(false)
227 : {
228 0 : MOZ_COUNT_CTOR(DisplayItemData);
229 :
230 0 : if (!sAliveDisplayItemDatas) {
231 0 : sAliveDisplayItemDatas = new nsTHashtable<nsPtrHashKey<DisplayItemData>>();
232 : }
233 0 : MOZ_RELEASE_ASSERT(!sAliveDisplayItemDatas->Contains(this));
234 0 : sAliveDisplayItemDatas->PutEntry(this);
235 :
236 0 : MOZ_RELEASE_ASSERT(mLayer);
237 0 : if (aFrame) {
238 0 : AddFrame(aFrame);
239 : }
240 :
241 0 : }
242 :
243 : void
244 0 : DisplayItemData::AddFrame(nsIFrame* aFrame)
245 : {
246 0 : MOZ_RELEASE_ASSERT(mLayer);
247 0 : mFrameList.AppendElement(aFrame);
248 :
249 0 : SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
250 0 : array.AppendElement(this);
251 0 : }
252 :
253 : void
254 0 : DisplayItemData::RemoveFrame(nsIFrame* aFrame)
255 : {
256 0 : MOZ_RELEASE_ASSERT(mLayer);
257 0 : bool result = mFrameList.RemoveElement(aFrame);
258 0 : MOZ_RELEASE_ASSERT(result, "Can't remove a frame that wasn't added!");
259 :
260 0 : SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
261 0 : array.RemoveElement(this);
262 0 : }
263 :
264 : void
265 0 : DisplayItemData::EndUpdate()
266 : {
267 0 : MOZ_RELEASE_ASSERT(mLayer);
268 0 : mItem = nullptr;
269 0 : mIsInvalid = false;
270 0 : mUsed = false;
271 0 : mReusedItem = false;
272 0 : }
273 :
274 : void
275 0 : DisplayItemData::EndUpdate(nsAutoPtr<nsDisplayItemGeometry> aGeometry)
276 : {
277 0 : MOZ_RELEASE_ASSERT(mLayer);
278 0 : MOZ_ASSERT(mItem);
279 0 : MOZ_ASSERT(mGeometry || aGeometry);
280 :
281 0 : if (aGeometry) {
282 0 : mGeometry = aGeometry;
283 : }
284 0 : mClip = mItem->GetClip();
285 0 : mChangedFrameInvalidations.SetEmpty();
286 :
287 0 : mItem = nullptr;
288 0 : EndUpdate();
289 0 : }
290 :
291 : void
292 0 : DisplayItemData::BeginUpdate(Layer* aLayer, LayerState aState,
293 : bool aFirstUpdate,
294 : nsDisplayItem* aItem /* = nullptr */)
295 : {
296 0 : BeginUpdate(aLayer, aState, aItem,
297 0 : (aItem && !aFirstUpdate) ? aItem->IsReused() : false,
298 0 : aItem ? aItem->HasMergedFrames() : false);
299 0 : }
300 :
301 : void
302 0 : DisplayItemData::BeginUpdate(Layer* aLayer, LayerState aState,
303 : nsDisplayItem* aItem, bool aIsReused,
304 : bool aIsMerged)
305 : {
306 0 : MOZ_RELEASE_ASSERT(mLayer);
307 0 : MOZ_RELEASE_ASSERT(aLayer);
308 0 : mLayer = aLayer;
309 0 : mOptLayer = nullptr;
310 0 : mInactiveManager = nullptr;
311 0 : mLayerState = aState;
312 0 : mUsed = true;
313 :
314 0 : if (aLayer->AsPaintedLayer()) {
315 0 : mItem = aItem;
316 0 : mReusedItem = aIsReused;
317 : }
318 :
319 0 : if (!aItem) {
320 0 : return;
321 : }
322 :
323 0 : if (!aIsMerged && mFrameList.Length() == 1) {
324 0 : MOZ_ASSERT(mFrameList[0] == aItem->Frame());
325 : return;
326 : }
327 :
328 : // We avoid adding or removing element unnecessarily
329 : // since we have to modify userdata each time
330 0 : AutoTArray<nsIFrame*, 4> copy(mFrameList);
331 0 : if (!copy.RemoveElement(aItem->Frame())) {
332 0 : AddFrame(aItem->Frame());
333 : mChangedFrameInvalidations.Or(mChangedFrameInvalidations,
334 0 : aItem->Frame()->GetVisualOverflowRect());
335 : }
336 :
337 0 : AutoTArray<nsIFrame*,4> mergedFrames;
338 0 : aItem->GetMergedFrames(&mergedFrames);
339 0 : for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
340 0 : if (!copy.RemoveElement(mergedFrames[i])) {
341 0 : AddFrame(mergedFrames[i]);
342 : mChangedFrameInvalidations.Or(mChangedFrameInvalidations,
343 0 : mergedFrames[i]->GetVisualOverflowRect());
344 : }
345 : }
346 :
347 0 : for (uint32_t i = 0; i < copy.Length(); i++) {
348 0 : RemoveFrame(copy[i]);
349 : mChangedFrameInvalidations.Or(mChangedFrameInvalidations,
350 0 : copy[i]->GetVisualOverflowRect());
351 : }
352 : }
353 :
354 : static const nsIFrame* sDestroyedFrame = nullptr;
355 0 : DisplayItemData::~DisplayItemData()
356 : {
357 0 : MOZ_COUNT_DTOR(DisplayItemData);
358 0 : Disconnect();
359 :
360 0 : MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas);
361 : nsPtrHashKey<mozilla::DisplayItemData>* entry
362 0 : = sAliveDisplayItemDatas->GetEntry(this);
363 0 : MOZ_RELEASE_ASSERT(entry);
364 :
365 0 : sAliveDisplayItemDatas->RemoveEntry(entry);
366 :
367 0 : if (sAliveDisplayItemDatas->Count() == 0) {
368 0 : delete sAliveDisplayItemDatas;
369 0 : sAliveDisplayItemDatas = nullptr;
370 : }
371 0 : }
372 :
373 : void
374 0 : DisplayItemData::Disconnect()
375 : {
376 0 : if (mDisconnected) {
377 : return;
378 : }
379 0 : mDisconnected = true;
380 :
381 0 : for (uint32_t i = 0; i < mFrameList.Length(); i++) {
382 0 : nsIFrame* frame = mFrameList[i];
383 0 : if (frame == sDestroyedFrame) {
384 : continue;
385 : }
386 0 : SmallPointerArray<DisplayItemData>& array = frame->DisplayItemData();
387 0 : array.RemoveElement(this);
388 : }
389 :
390 0 : mLayer = nullptr;
391 0 : mOptLayer = nullptr;
392 : }
393 :
394 : void
395 0 : DisplayItemData::ClearAnimationCompositorState()
396 : {
397 0 : if (mDisplayItemKey != static_cast<uint32_t>(DisplayItemType::TYPE_TRANSFORM) &&
398 : mDisplayItemKey != static_cast<uint32_t>(DisplayItemType::TYPE_OPACITY)) {
399 : return;
400 : }
401 :
402 0 : for (nsIFrame* frame : mFrameList) {
403 0 : nsCSSPropertyID prop = mDisplayItemKey == static_cast<uint32_t>(DisplayItemType::TYPE_TRANSFORM) ?
404 0 : eCSSProperty_transform : eCSSProperty_opacity;
405 0 : EffectCompositor::ClearIsRunningOnCompositor(frame, prop);
406 : }
407 : }
408 :
409 : const nsRegion&
410 0 : DisplayItemData::GetChangedFrameInvalidations()
411 : {
412 0 : return mChangedFrameInvalidations;
413 : }
414 :
415 : DisplayItemData*
416 0 : DisplayItemData::AssertDisplayItemData(DisplayItemData* aData)
417 : {
418 0 : MOZ_RELEASE_ASSERT(aData);
419 0 : MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas && sAliveDisplayItemDatas->Contains(aData));
420 0 : MOZ_RELEASE_ASSERT(aData->mLayer);
421 0 : return aData;
422 : }
423 :
424 : /**
425 : * This is the userdata we associate with a layer manager.
426 : */
427 : class LayerManagerData : public LayerUserData {
428 : public:
429 0 : explicit LayerManagerData(LayerManager *aManager)
430 0 : : mLayerManager(aManager)
431 : #ifdef DEBUG_DISPLAY_ITEM_DATA
432 : , mParent(nullptr)
433 : #endif
434 0 : , mInvalidateAllLayers(false)
435 : {
436 0 : MOZ_COUNT_CTOR(LayerManagerData);
437 0 : }
438 0 : ~LayerManagerData() {
439 0 : MOZ_COUNT_DTOR(LayerManagerData);
440 :
441 0 : for (auto& item : mDisplayItems) {
442 0 : item->Disconnect();
443 : }
444 0 : }
445 :
446 : #ifdef DEBUG_DISPLAY_ITEM_DATA
447 : void Dump(const char *aPrefix = "") {
448 : printf_stderr("%sLayerManagerData %p\n", aPrefix, this);
449 :
450 : for (auto& data : mDisplayItems) {
451 : nsAutoCString prefix;
452 : prefix += aPrefix;
453 : prefix += " ";
454 :
455 : const char* layerState;
456 : switch (data->mLayerState) {
457 : case LAYER_NONE:
458 : layerState = "LAYER_NONE"; break;
459 : case LAYER_INACTIVE:
460 : layerState = "LAYER_INACTIVE"; break;
461 : case LAYER_ACTIVE:
462 : layerState = "LAYER_ACTIVE"; break;
463 : case LAYER_ACTIVE_FORCE:
464 : layerState = "LAYER_ACTIVE_FORCE"; break;
465 : case LAYER_ACTIVE_EMPTY:
466 : layerState = "LAYER_ACTIVE_EMPTY"; break;
467 : case LAYER_SVG_EFFECTS:
468 : layerState = "LAYER_SVG_EFFECTS"; break;
469 : }
470 : uint32_t mask = (1 << TYPE_BITS) - 1;
471 :
472 : nsAutoCString str;
473 : str += prefix;
474 : str += nsPrintfCString("Frame %p ", data->mFrameList[0]);
475 : str += nsDisplayItem::DisplayItemTypeName(static_cast<nsDisplayItem::Type>(data->mDisplayItemKey & mask));
476 : if ((data->mDisplayItemKey >> TYPE_BITS)) {
477 : str += nsPrintfCString("(%i)", data->mDisplayItemKey >> TYPE_BITS);
478 : }
479 : str += nsPrintfCString(", %s, Layer %p", layerState, data->mLayer.get());
480 : if (data->mOptLayer) {
481 : str += nsPrintfCString(", OptLayer %p", data->mOptLayer.get());
482 : }
483 : if (data->mInactiveManager) {
484 : str += nsPrintfCString(", InactiveLayerManager %p", data->mInactiveManager.get());
485 : }
486 : str += "\n";
487 :
488 : printf_stderr("%s", str.get());
489 :
490 : if (data->mInactiveManager) {
491 : prefix += " ";
492 : printf_stderr("%sDumping inactive layer info:\n", prefix.get());
493 : LayerManagerData* lmd = static_cast<LayerManagerData*>
494 : (data->mInactiveManager->GetUserData(&gLayerManagerUserData));
495 : lmd->Dump(prefix.get());
496 : }
497 : }
498 : }
499 : #endif
500 :
501 : /**
502 : * Tracks which frames have layers associated with them.
503 : */
504 : LayerManager *mLayerManager;
505 : #ifdef DEBUG_DISPLAY_ITEM_DATA
506 : LayerManagerData *mParent;
507 : #endif
508 : std::vector<RefPtr<DisplayItemData>> mDisplayItems;
509 : bool mInvalidateAllLayers;
510 : };
511 :
512 : /* static */ void
513 : FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame)
514 : {
515 0 : RemoveFrameFromLayerManager(aFrame, aFrame->DisplayItemData());
516 : aFrame->DisplayItemData().Clear();
517 0 : aFrame->DeleteProperty(WebRenderUserDataProperty::Key());
518 0 : }
519 0 :
520 0 : /**
521 : * We keep a stack of these to represent the PaintedLayers that are
522 : * currently available to have display items added to.
523 : * We use a stack here because as much as possible we want to
524 : * assign display items to existing PaintedLayers, and to the lowest
525 : * PaintedLayer in z-order. This reduces the number of layers and
526 : * makes it more likely a display item will be rendered to an opaque
527 : * layer, giving us the best chance of getting subpixel AA.
528 : */
529 : class PaintedLayerData {
530 : public:
531 0 : PaintedLayerData() :
532 : mAnimatedGeometryRoot(nullptr),
533 0 : mASR(nullptr),
534 : mClipChain(nullptr),
535 : mReferenceFrame(nullptr),
536 : mLayer(nullptr),
537 : mSolidColor(NS_RGBA(0, 0, 0, 0)),
538 : mIsSolidColorInVisibleRegion(false),
539 : mNeedComponentAlpha(false),
540 : mForceTransparentSurface(false),
541 : mHideAllLayersBelow(false),
542 : mOpaqueForAnimatedGeometryRootParent(false),
543 : mDisableFlattening(false),
544 : mBackfaceHidden(false),
545 : mShouldPaintOnContentSide(false),
546 : mDTCRequiresTargetConfirmation(false),
547 : mImage(nullptr),
548 : mItemClip(nullptr),
549 : mNewChildLayersIndex(-1)
550 0 : {}
551 0 :
552 : #ifdef MOZ_DUMP_PAINTING
553 : /**
554 : * Keep track of important decisions for debugging.
555 : */
556 : nsCString mLog;
557 :
558 : #define FLB_LOG_PAINTED_LAYER_DECISION(pld, ...) \
559 : if (gfxPrefs::LayersDumpDecision()) { \
560 : pld->mLog.AppendPrintf("\t\t\t\t"); \
561 : pld->mLog.AppendPrintf(__VA_ARGS__); \
562 : }
563 : #else
564 : #define FLB_LOG_PAINTED_LAYER_DECISION(...)
565 : #endif
566 :
567 : /**
568 : * Record that an item has been added to the PaintedLayer, so we
569 : * need to update our regions.
570 : * @param aVisibleRect the area of the item that's visible
571 : * @param aSolidColor if non-null, the visible area of the item is
572 : * a constant color given by *aSolidColor
573 : */
574 : void Accumulate(ContainerState* aState,
575 : nsDisplayItem* aItem,
576 : const nsIntRect& aVisibleRect,
577 : const nsRect& aContentRect,
578 : const DisplayItemClip& aClip,
579 : LayerState aLayerState,
580 : nsDisplayList *aList,
581 : DisplayItemEntryType aType);
582 : AnimatedGeometryRoot* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; }
583 :
584 : /**
585 : * A region including the horizontal pan, vertical pan, and no action regions.
586 : */
587 : nsRegion CombinedTouchActionRegion();
588 :
589 : /**
590 : * Add the given hit test info to the hit regions for this PaintedLayer.
591 : */
592 : void AccumulateHitTestInfo(ContainerState* aState,
593 : nsDisplayCompositorHitTestInfo* aItem);
594 :
595 : /**
596 : * If this represents only a nsDisplayImage, and the image type supports being
597 : * optimized to an ImageLayer, returns true.
598 : */
599 : bool CanOptimizeToImageLayer(nsDisplayListBuilder* aBuilder);
600 :
601 : /**
602 : * If this represents only a nsDisplayImage, and the image type supports being
603 : * optimized to an ImageLayer, returns an ImageContainer for the underlying
604 : * image if one is available.
605 : */
606 : already_AddRefed<ImageContainer> GetContainerForImageLayer(nsDisplayListBuilder* aBuilder);
607 :
608 : bool VisibleAboveRegionIntersects(const nsIntRegion& aRegion) const
609 11 : { return !mVisibleAboveRegion.Intersect(aRegion).IsEmpty(); }
610 44 : bool VisibleRegionIntersects(const nsIntRegion& aRegion) const
611 11 : { return !mVisibleRegion.Intersect(aRegion).IsEmpty(); }
612 44 :
613 : /**
614 : * The region of visible content in the layer, relative to the
615 : * container layer (which is at the snapped top-left of the display
616 : * list reference frame).
617 : */
618 : nsIntRegion mVisibleRegion;
619 : /**
620 : * The region of visible content in the layer that is opaque.
621 : * Same coordinate system as mVisibleRegion.
622 : */
623 : nsIntRegion mOpaqueRegion;
624 : /**
625 : * The definitely-hit region for this PaintedLayer.
626 : */
627 : nsRegion mHitRegion;
628 : /**
629 : * The maybe-hit region for this PaintedLayer.
630 : */
631 : nsRegion mMaybeHitRegion;
632 : /**
633 : * The dispatch-to-content hit region for this PaintedLayer.
634 : */
635 : nsRegion mDispatchToContentHitRegion;
636 : /**
637 : * The region for this PaintedLayer that is sensitive to events
638 : * but disallows panning and zooming. This is an approximation
639 : * and any deviation from the true region will be part of the
640 : * mDispatchToContentHitRegion.
641 : */
642 : nsRegion mNoActionRegion;
643 : /**
644 : * The region for this PaintedLayer that is sensitive to events and
645 : * allows horizontal panning but not zooming. This is an approximation
646 : * and any deviation from the true region will be part of the
647 : * mDispatchToContentHitRegion.
648 : */
649 : nsRegion mHorizontalPanRegion;
650 : /**
651 : * The region for this PaintedLayer that is sensitive to events and
652 : * allows vertical panning but not zooming. This is an approximation
653 : * and any deviation from the true region will be part of the
654 : * mDispatchToContentHitRegion.
655 : */
656 : nsRegion mVerticalPanRegion;
657 : /**
658 : * Scaled versions of the bounds of mHitRegion and mMaybeHitRegion.
659 : * We store these because FindPaintedLayerFor() needs to consume them
660 : * in this form, and it's a hot code path so we don't want to scale
661 : * them inside that function.
662 : */
663 : nsIntRect mScaledHitRegionBounds;
664 : nsIntRect mScaledMaybeHitRegionBounds;
665 : /**
666 : * The "active scrolled root" for all content in the layer. Must
667 : * be non-null; all content in a PaintedLayer must have the same
668 : * active scrolled root.
669 : */
670 : AnimatedGeometryRoot* mAnimatedGeometryRoot;
671 : const ActiveScrolledRoot* mASR;
672 : /**
673 : * The chain of clips that should apply to this layer.
674 : */
675 : const DisplayItemClipChain* mClipChain;
676 : /**
677 : * The offset between mAnimatedGeometryRoot and the reference frame.
678 : */
679 : nsPoint mAnimatedGeometryRootOffset;
680 : /**
681 : * If non-null, the frame from which we'll extract "fixed positioning"
682 : * metadata for this layer. This can be a position:fixed frame or a viewport
683 : * frame; the latter case is used for background-attachment:fixed content.
684 : */
685 : const nsIFrame* mReferenceFrame;
686 : PaintedLayer* mLayer;
687 : /**
688 : * If mIsSolidColorInVisibleRegion is true, this is the color of the visible
689 : * region.
690 : */
691 : nscolor mSolidColor;
692 : /**
693 : * True if every pixel in mVisibleRegion will have color mSolidColor.
694 : */
695 : bool mIsSolidColorInVisibleRegion;
696 : /**
697 : * True if there is any text visible in the layer that's over
698 : * transparent pixels in the layer.
699 : */
700 : bool mNeedComponentAlpha;
701 : /**
702 : * Set if the layer should be treated as transparent, even if its entire
703 : * area is covered by opaque display items. For example, this needs to
704 : * be set if something is going to "punch holes" in the layer by clearing
705 : * part of its surface.
706 : */
707 : bool mForceTransparentSurface;
708 : /**
709 : * Set if all layers below this PaintedLayer should be hidden.
710 : */
711 : bool mHideAllLayersBelow;
712 : /**
713 : * Set if the opaque region for this layer can be applied to the parent
714 : * animated geometry root of this layer's animated geometry root.
715 : * We set this when a PaintedLayer's animated geometry root is a scrollframe
716 : * and the PaintedLayer completely fills the displayport of the scrollframe.
717 : */
718 : bool mOpaqueForAnimatedGeometryRootParent;
719 : /**
720 : * Set if there is content in the layer that must avoid being flattened.
721 : */
722 : bool mDisableFlattening;
723 : /**
724 : * Set if the backface of this region is hidden to the user.
725 : * Content that backface is hidden should not be draw on the layer
726 : * with visible backface.
727 : */
728 : bool mBackfaceHidden;
729 : /**
730 : * Set if it is better to render this layer on the content process, for
731 : * example if it contains native theme widgets.
732 : */
733 : bool mShouldPaintOnContentSide;
734 : /**
735 : * Set to true if events targeting the dispatch-to-content region
736 : * require target confirmation.
737 : * See CompositorHitTestFlags::eRequiresTargetConfirmation and
738 : * EventRegions::mDTCRequiresTargetConfirmation.
739 : */
740 : bool mDTCRequiresTargetConfirmation;
741 : /**
742 : * Stores the pointer to the nsDisplayImage if we want to
743 : * convert this to an ImageLayer.
744 : */
745 : nsDisplayImageContainer* mImage;
746 : /**
747 : * Stores the clip that we need to apply to the image or, if there is no
748 : * image, a clip for SOME item in the layer. There is no guarantee which
749 : * item's clip will be stored here and mItemClip should not be used to clip
750 : * the whole layer - only some part of the clip should be used, as determined
751 : * by PaintedDisplayItemLayerUserData::GetCommonClipCount() - which may even be
752 : * no part at all.
753 : */
754 : const DisplayItemClip* mItemClip;
755 : /**
756 : * Index of this layer in mNewChildLayers.
757 : */
758 : int32_t mNewChildLayersIndex;
759 : /**
760 : * The region of visible content above the layer and below the
761 : * next PaintedLayerData currently in the stack, if any.
762 : * This is a conservative approximation: it contains the true region.
763 : */
764 : nsIntRegion mVisibleAboveRegion;
765 : /**
766 : * All the display items that have been assigned to this painted layer.
767 : * These items get added by Accumulate().
768 : */
769 : nsTArray<AssignedDisplayItem> mAssignedDisplayItems;
770 : /**
771 : * Tracks the active opacity markers by holding the indices to PUSH_OPACITY
772 : * items in |mAssignedDisplayItems|.
773 : */
774 : nsTArray<size_t> mOpacityIndices;
775 : };
776 :
777 : struct NewLayerEntry {
778 207 : NewLayerEntry()
779 69 : : mAnimatedGeometryRoot(nullptr)
780 69 : , mASR(nullptr)
781 : , mClipChain(nullptr)
782 : , mScrollMetadataASR(nullptr)
783 : , mLayerContentsVisibleRect(0, 0, -1, -1)
784 : , mLayerState(LAYER_INACTIVE)
785 : , mHideAllLayersBelow(false)
786 : , mOpaqueForAnimatedGeometryRootParent(false)
787 : , mPropagateComponentAlphaFlattening(true)
788 : , mUntransformedVisibleRegion(false)
789 : , mIsFixedToRootScrollFrame(false)
790 690 : {}
791 69 : // mLayer is null if the previous entry is for a PaintedLayer that hasn't
792 : // been optimized to some other form (yet).
793 : RefPtr<Layer> mLayer;
794 : AnimatedGeometryRoot* mAnimatedGeometryRoot;
795 : const ActiveScrolledRoot* mASR;
796 : const DisplayItemClipChain* mClipChain;
797 : const ActiveScrolledRoot* mScrollMetadataASR;
798 : // If non-null, this ScrollMetadata is set to the be the first ScrollMetadata
799 : // on the layer.
800 : UniquePtr<ScrollMetadata> mBaseScrollMetadata;
801 : // The following are only used for retained layers (for occlusion
802 : // culling of those layers). These regions are all relative to the
803 : // container reference frame.
804 : nsIntRegion mVisibleRegion;
805 : nsIntRegion mOpaqueRegion;
806 : // This rect is in the layer's own coordinate space. The computed visible
807 : // region for the layer cannot extend beyond this rect.
808 : nsIntRect mLayerContentsVisibleRect;
809 : LayerState mLayerState;
810 : bool mHideAllLayersBelow;
811 : // When mOpaqueForAnimatedGeometryRootParent is true, the opaque region of
812 : // this layer is opaque in the same position even subject to the animation of
813 : // geometry of mAnimatedGeometryRoot. For example when mAnimatedGeometryRoot
814 : // is a scrolled frame and the scrolled content is opaque everywhere in the
815 : // displayport, we can set this flag.
816 : // When this flag is set, we can treat this opaque region as covering
817 : // content whose animated geometry root is the animated geometry root for
818 : // mAnimatedGeometryRoot->GetParent().
819 : bool mOpaqueForAnimatedGeometryRootParent;
820 :
821 : // If true, then the content flags for this layer should contribute
822 : // to our decision to flatten component alpha layers, false otherwise.
823 : bool mPropagateComponentAlphaFlattening;
824 : // mVisibleRegion is relative to the associated frame before
825 : // transform.
826 : bool mUntransformedVisibleRegion;
827 : bool mIsFixedToRootScrollFrame;
828 : };
829 :
830 : class PaintedLayerDataTree;
831 :
832 : /**
833 : * This is tree node type for PaintedLayerDataTree.
834 : * Each node corresponds to a different animated geometry root, and contains
835 : * a stack of PaintedLayerDatas, in bottom-to-top order.
836 : * There is at most one node per animated geometry root. The ancestor and
837 : * descendant relations in PaintedLayerDataTree tree mirror those in the frame
838 : * tree.
839 : * Each node can have clip that describes the potential extents that items in
840 : * this node can cover. If mHasClip is false, it means that the node's contents
841 : * can move anywhere.
842 : * Testing against the clip instead of the node's actual contents has the
843 : * advantage that the node's contents can move or animate without affecting
844 : * content in other nodes. So we don't need to re-layerize during animations
845 : * (sync or async), and during async animations everything is guaranteed to
846 : * look correct.
847 : * The contents of a node's PaintedLayerData stack all share the node's
848 : * animated geometry root. The child nodes are on top of the PaintedLayerData
849 : * stack, in z-order, and the clip rects of the child nodes are allowed to
850 : * intersect with the visible region or visible above region of their parent
851 : * node's PaintedLayerDatas.
852 : */
853 : class PaintedLayerDataNode {
854 : public:
855 : PaintedLayerDataNode(PaintedLayerDataTree& aTree,
856 : PaintedLayerDataNode* aParent,
857 : AnimatedGeometryRoot* aAnimatedGeometryRoot);
858 : ~PaintedLayerDataNode();
859 :
860 : AnimatedGeometryRoot* GetAnimatedGeometryRoot() const { return mAnimatedGeometryRoot; }
861 :
862 : /**
863 : * Whether this node's contents can potentially intersect aRect.
864 : * aRect is in our tree's ContainerState's coordinate space.
865 : */
866 : bool Intersects(const nsIntRect& aRect) const
867 0 : { return !mHasClip || mClipRect.Intersects(aRect); }
868 0 :
869 : /**
870 : * Create a PaintedLayerDataNode for aAnimatedGeometryRoot, add it to our
871 : * children, and return it.
872 : */
873 : PaintedLayerDataNode* AddChildNodeFor(AnimatedGeometryRoot* aAnimatedGeometryRoot);
874 :
875 : /**
876 : * Find a PaintedLayerData in our mPaintedLayerDataStack that aItem can be
877 : * added to. Creates a new PaintedLayerData by calling
878 : * aNewPaintedLayerCallback if necessary.
879 : */
880 : template<typename NewPaintedLayerCallbackType>
881 : PaintedLayerData* FindPaintedLayerFor(const nsIntRect& aVisibleRect,
882 : bool aBackfaceHidden,
883 : const ActiveScrolledRoot* aASR,
884 : const DisplayItemClipChain* aClipChain,
885 : NewPaintedLayerCallbackType aNewPaintedLayerCallback);
886 :
887 : /**
888 : * Find an opaque background color for aRegion. Pulls a color from the parent
889 : * geometry root if appropriate, but only if that color is present underneath
890 : * the whole clip of this node, so that this node's contents can animate or
891 : * move (possibly async) without having to change the background color.
892 : * @param aUnderIndex Searching will start in mPaintedLayerDataStack right
893 : * below aUnderIndex.
894 : */
895 : enum { ABOVE_TOP = -1 };
896 : nscolor FindOpaqueBackgroundColor(const nsIntRegion& aRegion,
897 : int32_t aUnderIndex = ABOVE_TOP) const;
898 : /**
899 : * Same as FindOpaqueBackgroundColor, but only returns a color if absolutely
900 : * nothing is in between, so that it can be used for a layer that can move
901 : * anywhere inside our clip.
902 : */
903 : nscolor FindOpaqueBackgroundColorCoveringEverything() const;
904 :
905 : /**
906 : * Adds aRect to this node's top PaintedLayerData's mVisibleAboveRegion,
907 : * or mVisibleAboveBackgroundRegion if mPaintedLayerDataStack is empty.
908 : */
909 : void AddToVisibleAboveRegion(const nsIntRect& aRect);
910 : /**
911 : * Call this if all of our existing content can potentially be covered, so
912 : * nothing can merge with it and all new content needs to create new items
913 : * on top. This will finish all of our children and pop our whole
914 : * mPaintedLayerDataStack.
915 : */
916 : void SetAllDrawingAbove();
917 :
918 : /**
919 : * Finish this node: Finish all children, finish our PaintedLayer contents,
920 : * and (if requested) adjust our parent's visible above region to include
921 : * our clip.
922 : */
923 : void Finish(bool aParentNeedsAccurateVisibleAboveRegion);
924 :
925 : /**
926 : * Finish any children that intersect aRect.
927 : */
928 : void FinishChildrenIntersecting(const nsIntRect& aRect);
929 :
930 : /**
931 : * Finish all children.
932 : */
933 : void FinishAllChildren() { FinishAllChildren(true); }
934 0 :
935 : protected:
936 : /**
937 : * Finish all items in mPaintedLayerDataStack and clear the stack.
938 : */
939 : void PopAllPaintedLayerData();
940 : /**
941 : * Finish all of our child nodes, but don't touch mPaintedLayerDataStack.
942 : */
943 : void FinishAllChildren(bool aThisNodeNeedsAccurateVisibleAboveRegion);
944 : /**
945 : * Pass off opaque background color searching to our parent node, if we have
946 : * one.
947 : */
948 : nscolor FindOpaqueBackgroundColorInParentNode() const;
949 :
950 : PaintedLayerDataTree& mTree;
951 : PaintedLayerDataNode* mParent;
952 : AnimatedGeometryRoot* mAnimatedGeometryRoot;
953 :
954 : /**
955 : * Our contents: a PaintedLayerData stack and our child nodes.
956 : */
957 : AutoTArray<PaintedLayerData, 3> mPaintedLayerDataStack;
958 :
959 : /**
960 : * UniquePtr is used here in the sense of "unique ownership", i.e. there is
961 : * only one owner. Not in the sense of "this is the only pointer to the
962 : * node": There are two other, non-owning, pointers to our child nodes: The
963 : * node's respective children point to their parent node with their mParent
964 : * pointer, and the tree keeps a map of animated geometry root to node in its
965 : * mNodes member. These outside pointers are the reason that mChildren isn't
966 : * just an nsTArray<PaintedLayerDataNode> (since the pointers would become
967 : * invalid whenever the array expands its capacity).
968 : */
969 : nsTArray<UniquePtr<PaintedLayerDataNode>> mChildren;
970 :
971 : /**
972 : * The region that's covered between our "background" and the bottom of
973 : * mPaintedLayerDataStack. This is used to indicate whether we can pull
974 : * a background color from our parent node. If mVisibleAboveBackgroundRegion
975 : * should be considered infinite, mAllDrawingAboveBackground will be true and
976 : * the value of mVisibleAboveBackgroundRegion will be meaningless.
977 : */
978 : nsIntRegion mVisibleAboveBackgroundRegion;
979 :
980 : /**
981 : * Our clip, if we have any. If not, that means we can move anywhere, and
982 : * mHasClip will be false and mClipRect will be meaningless.
983 : */
984 : nsIntRect mClipRect;
985 : bool mHasClip;
986 :
987 : /**
988 : * Whether mVisibleAboveBackgroundRegion should be considered infinite.
989 : */
990 : bool mAllDrawingAboveBackground;
991 : };
992 :
993 : class ContainerState;
994 :
995 : /**
996 : * A tree of PaintedLayerDataNodes. At any point in time, the tree only
997 : * contains nodes for animated geometry roots that new items can potentially
998 : * merge into. Any time content is added on top that overlaps existing things
999 : * in such a way that we no longer want to merge new items with some existing
1000 : * content, that existing content gets "finished".
1001 : * The public-facing methods of this class are FindPaintedLayerFor,
1002 : * AddingOwnLayer, and Finish. The other public methods are for
1003 : * PaintedLayerDataNode.
1004 : * The tree calls out to its containing ContainerState for some things.
1005 : * All coordinates / rects in the tree or the tree nodes are in the
1006 : * ContainerState's coordinate space, i.e. relative to the reference frame and
1007 : * in layer pixels.
1008 : * The clip rects of sibling nodes never overlap. This is ensured by finishing
1009 : * existing nodes before adding new ones, if this property were to be violated.
1010 : * The root tree node doesn't get finished until the ContainerState is
1011 : * finished.
1012 : * The tree's root node is always the root reference frame of the builder. We
1013 : * don't stop at the container state's mContainerAnimatedGeometryRoot because
1014 : * some of our contents can have animated geometry roots that are not
1015 : * descendants of the container's animated geometry root. Every animated
1016 : * geometry root we encounter for our contents needs to have a defined place in
1017 : * the tree.
1018 : */
1019 : class PaintedLayerDataTree {
1020 : public:
1021 : PaintedLayerDataTree(ContainerState& aContainerState,
1022 29 : nscolor& aBackgroundColor)
1023 : : mContainerState(aContainerState)
1024 29 : , mContainerUniformBackgroundColor(aBackgroundColor)
1025 : , mForInactiveLayer(false)
1026 87 : {}
1027 29 :
1028 : ~PaintedLayerDataTree()
1029 0 : {
1030 87 : MOZ_ASSERT(!mRoot);
1031 0 : MOZ_ASSERT(mNodes.Count() == 0);
1032 58 : }
1033 0 :
1034 : void InitializeForInactiveLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot);
1035 :
1036 : /**
1037 : * Notify our contents that some non-PaintedLayer content has been added.
1038 : * *aRect needs to be a rectangle that doesn't move with respect to
1039 : * aAnimatedGeometryRoot and that contains the added item.
1040 : * If aRect is null, the extents will be considered infinite.
1041 : * If aOutUniformBackgroundColor is non-null, it will be set to an opaque
1042 : * color that can be pulled into the background of the added content, or
1043 : * transparent if that is not possible.
1044 : */
1045 : void AddingOwnLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot,
1046 : const nsIntRect* aRect,
1047 : nscolor* aOutUniformBackgroundColor);
1048 :
1049 : /**
1050 : * Find a PaintedLayerData for aItem. This can either be an existing
1051 : * PaintedLayerData from inside a node in our tree, or a new one that gets
1052 : * created by a call out to aNewPaintedLayerCallback.
1053 : */
1054 : template<typename NewPaintedLayerCallbackType>
1055 : PaintedLayerData* FindPaintedLayerFor(AnimatedGeometryRoot* aAnimatedGeometryRoot,
1056 : const ActiveScrolledRoot* aASR,
1057 : const DisplayItemClipChain* aClipChain,
1058 : const nsIntRect& aVisibleRect,
1059 : const bool aBackfaceHidden,
1060 : NewPaintedLayerCallbackType aNewPaintedLayerCallback);
1061 :
1062 : /**
1063 : * Finish everything.
1064 : */
1065 : void Finish();
1066 :
1067 : /**
1068 : * Get the parent animated geometry root of aAnimatedGeometryRoot.
1069 : * That's either aAnimatedGeometryRoot's animated geometry root, or, if
1070 : * that's aAnimatedGeometryRoot itself, then it's the animated geometry
1071 : * root for aAnimatedGeometryRoot's cross-doc parent frame.
1072 : */
1073 : AnimatedGeometryRoot* GetParentAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot);
1074 :
1075 : /**
1076 : * Whether aAnimatedGeometryRoot has an intrinsic clip that doesn't move with
1077 : * respect to aAnimatedGeometryRoot's parent animated geometry root.
1078 : * If aAnimatedGeometryRoot is a scroll frame, this will be the scroll frame's
1079 : * scroll port, otherwise there is no clip.
1080 : * This method doesn't have much to do with PaintedLayerDataTree, but this is
1081 : * where we have easy access to a display list builder, which we use to get
1082 : * the clip rect result into the right coordinate space.
1083 : */
1084 : bool IsClippedWithRespectToParentAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot,
1085 : nsIntRect* aOutClip);
1086 :
1087 : /**
1088 : * Called by PaintedLayerDataNode when it is finished, so that we can drop
1089 : * our pointers to it.
1090 : */
1091 : void NodeWasFinished(AnimatedGeometryRoot* aAnimatedGeometryRoot);
1092 :
1093 : nsDisplayListBuilder* Builder() const;
1094 : ContainerState& ContState() const { return mContainerState; }
1095 : nscolor UniformBackgroundColor() const { return mContainerUniformBackgroundColor; }
1096 :
1097 : protected:
1098 : /**
1099 : * Finish all nodes that potentially intersect *aRect, where *aRect is a rect
1100 : * that doesn't move with respect to aAnimatedGeometryRoot.
1101 : * If aRect is null, *aRect will be considered infinite.
1102 : */
1103 : void FinishPotentiallyIntersectingNodes(AnimatedGeometryRoot* aAnimatedGeometryRoot,
1104 : const nsIntRect* aRect);
1105 :
1106 : /**
1107 : * Make sure that there is a node for aAnimatedGeometryRoot and all of its
1108 : * ancestor geometry roots. Return the node for aAnimatedGeometryRoot.
1109 : */
1110 : PaintedLayerDataNode* EnsureNodeFor(AnimatedGeometryRoot* aAnimatedGeometryRoot);
1111 :
1112 : /**
1113 : * Find an existing node in the tree for an ancestor of aAnimatedGeometryRoot.
1114 : * *aOutAncestorChild will be set to the last ancestor that was encountered
1115 : * in the search up from aAnimatedGeometryRoot; it will be a child animated
1116 : * geometry root of the result, if neither are null.
1117 : */
1118 : PaintedLayerDataNode*
1119 : FindNodeForAncestorAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot,
1120 : AnimatedGeometryRoot** aOutAncestorChild);
1121 :
1122 : ContainerState& mContainerState;
1123 : Maybe<PaintedLayerDataNode> mRoot;
1124 :
1125 : /**
1126 : * The uniform opaque color from behind this container layer, or
1127 : * NS_RGBA(0,0,0,0) if the background behind this container layer is not
1128 : * uniform and opaque. This color can be pulled into PaintedLayers that are
1129 : * directly above the background.
1130 : */
1131 : nscolor mContainerUniformBackgroundColor;
1132 :
1133 : /**
1134 : * A hash map for quick access the node belonging to a particular animated
1135 : * geometry root.
1136 : */
1137 : nsDataHashtable<nsPtrHashKey<AnimatedGeometryRoot>, PaintedLayerDataNode*> mNodes;
1138 :
1139 : bool mForInactiveLayer;
1140 : };
1141 :
1142 : /**
1143 : * This is a helper object used to build up the layer children for
1144 : * a ContainerLayer.
1145 : */
1146 : class ContainerState {
1147 174 : public:
1148 : ContainerState(nsDisplayListBuilder* aBuilder,
1149 29 : LayerManager* aManager,
1150 : FrameLayerBuilder* aLayerBuilder,
1151 : nsIFrame* aContainerFrame,
1152 : nsDisplayItem* aContainerItem,
1153 : const nsRect& aContainerBounds,
1154 : ContainerLayer* aContainerLayer,
1155 : const ContainerLayerParameters& aParameters,
1156 : nscolor aBackgroundColor,
1157 : const ActiveScrolledRoot* aContainerASR,
1158 : const ActiveScrolledRoot* aContainerScrollMetadataASR,
1159 : const ActiveScrolledRoot* aContainerCompositorASR) :
1160 29 : mBuilder(aBuilder), mManager(aManager),
1161 : mLayerBuilder(aLayerBuilder),
1162 : mContainerFrame(aContainerFrame),
1163 : mContainerLayer(aContainerLayer),
1164 : mContainerBounds(aContainerBounds),
1165 : mContainerASR(aContainerASR),
1166 : mContainerScrollMetadataASR(aContainerScrollMetadataASR),
1167 : mContainerCompositorASR(aContainerCompositorASR),
1168 : mParameters(aParameters),
1169 : mPaintedLayerDataTree(*this, aBackgroundColor),
1170 : mLastDisplayPortAGR(nullptr)
1171 116 : {
1172 : nsPresContext* presContext = aContainerFrame->PresContext();
1173 29 : mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
1174 29 : mContainerReferenceFrame =
1175 29 : const_cast<nsIFrame*>(aContainerItem ? aContainerItem->ReferenceFrameForChildren() :
1176 11 : mBuilder->FindReferenceFrameFor(mContainerFrame));
1177 40 : bool isAtRoot = !aContainerItem || (aContainerItem->Frame() == mBuilder->RootReferenceFrame());
1178 0 : MOZ_ASSERT(!isAtRoot || mContainerReferenceFrame == mBuilder->RootReferenceFrame());
1179 29 : mContainerAnimatedGeometryRoot = isAtRoot
1180 0 : ? aBuilder->GetRootAnimatedGeometryRoot()
1181 0 : : aContainerItem->GetAnimatedGeometryRoot();
1182 : MOZ_ASSERT(!mBuilder->IsPaintingToWindow() ||
1183 0 : nsLayoutUtils::IsAncestorFrameCrossDoc(mBuilder->RootReferenceFrame(),
1184 : *mContainerAnimatedGeometryRoot));
1185 : // When AllowResidualTranslation is false, display items will be drawn
1186 : // scaled with a translation by integer pixels, so we know how the snapping
1187 : // will work.
1188 : mSnappingEnabled = aManager->IsSnappingEffectiveTransforms() &&
1189 58 : !mParameters.AllowResidualTranslation();
1190 0 : CollectOldLayers();
1191 29 : }
1192 29 :
1193 : /**
1194 : * This is the method that actually walks a display list and builds
1195 : * the child layers.
1196 : */
1197 : void ProcessDisplayItems(nsDisplayList* aList);
1198 : /**
1199 : * This finalizes all the open PaintedLayers by popping every element off
1200 : * mPaintedLayerDataStack, then sets the children of the container layer
1201 : * to be all the layers in mNewChildLayers in that order and removes any
1202 : * layers as children of the container that aren't in mNewChildLayers.
1203 : * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA,
1204 : * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA
1205 : */
1206 : void Finish(uint32_t *aTextContentFlags,
1207 : const nsIntRect& aContainerPixelBounds,
1208 : nsDisplayList* aChildItems);
1209 :
1210 : nscoord GetAppUnitsPerDevPixel() { return mAppUnitsPerDevPixel; }
1211 :
1212 : nsIntRect ScaleToNearestPixels(const nsRect& aRect) const
1213 536 : {
1214 : return aRect.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
1215 536 : mAppUnitsPerDevPixel);
1216 1072 : }
1217 : nsIntRegion ScaleRegionToNearestPixels(const nsRegion& aRegion) const
1218 7 : {
1219 : return aRegion.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
1220 0 : mAppUnitsPerDevPixel);
1221 14 : }
1222 : nsIntRect ScaleToOutsidePixels(const nsRect& aRect, bool aSnap = false) const
1223 0 : {
1224 : if (aSnap && mSnappingEnabled) {
1225 0 : return ScaleToNearestPixels(aRect);
1226 211 : }
1227 : return aRect.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
1228 0 : mAppUnitsPerDevPixel);
1229 1656 : }
1230 : nsIntRegion ScaleToOutsidePixels(const nsRegion& aRegion, bool aSnap = false) const
1231 0 : {
1232 : if (aSnap && mSnappingEnabled) {
1233 0 : return ScaleRegionToNearestPixels(aRegion);
1234 0 : }
1235 : return aRegion.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
1236 0 : mAppUnitsPerDevPixel);
1237 0 : }
1238 : nsIntRect ScaleToInsidePixels(const nsRect& aRect, bool aSnap = false) const
1239 7 : {
1240 : if (aSnap && mSnappingEnabled) {
1241 1 : return ScaleToNearestPixels(aRect);
1242 7 : }
1243 : return aRect.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale,
1244 0 : mAppUnitsPerDevPixel);
1245 0 : }
1246 :
1247 : nsIntRegion ScaleRegionToInsidePixels(const nsRegion& aRegion, bool aSnap = false) const
1248 0 : {
1249 : if (aSnap && mSnappingEnabled) {
1250 7 : return ScaleRegionToNearestPixels(aRegion);
1251 0 : }
1252 : return aRegion.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale,
1253 0 : mAppUnitsPerDevPixel);
1254 0 : }
1255 :
1256 : nsIntRegion ScaleRegionToOutsidePixels(const nsRegion& aRegion, bool aSnap = false) const
1257 0 : {
1258 : if (aSnap && mSnappingEnabled) {
1259 174 : return ScaleRegionToNearestPixels(aRegion);
1260 0 : }
1261 : return aRegion.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
1262 174 : mAppUnitsPerDevPixel);
1263 348 : }
1264 :
1265 : nsIFrame* GetContainerFrame() const { return mContainerFrame; }
1266 : nsDisplayListBuilder* Builder() const { return mBuilder; }
1267 :
1268 : /**
1269 : * Check if we are currently inside an inactive layer.
1270 : */
1271 : bool IsInInactiveLayer() const {
1272 : return mLayerBuilder->GetContainingPaintedLayerData();
1273 299 : }
1274 :
1275 : /**
1276 : * Sets aOuterVisibleRegion as aLayer's visible region.
1277 : * @param aOuterVisibleRegion
1278 : * is in the coordinate space of the container reference frame.
1279 : * @param aLayerContentsVisibleRect, if non-null, is in the layer's own
1280 : * coordinate system.
1281 : * @param aOuterUntransformed is true if the given aOuterVisibleRegion
1282 : * is already untransformed with the matrix of the layer.
1283 : */
1284 : void SetOuterVisibleRegionForLayer(Layer* aLayer,
1285 : const nsIntRegion& aOuterVisibleRegion,
1286 : const nsIntRect* aLayerContentsVisibleRect = nullptr,
1287 : bool aOuterUntransformed = false) const;
1288 :
1289 : /**
1290 : * Try to determine whether the PaintedLayer aData has a single opaque color
1291 : * covering aRect. If successful, return that color, otherwise return
1292 : * NS_RGBA(0,0,0,0).
1293 : * If aRect turns out not to intersect any content in the layer,
1294 : * *aOutIntersectsLayer will be set to false.
1295 : */
1296 : nscolor FindOpaqueBackgroundColorInLayer(const PaintedLayerData* aData,
1297 : const nsIntRect& aRect,
1298 : bool* aOutIntersectsLayer) const;
1299 :
1300 : /**
1301 : * Indicate that we are done adding items to the PaintedLayer represented by
1302 : * aData. Make sure that a real PaintedLayer exists for it, and set the final
1303 : * visible region and opaque-content.
1304 : */
1305 : template<typename FindOpaqueBackgroundColorCallbackType>
1306 : void FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueBackgroundColorCallbackType aFindOpaqueBackgroundColor);
1307 :
1308 : protected:
1309 : friend class PaintedLayerData;
1310 : friend class FLBDisplayItemIterator;
1311 :
1312 : LayerManager::PaintedLayerCreationHint
1313 : GetLayerCreationHint(AnimatedGeometryRoot* aAnimatedGeometryRoot);
1314 :
1315 : /**
1316 : * Creates a new PaintedLayer and sets up the transform on the PaintedLayer
1317 : * to account for scrolling.
1318 : */
1319 : already_AddRefed<PaintedLayer> CreatePaintedLayer(PaintedLayerData* aData);
1320 :
1321 : /**
1322 : * Find a PaintedLayer for recycling, recycle it and prepare it for use, or
1323 : * return null if no suitable layer was found.
1324 : */
1325 : already_AddRefed<PaintedLayer> AttemptToRecyclePaintedLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot,
1326 : nsDisplayItem* aItem,
1327 : const nsPoint& aTopLeft,
1328 : const nsIFrame* aReferenceFrame);
1329 : /**
1330 : * Recycle aLayer and do any necessary invalidation.
1331 : */
1332 : PaintedDisplayItemLayerUserData* RecyclePaintedLayer(PaintedLayer* aLayer,
1333 : AnimatedGeometryRoot* aAnimatedGeometryRoot,
1334 : bool& didResetScrollPositionForLayerPixelAlignment);
1335 :
1336 : /**
1337 : * Perform the last step of CreatePaintedLayer / AttemptToRecyclePaintedLayer:
1338 : * Initialize aData, set up the layer's transform for scrolling, and
1339 : * invalidate the layer for layer pixel alignment changes if necessary.
1340 : */
1341 : void PreparePaintedLayerForUse(PaintedLayer* aLayer,
1342 : PaintedDisplayItemLayerUserData* aData,
1343 : AnimatedGeometryRoot* aAnimatedGeometryRoot,
1344 : const nsIFrame* aReferenceFrame,
1345 : const nsPoint& aTopLeft,
1346 : bool aDidResetScrollPositionForLayerPixelAlignment);
1347 :
1348 : /**
1349 : * Attempt to prepare an ImageLayer based upon the provided PaintedLayerData.
1350 : * Returns nullptr on failure.
1351 : */
1352 : already_AddRefed<Layer> PrepareImageLayer(PaintedLayerData* aData);
1353 :
1354 : /**
1355 : * Attempt to prepare a ColorLayer based upon the provided PaintedLayerData.
1356 : * Returns nullptr on failure.
1357 : */
1358 : already_AddRefed<Layer> PrepareColorLayer(PaintedLayerData* aData);
1359 :
1360 : /**
1361 : * Grab the next recyclable ColorLayer, or create one if there are no
1362 : * more recyclable ColorLayers.
1363 : */
1364 : already_AddRefed<ColorLayer> CreateOrRecycleColorLayer(PaintedLayer* aPainted);
1365 : /**
1366 : * Grab the next recyclable ImageLayer, or create one if there are no
1367 : * more recyclable ImageLayers.
1368 : */
1369 : already_AddRefed<ImageLayer> CreateOrRecycleImageLayer(PaintedLayer* aPainted);
1370 : /**
1371 : * Grab a recyclable ImageLayer for use as a mask layer for aLayer (that is a
1372 : * mask layer which has been used for aLayer before), or create one if such
1373 : * a layer doesn't exist.
1374 : *
1375 : * Since mask layers can exist either on the layer directly, or as a side-
1376 : * attachment to FrameMetrics (for ancestor scrollframe clips), we key the
1377 : * recycle operation on both the originating layer and the mask layer's
1378 : * index in the layer, if any.
1379 : */
1380 : struct MaskLayerKey;
1381 : template<typename UserData>
1382 : already_AddRefed<ImageLayer> CreateOrRecycleMaskImageLayerFor(
1383 : const MaskLayerKey& aKey,
1384 : UserData* (*aGetUserData)(Layer* aLayer),
1385 : void (*aSetDefaultUserData)(Layer* aLayer));
1386 : /**
1387 : * Grabs all PaintedLayers and ColorLayers from the ContainerLayer and makes them
1388 : * available for recycling.
1389 : */
1390 : void CollectOldLayers();
1391 : /**
1392 : * If aItem used to belong to a PaintedLayer, invalidates the area of
1393 : * aItem in that layer. If aNewLayer is a PaintedLayer, invalidates the area of
1394 : * aItem in that layer.
1395 : */
1396 : void InvalidateForLayerChange(nsDisplayItem* aItem,
1397 : PaintedLayer* aNewLayer,
1398 : DisplayItemData* aData);
1399 : /**
1400 : * Returns true if aItem's opaque area (in aOpaque) covers the entire
1401 : * scrollable area of its presshell.
1402 : */
1403 : bool ItemCoversScrollableArea(nsDisplayItem* aItem, const nsRegion& aOpaque);
1404 :
1405 : /**
1406 : * Set ScrollMetadata and scroll-induced clipping on aEntry's layer.
1407 : */
1408 : void SetupScrollingMetadata(NewLayerEntry* aEntry);
1409 :
1410 : /**
1411 : * Applies occlusion culling.
1412 : * For each layer in mNewChildLayers, remove from its visible region the
1413 : * opaque regions of the layers at higher z-index, but only if they have
1414 : * the same animated geometry root and fixed-pos frame ancestor.
1415 : * The opaque region for the child layers that share the same animated
1416 : * geometry root as the container frame is returned in
1417 : * *aOpaqueRegionForContainer.
1418 : *
1419 : * Also sets scroll metadata on the layers.
1420 : */
1421 : void PostprocessRetainedLayers(nsIntRegion* aOpaqueRegionForContainer);
1422 :
1423 : /**
1424 : * Computes the snapped opaque area of aItem. Sets aList's opaque flag
1425 : * if it covers the entire list bounds. Sets *aHideAllLayersBelow to true
1426 : * this item covers the entire viewport so that all layers below are
1427 : * permanently invisible.
1428 : */
1429 : nsIntRegion ComputeOpaqueRect(nsDisplayItem* aItem,
1430 : AnimatedGeometryRoot* aAnimatedGeometryRoot,
1431 : const ActiveScrolledRoot* aASR,
1432 : const DisplayItemClip& aClip,
1433 : nsDisplayList* aList,
1434 : bool* aHideAllLayersBelow,
1435 : bool* aOpaqueForAnimatedGeometryRootParent);
1436 :
1437 : /**
1438 : * Fills a PaintedLayerData object that is initialized for a layer that the
1439 : * current item will be assigned to. Also creates mNewChildLayers entries.
1440 : * @param aData The PaintedLayerData that will be filled.
1441 : * @param aVisibleRect The visible rect of the item.
1442 : * @param aAnimatedGeometryRoot The item's animated geometry root.
1443 : * @param aASR The active scrolled root that moves this PaintedLayer.
1444 : * @param aClipChain The clip chain that the compositor needs to
1445 : * apply to this layer.
1446 : * @param aScrollMetadataASR The leaf ASR for which scroll metadata needs to be
1447 : * set on the layer, because either the layer itself
1448 : * or its scrolled clip need to move with that ASR.
1449 : * @param aTopLeft The offset between aAnimatedGeometryRoot and
1450 : * the reference frame.
1451 : * @param aReferenceFrame The reference frame for the item.
1452 : * @param aBackfaceHidden The backface visibility for the item frame.
1453 : */
1454 : void NewPaintedLayerData(PaintedLayerData* aData,
1455 : AnimatedGeometryRoot* aAnimatedGeometryRoot,
1456 : const ActiveScrolledRoot* aASR,
1457 : const DisplayItemClipChain* aClipChain,
1458 : const ActiveScrolledRoot* aScrollMetadataASR,
1459 : const nsPoint& aTopLeft,
1460 : const nsIFrame* aReferenceFrame,
1461 : const bool aBackfaceHidden);
1462 :
1463 : /* Build a mask layer to represent the clipping region. Will return null if
1464 : * there is no clipping specified or a mask layer cannot be built.
1465 : * Builds an ImageLayer for the appropriate backend; the mask is relative to
1466 : * aLayer's visible region.
1467 : * aLayer is the layer to be clipped.
1468 : * relative to the container reference frame
1469 : * aRoundedRectClipCount is used when building mask layers for PaintedLayers,
1470 : */
1471 : void SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip);
1472 :
1473 : /**
1474 : * If |aClip| has rounded corners, create a mask layer for them, and
1475 : * add it to |aLayer|'s ancestor mask layers, returning an index into
1476 : * the array of ancestor mask layers. Returns an empty Maybe if
1477 : * |aClip| does not have rounded corners, or if no mask layer could
1478 : * be created.
1479 : */
1480 : Maybe<size_t> SetupMaskLayerForScrolledClip(Layer* aLayer,
1481 : const DisplayItemClip& aClip);
1482 :
1483 : /*
1484 : * Create/find a mask layer with suitable size for aMaskItem to paint
1485 : * css-positioned-masking onto.
1486 : */
1487 : void SetupMaskLayerForCSSMask(Layer* aLayer, nsDisplayMask* aMaskItem);
1488 :
1489 : already_AddRefed<Layer> CreateMaskLayer(
1490 : Layer *aLayer, const DisplayItemClip& aClip,
1491 : const Maybe<size_t>& aForAncestorMaskLayer);
1492 :
1493 : /**
1494 : * Get the display port for an AGR.
1495 : * The result would be cached for later reusing.
1496 : */
1497 : nsRect GetDisplayPortForAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot);
1498 :
1499 : nsDisplayListBuilder* mBuilder;
1500 : LayerManager* mManager;
1501 : FrameLayerBuilder* mLayerBuilder;
1502 : nsIFrame* mContainerFrame;
1503 : nsIFrame* mContainerReferenceFrame;
1504 : AnimatedGeometryRoot* mContainerAnimatedGeometryRoot;
1505 : ContainerLayer* mContainerLayer;
1506 : nsRect mContainerBounds;
1507 :
1508 : // Due to the way we store scroll annotations in the layer tree, we need to
1509 : // keep track of three (possibly different) ASRs here.
1510 : // mContainerASR is the ASR of the container display item that this
1511 : // ContainerState was created for.
1512 : // mContainerScrollMetadataASR is the ASR of the leafmost scroll metadata
1513 : // that's in effect on mContainerLayer.
1514 : // mContainerCompositorASR is the ASR that mContainerLayer moves with on
1515 : // the compositor / APZ side, taking into account both the scroll meta data
1516 : // and the fixed position annotation on itself and its ancestors.
1517 : const ActiveScrolledRoot* mContainerASR;
1518 : const ActiveScrolledRoot* mContainerScrollMetadataASR;
1519 : const ActiveScrolledRoot* mContainerCompositorASR;
1520 : #ifdef DEBUG
1521 : nsRect mAccumulatedChildBounds;
1522 : #endif
1523 : ContainerLayerParameters mParameters;
1524 : /**
1525 : * The region of PaintedLayers that should be invalidated every time
1526 : * we recycle one.
1527 : */
1528 : nsIntRegion mInvalidPaintedContent;
1529 : PaintedLayerDataTree mPaintedLayerDataTree;
1530 : /**
1531 : * We collect the list of children in here. During ProcessDisplayItems,
1532 : * the layers in this array either have mContainerLayer as their parent,
1533 : * or no parent.
1534 : * PaintedLayers have two entries in this array: the second one is used only if
1535 : * the PaintedLayer is optimized away to a ColorLayer or ImageLayer.
1536 : * It's essential that this array is only appended to, since PaintedLayerData
1537 : * records the index of its PaintedLayer in this array.
1538 : */
1539 : typedef AutoTArray<NewLayerEntry,1> AutoLayersArray;
1540 : AutoLayersArray mNewChildLayers;
1541 : nsTHashtable<nsRefPtrHashKey<PaintedLayer>> mPaintedLayersAvailableForRecycling;
1542 : nscoord mAppUnitsPerDevPixel;
1543 : bool mSnappingEnabled;
1544 :
1545 : struct MaskLayerKey {
1546 0 : MaskLayerKey() : mLayer(nullptr) {}
1547 : MaskLayerKey(Layer* aLayer, const Maybe<size_t>& aAncestorIndex)
1548 : : mLayer(aLayer),
1549 0 : mAncestorIndex(aAncestorIndex)
1550 0 : {}
1551 :
1552 : PLDHashNumber Hash() const {
1553 0 : // Hash the layer and add the layer index to the hash.
1554 : return (NS_PTR_TO_UINT32(mLayer) >> 2)
1555 0 : + (mAncestorIndex ? (*mAncestorIndex + 1) : 0);
1556 0 : }
1557 : bool operator ==(const MaskLayerKey& aOther) const {
1558 0 : return mLayer == aOther.mLayer &&
1559 0 : mAncestorIndex == aOther.mAncestorIndex;
1560 0 : }
1561 :
1562 : Layer* mLayer;
1563 : Maybe<size_t> mAncestorIndex;
1564 : };
1565 :
1566 : nsDataHashtable<nsGenericHashKey<MaskLayerKey>, RefPtr<ImageLayer>>
1567 : mRecycledMaskImageLayers;
1568 : // Keep display port of AGR to avoid wasting time on doing the same
1569 : // thing repeatly.
1570 : AnimatedGeometryRoot* mLastDisplayPortAGR;
1571 : nsRect mLastDisplayPortRect;
1572 :
1573 : // Cache ScrollMetadata so it doesn't need recomputed if the ASR and clip are unchanged.
1574 : // If mASR == nullptr then mMetadata is not valid.
1575 : struct CachedScrollMetadata {
1576 58 : const ActiveScrolledRoot* mASR;
1577 : const DisplayItemClip* mClip;
1578 : Maybe<ScrollMetadata> mMetadata;
1579 :
1580 : CachedScrollMetadata()
1581 : : mASR(nullptr), mClip(nullptr)
1582 58 : {}
1583 : };
1584 : CachedScrollMetadata mCachedScrollMetadata;
1585 : };
1586 :
1587 : bool
1588 : FLBDisplayItemIterator::ShouldFlattenNextItem()
1589 0 : {
1590 : if (!mNext) {
1591 503 : return false;
1592 : }
1593 :
1594 : if (!mNext->ShouldFlattenAway(mBuilder)) {
1595 474 : return false;
1596 : }
1597 :
1598 : if (mNext->GetType() == DisplayItemType::TYPE_OPACITY) {
1599 111 : nsDisplayOpacity* opacity = static_cast<nsDisplayOpacity*>(mNext);
1600 28 :
1601 : if (opacity->OpacityAppliedToChildren()) {
1602 0 : // This is the previous opacity flattening path, where the opacity has
1603 : // been applied to children.
1604 : return true;
1605 : }
1606 :
1607 : if (!mState->mManager->IsWidgetLayerManager()) {
1608 21 : // Do not flatten opacity inside an inactive layer tree.
1609 : return false;
1610 : }
1611 :
1612 : LayerState layerState = mNext->GetLayerState(mState->mBuilder,
1613 42 : mState->mManager,
1614 : mState->mParameters);
1615 0 :
1616 : // Do not flatten opacity if child display items require an active layer.
1617 : if (layerState != LayerState::LAYER_NONE &&
1618 21 : layerState != LayerState::LAYER_INACTIVE) {
1619 : return false;
1620 : }
1621 :
1622 : mStoreMarker = true;
1623 21 : }
1624 :
1625 : return true;
1626 : }
1627 :
1628 : class PaintedDisplayItemLayerUserData : public LayerUserData
1629 : {
1630 : public:
1631 : PaintedDisplayItemLayerUserData() :
1632 23 : mForcedBackgroundColor(NS_RGBA(0,0,0,0)),
1633 : mXScale(1.f), mYScale(1.f),
1634 : mAppUnitsPerDevPixel(0),
1635 : mTranslation(0, 0),
1636 : mAnimatedGeometryRootPosition(0, 0),
1637 : mLastItemCount(0),
1638 : mContainerLayerFrame(nullptr),
1639 : mHasExplicitLastPaintOffset(false),
1640 322 : mDisabledAlpha(false) {}
1641 :
1642 767 : NS_INLINE_DECL_REFCOUNTING(PaintedDisplayItemLayerUserData);
1643 :
1644 : /**
1645 : * A color that should be painted over the bounds of the layer's visible
1646 : * region before any other content is painted.
1647 : */
1648 : nscolor mForcedBackgroundColor;
1649 :
1650 : /**
1651 : * The resolution scale used.
1652 : */
1653 : float mXScale, mYScale;
1654 :
1655 : /**
1656 : * The appunits per dev pixel for the items in this layer.
1657 : */
1658 : nscoord mAppUnitsPerDevPixel;
1659 :
1660 : /**
1661 : * The offset from the PaintedLayer's 0,0 to the
1662 : * reference frame. This isn't necessarily the same as the transform
1663 : * set on the PaintedLayer since we might also be applying an extra
1664 : * offset specified by the parent ContainerLayer/
1665 : */
1666 : nsIntPoint mTranslation;
1667 :
1668 : /**
1669 : * We try to make 0,0 of the PaintedLayer be the top-left of the
1670 : * border-box of the "active scrolled root" frame (i.e. the nearest ancestor
1671 : * frame for the display items that is being actively scrolled). But
1672 : * we force the PaintedLayer transform to be an integer translation, and we may
1673 : * have a resolution scale, so we have to snap the PaintedLayer transform, so
1674 : * 0,0 may not be exactly the top-left of the active scrolled root. Here we
1675 : * store the coordinates in PaintedLayer space of the top-left of the
1676 : * active scrolled root.
1677 : */
1678 : gfxPoint mAnimatedGeometryRootPosition;
1679 :
1680 : nsIntRegion mRegionToInvalidate;
1681 :
1682 : // The offset between the active scrolled root of this layer
1683 : // and the root of the container for the previous and current
1684 : // paints respectively.
1685 : nsPoint mLastAnimatedGeometryRootOrigin;
1686 : nsPoint mAnimatedGeometryRootOrigin;
1687 :
1688 : RefPtr<ColorLayer> mColorLayer;
1689 : RefPtr<ImageLayer> mImageLayer;
1690 :
1691 : // The region for which display item visibility for this layer has already
1692 : // been calculated. Used to reduce the number of calls to
1693 : // RecomputeVisibilityForItems if it is known in advance that a larger
1694 : // region will be painted during a transaction than in a single call to
1695 : // DrawPaintedLayer, for example when progressive paint is enabled.
1696 : nsIntRegion mVisibilityComputedRegion;
1697 :
1698 : // The area for which we called RecomputeVisibilityForItems on the
1699 : // previous paint.
1700 : nsRect mPreviousRecomputeVisibilityRect;
1701 :
1702 : // The number of items assigned to this layer on the previous paint.
1703 : size_t mLastItemCount;
1704 :
1705 : // The translation set on this PaintedLayer before we started updating the
1706 : // layer tree.
1707 : nsIntPoint mLastPaintOffset;
1708 :
1709 : // Temporary state only valid during the FrameLayerBuilder's lifetime.
1710 : // FLB's mPaintedLayerItems is responsible for cleaning these up when
1711 : // we finish painting to avoid dangling pointers.
1712 : nsTArray<AssignedDisplayItem> mItems;
1713 : nsIFrame* mContainerLayerFrame;
1714 :
1715 : bool mHasExplicitLastPaintOffset;
1716 :
1717 : /**
1718 : * This is set when the painted layer has no component alpha.
1719 : */
1720 : bool mDisabledAlpha;
1721 :
1722 : protected:
1723 132 : ~PaintedDisplayItemLayerUserData() = default;
1724 : };
1725 :
1726 18 : FrameLayerBuilder::FrameLayerBuilder()
1727 : : mRetainingManager(nullptr)
1728 : , mDisplayListBuilder(nullptr)
1729 : , mContainingPaintedLayer(nullptr)
1730 : , mInactiveLayerClip(nullptr)
1731 : , mInvalidateAllLayers(false)
1732 36 : , mInLayerTreeCompressionMode(false)
1733 : , mIsInactiveLayerManager(false)
1734 18 : {
1735 18 : MOZ_COUNT_CTOR(FrameLayerBuilder);
1736 : }
1737 72 :
1738 : FrameLayerBuilder::~FrameLayerBuilder()
1739 0 : {
1740 112 : GetMaskLayerImageCache()->Sweep();
1741 0 : for (PaintedDisplayItemLayerUserData* userData : mPaintedLayerItems) {
1742 0 : userData->mItems.Clear();
1743 : userData->mContainerLayerFrame = nullptr;
1744 0 : }
1745 54 : MOZ_COUNT_DTOR(FrameLayerBuilder);
1746 : }
1747 :
1748 0 : void
1749 : FrameLayerBuilder::AddPaintedLayerItemsEntry(PaintedDisplayItemLayerUserData* aData)
1750 29 : {
1751 0 : mPaintedLayerItems.AppendElement(aData);
1752 : }
1753 :
1754 : /*
1755 : * User data for layers which will be used as masks.
1756 0 : */
1757 : struct MaskLayerUserData : public LayerUserData
1758 0 : {
1759 0 : MaskLayerUserData()
1760 : : mScaleX(-1.0f)
1761 0 : , mScaleY(-1.0f)
1762 0 : , mAppUnitsPerDevPixel(-1)
1763 0 : { }
1764 : MaskLayerUserData(const DisplayItemClip& aClip,
1765 : int32_t aAppUnitsPerDevPixel,
1766 0 : const ContainerLayerParameters& aParams)
1767 0 : : mScaleX(aParams.mXScale)
1768 : , mScaleY(aParams.mYScale)
1769 0 : , mOffset(aParams.mOffset)
1770 : , mAppUnitsPerDevPixel(aAppUnitsPerDevPixel)
1771 0 : {
1772 0 : aClip.AppendRoundedRects(&mRoundedClipRects);
1773 : }
1774 0 :
1775 : void operator=(MaskLayerUserData&& aOther)
1776 0 : {
1777 0 : mScaleX = aOther.mScaleX;
1778 0 : mScaleY = aOther.mScaleY;
1779 0 : mOffset = aOther.mOffset;
1780 0 : mAppUnitsPerDevPixel = aOther.mAppUnitsPerDevPixel;
1781 0 : mRoundedClipRects.SwapElements(aOther.mRoundedClipRects);
1782 : }
1783 :
1784 0 : bool
1785 : operator== (const MaskLayerUserData& aOther) const
1786 0 : {
1787 0 : return mRoundedClipRects == aOther.mRoundedClipRects &&
1788 0 : mScaleX == aOther.mScaleX &&
1789 0 : mScaleY == aOther.mScaleY &&
1790 0 : mOffset == aOther.mOffset &&
1791 : mAppUnitsPerDevPixel == aOther.mAppUnitsPerDevPixel;
1792 : }
1793 :
1794 : // Keeps a MaskLayerImageKey alive by managing its mLayerCount member-var
1795 : MaskLayerImageCache::MaskLayerImageKeyRef mImageKey;
1796 : // properties of the mask layer; the mask layer may be re-used if these
1797 : // remain unchanged.
1798 : nsTArray<DisplayItemClip::RoundedRect> mRoundedClipRects;
1799 : // scale from the masked layer which is applied to the mask
1800 : float mScaleX, mScaleY;
1801 : // The ContainerLayerParameters offset which is applied to the mask's transform.
1802 : nsIntPoint mOffset;
1803 : int32_t mAppUnitsPerDevPixel;
1804 : };
1805 :
1806 : /*
1807 : * User data for layers which will be used as masks for css positioned mask.
1808 0 : */
1809 : struct CSSMaskLayerUserData : public LayerUserData
1810 0 : {
1811 0 : CSSMaskLayerUserData()
1812 0 : : mMaskStyle(nsStyleImageLayers::LayerType::Mask)
1813 : { }
1814 0 :
1815 : CSSMaskLayerUserData(nsIFrame* aFrame, const nsIntRect& aMaskBounds,
1816 0 : const nsPoint& aMaskLayerOffset)
1817 0 : : mMaskBounds(aMaskBounds),
1818 0 : mMaskStyle(aFrame->StyleSVGReset()->mMask),
1819 : mMaskLayerOffset(aMaskLayerOffset)
1820 0 : {
1821 : }
1822 0 :
1823 : void operator=(CSSMaskLayerUserData&& aOther)
1824 0 : {
1825 0 : mMaskBounds = aOther.mMaskBounds;
1826 0 : mMaskStyle = std::move(aOther.mMaskStyle);
1827 0 : mMaskLayerOffset = aOther.mMaskLayerOffset;
1828 : }
1829 :
1830 0 : bool
1831 : operator==(const CSSMaskLayerUserData& aOther) const
1832 0 : {
1833 : if (!mMaskBounds.IsEqualInterior(aOther.mMaskBounds)) {
1834 : return false;
1835 : }
1836 :
1837 0 : // Make sure we draw the same portion of the mask onto mask layer.
1838 : if (mMaskLayerOffset != aOther.mMaskLayerOffset) {
1839 : return false;
1840 : }
1841 0 :
1842 : return mMaskStyle == aOther.mMaskStyle;
1843 : }
1844 :
1845 : private:
1846 : nsIntRect mMaskBounds;
1847 : nsStyleImageLayers mMaskStyle;
1848 : nsPoint mMaskLayerOffset; // The offset from the origin of mask bounds to
1849 : // the origin of mask layer.
1850 : };
1851 :
1852 : /*
1853 : * A helper object to create a draw target for painting mask and create a
1854 : * image container to hold the drawing result. The caller can then bind this
1855 : * image container with a image mask layer via ImageLayer::SetContainer.
1856 : */
1857 : class MaskImageData
1858 : {
1859 0 : public:
1860 0 : MaskImageData(const gfx::IntSize& aSize, LayerManager* aLayerManager)
1861 : : mTextureClientLocked(false)
1862 0 : , mSize(aSize)
1863 : , mLayerManager(aLayerManager)
1864 0 : {
1865 0 : MOZ_ASSERT(!mSize.IsEmpty());
1866 0 : MOZ_ASSERT(mLayerManager);
1867 : }
1868 0 :
1869 0 : ~MaskImageData()
1870 0 : {
1871 0 : if (mTextureClientLocked) {
1872 : MOZ_ASSERT(mTextureClient);
1873 0 : // Clear DrawTarget before Unlock.
1874 0 : mDrawTarget = nullptr;
1875 : mTextureClient->Unlock();
1876 0 : }
1877 : }
1878 0 :
1879 : gfx::DrawTarget* CreateDrawTarget()
1880 0 : {
1881 : if (mDrawTarget) {
1882 : return mDrawTarget;
1883 : }
1884 0 :
1885 0 : if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) {
1886 0 : mDrawTarget = mLayerManager->CreateOptimalMaskDrawTarget(mSize);
1887 : return mDrawTarget;
1888 : }
1889 0 :
1890 : MOZ_ASSERT(mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT ||
1891 : mLayerManager->GetBackendType() == LayersBackend::LAYERS_WR);
1892 0 :
1893 0 : KnowsCompositor* knowsCompositor = mLayerManager->AsKnowsCompositor();
1894 : if (!knowsCompositor) {
1895 : return nullptr;
1896 : }
1897 0 : mTextureClient =
1898 : TextureClient::CreateForDrawing(knowsCompositor,
1899 : SurfaceFormat::A8,
1900 : mSize,
1901 : BackendSelector::Content,
1902 0 : TextureFlags::DISALLOW_BIGIMAGE,
1903 0 : TextureAllocationFlags::ALLOC_CLEAR_BUFFER);
1904 : if (!mTextureClient) {
1905 : return nullptr;
1906 : }
1907 0 :
1908 0 : mTextureClientLocked = mTextureClient->Lock(OpenMode::OPEN_READ_WRITE);
1909 : if (!mTextureClientLocked) {
1910 : return nullptr;
1911 : }
1912 0 :
1913 0 : mDrawTarget = mTextureClient->BorrowDrawTarget();
1914 : return mDrawTarget;
1915 : }
1916 0 :
1917 : already_AddRefed<ImageContainer> CreateImageAndImageContainer()
1918 0 : {
1919 0 : RefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
1920 : RefPtr<Image> image = CreateImage();
1921 0 :
1922 : if (!image) {
1923 : return nullptr;
1924 0 : }
1925 : container->SetCurrentImageInTransaction(image);
1926 :
1927 : return container.forget();
1928 : }
1929 :
1930 0 : private:
1931 : already_AddRefed<Image> CreateImage()
1932 0 : {
1933 0 : if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC &&
1934 0 : mDrawTarget) {
1935 0 : RefPtr<SourceSurface> surface = mDrawTarget->Snapshot();
1936 : RefPtr<SourceSurfaceImage> image = new SourceSurfaceImage(mSize, surface);
1937 : // Disallow BIGIMAGE (splitting into multiple textures) for mask
1938 0 : // layer images
1939 0 : image->SetTextureFlags(TextureFlags::DISALLOW_BIGIMAGE);
1940 : return image.forget();
1941 : }
1942 0 :
1943 0 : if ((mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT ||
1944 0 : mLayerManager->GetBackendType() == LayersBackend::LAYERS_WR) &&
1945 0 : mTextureClient &&
1946 : mDrawTarget) {
1947 0 : RefPtr<TextureWrapperImage> image =
1948 0 : new TextureWrapperImage(mTextureClient, gfx::IntRect(gfx::IntPoint(0, 0), mSize));
1949 : return image.forget();
1950 : }
1951 :
1952 : return nullptr;
1953 : }
1954 :
1955 : bool mTextureClientLocked;
1956 : gfx::IntSize mSize;
1957 : LayerManager* mLayerManager;
1958 : RefPtr<gfx::DrawTarget> mDrawTarget;
1959 : RefPtr<TextureClient> mTextureClient;
1960 : };
1961 :
1962 37 : static PaintedDisplayItemLayerUserData*
1963 : GetPaintedDisplayItemLayerUserData(Layer* aLayer)
1964 : {
1965 37 : return static_cast<PaintedDisplayItemLayerUserData*>(
1966 : aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
1967 : }
1968 :
1969 0 : /* static */ void
1970 : FrameLayerBuilder::Shutdown()
1971 0 : {
1972 0 : if (gMaskLayerImageCache) {
1973 0 : delete gMaskLayerImageCache;
1974 : gMaskLayerImageCache = nullptr;
1975 0 : }
1976 : }
1977 :
1978 0 : void
1979 : FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
1980 : PaintedLayerData* aLayerData,
1981 : bool aIsInactiveLayerManager,
1982 : const DisplayItemClip* aInactiveLayerClip)
1983 18 : {
1984 54 : mDisplayListBuilder = aBuilder;
1985 0 : mRootPresContext = aBuilder->RootReferenceFrame()->PresContext()->GetRootPresContext();
1986 18 : mContainingPaintedLayer = aLayerData;
1987 18 : mIsInactiveLayerManager = aIsInactiveLayerManager;
1988 18 : mInactiveLayerClip = aInactiveLayerClip;
1989 18 : aManager->SetUserData(&gLayerManagerLayerBuilder, this);
1990 : }
1991 :
1992 0 : void
1993 : FrameLayerBuilder::FlashPaint(gfxContext *aContext)
1994 0 : {
1995 0 : float r = float(rand()) / RAND_MAX;
1996 0 : float g = float(rand()) / RAND_MAX;
1997 0 : float b = float(rand()) / RAND_MAX;
1998 0 : aContext->SetColor(Color(r, g, b, 0.4f));
1999 0 : aContext->Paint();
2000 : }
2001 :
2002 0 : DisplayItemData*
2003 : FrameLayerBuilder::GetDisplayItemData(nsIFrame* aFrame, uint32_t aKey)
2004 0 : {
2005 0 : const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
2006 0 : for (uint32_t i = 0; i < array.Length(); i++) {
2007 563 : DisplayItemData* item = DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
2008 236 : if (item->mDisplayItemKey == aKey &&
2009 : item->mLayer->Manager() == mRetainingManager) {
2010 : return item;
2011 : }
2012 : }
2013 : return nullptr;
2014 : }
2015 :
2016 : #ifdef MOZ_DUMP_PAINTING
2017 0 : static nsACString&
2018 : AppendToString(nsACString& s, const nsIntRect& r,
2019 : const char* pfx="", const char* sfx="")
2020 0 : {
2021 0 : s += pfx;
2022 : s += nsPrintfCString(
2023 0 : "(x=%d, y=%d, w=%d, h=%d)",
2024 0 : r.x, r.y, r.width, r.height);
2025 : return s += sfx;
2026 : }
2027 :
2028 0 : static nsACString&
2029 : AppendToString(nsACString& s, const nsIntRegion& r,
2030 : const char* pfx="", const char* sfx="")
2031 0 : {
2032 : s += pfx;
2033 0 :
2034 0 : s += "< ";
2035 0 : for (auto iter = r.RectIter(); !iter.Done(); iter.Next()) {
2036 : AppendToString(s, iter.Get()) += "; ";
2037 0 : }
2038 : s += ">";
2039 0 :
2040 : return s += sfx;
2041 : }
2042 : #endif // MOZ_DUMP_PAINTING
2043 :
2044 : /**
2045 : * Invalidate aRegion in aLayer. aLayer is in the coordinate system
2046 : * *after* aTranslation has been applied, so we need to
2047 : * apply the inverse of that transform before calling InvalidateRegion.
2048 : */
2049 54 : static void
2050 : InvalidatePostTransformRegion(PaintedLayer* aLayer, const nsIntRegion& aRegion,
2051 : const nsIntPoint& aTranslation)
2052 : {
2053 : // Convert the region from the coordinates of the container layer
2054 : // (relative to the snapped top-left of the display list reference frame)
2055 108 : // to the PaintedLayer's own coordinates
2056 0 : nsIntRegion rgn = aRegion;
2057 54 : rgn.MoveBy(-aTranslation);
2058 : aLayer->InvalidateRegion(rgn);
2059 54 : #ifdef MOZ_DUMP_PAINTING
2060 0 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2061 0 : nsAutoCString str;
2062 0 : AppendToString(str, rgn);
2063 : printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
2064 : }
2065 54 : #endif
2066 : }
2067 :
2068 1 : static void
2069 : InvalidatePostTransformRegion(PaintedLayer* aLayer, const nsRect& aRect,
2070 : const DisplayItemClip& aClip,
2071 : const nsIntPoint& aTranslation)
2072 : {
2073 4 : PaintedDisplayItemLayerUserData* data =
2074 : static_cast<PaintedDisplayItemLayerUserData*>(aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
2075 0 :
2076 : nsRect rect = aClip.ApplyNonRoundedIntersection(aRect);
2077 2 :
2078 4 : nsIntRect pixelRect = rect.ScaleToOutsidePixels(data->mXScale, data->mYScale, data->mAppUnitsPerDevPixel);
2079 2 : InvalidatePostTransformRegion(aLayer, pixelRect, aTranslation);
2080 : }
2081 :
2082 :
2083 51 : static nsIntPoint
2084 : GetTranslationForPaintedLayer(PaintedLayer* aLayer)
2085 : {
2086 : PaintedDisplayItemLayerUserData* data =
2087 102 : static_cast<PaintedDisplayItemLayerUserData*>
2088 51 : (aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
2089 : NS_ASSERTION(data, "Must be a tracked painted layer!");
2090 0 :
2091 : return data->mTranslation;
2092 : }
2093 :
2094 : /**
2095 : * Some frames can have multiple, nested, retaining layer managers
2096 : * associated with them (normal manager, inactive managers, SVG effects).
2097 : * In these cases we store the 'outermost' LayerManager data property
2098 : * on the frame since we can walk down the chain from there.
2099 : *
2100 : * If one of these frames has just been destroyed, we will free the inner
2101 : * layer manager when removing the entry from mFramesWithLayers. Destroying
2102 : * the layer manager destroys the LayerManagerData and calls into
2103 : * the DisplayItemData destructor. If the inner layer manager had any
2104 : * items with the same frame, then we attempt to retrieve properties
2105 : * from the deleted frame.
2106 : *
2107 : * Cache the destroyed frame pointer here so we can avoid crashing in this case.
2108 : */
2109 :
2110 48 : /* static */ void
2111 : FrameLayerBuilder::RemoveFrameFromLayerManager(const nsIFrame* aFrame,
2112 : SmallPointerArray<DisplayItemData>& aArray)
2113 48 : {
2114 48 : MOZ_RELEASE_ASSERT(!sDestroyedFrame);
2115 : sDestroyedFrame = aFrame;
2116 :
2117 : // Hold a reference to all the items so that they don't get
2118 96 : // deleted from under us.
2119 102 : nsTArray<RefPtr<DisplayItemData> > arrayCopy;
2120 0 : for (DisplayItemData* data : aArray) {
2121 : arrayCopy.AppendElement(data);
2122 : }
2123 :
2124 : #ifdef DEBUG_DISPLAY_ITEM_DATA
2125 : if (aArray->Length()) {
2126 : LayerManagerData *rootData = aArray->ElementAt(0)->mParent;
2127 : while (rootData->mParent) {
2128 : rootData = rootData->mParent;
2129 : }
2130 : printf_stderr("Removing frame %p - dumping display data\n", aFrame);
2131 : rootData->Dump();
2132 : }
2133 : #endif
2134 102 :
2135 12 : for (DisplayItemData* data : aArray) {
2136 6 : PaintedLayer* t = data->mLayer ? data->mLayer->AsPaintedLayer() : nullptr;
2137 : if (t) {
2138 12 : PaintedDisplayItemLayerUserData* paintedData =
2139 12 : static_cast<PaintedDisplayItemLayerUserData*>(t->GetUserData(&gPaintedDisplayItemLayerUserData));
2140 18 : if (paintedData && data->mGeometry) {
2141 0 : nsRegion old = data->mGeometry->ComputeInvalidationRegion();
2142 0 : nsIntRegion rgn = old.ScaleToOutsidePixels(paintedData->mXScale, paintedData->mYScale, paintedData->mAppUnitsPerDevPixel);
2143 0 : rgn.MoveBy(-GetTranslationForPaintedLayer(t));
2144 12 : paintedData->mRegionToInvalidate.Or(paintedData->mRegionToInvalidate, rgn);
2145 : paintedData->mRegionToInvalidate.SimplifyOutward(8);
2146 : }
2147 : }
2148 0 :
2149 0 : data->Disconnect();
2150 : auto it = std::find(data->mParent->mDisplayItems.begin(),
2151 : data->mParent->mDisplayItems.end(),
2152 48 : data);
2153 48 : MOZ_ASSERT(it != data->mParent->mDisplayItems.end());
2154 48 : std::iter_swap(it, data->mParent->mDisplayItems.end() - 1);
2155 : data->mParent->mDisplayItems.pop_back();
2156 : }
2157 7 :
2158 : arrayCopy.Clear();
2159 0 : sDestroyedFrame = nullptr;
2160 : }
2161 0 :
2162 7 : void
2163 6 : FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager)
2164 : {
2165 1 : mRetainingManager = aManager;
2166 0 : LayerManagerData* data = static_cast<LayerManagerData*>
2167 : (aManager->GetUserData(&gLayerManagerUserData));
2168 0 : if (data) {
2169 : mInvalidateAllLayers = data->mInvalidateAllLayers;
2170 : } else {
2171 18 : data = new LayerManagerData(aManager);
2172 : aManager->SetUserData(&gLayerManagerUserData, data);
2173 0 : }
2174 18 : }
2175 :
2176 : void
2177 18 : FrameLayerBuilder::DidEndTransaction()
2178 : {
2179 18 : GetMaskLayerImageCache()->Sweep();
2180 : }
2181 :
2182 : void
2183 : FrameLayerBuilder::WillEndTransaction()
2184 : {
2185 14 : if (!mRetainingManager) {
2186 0 : return;
2187 : }
2188 :
2189 537 : // We need to save the data we'll need to support retaining.
2190 516 : LayerManagerData* data = static_cast<LayerManagerData*>
2191 258 : (mRetainingManager->GetUserData(&gLayerManagerUserData));
2192 : NS_ASSERTION(data, "Must have data!");
2193 0 :
2194 4 : // Update all the frames that used to have layers.
2195 : auto iter = data->mDisplayItems.begin();
2196 0 : while (iter != data->mDisplayItems.end()) {
2197 0 : DisplayItemData* did = iter->get();
2198 : if (!did->mUsed) {
2199 : // This item was visible, but isn't anymore.
2200 0 : PaintedLayer* t = did->mLayer->AsPaintedLayer();
2201 : if (t && did->mGeometry) {
2202 : #ifdef MOZ_DUMP_PAINTING
2203 0 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2204 : printf_stderr("Invalidating unused display item (%i) belonging to frame %p from layer %p\n", did->mDisplayItemKey, did->mFrameList[0], t);
2205 : }
2206 2 : #endif
2207 0 : InvalidatePostTransformRegion(t,
2208 2 : did->mGeometry->ComputeInvalidationRegion(),
2209 : did->mClip,
2210 0 : GetLastPaintOffset(t));
2211 : }
2212 :
2213 : did->ClearAnimationCompositorState();
2214 0 : did->Disconnect();
2215 :
2216 : // Remove this item. Swapping it with the last element first is
2217 : // quicker than erasing from the middle.
2218 0 : if (iter != data->mDisplayItems.end() - 1) {
2219 : std::iter_swap(iter, data->mDisplayItems.end() - 1);
2220 : data->mDisplayItems.pop_back();
2221 : } else {
2222 0 : data->mDisplayItems.pop_back();
2223 0 : break;
2224 0 : }
2225 0 :
2226 0 : // Don't increment iter because we still need to process the item which was moved.
2227 :
2228 : } else {
2229 : ComputeGeometryChangeForItem(did);
2230 : iter++;
2231 : }
2232 : }
2233 :
2234 19 : data->mInvalidateAllLayers = false;
2235 : }
2236 :
2237 19 : /* static */ DisplayItemData*
2238 21 : FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem,
2239 13 : LayerManager* aManager)
2240 : {
2241 : const SmallPointerArray<DisplayItemData>& array =
2242 : aItem->Frame()->DisplayItemData();
2243 32 : for (uint32_t i = 0; i < array.Length(); i++) {
2244 0 : DisplayItemData* item = DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
2245 : if (item->mDisplayItemKey == aItem->GetPerFrameKey() &&
2246 0 : item->mLayer->Manager() == aManager) {
2247 : return item;
2248 : }
2249 : }
2250 0 : return nullptr;
2251 : }
2252 :
2253 : bool
2254 360 : FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
2255 : {
2256 : const SmallPointerArray<DisplayItemData>& array =
2257 0 : aFrame->DisplayItemData();
2258 301 : for (uint32_t i = 0; i < array.Length(); i++) {
2259 95 : if (DisplayItemData::AssertDisplayItemData(array.ElementAt(i))->mDisplayItemKey == aDisplayItemKey) {
2260 : return true;
2261 0 : }
2262 : }
2263 301 : if (RefPtr<WebRenderUserData> data = GetWebRenderUserData<WebRenderFallbackData>(aFrame, aDisplayItemKey)) {
2264 : return true;
2265 : }
2266 0 : return false;
2267 : }
2268 :
2269 : DisplayItemData*
2270 0 : FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey, DisplayItemData* aOldData /* = nullptr */)
2271 : {
2272 : // If we need to build a new layer tree, then just refuse to recycle
2273 : // anything.
2274 69 : if (!mRetainingManager || mInvalidateAllLayers)
2275 69 : return nullptr;
2276 :
2277 0 : DisplayItemData* data = aOldData;
2278 69 : if (!data || data->Disconnected() || data->mLayer->Manager() != mRetainingManager) {
2279 6 : data = GetDisplayItemData(aFrame, aDisplayItemKey);
2280 0 : }
2281 : MOZ_ASSERT(data == GetDisplayItemData(aFrame, aDisplayItemKey));
2282 0 :
2283 0 : if (data && data->mLayer->Manager() == mRetainingManager) {
2284 : return data;
2285 0 : }
2286 : return nullptr;
2287 : }
2288 :
2289 : Layer*
2290 : FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem,
2291 : nsDisplayItemGeometry** aOldGeometry,
2292 0 : DisplayItemClip** aOldClip)
2293 : {
2294 0 : uint32_t key = aItem->GetPerFrameKey();
2295 : nsIFrame* frame = aItem->Frame();
2296 0 :
2297 0 : DisplayItemData* oldData = GetOldLayerForFrame(frame, key);
2298 : if (oldData) {
2299 0 : if (aOldGeometry) {
2300 : *aOldGeometry = oldData->mGeometry.get();
2301 : }
2302 : if (aOldClip) {
2303 : *aOldClip = &oldData->mClip;
2304 : }
2305 : return oldData->mLayer;
2306 : }
2307 :
2308 12 : return nullptr;
2309 : }
2310 :
2311 12 : /* static */ DisplayItemData*
2312 24 : FrameLayerBuilder::GetOldDataFor(nsDisplayItem* aItem)
2313 12 : {
2314 : const SmallPointerArray<DisplayItemData>& array = aItem->Frame()->DisplayItemData();
2315 :
2316 0 : for (uint32_t i = 0; i < array.Length(); i++) {
2317 : DisplayItemData *data = DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
2318 :
2319 0 : if (data->mDisplayItemKey == aItem->GetPerFrameKey()) {
2320 0 : return data;
2321 0 : }
2322 0 : }
2323 0 : return nullptr;
2324 : }
2325 :
2326 0 : // Reset state that should not persist when a layer is recycled.
2327 0 : static void
2328 : ResetLayerStateForRecycling(Layer* aLayer) {
2329 : // Currently, this clears the mask layer and ancestor mask layers.
2330 0 : // Other cleanup may be added here.
2331 0 : aLayer->SetMaskLayer(nullptr);
2332 : aLayer->SetAncestorMaskLayers({});
2333 : }
2334 0 :
2335 : already_AddRefed<ColorLayer>
2336 : ContainerState::CreateOrRecycleColorLayer(PaintedLayer *aPainted)
2337 : {
2338 : PaintedDisplayItemLayerUserData* data =
2339 : static_cast<PaintedDisplayItemLayerUserData*>(aPainted->GetUserData(&gPaintedDisplayItemLayerUserData));
2340 0 : RefPtr<ColorLayer> layer = data->mColorLayer;
2341 : if (layer) {
2342 : ResetLayerStateForRecycling(layer);
2343 0 : layer->ClearExtraDumpInfo();
2344 0 : } else {
2345 0 : // Create a new layer
2346 0 : layer = mManager->CreateColorLayer();
2347 0 : if (!layer)
2348 : return nullptr;
2349 : // Mark this layer as being used for painting display items
2350 0 : data->mColorLayer = layer;
2351 0 : layer->SetUserData(&gColorLayerUserData, nullptr);
2352 :
2353 : // Remove other layer types we might have stored for this PaintedLayer
2354 0 : data->mImageLayer = nullptr;
2355 0 : }
2356 : return layer.forget();
2357 : }
2358 0 :
2359 : already_AddRefed<ImageLayer>
2360 : ContainerState::CreateOrRecycleImageLayer(PaintedLayer *aPainted)
2361 : {
2362 : PaintedDisplayItemLayerUserData* data =
2363 : static_cast<PaintedDisplayItemLayerUserData*>(aPainted->GetUserData(&gPaintedDisplayItemLayerUserData));
2364 : RefPtr<ImageLayer> layer = data->mImageLayer;
2365 0 : if (layer) {
2366 : ResetLayerStateForRecycling(layer);
2367 : layer->ClearExtraDumpInfo();
2368 : } else {
2369 : // Create a new layer
2370 0 : layer = mManager->CreateImageLayer();
2371 : if (!layer)
2372 0 : return nullptr;
2373 0 : // Mark this layer as being used for painting display items
2374 0 : data->mImageLayer = layer;
2375 : layer->SetUserData(&gImageLayerUserData, nullptr);
2376 :
2377 : // Remove other layer types we might have stored for this PaintedLayer
2378 0 : data->mColorLayer = nullptr;
2379 0 : }
2380 : return layer.forget();
2381 : }
2382 0 :
2383 : template<typename UserData>
2384 : already_AddRefed<ImageLayer>
2385 : ContainerState::CreateOrRecycleMaskImageLayerFor(
2386 : const MaskLayerKey& aKey,
2387 : UserData* (*aGetUserData)(Layer* aLayer),
2388 : void (*aSetDefaultUserData)(Layer* aLayer))
2389 : {
2390 : RefPtr<ImageLayer> result = mRecycledMaskImageLayers.Get(aKey);
2391 :
2392 : if (result && aGetUserData(result.get())) {
2393 : mRecycledMaskImageLayers.Remove(aKey);
2394 : aKey.mLayer->ClearExtraDumpInfo();
2395 : // XXX if we use clip on mask layers, null it out here
2396 : } else {
2397 : // Create a new layer
2398 58 : result = mManager->CreateImageLayer();
2399 : if (!result) {
2400 58 : return nullptr;
2401 58 : }
2402 58 : aSetDefaultUserData(result);
2403 0 : }
2404 :
2405 0 : return result.forget();
2406 : }
2407 0 :
2408 0 : static const double SUBPIXEL_OFFSET_EPSILON = 0.02;
2409 :
2410 0 : /**
2411 : * This normally computes NSToIntRoundUp(aValue). However, if that would
2412 : * give a residual near 0.5 while aOldResidual is near -0.5, or
2413 : * it would give a residual near -0.5 while aOldResidual is near 0.5, then
2414 : * instead we return the integer in the other direction so that the residual
2415 : * is close to aOldResidual.
2416 : */
2417 0 : static int32_t
2418 : RoundToMatchResidual(double aValue, double aOldResidual)
2419 23 : {
2420 23 : int32_t v = NSToIntRoundUp(aValue);
2421 0 : double residual = aValue - v;
2422 : if (aOldResidual < 0) {
2423 23 : if (residual > 0 && fabs(residual - 1.0 - aOldResidual) < SUBPIXEL_OFFSET_EPSILON) {
2424 : // Round up instead
2425 : return int32_t(ceil(aValue));
2426 0 : }
2427 : } else if (aOldResidual > 0) {
2428 : if (residual < 0 && fabs(residual + 1.0 - aOldResidual) < SUBPIXEL_OFFSET_EPSILON) {
2429 0 : // Round down instead
2430 0 : return int32_t(floor(aValue));
2431 : }
2432 : }
2433 0 : return v;
2434 0 : }
2435 0 :
2436 0 : static void
2437 : ResetScrollPositionForLayerPixelAlignment(AnimatedGeometryRoot* aAnimatedGeometryRoot)
2438 : {
2439 40 : nsIScrollableFrame* sf = nsLayoutUtils::GetScrollableFrameFor(*aAnimatedGeometryRoot);
2440 : if (sf) {
2441 : sf->ResetScrollPositionForLayerPixelAlignment();
2442 : }
2443 : }
2444 :
2445 40 : static void
2446 : InvalidateEntirePaintedLayer(PaintedLayer* aLayer, AnimatedGeometryRoot* aAnimatedGeometryRoot, const char *aReason)
2447 : {
2448 : #ifdef MOZ_DUMP_PAINTING
2449 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2450 : printf_stderr("Invalidating entire layer %p: %s\n", aLayer, aReason);
2451 0 : }
2452 0 : #endif
2453 0 : aLayer->InvalidateWholeLayer();
2454 0 : aLayer->SetInvalidRectToVisibleRegion();
2455 0 : ResetScrollPositionForLayerPixelAlignment(aAnimatedGeometryRoot);
2456 : }
2457 :
2458 0 : LayerManager::PaintedLayerCreationHint
2459 0 : ContainerState::GetLayerCreationHint(AnimatedGeometryRoot* aAnimatedGeometryRoot)
2460 : {
2461 : // Check whether the layer will be scrollable. This is used as a hint to
2462 : // influence whether tiled layers are used or not.
2463 :
2464 : // Check creation hint inherited from our parent.
2465 : if (mParameters.mLayerCreationHint == LayerManager::SCROLLABLE) {
2466 : return LayerManager::SCROLLABLE;
2467 69 : }
2468 :
2469 : // Check whether there's any active scroll frame on the animated geometry
2470 : // root chain.
2471 : for (AnimatedGeometryRoot* agr = aAnimatedGeometryRoot;
2472 69 : agr && agr != mContainerAnimatedGeometryRoot;
2473 69 : agr = agr->mParentAGR) {
2474 : nsIFrame* fParent = nsLayoutUtils::GetCrossDocParentFrame(*agr);
2475 : if (!fParent) {
2476 : break;
2477 6 : }
2478 : nsIScrollableFrame* scrollable = do_QueryFrame(fParent);
2479 : if (scrollable) {
2480 : return LayerManager::SCROLLABLE;
2481 : }
2482 : }
2483 12 : return LayerManager::NONE;
2484 : }
2485 :
2486 : already_AddRefed<PaintedLayer>
2487 6 : ContainerState::AttemptToRecyclePaintedLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot,
2488 : nsDisplayItem* aItem,
2489 : const nsPoint& aTopLeft,
2490 : const nsIFrame* aReferenceFrame)
2491 6 : {
2492 : Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem);
2493 6 : if (!oldLayer || !oldLayer->AsPaintedLayer()) {
2494 0 : return nullptr;
2495 12 : }
2496 :
2497 6 : if (!mPaintedLayersAvailableForRecycling.EnsureRemoved(oldLayer->AsPaintedLayer())) {
2498 : // Not found.
2499 : return nullptr;
2500 : }
2501 :
2502 0 : // Try to recycle the layer.
2503 : RefPtr<PaintedLayer> layer = oldLayer->AsPaintedLayer();
2504 :
2505 22 : // Check if the layer hint has changed and whether or not the layer should
2506 22 : // be recreated because of it.
2507 22 : if (!layer->IsOptimizedFor(GetLayerCreationHint(aAnimatedGeometryRoot))) {
2508 : return nullptr;
2509 : }
2510 23 :
2511 : bool didResetScrollPositionForLayerPixelAlignment = false;
2512 : PaintedDisplayItemLayerUserData* data =
2513 0 : RecyclePaintedLayer(layer, aAnimatedGeometryRoot,
2514 : didResetScrollPositionForLayerPixelAlignment);
2515 : PreparePaintedLayerForUse(layer, data, aAnimatedGeometryRoot,
2516 69 : aReferenceFrame, aTopLeft,
2517 0 : didResetScrollPositionForLayerPixelAlignment);
2518 :
2519 : return layer.forget();
2520 : }
2521 :
2522 46 : void ReleaseLayerUserData(void* aData)
2523 0 : {
2524 0 : PaintedDisplayItemLayerUserData* userData =
2525 23 : static_cast<PaintedDisplayItemLayerUserData*>(aData);
2526 46 : userData->Release();
2527 23 : }
2528 :
2529 0 : already_AddRefed<PaintedLayer>
2530 : ContainerState::CreatePaintedLayer(PaintedLayerData* aData)
2531 0 : {
2532 : LayerManager::PaintedLayerCreationHint creationHint =
2533 0 : GetLayerCreationHint(aData->mAnimatedGeometryRoot);
2534 :
2535 : // Create a new painted layer
2536 : RefPtr<PaintedLayer> layer = mManager->CreatePaintedLayerWithHint(creationHint);
2537 6 : if (!layer) {
2538 : return nullptr;
2539 : }
2540 :
2541 : // Mark this layer as being used for painting display items
2542 : RefPtr<PaintedDisplayItemLayerUserData> userData = new PaintedDisplayItemLayerUserData();
2543 6 : userData->mDisabledAlpha =
2544 0 : mParameters.mDisableSubpixelAntialiasingInDescendants;
2545 : userData.get()->AddRef();
2546 : layer->SetUserData(&gPaintedDisplayItemLayerUserData, userData, ReleaseLayerUserData);
2547 : ResetScrollPositionForLayerPixelAlignment(aData->mAnimatedGeometryRoot);
2548 12 :
2549 6 : PreparePaintedLayerForUse(layer, userData, aData->mAnimatedGeometryRoot,
2550 : aData->mReferenceFrame,
2551 : aData->mAnimatedGeometryRootOffset, true);
2552 :
2553 : return layer.forget();
2554 : }
2555 :
2556 : PaintedDisplayItemLayerUserData*
2557 : ContainerState::RecyclePaintedLayer(PaintedLayer* aLayer,
2558 : AnimatedGeometryRoot* aAnimatedGeometryRoot,
2559 18 : bool& didResetScrollPositionForLayerPixelAlignment)
2560 12 : {
2561 6 : // Clear clip rect and mask layer so we don't accidentally stay clipped.
2562 : // We will reapply any necessary clipping.
2563 0 : ResetLayerStateForRecycling(aLayer);
2564 0 : aLayer->ClearExtraDumpInfo();
2565 :
2566 : PaintedDisplayItemLayerUserData* data =
2567 0 : static_cast<PaintedDisplayItemLayerUserData*>(
2568 0 : aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
2569 : NS_ASSERTION(data, "Recycled PaintedLayers must have user data");
2570 0 :
2571 : // This gets called on recycled PaintedLayers that are going to be in the
2572 1 : // final layer tree, so it's a convenient time to invalidate the
2573 0 : // content that changed where we don't know what PaintedLayer it belonged
2574 : // to, or if we need to invalidate the entire layer, we can do that.
2575 : // This needs to be done before we update the PaintedLayer to its new
2576 1 : // transform. See nsGfxScrollFrame::InvalidateInternal, where
2577 : // we ensure that mInvalidPaintedContent is updated according to the
2578 1 : // scroll position as of the most recent paint.
2579 0 : if (!FuzzyEqual(data->mXScale, mParameters.mXScale, 0.00001f) ||
2580 0 : !FuzzyEqual(data->mYScale, mParameters.mYScale, 0.00001f) ||
2581 0 : data->mAppUnitsPerDevPixel != mAppUnitsPerDevPixel) {
2582 : #ifdef MOZ_DUMP_PAINTING
2583 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2584 1 : printf_stderr("Recycled layer %p changed scale\n", aLayer);
2585 : }
2586 1 : #endif
2587 : InvalidateEntirePaintedLayer(aLayer, aAnimatedGeometryRoot, "recycled layer changed state");
2588 : didResetScrollPositionForLayerPixelAlignment = true;
2589 : }
2590 29 : if (!data->mRegionToInvalidate.IsEmpty()) {
2591 : #ifdef MOZ_DUMP_PAINTING
2592 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2593 : printf_stderr("Invalidating deleted frame content from layer %p\n", aLayer);
2594 : }
2595 : #endif
2596 : aLayer->InvalidateRegion(data->mRegionToInvalidate);
2597 0 : #ifdef MOZ_DUMP_PAINTING
2598 29 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
2599 29 : nsAutoCString str;
2600 29 : AppendToString(str, data->mRegionToInvalidate);
2601 29 : printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
2602 58 : }
2603 : #endif
2604 0 : data->mRegionToInvalidate.SetEmpty();
2605 0 : }
2606 : return data;
2607 : }
2608 :
2609 0 : void
2610 58 : ContainerState::PreparePaintedLayerForUse(PaintedLayer* aLayer,
2611 : PaintedDisplayItemLayerUserData* aData,
2612 0 : AnimatedGeometryRoot* aAnimatedGeometryRoot,
2613 116 : const nsIFrame* aReferenceFrame,
2614 : const nsPoint& aTopLeft,
2615 : bool didResetScrollPositionForLayerPixelAlignment)
2616 : {
2617 0 : aData->mXScale = mParameters.mXScale;
2618 29 : aData->mYScale = mParameters.mYScale;
2619 0 : aData->mLastAnimatedGeometryRootOrigin = aData->mAnimatedGeometryRootOrigin;
2620 0 : aData->mAnimatedGeometryRootOrigin = aTopLeft;
2621 29 : aData->mAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
2622 : aLayer->SetAllowResidualTranslation(mParameters.AllowResidualTranslation());
2623 58 :
2624 : aData->mLastPaintOffset = GetTranslationForPaintedLayer(aLayer);
2625 : aData->mHasExplicitLastPaintOffset = true;
2626 :
2627 0 : // Set up transform so that 0,0 in the PaintedLayer corresponds to the
2628 : // (pixel-snapped) top-left of the aAnimatedGeometryRoot.
2629 29 : nsPoint offset = (*aAnimatedGeometryRoot)->GetOffsetToCrossDoc(aReferenceFrame);
2630 0 : nscoord appUnitsPerDevPixel = (*aAnimatedGeometryRoot)->PresContext()->AppUnitsPerDevPixel();
2631 0 : gfxPoint scaledOffset(
2632 0 : NSAppUnitsToDoublePixels(offset.x, appUnitsPerDevPixel)*mParameters.mXScale,
2633 0 : NSAppUnitsToDoublePixels(offset.y, appUnitsPerDevPixel)*mParameters.mYScale);
2634 0 : // We call RoundToMatchResidual here so that the residual after rounding
2635 : // is close to aData->mAnimatedGeometryRootPosition if possible.
2636 : nsIntPoint pixOffset(RoundToMatchResidual(scaledOffset.x, aData->mAnimatedGeometryRootPosition.x),
2637 : RoundToMatchResidual(scaledOffset.y, aData->mAnimatedGeometryRootPosition.y));
2638 : aData->mTranslation = pixOffset;
2639 : pixOffset += mParameters.mOffset;
2640 : Matrix matrix = Matrix::Translation(pixOffset.x, pixOffset.y);
2641 : aLayer->SetBaseTransform(Matrix4x4::From2D(matrix));
2642 29 :
2643 0 : aData->mVisibilityComputedRegion.SetEmpty();
2644 0 :
2645 29 : // Calculate exact position of the top-left of the active scrolled root.
2646 23 : // This might not be 0,0 due to the snapping in ScaleToNearestPixels.
2647 : gfxPoint animatedGeometryRootTopLeft = scaledOffset - ThebesPoint(matrix.GetTranslation()) + mParameters.mOffset;
2648 : const bool disableAlpha =
2649 : mParameters.mDisableSubpixelAntialiasingInDescendants;
2650 : if (aData->mDisabledAlpha != disableAlpha) {
2651 : aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
2652 : InvalidateEntirePaintedLayer(aLayer, aAnimatedGeometryRoot, "change of subpixel-AA");
2653 : aData->mDisabledAlpha = disableAlpha;
2654 : return;
2655 : }
2656 :
2657 : // FIXME: Temporary workaround for bug 681192 and bug 724786.
2658 571 : #ifndef MOZ_WIDGET_ANDROID
2659 : // If it has changed, then we need to invalidate the entire layer since the
2660 : // pixels in the layer buffer have the content at a (subpixel) offset
2661 : // from what we need.
2662 : if (!animatedGeometryRootTopLeft.WithinEpsilonOf(aData->mAnimatedGeometryRootPosition, SUBPIXEL_OFFSET_EPSILON)) {
2663 : aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
2664 571 : InvalidateEntirePaintedLayer(aLayer, aAnimatedGeometryRoot, "subpixel offset");
2665 0 : } else if (didResetScrollPositionForLayerPixelAlignment) {
2666 : aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
2667 1142 : }
2668 : #else
2669 : Unused << didResetScrollPositionForLayerPixelAlignment;
2670 : #endif
2671 : }
2672 :
2673 : #if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
2674 : /**
2675 : * Returns the appunits per dev pixel for the item's frame
2676 : */
2677 : static int32_t
2678 : AppUnitsPerDevPixel(nsDisplayItem* aItem)
2679 40 : {
2680 : // The underlying frame for zoom items is the root frame of the subdocument.
2681 : // But zoom display items report their bounds etc using the parent document's
2682 : // APD because zoom items act as a conversion layer between the two different
2683 40 : // APDs.
2684 40 : if (aItem->GetType() == DisplayItemType::TYPE_ZOOM) {
2685 40 : return static_cast<nsDisplayZoom*>(aItem)->GetParentAppUnitsPerDevPixel();
2686 0 : }
2687 : return aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
2688 0 : }
2689 : #endif
2690 0 :
2691 0 : /**
2692 0 : * Set the visible region for aLayer.
2693 0 : * aOuterVisibleRegion is the visible region relative to the parent layer.
2694 : * aLayerContentsVisibleRect, if non-null, is a rectangle in the layer's
2695 : * own coordinate system to which the layer's visible region is restricted.
2696 0 : * Consumes *aOuterVisibleRegion.
2697 : */
2698 : static void
2699 0 : SetOuterVisibleRegion(Layer* aLayer, nsIntRegion* aOuterVisibleRegion,
2700 0 : const nsIntRect* aLayerContentsVisibleRect = nullptr,
2701 : bool aOuterUntransformed = false)
2702 : {
2703 0 : Matrix4x4 transform = aLayer->GetTransform();
2704 0 : Matrix transform2D;
2705 0 : if (aOuterUntransformed) {
2706 : if (aLayerContentsVisibleRect) {
2707 : aOuterVisibleRegion->And(*aOuterVisibleRegion,
2708 : *aLayerContentsVisibleRect);
2709 : }
2710 : } else if (transform.Is2D(&transform2D) && !transform2D.HasNonIntegerTranslation()) {
2711 0 : aOuterVisibleRegion->MoveBy(-int(transform2D._31), -int(transform2D._32));
2712 0 : if (aLayerContentsVisibleRect) {
2713 0 : aOuterVisibleRegion->And(*aOuterVisibleRegion, *aLayerContentsVisibleRect);
2714 : }
2715 0 : } else {
2716 0 : nsIntRect outerRect = aOuterVisibleRegion->GetBounds();
2717 0 : // if 'transform' is not invertible, then nothing will be displayed
2718 0 : // for the layer, so it doesn't really matter what we do here
2719 0 : Rect outerVisible(outerRect.x, outerRect.y, outerRect.width, outerRect.height);
2720 : transform.Invert();
2721 0 :
2722 : Rect layerContentsVisible(-float(INT32_MAX) / 2, -float(INT32_MAX) / 2,
2723 : float(INT32_MAX), float(INT32_MAX));
2724 : if (aLayerContentsVisibleRect) {
2725 0 : NS_ASSERTION(aLayerContentsVisibleRect->width >= 0 &&
2726 0 : aLayerContentsVisibleRect->height >= 0,
2727 : "Bad layer contents rectangle");
2728 : // restrict to aLayerContentsVisibleRect before call GfxRectToIntRect,
2729 40 : // in case layerVisible is extremely large (as it can be when
2730 : // projecting through the inverse of a 3D transform)
2731 : layerContentsVisible = Rect(
2732 : aLayerContentsVisibleRect->x, aLayerContentsVisibleRect->y,
2733 : aLayerContentsVisibleRect->width, aLayerContentsVisibleRect->height);
2734 80 : }
2735 40 : gfxRect layerVisible = ThebesRect(transform.ProjectRectBounds(outerVisible, layerContentsVisible));
2736 0 : layerVisible.RoundOut();
2737 : nsIntRect visRect;
2738 40 : if (gfxUtils::GfxRectToIntRect(layerVisible, &visRect)) {
2739 40 : *aOuterVisibleRegion = visRect;
2740 40 : } else {
2741 : aOuterVisibleRegion->SetEmpty();
2742 : }
2743 0 : }
2744 :
2745 : aLayer->SetVisibleRegion(LayerIntRegion::FromUnknownRegion(*aOuterVisibleRegion));
2746 : }
2747 0 :
2748 : void
2749 : ContainerState::SetOuterVisibleRegionForLayer(Layer* aLayer,
2750 0 : const nsIntRegion& aOuterVisibleRegion,
2751 0 : const nsIntRect* aLayerContentsVisibleRect,
2752 0 : bool aOuterUntransformed) const
2753 : {
2754 0 : nsIntRegion visRegion = aOuterVisibleRegion;
2755 0 : if (!aOuterUntransformed) {
2756 : visRegion.MoveBy(mParameters.mOffset);
2757 0 : }
2758 : SetOuterVisibleRegion(aLayer, &visRegion, aLayerContentsVisibleRect,
2759 : aOuterUntransformed);
2760 0 : }
2761 :
2762 0 : nscolor
2763 0 : ContainerState::FindOpaqueBackgroundColorInLayer(const PaintedLayerData* aData,
2764 0 : const nsIntRect& aRect,
2765 0 : bool* aOutIntersectsLayer) const
2766 0 : {
2767 : *aOutIntersectsLayer = true;
2768 0 :
2769 0 : // Scan the candidate's display items.
2770 : nsIntRect deviceRect = aRect;
2771 : nsRect appUnitRect = ToAppUnits(deviceRect, mAppUnitsPerDevPixel);
2772 : appUnitRect.ScaleInverseRoundOut(mParameters.mXScale, mParameters.mYScale);
2773 :
2774 0 : for (auto& assignedItem : Reversed(aData->mAssignedDisplayItems)) {
2775 : if (assignedItem.mType != DisplayItemEntryType::ITEM) {
2776 : // |assignedItem| is an effect marker.
2777 0 : continue;
2778 : }
2779 :
2780 : nsDisplayItem* item = assignedItem.mItem;
2781 0 : bool snap;
2782 : nsRect bounds = item->GetBounds(mBuilder, &snap);
2783 : if (snap && mSnappingEnabled) {
2784 : nsIntRect snappedBounds = ScaleToNearestPixels(bounds);
2785 0 : if (!snappedBounds.Intersects(deviceRect))
2786 0 : continue;
2787 0 :
2788 0 : if (!snappedBounds.Contains(deviceRect))
2789 : return NS_RGBA(0,0,0,0);
2790 :
2791 : } else {
2792 0 : // The layer's visible rect is already (close enough to) pixel
2793 0 : // aligned, so no need to round out and in here.
2794 : if (!bounds.Intersects(appUnitRect))
2795 0 : continue;
2796 0 :
2797 : if (!bounds.Contains(appUnitRect))
2798 : return NS_RGBA(0,0,0,0);
2799 : }
2800 :
2801 : if (item->IsInvisibleInRect(appUnitRect)) {
2802 : continue;
2803 0 : }
2804 0 :
2805 : if (item->GetClip().IsRectAffectedByClip(deviceRect,
2806 : mParameters.mXScale,
2807 : mParameters.mYScale,
2808 22 : mAppUnitsPerDevPixel)) {
2809 : return NS_RGBA(0,0,0,0);
2810 : }
2811 0 :
2812 22 : if (!assignedItem.mHasOpacity) {
2813 : Maybe<nscolor> color = item->IsUniform(mBuilder);
2814 33 :
2815 0 : if (color && NS_GET_A(*color) == 255) {
2816 11 : return *color;
2817 : }
2818 : }
2819 0 :
2820 : return NS_RGBA(0,0,0,0);
2821 : }
2822 0 :
2823 : *aOutIntersectsLayer = false;
2824 11 : return NS_RGBA(0,0,0,0);
2825 : }
2826 :
2827 0 : nscolor
2828 0 : PaintedLayerDataNode::FindOpaqueBackgroundColor(const nsIntRegion& aTargetVisibleRegion,
2829 0 : int32_t aUnderIndex) const
2830 0 : {
2831 0 : if (aUnderIndex == ABOVE_TOP) {
2832 : aUnderIndex = mPaintedLayerDataStack.Length();
2833 : }
2834 : for (int32_t i = aUnderIndex - 1; i >= 0; --i) {
2835 : const PaintedLayerData* candidate = &mPaintedLayerDataStack[i];
2836 0 : if (candidate->VisibleAboveRegionIntersects(aTargetVisibleRegion)) {
2837 0 : // Some non-PaintedLayer content between target and candidate; this is
2838 : // hopeless
2839 : return NS_RGBA(0,0,0,0);
2840 : }
2841 22 :
2842 : if (!candidate->VisibleRegionIntersects(aTargetVisibleRegion)) {
2843 : // The layer doesn't intersect our target, ignore it and move on
2844 : continue;
2845 0 : }
2846 :
2847 0 : bool intersectsLayer = true;
2848 0 : nsIntRect rect = aTargetVisibleRegion.GetBounds();
2849 0 : nscolor color = mTree.ContState().FindOpaqueBackgroundColorInLayer(
2850 : candidate, rect, &intersectsLayer);
2851 : if (!intersectsLayer) {
2852 0 : continue;
2853 : }
2854 : return color;
2855 : }
2856 0 : if (mAllDrawingAboveBackground ||
2857 : !mVisibleAboveBackgroundRegion.Intersect(aTargetVisibleRegion).IsEmpty()) {
2858 22 : // Some non-PaintedLayer content is between this node's background and target.
2859 0 : return NS_RGBA(0,0,0,0);
2860 : }
2861 : return FindOpaqueBackgroundColorInParentNode();
2862 : }
2863 :
2864 : nscolor
2865 : PaintedLayerDataNode::FindOpaqueBackgroundColorCoveringEverything() const
2866 : {
2867 : if (!mPaintedLayerDataStack.IsEmpty() ||
2868 : mAllDrawingAboveBackground ||
2869 0 : !mVisibleAboveBackgroundRegion.IsEmpty()) {
2870 : return NS_RGBA(0,0,0,0);
2871 0 : }
2872 : return FindOpaqueBackgroundColorInParentNode();
2873 : }
2874 22 :
2875 : nscolor
2876 : PaintedLayerDataNode::FindOpaqueBackgroundColorInParentNode() const
2877 : {
2878 0 : if (mParent) {
2879 : if (mHasClip) {
2880 29 : // Check whether our parent node has uniform content behind our whole
2881 : // clip.
2882 : // There's one tricky case here: If our parent node is also a scrollable,
2883 : // and is currently scrolled in such a way that this inner one is
2884 0 : // clipped by it, then it's not really clear how we should determine
2885 : // whether we have a uniform background in the parent: There might be
2886 : // non-uniform content in the parts that our scroll port covers in the
2887 : // parent and that are currently outside the parent's clip.
2888 0 : // For now, we'll fail to pull a background color in that case.
2889 : return mParent->FindOpaqueBackgroundColor(mClipRect);
2890 0 : }
2891 : return mParent->FindOpaqueBackgroundColorCoveringEverything();
2892 : }
2893 : // We are the root.
2894 0 : return mTree.UniformBackgroundColor();
2895 : }
2896 :
2897 0 : bool
2898 : PaintedLayerData::CanOptimizeToImageLayer(nsDisplayListBuilder* aBuilder)
2899 29 : {
2900 : if (!mImage) {
2901 : return false;
2902 : }
2903 116 :
2904 : return mImage->CanOptimizeToImageLayer(mLayer->Manager(), aBuilder);
2905 58 : }
2906 0 :
2907 29 : already_AddRefed<ImageContainer>
2908 : PaintedLayerData::GetContainerForImageLayer(nsDisplayListBuilder* aBuilder)
2909 116 : {
2910 : if (!mImage) {
2911 58 : return nullptr;
2912 0 : }
2913 0 :
2914 : return mImage->GetContainer(mLayer->Manager(), aBuilder);
2915 : }
2916 0 :
2917 : PaintedLayerDataNode::PaintedLayerDataNode(PaintedLayerDataTree& aTree,
2918 0 : PaintedLayerDataNode* aParent,
2919 : AnimatedGeometryRoot* aAnimatedGeometryRoot)
2920 0 : : mTree(aTree)
2921 0 : , mParent(aParent)
2922 0 : , mAnimatedGeometryRoot(aAnimatedGeometryRoot)
2923 : , mAllDrawingAboveBackground(false)
2924 : {
2925 : MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(mTree.Builder()->RootReferenceFrame(), *mAnimatedGeometryRoot));
2926 : mHasClip = mTree.IsClippedWithRespectToParentAnimatedGeometryRoot(mAnimatedGeometryRoot, &mClipRect);
2927 0 : }
2928 :
2929 : PaintedLayerDataNode::~PaintedLayerDataNode()
2930 : {
2931 : MOZ_ASSERT(mPaintedLayerDataStack.IsEmpty());
2932 : MOZ_ASSERT(mChildren.IsEmpty());
2933 620 : }
2934 0 :
2935 1124 : PaintedLayerDataNode*
2936 281 : PaintedLayerDataNode::AddChildNodeFor(AnimatedGeometryRoot* aAnimatedGeometryRoot)
2937 : {
2938 : MOZ_ASSERT(aAnimatedGeometryRoot->mParentAGR == mAnimatedGeometryRoot);
2939 562 : UniquePtr<PaintedLayerDataNode> child =
2940 0 : MakeUnique<PaintedLayerDataNode>(mTree, this, aAnimatedGeometryRoot);
2941 0 : mChildren.AppendElement(std::move(child));
2942 0 : return mChildren.LastElement().get();
2943 : }
2944 :
2945 : template<typename NewPaintedLayerCallbackType>
2946 : PaintedLayerData*
2947 : PaintedLayerDataNode::FindPaintedLayerFor(const nsIntRect& aVisibleRect,
2948 : const bool aBackfaceHidden,
2949 0 : const ActiveScrolledRoot* aASR,
2950 290 : const DisplayItemClipChain* aClipChain,
2951 9 : NewPaintedLayerCallbackType aNewPaintedLayerCallback)
2952 : {
2953 : if (!mPaintedLayerDataStack.IsEmpty()) {
2954 : PaintedLayerData* lowestUsableLayer = nullptr;
2955 : for (auto& data : Reversed(mPaintedLayerDataStack)) {
2956 : if (data.mVisibleAboveRegion.Intersects(aVisibleRect)) {
2957 : break;
2958 : }
2959 : if (data.mBackfaceHidden == aBackfaceHidden &&
2960 : data.mASR == aASR &&
2961 9 : data.mClipChain == aClipChain) {
2962 : lowestUsableLayer = &data;
2963 0 : }
2964 0 : // Also check whether the event-regions intersect the visible rect,
2965 : // unless we're in an inactive layer, in which case the event-regions
2966 : // will be hoisted out into their own layer.
2967 281 : // For performance reasons, we check the intersection with the bounds
2968 : // of the event-regions.
2969 : if (!mTree.ContState().IsInInactiveLayer() &&
2970 : (data.mScaledHitRegionBounds.Intersects(aVisibleRect) ||
2971 1 : data.mScaledMaybeHitRegionBounds.Intersects(aVisibleRect))) {
2972 29 : break;
2973 : }
2974 0 : // If the visible region intersects with the current layer then we
2975 : // can't possibly use any of the layers below it, so stop the search
2976 : // now.
2977 : //
2978 0 : // If we're trying to minimize painted layer size and we don't
2979 : // intersect the current visible region, then make sure we don't
2980 558 : // use this painted layer.
2981 0 : if (data.mVisibleRegion.Intersects(aVisibleRect)) {
2982 0 : break;
2983 0 : } else if (gfxPrefs::LayoutSmallerPaintedLayers()) {
2984 : lowestUsableLayer = nullptr;
2985 : }
2986 279 : }
2987 : if (lowestUsableLayer) {
2988 : return lowestUsableLayer;
2989 0 : }
2990 : }
2991 58 : PaintedLayerData* data = mPaintedLayerDataStack.AppendElement();
2992 0 : aNewPaintedLayerCallback(data);
2993 :
2994 29 : return data;
2995 29 : }
2996 :
2997 : void
2998 0 : PaintedLayerDataNode::FinishChildrenIntersecting(const nsIntRect& aRect)
2999 : {
3000 : for (int32_t i = mChildren.Length() - 1; i >= 0; i--) {
3001 0 : if (mChildren[i]->Intersects(aRect)) {
3002 : mChildren[i]->Finish(true);
3003 29 : mChildren.RemoveElementAt(i);
3004 : }
3005 0 : }
3006 0 : }
3007 0 :
3008 : void
3009 0 : PaintedLayerDataNode::FinishAllChildren(bool aThisNodeNeedsAccurateVisibleAboveRegion)
3010 : {
3011 : for (int32_t i = mChildren.Length() - 1; i >= 0; i--) {
3012 0 : mChildren[i]->Finish(aThisNodeNeedsAccurateVisibleAboveRegion);
3013 0 : }
3014 : mChildren.Clear();
3015 : }
3016 0 :
3017 : void
3018 22 : PaintedLayerDataNode::Finish(bool aParentNeedsAccurateVisibleAboveRegion)
3019 : {
3020 0 : // Skip "visible above region" maintenance, because this node is going away.
3021 11 : FinishAllChildren(false);
3022 22 :
3023 0 : PopAllPaintedLayerData();
3024 :
3025 : if (mParent && aParentNeedsAccurateVisibleAboveRegion) {
3026 0 : if (mHasClip) {
3027 : mParent->AddToVisibleAboveRegion(mClipRect);
3028 0 : } else {
3029 0 : mParent->SetAllDrawingAbove();
3030 0 : }
3031 0 : }
3032 : mTree.NodeWasFinished(mAnimatedGeometryRoot);
3033 : }
3034 29 :
3035 : void
3036 0 : PaintedLayerDataNode::AddToVisibleAboveRegion(const nsIntRect& aRect)
3037 0 : {
3038 0 : nsIntRegion& visibleAboveRegion = mPaintedLayerDataStack.IsEmpty()
3039 11 : ? mVisibleAboveBackgroundRegion
3040 69 : : mPaintedLayerDataStack.LastElement().mVisibleAboveRegion;
3041 : visibleAboveRegion.Or(visibleAboveRegion, aRect);
3042 29 : visibleAboveRegion.SimplifyOutward(8);
3043 0 : }
3044 :
3045 : void
3046 0 : PaintedLayerDataNode::SetAllDrawingAbove()
3047 : {
3048 22 : PopAllPaintedLayerData();
3049 0 : mAllDrawingAboveBackground = true;
3050 : mVisibleAboveBackgroundRegion.SetEmpty();
3051 22 : }
3052 :
3053 : void
3054 0 : PaintedLayerDataNode::PopAllPaintedLayerData()
3055 : {
3056 0 : for (int32_t index = mPaintedLayerDataStack.Length() - 1; index >= 0; index--) {
3057 : PaintedLayerData& data = mPaintedLayerDataStack[index];
3058 : mTree.ContState().FinishPaintedLayerData(data, [this, &data, index]() {
3059 : return this->FindOpaqueBackgroundColor(data.mVisibleRegion, index);
3060 29 : });
3061 : }
3062 58 : mPaintedLayerDataStack.Clear();
3063 0 : }
3064 :
3065 58 : void
3066 29 : PaintedLayerDataTree::InitializeForInactiveLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot)
3067 0 : {
3068 : mForInactiveLayer = true;
3069 : mRoot.emplace(*this, nullptr, aAnimatedGeometryRoot);
3070 0 :
3071 : }
3072 0 :
3073 0 : nsDisplayListBuilder*
3074 : PaintedLayerDataTree::Builder() const
3075 : {
3076 11 : return mContainerState.Builder();
3077 : }
3078 :
3079 : void
3080 0 : PaintedLayerDataTree::Finish()
3081 11 : {
3082 11 : if (mRoot) {
3083 : mRoot->Finish(false);
3084 0 : }
3085 0 : MOZ_ASSERT(mNodes.Count() == 0);
3086 : mRoot.reset();
3087 0 : }
3088 0 :
3089 0 : void
3090 : PaintedLayerDataTree::NodeWasFinished(AnimatedGeometryRoot* aAnimatedGeometryRoot)
3091 0 : {
3092 : mNodes.Remove(aAnimatedGeometryRoot);
3093 0 : }
3094 0 :
3095 : void
3096 0 : PaintedLayerDataTree::AddingOwnLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot,
3097 : const nsIntRect* aRect,
3098 0 : nscolor* aOutUniformBackgroundColor)
3099 : {
3100 : PaintedLayerDataNode* node = nullptr;
3101 : if (mForInactiveLayer) {
3102 310 : node = mRoot.ptr();
3103 : } else {
3104 : FinishPotentiallyIntersectingNodes(aAnimatedGeometryRoot, aRect);
3105 : node = EnsureNodeFor(aAnimatedGeometryRoot);
3106 : }
3107 : if (aRect) {
3108 : if (aOutUniformBackgroundColor) {
3109 0 : *aOutUniformBackgroundColor = node->FindOpaqueBackgroundColor(*aRect);
3110 310 : }
3111 310 : node->AddToVisibleAboveRegion(*aRect);
3112 24 : } else {
3113 : if (aOutUniformBackgroundColor) {
3114 286 : *aOutUniformBackgroundColor = node->FindOpaqueBackgroundColorCoveringEverything();
3115 286 : }
3116 : node->SetAllDrawingAbove();
3117 : }
3118 : }
3119 :
3120 310 : template<typename NewPaintedLayerCallbackType>
3121 0 : PaintedLayerData*
3122 : PaintedLayerDataTree::FindPaintedLayerFor(AnimatedGeometryRoot* aAnimatedGeometryRoot,
3123 : const ActiveScrolledRoot* aASR,
3124 : const DisplayItemClipChain* aClipChain,
3125 286 : const nsIntRect& aVisibleRect,
3126 : const bool aBackfaceHidden,
3127 : NewPaintedLayerCallbackType aNewPaintedLayerCallback)
3128 0 : {
3129 : const nsIntRect* bounds = &aVisibleRect;
3130 : PaintedLayerDataNode* node = nullptr;
3131 286 : if (mForInactiveLayer) {
3132 0 : node = mRoot.ptr();
3133 : } else {
3134 : FinishPotentiallyIntersectingNodes(aAnimatedGeometryRoot, bounds);
3135 0 : node = EnsureNodeFor(aAnimatedGeometryRoot);
3136 286 : }
3137 :
3138 : PaintedLayerData* data =
3139 0 : node->FindPaintedLayerFor(aVisibleRect, aBackfaceHidden, aASR, aClipChain,
3140 : aNewPaintedLayerCallback);
3141 : return data;
3142 0 : }
3143 0 :
3144 279 : void
3145 : PaintedLayerDataTree::FinishPotentiallyIntersectingNodes(AnimatedGeometryRoot* aAnimatedGeometryRoot,
3146 0 : const nsIntRect* aRect)
3147 : {
3148 : AnimatedGeometryRoot* ancestorThatIsChildOfCommonAncestor = nullptr;
3149 : PaintedLayerDataNode* ancestorNode =
3150 : FindNodeForAncestorAnimatedGeometryRoot(aAnimatedGeometryRoot,
3151 : &ancestorThatIsChildOfCommonAncestor);
3152 : if (!ancestorNode) {
3153 : // None of our ancestors are in the tree. This should only happen if this
3154 : // is the very first item we're looking at.
3155 0 : MOZ_ASSERT(!mRoot);
3156 0 : return;
3157 0 : }
3158 :
3159 : if (ancestorNode->GetAnimatedGeometryRoot() == aAnimatedGeometryRoot) {
3160 0 : // aAnimatedGeometryRoot already has a node in the tree.
3161 : // This is the common case.
3162 : MOZ_ASSERT(!ancestorThatIsChildOfCommonAncestor);
3163 : if (aRect) {
3164 0 : ancestorNode->FinishChildrenIntersecting(*aRect);
3165 0 : } else {
3166 0 : ancestorNode->FinishAllChildren();
3167 : }
3168 0 : return;
3169 : }
3170 :
3171 : // We have found an existing ancestor, but it's a proper ancestor of our
3172 : // animated geometry root.
3173 0 : // ancestorThatIsChildOfCommonAncestor is the last animated geometry root
3174 : // encountered on the way up from aAnimatedGeometryRoot to ancestorNode.
3175 0 : MOZ_ASSERT(ancestorThatIsChildOfCommonAncestor);
3176 286 : MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(*ancestorThatIsChildOfCommonAncestor, *aAnimatedGeometryRoot));
3177 286 : MOZ_ASSERT(ancestorThatIsChildOfCommonAncestor->mParentAGR == ancestorNode->GetAnimatedGeometryRoot());
3178 :
3179 : // ancestorThatIsChildOfCommonAncestor is not in the tree yet!
3180 : MOZ_ASSERT(!mNodes.Get(ancestorThatIsChildOfCommonAncestor));
3181 14 :
3182 0 : // We're about to add a node for ancestorThatIsChildOfCommonAncestor, so we
3183 0 : // finish all intersecting siblings.
3184 0 : nsIntRect clip;
3185 7 : if (IsClippedWithRespectToParentAnimatedGeometryRoot(ancestorThatIsChildOfCommonAncestor, &clip)) {
3186 7 : ancestorNode->FinishChildrenIntersecting(clip);
3187 : } else {
3188 0 : ancestorNode->FinishAllChildren();
3189 0 : }
3190 0 : }
3191 :
3192 0 : PaintedLayerDataNode*
3193 0 : PaintedLayerDataTree::EnsureNodeFor(AnimatedGeometryRoot* aAnimatedGeometryRoot)
3194 7 : {
3195 : MOZ_ASSERT(aAnimatedGeometryRoot);
3196 : PaintedLayerDataNode* node = mNodes.Get(aAnimatedGeometryRoot);
3197 : if (node) {
3198 29 : return node;
3199 : }
3200 :
3201 0 : AnimatedGeometryRoot* parentAnimatedGeometryRoot = aAnimatedGeometryRoot->mParentAGR;
3202 : if (!parentAnimatedGeometryRoot) {
3203 : MOZ_ASSERT(!mRoot);
3204 7 : MOZ_ASSERT(*aAnimatedGeometryRoot == Builder()->RootReferenceFrame());
3205 0 : mRoot.emplace(*this, nullptr, aAnimatedGeometryRoot);
3206 : node = mRoot.ptr();
3207 : } else {
3208 0 : PaintedLayerDataNode* parentNode = EnsureNodeFor(parentAnimatedGeometryRoot);
3209 0 : MOZ_ASSERT(parentNode);
3210 0 : node = parentNode->AddChildNodeFor(aAnimatedGeometryRoot);
3211 : }
3212 : MOZ_ASSERT(node);
3213 : mNodes.Put(aAnimatedGeometryRoot, node);
3214 : return node;
3215 0 : }
3216 :
3217 : bool
3218 293 : PaintedLayerDataTree::IsClippedWithRespectToParentAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot,
3219 : nsIntRect* aOutClip)
3220 : {
3221 286 : if (mForInactiveLayer) {
3222 0 : return false;
3223 : }
3224 : nsIScrollableFrame* scrollableFrame = nsLayoutUtils::GetScrollableFrameFor(*aAnimatedGeometryRoot);
3225 0 : if (!scrollableFrame) {
3226 14 : return false;
3227 : }
3228 : nsIFrame* scrollFrame = do_QueryFrame(scrollableFrame);
3229 : nsRect scrollPort = scrollableFrame->GetScrollPortRect() + Builder()->ToReferenceFrame(scrollFrame);
3230 0 : *aOutClip = mContainerState.ScaleToNearestPixels(scrollPort);
3231 : return true;
3232 : }
3233 0 :
3234 : PaintedLayerDataNode*
3235 : PaintedLayerDataTree::FindNodeForAncestorAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot,
3236 : AnimatedGeometryRoot** aOutAncestorChild)
3237 : {
3238 : if (!aAnimatedGeometryRoot) {
3239 : return nullptr;
3240 0 : }
3241 : PaintedLayerDataNode* node = mNodes.Get(aAnimatedGeometryRoot);
3242 : if (node) {
3243 : return node;
3244 : }
3245 : *aOutAncestorChild = aAnimatedGeometryRoot;
3246 : return FindNodeForAncestorAnimatedGeometryRoot(aAnimatedGeometryRoot->mParentAGR, aOutAncestorChild);
3247 : }
3248 0 :
3249 : static bool
3250 : CanOptimizeAwayPaintedLayer(PaintedLayerData* aData,
3251 : FrameLayerBuilder* aLayerBuilder)
3252 40 : {
3253 : if (!aLayerBuilder->IsBuildingRetainedLayers()) {
3254 : return false;
3255 0 : }
3256 273 :
3257 0 : // If there's no painted layer with valid content in it that we can reuse,
3258 : // always create a color or image layer (and potentially throw away an
3259 : // existing completely invalid painted layer).
3260 : if (aData->mLayer->GetValidRegion().IsEmpty()) {
3261 : return true;
3262 : }
3263 :
3264 : // There is an existing painted layer we can reuse. Throwing it away can make
3265 0 : // compositing cheaper (see bug 946952), but it might cause us to re-allocate
3266 : // the painted layer frequently due to an animation. So we only discard it if
3267 : // we're in tree compression mode, which is triggered at a low frequency.
3268 0 : return aLayerBuilder->CheckInLayerTreeCompressionMode();
3269 0 : }
3270 :
3271 : #ifdef DEBUG
3272 : static int32_t FindIndexOfLayerIn(nsTArray<NewLayerEntry>& aArray,
3273 0 : Layer* aLayer)
3274 0 : {
3275 0 : for (uint32_t i = 0; i < aArray.Length(); ++i) {
3276 0 : if (aArray[i].mLayer == aLayer) {
3277 0 : return i;
3278 : }
3279 0 : }
3280 : return -1;
3281 0 : }
3282 0 : #endif
3283 0 :
3284 : already_AddRefed<Layer>
3285 0 : ContainerState::PrepareImageLayer(PaintedLayerData* aData)
3286 : {
3287 : RefPtr<ImageContainer> imageContainer =
3288 0 : aData->GetContainerForImageLayer(mBuilder);
3289 : if (!imageContainer) {
3290 : return nullptr;
3291 0 : }
3292 :
3293 : RefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(aData->mLayer);
3294 : imageLayer->SetContainer(imageContainer);
3295 0 : aData->mImage->ConfigureLayer(imageLayer, mParameters);
3296 : imageLayer->SetPostScale(mParameters.mXScale,
3297 0 : mParameters.mYScale);
3298 0 :
3299 : if (aData->mItemClip->HasClip()) {
3300 : ParentLayerIntRect clip =
3301 0 : ViewAs<ParentLayerPixel>(ScaleToNearestPixels(aData->mItemClip->GetClipRect()));
3302 0 : clip.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset));
3303 0 : imageLayer->SetClipRect(Some(clip));
3304 : } else {
3305 0 : imageLayer->SetClipRect(Nothing());
3306 0 : }
3307 0 :
3308 0 : FLB_LOG_PAINTED_LAYER_DECISION(aData,
3309 : " Selected image layer=%p\n", imageLayer.get());
3310 0 :
3311 : return imageLayer.forget();
3312 : }
3313 0 :
3314 : already_AddRefed<Layer>
3315 : ContainerState::PrepareColorLayer(PaintedLayerData* aData)
3316 : {
3317 0 : RefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(aData->mLayer);
3318 : colorLayer->SetColor(Color::FromABGR(aData->mSolidColor));
3319 29 :
3320 0 : // Copy transform
3321 0 : colorLayer->SetBaseTransform(aData->mLayer->GetBaseTransform());
3322 : colorLayer->SetPostScale(aData->mLayer->GetPostXScale(),
3323 29 : aData->mLayer->GetPostYScale());
3324 0 :
3325 : nsIntRect visibleRect = aData->mVisibleRegion.GetBounds();
3326 0 : visibleRect.MoveBy(-GetTranslationForPaintedLayer(aData->mLayer));
3327 : colorLayer->SetBounds(visibleRect);
3328 : colorLayer->SetClipRect(Nothing());
3329 29 :
3330 : FLB_LOG_PAINTED_LAYER_DECISION(aData,
3331 0 : " Selected color layer=%p\n", colorLayer.get());
3332 :
3333 0 : return colorLayer.forget();
3334 : }
3335 29 :
3336 : static void
3337 69 : SetBackfaceHiddenForLayer(bool aBackfaceHidden, Layer* aLayer)
3338 0 : {
3339 : if (aBackfaceHidden) {
3340 0 : aLayer->SetContentFlags(aLayer->GetContentFlags() |
3341 : Layer::CONTENT_BACKFACE_HIDDEN);
3342 0 : } else {
3343 : aLayer->SetContentFlags(aLayer->GetContentFlags() &
3344 : ~Layer::CONTENT_BACKFACE_HIDDEN);
3345 0 : }
3346 29 : }
3347 0 :
3348 : template<typename FindOpaqueBackgroundColorCallbackType>
3349 0 : void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueBackgroundColorCallbackType aFindOpaqueBackgroundColor)
3350 : {
3351 58 : PaintedLayerData* data = &aData;
3352 0 :
3353 : MOZ_ASSERT(data->mOpacityIndices.IsEmpty());
3354 0 :
3355 29 : if (!data->mLayer) {
3356 : // No layer was recycled, so we create a new one.
3357 : RefPtr<PaintedLayer> paintedLayer = CreatePaintedLayer(data);
3358 : data->mLayer = paintedLayer;
3359 0 :
3360 0 : NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, paintedLayer) < 0,
3361 0 : "Layer already in list???");
3362 : mNewChildLayers[data->mNewChildLayersIndex].mLayer = paintedLayer.forget();
3363 : }
3364 0 :
3365 : PaintedDisplayItemLayerUserData* userData = GetPaintedDisplayItemLayerUserData(data->mLayer);
3366 : NS_ASSERTION(userData, "where did our user data go?");
3367 0 : userData->mLastItemCount = data->mAssignedDisplayItems.Length();
3368 0 :
3369 : NewLayerEntry* newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex];
3370 0 :
3371 : RefPtr<Layer> layer;
3372 : bool canOptimizeToImageLayer = data->CanOptimizeToImageLayer(mBuilder);
3373 0 :
3374 0 : FLB_LOG_PAINTED_LAYER_DECISION(data, "Selecting layer for pld=%p\n", data);
3375 0 : FLB_LOG_PAINTED_LAYER_DECISION(data, " Solid=%i, hasImage=%c, canOptimizeAwayPaintedLayer=%i\n",
3376 0 : data->mIsSolidColorInVisibleRegion, canOptimizeToImageLayer ? 'y' : 'n',
3377 0 : CanOptimizeAwayPaintedLayer(data, mLayerBuilder));
3378 0 :
3379 0 : if ((data->mIsSolidColorInVisibleRegion || canOptimizeToImageLayer) &&
3380 0 : CanOptimizeAwayPaintedLayer(data, mLayerBuilder)) {
3381 : NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && canOptimizeToImageLayer),
3382 : "Can't be a solid color as well as an image!");
3383 :
3384 0 : layer = canOptimizeToImageLayer ? PrepareImageLayer(data)
3385 0 : : PrepareColorLayer(data);
3386 0 :
3387 0 : if (layer) {
3388 0 : NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
3389 : "Layer already in list???");
3390 : NS_ASSERTION(newLayerEntry->mLayer == data->mLayer,
3391 : "Painted layer at wrong index");
3392 0 : // Store optimized layer in reserved slot
3393 : NewLayerEntry* paintedLayerEntry = newLayerEntry;
3394 0 : newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex + 1];
3395 0 : NS_ASSERTION(!newLayerEntry->mLayer, "Slot already occupied?");
3396 29 : newLayerEntry->mLayer = layer;
3397 : newLayerEntry->mAnimatedGeometryRoot = data->mAnimatedGeometryRoot;
3398 : newLayerEntry->mASR = paintedLayerEntry->mASR;
3399 0 : newLayerEntry->mClipChain = paintedLayerEntry->mClipChain;
3400 294 : newLayerEntry->mScrollMetadataASR = paintedLayerEntry->mScrollMetadataASR;
3401 :
3402 0 : // Hide the PaintedLayer. We leave it in the layer tree so that we
3403 : // can find and recycle it later.
3404 : ParentLayerIntRect emptyRect;
3405 : data->mLayer->SetClipRect(Some(emptyRect));
3406 : data->mLayer->SetVisibleRegion(LayerIntRegion());
3407 0 : data->mLayer->InvalidateWholeLayer();
3408 0 : data->mLayer->SetEventRegions(EventRegions());
3409 273 : }
3410 : }
3411 :
3412 29 : if (!layer) {
3413 14 : // We couldn't optimize to an image layer or a color layer above.
3414 14 : layer = data->mLayer;
3415 0 : layer->SetClipRect(Nothing());
3416 0 : FLB_LOG_PAINTED_LAYER_DECISION(data, " Selected painted layer=%p\n", layer.get());
3417 : }
3418 44 :
3419 : for (auto& item : data->mAssignedDisplayItems) {
3420 : MOZ_ASSERT(item.mItem->GetType() != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO);
3421 :
3422 0 : if (item.mType == DisplayItemEntryType::POP_OPACITY) {
3423 0 : // Do not invalidate for end markers.
3424 0 : continue;
3425 : }
3426 0 :
3427 : InvalidateForLayerChange(item.mItem, data->mLayer, item.mDisplayItemData);
3428 : mLayerBuilder->AddPaintedDisplayItem(data, item, *this, layer);
3429 : item.mDisplayItemData = nullptr;
3430 : }
3431 1 :
3432 : if (mLayerBuilder->IsBuildingRetainedLayers()) {
3433 58 : newLayerEntry->mVisibleRegion = data->mVisibleRegion;
3434 1 : newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
3435 29 : newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
3436 : newLayerEntry->mOpaqueForAnimatedGeometryRootParent = data->mOpaqueForAnimatedGeometryRootParent;
3437 : } else {
3438 : SetOuterVisibleRegionForLayer(layer, data->mVisibleRegion);
3439 0 : }
3440 29 :
3441 0 : #ifdef MOZ_DUMP_PAINTING
3442 0 : if (!data->mLog.IsEmpty()) {
3443 0 : if (PaintedLayerData* containingPld = mLayerBuilder->GetContainingPaintedLayerData()) {
3444 0 : containingPld->mLayer->AddExtraDumpInfo(nsCString(data->mLog));
3445 : } else {
3446 : layer->AddExtraDumpInfo(nsCString(data->mLog));
3447 : }
3448 : }
3449 0 : #endif
3450 :
3451 : mLayerBuilder->AddPaintedLayerItemsEntry(userData);
3452 :
3453 0 : nsIntRegion transparentRegion;
3454 0 : transparentRegion.Sub(data->mVisibleRegion, data->mOpaqueRegion);
3455 : bool isOpaque = transparentRegion.IsEmpty();
3456 0 : // For translucent PaintedLayers, try to find an opaque background
3457 0 : // color that covers the entire area beneath it so we can pull that
3458 0 : // color into this layer to make it opaque.
3459 : if (layer == data->mLayer) {
3460 : nscolor backgroundColor = NS_RGBA(0,0,0,0);
3461 0 : if (!isOpaque) {
3462 : backgroundColor = aFindOpaqueBackgroundColor();
3463 29 : if (NS_GET_A(backgroundColor) == 255) {
3464 : isOpaque = true;
3465 : }
3466 0 : }
3467 :
3468 : // Store the background color
3469 0 : if (userData->mForcedBackgroundColor != backgroundColor) {
3470 58 : // Invalidate the entire target PaintedLayer since we're changing
3471 : // the background color
3472 29 : #ifdef MOZ_DUMP_PAINTING
3473 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
3474 : printf_stderr("Forced background color has changed from #%08X to #%08X on layer %p\n",
3475 : userData->mForcedBackgroundColor, backgroundColor, data->mLayer);
3476 29 : nsAutoCString str;
3477 : AppendToString(str, data->mLayer->GetValidRegion());
3478 0 : printf_stderr("Invalidating layer %p: %s\n", data->mLayer, str.get());
3479 0 : }
3480 : #endif
3481 29 : data->mLayer->InvalidateWholeLayer();
3482 0 : }
3483 : userData->mForcedBackgroundColor = backgroundColor;
3484 0 : } else {
3485 : // mask layer for image and color layers
3486 0 : SetupMaskLayer(layer, *data->mItemClip);
3487 0 : }
3488 :
3489 : uint32_t flags = 0;
3490 0 : nsIWidget* widget = mContainerReferenceFrame->PresContext()->GetRootWidget();
3491 : // See bug 941095. Not quite ready to disable this.
3492 : bool hidpi = false && widget && widget->GetDefaultScale().scale >= 2;
3493 : if (hidpi) {
3494 : flags |= Layer::CONTENT_DISABLE_SUBPIXEL_AA;
3495 : }
3496 : if (isOpaque && !data->mForceTransparentSurface) {
3497 : flags |= Layer::CONTENT_OPAQUE;
3498 : } else if (data->mNeedComponentAlpha && !hidpi) {
3499 29 : flags |= Layer::CONTENT_COMPONENT_ALPHA;
3500 29 : }
3501 0 : if (data->mDisableFlattening) {
3502 : flags |= Layer::CONTENT_DISABLE_FLATTENING;
3503 : }
3504 : layer->SetContentFlags(flags);
3505 0 :
3506 0 : userData->mItems = std::move(data->mAssignedDisplayItems);
3507 0 : userData->mContainerLayerFrame = GetContainerFrame();
3508 :
3509 0 : PaintedLayerData* containingPaintedLayerData =
3510 : mLayerBuilder->GetContainingPaintedLayerData();
3511 0 : // If we're building layers for an inactive layer, the event regions are
3512 0 : // clipped to the inactive layer's clip prior to being combined into the
3513 0 : // event regions of the containing PLD.
3514 : // For the dispatch-to-content and maybe-hit regions, rounded corners on
3515 : // the clip are ignored, since these are approximate regions. For the
3516 0 : // remaining regions, rounded corners in the clip cause the region to
3517 : // be combined into the corresponding "imprecise" region of the
3518 : // containing's PLD (e.g. the maybe-hit region instead of the hit region).
3519 : const DisplayItemClip* inactiveLayerClip = mLayerBuilder->GetInactiveLayerClip();
3520 0 : if (containingPaintedLayerData) {
3521 0 : if (!data->mDispatchToContentHitRegion.GetBounds().IsEmpty()) {
3522 0 : nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
3523 : mContainerReferenceFrame,
3524 0 : data->mDispatchToContentHitRegion.GetBounds(),
3525 : containingPaintedLayerData->mReferenceFrame);
3526 0 : if (inactiveLayerClip) {
3527 : rect = inactiveLayerClip->ApplyNonRoundedIntersection(rect);
3528 0 : }
3529 0 : containingPaintedLayerData->mDispatchToContentHitRegion.Or(
3530 : containingPaintedLayerData->mDispatchToContentHitRegion, rect);
3531 : containingPaintedLayerData->mDispatchToContentHitRegion.SimplifyOutward(8);
3532 : if (data->mDTCRequiresTargetConfirmation) {
3533 : containingPaintedLayerData->mDTCRequiresTargetConfirmation = true;
3534 : }
3535 : }
3536 : if (!data->mMaybeHitRegion.GetBounds().IsEmpty()) {
3537 : nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
3538 : mContainerReferenceFrame,
3539 : data->mMaybeHitRegion.GetBounds(),
3540 0 : containingPaintedLayerData->mReferenceFrame);
3541 0 : if (inactiveLayerClip) {
3542 0 : rect = inactiveLayerClip->ApplyNonRoundedIntersection(rect);
3543 0 : }
3544 : containingPaintedLayerData->mMaybeHitRegion.Or(
3545 : containingPaintedLayerData->mMaybeHitRegion, rect);
3546 : containingPaintedLayerData->mMaybeHitRegion.SimplifyOutward(8);
3547 : }
3548 : Maybe<Matrix4x4Flagged> matrixCache;
3549 : nsLayoutUtils::TransformToAncestorAndCombineRegions(
3550 : data->mHitRegion,
3551 0 : mContainerReferenceFrame,
3552 : containingPaintedLayerData->mReferenceFrame,
3553 : &containingPaintedLayerData->mHitRegion,
3554 : &containingPaintedLayerData->mMaybeHitRegion,
3555 : &matrixCache,
3556 : inactiveLayerClip);
3557 : // See the comment in nsDisplayList::AddFrame, where the touch action regions
3558 : // are handled. The same thing applies here.
3559 0 : bool alreadyHadRegions =
3560 : !containingPaintedLayerData->mNoActionRegion.IsEmpty() ||
3561 : !containingPaintedLayerData->mHorizontalPanRegion.IsEmpty() ||
3562 : !containingPaintedLayerData->mVerticalPanRegion.IsEmpty();
3563 : nsLayoutUtils::TransformToAncestorAndCombineRegions(
3564 : data->mNoActionRegion,
3565 : mContainerReferenceFrame,
3566 : containingPaintedLayerData->mReferenceFrame,
3567 0 : &containingPaintedLayerData->mNoActionRegion,
3568 0 : &containingPaintedLayerData->mDispatchToContentHitRegion,
3569 : &matrixCache,
3570 : inactiveLayerClip);
3571 : nsLayoutUtils::TransformToAncestorAndCombineRegions(
3572 : data->mHorizontalPanRegion,
3573 : mContainerReferenceFrame,
3574 : containingPaintedLayerData->mReferenceFrame,
3575 : &containingPaintedLayerData->mHorizontalPanRegion,
3576 : &containingPaintedLayerData->mDispatchToContentHitRegion,
3577 : &matrixCache,
3578 : inactiveLayerClip);
3579 232 : nsLayoutUtils::TransformToAncestorAndCombineRegions(
3580 : data->mVerticalPanRegion,
3581 29 : mContainerReferenceFrame,
3582 29 : containingPaintedLayerData->mReferenceFrame,
3583 29 : &containingPaintedLayerData->mVerticalPanRegion,
3584 : &containingPaintedLayerData->mDispatchToContentHitRegion,
3585 29 : &matrixCache,
3586 : inactiveLayerClip);
3587 : if (alreadyHadRegions) {
3588 29 : containingPaintedLayerData->mDispatchToContentHitRegion.OrWith(
3589 0 : containingPaintedLayerData->CombinedTouchActionRegion());
3590 0 : }
3591 : } else {
3592 29 : EventRegions regions(
3593 : ScaleRegionToOutsidePixels(data->mHitRegion),
3594 : ScaleRegionToOutsidePixels(data->mMaybeHitRegion),
3595 0 : ScaleRegionToOutsidePixels(data->mDispatchToContentHitRegion),
3596 : ScaleRegionToOutsidePixels(data->mNoActionRegion),
3597 : ScaleRegionToOutsidePixels(data->mHorizontalPanRegion),
3598 : ScaleRegionToOutsidePixels(data->mVerticalPanRegion),
3599 0 : data->mDTCRequiresTargetConfirmation);
3600 :
3601 : Matrix mat = layer->GetTransform().As2D();
3602 : mat.Invert();
3603 0 : regions.ApplyTranslationAndScale(mat._31, mat._32, mat._11, mat._22);
3604 :
3605 : layer->SetEventRegions(regions);
3606 : }
3607 :
3608 : SetBackfaceHiddenForLayer(data->mBackfaceHidden, data->mLayer);
3609 : if (layer != data->mLayer) {
3610 0 : SetBackfaceHiddenForLayer(data->mBackfaceHidden, layer);
3611 : }
3612 : }
3613 :
3614 294 : static bool
3615 : IsItemAreaInWindowOpaqueRegion(nsDisplayListBuilder* aBuilder,
3616 : nsDisplayItem* aItem,
3617 : const nsRect& aComponentAlphaBounds)
3618 : {
3619 : if (!aItem->Frame()->PresContext()->IsChrome()) {
3620 : // Assume that Web content is always in the window opaque region.
3621 : return true;
3622 : }
3623 294 : if (aItem->ReferenceFrame() != aBuilder->RootReferenceFrame()) {
3624 : // aItem is probably in some transformed subtree.
3625 588 : // We're not going to bother figuring out where this landed, we're just
3626 : // going to assume it might have landed over a transparent part of
3627 294 : // the window.
3628 294 : return false;
3629 : }
3630 294 : return aBuilder->GetWindowOpaqueRegion().Contains(aComponentAlphaBounds);
3631 0 : }
3632 21 :
3633 : void
3634 : PaintedLayerData::Accumulate(ContainerState* aState,
3635 0 : nsDisplayItem* aItem,
3636 0 : const nsIntRect& aVisibleRect,
3637 : const nsRect& aContentRect,
3638 : const DisplayItemClip& aClip,
3639 : LayerState aLayerState,
3640 0 : nsDisplayList* aList,
3641 0 : DisplayItemEntryType aType)
3642 : {
3643 : FLB_LOG_PAINTED_LAYER_DECISION(this, "Accumulating dp=%s(%p), f=%p against pld=%p\n", aItem->Name(), aItem, aItem->Frame(), this);
3644 0 :
3645 273 : const bool hasOpacity = mOpacityIndices.Length() > 0;
3646 :
3647 : const DisplayItemClip* oldClip = mItemClip;
3648 : mItemClip = &aClip;
3649 0 :
3650 : if (aType == DisplayItemEntryType::POP_OPACITY) {
3651 273 : MOZ_ASSERT(!mOpacityIndices.IsEmpty());
3652 : mOpacityIndices.RemoveLastElement();
3653 0 :
3654 : AssignedDisplayItem item(aItem, aLayerState,
3655 42 : nullptr, aContentRect, aType, hasOpacity);
3656 0 : mAssignedDisplayItems.AppendElement(std::move(item));
3657 0 : return;
3658 : }
3659 0 :
3660 : if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) {
3661 : mForceTransparentSurface = true;
3662 : }
3663 :
3664 0 : nsRect componentAlphaBounds;
3665 : if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
3666 : // Disable component alpha.
3667 0 : // Note that the transform (if any) on the PaintedLayer is always an integer
3668 : // translation so we don't have to factor that in here.
3669 : aItem->DisableComponentAlpha();
3670 273 : } else {
3671 273 : componentAlphaBounds = aItem->GetComponentAlphaBounds(aState->mBuilder);
3672 0 :
3673 : if (!componentAlphaBounds.IsEmpty()) {
3674 311 : // This display item needs background copy when pushing opacity group.
3675 0 : for (size_t i : mOpacityIndices) {
3676 : AssignedDisplayItem& item = mAssignedDisplayItems[i];
3677 273 : MOZ_ASSERT(item.mType == DisplayItemEntryType::PUSH_OPACITY ||
3678 0 : item.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG);
3679 : item.mType = DisplayItemEntryType::PUSH_OPACITY_WITH_BG;
3680 : }
3681 273 : }
3682 0 : }
3683 :
3684 : bool clipMatches = (oldClip == mItemClip) || (oldClip && *oldClip == *mItemClip);
3685 0 :
3686 0 : DisplayItemData* currentData =
3687 : aItem->HasMergedFrames() ? nullptr : aItem->GetDisplayItemData();
3688 :
3689 : DisplayItemData* oldData =
3690 : aState->mLayerBuilder->GetOldLayerForFrame(aItem->Frame(),
3691 : aItem->GetPerFrameKey(),
3692 : currentData);
3693 : AssignedDisplayItem item(aItem, aLayerState,
3694 : oldData, aContentRect, aType, hasOpacity);
3695 235 : mAssignedDisplayItems.AppendElement(std::move(item));
3696 :
3697 : if (aType == DisplayItemEntryType::PUSH_OPACITY) {
3698 76 : mOpacityIndices.AppendElement(mAssignedDisplayItems.Length() - 1);
3699 : }
3700 :
3701 38 : if (aItem->MustPaintOnContentSide()) {
3702 76 : mShouldPaintOnContentSide = true;
3703 : }
3704 38 :
3705 38 : if (!mIsSolidColorInVisibleRegion && mOpaqueRegion.Contains(aVisibleRect) &&
3706 : mVisibleRegion.Contains(aVisibleRect) && !mImage) {
3707 : // A very common case! Most pages have a PaintedLayer with the page
3708 : // background (opaque) visible and most or all of the page content over the
3709 : // top of that background.
3710 : // The rest of this method won't do anything. mVisibleRegion and mOpaqueRegion
3711 188 : // don't need updating. mVisibleRegion contains aVisibleRect already,
3712 0 : // mOpaqueRegion contains aVisibleRect and therefore whatever the opaque
3713 0 : // region of the item is. mVisibleRegion must contain mOpaqueRegion
3714 0 : // and therefore aVisibleRect.
3715 0 : return;
3716 38 : }
3717 0 :
3718 0 : nsIntRegion opaquePixels;
3719 :
3720 : // Active opacity means no opaque pixels.
3721 0 : if (!hasOpacity) {
3722 : opaquePixels = aState->ComputeOpaqueRect(aItem, mAnimatedGeometryRoot, mASR,
3723 0 : aClip, aList, &mHideAllLayersBelow,
3724 0 : &mOpaqueForAnimatedGeometryRootParent);
3725 0 : opaquePixels.AndWith(aVisibleRect);
3726 : }
3727 :
3728 : /* Mark as available for conversion to image layer if this is a nsDisplayImage and
3729 : * it's the only thing visible in this layer.
3730 : */
3731 0 : if (nsIntRegion(aVisibleRect).Contains(mVisibleRegion) &&
3732 : opaquePixels.Contains(mVisibleRegion) &&
3733 : aItem->SupportsOptimizingToImage()) {
3734 : mImage = static_cast<nsDisplayImageContainer*>(aItem);
3735 27 : FLB_LOG_PAINTED_LAYER_DECISION(this, " Tracking image: nsDisplayImageContainer covers the layer\n");
3736 : } else if (mImage) {
3737 14 : FLB_LOG_PAINTED_LAYER_DECISION(this, " No longer tracking image\n");
3738 7 : mImage = nullptr;
3739 0 : }
3740 0 :
3741 : bool isFirstVisibleItem = mVisibleRegion.IsEmpty();
3742 :
3743 0 : Maybe<nscolor> uniformColor;
3744 7 : if (!hasOpacity) {
3745 : uniformColor = aItem->IsUniform(aState->mBuilder);
3746 0 : }
3747 0 :
3748 0 : // Some display items have to exist (so they can set forceTransparentSurface
3749 0 : // below) but don't draw anything. They'll return true for isUniform but
3750 : // a color with opacity 0.
3751 : if (!uniformColor || NS_GET_A(*uniformColor) > 0) {
3752 0 : // Make sure that the visible area is covered by uniform pixels. In
3753 : // particular this excludes cases where the edges of the item are not
3754 0 : // pixel-aligned (thus the item will not be truly uniform).
3755 0 : if (uniformColor) {
3756 : bool snap;
3757 : nsRect bounds = aItem->GetBounds(aState->mBuilder, &snap);
3758 20 : if (!aState->ScaleToInsidePixels(bounds, snap).Contains(aVisibleRect)) {
3759 20 : uniformColor = Nothing();
3760 : FLB_LOG_PAINTED_LAYER_DECISION(this, " Display item does not cover the visible rect\n");
3761 : }
3762 0 : }
3763 0 : if (uniformColor) {
3764 : if (isFirstVisibleItem) {
3765 : // This color is all we have
3766 0 : mSolidColor = *uniformColor;
3767 0 : mIsSolidColorInVisibleRegion = true;
3768 : } else if (mIsSolidColorInVisibleRegion &&
3769 : mVisibleRegion.IsEqual(nsIntRegion(aVisibleRect)) &&
3770 : clipMatches) {
3771 : // we can just blend the colors together
3772 : mSolidColor = NS_ComposeColors(mSolidColor, *uniformColor);
3773 14 : } else {
3774 0 : FLB_LOG_PAINTED_LAYER_DECISION(this, " Layer not a solid color: Can't blend colors togethers\n");
3775 : mIsSolidColorInVisibleRegion = false;
3776 : }
3777 : } else {
3778 7 : FLB_LOG_PAINTED_LAYER_DECISION(this, " Layer is not a solid color: Display item is not uniform over the visible bound\n");
3779 7 : mIsSolidColorInVisibleRegion = false;
3780 : }
3781 :
3782 : mVisibleRegion.Or(mVisibleRegion, aVisibleRect);
3783 : mVisibleRegion.SimplifyOutward(4);
3784 76 : }
3785 38 :
3786 : if (!opaquePixels.IsEmpty()) {
3787 0 : for (auto iter = opaquePixels.RectIter(); !iter.Done(); iter.Next()) {
3788 : // We don't use SimplifyInward here since it's not defined exactly
3789 0 : // what it will discard. For our purposes the most important case
3790 0 : // is a large opaque background at the bottom of z-order (e.g.,
3791 0 : // a canvas background), so we need to make sure that the first rect
3792 0 : // we see doesn't get discarded.
3793 : nsIntRegion tmp;
3794 0 : tmp.Or(mOpaqueRegion, iter.Get());
3795 : // Opaque display items in chrome documents whose window is partially
3796 : // transparent are always added to the opaque region. This helps ensure
3797 : // that we get as much subpixel-AA as possible in the chrome.
3798 : if (tmp.GetNumRects() <= 4 || aItem->Frame()->PresContext()->IsChrome()) {
3799 : mOpaqueRegion = std::move(tmp);
3800 : }
3801 : }
3802 : }
3803 76 :
3804 0 : if (!aState->mParameters.mDisableSubpixelAntialiasingInDescendants &&
3805 0 : !componentAlphaBounds.IsEmpty()) {
3806 : nsIntRect componentAlphaRect =
3807 : aState->ScaleToOutsidePixels(componentAlphaBounds, false).Intersect(aVisibleRect);
3808 :
3809 : if (!mOpaqueRegion.Contains(componentAlphaRect)) {
3810 0 : if (IsItemAreaInWindowOpaqueRegion(aState->mBuilder, aItem,
3811 : componentAlphaBounds.Intersect(aItem->GetBuildingRect()))) {
3812 0 : mNeedComponentAlpha = true;
3813 0 : } else {
3814 0 : aItem->DisableComponentAlpha();
3815 0 : }
3816 : }
3817 : }
3818 :
3819 100 : // Ensure animated text does not get flattened, even if it forces other
3820 : // content in the container to be layerized. The content backend might
3821 : // not support subpixel positioning of text that animated transforms can
3822 0 : // generate. bug 633097
3823 : if (aState->mParameters.mInActiveTransformedSubtree &&
3824 : (mNeedComponentAlpha || !componentAlphaBounds.IsEmpty())) {
3825 100 : mDisableFlattening = true;
3826 200 : }
3827 1 : }
3828 :
3829 1 : nsRegion
3830 : PaintedLayerData::CombinedTouchActionRegion()
3831 : {
3832 : nsRegion result;
3833 : result.Or(mHorizontalPanRegion, mVerticalPanRegion);
3834 100 : result.OrWith(mNoActionRegion);
3835 : return result;
3836 200 : }
3837 1 :
3838 1 : void
3839 : PaintedLayerData::AccumulateHitTestInfo(ContainerState* aState,
3840 : nsDisplayCompositorHitTestInfo* aItem)
3841 : {
3842 : FLB_LOG_PAINTED_LAYER_DECISION(this,
3843 : "Accumulating hit test info %p against pld=%p\n", aItem, this);
3844 :
3845 193 : const mozilla::DisplayItemClip& clip = aItem->GetClip();
3846 7 : const nsRect area = clip.ApplyNonRoundedIntersection(aItem->Area());
3847 : const mozilla::gfx::CompositorHitTestInfo hitTestInfo = aItem->HitTestInfo();
3848 93 :
3849 : bool hasRoundedCorners = clip.GetRoundedRectCount() > 0;
3850 :
3851 200 : // use the NS_FRAME_SIMPLE_EVENT_REGIONS to avoid calling the slightly
3852 74 : // expensive HasNonZeroCorner function if we know from a previous run that
3853 : // the frame has zero corners.
3854 1 : nsIFrame* frame = aItem->Frame();
3855 0 :
3856 : bool simpleRegions = frame->HasAnyStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
3857 : if (!simpleRegions) {
3858 : if (nsLayoutUtils::HasNonZeroCorner(frame->StyleBorder()->mBorderRadius)) {
3859 0 : hasRoundedCorners = true;
3860 100 : } else {
3861 : frame->AddStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
3862 0 : }
3863 : }
3864 0 :
3865 : if (hasRoundedCorners || (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
3866 : mMaybeHitRegion.OrWith(area);
3867 : } else {
3868 : mHitRegion.OrWith(area);
3869 : }
3870 :
3871 : if (aItem->HitTestInfo() & CompositorHitTestInfo::eDispatchToContent) {
3872 : mDispatchToContentHitRegion.OrWith(area);
3873 :
3874 : if (aItem->HitTestInfo() & CompositorHitTestInfo::eRequiresTargetConfirmation) {
3875 : mDTCRequiresTargetConfirmation = true;
3876 : }
3877 : }
3878 :
3879 : auto touchFlags = hitTestInfo & CompositorHitTestInfo::eTouchActionMask;
3880 : if (touchFlags) {
3881 0 : // something was disabled
3882 0 : if (touchFlags == CompositorHitTestInfo::eTouchActionMask) {
3883 : // everything was disabled, so touch-action:none
3884 0 : mNoActionRegion.OrWith(area);
3885 : } else {
3886 0 : // The event regions code does not store enough information to actually
3887 : // represent all the different states. Prior to the introduction of
3888 0 : // CompositorHitTestInfo here in bug 1389149, the following two cases
3889 : // were effectively getting collapsed:
3890 : // (1) touch-action: auto
3891 : // (2) touch-action: manipulation
3892 : // In both of these cases, none of {mNoActionRegion, mHorizontalPanRegion,
3893 : // mVerticalPanRegion} were modified, and so the fact that case (2) should
3894 : // have prevented double-tap-zooming was getting lost.
3895 : // With CompositorHitTestInfo we can now represent that case correctly,
3896 : // but only if we use CompositorHitTestInfo all the way to the compositor
3897 : // (i.e. in the WebRender-enabled case). In the non-WebRender case where
3898 : // we still use the event regions, we must collapse these two cases back
3899 : // together. Or add another region to the event regions to fix this
3900 : // properly.
3901 : if (touchFlags != CompositorHitTestInfo::eTouchActionDoubleTapZoomDisabled) {
3902 : if (!(hitTestInfo & CompositorHitTestInfo::eTouchActionPanXDisabled)) {
3903 : // pan-x is allowed
3904 0 : mHorizontalPanRegion.OrWith(area);
3905 200 : }
3906 200 : if (!(hitTestInfo & CompositorHitTestInfo::eTouchActionPanYDisabled)) {
3907 : // pan-y is allowed
3908 100 : mVerticalPanRegion.OrWith(area);
3909 0 : }
3910 : } else {
3911 : // the touch-action: manipulation case described above. To preserve the
3912 : // existing behaviour, don't touch either mHorizontalPanRegion or
3913 : // mVerticalPanRegion
3914 100 : }
3915 100 : }
3916 : }
3917 :
3918 : // If there are multiple touch-action areas, there are multiple elements with
3919 : // touch-action properties. We don't know what the relationship is between
3920 200 : // those elements in terms of DOM ancestry, and so we don't know how to
3921 : // combine the regions properly. Instead, we just add all the areas to the
3922 0 : // dispatch-to-content region, so that the APZ knows to check with the
3923 100 : // main thread. See bug 1286957.
3924 : const int alreadyHadRegions = mNoActionRegion.GetNumRects() +
3925 : mHorizontalPanRegion.GetNumRects() +
3926 0 : mVerticalPanRegion.GetNumRects();
3927 :
3928 : if (alreadyHadRegions > 1) {
3929 : mDispatchToContentHitRegion.OrWith(CombinedTouchActionRegion());
3930 : }
3931 :
3932 : // Avoid quadratic performance as a result of the region growing to include
3933 : // and arbitrarily large number of rects, which can happen on some pages.
3934 : mMaybeHitRegion.SimplifyOutward(8);
3935 29 : mDispatchToContentHitRegion.SimplifyOutward(8);
3936 29 :
3937 29 : // Calculate scaled versions of the bounds of mHitRegion and mMaybeHitRegion
3938 29 : // for quick access in FindPaintedLayerFor().
3939 29 : mScaledHitRegionBounds =
3940 29 : aState->ScaleToOutsidePixels(mHitRegion.GetBounds());
3941 : mScaledMaybeHitRegionBounds =
3942 58 : aState->ScaleToOutsidePixels(mMaybeHitRegion.GetBounds());
3943 29 : }
3944 0 :
3945 0 : void
3946 0 : ContainerState::NewPaintedLayerData(PaintedLayerData* aData,
3947 29 : AnimatedGeometryRoot* aAnimatedGeometryRoot,
3948 : const ActiveScrolledRoot* aASR,
3949 : const DisplayItemClipChain* aClipChain,
3950 : const ActiveScrolledRoot* aScrollMetadataASR,
3951 : const nsPoint& aTopLeft,
3952 29 : const nsIFrame* aReferenceFrame,
3953 29 : const bool aBackfaceHidden)
3954 : {
3955 : aData->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
3956 : aData->mASR = aASR;
3957 0 : aData->mClipChain = aClipChain;
3958 : aData->mAnimatedGeometryRootOffset = aTopLeft;
3959 0 : aData->mReferenceFrame = aReferenceFrame;
3960 0 : aData->mBackfaceHidden = aBackfaceHidden;
3961 0 :
3962 0 : aData->mNewChildLayersIndex = mNewChildLayers.Length();
3963 0 : NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
3964 0 : newLayerEntry->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
3965 0 : newLayerEntry->mASR = aASR;
3966 : newLayerEntry->mScrollMetadataASR = aScrollMetadataASR;
3967 : newLayerEntry->mClipChain = aClipChain;
3968 : // newLayerEntry->mOpaqueRegion is filled in later from
3969 0 : // paintedLayerData->mOpaqueRegion, if necessary.
3970 :
3971 : // Allocate another entry for this layer's optimization to ColorLayer/ImageLayer
3972 : mNewChildLayers.AppendElement();
3973 : }
3974 :
3975 : #ifdef MOZ_DUMP_PAINTING
3976 : static void
3977 0 : DumpPaintedImage(nsDisplayItem* aItem, SourceSurface* aSurface)
3978 0 : {
3979 : nsCString string(aItem->Name());
3980 0 : string.Append('-');
3981 : string.AppendInt((uint64_t)aItem);
3982 0 : fprintf_stderr(gfxUtils::sDumpPaintFile, "<script>array[\"%s\"]=\"", string.BeginReading());
3983 : gfxUtils::DumpAsDataURI(aSurface, gfxUtils::sDumpPaintFile);
3984 0 : fprintf_stderr(gfxUtils::sDumpPaintFile, "\";</script>\n");
3985 0 : }
3986 0 : #endif
3987 0 :
3988 0 : static void
3989 0 : PaintInactiveLayer(nsDisplayListBuilder* aBuilder,
3990 0 : LayerManager* aManager,
3991 0 : nsDisplayItem* aItem,
3992 : gfxContext* aContext,
3993 0 : gfxContext* aCtx)
3994 0 : {
3995 : // This item has an inactive layer. Render it to a PaintedLayer
3996 0 : // using a temporary BasicLayerManager.
3997 0 : BasicLayerManager* basic = static_cast<BasicLayerManager*>(aManager);
3998 : RefPtr<gfxContext> context = aContext;
3999 : #ifdef MOZ_DUMP_PAINTING
4000 : int32_t appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
4001 0 : nsIntRect itemVisibleRect =
4002 0 : aItem->GetPaintRect().ToOutsidePixels(appUnitsPerDevPixel);
4003 :
4004 0 : RefPtr<DrawTarget> tempDT;
4005 0 : if (gfxEnv::DumpPaint()) {
4006 0 : tempDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
4007 0 : itemVisibleRect.Size(),
4008 : SurfaceFormat::B8G8R8A8);
4009 0 : if (tempDT) {
4010 0 : context = gfxContext::CreateOrNull(tempDT);
4011 0 : if (!context) {
4012 0 : // Leave this as crash, it's in the debugging code, we want to know
4013 : gfxDevCrash(LogReason::InvalidContext) << "PaintInactive context problem " << gfx::hexa(tempDT);
4014 : return;
4015 0 : }
4016 : context->SetMatrix(Matrix::Translation(-itemVisibleRect.x,
4017 0 : -itemVisibleRect.y));
4018 0 : }
4019 0 : }
4020 : #endif
4021 : basic->BeginTransaction();
4022 0 : basic->SetTarget(context);
4023 :
4024 : if (aItem->GetType() == DisplayItemType::TYPE_MASK) {
4025 0 : static_cast<nsDisplayMask*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
4026 0 : if (basic->InTransaction()) {
4027 0 : basic->AbortTransaction();
4028 : }
4029 0 : } else if (aItem->GetType() == DisplayItemType::TYPE_FILTER){
4030 : static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
4031 0 : if (basic->InTransaction()) {
4032 0 : basic->AbortTransaction();
4033 : }
4034 0 : } else {
4035 : basic->EndTransaction(FrameLayerBuilder::DrawPaintedLayer, aBuilder);
4036 : }
4037 : FrameLayerBuilder *builder = static_cast<FrameLayerBuilder*>(basic->GetUserData(&gLayerManagerLayerBuilder));
4038 : if (builder) {
4039 : builder->DidEndTransaction();
4040 7 : }
4041 :
4042 0 : basic->SetTarget(nullptr);
4043 0 :
4044 : #ifdef MOZ_DUMP_PAINTING
4045 : if (gfxEnv::DumpPaint() && tempDT) {
4046 0 : RefPtr<SourceSurface> surface = tempDT->Snapshot();
4047 : DumpPaintedImage(aItem, surface);
4048 7 :
4049 0 : DrawTarget* drawTarget = aContext->GetDrawTarget();
4050 0 : Rect rect(itemVisibleRect.x, itemVisibleRect.y,
4051 0 : itemVisibleRect.width, itemVisibleRect.height);
4052 : drawTarget->DrawSurface(surface, rect, Rect(Point(0,0), rect.Size()));
4053 :
4054 : aItem->SetPainted();
4055 0 : }
4056 0 : #endif
4057 0 : }
4058 :
4059 : nsRect
4060 0 : ContainerState::GetDisplayPortForAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot)
4061 : {
4062 0 : if (mLastDisplayPortAGR == aAnimatedGeometryRoot) {
4063 0 : return mLastDisplayPortRect;
4064 0 : }
4065 :
4066 : mLastDisplayPortAGR = aAnimatedGeometryRoot;
4067 :
4068 38 : nsIScrollableFrame* sf = nsLayoutUtils::GetScrollableFrameFor(*aAnimatedGeometryRoot);
4069 : if (sf == nullptr || nsLayoutUtils::UsesAsyncScrolling(*aAnimatedGeometryRoot)) {
4070 : mLastDisplayPortRect = nsRect();
4071 : return mLastDisplayPortRect;
4072 : }
4073 :
4074 : bool usingDisplayport =
4075 : nsLayoutUtils::GetDisplayPort((*aAnimatedGeometryRoot)->GetContent(), &mLastDisplayPortRect,
4076 : RelativeTo::ScrollFrame);
4077 76 : if (!usingDisplayport) {
4078 38 : // No async scrolling, so all that matters is that the layer contents
4079 : // cover the scrollport.
4080 : mLastDisplayPortRect = sf->GetScrollPortRect();
4081 : }
4082 0 : nsIFrame* scrollFrame = do_QueryFrame(sf);
4083 0 : mLastDisplayPortRect += scrollFrame->GetOffsetToCrossDoc(mContainerReferenceFrame);
4084 21 : return mLastDisplayPortRect;
4085 : }
4086 0 :
4087 : nsIntRegion
4088 0 : ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
4089 0 : AnimatedGeometryRoot* aAnimatedGeometryRoot,
4090 0 : const ActiveScrolledRoot* aASR,
4091 0 : const DisplayItemClip& aClip,
4092 7 : nsDisplayList* aList,
4093 : bool* aHideAllLayersBelow,
4094 : bool* aOpaqueForAnimatedGeometryRootParent)
4095 : {
4096 : bool snapOpaque;
4097 : nsRegion opaque = aItem->GetOpaqueRegion(mBuilder, &snapOpaque);
4098 7 : if (opaque.IsEmpty()) {
4099 7 : return nsIntRegion();
4100 : }
4101 21 :
4102 : nsIntRegion opaquePixels;
4103 0 : nsRegion opaqueClipped;
4104 : for (auto iter = opaque.RectIter(); !iter.Done(); iter.Next()) {
4105 : opaqueClipped.Or(opaqueClipped,
4106 : aClip.ApproximateIntersectInward(iter.Get()));
4107 : }
4108 0 : if (aAnimatedGeometryRoot == mContainerAnimatedGeometryRoot &&
4109 28 : aASR == mContainerASR &&
4110 7 : opaqueClipped.Contains(mContainerBounds)) {
4111 0 : *aHideAllLayersBelow = true;
4112 : aList->SetIsOpaque();
4113 7 : }
4114 : // Add opaque areas to the "exclude glass" region. Only do this when our
4115 : // container layer is going to be the rootmost layer, otherwise transforms
4116 : // etc will mess us up (and opaque contributions from other containers are
4117 0 : // not needed).
4118 : if (!nsLayoutUtils::GetCrossDocParentFrame(mContainerFrame)) {
4119 : mBuilder->AddWindowOpaqueRegion(opaqueClipped);
4120 0 : }
4121 0 : opaquePixels = ScaleRegionToInsidePixels(opaqueClipped, snapOpaque);
4122 0 :
4123 0 : if (IsInInactiveLayer()) {
4124 0 : return opaquePixels;
4125 : }
4126 :
4127 : const nsRect& displayport =
4128 : GetDisplayPortForAnimatedGeometryRoot(aAnimatedGeometryRoot);
4129 : if (!displayport.IsEmpty() &&
4130 : opaquePixels.Contains(ScaleRegionToNearestPixels(displayport))) {
4131 : *aOpaqueForAnimatedGeometryRootParent = true;
4132 0 : }
4133 : return opaquePixels;
4134 0 : }
4135 0 :
4136 0 : Maybe<size_t>
4137 : ContainerState::SetupMaskLayerForScrolledClip(Layer* aLayer,
4138 : const DisplayItemClip& aClip)
4139 : {
4140 : if (aClip.GetRoundedRectCount() > 0) {
4141 : Maybe<size_t> maskLayerIndex = Some(aLayer->GetAncestorMaskLayerCount());
4142 : if (RefPtr<Layer> maskLayer = CreateMaskLayer(aLayer, aClip, maskLayerIndex)) {
4143 : aLayer->AddAncestorMaskLayer(maskLayer);
4144 0 : return maskLayerIndex;
4145 : }
4146 0 : // Fall through to |return Nothing()|.
4147 : }
4148 : return Nothing();
4149 : }
4150 0 :
4151 : static const ActiveScrolledRoot*
4152 : GetASRForPerspective(const ActiveScrolledRoot* aASR, nsIFrame* aPerspectiveFrame)
4153 : {
4154 0 : for (const ActiveScrolledRoot* asr = aASR; asr; asr = asr->mParent) {
4155 : nsIFrame* scrolledFrame = asr->mScrollableFrame->GetScrolledFrame();
4156 0 : if (nsLayoutUtils::IsAncestorFrameCrossDoc(scrolledFrame, aPerspectiveFrame)) {
4157 : return asr;
4158 0 : }
4159 0 : }
4160 0 : return nullptr;
4161 : }
4162 :
4163 0 : static CSSMaskLayerUserData*
4164 : GetCSSMaskLayerUserData(Layer* aMaskLayer)
4165 : {
4166 : if (!aMaskLayer) {
4167 0 : return nullptr;
4168 : }
4169 0 :
4170 0 : return static_cast<CSSMaskLayerUserData*>(aMaskLayer->GetUserData(&gCSSMaskLayerUserData));
4171 0 : }
4172 :
4173 : static void
4174 0 : SetCSSMaskLayerUserData(Layer* aMaskLayer)
4175 0 : {
4176 : MOZ_ASSERT(aMaskLayer);
4177 :
4178 : aMaskLayer->SetUserData(&gCSSMaskLayerUserData,
4179 : new CSSMaskLayerUserData());
4180 0 : }
4181 0 :
4182 0 : void
4183 0 : ContainerState::SetupMaskLayerForCSSMask(Layer* aLayer,
4184 : nsDisplayMask* aMaskItem)
4185 0 : {
4186 : RefPtr<ImageLayer> maskLayer =
4187 0 : CreateOrRecycleMaskImageLayerFor(MaskLayerKey(aLayer, Nothing()),
4188 0 : GetCSSMaskLayerUserData,
4189 0 : SetCSSMaskLayerUserData);
4190 0 : CSSMaskLayerUserData* oldUserData = GetCSSMaskLayerUserData(maskLayer.get());
4191 0 : MOZ_ASSERT(oldUserData);
4192 :
4193 : bool snap;
4194 0 : nsRect bounds = aMaskItem->GetBounds(mBuilder, &snap);
4195 0 : nsIntRect itemRect = ScaleToOutsidePixels(bounds, snap);
4196 0 :
4197 : // Setup mask layer offset.
4198 0 : // We do not repaint mask for mask position change, so update base transform
4199 : // each time is required.
4200 : Matrix4x4 matrix;
4201 : matrix.PreTranslate(itemRect.x, itemRect.y, 0);
4202 : matrix.PreTranslate(mParameters.mOffset.x, mParameters.mOffset.y, 0);
4203 0 : maskLayer->SetBaseTransform(matrix);
4204 0 :
4205 0 : nsPoint maskLayerOffset = aMaskItem->ToReferenceFrame() - bounds.TopLeft();
4206 0 :
4207 0 : CSSMaskLayerUserData newUserData(aMaskItem->Frame(), itemRect, maskLayerOffset);
4208 : nsRect dirtyRect;
4209 : if (!aMaskItem->IsInvalid(dirtyRect) && *oldUserData == newUserData) {
4210 0 : aLayer->SetMaskLayer(maskLayer);
4211 0 : return;
4212 0 : }
4213 :
4214 0 : int32_t maxSize = mManager->GetMaxTextureSize();
4215 : IntSize surfaceSize(std::min(itemRect.width, maxSize),
4216 : std::min(itemRect.height, maxSize));
4217 0 :
4218 0 : if (surfaceSize.IsEmpty()) {
4219 0 : // Return early if we know that the size of this mask surface is empty.
4220 : return;
4221 0 : }
4222 :
4223 0 : MaskImageData imageData(surfaceSize, mManager);
4224 0 : RefPtr<DrawTarget> dt = imageData.CreateDrawTarget();
4225 : if (!dt || !dt->IsValid()) {
4226 0 : NS_WARNING("Could not create DrawTarget for mask layer.");
4227 : return;
4228 : }
4229 :
4230 0 : RefPtr<gfxContext> maskCtx = gfxContext::CreateOrNull(dt);
4231 : maskCtx->SetMatrix(Matrix::Translation(-itemRect.TopLeft()));
4232 329 : maskCtx->Multiply(gfxMatrix::Scaling(mParameters.mXScale, mParameters.mYScale));
4233 329 :
4234 : bool isPaintFinished = aMaskItem->PaintMask(mBuilder, maskCtx);
4235 :
4236 : RefPtr<ImageContainer> imgContainer =
4237 : imageData.CreateImageAndImageContainer();
4238 : if (!imgContainer) {
4239 : return;
4240 : }
4241 : maskLayer->SetContainer(imgContainer);
4242 :
4243 : if (isPaintFinished) {
4244 : *oldUserData = std::move(newUserData);
4245 : }
4246 : aLayer->SetMaskLayer(maskLayer);
4247 : }
4248 :
4249 : static bool
4250 : IsScrollThumbLayer(nsDisplayItem* aItem)
4251 0 : {
4252 : return aItem->GetType() == DisplayItemType::TYPE_OWN_LAYER &&
4253 58 : static_cast<nsDisplayOwnLayer*>(aItem)->IsScrollThumbLayer();
4254 : }
4255 29 :
4256 : /*
4257 0 : * Iterate through the non-clip items in aList and its descendants.
4258 0 : * For each item we compute the effective clip rect. Each item is assigned
4259 : * to a layer. We invalidate the areas in PaintedLayers where an item
4260 29 : * has moved from one PaintedLayer to another. Also,
4261 0 : * aState->mInvalidPaintedContent is invalidated in every PaintedLayer.
4262 : * We set the clip rect for items that generated their own layer, and
4263 : * create a mask layer to do any rounded rect clipping.
4264 0 : * (PaintedLayers don't need a clip rect on the layer, we clip the items
4265 29 : * individually when we draw them.)
4266 : * We set the visible rect for all layers, although the actual setting
4267 : * of visible rects for some PaintedLayers is deferred until the calling
4268 : * of ContainerState::Finish.
4269 29 : */
4270 : void
4271 58 : ContainerState::ProcessDisplayItems(nsDisplayList* aList)
4272 0 : {
4273 0 : AUTO_PROFILER_LABEL("ContainerState::ProcessDisplayItems", GRAPHICS);
4274 405 :
4275 405 : nsPoint topLeft(0,0);
4276 :
4277 : int32_t maxLayers = gfxPrefs::MaxActiveLayers();
4278 405 : int layerCount = 0;
4279 405 :
4280 405 : if (!mManager->IsWidgetLayerManager()) {
4281 : mPaintedLayerDataTree.InitializeForInactiveLayer(mContainerAnimatedGeometryRoot);
4282 405 : }
4283 :
4284 100 : AnimatedGeometryRoot* lastAnimatedGeometryRoot = nullptr;
4285 : nsPoint lastTopLeft;
4286 200 :
4287 0 : // Tracks the PaintedLayerData that the item will be accumulated in, if it is
4288 : // non-null. Currently only used with PUSH_OPACITY and POP_OPACITY markers.
4289 : PaintedLayerData* selectedPLD = nullptr;
4290 :
4291 0 : FLBDisplayItemIterator iter(mBuilder, aList, this);
4292 : while (iter.HasNext()) {
4293 : DisplayItemEntry e = iter.GetNextEntry();
4294 363 : nsDisplayItem* i = e.mItem;
4295 0 : DisplayItemEntryType marker = e.mType;
4296 :
4297 0 :
4298 0 : nsDisplayItem* item = i;
4299 0 : MOZ_ASSERT(item);
4300 : DisplayItemType itemType = item->GetType();
4301 :
4302 : if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
4303 0 : nsDisplayCompositorHitTestInfo* hitTestInfo =
4304 : static_cast<nsDisplayCompositorHitTestInfo*>(item);
4305 :
4306 0 : if (hitTestInfo->Area().IsEmpty()) {
4307 : continue;
4308 : }
4309 : }
4310 :
4311 0 : if (marker == DisplayItemEntryType::ITEM) {
4312 0 : // Peek ahead to the next item and see if it can be merged with the
4313 0 : // current item.
4314 : nsDisplayItem* peek = iter.PeekNext();
4315 : if (peek && item->CanMerge(peek)) {
4316 : // Create a list of consecutive items that can be merged together.
4317 0 : AutoTArray<nsDisplayItem*, 2> mergedItems { item };
4318 : while ((peek = iter.PeekNext())) {
4319 0 : if (!item->CanMerge(peek)) {
4320 : break;
4321 : }
4322 405 :
4323 0 : mergedItems.AppendElement(peek);
4324 :
4325 : // Move the iterator forward since we will merge this item.
4326 405 : i = iter.GetNext();
4327 0 : }
4328 0 :
4329 : // We have items that can be merged together.
4330 : // Merge them into a temporary item and process that item immediately.
4331 : MOZ_ASSERT(mergedItems.Length() > 1);
4332 405 : item = mBuilder->MergeItems(mergedItems);
4333 : MOZ_ASSERT(item && itemType == item->GetType());
4334 1 : }
4335 363 : }
4336 :
4337 0 : MOZ_ASSERT(item->GetType() != DisplayItemType::TYPE_WRAP_LIST);
4338 0 :
4339 : NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item),
4340 : "items in a container layer should all have the same app units per dev pixel");
4341 :
4342 405 : if (mBuilder->NeedToForceTransparentSurfaceForItem(item)) {
4343 : aList->SetNeedsTransparentSurface();
4344 405 : }
4345 405 :
4346 : if (mParameters.mForEventsAndPluginsOnly && !item->GetChildren() &&
4347 405 : (itemType != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO &&
4348 0 : itemType != DisplayItemType::TYPE_PLUGIN)) {
4349 740 : continue;
4350 740 : }
4351 370 :
4352 : LayerState layerState = LAYER_NONE;
4353 614 :
4354 : if (marker == DisplayItemEntryType::ITEM) {
4355 63 : layerState = item->GetLayerState(mBuilder, mManager, mParameters);
4356 :
4357 : if (layerState == LAYER_INACTIVE && nsDisplayItem::ForceActiveLayers()) {
4358 : layerState = LAYER_ACTIVE;
4359 : }
4360 : }
4361 35 :
4362 0 : bool forceInactive = false;
4363 0 : AnimatedGeometryRoot* animatedGeometryRoot;
4364 : const ActiveScrolledRoot* itemASR = nullptr;
4365 405 : const DisplayItemClipChain* layerClipChain = nullptr;
4366 376 :
4367 : if (mManager->IsWidgetLayerManager()) {
4368 0 : animatedGeometryRoot = item->GetAnimatedGeometryRoot();
4369 29 : itemASR = item->GetActiveScrolledRoot();
4370 : const DisplayItemClipChain* itemClipChain = item->GetClipChain();
4371 : if (itemClipChain && itemClipChain->mASR == itemASR &&
4372 : itemType != DisplayItemType::TYPE_STICKY_POSITION) {
4373 405 : layerClipChain = itemClipChain->mParent;
4374 : } else {
4375 : layerClipChain = itemClipChain;
4376 0 : }
4377 : } else {
4378 0 : // For inactive layer subtrees, splitting content into PaintedLayers
4379 : // based on animated geometry roots is pointless. It's more efficient
4380 100 : // to build the minimum number of layers.
4381 100 : animatedGeometryRoot = mContainerAnimatedGeometryRoot;
4382 : itemASR = mContainerASR;
4383 : item->FuseClipChainUpTo(mBuilder, mContainerASR);
4384 0 : }
4385 416 : if (animatedGeometryRoot == lastAnimatedGeometryRoot) {
4386 416 : topLeft = lastTopLeft;
4387 0 : } else {
4388 1 : lastTopLeft = topLeft = (*animatedGeometryRoot)->GetOffsetToCrossDoc(mContainerReferenceFrame);
4389 405 : lastAnimatedGeometryRoot = animatedGeometryRoot;
4390 318 : }
4391 0 :
4392 0 : const ActiveScrolledRoot* scrollMetadataASR =
4393 0 : layerClipChain ? ActiveScrolledRoot::PickDescendant(itemASR, layerClipChain->mASR) : itemASR;
4394 :
4395 636 : bool snap;
4396 : nsRect itemContent = item->GetBounds(mBuilder, &snap);
4397 :
4398 0 : if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
4399 : nsDisplayCompositorHitTestInfo* hitInfo =
4400 0 : static_cast<nsDisplayCompositorHitTestInfo*>(item);
4401 : itemContent = hitInfo->Area();
4402 : }
4403 :
4404 0 : nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
4405 305 : bool prerenderedTransform = itemType == DisplayItemType::TYPE_TRANSFORM &&
4406 0 : static_cast<nsDisplayTransform*>(item)->MayBeAnimated(mBuilder);
4407 0 : ParentLayerIntRect clipRect;
4408 : const DisplayItemClip& itemClip = item->GetClip();
4409 : if (itemClip.HasClip()) {
4410 : itemContent.IntersectRect(itemContent, itemClip.GetClipRect());
4411 0 : clipRect = ViewAs<ParentLayerPixel>(ScaleToNearestPixels(itemClip.GetClipRect()));
4412 : if (!prerenderedTransform && !IsScrollThumbLayer(item)) {
4413 : itemDrawRect.IntersectRect(itemDrawRect, clipRect.ToUnknownRect());
4414 0 : }
4415 : clipRect.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset));
4416 : }
4417 0 : #ifdef DEBUG
4418 : nsRect bounds = itemContent;
4419 0 :
4420 : if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
4421 : bounds.SetEmpty();
4422 405 : }
4423 0 :
4424 : if (!bounds.IsEmpty()) {
4425 : if (itemASR != mContainerASR) {
4426 : if (Maybe<nsRect> clip = item->GetClipWithRespectToASR(mBuilder, mContainerASR)) {
4427 0 : bounds = clip.ref();
4428 0 : }
4429 0 : }
4430 788 : }
4431 0 : ((nsRect&)mAccumulatedChildBounds).UnionRect(mAccumulatedChildBounds, bounds);
4432 : #endif
4433 11 :
4434 : nsIntRect itemVisibleRect = itemDrawRect;
4435 : // We intersect the building rect with the clipped item bounds to get a
4436 : // tighter visible rect.
4437 11 : if (!prerenderedTransform) {
4438 11 : itemVisibleRect = itemVisibleRect.Intersect(
4439 : ScaleToOutsidePixels(item->GetBuildingRect(), false));
4440 : }
4441 :
4442 0 : if (maxLayers != -1 && layerCount >= maxLayers) {
4443 : forceInactive = true;
4444 : }
4445 :
4446 : // Assign the item to a layer
4447 : if (layerState == LAYER_ACTIVE_FORCE ||
4448 : (layerState == LAYER_INACTIVE && !mManager->IsWidgetLayerManager()) ||
4449 : (!forceInactive &&
4450 : (layerState == LAYER_ACTIVE_EMPTY ||
4451 0 : layerState == LAYER_ACTIVE))) {
4452 0 :
4453 : layerCount++;
4454 :
4455 : // Currently we do not support flattening effects within nested inactive
4456 : // layer trees.
4457 : MOZ_ASSERT(selectedPLD == nullptr);
4458 0 : MOZ_ASSERT(marker == DisplayItemEntryType::ITEM);
4459 0 :
4460 0 : // LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
4461 : // We should never see an empty layer with any visible content!
4462 : NS_ASSERTION(layerState != LAYER_ACTIVE_EMPTY ||
4463 : itemVisibleRect.IsEmpty(),
4464 : "State is LAYER_ACTIVE_EMPTY but visible rect is not.");
4465 22 :
4466 0 : // As long as the new layer isn't going to be a PaintedLayer,
4467 22 : // InvalidateForLayerChange doesn't need the new layer pointer.
4468 : // We also need to check the old data now, because BuildLayer
4469 : // can overwrite it.
4470 : DisplayItemData* oldData =
4471 : mLayerBuilder->GetOldLayerForFrame(item->Frame(), item->GetPerFrameKey());
4472 : InvalidateForLayerChange(item, nullptr, oldData);
4473 :
4474 : // If the item would have its own layer but is invisible, just hide it.
4475 : // Note that items without their own layers can't be skipped this
4476 : // way, since their PaintedLayer may decide it wants to draw them
4477 : // into its buffer even if they're currently covered.
4478 0 : if (itemVisibleRect.IsEmpty() &&
4479 0 : !item->ShouldBuildLayerEvenIfInvisible(mBuilder)) {
4480 11 : continue;
4481 11 : }
4482 11 :
4483 0 : // 3D-transformed layers don't necessarily draw in the order in which
4484 11 : // they're added to their parent container layer.
4485 11 : bool mayDrawOutOfOrder = itemType == DisplayItemType::TYPE_TRANSFORM &&
4486 : (item->Frame()->Combines3DTransformWithAncestors() ||
4487 : item->Frame()->Extend3DContext());
4488 11 :
4489 0 : // Let mPaintedLayerDataTree know about this item, so that
4490 11 : // FindPaintedLayerFor and FindOpaqueBackgroundColor are aware of this
4491 : // item, even though it's not in any PaintedLayerDataStack.
4492 11 : // Ideally we'd only need the "else" case here and have
4493 : // mPaintedLayerDataTree figure out the right clip from the animated
4494 : // geometry root that we give it, but it can't easily figure about
4495 : // overflow:hidden clips on ancestors just by looking at the frame.
4496 0 : // So we'll do a little hand holding and pass the clip instead of the
4497 0 : // visible rect for the two important cases.
4498 : nscolor uniformColor = NS_RGBA(0,0,0,0);
4499 0 : nscolor* uniformColorPtr = (mayDrawOutOfOrder || IsInInactiveLayer()) ? nullptr :
4500 0 : &uniformColor;
4501 : nsIntRect clipRectUntyped;
4502 0 : nsIntRect* clipPtr = nullptr;
4503 0 : if (itemClip.HasClip()) {
4504 11 : clipRectUntyped = clipRect.ToUnknownRect();
4505 0 : clipPtr = &clipRectUntyped;
4506 : }
4507 :
4508 : bool hasScrolledClip = layerClipChain && layerClipChain->mClip.HasClip() &&
4509 : (!ActiveScrolledRoot::IsAncestor(layerClipChain->mASR, itemASR) ||
4510 : itemType == DisplayItemType::TYPE_STICKY_POSITION);
4511 0 :
4512 : if (hasScrolledClip) {
4513 0 : // If the clip is scrolled, reserve just the area of the clip for
4514 0 : // layerization, so that elements outside the clip can still merge
4515 : // into the same layer.
4516 0 : const ActiveScrolledRoot* clipASR = layerClipChain->mASR;
4517 11 : AnimatedGeometryRoot* clipAGR = mBuilder->AnimatedGeometryRootForASR(clipASR);
4518 : nsIntRect scrolledClipRect =
4519 : ScaleToNearestPixels(layerClipChain->mClip.GetClipRect()) + mParameters.mOffset;
4520 0 : mPaintedLayerDataTree.AddingOwnLayer(clipAGR,
4521 : &scrolledClipRect,
4522 0 : uniformColorPtr);
4523 0 : } else if (item->ShouldFixToViewport(mBuilder) && itemClip.HasClip() &&
4524 0 : item->AnimatedGeometryRootForScrollMetadata() != animatedGeometryRoot &&
4525 0 : !nsLayoutUtils::UsesAsyncScrolling(item->Frame())) {
4526 : // This is basically the same as the case above, but for the non-APZ
4527 0 : // case. At the moment, when APZ is off, there is only the root ASR
4528 : // (because scroll frames without display ports don't create ASRs) and
4529 0 : // the whole clip chain is always just one fused clip.
4530 : // Bug 1336516 aims to change that and to remove this workaround.
4531 0 : AnimatedGeometryRoot* clipAGR = item->AnimatedGeometryRootForScrollMetadata();
4532 : nsIntRect scrolledClipRect =
4533 : ScaleToNearestPixels(itemClip.GetClipRect()) + mParameters.mOffset;
4534 : mPaintedLayerDataTree.AddingOwnLayer(clipAGR,
4535 : &scrolledClipRect,
4536 : uniformColorPtr);
4537 : } else if (IsScrollThumbLayer(item) && mManager->IsWidgetLayerManager()) {
4538 : // For scrollbar thumbs, the clip we care about is the clip added by the
4539 : // slider frame.
4540 : mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot->mParentAGR,
4541 : clipPtr,
4542 11 : uniformColorPtr);
4543 22 : } else if (prerenderedTransform && mManager->IsWidgetLayerManager()) {
4544 : if (animatedGeometryRoot->mParentAGR) {
4545 : mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot->mParentAGR,
4546 11 : clipPtr,
4547 11 : uniformColorPtr);
4548 11 : } else {
4549 11 : mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot,
4550 0 : nullptr,
4551 0 : uniformColorPtr);
4552 : }
4553 0 : } else {
4554 0 : // Using itemVisibleRect here isn't perfect. itemVisibleRect can be
4555 : // larger or smaller than the potential bounds of item's contents in
4556 : // animatedGeometryRoot: It's too large if there's a clipped display
4557 0 : // port somewhere among item's contents (see bug 1147673), and it can
4558 : // be too small if the contents can move, because it only looks at the
4559 : // contents' current bounds and doesn't anticipate any animations.
4560 : // Time will tell whether this is good enough, or whether we need to do
4561 : // something more sophisticated here.
4562 : mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot,
4563 : &itemVisibleRect, uniformColorPtr);
4564 : }
4565 :
4566 0 : ContainerLayerParameters params = mParameters;
4567 0 : params.mBackgroundColor = uniformColor;
4568 0 : params.mLayerCreationHint = GetLayerCreationHint(animatedGeometryRoot);
4569 : params.mScrollMetadataASR = ActiveScrolledRoot::PickDescendant(mContainerScrollMetadataASR, scrollMetadataASR);
4570 : params.mCompositorASR = params.mScrollMetadataASR != mContainerScrollMetadataASR
4571 : ? params.mScrollMetadataASR
4572 : : mContainerCompositorASR;
4573 : if (itemType == DisplayItemType::TYPE_FIXED_POSITION) {
4574 : params.mCompositorASR = itemASR;
4575 0 : }
4576 0 :
4577 0 : if (itemType == DisplayItemType::TYPE_PERSPECTIVE) {
4578 11 : // Perspective items have a single child item, an nsDisplayTransform.
4579 0 : // If the perspective item is scrolled, but the perspective-inducing
4580 : // frame is outside the scroll frame (indicated by item->Frame()
4581 : // being outside that scroll frame), we have to take special care to
4582 11 : // make APZ scrolling work properly. APZ needs us to put the scroll
4583 : // frame's FrameMetrics on our child transform ContainerLayer instead.
4584 : // It's worth investigating whether this ASR adjustment can be done at
4585 0 : // display item creation time.
4586 0 : scrollMetadataASR = GetASRForPerspective(scrollMetadataASR, item->Frame()->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME));
4587 0 : params.mScrollMetadataASR = scrollMetadataASR;
4588 : itemASR = scrollMetadataASR;
4589 0 : }
4590 11 :
4591 : // Just use its layer.
4592 : // Set layerContentsVisibleRect.width/height to -1 to indicate we
4593 22 : // currently don't know. If BuildContainerLayerFor gets called by
4594 0 : // item->BuildLayer, this will be set to a proper rect.
4595 0 : nsIntRect layerContentsVisibleRect(0, 0, -1, -1);
4596 : params.mLayerContentsVisibleRect = &layerContentsVisibleRect;
4597 : RefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, params);
4598 : if (!ownLayer) {
4599 : continue;
4600 11 : }
4601 0 :
4602 0 : NS_ASSERTION(!ownLayer->AsPaintedLayer(),
4603 : "Should never have created a dedicated Painted layer!");
4604 :
4605 : if (item->BackfaceIsHidden()) {
4606 11 : ownLayer->SetContentFlags(ownLayer->GetContentFlags() |
4607 22 : Layer::CONTENT_BACKFACE_HIDDEN);
4608 : } else {
4609 11 : ownLayer->SetContentFlags(ownLayer->GetContentFlags() &
4610 : ~Layer::CONTENT_BACKFACE_HIDDEN);
4611 : }
4612 :
4613 : nsRect invalid;
4614 0 : if (item->IsInvalid(invalid)) {
4615 0 : ownLayer->SetInvalidRectToVisibleRegion();
4616 22 : }
4617 11 :
4618 0 : // If it's not a ContainerLayer, we need to apply the scale transform
4619 : // ourselves.
4620 : if (!ownLayer->AsContainerLayer()) {
4621 : ownLayer->SetPostScale(mParameters.mXScale,
4622 0 : mParameters.mYScale);
4623 0 : }
4624 :
4625 : // Update that layer's clip and visible rects.
4626 : NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
4627 11 : NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
4628 0 : "We shouldn't have a FrameLayerBuilder-managed layer here!");
4629 0 : NS_ASSERTION(itemClip.HasClip() ||
4630 0 : itemClip.GetRoundedRectCount() == 0,
4631 0 : "If we have rounded rects, we must have a clip rect");
4632 0 :
4633 : // It has its own layer. Update that layer's clip and visible rects.
4634 0 : ownLayer->SetClipRect(Nothing());
4635 : ownLayer->SetScrolledClip(Nothing());
4636 0 : ownLayer->SetAncestorMaskLayers({});
4637 : if (itemClip.HasClip()) {
4638 : ownLayer->SetClipRect(Some(clipRect));
4639 0 :
4640 0 : // rounded rectangle clipping using mask layers
4641 : // (must be done after visible rect is set on layer)
4642 0 : if (itemClip.GetRoundedRectCount() > 0) {
4643 0 : SetupMaskLayer(ownLayer, itemClip);
4644 : }
4645 0 : }
4646 0 :
4647 : if (hasScrolledClip) {
4648 : const DisplayItemClip& scrolledClip = layerClipChain->mClip;
4649 0 : LayerClip scrolledLayerClip;
4650 : scrolledLayerClip.SetClipRect(ViewAs<ParentLayerPixel>(
4651 : ScaleToNearestPixels(scrolledClip.GetClipRect()) + mParameters.mOffset));
4652 : if (scrolledClip.GetRoundedRectCount() > 0) {
4653 : scrolledLayerClip.SetMaskLayerIndex(
4654 : SetupMaskLayerForScrolledClip(ownLayer.get(), scrolledClip));
4655 22 : }
4656 22 : ownLayer->SetScrolledClip(Some(scrolledLayerClip));
4657 0 : }
4658 0 :
4659 : if (item->GetType() == DisplayItemType::TYPE_MASK) {
4660 : MOZ_ASSERT(itemClip.GetRoundedRectCount() == 0);
4661 0 :
4662 0 : nsDisplayMask* maskItem = static_cast<nsDisplayMask*>(item);
4663 0 : SetupMaskLayerForCSSMask(ownLayer, maskItem);
4664 :
4665 0 : if (iter.PeekNext() &&
4666 : iter.PeekNext()->GetType() == DisplayItemType::TYPE_SCROLL_INFO_LAYER) {
4667 : // Since we do build a layer for mask, there is no need for this
4668 11 : // scroll info layer anymore.
4669 11 : i = iter.GetNext();
4670 11 : }
4671 11 : }
4672 0 :
4673 0 : // Convert the visible rect to a region and give the item
4674 0 : // a chance to try restrict it further.
4675 11 : nsIntRegion itemVisibleRegion = itemVisibleRect;
4676 0 : nsRegion tightBounds = item->GetTightBounds(mBuilder, &snap);
4677 0 : if (!tightBounds.IsEmpty()) {
4678 0 : itemVisibleRegion.AndWith(ScaleToOutsidePixels(tightBounds, snap));
4679 : }
4680 :
4681 : ContainerLayer* oldContainer = ownLayer->GetParent();
4682 : if (oldContainer && oldContainer != mContainerLayer) {
4683 22 : oldContainer->RemoveChild(ownLayer);
4684 11 : }
4685 11 : NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, ownLayer) < 0,
4686 : "Layer already in list???");
4687 :
4688 0 : NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
4689 0 : newLayerEntry->mLayer = ownLayer;
4690 0 : newLayerEntry->mAnimatedGeometryRoot = animatedGeometryRoot;
4691 11 : newLayerEntry->mASR = itemASR;
4692 11 : newLayerEntry->mScrollMetadataASR = scrollMetadataASR;
4693 : newLayerEntry->mClipChain = layerClipChain;
4694 : newLayerEntry->mLayerState = layerState;
4695 : if (itemType == DisplayItemType::TYPE_FIXED_POSITION) {
4696 : newLayerEntry->mIsFixedToRootScrollFrame =
4697 11 : item->Frame()->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED &&
4698 : nsLayoutUtils::IsReallyFixedPos(item->Frame());
4699 : }
4700 0 :
4701 0 : // Don't attempt to flatten compnent alpha layers that are within
4702 0 : // a forced active layer, or an active transform;
4703 0 : if (itemType == DisplayItemType::TYPE_TRANSFORM ||
4704 0 : layerState == LAYER_ACTIVE_FORCE) {
4705 0 : newLayerEntry->mPropagateComponentAlphaFlattening = false;
4706 0 : }
4707 :
4708 : float contentXScale = 1.0f;
4709 0 : float contentYScale = 1.0f;
4710 : if (ContainerLayer* ownContainer = ownLayer->AsContainerLayer()) {
4711 0 : contentXScale = 1 / ownContainer->GetPreXScale();
4712 : contentYScale = 1 / ownContainer->GetPreYScale();
4713 0 : }
4714 : // nsDisplayTransform::BuildLayer must set layerContentsVisibleRect.
4715 0 : // We rely on this to ensure 3D transforms compute a reasonable
4716 : // layer visible region.
4717 : NS_ASSERTION(itemType != DisplayItemType::TYPE_TRANSFORM ||
4718 0 : layerContentsVisibleRect.width >= 0,
4719 : "Transform items must set layerContentsVisibleRect!");
4720 : if (mLayerBuilder->IsBuildingRetainedLayers()) {
4721 0 : newLayerEntry->mLayerContentsVisibleRect = layerContentsVisibleRect;
4722 22 : if (itemType == DisplayItemType::TYPE_PERSPECTIVE ||
4723 22 : (itemType == DisplayItemType::TYPE_TRANSFORM &&
4724 : (item->Frame()->Extend3DContext() ||
4725 0 : item->Frame()->Combines3DTransformWithAncestors() ||
4726 22 : item->Frame()->HasPerspective()))) {
4727 : // Give untransformed visible region as outer visible region
4728 0 : // to avoid failure caused by singular transforms.
4729 0 : newLayerEntry->mUntransformedVisibleRegion = true;
4730 1 : newLayerEntry->mVisibleRegion =
4731 : item->GetBuildingRectForChildren().ScaleToOutsidePixels(contentXScale, contentYScale, mAppUnitsPerDevPixel);
4732 11 : } else {
4733 0 : newLayerEntry->mVisibleRegion = itemVisibleRegion;
4734 0 : }
4735 : newLayerEntry->mOpaqueRegion = ComputeOpaqueRect(item,
4736 0 : animatedGeometryRoot, itemASR, itemClip, aList,
4737 0 : &newLayerEntry->mHideAllLayersBelow,
4738 22 : &newLayerEntry->mOpaqueForAnimatedGeometryRootParent);
4739 11 : } else {
4740 0 : bool useChildrenVisible =
4741 : itemType == DisplayItemType::TYPE_TRANSFORM &&
4742 : (item->Frame()->IsPreserve3DLeaf() ||
4743 0 : item->Frame()->HasPerspective());
4744 : const nsIntRegion &visible = useChildrenVisible ?
4745 : item->GetBuildingRectForChildren().ScaleToOutsidePixels(contentXScale, contentYScale, mAppUnitsPerDevPixel):
4746 : itemVisibleRegion;
4747 :
4748 : SetOuterVisibleRegionForLayer(ownLayer, visible,
4749 : layerContentsVisibleRect.width >= 0 ? &layerContentsVisibleRect : nullptr,
4750 0 : useChildrenVisible);
4751 : }
4752 0 : if (itemType == DisplayItemType::TYPE_SCROLL_INFO_LAYER) {
4753 0 : nsDisplayScrollInfoLayer* scrollItem = static_cast<nsDisplayScrollInfoLayer*>(item);
4754 : newLayerEntry->mOpaqueForAnimatedGeometryRootParent = false;
4755 : newLayerEntry->mBaseScrollMetadata =
4756 0 : scrollItem->ComputeScrollMetadata(ownLayer->Manager(), mParameters);
4757 0 : } else if ((itemType == DisplayItemType::TYPE_SUBDOCUMENT ||
4758 : itemType == DisplayItemType::TYPE_ZOOM ||
4759 394 : itemType == DisplayItemType::TYPE_RESOLUTION) &&
4760 : gfxPrefs::LayoutUseContainersForRootFrames())
4761 0 : {
4762 0 : newLayerEntry->mBaseScrollMetadata =
4763 : static_cast<nsDisplaySubDocument*>(item)->ComputeScrollMetadata(ownLayer->Manager(), mParameters);
4764 0 : }
4765 310 :
4766 : /**
4767 29 : * No need to allocate geometry for items that aren't
4768 116 : * part of a PaintedLayer.
4769 0 : */
4770 87 : if (ownLayer->Manager() == mLayerBuilder->GetRetainingLayerManager()) {
4771 29 : oldData =
4772 : mLayerBuilder->GetOldLayerForFrame(item->Frame(), item->GetPerFrameKey());
4773 0 : mLayerBuilder->StoreDataForFrame(item, ownLayer, layerState, oldData);
4774 : }
4775 0 : } else {
4776 : const bool backfaceHidden = item->In3DContextAndBackfaceIsHidden();
4777 0 : const nsIFrame* referenceFrame = item->ReferenceFrame();
4778 0 :
4779 : PaintedLayerData* paintedLayerData = selectedPLD;
4780 :
4781 0 : if (!selectedPLD) {
4782 : MOZ_ASSERT(marker != DisplayItemEntryType::POP_OPACITY);
4783 0 :
4784 : paintedLayerData =
4785 : mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, itemASR, layerClipChain,
4786 138 : itemVisibleRect, backfaceHidden,
4787 0 : [&](PaintedLayerData* aData) {
4788 69 : NewPaintedLayerData(aData, animatedGeometryRoot, itemASR,
4789 12 : layerClipChain, scrollMetadataASR, topLeft,
4790 : referenceFrame, backfaceHidden);
4791 6 : });
4792 6 : }
4793 : MOZ_ASSERT(paintedLayerData);
4794 0 :
4795 : if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
4796 12 : nsDisplayCompositorHitTestInfo* hitTestInfo =
4797 : static_cast<nsDisplayCompositorHitTestInfo*>(item);
4798 : paintedLayerData->AccumulateHitTestInfo(this, hitTestInfo);
4799 : } else {
4800 : paintedLayerData->Accumulate(this, item, itemVisibleRect, itemContent, itemClip,
4801 0 : layerState, aList, marker);
4802 0 :
4803 : if (!paintedLayerData->mLayer) {
4804 : // Try to recycle the old layer of this display item.
4805 0 : RefPtr<PaintedLayer> layer =
4806 0 : AttemptToRecyclePaintedLayer(animatedGeometryRoot, item,
4807 : topLeft, referenceFrame);
4808 0 : if (layer) {
4809 0 : paintedLayerData->mLayer = layer;
4810 :
4811 : PaintedDisplayItemLayerUserData* userData = GetPaintedDisplayItemLayerUserData(layer);
4812 : paintedLayerData->mAssignedDisplayItems.SetCapacity(userData->mLastItemCount);
4813 :
4814 405 : NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
4815 1 : "Layer already in list???");
4816 0 : mNewChildLayers[paintedLayerData->mNewChildLayersIndex].mLayer = layer.forget();
4817 : }
4818 : }
4819 : }
4820 29 :
4821 29 : if (marker == DisplayItemEntryType::PUSH_OPACITY) {
4822 : selectedPLD = paintedLayerData;
4823 : }
4824 0 :
4825 : if (marker == DisplayItemEntryType::POP_OPACITY ) {
4826 : MOZ_ASSERT(selectedPLD);
4827 :
4828 0 : if (selectedPLD->mOpacityIndices.IsEmpty()) {
4829 : selectedPLD = nullptr;
4830 490 : }
4831 0 : }
4832 : }
4833 :
4834 0 : nsDisplayList* childItems = item->GetSameCoordinateSystemChildren();
4835 0 : if (childItems && childItems->NeedsTransparentSurface()) {
4836 : aList->SetNeedsTransparentSurface();
4837 : }
4838 : }
4839 :
4840 0 : MOZ_ASSERT(selectedPLD == nullptr);
4841 0 : }
4842 :
4843 : void
4844 0 : ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
4845 : PaintedLayer* aNewLayer,
4846 : DisplayItemData* aData)
4847 0 : {
4848 : NS_ASSERTION(aItem->GetPerFrameKey(),
4849 : "Display items that render using Thebes must have a key");
4850 : Layer* oldLayer = aData ? aData->mLayer.get() : nullptr;
4851 0 : if (aNewLayer != oldLayer && oldLayer) {
4852 : // The item has changed layers.
4853 0 : // Invalidate the old bounds in the old layer and new bounds in the new layer.
4854 : PaintedLayer* t = oldLayer->AsPaintedLayer();
4855 : if (t && aData->mGeometry) {
4856 256 : // Note that whenever the layer's scale changes, we invalidate the whole thing,
4857 : // so it doesn't matter whether we are using the old scale at last paint
4858 256 : // or a new scale here
4859 0 : #ifdef MOZ_DUMP_PAINTING
4860 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
4861 : printf_stderr("Display item type %s(%p) changed layers %p to %p!\n", aItem->Name(), aItem->Frame(), t, aNewLayer);
4862 0 : }
4863 0 : #endif
4864 0 : InvalidatePostTransformRegion(t,
4865 : aData->mGeometry->ComputeInvalidationRegion(),
4866 : aData->mClip,
4867 : mLayerBuilder->GetLastPaintOffset(t));
4868 : }
4869 : // Clear the old geometry so that invalidation thinks the item has been
4870 : // added this paint.
4871 498 : aData->mGeometry = nullptr;
4872 0 : }
4873 0 : }
4874 0 :
4875 : void
4876 : FrameLayerBuilder::ComputeGeometryChangeForItem(DisplayItemData* aData)
4877 : {
4878 0 : nsDisplayItem *item = aData->mItem;
4879 249 : PaintedLayer* paintedLayer = aData->mLayer->AsPaintedLayer();
4880 : // If aData->mOptLayer is presence, means this item has been optimized to the separate
4881 0 : // layer. Thus, skip geometry change calculation.
4882 : if (aData->mOptLayer || !item || !paintedLayer) {
4883 : aData->EndUpdate();
4884 : return;
4885 : }
4886 498 :
4887 498 : // If we're a reused display item, then we can't be invalid, so no need to
4888 498 : // do an in-depth comparison. If we haven't previously stored geometry
4889 : // for this item (if it was an active layer), then we can't skip this
4890 0 : // yet.
4891 0 : nsAutoPtr<nsDisplayItemGeometry> geometry;
4892 : if (aData->mReusedItem && aData->mGeometry) {
4893 43 : aData->EndUpdate();
4894 0 : return;
4895 : }
4896 :
4897 0 : PaintedDisplayItemLayerUserData* layerData =
4898 : static_cast<PaintedDisplayItemLayerUserData*>(aData->mLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
4899 18 : nsPoint shift = layerData->mAnimatedGeometryRootOrigin - layerData->mLastAnimatedGeometryRootOrigin;
4900 0 :
4901 9 : const DisplayItemClip& clip = item->GetClip();
4902 18 :
4903 : // If the frame is marked as invalidated, and didn't specify a rect to invalidate then we want to
4904 0 : // invalidate both the old and new bounds, otherwise we only want to invalidate the changed areas.
4905 0 : // If we do get an invalid rect, then we want to add this on top of the change areas.
4906 : nsRect invalid;
4907 : nsRegion combined;
4908 : if (!aData->mGeometry) {
4909 : // This item is being added for the first time, invalidate its entire area.
4910 : geometry = item->AllocateGeometry(mDisplayListBuilder);
4911 : combined = clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion());
4912 197 : #ifdef MOZ_DUMP_PAINTING
4913 197 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
4914 394 : printf_stderr("Display item type %s(%p) added to layer %p!\n", item->Name(), item->Frame(), aData->mLayer.get());
4915 : }
4916 : #endif
4917 : } else if (aData->mIsInvalid || (item->IsInvalid(invalid) && invalid.IsEmpty())) {
4918 : // Layout marked item/frame as needing repainting (without an explicit rect), invalidate the entire old and new areas.
4919 : geometry = item->AllocateGeometry(mDisplayListBuilder);
4920 0 : combined = aData->mClip.ApplyNonRoundedIntersection(aData->mGeometry->ComputeInvalidationRegion());
4921 0 : combined.MoveBy(shift);
4922 : combined.Or(combined, clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion()));
4923 0 : #ifdef MOZ_DUMP_PAINTING
4924 0 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
4925 394 : printf_stderr("Display item type %s(%p) (in layer %p) belongs to an invalidated frame!\n", item->Name(), item->Frame(), aData->mLayer.get());
4926 197 : }
4927 : #endif
4928 : } else {
4929 0 : // Let the display item check for geometry changes and decide what needs to be
4930 197 : // repainted.
4931 :
4932 : const nsRegion& changedFrameInvalidations = aData->GetChangedFrameInvalidations();
4933 394 : aData->mGeometry->MoveBy(shift);
4934 0 : item->ComputeInvalidationRegion(mDisplayListBuilder, aData->mGeometry, &combined);
4935 0 :
4936 : // Only allocate a new geometry object if something actually changed, otherwise the existing
4937 : // one should be fine. We always reallocate for inactive layers, since these types don't
4938 0 : // implement ComputeInvalidateRegion (and rely on the ComputeDifferences call in
4939 0 : // AddPaintedDisplayItem instead).
4940 0 : if (!combined.IsEmpty() || aData->mLayerState == LAYER_INACTIVE) {
4941 : geometry = item->AllocateGeometry(mDisplayListBuilder);
4942 : }
4943 : aData->mClip.AddOffsetAndComputeDifference(shift, aData->mGeometry->ComputeInvalidationRegion(),
4944 : clip, geometry ? geometry->ComputeInvalidationRegion() :
4945 249 : aData->mGeometry->ComputeInvalidationRegion(),
4946 52 : &combined);
4947 0 :
4948 0 : // Add in any rect that the frame specified
4949 : combined.Or(combined, invalid);
4950 : combined.Or(combined, changedFrameInvalidations);
4951 249 :
4952 : // Restrict invalidation to the clipped region
4953 : nsRegion clipRegion;
4954 : if (clip.ComputeRegionInClips(&aData->mClip, shift, &clipRegion)) {
4955 0 : combined.And(combined, clipRegion);
4956 : }
4957 : #ifdef MOZ_DUMP_PAINTING
4958 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
4959 : if (!combined.IsEmpty()) {
4960 273 : printf_stderr("Display item type %s(%p) (in layer %p) changed geometry!\n", item->Name(), item->Frame(), aData->mLayer.get());
4961 : }
4962 : }
4963 0 : #endif
4964 0 : }
4965 273 : if (!combined.IsEmpty()) {
4966 0 : InvalidatePostTransformRegion(paintedLayer,
4967 0 : combined.ScaleToOutsidePixels(layerData->mXScale, layerData->mYScale, layerData->mAppUnitsPerDevPixel),
4968 0 : layerData->mTranslation);
4969 0 : }
4970 :
4971 : aData->EndUpdate(geometry);
4972 0 : }
4973 0 :
4974 0 : void
4975 : FrameLayerBuilder::AddPaintedDisplayItem(PaintedLayerData* aLayerData,
4976 0 : AssignedDisplayItem& aItem,
4977 : ContainerState& aContainerState,
4978 0 : Layer* aLayer)
4979 : {
4980 : PaintedLayer* layer = aLayerData->mLayer;
4981 0 : PaintedDisplayItemLayerUserData* paintedData =
4982 0 : static_cast<PaintedDisplayItemLayerUserData*>
4983 : (layer->GetUserData(&gPaintedDisplayItemLayerUserData));
4984 : RefPtr<BasicLayerManager> tempManager;
4985 : nsIntRect intClip;
4986 273 : bool hasClip = false;
4987 249 : if (aItem.mLayerState != LAYER_NONE) {
4988 0 : if (aItem.mDisplayItemData) {
4989 0 : tempManager = aItem.mDisplayItemData->mInactiveManager;
4990 0 :
4991 : // We need to grab these before updating the DisplayItemData because it will overwrite them.
4992 : nsRegion clip;
4993 43 : if (aItem.mItem->GetClip().ComputeRegionInClips(&aItem.mDisplayItemData->GetClip(),
4994 : aLayerData->mAnimatedGeometryRootOffset - paintedData->mLastAnimatedGeometryRootOrigin,
4995 249 : &clip)) {
4996 : intClip = clip.GetBounds().ScaleToOutsidePixels(paintedData->mXScale,
4997 : paintedData->mYScale,
4998 249 : paintedData->mAppUnitsPerDevPixel);
4999 0 : }
5000 0 : }
5001 : if (!tempManager) {
5002 : tempManager = new BasicLayerManager(BasicLayerManager::BLM_INACTIVE);
5003 : }
5004 273 : }
5005 0 :
5006 0 : if (layer->Manager() == mRetainingManager) {
5007 0 : DisplayItemData *data = aItem.mDisplayItemData;
5008 0 : if (data) {
5009 : if (!data->mUsed) {
5010 0 : data->BeginUpdate(layer, aItem.mLayerState, aItem.mItem, aItem.mReused, aItem.mMerged);
5011 0 : }
5012 0 : } else {
5013 : data = StoreDataForFrame(aItem.mItem, layer, aItem.mLayerState, nullptr);
5014 : }
5015 0 : data->mInactiveManager = tempManager;
5016 : // We optimized this PaintedLayer into a ColorLayer/ImageLayer. Store the optimized
5017 0 : // layer here.
5018 : if (aLayer != layer) {
5019 : data->mOptLayer = aLayer;
5020 0 : data->mItem = nullptr;
5021 0 : }
5022 0 : }
5023 0 :
5024 0 : if (tempManager) {
5025 : FLB_LOG_PAINTED_LAYER_DECISION(aLayerData, "Creating nested FLB for item %p\n", aItem.mItem);
5026 : FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
5027 : layerBuilder->Init(mDisplayListBuilder, tempManager, aLayerData, true,
5028 : &aItem.mItem->GetClip());
5029 0 :
5030 0 : tempManager->BeginTransaction();
5031 : if (mRetainingManager) {
5032 : layerBuilder->DidBeginRetainedLayerTransaction(tempManager);
5033 : }
5034 0 :
5035 0 : UniquePtr<LayerProperties> props(LayerProperties::CloneFrom(tempManager->GetRoot()));
5036 0 : RefPtr<Layer> tmpLayer =
5037 : aItem.mItem->BuildLayer(mDisplayListBuilder, tempManager, ContainerLayerParameters());
5038 0 : // We have no easy way of detecting if this transaction will ever actually get finished.
5039 : // For now, I've just silenced the warning with nested transactions in BasicLayers.cpp
5040 : if (!tmpLayer) {
5041 : tempManager->EndTransaction(nullptr, nullptr);
5042 0 : tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
5043 : aItem.mItem = nullptr;
5044 : return;
5045 : }
5046 :
5047 : bool snap;
5048 : nsRect visibleRect =
5049 : aItem.mItem->GetBuildingRect().Intersect(aItem.mItem->GetBounds(mDisplayListBuilder, &snap));
5050 0 : nsIntRegion rgn = visibleRect.ToOutsidePixels(paintedData->mAppUnitsPerDevPixel);
5051 0 :
5052 : // Convert the visible rect to a region and give the item
5053 : // a chance to try restrict it further.
5054 0 : nsRegion tightBounds = aItem.mItem->GetTightBounds(mDisplayListBuilder, &snap);
5055 0 : if (!tightBounds.IsEmpty()) {
5056 0 : rgn.AndWith(tightBounds.ToOutsidePixels(paintedData->mAppUnitsPerDevPixel));
5057 : }
5058 0 : SetOuterVisibleRegion(tmpLayer, &rgn);
5059 0 :
5060 0 : // If BuildLayer didn't call BuildContainerLayerFor, then our new layer won't have been
5061 0 : // stored in layerBuilder. Manually add it now.
5062 0 : if (mRetainingManager) {
5063 : #ifdef DEBUG_DISPLAY_ITEM_DATA
5064 : LayerManagerData* parentLmd = static_cast<LayerManagerData*>
5065 0 : (layer->Manager()->GetUserData(&gLayerManagerUserData));
5066 0 : LayerManagerData* lmd = static_cast<LayerManagerData*>
5067 : (tempManager->GetUserData(&gLayerManagerUserData));
5068 0 : lmd->mParent = parentLmd;
5069 0 : #endif
5070 0 : DisplayItemData* data = layerBuilder->GetDisplayItemDataForManager(aItem.mItem, tempManager);
5071 0 : layerBuilder->StoreDataForFrame(aItem.mItem, tmpLayer, LAYER_ACTIVE, data);
5072 0 : }
5073 :
5074 0 : tempManager->SetRoot(tmpLayer);
5075 0 : layerBuilder->WillEndTransaction();
5076 0 : tempManager->AbortTransaction();
5077 0 :
5078 : if (gfxUtils::DumpDisplayList() || gfxEnv::DumpPaint()) {
5079 0 : fprintf_stderr(gfxUtils::sDumpPaintFile, "Basic layer tree for painting contents of display item %s(%p):\n", aItem.mItem->Name(), aItem.mItem->Frame());
5080 : std::stringstream stream;
5081 0 : tempManager->Dump(stream, "", gfxEnv::DumpPaintToFile());
5082 0 : fprint_stderr(gfxUtils::sDumpPaintFile, stream); // not a typo, fprint_stderr declared in LayersLogging.h
5083 : }
5084 :
5085 0 : nsIntPoint offset = GetLastPaintOffset(layer) - GetTranslationForPaintedLayer(layer);
5086 : props->MoveBy(-offset);
5087 : // Effective transforms are needed by ComputeDifferences().
5088 : tmpLayer->ComputeEffectiveTransforms(Matrix4x4());
5089 : nsIntRegion invalid;
5090 : if (!props->ComputeDifferences(tmpLayer, invalid, nullptr)) {
5091 : nsRect visible = aItem.mItem->Frame()->GetVisualOverflowRect();
5092 0 : invalid = visible.ToOutsidePixels(paintedData->mAppUnitsPerDevPixel);
5093 : }
5094 : if (aItem.mLayerState == LAYER_SVG_EFFECTS) {
5095 273 : invalid = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(aItem.mItem->Frame(),
5096 : aItem.mItem->ToReferenceFrame(),
5097 : invalid);
5098 : }
5099 0 : if (!invalid.IsEmpty()) {
5100 : #ifdef MOZ_DUMP_PAINTING
5101 : if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
5102 43 : printf_stderr("Inactive LayerManager(%p) for display item %s(%p) has an invalid region - invalidating layer %p\n", tempManager.get(), aItem.mItem->Name(), aItem.mItem->Frame(), layer);
5103 0 : }
5104 0 : #endif
5105 : invalid.ScaleRoundOut(paintedData->mXScale, paintedData->mYScale);
5106 :
5107 : if (hasClip) {
5108 : invalid.And(invalid, intClip);
5109 : }
5110 0 :
5111 : InvalidatePostTransformRegion(layer, invalid,
5112 : GetTranslationForPaintedLayer(layer));
5113 129 : }
5114 : }
5115 86 : aItem.mInactiveLayerManager = tempManager;
5116 43 : }
5117 :
5118 : DisplayItemData*
5119 43 : FrameLayerBuilder::StoreDataForFrame(nsDisplayItem* aItem, Layer* aLayer,
5120 : LayerState aState, DisplayItemData* aData)
5121 43 : {
5122 43 : if (aData) {
5123 : if (!aData->mUsed) {
5124 : aData->BeginUpdate(aLayer, aState, false, aItem);
5125 : }
5126 0 : return aData;
5127 : }
5128 :
5129 : LayerManagerData* lmd = static_cast<LayerManagerData*>
5130 : (mRetainingManager->GetUserData(&gLayerManagerUserData));
5131 0 :
5132 0 : RefPtr<DisplayItemData> data =
5133 6 : new (aItem->Frame()->PresContext()) DisplayItemData(lmd, aItem->GetPerFrameKey(), aLayer);
5134 0 :
5135 : if (!data->HasMergedFrames()) {
5136 : aItem->SetDisplayItemData(data);
5137 : }
5138 1 :
5139 : data->BeginUpdate(aLayer, aState, true, aItem);
5140 :
5141 0 : lmd->mDisplayItems.push_back(data);
5142 : return data;
5143 1 : }
5144 :
5145 0 : void
5146 : FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame,
5147 : uint32_t aDisplayItemKey,
5148 1 : Layer* aLayer,
5149 : LayerState aState)
5150 : {
5151 : DisplayItemData* oldData = GetDisplayItemData(aFrame, aDisplayItemKey);
5152 : if (oldData && oldData->mFrameList.Length() == 1) {
5153 0 : oldData->BeginUpdate(aLayer, aState, false);
5154 : return;
5155 : }
5156 :
5157 : LayerManagerData* lmd = static_cast<LayerManagerData*>
5158 : (mRetainingManager->GetUserData(&gLayerManagerUserData));
5159 294 :
5160 294 : RefPtr<DisplayItemData> data =
5161 : new (aFrame->PresContext()) DisplayItemData(lmd, aDisplayItemKey, aLayer, aFrame);
5162 1176 :
5163 294 : data->BeginUpdate(aLayer, aState, true);
5164 :
5165 1176 : lmd->mDisplayItems.push_back(data);
5166 : }
5167 1176 :
5168 0 : AssignedDisplayItem::AssignedDisplayItem(nsDisplayItem* aItem,
5169 : LayerState aLayerState,
5170 588 : DisplayItemData* aData,
5171 : const nsRect& aContentRect,
5172 : DisplayItemEntryType aType,
5173 2 : const bool aHasOpacity)
5174 : : mItem(aItem)
5175 0 : , mLayerState(aLayerState)
5176 2 : , mDisplayItemData(aData)
5177 2 : , mContentRect(aContentRect)
5178 0 : , mType(aType)
5179 : , mReused(aItem->IsReused())
5180 0 : , mMerged(aItem->HasMergedFrames())
5181 : , mHasOpacity(aHasOpacity)
5182 : , mHasPaintRect(aItem->HasPaintRect())
5183 : {}
5184 0 :
5185 : AssignedDisplayItem::~AssignedDisplayItem()
5186 0 : {
5187 : if (mInactiveLayerManager) {
5188 : mInactiveLayerManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
5189 : }
5190 : }
5191 :
5192 0 : nsIntPoint
5193 : FrameLayerBuilder::GetLastPaintOffset(PaintedLayer* aLayer)
5194 0 : {
5195 : PaintedDisplayItemLayerUserData* layerData = GetPaintedDisplayItemLayerUserData(aLayer);
5196 : MOZ_ASSERT(layerData);
5197 : if (layerData->mHasExplicitLastPaintOffset) {
5198 0 : return layerData->mLastPaintOffset;
5199 : }
5200 35 : return GetTranslationForPaintedLayer(aLayer);
5201 : }
5202 0 :
5203 : bool
5204 6 : FrameLayerBuilder::CheckInLayerTreeCompressionMode()
5205 6 : {
5206 6 : if (mInLayerTreeCompressionMode) {
5207 : return true;
5208 : }
5209 0 :
5210 0 : // If we wanted to be in layer tree compression mode, but weren't, then scheduled
5211 : // a delayed repaint where we will be.
5212 0 : mRootPresContext->PresShell()->GetRootFrame()->SchedulePaint(nsIFrame::PAINT_DELAYED_COMPRESS, false);
5213 :
5214 0 : return false;
5215 0 : }
5216 :
5217 0 : void
5218 : ContainerState::CollectOldLayers()
5219 0 : {
5220 : for (Layer* layer = mContainerLayer->GetFirstChild(); layer;
5221 : layer = layer->GetNextSibling()) {
5222 29 : NS_ASSERTION(!layer->HasUserData(&gMaskLayerUserData),
5223 : "Mask layers should not be part of the layer tree.");
5224 0 : if (layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
5225 : NS_ASSERTION(layer->AsPaintedLayer(), "Wrong layer type");
5226 : mPaintedLayersAvailableForRecycling.PutEntry(static_cast<PaintedLayer*>(layer));
5227 : }
5228 :
5229 : if (Layer* maskLayer = layer->GetMaskLayer()) {
5230 : NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE,
5231 7 : "Could not recycle mask layer, unsupported layer type.");
5232 : mRecycledMaskImageLayers.Put(MaskLayerKey(layer, Nothing()), static_cast<ImageLayer*>(maskLayer));
5233 : }
5234 : for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) {
5235 0 : Layer* maskLayer = layer->GetAncestorMaskLayerAt(i);
5236 0 :
5237 0 : NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE,
5238 0 : "Could not recycle mask layer, unsupported layer type.");
5239 : mRecycledMaskImageLayers.Put(MaskLayerKey(layer, Some(i)), static_cast<ImageLayer*>(maskLayer));
5240 : }
5241 : }
5242 : }
5243 :
5244 : struct OpaqueRegionEntry {
5245 : AnimatedGeometryRoot* mAnimatedGeometryRoot;
5246 0 : const ActiveScrolledRoot* mASR;
5247 : nsIntRegion mOpaqueRegion;
5248 : };
5249 0 :
5250 0 : static OpaqueRegionEntry*
5251 : FindOpaqueRegionEntry(nsTArray<OpaqueRegionEntry>& aEntries,
5252 0 : AnimatedGeometryRoot* aAnimatedGeometryRoot,
5253 0 : const ActiveScrolledRoot* aASR)
5254 0 : {
5255 : for (uint32_t i = 0; i < aEntries.Length(); ++i) {
5256 0 : OpaqueRegionEntry* d = &aEntries[i];
5257 : if (d->mAnimatedGeometryRoot == aAnimatedGeometryRoot &&
5258 : d->mASR == aASR) {
5259 : return d;
5260 0 : }
5261 : }
5262 : return nullptr;
5263 : }
5264 :
5265 : static const ActiveScrolledRoot*
5266 : FindDirectChildASR(const ActiveScrolledRoot* aParent,
5267 7 : const ActiveScrolledRoot* aDescendant)
5268 : {
5269 : MOZ_ASSERT(aDescendant, "can't start at the root when looking for a child");
5270 : MOZ_ASSERT(ActiveScrolledRoot::IsAncestor(aParent, aDescendant));
5271 : const ActiveScrolledRoot* directChild = aDescendant;
5272 : while (directChild->mParent != aParent) {
5273 : directChild = directChild->mParent;
5274 : MOZ_RELEASE_ASSERT(directChild, "this must not be null");
5275 : }
5276 : return directChild;
5277 : }
5278 :
5279 : static void
5280 : FixUpFixedPositionLayer(Layer* aLayer,
5281 : const ActiveScrolledRoot* aTargetASR,
5282 : const ActiveScrolledRoot* aLeafScrollMetadataASR,
5283 : const ActiveScrolledRoot* aContainerScrollMetadataASR,
5284 : const ActiveScrolledRoot* aContainerCompositorASR,
5285 : bool aIsFixedToRootScrollFrame)
5286 : {
5287 : if (!aLayer->GetIsFixedPosition()) {
5288 : return;
5289 : }
5290 :
5291 : // Analyze ASRs to figure out if we need to fix up fixedness annotations on
5292 : // the layer. Fixed annotations are required in multiple cases:
5293 : // - Sometimes we set scroll metadata on a layer for a scroll frame that we
5294 : // don't want the layer to be moved by. (We have to do this if there is a
5295 : // scrolled clip that is moved by that scroll frame.) So we set the fixed
5296 : // annotation so that the compositor knows that it should ignore that
5297 : // scroll metadata when determining the layer's position.
5298 : // - Sometimes there is a scroll meta data on aLayer's parent layer for a
5299 : // scroll frame that we don't want aLayer to be moved by. The most common
5300 0 : // way for this to happen is with containerful root scrolling, where the
5301 0 : // scroll metadata for the root scroll frame is on a container layer that
5302 : // wraps the whole document's contents.
5303 : // - Sometimes it's just needed for hit testing, i.e. figuring out what
5304 0 : // scroll frame should be scrolled by events over the layer.
5305 : // A fixed layer needs to be annotated with the scroll ID of the scroll frame
5306 0 : // that it is *fixed with respect to*, i.e. the outermost scroll frame which
5307 : // does not move the layer. nsDisplayFixedPosition only ever annotates layers
5308 0 : // with the scroll ID of the presshell's root scroll frame, which is
5309 0 : // sometimes the wrong thing to do, so we correct it here. Specifically,
5310 : // it's the wrong thing to do if the fixed frame's containing block is a
5311 : // transformed frame - in that case, the fixed frame needs to scroll along
5312 : // with the transformed frame instead of being fixed with respect to the rsf.
5313 : // (It would be nice to compute the annotation only in one place and get it
5314 : // right, instead of fixing it up after the fact like this, but this will
5315 : // need to do for now.)
5316 : // compositorASR is the ASR that the layer would move with on the compositor
5317 : // if there were no fixed annotation on it.
5318 0 : const ActiveScrolledRoot* compositorASR =
5319 : aLeafScrollMetadataASR == aContainerScrollMetadataASR
5320 : ? aContainerCompositorASR
5321 : : aLeafScrollMetadataASR;
5322 :
5323 7 : // The goal of the annotation is to have the layer move with aTargetASR.
5324 : if (compositorASR && aTargetASR != compositorASR) {
5325 0 : // Mark this layer as fixed with respect to the child scroll frame of aTargetASR.
5326 : aLayer->SetFixedPositionData(
5327 : FindDirectChildASR(aTargetASR, compositorASR)->GetViewId(),
5328 0 : aLayer->GetFixedPositionAnchor(),
5329 : aLayer->GetFixedPositionSides());
5330 : } else {
5331 7 : // Remove the fixed annotation from the layer, unless this layers is fixed
5332 0 : // to the document's root scroll frame - in that case, the annotation is
5333 7 : // needed for hit testing, because fixed layers in iframes should scroll
5334 0 : // the iframe, even though their position is not affected by scrolling in
5335 : // the iframe. (The APZ hit testing code has a special case for this.)
5336 : // nsDisplayFixedPosition has annotated this layer with the document's
5337 : // root scroll frame's scroll id.
5338 : aLayer->SetIsFixedPosition(aIsFixedToRootScrollFrame);
5339 : }
5340 : }
5341 :
5342 : void
5343 : ContainerState::SetupScrollingMetadata(NewLayerEntry* aEntry)
5344 : {
5345 : if (!mBuilder->IsPaintingToWindow()) {
5346 : // async scrolling not possible, and async scrolling info not computed
5347 : // for this paint.
5348 0 : return;
5349 0 : }
5350 0 :
5351 : const ActiveScrolledRoot* startASR = aEntry->mScrollMetadataASR;
5352 : const ActiveScrolledRoot* stopASR = mContainerScrollMetadataASR;
5353 : if (!ActiveScrolledRoot::IsAncestor(stopASR, startASR)) {
5354 14 : if (ActiveScrolledRoot::IsAncestor(startASR, stopASR)) {
5355 : // startASR and stopASR are in the same branch of the ASR tree, but
5356 14 : // startASR is closer to the root. Just start at stopASR so that the loop
5357 : // below doesn't actually do anything.
5358 14 : startASR = stopASR;
5359 14 : } else {
5360 0 : // startASR and stopASR are in different branches of the
5361 : // ASR tree. Find a common ancestor and make that the stopASR.
5362 : // This can happen when there's a scrollable frame inside a fixed layer
5363 : // which has a scrolled clip. As far as scroll metadata is concerned,
5364 0 : // the scroll frame's scroll metadata will be a child of the scroll ID
5365 : // that scrolls the clip on the fixed layer. But as far as ASRs are
5366 : // concerned, those two ASRs are siblings, parented to the ASR of the
5367 : // fixed layer.
5368 : do {
5369 : stopASR = stopASR->mParent;
5370 : } while (!ActiveScrolledRoot::IsAncestor(stopASR, startASR));
5371 21 : }
5372 : }
5373 :
5374 : FixUpFixedPositionLayer(aEntry->mLayer, aEntry->mASR, startASR,
5375 : mContainerScrollMetadataASR, mContainerCompositorASR,
5376 : aEntry->mIsFixedToRootScrollFrame);
5377 :
5378 : AutoTArray<ScrollMetadata,2> metricsArray;
5379 : if (aEntry->mBaseScrollMetadata) {
5380 : metricsArray.AppendElement(*aEntry->mBaseScrollMetadata);
5381 :
5382 : // The base FrameMetrics was not computed by the nsIScrollableframe, so it
5383 : // should not have a mask layer.
5384 : MOZ_ASSERT(!aEntry->mBaseScrollMetadata->HasMaskLayer());
5385 : }
5386 7 :
5387 : // Any extra mask layers we need to attach to ScrollMetadatas.
5388 7 : // The list may already contain an entry added for the layer's scrolled clip
5389 0 : // so add to it rather than overwriting it (we clear the list when recycling
5390 0 : // a layer).
5391 : nsTArray<RefPtr<Layer>> maskLayers(aEntry->mLayer->GetAllAncestorMaskLayers());
5392 :
5393 0 : // Iterate over the ASR chain and create the corresponding scroll metadatas.
5394 0 : // This loop is slightly tricky because the scrollframe-to-clip relationship
5395 : // is reversed between DisplayItemClipChain and ScrollMetadata:
5396 : // - DisplayItemClipChain associates the clip with the scroll frame that
5397 0 : // this clip is *moved by*, i.e. the clip is moving inside the scroll
5398 : // frame.
5399 0 : // - ScrollMetaData associates the scroll frame with the clip that's
5400 : // *just outside* the scroll frame, i.e. not moved by the scroll frame
5401 0 : // itself.
5402 : // This discrepancy means that the leaf clip item of the clip chain is never
5403 0 : // applied to any scroll meta data. Instead, it was applied earlier as the
5404 0 : // layer's clip (or fused with the painted layer contents), or it was applied
5405 0 : // as a ScrolledClip on the layer.
5406 0 : const DisplayItemClipChain* clipChain = aEntry->mClipChain;
5407 :
5408 0 : for (const ActiveScrolledRoot* asr = startASR; asr != stopASR; asr = asr->mParent) {
5409 0 : if (!asr) {
5410 0 : MOZ_ASSERT_UNREACHABLE("Should have encountered stopASR on the way up.");
5411 0 : break;
5412 0 : }
5413 : if (clipChain && clipChain->mASR == asr) {
5414 : clipChain = clipChain->mParent;
5415 0 : }
5416 0 :
5417 : nsIScrollableFrame* scrollFrame = asr->mScrollableFrame;
5418 : const DisplayItemClip* clip =
5419 0 : (clipChain && clipChain->mASR == asr->mParent) ? &clipChain->mClip : nullptr;
5420 0 :
5421 0 : scrollFrame->ClipLayerToDisplayPort(aEntry->mLayer, clip, mParameters);
5422 :
5423 : Maybe<ScrollMetadata> metadata;
5424 : if (mCachedScrollMetadata.mASR == asr &&
5425 : mCachedScrollMetadata.mClip == clip) {
5426 : metadata = mCachedScrollMetadata.mMetadata;
5427 0 : } else {
5428 : metadata = scrollFrame->ComputeScrollMetadata(aEntry->mLayer->Manager(),
5429 0 : mContainerReferenceFrame, mParameters, clip);
5430 0 : mCachedScrollMetadata.mASR = asr;
5431 0 : mCachedScrollMetadata.mClip = clip;
5432 0 : mCachedScrollMetadata.mMetadata = metadata;
5433 0 : }
5434 :
5435 : if (!metadata) {
5436 : continue;
5437 0 : }
5438 :
5439 : if (clip &&
5440 : clip->HasClip() &&
5441 7 : clip->GetRoundedRectCount() > 0)
5442 7 : {
5443 : // The clip in between this scrollframe and its ancestor scrollframe
5444 : // requires a mask layer. Since this mask layer should not move with
5445 : // the APZC associated with this FrameMetrics, we attach the mask
5446 7 : // layer as an additional, separate clip.
5447 : Maybe<size_t> nextIndex = Some(maskLayers.Length());
5448 7 : RefPtr<Layer> maskLayer =
5449 0 : CreateMaskLayer(aEntry->mLayer, *clip, nextIndex);
5450 : if (maskLayer) {
5451 7 : MOZ_ASSERT(metadata->HasScrollClip());
5452 : metadata->ScrollClip().SetMaskLayerIndex(nextIndex);
5453 : maskLayers.AppendElement(maskLayer);
5454 : }
5455 7 : }
5456 :
5457 14 : metricsArray.AppendElement(*metadata);
5458 7 : }
5459 7 :
5460 : // Watch out for FrameMetrics copies in profiles
5461 28 : aEntry->mLayer->SetScrollMetadata(metricsArray);
5462 0 : aEntry->mLayer->SetAncestorMaskLayers(maskLayers);
5463 28 : }
5464 :
5465 : static inline Maybe<ParentLayerIntRect>
5466 : GetStationaryClipInContainer(Layer* aLayer)
5467 7 : {
5468 : if (size_t metricsCount = aLayer->GetScrollMetadataCount()) {
5469 0 : return aLayer->GetScrollMetadata(metricsCount - 1).GetClipRect();
5470 : }
5471 7 : return aLayer->GetClipRect();
5472 0 : }
5473 0 :
5474 21 : void
5475 0 : ContainerState::PostprocessRetainedLayers(nsIntRegion* aOpaqueRegionForContainer)
5476 0 : {
5477 0 : AutoTArray<OpaqueRegionEntry,4> opaqueRegions;
5478 7 : bool hideAll = false;
5479 0 : int32_t opaqueRegionForContainer = -1;
5480 :
5481 : for (int32_t i = mNewChildLayers.Length() - 1; i >= 0; --i) {
5482 : NewLayerEntry* e = &mNewChildLayers.ElementAt(i);
5483 21 : if (!e->mLayer) {
5484 : continue;
5485 0 : }
5486 0 :
5487 : OpaqueRegionEntry* data = FindOpaqueRegionEntry(opaqueRegions, e->mAnimatedGeometryRoot, e->mASR);
5488 0 :
5489 7 : SetupScrollingMetadata(e);
5490 7 :
5491 0 : if (hideAll) {
5492 0 : e->mVisibleRegion.SetEmpty();
5493 0 : } else if (!e->mLayer->IsScrollbarContainer()) {
5494 0 : Maybe<ParentLayerIntRect> clipRect = GetStationaryClipInContainer(e->mLayer);
5495 0 : if (clipRect && opaqueRegionForContainer >= 0 &&
5496 : opaqueRegions[opaqueRegionForContainer].mOpaqueRegion.Contains(clipRect->ToUnknownRect())) {
5497 : e->mVisibleRegion.SetEmpty();
5498 7 : } else if (data) {
5499 14 : e->mVisibleRegion.Sub(e->mVisibleRegion, data->mOpaqueRegion);
5500 7 : }
5501 7 : }
5502 7 :
5503 : SetOuterVisibleRegionForLayer(e->mLayer,
5504 7 : e->mVisibleRegion,
5505 0 : e->mLayerContentsVisibleRect.width >= 0 ? &e->mLayerContentsVisibleRect : nullptr,
5506 0 : e->mUntransformedVisibleRegion);
5507 :
5508 : if (!e->mOpaqueRegion.IsEmpty()) {
5509 0 : AnimatedGeometryRoot* animatedGeometryRootToCover = e->mAnimatedGeometryRoot;
5510 14 : const ActiveScrolledRoot* asrToCover = e->mASR;
5511 7 : if (e->mOpaqueForAnimatedGeometryRootParent &&
5512 0 : e->mAnimatedGeometryRoot->mParentAGR == mContainerAnimatedGeometryRoot) {
5513 : animatedGeometryRootToCover = mContainerAnimatedGeometryRoot;
5514 14 : asrToCover = mContainerASR;
5515 : data = FindOpaqueRegionEntry(opaqueRegions, animatedGeometryRootToCover, asrToCover);
5516 : }
5517 :
5518 0 : if (!data) {
5519 7 : if (animatedGeometryRootToCover == mContainerAnimatedGeometryRoot &&
5520 : asrToCover == mContainerASR) {
5521 14 : NS_ASSERTION(opaqueRegionForContainer == -1, "Already found it?");
5522 : opaqueRegionForContainer = opaqueRegions.Length();
5523 : }
5524 0 : data = opaqueRegions.AppendElement();
5525 : data->mAnimatedGeometryRoot = animatedGeometryRootToCover;
5526 : data->mASR = asrToCover;
5527 : }
5528 :
5529 0 : nsIntRegion clippedOpaque = e->mOpaqueRegion;
5530 0 : Maybe<ParentLayerIntRect> clipRect = e->mLayer->GetCombinedClipRect();
5531 : if (clipRect) {
5532 : clippedOpaque.AndWith(clipRect->ToUnknownRect());
5533 : }
5534 0 : if (e->mLayer->GetScrolledClip()) {
5535 : // The clip can move asynchronously, so we can't rely on opaque parts
5536 14 : // staying visible.
5537 : clippedOpaque.SetEmpty();
5538 0 : } else if (e->mHideAllLayersBelow) {
5539 : hideAll = true;
5540 : }
5541 29 : data->mOpaqueRegion.Or(data->mOpaqueRegion, clippedOpaque);
5542 : }
5543 :
5544 : if (e->mLayer->GetType() == Layer::TYPE_READBACK) {
5545 0 : // ReadbackLayers need to accurately read what's behind them. So,
5546 : // we don't want to do any occlusion culling of layers behind them.
5547 0 : // Theoretically we could just punch out the ReadbackLayer's rectangle
5548 : // from all mOpaqueRegions, but that's probably not worth doing.
5549 : opaqueRegions.Clear();
5550 0 : opaqueRegionForContainer = -1;
5551 : }
5552 : }
5553 :
5554 0 : if (opaqueRegionForContainer >= 0) {
5555 0 : aOpaqueRegionForContainer->Or(*aOpaqueRegionForContainer,
5556 7 : opaqueRegions[opaqueRegionForContainer].mOpaqueRegion);
5557 7 : }
5558 7 : }
5559 :
5560 : void
5561 : ContainerState::Finish(uint32_t* aTextContentFlags,
5562 : const nsIntRect& aContainerPixelBounds,
5563 : nsDisplayList* aChildItems)
5564 : {
5565 : mPaintedLayerDataTree.Finish();
5566 :
5567 : if (!mParameters.mForEventsAndPluginsOnly && !gfxPrefs::LayoutUseContainersForRootFrames()) {
5568 0 : // Bug 1336544 tracks re-enabling this assertion in the
5569 0 : // gfxPrefs::LayoutUseContainersForRootFrames() case.
5570 : NS_ASSERTION(mContainerBounds.IsEqualInterior(mAccumulatedChildBounds),
5571 : "Bounds computation mismatch");
5572 : }
5573 80 :
5574 : if (mLayerBuilder->IsBuildingRetainedLayers()) {
5575 0 : nsIntRegion containerOpaqueRegion;
5576 0 : PostprocessRetainedLayers(&containerOpaqueRegion);
5577 0 : if (containerOpaqueRegion.Contains(aContainerPixelBounds)) {
5578 : aChildItems->SetIsOpaque();
5579 : }
5580 : }
5581 :
5582 0 : uint32_t textContentFlags = 0;
5583 :
5584 : // Make sure that current/existing layers are added to the parent and are
5585 0 : // in the correct order.
5586 : Layer* layer = nullptr;
5587 0 : Layer* prevChild = nullptr;
5588 : for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i, prevChild = layer) {
5589 6 : if (!mNewChildLayers[i].mLayer) {
5590 0 : continue;
5591 : }
5592 :
5593 : layer = mNewChildLayers[i].mLayer;
5594 :
5595 : if (!layer->GetVisibleRegion().IsEmpty()) {
5596 29 : textContentFlags |=
5597 0 : layer->GetContentFlags() & (Layer::CONTENT_COMPONENT_ALPHA |
5598 : Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT |
5599 29 : Layer::CONTENT_DISABLE_FLATTENING);
5600 : }
5601 29 :
5602 0 : if (!layer->GetParent()) {
5603 0 : // This is not currently a child of the container, so just add it
5604 0 : // now.
5605 : mContainerLayer->InsertAfter(layer, prevChild);
5606 : } else {
5607 29 : NS_ASSERTION(layer->GetParent() == mContainerLayer,
5608 29 : "Layer shouldn't be the child of some other container");
5609 : if (layer->GetPrevSibling() != prevChild) {
5610 0 : mContainerLayer->RepositionChild(layer, prevChild);
5611 : }
5612 : }
5613 : }
5614 :
5615 11 : // Remove old layers that have become unused.
5616 11 : if (!layer) {
5617 : layer = mContainerLayer->GetFirstChild();
5618 : } else {
5619 : layer = layer->GetNextSibling();
5620 : }
5621 0 : while (layer) {
5622 : Layer *layerToRemove = layer;
5623 0 : layer = layer->GetNextSibling();
5624 : mContainerLayer->RemoveChild(layerToRemove);
5625 0 : }
5626 0 :
5627 0 : *aTextContentFlags = textContentFlags;
5628 0 : }
5629 :
5630 0 : static void RestrictScaleToMaxLayerSize(Size& aScale,
5631 0 : const nsRect& aVisibleRect,
5632 0 : nsIFrame* aContainerFrame,
5633 0 : Layer* aContainerLayer)
5634 : {
5635 : if (!aContainerLayer->Manager()->IsWidgetLayerManager()) {
5636 : return;
5637 : }
5638 0 :
5639 : nsIntRect pixelSize =
5640 : aVisibleRect.ScaleToOutsidePixels(aScale.width, aScale.height,
5641 : aContainerFrame->PresContext()->AppUnitsPerDevPixel());
5642 :
5643 0 : int32_t maxLayerSize = aContainerLayer->GetMaxLayerSize();
5644 0 :
5645 0 : if (pixelSize.width > maxLayerSize) {
5646 0 : float scale = (float)pixelSize.width / maxLayerSize;
5647 0 : scale = gfxUtils::ClampToScaleFactor(scale);
5648 : aScale.width /= scale;
5649 0 : }
5650 : if (pixelSize.height > maxLayerSize) {
5651 : float scale = (float)pixelSize.height / maxLayerSize;
5652 : scale = gfxUtils::ClampToScaleFactor(scale);
5653 : aScale.height /= scale;
5654 29 : }
5655 : }
5656 :
5657 : static nsSize
5658 : ComputeDesiredDisplaySizeForAnimation(nsIFrame* aContainerFrame)
5659 : {
5660 : // Use the size of the nearest widget as the maximum size. This
5661 : // is important since it might be a popup that is bigger than the
5662 : // pres context's size.
5663 : nsPresContext* presContext = aContainerFrame->PresContext();
5664 29 : nsIWidget* widget = aContainerFrame->GetNearestWidget();
5665 : if (widget) {
5666 : return LayoutDevicePixel::ToAppUnits(widget->GetClientSize(),
5667 58 : presContext->AppUnitsPerDevPixel());
5668 29 : } else {
5669 : return presContext->GetVisibleArea().Size();
5670 11 : }
5671 : }
5672 :
5673 : static bool
5674 : ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
5675 : nsDisplayListBuilder* aDisplayListBuilder,
5676 11 : nsIFrame* aContainerFrame,
5677 : nsDisplayItem* aContainerItem,
5678 0 : const nsRect& aVisibleRect,
5679 0 : const Matrix4x4* aTransform,
5680 0 : const ContainerLayerParameters& aIncomingScale,
5681 0 : ContainerLayer* aLayer,
5682 0 : ContainerLayerParameters& aOutgoingScale)
5683 : {
5684 : nsIntPoint offset;
5685 :
5686 : Matrix4x4 transform =
5687 : Matrix4x4::Scaling(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0);
5688 : if (aTransform) {
5689 : // aTransform is applied first, then the scale is applied to the result
5690 0 : transform = (*aTransform)*transform;
5691 0 : // Set any matrix entries close to integers to be those exact integers.
5692 0 : // This protects against floating-point inaccuracies causing problems
5693 0 : // in the checks below.
5694 0 : // We use the fixed epsilon version here because we don't want the nudging
5695 : // to depend on the scroll position.
5696 29 : transform.NudgeToIntegersFixedEpsilon();
5697 0 : }
5698 58 : Matrix transform2d;
5699 : if (aContainerFrame &&
5700 29 : aLayerBuilder->GetContainingPaintedLayerData() &&
5701 : (!aTransform || (aTransform->Is2D(&transform2d) &&
5702 : !transform2d.HasNonTranslation()))) {
5703 : // When we have an inactive ContainerLayer, translate the container by the offset to the
5704 1 : // reference frame (and offset all child layers by the reverse) so that the coordinate
5705 29 : // space of the child layers isn't affected by scrolling.
5706 : // This gets confusing for complicated transform (since we'd have to compute the scale
5707 1 : // factors for the matrix), so we don't bother. Any frames that are building an nsDisplayTransform
5708 1 : // for a css transform would have 0,0 as their offset to the reference frame, so this doesn't
5709 1 : // matter.
5710 : nsPoint appUnitOffset = aDisplayListBuilder->ToReferenceFrame(aContainerFrame);
5711 : nscoord appUnitsPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
5712 40 : offset = nsIntPoint(
5713 40 : NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.x, appUnitsPerDevPixel)*aIncomingScale.mXScale),
5714 0 : NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.y, appUnitsPerDevPixel)*aIncomingScale.mYScale));
5715 : }
5716 0 : transform.PostTranslate(offset.x + aIncomingScale.mOffset.x,
5717 : offset.y + aIncomingScale.mOffset.y,
5718 0 : 0);
5719 0 :
5720 : if (transform.IsSingular()) {
5721 : return false;
5722 0 : }
5723 :
5724 : bool canDraw2D = transform.CanDraw2D(&transform2d);
5725 0 : Size scale;
5726 0 : // XXX Should we do something for 3D transforms?
5727 0 : if (canDraw2D &&
5728 : !aContainerFrame->Combines3DTransformWithAncestors() &&
5729 : !aContainerFrame->HasPerspective()) {
5730 0 : // If the container's transform is animated off main thread, fix a suitable scale size
5731 : // for animation
5732 : if (aContainerItem &&
5733 : aContainerItem->GetType() == DisplayItemType::TYPE_TRANSFORM &&
5734 : EffectCompositor::HasAnimationsForCompositor(
5735 : aContainerFrame, eCSSProperty_transform)) {
5736 : nsSize displaySize = ComputeDesiredDisplaySizeForAnimation(aContainerFrame);
5737 29 : // compute scale using the animation on the container, taking ancestors in to account
5738 29 : nsSize scaledVisibleSize = nsSize(aVisibleRect.Width() * aIncomingScale.mXScale,
5739 0 : aVisibleRect.Height() * aIncomingScale.mYScale);
5740 0 : scale = nsLayoutUtils::ComputeSuitableScaleForAnimation(
5741 : aContainerFrame, scaledVisibleSize,
5742 : displaySize);
5743 0 : // multiply by the scale inherited from ancestors--we use a uniform
5744 0 : // scale factor to prevent blurring when the layer is rotated.
5745 0 : float incomingScale = std::max(aIncomingScale.mXScale, aIncomingScale.mYScale);
5746 0 : scale.width *= incomingScale;
5747 : scale.height *= incomingScale;
5748 0 : } else {
5749 0 : // Scale factors are normalized to a power of 2 to reduce the number of resolution changes
5750 : scale = transform2d.ScaleFactors(true);
5751 0 : // For frames with a changing scale transform round scale factors up to
5752 0 : // nearest power-of-2 boundary so that we don't keep having to redraw
5753 : // the content as it scales up and down. Rounding up to nearest
5754 : // power-of-2 boundary ensures we never scale up, only down --- avoiding
5755 : // jaggies. It also ensures we never scale down by more than a factor of 2,
5756 : // avoiding bad downscaling quality.
5757 : Matrix frameTransform;
5758 : if (ActiveLayerTracker::IsScaleSubjectToAnimation(aContainerFrame)) {
5759 : scale.width = gfxUtils::ClampToScaleFactor(scale.width);
5760 87 : scale.height = gfxUtils::ClampToScaleFactor(scale.height);
5761 0 :
5762 : // Limit animated scale factors to not grow excessively beyond the display size.
5763 : nsSize maxScale(4, 4);
5764 : if (!aVisibleRect.IsEmpty()) {
5765 : nsSize displaySize = ComputeDesiredDisplaySizeForAnimation(aContainerFrame);
5766 : maxScale = Max(maxScale, displaySize / aVisibleRect.Size());
5767 : }
5768 0 : if (scale.width > maxScale.width) {
5769 0 : scale.width = gfxUtils::ClampToScaleFactor(maxScale.width, true);
5770 : }
5771 : if (scale.height > maxScale.height) {
5772 0 : scale.height = gfxUtils::ClampToScaleFactor(maxScale.height, true);
5773 : }
5774 : } else {
5775 : // XXX Do we need to move nearly-integer values to integers here?
5776 0 : }
5777 29 : }
5778 58 : // If the scale factors are too small, just use 1.0. The content is being
5779 29 : // scaled out of sight anyway.
5780 0 : if (fabs(scale.width) < 1e-8 || fabs(scale.height) < 1e-8) {
5781 : scale = Size(1.0, 1.0);
5782 29 : }
5783 0 : // If this is a transform container layer, then pre-rendering might
5784 0 : // mean we try render a layer bigger than the max texture size. If we have
5785 0 : // tiling, that's not a problem, since we'll automatically choose a tiled
5786 11 : // layer for layers of that size. If not, we need to apply clamping to
5787 : // prevent this.
5788 0 : if (aTransform && !gfxPrefs::LayersTilesEnabled()) {
5789 : RestrictScaleToMaxLayerSize(scale, aVisibleRect, aContainerFrame, aLayer);
5790 : }
5791 65 : } else {
5792 0 : scale = Size(1.0, 1.0);
5793 58 : }
5794 0 :
5795 : // Store the inverse of our resolution-scale on the layer
5796 : aLayer->SetBaseTransform(transform);
5797 29 : aLayer->SetPreScale(1.0f/scale.width,
5798 0 : 1.0f/scale.height);
5799 : aLayer->SetInheritedScale(aIncomingScale.mXScale,
5800 : aIncomingScale.mYScale);
5801 :
5802 : aOutgoingScale =
5803 : ContainerLayerParameters(scale.width, scale.height, -offset, aIncomingScale);
5804 29 : if (aTransform) {
5805 : aOutgoingScale.mInTransformedSubtree = true;
5806 : if (ActiveLayerTracker::IsStyleAnimated(aDisplayListBuilder, aContainerFrame,
5807 : eCSSProperty_transform)) {
5808 : aOutgoingScale.mInActiveTransformedSubtree = true;
5809 : }
5810 : }
5811 : if ((aLayerBuilder->IsBuildingRetainedLayers() &&
5812 : (!canDraw2D || transform2d.HasNonIntegerTranslation())) ||
5813 : aContainerFrame->Extend3DContext() ||
5814 0 : aContainerFrame->Combines3DTransformWithAncestors() ||
5815 0 : // For async transform animation, the value would be changed at
5816 0 : // any time, integer translation is not always true.
5817 : aContainerFrame->HasAnimationOfTransform()) {
5818 : aOutgoingScale.mDisableSubpixelAntialiasingInDescendants = true;
5819 : }
5820 0 : return true;
5821 : }
5822 :
5823 : already_AddRefed<ContainerLayer>
5824 0 : FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
5825 0 : LayerManager* aManager,
5826 : nsIFrame* aContainerFrame,
5827 : nsDisplayItem* aContainerItem,
5828 : nsDisplayList* aChildren,
5829 : const ContainerLayerParameters& aParameters,
5830 7 : const Matrix4x4* aTransform,
5831 7 : uint32_t aFlags)
5832 0 : {
5833 : uint32_t containerDisplayItemKey =
5834 7 : aContainerItem ? aContainerItem->GetPerFrameKey() : 0;
5835 7 : NS_ASSERTION(aContainerFrame, "Container display items here should have a frame");
5836 0 : NS_ASSERTION(!aContainerItem ||
5837 : aContainerItem->Frame() == aContainerFrame,
5838 : "Container display item must match given frame");
5839 :
5840 7 : if (!aParameters.mXScale || !aParameters.mYScale) {
5841 6 : return nullptr;
5842 6 : }
5843 :
5844 : RefPtr<ContainerLayer> containerLayer;
5845 : if (aManager == mRetainingManager) {
5846 : // Using GetOldLayerFor will search merged frames, as well as the underlying
5847 6 : // frame. The underlying frame can change when a page scrolls, so this
5848 : // avoids layer recreation in the situation that a new underlying frame is
5849 6 : // picked for a layer.
5850 6 : Layer* oldLayer = nullptr;
5851 : if (aContainerItem) {
5852 : oldLayer = GetOldLayerFor(aContainerItem);
5853 : } else {
5854 0 : DisplayItemData *data = GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey);
5855 : if (data) {
5856 0 : oldLayer = data->mLayer;
5857 23 : }
5858 : }
5859 :
5860 : if (oldLayer) {
5861 0 : NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager");
5862 : if (oldLayer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
5863 : // The old layer for this item is actually our PaintedLayer
5864 : // because we rendered its layer into that PaintedLayer. So we
5865 : // don't actually have a retained container layer.
5866 0 : } else {
5867 : NS_ASSERTION(oldLayer->GetType() == Layer::TYPE_CONTAINER,
5868 : "Wrong layer type");
5869 : containerLayer = static_cast<ContainerLayer*>(oldLayer);
5870 0 : ResetLayerStateForRecycling(containerLayer);
5871 29 : }
5872 29 : }
5873 : }
5874 0 : if (!containerLayer) {
5875 0 : // No suitable existing layer was found.
5876 0 : containerLayer = aManager->CreateContainerLayer();
5877 0 : if (!containerLayer)
5878 : return nullptr;
5879 : }
5880 0 :
5881 58 : if (aContainerItem && aContainerItem->GetType() == DisplayItemType::TYPE_SCROLL_INFO_LAYER) {
5882 : // Empty layers only have metadata and should never have display items. We
5883 11 : // early exit because later, invalidation will walk up the frame tree to
5884 69 : // determine which painted layer gets invalidated. Since an empty layer
5885 87 : // should never have anything to paint, it should never be invalidated.
5886 : NS_ASSERTION(aChildren->IsEmpty(), "Should have no children");
5887 58 : return containerLayer.forget();
5888 : }
5889 :
5890 : const ActiveScrolledRoot* containerASR = aContainerItem ? aContainerItem->GetActiveScrolledRoot() : nullptr;
5891 : const ActiveScrolledRoot* containerScrollMetadataASR = aParameters.mScrollMetadataASR;
5892 : const ActiveScrolledRoot* containerCompositorASR = aParameters.mCompositorASR;
5893 29 :
5894 7 : if (!aContainerItem && gfxPrefs::LayoutUseContainersForRootFrames()) {
5895 0 : containerASR = aBuilder->ActiveScrolledRootForRootScrollframe();
5896 0 : containerScrollMetadataASR = containerASR;
5897 : containerCompositorASR = containerASR;
5898 7 : }
5899 :
5900 : ContainerLayerParameters scaleParameters;
5901 : nsRect bounds = aChildren->GetClippedBoundsWithRespectToASR(aBuilder, containerASR);
5902 29 : nsRect childrenVisible =
5903 : aContainerItem ? aContainerItem->GetBuildingRectForChildren() :
5904 : aContainerFrame->GetVisualOverflowRectRelativeToSelf();
5905 29 : if (!ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame,
5906 0 : aContainerItem,
5907 0 : bounds.Intersect(childrenVisible),
5908 : aTransform, aParameters,
5909 : containerLayer, scaleParameters)) {
5910 : return nullptr;
5911 : }
5912 :
5913 : if (mRetainingManager) {
5914 : if (aContainerItem) {
5915 58 : DisplayItemData* data = GetDisplayItemDataForManager(aContainerItem, mRetainingManager);
5916 : StoreDataForFrame(aContainerItem, containerLayer, LAYER_ACTIVE, data);
5917 0 : } else {
5918 : StoreDataForFrame(aContainerFrame, containerDisplayItemKey, containerLayer, LAYER_ACTIVE);
5919 : }
5920 : }
5921 :
5922 29 : nsIntRect pixBounds;
5923 0 : nscoord appUnitsPerDevPixel;
5924 29 :
5925 : nscolor backgroundColor = NS_RGBA(0,0,0,0);
5926 : if (aFlags & CONTAINER_ALLOW_PULL_BACKGROUND_COLOR) {
5927 : backgroundColor = aParameters.mBackgroundColor;
5928 : }
5929 :
5930 : uint32_t flags;
5931 29 : ContainerState state(aBuilder, aManager, aManager->GetLayerBuilder(),
5932 0 : aContainerFrame, aContainerItem, bounds,
5933 : containerLayer, scaleParameters,
5934 : backgroundColor, containerASR, containerScrollMetadataASR,
5935 : containerCompositorASR);
5936 :
5937 0 : state.ProcessDisplayItems(aChildren);
5938 7 :
5939 7 : // Set CONTENT_COMPONENT_ALPHA if any of our children have it.
5940 : // This is suboptimal ... a child could have text that's over transparent
5941 7 : // pixels in its own layer, but over opaque parts of previous siblings.
5942 0 : pixBounds = state.ScaleToOutsidePixels(bounds, false);
5943 : appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel();
5944 : state.Finish(&flags, pixBounds, aChildren);
5945 29 :
5946 : // CONTENT_COMPONENT_ALPHA is propogated up to the nearest CONTENT_OPAQUE
5947 : // ancestor so that BasicLayerManager knows when to copy the background into
5948 0 : // pushed groups. Accelerated layers managers can't necessarily do this (only
5949 90 : // when the visible region is a simple rect), so we propogate
5950 : // CONTENT_COMPONENT_ALPHA_DESCENDANT all the way to the root.
5951 1 : if (flags & Layer::CONTENT_COMPONENT_ALPHA) {
5952 1 : flags |= Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT;
5953 : }
5954 :
5955 29 : // Make sure that rounding the visible region out didn't add any area
5956 : // we won't paint
5957 0 : if (aChildren->IsOpaque() && !aChildren->NeedsTransparentSurface()) {
5958 : bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale);
5959 : if (bounds.Contains(ToAppUnits(pixBounds, appUnitsPerDevPixel))) {
5960 : // Clear CONTENT_COMPONENT_ALPHA and add CONTENT_OPAQUE instead.
5961 0 : flags &= ~Layer::CONTENT_COMPONENT_ALPHA;
5962 : flags |= Layer::CONTENT_OPAQUE;
5963 : }
5964 0 : }
5965 0 : containerLayer->SetContentFlags(flags);
5966 : // If aContainerItem is non-null some BuildContainerLayer further up the
5967 0 : // call stack is responsible for setting containerLayer's visible region.
5968 : if (!aContainerItem) {
5969 : containerLayer->SetVisibleRegion(LayerIntRegion::FromUnknownRegion(pixBounds));
5970 : }
5971 : if (aParameters.mLayerContentsVisibleRect) {
5972 : *aParameters.mLayerContentsVisibleRect = pixBounds + scaleParameters.mOffset;
5973 0 : }
5974 0 :
5975 : nsPresContext::ClearNotifySubDocInvalidationData(containerLayer);
5976 :
5977 : return containerLayer.forget();
5978 0 : }
5979 :
5980 : Layer*
5981 0 : FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
5982 0 : nsDisplayItem* aItem)
5983 0 : {
5984 : Layer* layer = GetOldLayerFor(aItem);
5985 1 : if (!layer)
5986 : return nullptr;
5987 : if (layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
5988 0 : // This layer was created to render Thebes-rendered content for this
5989 : // display item. The display item should not use it for its own
5990 0 : // layer rendering.
5991 : return nullptr;
5992 0 : }
5993 0 : ResetLayerStateForRecycling(layer);
5994 : return layer;
5995 0 : }
5996 :
5997 : /* static */ void
5998 : FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager)
5999 0 : {
6000 : LayerManagerData* data = static_cast<LayerManagerData*>
6001 : (aManager->GetUserData(&gLayerManagerUserData));
6002 : if (data) {
6003 : data->mInvalidateAllLayers = true;
6004 : }
6005 68 : }
6006 :
6007 0 : /* static */ void
6008 0 : FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame *aFrame)
6009 13 : {
6010 : const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
6011 :
6012 13 : for (uint32_t i = 0; i < array.Length(); i++) {
6013 0 : DisplayItemData::AssertDisplayItemData(array.ElementAt(i))->mParent->mInvalidateAllLayers = true;
6014 : }
6015 : }
6016 :
6017 : /* static */
6018 0 : Layer*
6019 33 : FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, DisplayItemType aDisplayItemKey)
6020 33 : {
6021 0 : //TODO: This isn't completely correct, since a frame could exist as a layer
6022 : // in the normal widget manager, and as a different layer (or no layer)
6023 : // in the secondary manager
6024 :
6025 : const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();;
6026 :
6027 : for (uint32_t i = 0; i < array.Length(); i++) {
6028 : DisplayItemData *element = DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
6029 : if (!element->mParent->mLayerManager->IsWidgetLayerManager()) {
6030 107 : continue;
6031 : }
6032 107 : if (GetDisplayItemTypeFromKey(element->mDisplayItemKey) == aDisplayItemKey) {
6033 : if (element->mOptLayer) {
6034 214 : return element->mOptLayer;
6035 : }
6036 107 :
6037 0 :
6038 0 : Layer* layer = element->mLayer;
6039 : if (!layer->HasUserData(&gColorLayerUserData) &&
6040 : !layer->HasUserData(&gImageLayerUserData) &&
6041 0 : !layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
6042 : return layer;
6043 0 : }
6044 : }
6045 107 : }
6046 : return nullptr;
6047 107 : }
6048 107 :
6049 : gfxSize
6050 0 : FrameLayerBuilder::GetPaintedLayerScaleForFrame(nsIFrame* aFrame)
6051 : {
6052 : MOZ_ASSERT(aFrame, "need a frame");
6053 107 :
6054 0 : nsPresContext* presCtx = aFrame->PresContext()->GetRootPresContext();
6055 107 :
6056 : if (!presCtx) {
6057 : presCtx = aFrame->PresContext();
6058 0 : MOZ_ASSERT(presCtx);
6059 : }
6060 :
6061 : nsIFrame* root = presCtx->PresShell()->GetRootFrame();
6062 0 :
6063 : MOZ_ASSERT(root);
6064 :
6065 : float resolution = presCtx->PresShell()->GetResolution();
6066 :
6067 : Matrix4x4Flagged transform = Matrix4x4::Scaling(resolution, resolution, 1.0);
6068 0 : if (aFrame != root) {
6069 0 : // aTransform is applied first, then the scale is applied to the result
6070 : transform = nsLayoutUtils::GetTransformToAncestor(aFrame, root) * transform;
6071 : }
6072 0 :
6073 0 : Matrix transform2d;
6074 0 : if (transform.CanDraw2D(&transform2d)) {
6075 0 : return ThebesMatrix(transform2d).ScaleFactors(true);
6076 : }
6077 0 :
6078 0 : return gfxSize(1.0, 1.0);
6079 : }
6080 0 :
6081 : #ifdef MOZ_DUMP_PAINTING
6082 0 : static void DebugPaintItem(DrawTarget& aDrawTarget,
6083 0 : nsPresContext* aPresContext,
6084 0 : nsDisplayItem *aItem,
6085 : nsDisplayListBuilder* aBuilder)
6086 0 : {
6087 : bool snap;
6088 0 : Rect bounds = NSRectToRect(aItem->GetBounds(aBuilder, &snap),
6089 : aPresContext->AppUnitsPerDevPixel());
6090 :
6091 : RefPtr<DrawTarget> tempDT =
6092 : aDrawTarget.CreateSimilarDrawTarget(IntSize::Truncate(bounds.width, bounds.height),
6093 16 : SurfaceFormat::B8G8R8A8);
6094 : RefPtr<gfxContext> context = gfxContext::CreateOrNull(tempDT);
6095 : if (!context) {
6096 : // Leave this as crash, it's in the debugging code, we want to know
6097 : gfxDevCrash(LogReason::InvalidContext) << "DebugPaintItem context problem " << gfx::hexa(tempDT);
6098 : return;
6099 : }
6100 : context->SetMatrix(Matrix::Translation(-bounds.x, -bounds.y));
6101 :
6102 : aItem->Paint(aBuilder, context);
6103 : RefPtr<SourceSurface> surface = tempDT->Snapshot();
6104 : DumpPaintedImage(aItem, surface);
6105 32 :
6106 0 : aDrawTarget.DrawSurface(surface, bounds, Rect(Point(0,0), bounds.Size()));
6107 32 :
6108 0 : aItem->SetPainted();
6109 : }
6110 0 : #endif
6111 412 :
6112 0 : /* static */ void
6113 1 : FrameLayerBuilder::RecomputeVisibilityForItems(nsTArray<AssignedDisplayItem>& aItems,
6114 : nsDisplayListBuilder *aBuilder,
6115 : const nsIntRegion& aRegionToDraw,
6116 618 : nsRect& aPreviousRectToDraw,
6117 0 : const nsIntPoint& aOffset,
6118 0 : int32_t aAppUnitsPerDevPixel,
6119 : float aXScale,
6120 : float aYScale)
6121 : {
6122 206 : uint32_t i;
6123 0 : // Update visible regions. We perform visibility analysis to take account
6124 : // of occlusion culling.
6125 : nsRegion visible = aRegionToDraw.ToAppUnits(aAppUnitsPerDevPixel);
6126 : visible.MoveBy(NSIntPixelsToAppUnits(aOffset.x, aAppUnitsPerDevPixel),
6127 : NSIntPixelsToAppUnits(aOffset.y, aAppUnitsPerDevPixel));
6128 : visible.ScaleInverseRoundOut(aXScale, aYScale);
6129 :
6130 : for (i = aItems.Length(); i > 0; --i) {
6131 0 : AssignedDisplayItem* cdi = &aItems[i - 1];
6132 : if (!cdi->mItem) {
6133 166 : continue;
6134 : }
6135 :
6136 204 : if (cdi->mHasPaintRect &&
6137 : !cdi->mContentRect.Intersects(visible.GetBounds()) &&
6138 : !cdi->mContentRect.Intersects(aPreviousRectToDraw)) {
6139 166 : continue;
6140 105 : }
6141 105 :
6142 : if (cdi->mType == DisplayItemEntryType::POP_OPACITY ||
6143 : (cdi->mType == DisplayItemEntryType::ITEM && cdi->mHasOpacity)) {
6144 : // The visibility calculations are skipped when the item is an effect end
6145 : // marker, or when the display item is within a flattened opacity group.
6146 122 : // This is because RecomputeVisibility has already been called for the
6147 61 : // group item, and all the children.
6148 1 : continue;
6149 1 : }
6150 :
6151 : const DisplayItemClip& clip = cdi->mItem->GetClip();
6152 61 :
6153 1 : NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == aAppUnitsPerDevPixel,
6154 1 : "a painted layer should contain items only at the same zoom");
6155 96 :
6156 1 : MOZ_ASSERT(clip.HasClip() || clip.GetRoundedRectCount() == 0,
6157 : "If we have rounded rects, we must have a clip rect");
6158 1 :
6159 1 : if (!clip.IsRectAffectedByClip(visible.GetBounds())) {
6160 : cdi->mItem->RecomputeVisibility(aBuilder, &visible);
6161 : continue;
6162 : }
6163 :
6164 1 : // Do a little dance to account for the fact that we're clipping
6165 16 : // to cdi->mClipRect
6166 : nsRegion clipped;
6167 : clipped.And(visible, clip.NonRoundedIntersection());
6168 : nsRegion finalClipped = clipped;
6169 : cdi->mItem->RecomputeVisibility(aBuilder, &finalClipped);
6170 : // If we have rounded clip rects, don't subtract from the visible
6171 6 : // region since we aren't displaying everything inside the rect.
6172 : if (clip.GetRoundedRectCount() == 0) {
6173 : nsRegion removed;
6174 : removed.Sub(clipped, finalClipped);
6175 : nsRegion newVisible;
6176 6 : newVisible.Sub(visible, removed);
6177 : // Don't let the visible region get too complex.
6178 6 : if (newVisible.GetNumRects() <= 15) {
6179 : visible = std::move(newVisible);
6180 6 : }
6181 : }
6182 0 : }
6183 0 :
6184 0 : aPreviousRectToDraw = visible.GetBounds();
6185 6 : }
6186 :
6187 0 : /**
6188 0 : * Sets the clip chain and starts a new opacity group.
6189 : */
6190 6 : static void
6191 0 : PushOpacity(gfxContext* aContext,
6192 : const nsRect& aPaintRect,
6193 0 : AssignedDisplayItem& aItem,
6194 : const int32_t aAUPDP)
6195 6 : {
6196 : MOZ_ASSERT(aItem.mType == DisplayItemEntryType::PUSH_OPACITY ||
6197 : aItem.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG);
6198 : MOZ_ASSERT(aItem.mItem->GetType() == DisplayItemType::TYPE_OPACITY);
6199 :
6200 32 : aContext->Save();
6201 :
6202 16 : DisplayItemClip clip;
6203 : clip.SetTo(aPaintRect);
6204 : clip.IntersectWith(aItem.mItem->GetClip());
6205 168 : clip.ApplyTo(aContext, aAUPDP);
6206 :
6207 0 : nsDisplayOpacity* opacityItem = static_cast<nsDisplayOpacity*>(aItem.mItem);
6208 278 : const float opacity = opacityItem->GetOpacity();
6209 :
6210 : if (aItem.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG) {
6211 84 : aContext->PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA, opacity);
6212 : } else {
6213 84 : aContext->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity);
6214 : }
6215 : }
6216 :
6217 0 : /**
6218 56 : * Tracks item clips per opacity nesting level.
6219 : */
6220 : struct ClipTracker {
6221 56 : explicit ClipTracker(gfxContext* aContext)
6222 : : mContext(aContext)
6223 0 : {}
6224 0 :
6225 0 : bool HasClip(int aOpacityNesting) const
6226 : {
6227 : return !mClips.IsEmpty() &&
6228 : mClips.LastElement() == aOpacityNesting;
6229 : }
6230 :
6231 : void PopClipIfNeeded(int aOpacityNesting)
6232 0 : {
6233 : if (!HasClip(aOpacityNesting)) {
6234 0 : return;
6235 : }
6236 15 :
6237 : mContext->Restore();
6238 : mClips.RemoveLastElement();
6239 122 : };
6240 0 :
6241 : void SaveClip(int aOpacityNesting)
6242 : {
6243 122 : mContext->Save();
6244 122 : mClips.AppendElement(aOpacityNesting);
6245 : };
6246 :
6247 0 : AutoTArray<int, 2> mClips;
6248 : gfxContext* mContext;
6249 : };
6250 :
6251 : static void
6252 : UpdateOpacityNesting(int& aOpacityNesting, DisplayItemEntryType aType)
6253 : {
6254 : if (aType == DisplayItemEntryType::PUSH_OPACITY ||
6255 16 : aType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG) {
6256 : aOpacityNesting++;
6257 16 : }
6258 0 :
6259 0 : if (aType == DisplayItemEntryType::POP_OPACITY) {
6260 0 : aOpacityNesting--;
6261 0 : }
6262 :
6263 0 : MOZ_ASSERT(aOpacityNesting >= 0);
6264 : }
6265 :
6266 0 : void
6267 : FrameLayerBuilder::PaintItems(nsTArray<AssignedDisplayItem>& aItems,
6268 : const nsIntRect& aRect,
6269 : gfxContext *aContext,
6270 16 : nsDisplayListBuilder* aBuilder,
6271 : nsPresContext* aPresContext,
6272 32 : const nsIntPoint& aOffset,
6273 : float aXScale, float aYScale)
6274 444 : {
6275 412 : DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
6276 0 :
6277 : int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
6278 0 : nsRect boundRect = ToAppUnits(aRect, appUnitsPerDevPixel);
6279 0 : boundRect.MoveBy(NSIntPixelsToAppUnits(aOffset.x, appUnitsPerDevPixel),
6280 122 : NSIntPixelsToAppUnits(aOffset.y, appUnitsPerDevPixel));
6281 : boundRect.ScaleInverseRoundOut(aXScale, aYScale);
6282 :
6283 0 : DisplayItemClip currentClip, tmpClip;
6284 0 :
6285 : // Tracks opacity nesting level for item level clipping.
6286 412 : int opacityNesting = 0;
6287 :
6288 : // Tracks opacity nesting level for skipping items between opacity markers,
6289 : // when opacity has empty visible rect set.
6290 : int emptyOpacityNesting = 0;
6291 110 :
6292 110 : ClipTracker clipTracker(aContext);
6293 :
6294 : for (uint32_t i = 0; i < aItems.Length(); ++i) {
6295 : AssignedDisplayItem& cdi = aItems[i];
6296 180 : nsDisplayItem* item = cdi.mItem;
6297 :
6298 : if (!item) {
6299 : MOZ_ASSERT(cdi.mType == DisplayItemEntryType::ITEM);
6300 : continue;
6301 : }
6302 96 :
6303 : const nsRect& visibleRect = item->GetPaintRect();
6304 : const nsRect paintRect = visibleRect.Intersect(boundRect);
6305 96 :
6306 : if (paintRect.IsEmpty() || emptyOpacityNesting > 0) {
6307 6 : // In order for this branch to be hit, either this item has an empty paint
6308 0 : // rect and nothing would be drawn, or a PUSH_OPACITY marker before this
6309 : // item had an empty paint rect. In the latter case, the items are skipped
6310 : // until POP_OPACITY markers bring |emptyOpacityNesting| back to 0.
6311 96 : UpdateOpacityNesting(emptyOpacityNesting, cdi.mType);
6312 0 : continue;
6313 6 : }
6314 :
6315 0 : #ifdef MOZ_DUMP_PAINTING
6316 0 : AUTO_PROFILER_LABEL_DYNAMIC_CSTR("FrameLayerBuilder::PaintItems", GRAPHICS,
6317 6 : item->Name());
6318 : #else
6319 : AUTO_PROFILER_LABEL("FrameLayerBuilder::PaintItems", GRAPHICS);
6320 0 : #endif
6321 12 :
6322 12 : MOZ_ASSERT((opacityNesting == 0 && !cdi.mHasOpacity) ||
6323 : (opacityNesting > 0 && cdi.mHasOpacity));
6324 :
6325 : if (cdi.mType == DisplayItemEntryType::PUSH_OPACITY ||
6326 : cdi.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG) {
6327 84 : clipTracker.PopClipIfNeeded(opacityNesting);
6328 103 : PushOpacity(aContext, paintRect, cdi, appUnitsPerDevPixel);
6329 19 : }
6330 13 :
6331 0 : if (cdi.mType == DisplayItemEntryType::POP_OPACITY) {
6332 13 : MOZ_ASSERT(item->GetType() == DisplayItemType::TYPE_OPACITY);
6333 : MOZ_ASSERT(opacityNesting > 0);
6334 0 :
6335 0 : clipTracker.PopClipIfNeeded(opacityNesting);
6336 0 : aContext->PopGroupAndBlend();
6337 : aContext->Restore();
6338 56 : }
6339 0 :
6340 56 : if (cdi.mType != DisplayItemEntryType::ITEM) {
6341 56 : UpdateOpacityNesting(opacityNesting, cdi.mType);
6342 0 : continue;
6343 : }
6344 :
6345 : // If the new desired clip state is different from the current state,
6346 0 : // update the clip.
6347 0 : const DisplayItemClip* clip = &item->GetClip();
6348 0 : if (clip->GetRoundedRectCount() > 0 &&
6349 0 : !clip->IsRectClippedByRoundedCorner(visibleRect)) {
6350 0 : tmpClip = *clip;
6351 : tmpClip.RemoveRoundedCorners();
6352 0 : clip = &tmpClip;
6353 84 : }
6354 : if (clipTracker.HasClip(opacityNesting) != clip->HasClip() ||
6355 : (clip->HasClip() && *clip != currentClip)) {
6356 : clipTracker.PopClipIfNeeded(opacityNesting);
6357 84 :
6358 0 : if (clip->HasClip()) {
6359 : currentClip = *clip;
6360 : clipTracker.SaveClip(opacityNesting);
6361 : currentClip.ApplyTo(aContext, appUnitsPerDevPixel);
6362 0 : aContext->NewPath();
6363 : }
6364 : }
6365 :
6366 : if (cdi.mInactiveLayerManager) {
6367 0 : bool saved = aDrawTarget.GetPermitSubpixelAA();
6368 0 : PaintInactiveLayer(aBuilder, cdi.mInactiveLayerManager,
6369 16 : item, aContext, aContext);
6370 16 : aDrawTarget.SetPermitSubpixelAA(saved);
6371 : } else {
6372 : nsIFrame* frame = item->Frame();
6373 : if (aBuilder->IsPaintingToWindow()) {
6374 : frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
6375 : }
6376 : #ifdef MOZ_DUMP_PAINTING
6377 : if (gfxEnv::DumpPaintItems()) {
6378 0 : DebugPaintItem(aDrawTarget, aPresContext, item, aBuilder);
6379 : } else
6380 16 : #endif
6381 : {
6382 : item->Paint(aBuilder, aContext);
6383 : }
6384 : }
6385 5 : }
6386 :
6387 : clipTracker.PopClipIfNeeded(opacityNesting);
6388 0 : MOZ_ASSERT(opacityNesting == 0);
6389 : MOZ_ASSERT(emptyOpacityNesting == 0);
6390 : }
6391 :
6392 0 : /**
6393 0 : * Returns true if it is preferred to draw the list of display
6394 0 : * items separately for each rect in the visible region rather
6395 : * than clipping to a complex region.
6396 0 : */
6397 : static bool
6398 : ShouldDrawRectsSeparately(DrawTarget* aDrawTarget, DrawRegionClip aClip)
6399 : {
6400 : if (!gfxPrefs::LayoutPaintRectsSeparately() ||
6401 : aClip == DrawRegionClip::NONE) {
6402 : return false;
6403 : }
6404 :
6405 : return !aDrawTarget->SupportsRegionClipping();
6406 : }
6407 :
6408 : static void DrawForcedBackgroundColor(DrawTarget& aDrawTarget,
6409 : const IntRect& aBounds,
6410 : nscolor aBackgroundColor)
6411 : {
6412 : if (NS_GET_A(aBackgroundColor) > 0) {
6413 : ColorPattern color(ToDeviceColor(aBackgroundColor));
6414 : aDrawTarget.FillRect(Rect(aBounds), color);
6415 : }
6416 : }
6417 :
6418 : /*
6419 : * A note on residual transforms:
6420 : *
6421 : * In a transformed subtree we sometimes apply the PaintedLayer's
6422 : * "residual transform" when drawing content into the PaintedLayer.
6423 : * This is a translation by components in the range [-0.5,0.5) provided
6424 : * by the layer system; applying the residual transform followed by the
6425 : * transforms used by layer compositing ensures that the subpixel alignment
6426 : * of the content of the PaintedLayer exactly matches what it would be if
6427 16 : * we used cairo/Thebes to draw directly to the screen without going through
6428 : * retained layer buffers.
6429 : *
6430 : * The visible and valid regions of the PaintedLayer are computed without
6431 : * knowing the residual transform (because we don't know what the residual
6432 : * transform is going to be until we've built the layer tree!). So we have to
6433 : * consider whether content painted in the range [x, xmost) might be painted
6434 : * outside the visible region we computed for that content. The visible region
6435 16 : * would be [floor(x), ceil(xmost)). The content would be rendered at
6436 : * [x + r, xmost + r), where -0.5 <= r < 0.5. So some half-rendered pixels could
6437 32 : * indeed fall outside the computed visible region, which is not a big deal;
6438 : * similar issues already arise when we snap cliprects to nearest pixels.
6439 : * Note that if the rendering of the content is snapped to nearest pixels ---
6440 16 : * which it often is --- then the content is actually rendered at
6441 : * [snap(x + r), snap(xmost + r)). It turns out that floor(x) <= snap(x + r)
6442 16 : * and ceil(xmost) >= snap(xmost + r), so the rendering of snapped content
6443 0 : * always falls within the visible region we computed.
6444 : */
6445 :
6446 : /* static */ void
6447 32 : FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
6448 16 : gfxContext* aContext,
6449 16 : const nsIntRegion& aRegionToDraw,
6450 0 : const nsIntRegion& aDirtyRegion,
6451 : DrawRegionClip aClip,
6452 : const nsIntRegion& aRegionToInvalidate,
6453 : void* aCallbackData)
6454 0 : {
6455 : DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
6456 0 :
6457 16 : AUTO_PROFILER_LABEL("FrameLayerBuilder::DrawPaintedLayer", GRAPHICS);
6458 5 :
6459 : nsDisplayListBuilder* builder = static_cast<nsDisplayListBuilder*>
6460 : (aCallbackData);
6461 0 :
6462 16 : FrameLayerBuilder *layerBuilder = aLayer->Manager()->GetLayerBuilder();
6463 : NS_ASSERTION(layerBuilder, "Unexpectedly null layer builder!");
6464 :
6465 : PaintedDisplayItemLayerUserData* userData =
6466 : static_cast<PaintedDisplayItemLayerUserData*>
6467 32 : (aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
6468 0 : NS_ASSERTION(userData, "where did our user data go?");
6469 0 : if (!userData->mContainerLayerFrame) {
6470 : return;
6471 48 : }
6472 0 :
6473 : bool shouldDrawRectsSeparately =
6474 : ShouldDrawRectsSeparately(&aDrawTarget, aClip);
6475 :
6476 : if (!shouldDrawRectsSeparately) {
6477 : if (aClip == DrawRegionClip::DRAW) {
6478 16 : gfxUtils::ClipToRegion(aContext, aRegionToDraw);
6479 16 : }
6480 :
6481 : DrawForcedBackgroundColor(aDrawTarget, aRegionToDraw.GetBounds(),
6482 16 : userData->mForcedBackgroundColor);
6483 16 : }
6484 :
6485 : // make the origin of the context coincide with the origin of the
6486 16 : // PaintedLayer
6487 0 : gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
6488 0 : nsIntPoint offset = GetTranslationForPaintedLayer(aLayer);
6489 0 : nsPresContext* presContext = userData->mContainerLayerFrame->PresContext();
6490 0 :
6491 0 : if (!userData->mVisibilityComputedRegion.Contains(aDirtyRegion) &&
6492 0 : !layerBuilder->GetContainingPaintedLayerData()) {
6493 : // Recompute visibility of items in our PaintedLayer, if required. Note
6494 0 : // that this recomputes visibility for all descendants of our display
6495 0 : // items too, so there's no need to do this for the items in inactive
6496 : // PaintedLayers. If aDirtyRegion has not changed since the previous call
6497 : // then we can skip this.
6498 : int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
6499 : RecomputeVisibilityForItems(userData->mItems, builder, aDirtyRegion,
6500 : userData->mPreviousRecomputeVisibilityRect,
6501 0 : offset, appUnitsPerDevPixel,
6502 0 : userData->mXScale, userData->mYScale);
6503 : userData->mVisibilityComputedRegion = aDirtyRegion;
6504 0 : }
6505 :
6506 0 : if (shouldDrawRectsSeparately) {
6507 0 : for (auto iter = aRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
6508 0 : const nsIntRect& iterRect = iter.Get();
6509 : gfxContextAutoSaveRestore save(aContext);
6510 : aContext->NewPath();
6511 : aContext->Rectangle(ThebesRect(iterRect));
6512 : aContext->Clip();
6513 :
6514 : DrawForcedBackgroundColor(aDrawTarget, iterRect,
6515 : userData->mForcedBackgroundColor);
6516 0 :
6517 32 : // Apply the residual transform if it has been enabled, to ensure that
6518 : // snapping when we draw into aContext exactly matches the ideal transform.
6519 0 : // See above for why this is OK.
6520 : aContext->SetMatrixDouble(
6521 16 : aContext->CurrentMatrixDouble().PreTranslate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y)).
6522 16 : PreScale(userData->mXScale, userData->mYScale));
6523 0 :
6524 0 : layerBuilder->PaintItems(userData->mItems, iterRect, aContext,
6525 : builder, presContext,
6526 : offset, userData->mXScale, userData->mYScale);
6527 : if (gfxPrefs::GfxLoggingPaintedPixelCountEnabled()) {
6528 16 : aLayer->Manager()->AddPaintedPixelCount(iterRect.Area());
6529 : }
6530 0 : }
6531 0 : } else {
6532 0 : // Apply the residual transform if it has been enabled, to ensure that
6533 0 : // snapping when we draw into aContext exactly matches the ideal transform.
6534 0 : // See above for why this is OK.
6535 : aContext->SetMatrixDouble(
6536 : aContext->CurrentMatrixDouble().PreTranslate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y)).
6537 0 : PreScale(userData->mXScale,userData->mYScale));
6538 :
6539 : layerBuilder->PaintItems(userData->mItems, aRegionToDraw.GetBounds(), aContext,
6540 16 : builder, presContext,
6541 5 : offset, userData->mXScale, userData->mYScale);
6542 15 : if (gfxPrefs::GfxLoggingPaintedPixelCountEnabled()) {
6543 : aLayer->Manager()->AddPaintedPixelCount(
6544 0 : aRegionToDraw.GetBounds().Area());
6545 0 : }
6546 0 : }
6547 :
6548 : bool isActiveLayerManager = !aLayer->Manager()->IsInactiveLayerManager();
6549 :
6550 32 : if (presContext->GetPaintFlashing() && isActiveLayerManager) {
6551 0 : gfxContextAutoSaveRestore save(aContext);
6552 : if (shouldDrawRectsSeparately) {
6553 : if (aClip == DrawRegionClip::DRAW) {
6554 : gfxUtils::ClipToRegion(aContext, aRegionToDraw);
6555 : }
6556 0 : }
6557 : FlashPaint(aContext);
6558 0 : }
6559 0 :
6560 : if (presContext->GetDocShell() && isActiveLayerManager) {
6561 : nsDocShell* docShell = static_cast<nsDocShell*>(presContext->GetDocShell());
6562 0 : RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
6563 :
6564 : if (timelines && timelines->HasConsumer(docShell)) {
6565 : timelines->AddMarkerForDocShell(docShell,
6566 : MakeUnique<LayerTimelineMarker>(aRegionToDraw));
6567 1 : }
6568 : }
6569 :
6570 1 : if (!aRegionToInvalidate.IsEmpty()) {
6571 1 : aLayer->AddInvalidRect(aRegionToInvalidate.GetBounds());
6572 107 : }
6573 107 : }
6574 70 :
6575 : /* static */ void
6576 : FrameLayerBuilder::DumpRetainedLayerTree(LayerManager* aManager, std::stringstream& aStream, bool aDumpHtml)
6577 1 : {
6578 0 : aManager->Dump(aStream, "", aDumpHtml);
6579 : }
6580 :
6581 13 : nsDisplayItemGeometry*
6582 : FrameLayerBuilder::GetMostRecentGeometry(nsDisplayItem* aItem)
6583 : {
6584 : typedef SmallPointerArray<DisplayItemData> DataArray;
6585 0 :
6586 : // Retrieve the array of DisplayItemData associated with our frame.
6587 0 : const DataArray& dataArray = aItem->Frame()->DisplayItemData();
6588 0 :
6589 0 : // Find our display item data, if it exists, and return its geometry.
6590 : uint32_t itemPerFrameKey = aItem->GetPerFrameKey();
6591 : for (uint32_t i = 0; i < dataArray.Length(); i++) {
6592 0 : DisplayItemData* data = DisplayItemData::AssertDisplayItemData(dataArray.ElementAt(i));
6593 : if (data->GetDisplayItemKey() == itemPerFrameKey) {
6594 : return data->GetGeometry();
6595 : }
6596 0 : }
6597 : if (RefPtr<WebRenderFallbackData> data = GetWebRenderUserData<WebRenderFallbackData>(aItem->Frame(), itemPerFrameKey)) {
6598 : return data->GetGeometry();
6599 : }
6600 0 :
6601 0 : return nullptr;
6602 : }
6603 :
6604 : static gfx::Rect
6605 0 : CalculateBounds(const nsTArray<DisplayItemClip::RoundedRect>& aRects, int32_t aAppUnitsPerDevPixel)
6606 : {
6607 0 : nsRect bounds = aRects[0].mRect;
6608 0 : for (uint32_t i = 1; i < aRects.Length(); ++i) {
6609 : bounds.UnionRect(bounds, aRects[i].mRect);
6610 : }
6611 0 :
6612 : return gfx::Rect(bounds.ToNearestPixels(aAppUnitsPerDevPixel));
6613 : }
6614 :
6615 0 : void
6616 : ContainerState::SetupMaskLayer(Layer *aLayer,
6617 0 : const DisplayItemClip& aClip)
6618 : {
6619 : // don't build an unnecessary mask
6620 : if (aClip.GetRoundedRectCount() == 0) {
6621 0 : return;
6622 : }
6623 :
6624 : RefPtr<Layer> maskLayer =
6625 0 : CreateMaskLayer(aLayer, aClip, Nothing());
6626 :
6627 0 : if (!maskLayer) {
6628 : return;
6629 0 : }
6630 0 :
6631 0 : aLayer->SetMaskLayer(maskLayer);
6632 : }
6633 :
6634 0 : static MaskLayerUserData*
6635 : GetMaskLayerUserData(Layer* aMaskLayer)
6636 : {
6637 : if (!aMaskLayer) {
6638 : return nullptr;
6639 : }
6640 :
6641 : return static_cast<MaskLayerUserData*>(aMaskLayer->GetUserData(&gMaskLayerUserData));
6642 0 : }
6643 :
6644 : static void
6645 : SetMaskLayerUserData(Layer* aMaskLayer)
6646 : {
6647 0 : MOZ_ASSERT(aMaskLayer);
6648 :
6649 0 : aMaskLayer->SetUserData(&gMaskLayerUserData,
6650 0 : new MaskLayerUserData());
6651 : }
6652 0 :
6653 0 : already_AddRefed<Layer>
6654 0 : ContainerState::CreateMaskLayer(Layer *aLayer,
6655 0 : const DisplayItemClip& aClip,
6656 : const Maybe<size_t>& aForAncestorMaskLayer)
6657 : {
6658 : // aLayer will never be the container layer created by an nsDisplayMask
6659 0 : // because nsDisplayMask propagates the DisplayItemClip to its contents
6660 0 : // and is not clipped itself.
6661 0 : // This assertion will fail if that ever stops being the case.
6662 : MOZ_ASSERT(!aLayer->GetUserData(&gCSSMaskLayerUserData),
6663 : "A layer contains round clips should not have css-mask on it.");
6664 :
6665 : // check if we can re-use the mask layer
6666 0 : RefPtr<ImageLayer> maskLayer =
6667 0 : CreateOrRecycleMaskImageLayerFor(MaskLayerKey(aLayer, aForAncestorMaskLayer),
6668 : GetMaskLayerUserData,
6669 : SetMaskLayerUserData);
6670 : MaskLayerUserData* userData = GetMaskLayerUserData(maskLayer.get());
6671 :
6672 : int32_t A2D = mContainerFrame->PresContext()->AppUnitsPerDevPixel();
6673 0 : MaskLayerUserData newData(aClip, A2D, mParameters);
6674 0 : if (*userData == newData) {
6675 : return maskLayer.forget();
6676 : }
6677 :
6678 : gfx::Rect boundingRect = CalculateBounds(newData.mRoundedClipRects,
6679 : newData.mAppUnitsPerDevPixel);
6680 : boundingRect.Scale(mParameters.mXScale, mParameters.mYScale);
6681 : if (boundingRect.IsEmpty()) {
6682 0 : // Return early if we know that there is effectively no visible data.
6683 0 : return nullptr;
6684 0 : }
6685 :
6686 : uint32_t maxSize = mManager->GetMaxTextureSize();
6687 : NS_ASSERTION(maxSize > 0, "Invalid max texture size");
6688 : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
6689 0 : // Make mask image width aligned to 4. See Bug 1245552.
6690 0 : gfx::Size surfaceSize(std::min<gfx::Float>(GetAlignedStride<4>(NSToIntCeil(boundingRect.Width()), 1), maxSize),
6691 : std::min<gfx::Float>(boundingRect.Height(), maxSize));
6692 0 : #else
6693 0 : gfx::Size surfaceSize(std::min<gfx::Float>(boundingRect.Width(), maxSize),
6694 : std::min<gfx::Float>(boundingRect.Height(), maxSize));
6695 : #endif
6696 0 :
6697 : // maskTransform is applied to the clip when it is painted into the mask (as a
6698 : // component of imageTransform), and its inverse used when the mask is used for
6699 0 : // masking.
6700 0 : // It is the transform from the masked layer's space to mask space
6701 0 : gfx::Matrix maskTransform =
6702 0 : Matrix::Scaling(surfaceSize.width / boundingRect.Width(),
6703 0 : surfaceSize.height / boundingRect.Height());
6704 : if (surfaceSize.IsEmpty()) {
6705 0 : // Return early if we know that the size of this mask surface is empty.
6706 : return nullptr;
6707 0 : }
6708 :
6709 : gfx::Point p = boundingRect.TopLeft();
6710 : maskTransform.PreTranslate(-p.x, -p.y);
6711 0 : // imageTransform is only used when the clip is painted to the mask
6712 : gfx::Matrix imageTransform = maskTransform;
6713 0 : imageTransform.PreScale(mParameters.mXScale, mParameters.mYScale);
6714 :
6715 0 : nsAutoPtr<MaskLayerImageCache::MaskLayerImageKey> newKey(
6716 : new MaskLayerImageCache::MaskLayerImageKey());
6717 0 :
6718 0 : // copy and transform the rounded rects
6719 : for (uint32_t i = 0; i < newData.mRoundedClipRects.Length(); ++i) {
6720 : newKey->mRoundedClipRects.AppendElement(
6721 0 : MaskLayerImageCache::PixelRoundedRect(newData.mRoundedClipRects[i],
6722 0 : mContainerFrame->PresContext()));
6723 0 : newKey->mRoundedClipRects[i].ScaleAndTranslate(imageTransform);
6724 : }
6725 : newKey->mKnowsCompositor = mManager->AsKnowsCompositor();
6726 0 :
6727 0 : const MaskLayerImageCache::MaskLayerImageKey* lookupKey = newKey;
6728 0 :
6729 : // check to see if we can reuse a mask image
6730 : RefPtr<ImageContainer> container =
6731 0 : GetMaskLayerImageCache()->FindImageFor(&lookupKey);
6732 0 :
6733 0 : if (!container) {
6734 : IntSize surfaceSizeInt(NSToIntCeil(surfaceSize.width),
6735 : NSToIntCeil(surfaceSize.height));
6736 0 : // no existing mask image, so build a new one
6737 0 : MaskImageData imageData(surfaceSizeInt, mManager);
6738 0 : RefPtr<DrawTarget> dt = imageData.CreateDrawTarget();
6739 :
6740 0 : // fail if we can't get the right surface
6741 0 : if (!dt || !dt->IsValid()) {
6742 : NS_WARNING("Could not create DrawTarget for mask layer.");
6743 : return nullptr;
6744 0 : }
6745 :
6746 : RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
6747 0 : MOZ_ASSERT(context); // already checked the draw target above
6748 : context->Multiply(ThebesMatrix(imageTransform));
6749 0 :
6750 0 : // paint the clipping rects with alpha to create the mask
6751 0 : aClip.FillIntersectionOfRoundedRectClips(context,
6752 0 : Color(1.f, 1.f, 1.f, 1.f),
6753 : newData.mAppUnitsPerDevPixel);
6754 :
6755 0 : // build the image and container
6756 0 : MOZ_ASSERT(aLayer->Manager() == mManager);
6757 : container = imageData.CreateImageAndImageContainer();
6758 0 : NS_ASSERTION(container, "Could not create image container for mask layer.");
6759 :
6760 : if (!container) {
6761 : return nullptr;
6762 : }
6763 :
6764 : GetMaskLayerImageCache()->PutImage(newKey.forget(), container);
6765 : }
6766 :
6767 : maskLayer->SetContainer(container);
6768 :
6769 : maskTransform.Invert();
6770 : Matrix4x4 matrix = Matrix4x4::From2D(maskTransform);
6771 : matrix.PreTranslate(mParameters.mOffset.x, mParameters.mOffset.y, 0);
6772 : maskLayer->SetBaseTransform(matrix);
6773 :
6774 : // save the details of the clip in user data
6775 : *userData = std::move(newData);
6776 : userData->mImageKey.Reset(lookupKey);
6777 :
6778 : return maskLayer.forget();
6779 : }
6780 :
6781 : } // namespace mozilla
|