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