1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 */
7
8 /*
9 * structures that represent things to be painted (ordered in z-order),
10 * used during painting and hit testing
11 */
12
13 #ifndef NSDISPLAYLIST_H_
14 #define NSDISPLAYLIST_H_
15
16 #include "DisplayItemClipChain.h"
17 #include "DisplayListClipState.h"
18 #include "FrameMetrics.h"
19 #include "HitTestInfo.h"
20 #include "ImgDrawResult.h"
21 #include "LayerState.h"
22 #include "RetainedDisplayListHelpers.h"
23 #include "Units.h"
24 #include "gfxContext.h"
25 #include "mozilla/ArenaAllocator.h"
26 #include "mozilla/Array.h"
27 #include "mozilla/ArrayIterator.h"
28 #include "mozilla/Assertions.h"
29 #include "mozilla/Attributes.h"
30 #include "mozilla/DebugOnly.h"
31 #include "mozilla/EffectCompositor.h"
32 #include "mozilla/EnumSet.h"
33 #include "mozilla/EnumeratedArray.h"
34 #include "mozilla/Logging.h"
35 #include "mozilla/Maybe.h"
36 #include "mozilla/MotionPathUtils.h"
37 #include "mozilla/RefPtr.h"
38 #include "mozilla/TemplateLib.h"
39 #include "mozilla/TimeStamp.h"
40 #include "mozilla/UniquePtr.h"
41 #include "mozilla/dom/EffectsInfo.h"
42 #include "mozilla/gfx/UserData.h"
43 #include "mozilla/layers/BSPTree.h"
44 #include "mozilla/layers/LayerAttributes.h"
45 #include "mozilla/layers/ScrollableLayerGuid.h"
46 #include "nsAutoLayoutPhase.h"
47 #include "nsCOMPtr.h"
48 #include "nsCSSRenderingBorders.h"
49 #include "nsContainerFrame.h"
50 #include "nsDisplayItemTypes.h"
51 #include "nsDisplayListInvalidation.h"
52 #include "nsPoint.h"
53 #include "nsPresArena.h"
54 #include "nsRect.h"
55 #include "nsRegion.h"
56 #include "nsClassHashtable.h"
57 #include "nsTHashSet.h"
58 #include "nsTHashMap.h"
59
60 #include <algorithm>
61 #include <unordered_set>
62
63 // XXX Includes that could be avoided by moving function implementations to the
64 // cpp file.
65 #include "gfxPlatform.h"
66
67 class gfxContext;
68 class nsIContent;
69 class nsIScrollableFrame;
70 class nsSubDocumentFrame;
71 class nsCaret;
72 struct WrFiltersHolder;
73
74 namespace nsStyleTransformMatrix {
75 class TransformReferenceBox;
76 }
77
78 namespace mozilla {
79
80 enum class nsDisplayOwnLayerFlags;
81 class nsDisplayCompositorHitTestInfo;
82 class nsDisplayScrollInfoLayer;
83 class PresShell;
84 class StickyScrollContainer;
85
86 namespace layers {
87 struct FrameMetrics;
88 class RenderRootStateManager;
89 class Layer;
90 class ImageContainer;
91 class StackingContextHelper;
92 class WebRenderScrollData;
93 class WebRenderLayerScrollData;
94 class WebRenderLayerManager;
95 } // namespace layers
96
97 namespace wr {
98 class DisplayListBuilder;
99 } // namespace wr
100
101 namespace dom {
102 class RemoteBrowser;
103 class Selection;
104 } // namespace dom
105
106 enum class DisplayListArenaObjectId {
107 #define DISPLAY_LIST_ARENA_OBJECT(name_) name_,
108 #include "nsDisplayListArenaTypes.h"
109 #undef DISPLAY_LIST_ARENA_OBJECT
110 COUNT
111 };
112
113 extern LazyLogModule sDisplayListLog;
114 #define DL_LOG(lvl, ...) MOZ_LOG(sDisplayListLog, lvl, (__VA_ARGS__))
115 #define DL_LOGI(...) DL_LOG(LogLevel::Info, __VA_ARGS__)
116 #define DL_LOGD(...) DL_LOG(LogLevel::Debug, __VA_ARGS__)
117 #define DL_LOGV(...) DL_LOG(LogLevel::Verbose, __VA_ARGS__)
118 #define DL_LOG_TEST(lvl) MOZ_LOG_TEST(sDisplayListLog, lvl)
119
120 /*
121 * An nsIFrame can have many different visual parts. For example an image frame
122 * can have a background, border, and outline, the image itself, and a
123 * translucent selection overlay. In general these parts can be drawn at
124 * discontiguous z-levels; see CSS2.1 appendix E:
125 * http://www.w3.org/TR/CSS21/zindex.html
126 *
127 * We construct a display list for a frame tree that contains one item
128 * for each visual part. The display list is itself a tree since some items
129 * are containers for other items; however, its structure does not match
130 * the structure of its source frame tree. The display list items are sorted
131 * by z-order. A display list can be used to paint the frames, to determine
132 * which frame is the target of a mouse event, and to determine what areas
133 * need to be repainted when scrolling. The display lists built for each task
134 * may be different for efficiency; in particular some frames need special
135 * display list items only for event handling, and do not create these items
136 * when the display list will be used for painting (the common case). For
137 * example, when painting we avoid creating nsDisplayBackground items for
138 * frames that don't display a visible background, but for event handling
139 * we need those backgrounds because they are not transparent to events.
140 *
141 * We could avoid constructing an explicit display list by traversing the
142 * frame tree multiple times in clever ways. However, reifying the display list
143 * reduces code complexity and reduces the number of times each frame must be
144 * traversed to one, which seems to be good for performance. It also means
145 * we can share code for painting, event handling and scroll analysis.
146 *
147 * Display lists are short-lived; content and frame trees cannot change
148 * between a display list being created and destroyed. Display lists should
149 * not be created during reflow because the frame tree may be in an
150 * inconsistent state (e.g., a frame's stored overflow-area may not include
151 * the bounds of all its children). However, it should be fine to create
152 * a display list while a reflow is pending, before it starts.
153 *
154 * A display list covers the "extended" frame tree; the display list for
155 * a frame tree containing FRAME/IFRAME elements can include frames from
156 * the subdocuments.
157 *
158 * Display item's coordinates are relative to their nearest reference frame
159 * ancestor. Both the display root and any frame with a transform act as a
160 * reference frame for their frame subtrees.
161 */
162
163 /**
164 * An active scrolled root (ASR) is similar to an animated geometry root (AGR).
165 * The differences are:
166 * - ASRs are only created for async-scrollable scroll frames. This is a
167 * (hopefully) temporary restriction. In the future we will want to create
168 * ASRs for all the things that are currently creating AGRs, and then
169 * replace AGRs with ASRs and rename them from "active scrolled root" to
170 * "animated geometry root".
171 * - ASR objects are created during display list construction by the nsIFrames
172 * that induce ASRs. This is done using AutoCurrentActiveScrolledRootSetter.
173 * The current ASR is returned by
174 * nsDisplayListBuilder::CurrentActiveScrolledRoot().
175 * - There is no way to go from an nsIFrame pointer to the ASR of that frame.
176 * If you need to look up an ASR after display list construction, you need
177 * to store it while the AutoCurrentActiveScrolledRootSetter that creates it
178 * is on the stack.
179 */
180 struct ActiveScrolledRoot {
181 static already_AddRefed<ActiveScrolledRoot> CreateASRForFrame(
182 const ActiveScrolledRoot* aParent, nsIScrollableFrame* aScrollableFrame,
183 bool aIsRetained);
184
PickAncestorActiveScrolledRoot185 static const ActiveScrolledRoot* PickAncestor(
186 const ActiveScrolledRoot* aOne, const ActiveScrolledRoot* aTwo) {
187 MOZ_ASSERT(IsAncestor(aOne, aTwo) || IsAncestor(aTwo, aOne));
188 return Depth(aOne) <= Depth(aTwo) ? aOne : aTwo;
189 }
190
PickDescendantActiveScrolledRoot191 static const ActiveScrolledRoot* PickDescendant(
192 const ActiveScrolledRoot* aOne, const ActiveScrolledRoot* aTwo) {
193 MOZ_ASSERT(IsAncestor(aOne, aTwo) || IsAncestor(aTwo, aOne));
194 return Depth(aOne) >= Depth(aTwo) ? aOne : aTwo;
195 }
196
197 static bool IsAncestor(const ActiveScrolledRoot* aAncestor,
198 const ActiveScrolledRoot* aDescendant);
199 static bool IsProperAncestor(const ActiveScrolledRoot* aAncestor,
200 const ActiveScrolledRoot* aDescendant);
201
202 static nsCString ToString(const ActiveScrolledRoot* aActiveScrolledRoot);
203
204 // Call this when inserting an ancestor.
IncrementDepthActiveScrolledRoot205 void IncrementDepth() { mDepth++; }
206
207 /**
208 * Find the view ID (or generate a new one) for the content element
209 * corresponding to the ASR.
210 */
GetViewIdActiveScrolledRoot211 layers::ScrollableLayerGuid::ViewID GetViewId() const {
212 if (!mViewId.isSome()) {
213 mViewId = Some(ComputeViewId());
214 }
215 return *mViewId;
216 }
217
218 RefPtr<const ActiveScrolledRoot> mParent;
219 nsIScrollableFrame* mScrollableFrame;
220
NS_INLINE_DECL_REFCOUNTINGActiveScrolledRoot221 NS_INLINE_DECL_REFCOUNTING(ActiveScrolledRoot)
222
223 private:
224 ActiveScrolledRoot()
225 : mScrollableFrame(nullptr), mDepth(0), mRetained(false) {}
226
227 ~ActiveScrolledRoot();
228
DetachASRActiveScrolledRoot229 static void DetachASR(ActiveScrolledRoot* aASR) {
230 aASR->mParent = nullptr;
231 aASR->mScrollableFrame = nullptr;
232 NS_RELEASE(aASR);
233 }
NS_DECLARE_FRAME_PROPERTY_WITH_DTORActiveScrolledRoot234 NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(ActiveScrolledRootCache,
235 ActiveScrolledRoot, DetachASR)
236
237 static uint32_t Depth(const ActiveScrolledRoot* aActiveScrolledRoot) {
238 return aActiveScrolledRoot ? aActiveScrolledRoot->mDepth : 0;
239 }
240
241 layers::ScrollableLayerGuid::ViewID ComputeViewId() const;
242
243 // This field is lazily populated in GetViewId(). We don't want to do the
244 // work of populating if webrender is disabled, because it is often not
245 // needed.
246 mutable Maybe<layers::ScrollableLayerGuid::ViewID> mViewId;
247
248 uint32_t mDepth;
249 bool mRetained;
250 };
251
252 enum class nsDisplayListBuilderMode : uint8_t {
253 Painting,
254 PaintForPrinting,
255 EventDelivery,
256 FrameVisibility,
257 TransformComputation,
258 GenerateGlyph,
259 };
260
261 using ListArenaAllocator = ArenaAllocator<4096, 8>;
262
263 class nsDisplayItem;
264 class nsPaintedDisplayItem;
265 class nsDisplayList;
266 class nsDisplayWrapList;
267 class nsDisplayTableBackgroundSet;
268 class nsDisplayTableItem;
269
270 class RetainedDisplayList;
271
272 /**
273 * This manages a display list and is passed as a parameter to
274 * nsIFrame::BuildDisplayList.
275 * It contains the parameters that don't change from frame to frame and manages
276 * the display list memory using an arena. It also establishes the reference
277 * coordinate system for all display list items. Some of the parameters are
278 * available from the prescontext/presshell, but we copy them into the builder
279 * for faster/more convenient access.
280 */
281 class nsDisplayListBuilder {
282 /**
283 * This manages status of a 3d context to collect visible rects of
284 * descendants and passing a dirty rect.
285 *
286 * Since some transforms maybe singular, passing visible rects or
287 * the dirty rect level by level from parent to children may get a
288 * wrong result, being different from the result of appling with
289 * effective transform directly.
290 *
291 * nsIFrame::BuildDisplayListForStackingContext() uses
292 * AutoPreserves3DContext to install an instance on the builder.
293 *
294 * \see AutoAccumulateTransform, AutoAccumulateRect,
295 * AutoPreserves3DContext, Accumulate, GetCurrentTransform,
296 * StartRoot.
297 */
298 class Preserves3DContext {
299 public:
Preserves3DContext()300 Preserves3DContext()
301 : mAccumulatedRectLevels(0), mAllowAsyncAnimation(true) {}
302
Preserves3DContext(const Preserves3DContext & aOther)303 Preserves3DContext(const Preserves3DContext& aOther)
304 : mAccumulatedTransform(),
305 mAccumulatedRect(),
306 mAccumulatedRectLevels(0),
307 mVisibleRect(aOther.mVisibleRect),
308 mAllowAsyncAnimation(aOther.mAllowAsyncAnimation) {}
309
310 // Accmulate transforms of ancestors on the preserves-3d chain.
311 gfx::Matrix4x4 mAccumulatedTransform;
312 // Accmulate visible rect of descendants in the preserves-3d context.
313 nsRect mAccumulatedRect;
314 // How far this frame is from the root of the current 3d context.
315 int mAccumulatedRectLevels;
316 nsRect mVisibleRect;
317 // Allow async animation for this 3D context.
318 bool mAllowAsyncAnimation;
319 };
320
321 public:
322 using ViewID = layers::ScrollableLayerGuid::ViewID;
323
324 /**
325 * @param aReferenceFrame the frame at the root of the subtree; its origin
326 * is the origin of the reference coordinate system for this display list
327 * @param aMode encodes what the builder is being used for.
328 * @param aBuildCaret whether or not we should include the caret in any
329 * display lists that we make.
330 */
331 nsDisplayListBuilder(nsIFrame* aReferenceFrame,
332 nsDisplayListBuilderMode aMode, bool aBuildCaret,
333 bool aRetainingDisplayList = false);
334 ~nsDisplayListBuilder();
335
336 void BeginFrame();
337 void EndFrame();
338
AddTemporaryItem(nsDisplayItem * aItem)339 void AddTemporaryItem(nsDisplayItem* aItem) {
340 mTemporaryItems.AppendElement(aItem);
341 }
342
343 WindowRenderer* GetWidgetWindowRenderer(nsView** aView = nullptr);
344 layers::WebRenderLayerManager* GetWidgetLayerManager(
345 nsView** aView = nullptr);
346
347 /**
348 * @return true if the display is being built in order to determine which
349 * frame is under the mouse position.
350 */
IsForEventDelivery()351 bool IsForEventDelivery() const {
352 return mMode == nsDisplayListBuilderMode::EventDelivery;
353 }
354
355 /**
356 * @return true if the display list is being built for painting. This
357 * includes both painting to a window or other buffer and painting to
358 * a print/pdf destination.
359 */
IsForPainting()360 bool IsForPainting() const {
361 return mMode == nsDisplayListBuilderMode::Painting ||
362 mMode == nsDisplayListBuilderMode::PaintForPrinting;
363 }
364
365 /**
366 * @return true if the display list is being built specifically for printing.
367 */
IsForPrinting()368 bool IsForPrinting() const {
369 return mMode == nsDisplayListBuilderMode::PaintForPrinting;
370 }
371
372 /**
373 * @return true if the display list is being built for determining frame
374 * visibility.
375 */
IsForFrameVisibility()376 bool IsForFrameVisibility() const {
377 return mMode == nsDisplayListBuilderMode::FrameVisibility;
378 }
379
380 /**
381 * @return true if the display list is being built for creating the glyph
382 * mask from text items.
383 */
IsForGenerateGlyphMask()384 bool IsForGenerateGlyphMask() const {
385 return mMode == nsDisplayListBuilderMode::GenerateGlyph;
386 }
387
IsForContent()388 bool IsForContent() const { return mIsForContent; }
389
BuildCompositorHitTestInfo()390 bool BuildCompositorHitTestInfo() const {
391 return mBuildCompositorHitTestInfo;
392 }
393
394 /**
395 * @return true if "painting is suppressed" during page load and we
396 * should paint only the background of the document.
397 */
IsBackgroundOnly()398 bool IsBackgroundOnly() {
399 NS_ASSERTION(mPresShellStates.Length() > 0,
400 "don't call this if we're not in a presshell");
401 return CurrentPresShellState()->mIsBackgroundOnly;
402 }
403
404 /**
405 * @return the root of given frame's (sub)tree, whose origin
406 * establishes the coordinate system for the child display items.
407 */
408 const nsIFrame* FindReferenceFrameFor(const nsIFrame* aFrame,
409 nsPoint* aOffset = nullptr) const;
410
AdditionalOffset()411 const Maybe<nsPoint>& AdditionalOffset() const { return mAdditionalOffset; }
412
413 /**
414 * @return the root of the display list's frame (sub)tree, whose origin
415 * establishes the coordinate system for the display list
416 */
RootReferenceFrame()417 nsIFrame* RootReferenceFrame() const { return mReferenceFrame; }
418
419 /**
420 * @return a point pt such that adding pt to a coordinate relative to aFrame
421 * makes it relative to ReferenceFrame(), i.e., returns
422 * aFrame->GetOffsetToCrossDoc(ReferenceFrame()). The returned point is in
423 * the appunits of aFrame.
424 */
ToReferenceFrame(const nsIFrame * aFrame)425 const nsPoint ToReferenceFrame(const nsIFrame* aFrame) const {
426 nsPoint result;
427 FindReferenceFrameFor(aFrame, &result);
428 return result;
429 }
430 /**
431 * When building the display list, the scrollframe aFrame will be "ignored"
432 * for the purposes of clipping, and its scrollbars will be hidden. We use
433 * this to allow RenderOffscreen to render a whole document without beign
434 * clipped by the viewport or drawing the viewport scrollbars.
435 */
SetIgnoreScrollFrame(nsIFrame * aFrame)436 void SetIgnoreScrollFrame(nsIFrame* aFrame) { mIgnoreScrollFrame = aFrame; }
437 /**
438 * Get the scrollframe to ignore, if any.
439 */
GetIgnoreScrollFrame()440 nsIFrame* GetIgnoreScrollFrame() { return mIgnoreScrollFrame; }
441 void SetIsRelativeToLayoutViewport();
IsRelativeToLayoutViewport()442 bool IsRelativeToLayoutViewport() const {
443 return mIsRelativeToLayoutViewport;
444 }
445 /**
446 * Get the ViewID of the nearest scrolling ancestor frame.
447 */
GetCurrentScrollParentId()448 ViewID GetCurrentScrollParentId() const { return mCurrentScrollParentId; }
449 /**
450 * Get and set the flag that indicates if scroll parents should have layers
451 * forcibly created. This flag is set when a deeply nested scrollframe has
452 * a displayport, and for scroll handoff to work properly the ancestor
453 * scrollframes should also get their own scrollable layers.
454 */
ForceLayerForScrollParent()455 void ForceLayerForScrollParent() { mForceLayerForScrollParent = true; }
456 /**
457 * Set the flag that indicates there is a non-minimal display port in the
458 * current subtree. This is used to determine display port expiry.
459 */
SetContainsNonMinimalDisplayPort()460 void SetContainsNonMinimalDisplayPort() {
461 mContainsNonMinimalDisplayPort = true;
462 }
463 /**
464 * Get the ViewID and the scrollbar flags corresponding to the scrollbar for
465 * which we are building display items at the moment.
466 */
GetCurrentScrollbarTarget()467 ViewID GetCurrentScrollbarTarget() const { return mCurrentScrollbarTarget; }
GetCurrentScrollbarDirection()468 Maybe<layers::ScrollDirection> GetCurrentScrollbarDirection() const {
469 return mCurrentScrollbarDirection;
470 }
471 /**
472 * Returns true if building a scrollbar, and the scrollbar will not be
473 * layerized.
474 */
IsBuildingNonLayerizedScrollbar()475 bool IsBuildingNonLayerizedScrollbar() const {
476 return mIsBuildingScrollbar && !mCurrentScrollbarWillHaveLayer;
477 }
478 /**
479 * Calling this setter makes us include all out-of-flow descendant
480 * frames in the display list, wherever they may be positioned (even
481 * outside the dirty rects).
482 */
SetIncludeAllOutOfFlows()483 void SetIncludeAllOutOfFlows() { mIncludeAllOutOfFlows = true; }
GetIncludeAllOutOfFlows()484 bool GetIncludeAllOutOfFlows() const { return mIncludeAllOutOfFlows; }
485 /**
486 * Calling this setter makes us exclude all leaf frames that aren't
487 * selected.
488 */
SetSelectedFramesOnly()489 void SetSelectedFramesOnly() { mSelectedFramesOnly = true; }
GetSelectedFramesOnly()490 bool GetSelectedFramesOnly() { return mSelectedFramesOnly; }
491 /**
492 * @return Returns true if we should include the caret in any display lists
493 * that we make.
494 */
IsBuildingCaret()495 bool IsBuildingCaret() const { return mBuildCaret; }
496
IsRetainingDisplayList()497 bool IsRetainingDisplayList() const { return mRetainingDisplayList; }
498
IsPartialUpdate()499 bool IsPartialUpdate() const { return mPartialUpdate; }
SetPartialUpdate(bool aPartial)500 void SetPartialUpdate(bool aPartial) { mPartialUpdate = aPartial; }
501
IsBuilding()502 bool IsBuilding() const { return mIsBuilding; }
SetIsBuilding(bool aIsBuilding)503 void SetIsBuilding(bool aIsBuilding) { mIsBuilding = aIsBuilding; }
504
InInvalidSubtree()505 bool InInvalidSubtree() const { return mInInvalidSubtree; }
506
507 /**
508 * Allows callers to selectively override the regular paint suppression
509 * checks, so that methods like GetFrameForPoint work when painting is
510 * suppressed.
511 */
IgnorePaintSuppression()512 void IgnorePaintSuppression() { mIgnoreSuppression = true; }
513 /**
514 * @return Returns if this builder will ignore paint suppression.
515 */
IsIgnoringPaintSuppression()516 bool IsIgnoringPaintSuppression() { return mIgnoreSuppression; }
517 /**
518 * Call this if we're doing normal painting to the window.
519 */
SetPaintingToWindow(bool aToWindow)520 void SetPaintingToWindow(bool aToWindow) { mIsPaintingToWindow = aToWindow; }
IsPaintingToWindow()521 bool IsPaintingToWindow() const { return mIsPaintingToWindow; }
522 /**
523 * Call this if we're using high quality scaling for image decoding.
524 * It is also implied by IsPaintingToWindow.
525 */
SetUseHighQualityScaling(bool aUseHighQualityScaling)526 void SetUseHighQualityScaling(bool aUseHighQualityScaling) {
527 mUseHighQualityScaling = aUseHighQualityScaling;
528 }
UseHighQualityScaling()529 bool UseHighQualityScaling() const {
530 return mIsPaintingToWindow || mUseHighQualityScaling;
531 }
532 /**
533 * Call this if we're doing painting for WebRender
534 */
SetPaintingForWebRender(bool aForWebRender)535 void SetPaintingForWebRender(bool aForWebRender) {
536 mIsPaintingForWebRender = true;
537 }
IsPaintingForWebRender()538 bool IsPaintingForWebRender() const { return mIsPaintingForWebRender; }
539 /**
540 * Call this to prevent descending into subdocuments.
541 */
SetDescendIntoSubdocuments(bool aDescend)542 void SetDescendIntoSubdocuments(bool aDescend) {
543 mDescendIntoSubdocuments = aDescend;
544 }
545
GetDescendIntoSubdocuments()546 bool GetDescendIntoSubdocuments() { return mDescendIntoSubdocuments; }
547
548 /**
549 * Get dirty rect relative to current frame (the frame that we're calling
550 * BuildDisplayList on right now).
551 */
GetVisibleRect()552 const nsRect& GetVisibleRect() { return mVisibleRect; }
GetDirtyRect()553 const nsRect& GetDirtyRect() { return mDirtyRect; }
554
SetVisibleRect(const nsRect & aVisibleRect)555 void SetVisibleRect(const nsRect& aVisibleRect) {
556 mVisibleRect = aVisibleRect;
557 }
558
IntersectVisibleRect(const nsRect & aVisibleRect)559 void IntersectVisibleRect(const nsRect& aVisibleRect) {
560 mVisibleRect.IntersectRect(mVisibleRect, aVisibleRect);
561 }
562
SetDirtyRect(const nsRect & aDirtyRect)563 void SetDirtyRect(const nsRect& aDirtyRect) { mDirtyRect = aDirtyRect; }
564
IntersectDirtyRect(const nsRect & aDirtyRect)565 void IntersectDirtyRect(const nsRect& aDirtyRect) {
566 mDirtyRect.IntersectRect(mDirtyRect, aDirtyRect);
567 }
568
GetCurrentFrame()569 const nsIFrame* GetCurrentFrame() { return mCurrentFrame; }
GetCurrentReferenceFrame()570 const nsIFrame* GetCurrentReferenceFrame() { return mCurrentReferenceFrame; }
571
GetCurrentFrameOffsetToReferenceFrame()572 const nsPoint& GetCurrentFrameOffsetToReferenceFrame() const {
573 return mCurrentOffsetToReferenceFrame;
574 }
575
Check()576 void Check() { mPool.Check(); }
577
578 /**
579 * Returns true if merging and flattening of display lists should be
580 * performed while computing visibility.
581 */
AllowMergingAndFlattening()582 bool AllowMergingAndFlattening() { return mAllowMergingAndFlattening; }
SetAllowMergingAndFlattening(bool aAllow)583 void SetAllowMergingAndFlattening(bool aAllow) {
584 mAllowMergingAndFlattening = aAllow;
585 }
586
SetCompositorHitTestInfo(const gfx::CompositorHitTestInfo & aInfo)587 void SetCompositorHitTestInfo(const gfx::CompositorHitTestInfo& aInfo) {
588 mCompositorHitTestInfo = aInfo;
589 }
590
GetCompositorHitTestInfo()591 const gfx::CompositorHitTestInfo& GetCompositorHitTestInfo() const {
592 return mCompositorHitTestInfo;
593 }
594
595 /**
596 * Builds a new nsDisplayCompositorHitTestInfo for the frame |aFrame| if
597 * needed, and adds it to the top of |aList|.
598 */
599 void BuildCompositorHitTestInfoIfNeeded(nsIFrame* aFrame,
600 nsDisplayList* aList);
601
IsInsidePointerEventsNoneDoc()602 bool IsInsidePointerEventsNoneDoc() {
603 return CurrentPresShellState()->mInsidePointerEventsNoneDoc;
604 }
605
IsTouchEventPrefEnabledDoc()606 bool IsTouchEventPrefEnabledDoc() {
607 return CurrentPresShellState()->mTouchEventPrefEnabledDoc;
608 }
609
GetAncestorHasApzAwareEventHandler()610 bool GetAncestorHasApzAwareEventHandler() const {
611 return mAncestorHasApzAwareEventHandler;
612 }
613
SetAncestorHasApzAwareEventHandler(bool aValue)614 void SetAncestorHasApzAwareEventHandler(bool aValue) {
615 mAncestorHasApzAwareEventHandler = aValue;
616 }
617
HaveScrollableDisplayPort()618 bool HaveScrollableDisplayPort() const { return mHaveScrollableDisplayPort; }
SetHaveScrollableDisplayPort()619 void SetHaveScrollableDisplayPort() { mHaveScrollableDisplayPort = true; }
ClearHaveScrollableDisplayPort()620 void ClearHaveScrollableDisplayPort() { mHaveScrollableDisplayPort = false; }
621
SetIsCompositingCheap(bool aCompositingCheap)622 bool SetIsCompositingCheap(bool aCompositingCheap) {
623 bool temp = mIsCompositingCheap;
624 mIsCompositingCheap = aCompositingCheap;
625 return temp;
626 }
627
IsCompositingCheap()628 bool IsCompositingCheap() const { return mIsCompositingCheap; }
629 /**
630 * Display the caret if needed.
631 */
DisplayCaret(nsIFrame * aFrame,nsDisplayList * aList)632 bool DisplayCaret(nsIFrame* aFrame, nsDisplayList* aList) {
633 nsIFrame* frame = GetCaretFrame();
634 if (aFrame == frame && !IsBackgroundOnly()) {
635 frame->DisplayCaret(this, aList);
636 return true;
637 }
638 return false;
639 }
640 /**
641 * Get the frame that the caret is supposed to draw in.
642 * If the caret is currently invisible, this will be null.
643 */
GetCaretFrame()644 nsIFrame* GetCaretFrame() { return mCaretFrame; }
645 /**
646 * Get the rectangle we're supposed to draw the caret into.
647 */
GetCaretRect()648 const nsRect& GetCaretRect() { return mCaretRect; }
649 /**
650 * Get the caret associated with the current presshell.
651 */
652 nsCaret* GetCaret();
653
654 /**
655 * Returns the root scroll frame for the current PresShell, if the PresShell
656 * is ignoring viewport scrolling.
657 */
GetPresShellIgnoreScrollFrame()658 nsIFrame* GetPresShellIgnoreScrollFrame() {
659 return CurrentPresShellState()->mPresShellIgnoreScrollFrame;
660 }
661
662 /**
663 * Notify the display list builder that we're entering a presshell.
664 * aReferenceFrame should be a frame in the new presshell.
665 * aPointerEventsNoneDoc should be set to true if the frame generating this
666 * document is pointer-events:none.
667 */
668 void EnterPresShell(const nsIFrame* aReferenceFrame,
669 bool aPointerEventsNoneDoc = false);
670 /**
671 * For print-preview documents, we sometimes need to build display items for
672 * the same frames multiple times in the same presentation, with different
673 * clipping. Between each such batch of items, call
674 * ResetMarkedFramesForDisplayList to make sure that the results of
675 * MarkFramesForDisplayList do not carry over between batches.
676 */
677 void ResetMarkedFramesForDisplayList(const nsIFrame* aReferenceFrame);
678 /**
679 * Notify the display list builder that we're leaving a presshell.
680 */
681 void LeavePresShell(const nsIFrame* aReferenceFrame,
682 nsDisplayList* aPaintedContents);
683
684 void IncrementPresShellPaintCount(PresShell* aPresShell);
685
686 /**
687 * Returns true if we're currently building a display list that's
688 * directly or indirectly under an nsDisplayTransform.
689 */
IsInTransform()690 bool IsInTransform() const { return mInTransform; }
691
InEventsOnly()692 bool InEventsOnly() const { return mInEventsOnly; }
693 /**
694 * Indicate whether or not we're directly or indirectly under and
695 * nsDisplayTransform or SVG foreignObject.
696 */
SetInTransform(bool aInTransform)697 void SetInTransform(bool aInTransform) { mInTransform = aInTransform; }
698
699 /**
700 * Returns true if we're currently building a display list that's
701 * under an nsDisplayFilters.
702 */
IsInFilter()703 bool IsInFilter() const { return mInFilter; }
704
705 /**
706 * Return true if we're currently building a display list for a
707 * nested presshell.
708 */
IsInSubdocument()709 bool IsInSubdocument() const { return mPresShellStates.Length() > 1; }
710
SetDisablePartialUpdates(bool aDisable)711 void SetDisablePartialUpdates(bool aDisable) {
712 mDisablePartialUpdates = aDisable;
713 }
DisablePartialUpdates()714 bool DisablePartialUpdates() const { return mDisablePartialUpdates; }
715
SetPartialBuildFailed(bool aFailed)716 void SetPartialBuildFailed(bool aFailed) { mPartialBuildFailed = aFailed; }
PartialBuildFailed()717 bool PartialBuildFailed() const { return mPartialBuildFailed; }
718
IsInActiveDocShell()719 bool IsInActiveDocShell() const { return mIsInActiveDocShell; }
SetInActiveDocShell(bool aActive)720 void SetInActiveDocShell(bool aActive) { mIsInActiveDocShell = aActive; }
721
722 /**
723 * Return true if we're currently building a display list for the presshell
724 * of a chrome document, or if we're building the display list for a popup.
725 */
IsInChromeDocumentOrPopup()726 bool IsInChromeDocumentOrPopup() const {
727 return mIsInChromePresContext || mIsBuildingForPopup;
728 }
729
730 /**
731 * @return true if images have been set to decode synchronously.
732 */
ShouldSyncDecodeImages()733 bool ShouldSyncDecodeImages() const { return mSyncDecodeImages; }
734
735 /**
736 * Indicates whether we should synchronously decode images. If true, we decode
737 * and draw whatever image data has been loaded. If false, we just draw
738 * whatever has already been decoded.
739 */
SetSyncDecodeImages(bool aSyncDecodeImages)740 void SetSyncDecodeImages(bool aSyncDecodeImages) {
741 mSyncDecodeImages = aSyncDecodeImages;
742 }
743
SetTableBackgroundSet(nsDisplayTableBackgroundSet * aTableSet)744 nsDisplayTableBackgroundSet* SetTableBackgroundSet(
745 nsDisplayTableBackgroundSet* aTableSet) {
746 nsDisplayTableBackgroundSet* old = mTableBackgroundSet;
747 mTableBackgroundSet = aTableSet;
748 return old;
749 }
GetTableBackgroundSet()750 nsDisplayTableBackgroundSet* GetTableBackgroundSet() const {
751 return mTableBackgroundSet;
752 }
753
754 void FreeClipChains();
755
756 /*
757 * Frees the temporary display items created during merging.
758 */
759 void FreeTemporaryItems();
760
761 /**
762 * Helper method to generate background painting flags based on the
763 * information available in the display list builder.
764 */
765 uint32_t GetBackgroundPaintFlags();
766
767 /**
768 * Helper method to generate nsImageRenderer flags based on the information
769 * available in the display list builder.
770 */
771 uint32_t GetImageRendererFlags() const;
772
773 /**
774 * Helper method to generate image decoding flags based on the
775 * information available in the display list builder.
776 */
777 uint32_t GetImageDecodeFlags() const;
778
779 /**
780 * Subtracts aRegion from *aVisibleRegion. We avoid letting
781 * aVisibleRegion become overcomplex by simplifying it if necessary.
782 */
783 void SubtractFromVisibleRegion(nsRegion* aVisibleRegion,
784 const nsRegion& aRegion);
785
786 /**
787 * Mark the frames in aFrames to be displayed if they intersect aDirtyRect
788 * (which is relative to aDirtyFrame). If the frames have placeholders
789 * that might not be displayed, we mark the placeholders and their ancestors
790 * to ensure that display list construction descends into them
791 * anyway. nsDisplayListBuilder will take care of unmarking them when it is
792 * destroyed.
793 */
794 void MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
795 const nsFrameList& aFrames);
796 void MarkFrameForDisplay(nsIFrame* aFrame, const nsIFrame* aStopAtFrame);
797 void MarkFrameForDisplayIfVisible(nsIFrame* aFrame,
798 const nsIFrame* aStopAtFrame);
799 void AddFrameMarkedForDisplayIfVisible(nsIFrame* aFrame);
800
801 void ClearFixedBackgroundDisplayData();
802 /**
803 * Mark all child frames that Preserve3D() as needing display.
804 * Because these frames include transforms set on their parent, dirty rects
805 * for intermediate frames may be empty, yet child frames could still be
806 * visible.
807 */
808 void MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame);
809
810 /**
811 * Returns true if we need to descend into this frame when building
812 * the display list, even though it doesn't intersect the dirty
813 * rect, because it may have out-of-flows that do so.
814 */
ShouldDescendIntoFrame(nsIFrame * aFrame,bool aVisible)815 bool ShouldDescendIntoFrame(nsIFrame* aFrame, bool aVisible) const {
816 return aFrame->HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) ||
817 (aVisible && aFrame->ForceDescendIntoIfVisible()) ||
818 GetIncludeAllOutOfFlows();
819 }
820
821 /**
822 * Returns the list of registered theme geometries.
823 */
GetThemeGeometries()824 nsTArray<nsIWidget::ThemeGeometry> GetThemeGeometries() const {
825 nsTArray<nsIWidget::ThemeGeometry> geometries;
826
827 for (const auto& data : mThemeGeometries.Values()) {
828 geometries.AppendElements(*data);
829 }
830
831 return geometries;
832 }
833
834 /**
835 * Notifies the builder that a particular themed widget exists
836 * at the given rectangle within the currently built display list.
837 * For certain appearance values (currently only StyleAppearance::Toolbar and
838 * StyleAppearance::WindowTitlebar) this gets called during every display list
839 * construction, for every themed widget of the right type within the
840 * display list, except for themed widgets which are transformed or have
841 * effects applied to them (e.g. CSS opacity or filters).
842 *
843 * @param aWidgetType the -moz-appearance value for the themed widget
844 * @param aItem the item associated with the theme geometry
845 * @param aRect the device-pixel rect relative to the widget's displayRoot
846 * for the themed widget
847 */
RegisterThemeGeometry(uint8_t aWidgetType,nsDisplayItem * aItem,const LayoutDeviceIntRect & aRect)848 void RegisterThemeGeometry(uint8_t aWidgetType, nsDisplayItem* aItem,
849 const LayoutDeviceIntRect& aRect) {
850 if (!mIsPaintingToWindow) {
851 return;
852 }
853
854 nsTArray<nsIWidget::ThemeGeometry>* geometries =
855 mThemeGeometries.GetOrInsertNew(aItem);
856 geometries->AppendElement(nsIWidget::ThemeGeometry(aWidgetType, aRect));
857 }
858
859 /**
860 * Removes theme geometries associated with the given display item |aItem|.
861 */
UnregisterThemeGeometry(nsDisplayItem * aItem)862 void UnregisterThemeGeometry(nsDisplayItem* aItem) {
863 mThemeGeometries.Remove(aItem);
864 }
865
866 /**
867 * Adjusts mWindowDraggingRegion to take into account aFrame. If aFrame's
868 * -moz-window-dragging value is |drag|, its border box is added to the
869 * collected dragging region; if the value is |no-drag|, the border box is
870 * subtracted from the region; if the value is |default|, that frame does
871 * not influence the window dragging region.
872 */
873 void AdjustWindowDraggingRegion(nsIFrame* aFrame);
874
875 LayoutDeviceIntRegion GetWindowDraggingRegion() const;
876
877 void RemoveModifiedWindowRegions();
878 void ClearRetainedWindowRegions();
879
880 const nsTHashMap<nsPtrHashKey<dom::RemoteBrowser>, dom::EffectsInfo>&
GetEffectUpdates()881 GetEffectUpdates() const {
882 return mEffectsUpdates;
883 }
884
885 void AddEffectUpdate(dom::RemoteBrowser* aBrowser,
886 const dom::EffectsInfo& aUpdate);
887
888 /**
889 * Allocate memory in our arena. It will only be freed when this display list
890 * builder is destroyed. This memory holds nsDisplayItems and
891 * DisplayItemClipChain objects.
892 *
893 * Destructors are called as soon as the item is no longer used.
894 */
Allocate(size_t aSize,DisplayListArenaObjectId aId)895 void* Allocate(size_t aSize, DisplayListArenaObjectId aId) {
896 return mPool.Allocate(aId, aSize);
897 }
Allocate(size_t aSize,DisplayItemType aType)898 void* Allocate(size_t aSize, DisplayItemType aType) {
899 #define DECLARE_DISPLAY_ITEM_TYPE(name_, ...) \
900 static_assert(size_t(DisplayItemType::TYPE_##name_) == \
901 size_t(DisplayListArenaObjectId::name_), \
902 "");
903 #include "nsDisplayItemTypesList.h"
904 static_assert(size_t(DisplayItemType::TYPE_MAX) ==
905 size_t(DisplayListArenaObjectId::CLIPCHAIN),
906 "");
907 static_assert(size_t(DisplayItemType::TYPE_MAX) + 1 ==
908 size_t(DisplayListArenaObjectId::LISTNODE),
909 "");
910 #undef DECLARE_DISPLAY_ITEM_TYPE
911 return Allocate(aSize, DisplayListArenaObjectId(size_t(aType)));
912 }
913
Destroy(DisplayListArenaObjectId aId,void * aPtr)914 void Destroy(DisplayListArenaObjectId aId, void* aPtr) {
915 return mPool.Free(aId, aPtr);
916 }
Destroy(DisplayItemType aType,void * aPtr)917 void Destroy(DisplayItemType aType, void* aPtr) {
918 return Destroy(DisplayListArenaObjectId(size_t(aType)), aPtr);
919 }
920
921 /**
922 * Allocate a new ActiveScrolledRoot in the arena. Will be cleaned up
923 * automatically when the arena goes away.
924 */
925 ActiveScrolledRoot* AllocateActiveScrolledRoot(
926 const ActiveScrolledRoot* aParent, nsIScrollableFrame* aScrollableFrame);
927
928 /**
929 * Allocate a new DisplayItemClipChain object in the arena. Will be cleaned
930 * up automatically when the arena goes away.
931 */
932 const DisplayItemClipChain* AllocateDisplayItemClipChain(
933 const DisplayItemClip& aClip, const ActiveScrolledRoot* aASR,
934 const DisplayItemClipChain* aParent);
935
936 /**
937 * Intersect two clip chains, allocating the new clip chain items in this
938 * builder's arena. The result is parented to aAncestor, and no intersections
939 * happen past aAncestor's ASR.
940 * That means aAncestor has to be living in this builder's arena already.
941 * aLeafClip1 and aLeafClip2 only need to outlive the call to this function,
942 * their values are copied into the newly-allocated intersected clip chain
943 * and this function does not hold on to any pointers to them.
944 */
945 const DisplayItemClipChain* CreateClipChainIntersection(
946 const DisplayItemClipChain* aAncestor,
947 const DisplayItemClipChain* aLeafClip1,
948 const DisplayItemClipChain* aLeafClip2);
949
950 /**
951 * Same as above, except aAncestor is computed as the nearest common
952 * ancestor of the two provided clips.
953 */
954 const DisplayItemClipChain* CreateClipChainIntersection(
955 const DisplayItemClipChain* aLeafClip1,
956 const DisplayItemClipChain* aLeafClip2);
957
958 /**
959 * Clone the supplied clip chain's chain items into this builder's arena.
960 */
961 const DisplayItemClipChain* CopyWholeChain(
962 const DisplayItemClipChain* aClipChain);
963
GetFilterASR()964 const ActiveScrolledRoot* GetFilterASR() const { return mFilterASR; }
965
966 /**
967 * Merges the display items in |aMergedItems| and returns a new temporary
968 * display item.
969 * The display items in |aMergedItems| have to be mergeable with each other.
970 */
971 nsDisplayWrapList* MergeItems(nsTArray<nsDisplayItem*>& aItems);
972
973 /**
974 * A helper class used to temporarily set nsDisplayListBuilder properties for
975 * building display items.
976 * aVisibleRect and aDirtyRect are relative to aForChild.
977 */
978 class AutoBuildingDisplayList {
979 public:
AutoBuildingDisplayList(nsDisplayListBuilder * aBuilder,nsIFrame * aForChild,const nsRect & aVisibleRect,const nsRect & aDirtyRect)980 AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aForChild,
981 const nsRect& aVisibleRect,
982 const nsRect& aDirtyRect)
983 : AutoBuildingDisplayList(aBuilder, aForChild, aVisibleRect, aDirtyRect,
984 aForChild->IsTransformed()) {}
985
986 AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aForChild,
987 const nsRect& aVisibleRect,
988 const nsRect& aDirtyRect,
989 const bool aIsTransformed);
990
SetReferenceFrameAndCurrentOffset(const nsIFrame * aFrame,const nsPoint & aOffset)991 void SetReferenceFrameAndCurrentOffset(const nsIFrame* aFrame,
992 const nsPoint& aOffset) {
993 mBuilder->mCurrentReferenceFrame = aFrame;
994 mBuilder->mCurrentOffsetToReferenceFrame = aOffset;
995 }
996
SetAdditionalOffset(const nsPoint & aOffset)997 void SetAdditionalOffset(const nsPoint& aOffset) {
998 MOZ_ASSERT(!mBuilder->mAdditionalOffset);
999 mBuilder->mAdditionalOffset = Some(aOffset);
1000
1001 mBuilder->mCurrentOffsetToReferenceFrame += aOffset;
1002 }
1003
RestoreBuildingInvisibleItemsValue()1004 void RestoreBuildingInvisibleItemsValue() {
1005 mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
1006 }
1007
~AutoBuildingDisplayList()1008 ~AutoBuildingDisplayList() {
1009 mBuilder->mCurrentFrame = mPrevFrame;
1010 mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame;
1011 mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset;
1012 mBuilder->mVisibleRect = mPrevVisibleRect;
1013 mBuilder->mDirtyRect = mPrevDirtyRect;
1014 mBuilder->mAncestorHasApzAwareEventHandler =
1015 mPrevAncestorHasApzAwareEventHandler;
1016 mBuilder->mBuildingInvisibleItems = mPrevBuildingInvisibleItems;
1017 mBuilder->mInInvalidSubtree = mPrevInInvalidSubtree;
1018 mBuilder->mAdditionalOffset = mPrevAdditionalOffset;
1019 mBuilder->mCompositorHitTestInfo = mPrevCompositorHitTestInfo;
1020 }
1021
1022 private:
1023 nsDisplayListBuilder* mBuilder;
1024 const nsIFrame* mPrevFrame;
1025 const nsIFrame* mPrevReferenceFrame;
1026 nsPoint mPrevOffset;
1027 Maybe<nsPoint> mPrevAdditionalOffset;
1028 nsRect mPrevVisibleRect;
1029 nsRect mPrevDirtyRect;
1030 gfx::CompositorHitTestInfo mPrevCompositorHitTestInfo;
1031 bool mPrevAncestorHasApzAwareEventHandler;
1032 bool mPrevBuildingInvisibleItems;
1033 bool mPrevInInvalidSubtree;
1034 };
1035
1036 /**
1037 * A helper class to temporarily set the value of mInTransform.
1038 */
1039 class AutoInTransformSetter {
1040 public:
AutoInTransformSetter(nsDisplayListBuilder * aBuilder,bool aInTransform)1041 AutoInTransformSetter(nsDisplayListBuilder* aBuilder, bool aInTransform)
1042 : mBuilder(aBuilder), mOldValue(aBuilder->mInTransform) {
1043 aBuilder->mInTransform = aInTransform;
1044 }
1045
~AutoInTransformSetter()1046 ~AutoInTransformSetter() { mBuilder->mInTransform = mOldValue; }
1047
1048 private:
1049 nsDisplayListBuilder* mBuilder;
1050 bool mOldValue;
1051 };
1052
1053 class AutoInEventsOnly {
1054 public:
AutoInEventsOnly(nsDisplayListBuilder * aBuilder,bool aInEventsOnly)1055 AutoInEventsOnly(nsDisplayListBuilder* aBuilder, bool aInEventsOnly)
1056 : mBuilder(aBuilder), mOldValue(aBuilder->mInEventsOnly) {
1057 aBuilder->mInEventsOnly |= aInEventsOnly;
1058 }
1059
~AutoInEventsOnly()1060 ~AutoInEventsOnly() { mBuilder->mInEventsOnly = mOldValue; }
1061
1062 private:
1063 nsDisplayListBuilder* mBuilder;
1064 bool mOldValue;
1065 };
1066
1067 /**
1068 * A helper class to temporarily set the value of mFilterASR and
1069 * mInFilter.
1070 */
1071 class AutoEnterFilter {
1072 public:
AutoEnterFilter(nsDisplayListBuilder * aBuilder,bool aUsingFilter)1073 AutoEnterFilter(nsDisplayListBuilder* aBuilder, bool aUsingFilter)
1074 : mBuilder(aBuilder),
1075 mOldValue(aBuilder->mFilterASR),
1076 mOldInFilter(aBuilder->mInFilter) {
1077 if (!aBuilder->mFilterASR && aUsingFilter) {
1078 aBuilder->mFilterASR = aBuilder->CurrentActiveScrolledRoot();
1079 aBuilder->mInFilter = true;
1080 }
1081 }
1082
~AutoEnterFilter()1083 ~AutoEnterFilter() {
1084 mBuilder->mFilterASR = mOldValue;
1085 mBuilder->mInFilter = mOldInFilter;
1086 }
1087
1088 private:
1089 nsDisplayListBuilder* mBuilder;
1090 const ActiveScrolledRoot* mOldValue;
1091 bool mOldInFilter;
1092 };
1093
1094 /**
1095 * A helper class to temporarily set the value of mCurrentScrollParentId.
1096 */
1097 class AutoCurrentScrollParentIdSetter {
1098 public:
AutoCurrentScrollParentIdSetter(nsDisplayListBuilder * aBuilder,ViewID aScrollId)1099 AutoCurrentScrollParentIdSetter(nsDisplayListBuilder* aBuilder,
1100 ViewID aScrollId)
1101 : mBuilder(aBuilder),
1102 mOldValue(aBuilder->mCurrentScrollParentId),
1103 mOldForceLayer(aBuilder->mForceLayerForScrollParent),
1104 mOldContainsNonMinimalDisplayPort(
1105 mBuilder->mContainsNonMinimalDisplayPort) {
1106 // If this AutoCurrentScrollParentIdSetter has the same scrollId as the
1107 // previous one on the stack, then that means the scrollframe that
1108 // created this isn't actually scrollable and cannot participate in
1109 // scroll handoff. We set mCanBeScrollParent to false to indicate this.
1110 mCanBeScrollParent = (mOldValue != aScrollId);
1111 aBuilder->mCurrentScrollParentId = aScrollId;
1112 aBuilder->mForceLayerForScrollParent = false;
1113 aBuilder->mContainsNonMinimalDisplayPort = false;
1114 }
1115
ShouldForceLayerForScrollParent()1116 bool ShouldForceLayerForScrollParent() const {
1117 // Only scrollframes participating in scroll handoff can be forced to
1118 // layerize
1119 return mCanBeScrollParent && mBuilder->mForceLayerForScrollParent;
1120 }
1121
GetContainsNonMinimalDisplayPort()1122 bool GetContainsNonMinimalDisplayPort() const {
1123 // Only for scrollframes participating in scroll handoff can we return
1124 // true.
1125 return mCanBeScrollParent && mBuilder->mContainsNonMinimalDisplayPort;
1126 }
1127
~AutoCurrentScrollParentIdSetter()1128 ~AutoCurrentScrollParentIdSetter() {
1129 mBuilder->mCurrentScrollParentId = mOldValue;
1130 if (mCanBeScrollParent) {
1131 // If this flag is set, caller code is responsible for having dealt
1132 // with the current value of mBuilder->mForceLayerForScrollParent, so
1133 // we can just restore the old value.
1134 mBuilder->mForceLayerForScrollParent = mOldForceLayer;
1135 } else {
1136 // Otherwise we need to keep propagating the force-layerization flag
1137 // upwards to the next ancestor scrollframe that does participate in
1138 // scroll handoff.
1139 mBuilder->mForceLayerForScrollParent |= mOldForceLayer;
1140 }
1141 mBuilder->mContainsNonMinimalDisplayPort |=
1142 mOldContainsNonMinimalDisplayPort;
1143 }
1144
1145 private:
1146 nsDisplayListBuilder* mBuilder;
1147 ViewID mOldValue;
1148 bool mOldForceLayer;
1149 bool mOldContainsNonMinimalDisplayPort;
1150 bool mCanBeScrollParent;
1151 };
1152
1153 /**
1154 * Used to update the current active scrolled root on the display list
1155 * builder, and to create new active scrolled roots.
1156 */
1157 class AutoCurrentActiveScrolledRootSetter {
1158 public:
AutoCurrentActiveScrolledRootSetter(nsDisplayListBuilder * aBuilder)1159 explicit AutoCurrentActiveScrolledRootSetter(nsDisplayListBuilder* aBuilder)
1160 : mBuilder(aBuilder),
1161 mSavedActiveScrolledRoot(aBuilder->mCurrentActiveScrolledRoot),
1162 mContentClipASR(aBuilder->ClipState().GetContentClipASR()),
1163 mDescendantsStartIndex(aBuilder->mActiveScrolledRoots.Length()),
1164 mUsed(false) {}
1165
~AutoCurrentActiveScrolledRootSetter()1166 ~AutoCurrentActiveScrolledRootSetter() {
1167 mBuilder->mCurrentActiveScrolledRoot = mSavedActiveScrolledRoot;
1168 }
1169
1170 void SetCurrentActiveScrolledRoot(
1171 const ActiveScrolledRoot* aActiveScrolledRoot);
1172
EnterScrollFrame(nsIScrollableFrame * aScrollableFrame)1173 void EnterScrollFrame(nsIScrollableFrame* aScrollableFrame) {
1174 MOZ_ASSERT(!mUsed);
1175 ActiveScrolledRoot* asr = mBuilder->AllocateActiveScrolledRoot(
1176 mBuilder->mCurrentActiveScrolledRoot, aScrollableFrame);
1177 mBuilder->mCurrentActiveScrolledRoot = asr;
1178 mUsed = true;
1179 }
1180
1181 void InsertScrollFrame(nsIScrollableFrame* aScrollableFrame);
1182
1183 private:
1184 nsDisplayListBuilder* mBuilder;
1185 /**
1186 * The builder's mCurrentActiveScrolledRoot at construction time which
1187 * needs to be restored at destruction time.
1188 */
1189 const ActiveScrolledRoot* mSavedActiveScrolledRoot;
1190 /**
1191 * If there's a content clip on the builder at construction time, then
1192 * mContentClipASR is that content clip's ASR, otherwise null. The
1193 * assumption is that the content clip doesn't get relaxed while this
1194 * object is on the stack.
1195 */
1196 const ActiveScrolledRoot* mContentClipASR;
1197 /**
1198 * InsertScrollFrame needs to mutate existing ASRs (those that were
1199 * created while this object was on the stack), and mDescendantsStartIndex
1200 * makes it easier to skip ASRs that were created in the past.
1201 */
1202 size_t mDescendantsStartIndex;
1203 /**
1204 * Flag to make sure that only one of SetCurrentActiveScrolledRoot /
1205 * EnterScrollFrame / InsertScrollFrame is called per instance of this
1206 * class.
1207 */
1208 bool mUsed;
1209 };
1210
1211 /**
1212 * Keeps track of the innermost ASR that can be used as the ASR for a
1213 * container item that wraps all items that were created while this
1214 * object was on the stack.
1215 * The rule is: all child items of the container item need to have
1216 * clipped bounds with respect to the container ASR.
1217 */
1218 class AutoContainerASRTracker {
1219 public:
1220 explicit AutoContainerASRTracker(nsDisplayListBuilder* aBuilder);
1221
GetContainerASR()1222 const ActiveScrolledRoot* GetContainerASR() {
1223 return mBuilder->mCurrentContainerASR;
1224 }
1225
~AutoContainerASRTracker()1226 ~AutoContainerASRTracker() {
1227 mBuilder->mCurrentContainerASR = ActiveScrolledRoot::PickAncestor(
1228 mBuilder->mCurrentContainerASR, mSavedContainerASR);
1229 }
1230
1231 private:
1232 nsDisplayListBuilder* mBuilder;
1233 const ActiveScrolledRoot* mSavedContainerASR;
1234 };
1235
1236 /**
1237 * A helper class to temporarily set the value of mCurrentScrollbarTarget
1238 * and mCurrentScrollbarFlags.
1239 */
1240 class AutoCurrentScrollbarInfoSetter {
1241 public:
AutoCurrentScrollbarInfoSetter(nsDisplayListBuilder * aBuilder,ViewID aScrollTargetID,const Maybe<layers::ScrollDirection> & aScrollbarDirection,bool aWillHaveLayer)1242 AutoCurrentScrollbarInfoSetter(
1243 nsDisplayListBuilder* aBuilder, ViewID aScrollTargetID,
1244 const Maybe<layers::ScrollDirection>& aScrollbarDirection,
1245 bool aWillHaveLayer)
1246 : mBuilder(aBuilder) {
1247 aBuilder->mIsBuildingScrollbar = true;
1248 aBuilder->mCurrentScrollbarTarget = aScrollTargetID;
1249 aBuilder->mCurrentScrollbarDirection = aScrollbarDirection;
1250 aBuilder->mCurrentScrollbarWillHaveLayer = aWillHaveLayer;
1251 }
1252
~AutoCurrentScrollbarInfoSetter()1253 ~AutoCurrentScrollbarInfoSetter() {
1254 // No need to restore old values because scrollbars cannot be nested.
1255 mBuilder->mIsBuildingScrollbar = false;
1256 mBuilder->mCurrentScrollbarTarget =
1257 layers::ScrollableLayerGuid::NULL_SCROLL_ID;
1258 mBuilder->mCurrentScrollbarDirection.reset();
1259 mBuilder->mCurrentScrollbarWillHaveLayer = false;
1260 }
1261
1262 private:
1263 nsDisplayListBuilder* mBuilder;
1264 };
1265
1266 /**
1267 * A helper class to temporarily set mBuildingExtraPagesForPageNum.
1268 */
1269 class MOZ_RAII AutoPageNumberSetter {
1270 public:
AutoPageNumberSetter(nsDisplayListBuilder * aBuilder,const uint8_t aPageNum)1271 AutoPageNumberSetter(nsDisplayListBuilder* aBuilder, const uint8_t aPageNum)
1272 : mBuilder(aBuilder),
1273 mOldPageNum(aBuilder->GetBuildingExtraPagesForPageNum()) {
1274 mBuilder->SetBuildingExtraPagesForPageNum(aPageNum);
1275 }
~AutoPageNumberSetter()1276 ~AutoPageNumberSetter() {
1277 mBuilder->SetBuildingExtraPagesForPageNum(mOldPageNum);
1278 }
1279
1280 private:
1281 nsDisplayListBuilder* mBuilder;
1282 uint8_t mOldPageNum;
1283 };
1284
1285 /**
1286 * A helper class to track current effective transform for items.
1287 *
1288 * For frames that is Combines3DTransformWithAncestors(), we need to
1289 * apply all transforms of ancestors on the same preserves3D chain
1290 * on the bounds of current frame to the coordination of the 3D
1291 * context root. The 3D context root computes it's bounds from
1292 * these transformed bounds.
1293 */
1294 class AutoAccumulateTransform {
1295 public:
AutoAccumulateTransform(nsDisplayListBuilder * aBuilder)1296 explicit AutoAccumulateTransform(nsDisplayListBuilder* aBuilder)
1297 : mBuilder(aBuilder),
1298 mSavedTransform(aBuilder->mPreserves3DCtx.mAccumulatedTransform) {}
1299
~AutoAccumulateTransform()1300 ~AutoAccumulateTransform() {
1301 mBuilder->mPreserves3DCtx.mAccumulatedTransform = mSavedTransform;
1302 }
1303
Accumulate(const gfx::Matrix4x4 & aTransform)1304 void Accumulate(const gfx::Matrix4x4& aTransform) {
1305 mBuilder->mPreserves3DCtx.mAccumulatedTransform =
1306 aTransform * mBuilder->mPreserves3DCtx.mAccumulatedTransform;
1307 }
1308
GetCurrentTransform()1309 const gfx::Matrix4x4& GetCurrentTransform() {
1310 return mBuilder->mPreserves3DCtx.mAccumulatedTransform;
1311 }
1312
StartRoot()1313 void StartRoot() {
1314 mBuilder->mPreserves3DCtx.mAccumulatedTransform = gfx::Matrix4x4();
1315 }
1316
1317 private:
1318 nsDisplayListBuilder* mBuilder;
1319 gfx::Matrix4x4 mSavedTransform;
1320 };
1321
1322 /**
1323 * A helper class to collect bounds rects of descendants.
1324 *
1325 * For a 3D context root, it's bounds is computed from the bounds of
1326 * descendants. If we transform bounds frame by frame applying
1327 * transforms, the bounds may turn to empty for any singular
1328 * transform on the path, but it is not empty for the accumulated
1329 * transform.
1330 */
1331 class AutoAccumulateRect {
1332 public:
AutoAccumulateRect(nsDisplayListBuilder * aBuilder)1333 explicit AutoAccumulateRect(nsDisplayListBuilder* aBuilder)
1334 : mBuilder(aBuilder),
1335 mSavedRect(aBuilder->mPreserves3DCtx.mAccumulatedRect) {
1336 aBuilder->mPreserves3DCtx.mAccumulatedRect = nsRect();
1337 aBuilder->mPreserves3DCtx.mAccumulatedRectLevels++;
1338 }
1339
~AutoAccumulateRect()1340 ~AutoAccumulateRect() {
1341 mBuilder->mPreserves3DCtx.mAccumulatedRect = mSavedRect;
1342 mBuilder->mPreserves3DCtx.mAccumulatedRectLevels--;
1343 }
1344
1345 private:
1346 nsDisplayListBuilder* mBuilder;
1347 nsRect mSavedRect;
1348 };
1349
AccumulateRect(const nsRect & aRect)1350 void AccumulateRect(const nsRect& aRect) {
1351 mPreserves3DCtx.mAccumulatedRect.UnionRect(mPreserves3DCtx.mAccumulatedRect,
1352 aRect);
1353 }
1354
GetAccumulatedRect()1355 const nsRect& GetAccumulatedRect() {
1356 return mPreserves3DCtx.mAccumulatedRect;
1357 }
1358
1359 /**
1360 * The level is increased by one for items establishing 3D rendering
1361 * context and starting a new accumulation.
1362 */
GetAccumulatedRectLevels()1363 int GetAccumulatedRectLevels() {
1364 return mPreserves3DCtx.mAccumulatedRectLevels;
1365 }
1366
1367 struct OutOfFlowDisplayData {
OutOfFlowDisplayDataOutOfFlowDisplayData1368 OutOfFlowDisplayData(
1369 const DisplayItemClipChain* aContainingBlockClipChain,
1370 const DisplayItemClipChain* aCombinedClipChain,
1371 const ActiveScrolledRoot* aContainingBlockActiveScrolledRoot,
1372 const nsRect& aVisibleRect, const nsRect& aDirtyRect)
1373 : mContainingBlockClipChain(aContainingBlockClipChain),
1374 mCombinedClipChain(aCombinedClipChain),
1375 mContainingBlockActiveScrolledRoot(
1376 aContainingBlockActiveScrolledRoot),
1377 mVisibleRect(aVisibleRect),
1378 mDirtyRect(aDirtyRect) {}
1379 const DisplayItemClipChain* mContainingBlockClipChain;
1380 const DisplayItemClipChain*
1381 mCombinedClipChain; // only necessary for the special case of top layer
1382 const ActiveScrolledRoot* mContainingBlockActiveScrolledRoot;
1383
1384 // If this OutOfFlowDisplayData is associated with the ViewportFrame
1385 // of a document that has a resolution (creating separate visual and
1386 // layout viewports with their own coordinate spaces), these rects
1387 // are in layout coordinates. Similarly, GetVisibleRectForFrame() in
1388 // such a case returns a quantity in layout coordinates.
1389 nsRect mVisibleRect;
1390 nsRect mDirtyRect;
1391
1392 static nsRect ComputeVisibleRectForFrame(nsDisplayListBuilder* aBuilder,
1393 nsIFrame* aFrame,
1394 const nsRect& aVisibleRect,
1395 const nsRect& aDirtyRect,
1396 nsRect* aOutDirtyRect);
1397
GetVisibleRectForFrameOutOfFlowDisplayData1398 nsRect GetVisibleRectForFrame(nsDisplayListBuilder* aBuilder,
1399 nsIFrame* aFrame, nsRect* aDirtyRect) {
1400 return ComputeVisibleRectForFrame(aBuilder, aFrame, mVisibleRect,
1401 mDirtyRect, aDirtyRect);
1402 }
1403 };
1404
1405 NS_DECLARE_FRAME_PROPERTY_DELETABLE(OutOfFlowDisplayDataProperty,
1406 OutOfFlowDisplayData)
1407
1408 struct DisplayListBuildingData {
1409 nsIFrame* mModifiedAGR = nullptr;
1410 nsRect mDirtyRect;
1411 };
NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayListBuildingRect,DisplayListBuildingData)1412 NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayListBuildingRect,
1413 DisplayListBuildingData)
1414
1415 NS_DECLARE_FRAME_PROPERTY_DELETABLE(DisplayListBuildingDisplayPortRect,
1416 nsRect)
1417
1418 static OutOfFlowDisplayData* GetOutOfFlowData(nsIFrame* aFrame) {
1419 if (!aFrame->GetParent()) {
1420 return nullptr;
1421 }
1422 return aFrame->GetParent()->GetProperty(OutOfFlowDisplayDataProperty());
1423 }
1424
1425 nsPresContext* CurrentPresContext();
1426
GetCurrentFixedBackgroundDisplayData()1427 OutOfFlowDisplayData* GetCurrentFixedBackgroundDisplayData() {
1428 auto& displayData = CurrentPresShellState()->mFixedBackgroundDisplayData;
1429 return displayData ? displayData.ptr() : nullptr;
1430 }
1431
1432 /**
1433 * Accumulates the bounds of box frames that have moz-appearance
1434 * -moz-win-exclude-glass style. Used in setting glass margins on
1435 * Windows.
1436 *
1437 * We set the window opaque region (from which glass margins are computed)
1438 * to the intersection of the glass region specified here and the opaque
1439 * region computed during painting. So the excluded glass region actually
1440 * *limits* the extent of the opaque area reported to Windows. We limit it
1441 * so that changes to the computed opaque region (which can vary based on
1442 * region optimizations and the placement of UI elements) outside the
1443 * -moz-win-exclude-glass area don't affect the glass margins reported to
1444 * Windows; changing those margins willy-nilly can cause the Windows 7 glass
1445 * haze effect to jump around disconcertingly.
1446 */
AddWindowExcludeGlassRegion(nsIFrame * aFrame,const nsRect & aBounds)1447 void AddWindowExcludeGlassRegion(nsIFrame* aFrame, const nsRect& aBounds) {
1448 mWindowExcludeGlassRegion.Add(aFrame, aBounds);
1449 }
1450
1451 /**
1452 * Returns the window exclude glass region.
1453 */
GetWindowExcludeGlassRegion()1454 nsRegion GetWindowExcludeGlassRegion() const {
1455 return mWindowExcludeGlassRegion.ToRegion();
1456 }
1457
1458 /**
1459 * Accumulates opaque stuff into the window opaque region.
1460 */
AddWindowOpaqueRegion(nsIFrame * aFrame,const nsRect & aBounds)1461 void AddWindowOpaqueRegion(nsIFrame* aFrame, const nsRect& aBounds) {
1462 if (IsRetainingDisplayList()) {
1463 mRetainedWindowOpaqueRegion.Add(aFrame, aBounds);
1464 return;
1465 }
1466 mWindowOpaqueRegion.Or(mWindowOpaqueRegion, aBounds);
1467 }
1468 /**
1469 * Returns the window opaque region built so far. This may be incomplete
1470 * since the opaque region is built during layer construction.
1471 */
GetWindowOpaqueRegion()1472 const nsRegion GetWindowOpaqueRegion() {
1473 return IsRetainingDisplayList() ? mRetainedWindowOpaqueRegion.ToRegion()
1474 : mWindowOpaqueRegion;
1475 }
1476
1477 void SetGlassDisplayItem(nsDisplayItem* aItem);
ClearGlassDisplayItem()1478 void ClearGlassDisplayItem() { mGlassDisplayItem = nullptr; }
GetGlassDisplayItem()1479 nsDisplayItem* GetGlassDisplayItem() { return mGlassDisplayItem; }
1480
1481 bool NeedToForceTransparentSurfaceForItem(nsDisplayItem* aItem);
1482
1483 /**
1484 * mContainsBlendMode is true if we processed a display item that
1485 * has a blend mode attached. We do this so we can insert a
1486 * nsDisplayBlendContainer in the parent stacking context.
1487 */
SetContainsBlendMode(bool aContainsBlendMode)1488 void SetContainsBlendMode(bool aContainsBlendMode) {
1489 mContainsBlendMode = aContainsBlendMode;
1490 }
ContainsBlendMode()1491 bool ContainsBlendMode() const { return mContainsBlendMode; }
1492
1493 /**
1494 * mContainsBackdropFilter is true if we proccessed a display item that
1495 * has a backdrop filter set. We track this so we can insert a
1496 * nsDisplayBackdropRootContainer in the stacking context of the nearest
1497 * ancestor that forms a backdrop root.
1498 */
SetContainsBackdropFilter(bool aContainsBackdropFilter)1499 void SetContainsBackdropFilter(bool aContainsBackdropFilter) {
1500 mContainsBackdropFilter = aContainsBackdropFilter;
1501 }
ContainsBackdropFilter()1502 bool ContainsBackdropFilter() const { return mContainsBackdropFilter; }
1503
ClipState()1504 DisplayListClipState& ClipState() { return mClipState; }
CurrentActiveScrolledRoot()1505 const ActiveScrolledRoot* CurrentActiveScrolledRoot() {
1506 return mCurrentActiveScrolledRoot;
1507 }
CurrentAncestorASRStackingContextContents()1508 const ActiveScrolledRoot* CurrentAncestorASRStackingContextContents() {
1509 return mCurrentContainerASR;
1510 }
1511
1512 /**
1513 * Add the current frame to the will-change budget if possible and
1514 * remeber the outcome. Subsequent calls to IsInWillChangeBudget
1515 * will return the same value as return here.
1516 */
1517 bool AddToWillChangeBudget(nsIFrame* aFrame, const nsSize& aSize);
1518
1519 /**
1520 * This will add the current frame to the will-change budget the first
1521 * time it is seen. On subsequent calls this will return the same
1522 * answer. This effectively implements a first-come, first-served
1523 * allocation of the will-change budget.
1524 */
1525 bool IsInWillChangeBudget(nsIFrame* aFrame, const nsSize& aSize);
1526
1527 /**
1528 * Clears the will-change budget status for the given |aFrame|.
1529 * This will also remove the frame from will-change budgets.
1530 */
1531 void ClearWillChangeBudgetStatus(nsIFrame* aFrame);
1532
1533 /**
1534 * Removes the given |aFrame| from will-change budgets.
1535 */
1536 void RemoveFromWillChangeBudgets(const nsIFrame* aFrame);
1537
1538 /**
1539 * Clears the will-change budgets.
1540 */
1541 void ClearWillChangeBudgets();
1542
1543 void EnterSVGEffectsContents(nsIFrame* aEffectsFrame,
1544 nsDisplayList* aHoistedItemsStorage);
1545 void ExitSVGEffectsContents();
1546
1547 bool ShouldBuildScrollInfoItemsForHoisting() const;
1548
1549 void AppendNewScrollInfoItemForHoisting(
1550 nsDisplayScrollInfoLayer* aScrollInfoItem);
1551
1552 /**
1553 * A helper class to install/restore nsDisplayListBuilder::mPreserves3DCtx.
1554 *
1555 * mPreserves3DCtx is used by class AutoAccumulateTransform &
1556 * AutoAccumulateRect to passing data between frames in the 3D
1557 * context. If a frame create a new 3D context, it should restore
1558 * the value of mPreserves3DCtx before returning back to the parent.
1559 * This class do it for the users.
1560 */
1561 class AutoPreserves3DContext {
1562 public:
AutoPreserves3DContext(nsDisplayListBuilder * aBuilder)1563 explicit AutoPreserves3DContext(nsDisplayListBuilder* aBuilder)
1564 : mBuilder(aBuilder), mSavedCtx(aBuilder->mPreserves3DCtx) {}
1565
~AutoPreserves3DContext()1566 ~AutoPreserves3DContext() { mBuilder->mPreserves3DCtx = mSavedCtx; }
1567
1568 private:
1569 nsDisplayListBuilder* mBuilder;
1570 Preserves3DContext mSavedCtx;
1571 };
1572
GetPreserves3DRect()1573 const nsRect GetPreserves3DRect() const {
1574 return mPreserves3DCtx.mVisibleRect;
1575 }
1576
SavePreserves3DRect()1577 void SavePreserves3DRect() { mPreserves3DCtx.mVisibleRect = mVisibleRect; }
1578
SavePreserves3DAllowAsyncAnimation(bool aValue)1579 void SavePreserves3DAllowAsyncAnimation(bool aValue) {
1580 mPreserves3DCtx.mAllowAsyncAnimation = aValue;
1581 }
1582
GetPreserves3DAllowAsyncAnimation()1583 bool GetPreserves3DAllowAsyncAnimation() const {
1584 return mPreserves3DCtx.mAllowAsyncAnimation;
1585 }
1586
IsBuildingInvisibleItems()1587 bool IsBuildingInvisibleItems() const { return mBuildingInvisibleItems; }
1588
SetBuildingInvisibleItems(bool aBuildingInvisibleItems)1589 void SetBuildingInvisibleItems(bool aBuildingInvisibleItems) {
1590 mBuildingInvisibleItems = aBuildingInvisibleItems;
1591 }
1592
SetBuildingExtraPagesForPageNum(uint8_t aPageNum)1593 void SetBuildingExtraPagesForPageNum(uint8_t aPageNum) {
1594 mBuildingExtraPagesForPageNum = aPageNum;
1595 }
GetBuildingExtraPagesForPageNum()1596 uint8_t GetBuildingExtraPagesForPageNum() const {
1597 return mBuildingExtraPagesForPageNum;
1598 }
1599
HitTestIsForVisibility()1600 bool HitTestIsForVisibility() const { return mVisibleThreshold.isSome(); }
1601
VisibilityThreshold()1602 float VisibilityThreshold() const {
1603 MOZ_DIAGNOSTIC_ASSERT(HitTestIsForVisibility());
1604 return mVisibleThreshold.valueOr(1.0f);
1605 }
1606
SetHitTestIsForVisibility(float aVisibleThreshold)1607 void SetHitTestIsForVisibility(float aVisibleThreshold) {
1608 mVisibleThreshold = Some(aVisibleThreshold);
1609 }
1610
ShouldBuildAsyncZoomContainer()1611 bool ShouldBuildAsyncZoomContainer() const {
1612 return mBuildAsyncZoomContainer;
1613 }
1614 void UpdateShouldBuildAsyncZoomContainer();
1615
1616 void UpdateShouldBuildBackdropRootContainer();
1617
1618 bool ShouldRebuildDisplayListDueToPrefChange();
1619
1620 /**
1621 * Represents a region composed of frame/rect pairs.
1622 * WeakFrames are used to track whether a rect still belongs to the region.
1623 * Modified frames and rects are removed and re-added to the region if needed.
1624 */
1625 struct WeakFrameRegion {
1626 /**
1627 * A wrapper to store WeakFrame and the pointer to the underlying frame.
1628 * This is needed because WeakFrame does not store the frame pointer after
1629 * the frame has been deleted.
1630 */
1631 struct WeakFrameWrapper {
WeakFrameWrapperWeakFrameRegion::WeakFrameWrapper1632 explicit WeakFrameWrapper(nsIFrame* aFrame)
1633 : mWeakFrame(new WeakFrame(aFrame)), mFrame(aFrame) {}
1634
1635 UniquePtr<WeakFrame> mWeakFrame;
1636 void* mFrame;
1637 };
1638
1639 nsTHashSet<void*> mFrameSet;
1640 nsTArray<WeakFrameWrapper> mFrames;
1641 nsTArray<pixman_box32_t> mRects;
1642
1643 template <typename RectType>
AddWeakFrameRegion1644 void Add(nsIFrame* aFrame, const RectType& aRect) {
1645 if (mFrameSet.Contains(aFrame)) {
1646 return;
1647 }
1648
1649 mFrameSet.Insert(aFrame);
1650 mFrames.AppendElement(WeakFrameWrapper(aFrame));
1651 mRects.AppendElement(nsRegion::RectToBox(aRect));
1652 }
1653
ClearWeakFrameRegion1654 void Clear() {
1655 mFrameSet.Clear();
1656 mFrames.Clear();
1657 mRects.Clear();
1658 }
1659
1660 void RemoveModifiedFramesAndRects();
1661
1662 size_t SizeOfExcludingThis(MallocSizeOf) const;
1663
1664 typedef gfx::ArrayView<pixman_box32_t> BoxArrayView;
1665
ToRegionWeakFrameRegion1666 nsRegion ToRegion() const { return nsRegion(BoxArrayView(mRects)); }
1667
ToLayoutDeviceIntRegionWeakFrameRegion1668 LayoutDeviceIntRegion ToLayoutDeviceIntRegion() const {
1669 return LayoutDeviceIntRegion(BoxArrayView(mRects));
1670 }
1671 };
1672
1673 void AddScrollFrameToNotify(nsIScrollableFrame* aScrollFrame);
1674 void NotifyAndClearScrollFrames();
1675
1676 // Helper class to find what link spec (if any) to associate with a frame,
1677 // recording it in the builder, and generate the corresponding DisplayItem.
1678 // This also takes care of generating a named destination for internal links
1679 // if the element has an id or name attribute.
1680 class Linkifier {
1681 public:
1682 Linkifier(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
1683 nsDisplayList* aList);
1684
~Linkifier()1685 ~Linkifier() {
1686 if (mBuilderToReset) {
1687 mBuilderToReset->mLinkSpec.Truncate(0);
1688 }
1689 }
1690
1691 void MaybeAppendLink(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
1692
1693 private:
1694 nsDisplayListBuilder* mBuilderToReset = nullptr;
1695 nsDisplayList* mList;
1696 };
1697
1698 /**
1699 * Returns the nearest ancestor frame to aFrame that is considered to have
1700 * (or will have) animated geometry. This can return aFrame.
1701 */
1702 nsIFrame* FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame);
1703
1704 /**
1705 * Returns true if this is a retained builder and reuse stacking contexts
1706 * mode is enabled by pref.
1707 */
IsReusingStackingContextItems()1708 bool IsReusingStackingContextItems() const {
1709 return mIsReusingStackingContextItems;
1710 }
1711
1712 /**
1713 * Adds display item |aItem| to the reuseable display items set.
1714 */
1715 void AddReusableDisplayItem(nsDisplayItem* aItem);
1716
1717 /**
1718 * Removes display item |aItem| from the reuseable display items set.
1719 * This is needed because display items are sometimes deleted during
1720 * display list building.
1721 * Called by |nsDisplayItem::Destroy()| when the item has been reused.
1722 */
1723 void RemoveReusedDisplayItem(nsDisplayItem* aItem);
1724
1725 /**
1726 * Clears the reuseable display items set.
1727 */
1728 void ClearReuseableDisplayItems();
1729
1730 /**
1731 * Marks the given display item |aItem| as reused, and updates the necessary
1732 * display list builder state.
1733 */
1734 void ReuseDisplayItem(nsDisplayItem* aItem);
1735
1736 private:
1737 bool MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
1738 const nsRect& aVisibleRect,
1739 const nsRect& aDirtyRect);
1740
1741 friend class nsDisplayBackgroundImage;
1742 friend struct RetainedDisplayListBuilder;
1743
1744 /**
1745 * Returns whether a frame acts as an animated geometry root, optionally
1746 * returning the next ancestor to check.
1747 */
1748 bool IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent = nullptr);
1749
1750 struct PresShellState {
1751 PresShell* mPresShell;
1752 #ifdef DEBUG
1753 Maybe<nsAutoLayoutPhase> mAutoLayoutPhase;
1754 #endif
1755 Maybe<OutOfFlowDisplayData> mFixedBackgroundDisplayData;
1756 uint32_t mFirstFrameMarkedForDisplay;
1757 uint32_t mFirstFrameWithOOFData;
1758 bool mIsBackgroundOnly;
1759 // This is a per-document flag turning off event handling for all content
1760 // in the document, and is set when we enter a subdocument for a pointer-
1761 // events:none frame.
1762 bool mInsidePointerEventsNoneDoc;
1763 bool mTouchEventPrefEnabledDoc;
1764 nsIFrame* mPresShellIgnoreScrollFrame;
1765 };
1766
CurrentPresShellState()1767 PresShellState* CurrentPresShellState() {
1768 NS_ASSERTION(mPresShellStates.Length() > 0,
1769 "Someone forgot to enter a presshell");
1770 return &mPresShellStates[mPresShellStates.Length() - 1];
1771 }
1772
1773 void AddSizeOfExcludingThis(nsWindowSizes&) const;
1774
1775 struct FrameWillChangeBudget {
FrameWillChangeBudgetFrameWillChangeBudget1776 FrameWillChangeBudget() : mPresContext(nullptr), mUsage(0) {}
1777
FrameWillChangeBudgetFrameWillChangeBudget1778 FrameWillChangeBudget(const nsPresContext* aPresContext, uint32_t aUsage)
1779 : mPresContext(aPresContext), mUsage(aUsage) {}
1780
1781 const nsPresContext* mPresContext;
1782 uint32_t mUsage;
1783 };
1784
1785 nsIFrame* const mReferenceFrame;
1786 nsIFrame* mIgnoreScrollFrame;
1787
1788 using Arena = nsPresArena<32768, DisplayListArenaObjectId,
1789 size_t(DisplayListArenaObjectId::COUNT)>;
1790 Arena mPool;
1791
1792 AutoTArray<PresShellState, 8> mPresShellStates;
1793 AutoTArray<nsIFrame*, 400> mFramesMarkedForDisplay;
1794 AutoTArray<nsIFrame*, 40> mFramesMarkedForDisplayIfVisible;
1795 AutoTArray<nsIFrame*, 20> mFramesWithOOFData;
1796 nsClassHashtable<nsPtrHashKey<nsDisplayItem>,
1797 nsTArray<nsIWidget::ThemeGeometry>>
1798 mThemeGeometries;
1799 DisplayListClipState mClipState;
1800 const ActiveScrolledRoot* mCurrentActiveScrolledRoot;
1801 const ActiveScrolledRoot* mCurrentContainerASR;
1802 // mCurrentFrame is the frame that we're currently calling (or about to call)
1803 // BuildDisplayList on.
1804 const nsIFrame* mCurrentFrame;
1805 // The reference frame for mCurrentFrame.
1806 const nsIFrame* mCurrentReferenceFrame;
1807 // The offset from mCurrentFrame to mCurrentReferenceFrame.
1808 nsPoint mCurrentOffsetToReferenceFrame;
1809
1810 Maybe<nsPoint> mAdditionalOffset;
1811
1812 // will-change budget tracker
1813 typedef uint32_t DocumentWillChangeBudget;
1814 nsTHashMap<nsPtrHashKey<const nsPresContext>, DocumentWillChangeBudget>
1815 mDocumentWillChangeBudgets;
1816
1817 // Any frame listed in this set is already counted in the budget
1818 // and thus is in-budget.
1819 nsTHashMap<nsPtrHashKey<const nsIFrame>, FrameWillChangeBudget>
1820 mFrameWillChangeBudgets;
1821
1822 uint8_t mBuildingExtraPagesForPageNum;
1823
1824 nsTHashMap<nsPtrHashKey<dom::RemoteBrowser>, dom::EffectsInfo>
1825 mEffectsUpdates;
1826
1827 // Relative to mCurrentFrame.
1828 nsRect mVisibleRect;
1829 nsRect mDirtyRect;
1830
1831 // Tracked regions used for retained display list.
1832 WeakFrameRegion mWindowExcludeGlassRegion;
1833 WeakFrameRegion mRetainedWindowDraggingRegion;
1834 WeakFrameRegion mRetainedWindowNoDraggingRegion;
1835
1836 // Window opaque region is calculated during layer building.
1837 WeakFrameRegion mRetainedWindowOpaqueRegion;
1838
1839 // Optimized versions for non-retained display list.
1840 LayoutDeviceIntRegion mWindowDraggingRegion;
1841 LayoutDeviceIntRegion mWindowNoDraggingRegion;
1842 nsRegion mWindowOpaqueRegion;
1843
1844 // The display item for the Windows window glass background, if any
1845 // Set during full display list builds or during display list merging only,
1846 // partial display list builds don't touch this.
1847 nsDisplayItem* mGlassDisplayItem;
1848 // If we've encountered a glass item yet, only used during partial display
1849 // list builds.
1850 bool mHasGlassItemDuringPartial;
1851
1852 nsIFrame* mCaretFrame;
1853 nsRect mCaretRect;
1854
1855 // A temporary list that we append scroll info items to while building
1856 // display items for the contents of frames with SVG effects.
1857 // Only non-null when ShouldBuildScrollInfoItemsForHoisting() is true.
1858 // This is a pointer and not a real nsDisplayList value because the
1859 // nsDisplayList class is defined below this class, so we can't use it here.
1860 nsDisplayList* mScrollInfoItemsForHoisting;
1861 nsTArray<RefPtr<ActiveScrolledRoot>> mActiveScrolledRoots;
1862 std::unordered_set<const DisplayItemClipChain*, DisplayItemClipChainHasher,
1863 DisplayItemClipChainEqualer>
1864 mClipDeduplicator;
1865 DisplayItemClipChain* mFirstClipChainToDestroy;
1866 nsTArray<nsDisplayItem*> mTemporaryItems;
1867 nsDisplayListBuilderMode mMode;
1868 nsDisplayTableBackgroundSet* mTableBackgroundSet;
1869 ViewID mCurrentScrollParentId;
1870 ViewID mCurrentScrollbarTarget;
1871 Maybe<layers::ScrollDirection> mCurrentScrollbarDirection;
1872 Preserves3DContext mPreserves3DCtx;
1873 nsTArray<nsIFrame*> mSVGEffectsFrames;
1874 // When we are inside a filter, the current ASR at the time we entered the
1875 // filter. Otherwise nullptr.
1876 const ActiveScrolledRoot* mFilterASR;
1877 std::unordered_set<nsIScrollableFrame*> mScrollFramesToNotify;
1878 nsCString mLinkSpec; // Destination of link currently being emitted, if any.
1879 nsTHashSet<nsCString> mDestinations; // Destination names emitted.
1880 bool mContainsBlendMode;
1881 bool mIsBuildingScrollbar;
1882 bool mCurrentScrollbarWillHaveLayer;
1883 bool mBuildCaret;
1884 bool mRetainingDisplayList;
1885 bool mPartialUpdate;
1886 bool mIgnoreSuppression;
1887 bool mIncludeAllOutOfFlows;
1888 bool mDescendIntoSubdocuments;
1889 bool mSelectedFramesOnly;
1890 bool mAllowMergingAndFlattening;
1891 // True when we're building a display list that's directly or indirectly
1892 // under an nsDisplayTransform
1893 bool mInTransform;
1894 bool mInEventsOnly;
1895 bool mInFilter;
1896 bool mInPageSequence;
1897 bool mIsInChromePresContext;
1898 bool mSyncDecodeImages;
1899 bool mIsPaintingToWindow;
1900 bool mUseHighQualityScaling;
1901 bool mIsPaintingForWebRender;
1902 bool mIsCompositingCheap;
1903 bool mAncestorHasApzAwareEventHandler;
1904 // True when the first async-scrollable scroll frame for which we build a
1905 // display list has a display port. An async-scrollable scroll frame is one
1906 // which WantsAsyncScroll().
1907 bool mHaveScrollableDisplayPort;
1908 bool mWindowDraggingAllowed;
1909 bool mIsBuildingForPopup;
1910 bool mForceLayerForScrollParent;
1911 bool mContainsNonMinimalDisplayPort;
1912 bool mAsyncPanZoomEnabled;
1913 bool mBuildingInvisibleItems;
1914 bool mIsBuilding;
1915 bool mInInvalidSubtree;
1916 bool mBuildCompositorHitTestInfo;
1917 bool mDisablePartialUpdates;
1918 bool mPartialBuildFailed;
1919 bool mIsInActiveDocShell;
1920 bool mBuildAsyncZoomContainer;
1921 bool mContainsBackdropFilter;
1922 bool mIsRelativeToLayoutViewport;
1923 bool mUseOverlayScrollbars;
1924 bool mAlwaysLayerizeScrollbars;
1925
1926 Maybe<float> mVisibleThreshold;
1927 gfx::CompositorHitTestInfo mCompositorHitTestInfo;
1928
1929 bool mIsForContent;
1930 bool mIsReusingStackingContextItems;
1931
1932 // Stores reusable items collected during display list preprocessing.
1933 nsTHashSet<nsDisplayItem*> mReuseableItems;
1934 };
1935
1936 // All types are defined in nsDisplayItemTypes.h
1937 #define NS_DISPLAY_DECL_NAME(n, e) \
1938 const char* Name() const override { return n; } \
1939 constexpr static DisplayItemType ItemType() { return DisplayItemType::e; } \
1940 \
1941 private: \
1942 void* operator new(size_t aSize, nsDisplayListBuilder* aBuilder) { \
1943 return aBuilder->Allocate(aSize, DisplayItemType::e); \
1944 } \
1945 \
1946 template <typename T, typename F, typename... Args> \
1947 friend T* mozilla::MakeDisplayItemWithIndex( \
1948 nsDisplayListBuilder* aBuilder, F* aFrame, const uint16_t aIndex, \
1949 Args&&... aArgs); \
1950 \
1951 public:
1952
1953 #define NS_DISPLAY_ALLOW_CLONING() \
1954 template <typename T> \
1955 friend T* mozilla::MakeClone(nsDisplayListBuilder* aBuilder, \
1956 const T* aItem); \
1957 \
1958 nsDisplayWrapList* Clone(nsDisplayListBuilder* aBuilder) const override { \
1959 return MakeClone(aBuilder, this); \
1960 }
1961
1962 template <typename T>
MakeClone(nsDisplayListBuilder * aBuilder,const T * aItem)1963 MOZ_ALWAYS_INLINE T* MakeClone(nsDisplayListBuilder* aBuilder, const T* aItem) {
1964 static_assert(std::is_base_of<nsDisplayWrapList, T>::value,
1965 "Display item type should be derived from nsDisplayWrapList");
1966 T* item = new (aBuilder) T(aBuilder, *aItem);
1967 item->SetType(T::ItemType());
1968 return item;
1969 }
1970
1971 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1972 void AssertUniqueItem(nsDisplayItem* aItem);
1973 #endif
1974
1975 /**
1976 * Returns true, if a display item of given |aType| needs to be built within
1977 * opacity:0 container.
1978 */
1979 bool ShouldBuildItemForEvents(const DisplayItemType aType);
1980
1981 /**
1982 * Initializes the hit test information of |aItem| if the item type supports it.
1983 */
1984 void InitializeHitTestInfo(nsDisplayListBuilder* aBuilder,
1985 nsPaintedDisplayItem* aItem,
1986 const DisplayItemType aType);
1987
1988 template <typename T, typename F, typename... Args>
MakeDisplayItemWithIndex(nsDisplayListBuilder * aBuilder,F * aFrame,const uint16_t aIndex,Args &&...aArgs)1989 MOZ_ALWAYS_INLINE T* MakeDisplayItemWithIndex(nsDisplayListBuilder* aBuilder,
1990 F* aFrame, const uint16_t aIndex,
1991 Args&&... aArgs) {
1992 static_assert(std::is_base_of<nsDisplayItem, T>::value,
1993 "Display item type should be derived from nsDisplayItem");
1994 static_assert(std::is_base_of<nsIFrame, F>::value,
1995 "Frame type should be derived from nsIFrame");
1996
1997 const DisplayItemType type = T::ItemType();
1998 if (aBuilder->InEventsOnly() && !ShouldBuildItemForEvents(type)) {
1999 // This item is not needed for events.
2000 return nullptr;
2001 }
2002
2003 T* item = new (aBuilder) T(aBuilder, aFrame, std::forward<Args>(aArgs)...);
2004
2005 if (type != DisplayItemType::TYPE_GENERIC) {
2006 item->SetType(type);
2007 }
2008
2009 item->SetPerFrameIndex(aIndex);
2010 item->SetExtraPageForPageNum(aBuilder->GetBuildingExtraPagesForPageNum());
2011
2012 nsPaintedDisplayItem* paintedItem = item->AsPaintedDisplayItem();
2013 if (paintedItem) {
2014 InitializeHitTestInfo(aBuilder, paintedItem, type);
2015 }
2016
2017 if (aBuilder->InInvalidSubtree() ||
2018 item->FrameForInvalidation()->IsFrameModified()) {
2019 item->SetModifiedFrame(true);
2020 }
2021
2022 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2023 if (aBuilder->IsRetainingDisplayList() && aBuilder->IsBuilding()) {
2024 AssertUniqueItem(item);
2025 }
2026
2027 // Verify that InInvalidSubtree matches invalidation frame's modified state.
2028 if (aBuilder->InInvalidSubtree()) {
2029 MOZ_DIAGNOSTIC_ASSERT(
2030 AnyContentAncestorModified(item->FrameForInvalidation()));
2031 }
2032
2033 DebugOnly<bool> isContainerType =
2034 (GetDisplayItemFlagsForType(type) & TYPE_IS_CONTAINER);
2035
2036 MOZ_ASSERT(item->HasChildren() == isContainerType,
2037 "Container items must have container display item flag set.");
2038 #endif
2039
2040 if (aBuilder->IsForPainting() && aBuilder->IsForContent()) {
2041 DL_LOGV("Created display item %p (%s) (frame: %p)", item, item->Name(),
2042 aFrame);
2043 }
2044
2045 return item;
2046 }
2047
2048 template <typename T, typename F, typename... Args>
MakeDisplayItem(nsDisplayListBuilder * aBuilder,F * aFrame,Args &&...aArgs)2049 MOZ_ALWAYS_INLINE T* MakeDisplayItem(nsDisplayListBuilder* aBuilder, F* aFrame,
2050 Args&&... aArgs) {
2051 return MakeDisplayItemWithIndex<T>(aBuilder, aFrame, 0,
2052 std::forward<Args>(aArgs)...);
2053 }
2054
2055 /*
2056 * nsDisplayItemBase is a base-class for all display items. It is mainly
2057 * responsible for handling the frame-display item 1:n relationship, as well as
2058 * storing the state needed for display list merging.
2059 *
2060 * Display items are arena-allocated during display list construction.
2061 *
2062 * Display items can be containers --- i.e., they can perform hit testing
2063 * and painting by recursively traversing a list of child items.
2064 *
2065 * Display items belong to a list at all times (except temporarily as they
2066 * move from one list to another).
2067 */
2068 class nsDisplayItem {
2069 public:
2070 using Layer = layers::Layer;
2071 using LayerManager = layers::LayerManager;
2072 using WebRenderLayerManager = layers::WebRenderLayerManager;
2073 using StackingContextHelper = layers::StackingContextHelper;
2074 using ViewID = layers::ScrollableLayerGuid::ViewID;
2075
2076 /**
2077 * Downcasts this item to nsPaintedDisplayItem, if possible.
2078 */
AsPaintedDisplayItem()2079 virtual nsPaintedDisplayItem* AsPaintedDisplayItem() { return nullptr; }
AsPaintedDisplayItem()2080 virtual const nsPaintedDisplayItem* AsPaintedDisplayItem() const {
2081 return nullptr;
2082 }
2083
2084 /**
2085 * Downcasts this item to nsDisplayWrapList, if possible.
2086 */
AsDisplayWrapList()2087 virtual nsDisplayWrapList* AsDisplayWrapList() { return nullptr; }
AsDisplayWrapList()2088 virtual const nsDisplayWrapList* AsDisplayWrapList() const { return nullptr; }
2089
2090 /**
2091 * Create a clone of this item.
2092 */
Clone(nsDisplayListBuilder * aBuilder)2093 virtual nsDisplayWrapList* Clone(nsDisplayListBuilder* aBuilder) const {
2094 return nullptr;
2095 }
2096
2097 /**
2098 * Checks if the given display item can be merged with this item.
2099 * @return true if the merging is possible, otherwise false.
2100 */
CanMerge(const nsDisplayItem * aItem)2101 virtual bool CanMerge(const nsDisplayItem* aItem) const { return false; }
2102
2103 /**
2104 * Frees the memory allocated for this display item.
2105 * The given display list builder must have allocated this display item.
2106 */
Destroy(nsDisplayListBuilder * aBuilder)2107 virtual void Destroy(nsDisplayListBuilder* aBuilder) {
2108 const DisplayItemType type = GetType();
2109 if (aBuilder->IsForPainting() && aBuilder->IsForContent()) {
2110 DL_LOGV("Destroying display item %p (%s)", this, Name());
2111 }
2112
2113 if (IsReusedItem()) {
2114 aBuilder->RemoveReusedDisplayItem(this);
2115 }
2116
2117 this->~nsDisplayItem();
2118 aBuilder->Destroy(type, this);
2119 }
2120
2121 /**
2122 * Returns the frame that this display item was created for.
2123 * Never returns null.
2124 */
Frame()2125 inline nsIFrame* Frame() const {
2126 MOZ_ASSERT(mFrame, "Trying to use display item after deletion!");
2127 return mFrame;
2128 }
2129
2130 /**
2131 * Called when the display item is prepared for deletion. The display item
2132 * should not be used after calling this function.
2133 */
RemoveFrame(nsIFrame * aFrame)2134 virtual void RemoveFrame(nsIFrame* aFrame) {
2135 MOZ_ASSERT(aFrame);
2136
2137 if (mFrame && aFrame == mFrame) {
2138 mFrame = nullptr;
2139 SetDeletedFrame();
2140 }
2141 }
2142
2143 /**
2144 * A display item can depend on multiple different frames for invalidation.
2145 */
GetDependentFrame()2146 virtual nsIFrame* GetDependentFrame() { return nullptr; }
2147
2148 /**
2149 * Returns the frame that provides the style data, and should
2150 * be checked when deciding if this display item can be reused.
2151 */
FrameForInvalidation()2152 virtual nsIFrame* FrameForInvalidation() const { return Frame(); }
2153
2154 /**
2155 * Display items can override this to communicate that they won't
2156 * contribute any visual information (for example fully transparent).
2157 */
IsInvisible()2158 virtual bool IsInvisible() const { return false; }
2159
2160 /**
2161 * Returns the printable name of this display item.
2162 */
2163 virtual const char* Name() const = 0;
2164
2165 /**
2166 * Some consecutive items should be rendered together as a unit, e.g.,
2167 * outlines for the same element. For this, we need a way for items to
2168 * identify their type. We use the type for other purposes too.
2169 */
GetType()2170 DisplayItemType GetType() const {
2171 MOZ_ASSERT(mType != DisplayItemType::TYPE_ZERO,
2172 "Display item should have a valid type!");
2173 return mType;
2174 }
2175
2176 /**
2177 * Pairing this with the Frame() pointer gives a key that
2178 * uniquely identifies this display item in the display item tree.
2179 */
GetPerFrameKey()2180 uint32_t GetPerFrameKey() const {
2181 // The top 8 bits are the page index
2182 // The middle 16 bits of the per frame key uniquely identify the display
2183 // item when there are more than one item of the same type for a frame.
2184 // The low 8 bits are the display item type.
2185 return (static_cast<uint32_t>(mExtraPageForPageNum)
2186 << (TYPE_BITS + (sizeof(mPerFrameIndex) * 8))) |
2187 (static_cast<uint32_t>(mPerFrameIndex) << TYPE_BITS) |
2188 static_cast<uint32_t>(mType);
2189 }
2190
2191 /**
2192 * Returns true if this item was reused during display list merging.
2193 */
IsReused()2194 bool IsReused() const { return mItemFlags.contains(ItemFlag::ReusedItem); }
2195
SetReused(bool aReused)2196 void SetReused(bool aReused) { SetItemFlag(ItemFlag::ReusedItem, aReused); }
2197
2198 /**
2199 * Returns true if this item can be reused during display list merging.
2200 */
CanBeReused()2201 bool CanBeReused() const {
2202 return !mItemFlags.contains(ItemFlag::CantBeReused);
2203 }
2204
SetCantBeReused()2205 void SetCantBeReused() { mItemFlags += ItemFlag::CantBeReused; }
2206
CanBeCached()2207 bool CanBeCached() const {
2208 return !mItemFlags.contains(ItemFlag::CantBeCached);
2209 }
2210
SetCantBeCached()2211 void SetCantBeCached() { mItemFlags += ItemFlag::CantBeCached; }
2212
IsOldItem()2213 bool IsOldItem() const { return !!mOldList; }
2214
2215 /**
2216 * Returns true if the frame of this display item is in a modified subtree.
2217 */
HasModifiedFrame()2218 bool HasModifiedFrame() const {
2219 return mItemFlags.contains(ItemFlag::ModifiedFrame);
2220 }
2221
SetModifiedFrame(bool aModified)2222 void SetModifiedFrame(bool aModified) {
2223 SetItemFlag(ItemFlag::ModifiedFrame, aModified);
2224 }
2225
2226 bool HasDeletedFrame() const;
2227
2228 /**
2229 * Set the nsDisplayList that this item belongs to, and what index it is
2230 * within that list.
2231 * Temporary state for merging used by RetainedDisplayListBuilder.
2232 */
SetOldListIndex(nsDisplayList * aList,OldListIndex aIndex,uint32_t aListKey,uint32_t aNestingDepth)2233 void SetOldListIndex(nsDisplayList* aList, OldListIndex aIndex,
2234 uint32_t aListKey, uint32_t aNestingDepth) {
2235 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2236 mOldListKey = aListKey;
2237 mOldNestingDepth = aNestingDepth;
2238 #endif
2239 mOldList = reinterpret_cast<uintptr_t>(aList);
2240 mOldListIndex = aIndex;
2241 }
2242
GetOldListIndex(nsDisplayList * aList,uint32_t aListKey,OldListIndex * aOutIndex)2243 bool GetOldListIndex(nsDisplayList* aList, uint32_t aListKey,
2244 OldListIndex* aOutIndex) {
2245 if (mOldList != reinterpret_cast<uintptr_t>(aList)) {
2246 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2247 MOZ_CRASH_UNSAFE_PRINTF(
2248 "Item found was in the wrong list! type %d "
2249 "(outer type was %d at depth %d, now is %d)",
2250 GetPerFrameKey(), mOldListKey, mOldNestingDepth, aListKey);
2251 #endif
2252 return false;
2253 }
2254 *aOutIndex = mOldListIndex;
2255 return true;
2256 }
2257
2258 /**
2259 * Returns the display list containing the children of this display item.
2260 * The children may be in a different coordinate system than this item.
2261 */
GetChildren()2262 virtual RetainedDisplayList* GetChildren() const { return nullptr; }
HasChildren()2263 bool HasChildren() const { return GetChildren(); }
2264
2265 /**
2266 * Display items with children may return true here. This causes the
2267 * display list iterator to descend into the child display list.
2268 */
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)2269 virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
2270 return false;
2271 }
2272
CreatesStackingContextHelper()2273 virtual bool CreatesStackingContextHelper() { return false; }
2274
2275 /**
2276 * Returns true if this item can be moved asynchronously on the compositor,
2277 * see RetainedDisplayListBuilder.cpp comments.
2278 */
CanMoveAsync()2279 virtual bool CanMoveAsync() { return false; }
2280
2281 protected:
2282 // This is never instantiated directly (it has pure virtual methods), so no
2283 // need to count constructors and destructors.
2284 nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
2285 nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
2286 const ActiveScrolledRoot* aActiveScrolledRoot);
2287
2288 /**
2289 * The custom copy-constructor is implemented to prevent copying the saved
2290 * state of the item.
2291 * This is currently only used when creating temporary items for merging.
2292 */
nsDisplayItem(nsDisplayListBuilder * aBuilder,const nsDisplayItem & aOther)2293 nsDisplayItem(nsDisplayListBuilder* aBuilder, const nsDisplayItem& aOther)
2294 : mFrame(aOther.mFrame),
2295 mItemFlags(aOther.mItemFlags),
2296 mType(aOther.mType),
2297 mExtraPageForPageNum(aOther.mExtraPageForPageNum),
2298 mPerFrameIndex(aOther.mPerFrameIndex),
2299 mBuildingRect(aOther.mBuildingRect),
2300 mToReferenceFrame(aOther.mToReferenceFrame),
2301 mActiveScrolledRoot(aOther.mActiveScrolledRoot),
2302 mClipChain(aOther.mClipChain) {
2303 MOZ_COUNT_CTOR(nsDisplayItem);
2304 // TODO: It might be better to remove the flags that aren't copied.
2305 if (aOther.ForceNotVisible()) {
2306 mItemFlags += ItemFlag::ForceNotVisible;
2307 }
2308 if (mFrame->In3DContextAndBackfaceIsHidden()) {
2309 mItemFlags += ItemFlag::BackfaceHidden;
2310 }
2311 if (aOther.Combines3DTransformWithAncestors()) {
2312 mItemFlags += ItemFlag::Combines3DTransformWithAncestors;
2313 }
2314 }
2315
~nsDisplayItem()2316 virtual ~nsDisplayItem() {
2317 MOZ_COUNT_DTOR(nsDisplayItem);
2318 if (mFrame) {
2319 mFrame->RemoveDisplayItem(this);
2320 }
2321 }
2322
SetType(const DisplayItemType aType)2323 void SetType(const DisplayItemType aType) { mType = aType; }
2324
SetPerFrameIndex(const uint16_t aIndex)2325 void SetPerFrameIndex(const uint16_t aIndex) { mPerFrameIndex = aIndex; }
2326
2327 // Display list building for printing can build duplicate
2328 // container display items when they contain a mixture of
2329 // OOF and normal content that is spread across multiple
2330 // pages. We include the page number for the duplicates
2331 // to make our GetPerFrameKey unique.
SetExtraPageForPageNum(const uint8_t aPageNum)2332 void SetExtraPageForPageNum(const uint8_t aPageNum) {
2333 mExtraPageForPageNum = aPageNum;
2334 }
2335
2336 void SetDeletedFrame();
2337
2338 public:
2339 nsDisplayItem() = delete;
2340 nsDisplayItem(const nsDisplayItem&) = delete;
2341
2342 /**
2343 * Invalidate cached information that depends on this node's contents, after
2344 * a mutation of those contents.
2345 *
2346 * Specifically, if you mutate an |nsDisplayItem| in a way that would change
2347 * the WebRender display list items generated for it, you should call this
2348 * method.
2349 *
2350 * If a |RestoreState| method exists to restore some piece of state, that's a
2351 * good indication that modifications to said state should be accompanied by a
2352 * call to this method. Opacity flattening's effects on
2353 * |nsDisplayBackgroundColor| items are one example.
2354 */
InvalidateItemCacheEntry()2355 virtual void InvalidateItemCacheEntry() {}
2356
2357 struct HitTestState {
2358 explicit HitTestState() = default;
2359
~HitTestStateHitTestState2360 ~HitTestState() {
2361 NS_ASSERTION(mItemBuffer.Length() == 0,
2362 "mItemBuffer should have been cleared");
2363 }
2364
2365 // Handling transform items for preserve 3D frames.
2366 bool mInPreserves3D = false;
2367 // When hit-testing for visibility, we may hit an fully opaque item in a
2368 // nested display list. We want to stop at that point, without looking
2369 // further on other items.
2370 bool mHitOccludingItem = false;
2371
2372 float mCurrentOpacity = 1.0f;
2373
2374 AutoTArray<nsDisplayItem*, 100> mItemBuffer;
2375 };
2376
GetFlags()2377 uint8_t GetFlags() const { return GetDisplayItemFlagsForType(GetType()); }
2378
IsContentful()2379 virtual bool IsContentful() const { return GetFlags() & TYPE_IS_CONTENTFUL; }
2380
2381 /**
2382 * This is called after we've constructed a display list for event handling.
2383 * When this is called, we've already ensured that aRect intersects the
2384 * item's bounds and that clipping has been taking into account.
2385 *
2386 * @param aRect the point or rect being tested, relative to the reference
2387 * frame. If the width and height are both 1 app unit, it indicates we're
2388 * hit testing a point, not a rect.
2389 * @param aState must point to a HitTestState. If you don't have one,
2390 * just create one with the default constructor and pass it in.
2391 * @param aOutFrames each item appends the frame(s) in this display item that
2392 * the rect is considered over (if any) to aOutFrames.
2393 */
HitTest(nsDisplayListBuilder * aBuilder,const nsRect & aRect,HitTestState * aState,nsTArray<nsIFrame * > * aOutFrames)2394 virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
2395 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) {}
2396
StyleFrame()2397 virtual nsIFrame* StyleFrame() const { return mFrame; }
2398
2399 /**
2400 * Compute the used z-index of our frame; returns zero for elements to which
2401 * z-index does not apply, and for z-index:auto.
2402 * @note This can be overridden, @see nsDisplayWrapList::SetOverrideZIndex.
2403 */
2404 virtual int32_t ZIndex() const;
2405 /**
2406 * The default bounds is the frame border rect.
2407 * @param aSnap *aSnap is set to true if the returned rect will be
2408 * snapped to nearest device pixel edges during actual drawing.
2409 * It might be set to false and snap anyway, so code computing the set of
2410 * pixels affected by this display item needs to round outwards to pixel
2411 * boundaries when *aSnap is set to false.
2412 * This does not take the item's clipping into account.
2413 * @return a rectangle relative to aBuilder->ReferenceFrame() that
2414 * contains the area drawn by this display item
2415 */
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)2416 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const {
2417 *aSnap = false;
2418 return nsRect(ToReferenceFrame(), Frame()->GetSize());
2419 }
2420
2421 /**
2422 * Returns the untransformed bounds of this display item.
2423 */
GetUntransformedBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)2424 virtual nsRect GetUntransformedBounds(nsDisplayListBuilder* aBuilder,
2425 bool* aSnap) const {
2426 return GetBounds(aBuilder, aSnap);
2427 }
2428
GetTightBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)2429 virtual nsRegion GetTightBounds(nsDisplayListBuilder* aBuilder,
2430 bool* aSnap) const {
2431 *aSnap = false;
2432 return nsRegion();
2433 }
2434
2435 /**
2436 * Returns true if nothing will be rendered inside aRect, false if uncertain.
2437 * aRect is assumed to be contained in this item's bounds.
2438 */
IsInvisibleInRect(const nsRect & aRect)2439 virtual bool IsInvisibleInRect(const nsRect& aRect) const { return false; }
2440
2441 /**
2442 * Returns the result of GetBounds intersected with the item's clip.
2443 * The intersection is approximate since rounded corners are not taking into
2444 * account.
2445 */
2446 nsRect GetClippedBounds(nsDisplayListBuilder* aBuilder) const;
2447
GetBorderRect()2448 nsRect GetBorderRect() const {
2449 return nsRect(ToReferenceFrame(), Frame()->GetSize());
2450 }
2451
GetPaddingRect()2452 nsRect GetPaddingRect() const {
2453 return Frame()->GetPaddingRectRelativeToSelf() + ToReferenceFrame();
2454 }
2455
GetContentRect()2456 nsRect GetContentRect() const {
2457 return Frame()->GetContentRectRelativeToSelf() + ToReferenceFrame();
2458 }
2459
2460 /**
2461 * Checks if the frame(s) owning this display item have been marked as
2462 * invalid, and needing repainting.
2463 */
IsInvalid(nsRect & aRect)2464 virtual bool IsInvalid(nsRect& aRect) const {
2465 bool result = mFrame ? mFrame->IsInvalid(aRect) : false;
2466 aRect += ToReferenceFrame();
2467 return result;
2468 }
2469
2470 /**
2471 * Creates and initializes an nsDisplayItemGeometry object that retains the
2472 * current areas covered by this display item. These need to retain enough
2473 * information such that they can be compared against a future nsDisplayItem
2474 * of the same type, and determine if repainting needs to happen.
2475 *
2476 * Subclasses wishing to store more information need to override both this
2477 * and ComputeInvalidationRegion, as well as implementing an
2478 * nsDisplayItemGeometry subclass.
2479 *
2480 * The default implementation tracks both the display item bounds, and the
2481 * frame's border rect.
2482 */
AllocateGeometry(nsDisplayListBuilder * aBuilder)2483 virtual nsDisplayItemGeometry* AllocateGeometry(
2484 nsDisplayListBuilder* aBuilder) {
2485 return new nsDisplayItemGenericGeometry(this, aBuilder);
2486 }
2487
2488 /**
2489 * Compares an nsDisplayItemGeometry object from a previous paint against the
2490 * current item. Computes if the geometry of the item has changed, and the
2491 * invalidation area required for correct repainting.
2492 *
2493 * The existing geometry will have been created from a display item with a
2494 * matching GetPerFrameKey()/mFrame pair to the current item.
2495 *
2496 * The default implementation compares the display item bounds, and the
2497 * frame's border rect, and invalidates the entire bounds if either rect
2498 * changes.
2499 *
2500 * @param aGeometry The geometry of the matching display item from the
2501 * previous paint.
2502 * @param aInvalidRegion Output param, the region to invalidate, or
2503 * unchanged if none.
2504 */
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion)2505 virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
2506 const nsDisplayItemGeometry* aGeometry,
2507 nsRegion* aInvalidRegion) const {
2508 const nsDisplayItemGenericGeometry* geometry =
2509 static_cast<const nsDisplayItemGenericGeometry*>(aGeometry);
2510 bool snap;
2511 if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
2512 !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
2513 aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
2514 }
2515 }
2516
2517 /**
2518 * An alternative default implementation of ComputeInvalidationRegion,
2519 * that instead invalidates only the changed area between the two items.
2520 */
ComputeInvalidationRegionDifference(nsDisplayListBuilder * aBuilder,const nsDisplayItemBoundsGeometry * aGeometry,nsRegion * aInvalidRegion)2521 void ComputeInvalidationRegionDifference(
2522 nsDisplayListBuilder* aBuilder,
2523 const nsDisplayItemBoundsGeometry* aGeometry,
2524 nsRegion* aInvalidRegion) const {
2525 bool snap;
2526 nsRect bounds = GetBounds(aBuilder, &snap);
2527
2528 if (!aGeometry->mBounds.IsEqualInterior(bounds)) {
2529 nscoord radii[8];
2530 if (aGeometry->mHasRoundedCorners || Frame()->GetBorderRadii(radii)) {
2531 aInvalidRegion->Or(aGeometry->mBounds, bounds);
2532 } else {
2533 aInvalidRegion->Xor(aGeometry->mBounds, bounds);
2534 }
2535 }
2536 }
2537
2538 /**
2539 * This function is called when an item's list of children has been modified
2540 * by RetainedDisplayListBuilder.
2541 */
InvalidateCachedChildInfo(nsDisplayListBuilder * aBuilder)2542 virtual void InvalidateCachedChildInfo(nsDisplayListBuilder* aBuilder) {}
2543
AddSizeOfExcludingThis(nsWindowSizes &)2544 virtual void AddSizeOfExcludingThis(nsWindowSizes&) const {}
2545
2546 /**
2547 * @param aSnap set to true if the edges of the rectangles of the opaque
2548 * region would be snapped to device pixels when drawing
2549 * @return a region of the item that is opaque --- that is, every pixel
2550 * that is visible is painted with an opaque
2551 * color. This is useful for determining when one piece
2552 * of content completely obscures another so that we can do occlusion
2553 * culling.
2554 * This does not take clipping into account.
2555 * This must return a simple region (1 rect) for painting display lists.
2556 * It is only allowed to be a complex region for hit testing.
2557 */
GetOpaqueRegion(nsDisplayListBuilder * aBuilder,bool * aSnap)2558 virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
2559 bool* aSnap) const {
2560 *aSnap = false;
2561 return nsRegion();
2562 }
2563 /**
2564 * @return Some(nscolor) if the item is guaranteed to paint every pixel in its
2565 * bounds with the same (possibly translucent) color
2566 */
IsUniform(nsDisplayListBuilder * aBuilder)2567 virtual Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) const {
2568 return Nothing();
2569 }
2570
2571 /**
2572 * @return true if the contents of this item are rendered fixed relative
2573 * to the nearest viewport.
2574 */
ShouldFixToViewport(nsDisplayListBuilder * aBuilder)2575 virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) const {
2576 return false;
2577 }
2578
2579 /**
2580 * Returns true if all layers that can be active should be forced to be
2581 * active. Requires setting the pref layers.force-active=true.
2582 */
2583 static bool ForceActiveLayers();
2584
2585 #ifdef MOZ_DUMP_PAINTING
2586 /**
2587 * Mark this display item as being painted via
2588 * FrameLayerBuilder::DrawPaintedLayer.
2589 */
Painted()2590 bool Painted() const { return mItemFlags.contains(ItemFlag::Painted); }
2591
2592 /**
2593 * Check if this display item has been painted.
2594 */
SetPainted()2595 void SetPainted() { mItemFlags += ItemFlag::Painted; }
2596 #endif
2597
SetIsGlassItem()2598 void SetIsGlassItem() { mItemFlags += ItemFlag::IsGlassItem; }
IsGlassItem()2599 bool IsGlassItem() { return mItemFlags.contains(ItemFlag::IsGlassItem); }
2600
2601 /**
2602 * Function to create the WebRenderCommands.
2603 * We should check if the layer state is
2604 * active first and have an early return if the layer state is
2605 * not active.
2606 *
2607 * @return true if successfully creating webrender commands.
2608 */
CreateWebRenderCommands(wr::DisplayListBuilder & aBuilder,wr::IpcResourceUpdateQueue & aResources,const StackingContextHelper & aSc,layers::RenderRootStateManager * aManager,nsDisplayListBuilder * aDisplayListBuilder)2609 virtual bool CreateWebRenderCommands(
2610 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
2611 const StackingContextHelper& aSc,
2612 layers::RenderRootStateManager* aManager,
2613 nsDisplayListBuilder* aDisplayListBuilder) {
2614 return false;
2615 }
2616
2617 /**
2618 * Updates the provided aLayerData with any APZ-relevant scroll data
2619 * that is specific to this display item. This is stuff that would normally
2620 * be put on the layer during BuildLayer, but this is only called in
2621 * layers-free webrender mode, where we don't have layers.
2622 *
2623 * This function returns true if and only if it has APZ-relevant scroll data
2624 * to provide. Note that the arguments passed in may be nullptr, in which case
2625 * the function should still return true if and only if it has APZ-relevant
2626 * scroll data, but obviously in this case it can't actually put the
2627 * data onto aLayerData, because there isn't one.
2628 *
2629 * This function assumes that aData and aLayerData will either both be null,
2630 * or will both be non-null. The caller is responsible for enforcing this.
2631 */
UpdateScrollData(layers::WebRenderScrollData * aData,layers::WebRenderLayerScrollData * aLayerData)2632 virtual bool UpdateScrollData(layers::WebRenderScrollData* aData,
2633 layers::WebRenderLayerScrollData* aLayerData) {
2634 return false;
2635 }
2636
2637 /**
2638 * Returns true if this item needs to have its geometry updated, despite
2639 * returning empty invalidation region.
2640 */
NeedsGeometryUpdates()2641 virtual bool NeedsGeometryUpdates() const { return false; }
2642
2643 /**
2644 * Some items such as those calling into the native themed widget machinery
2645 * have to be painted on the content process. In this case it is best to avoid
2646 * allocating layers that serializes and forwards the work to the compositor.
2647 */
MustPaintOnContentSide()2648 virtual bool MustPaintOnContentSide() const { return false; }
2649
2650 /**
2651 * If this has a child list where the children are in the same coordinate
2652 * system as this item (i.e., they have the same reference frame),
2653 * return the list.
2654 */
GetSameCoordinateSystemChildren()2655 virtual RetainedDisplayList* GetSameCoordinateSystemChildren() const {
2656 return nullptr;
2657 }
2658
UpdateBounds(nsDisplayListBuilder * aBuilder)2659 virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) {}
2660 /**
2661 * Do UpdateBounds() for items with frames establishing or extending
2662 * 3D rendering context.
2663 *
2664 * This function is called by UpdateBoundsFor3D() of
2665 * nsDisplayTransform(), and it is called by
2666 * BuildDisplayListForStackingContext() on transform items
2667 * establishing 3D rendering context.
2668 *
2669 * The bounds of a transform item with the frame establishing 3D
2670 * rendering context should be computed by calling
2671 * DoUpdateBoundsPreserves3D() on all descendants that participate
2672 * the same 3d rendering context.
2673 */
DoUpdateBoundsPreserves3D(nsDisplayListBuilder * aBuilder)2674 virtual void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) {}
2675
2676 /**
2677 * Returns the building rectangle used by nsDisplayListBuilder when
2678 * this item was constructed.
2679 */
GetBuildingRect()2680 const nsRect& GetBuildingRect() const { return mBuildingRect; }
2681
SetBuildingRect(const nsRect & aBuildingRect)2682 void SetBuildingRect(const nsRect& aBuildingRect) {
2683 if (aBuildingRect == mBuildingRect) {
2684 // Avoid unnecessary paint rect recompution when the
2685 // building rect is staying the same.
2686 return;
2687 }
2688 mBuildingRect = aBuildingRect;
2689 }
2690
2691 /**
2692 * Returns the building rect for the children, relative to their
2693 * reference frame. Can be different from mBuildingRect for
2694 * nsDisplayTransform, since the reference frame for the children is different
2695 * from the reference frame for the item itself.
2696 */
GetBuildingRectForChildren()2697 virtual const nsRect& GetBuildingRectForChildren() const {
2698 return mBuildingRect;
2699 }
2700
WriteDebugInfo(std::stringstream & aStream)2701 virtual void WriteDebugInfo(std::stringstream& aStream) {}
2702
2703 /**
2704 * Returns the result of aBuilder->ToReferenceFrame(GetUnderlyingFrame())
2705 */
ToReferenceFrame()2706 const nsPoint& ToReferenceFrame() const {
2707 NS_ASSERTION(mFrame, "No frame?");
2708 return mToReferenceFrame;
2709 }
2710
2711 /**
2712 * Returns the reference frame for display item children of this item.
2713 */
ReferenceFrameForChildren()2714 virtual const nsIFrame* ReferenceFrameForChildren() const { return nullptr; }
2715
2716 /**
2717 * Checks if this display item (or any children) contains content that might
2718 * be rendered with component alpha (e.g. subpixel antialiasing). Returns the
2719 * bounds of the area that needs component alpha, or an empty rect if nothing
2720 * in the item does.
2721 */
GetComponentAlphaBounds(nsDisplayListBuilder * aBuilder)2722 virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const {
2723 return nsRect();
2724 }
2725
2726 /**
2727 * Check if we can add async animations to the layer for this display item.
2728 */
CanUseAsyncAnimations(nsDisplayListBuilder * aBuilder)2729 virtual bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) {
2730 return false;
2731 }
2732
SupportsOptimizingToImage()2733 virtual bool SupportsOptimizingToImage() const { return false; }
2734
2735 virtual const DisplayItemClip& GetClip() const;
2736 void IntersectClip(nsDisplayListBuilder* aBuilder,
2737 const DisplayItemClipChain* aOther, bool aStore);
2738
SetActiveScrolledRoot(const ActiveScrolledRoot * aActiveScrolledRoot)2739 virtual void SetActiveScrolledRoot(
2740 const ActiveScrolledRoot* aActiveScrolledRoot) {
2741 mActiveScrolledRoot = aActiveScrolledRoot;
2742 }
GetActiveScrolledRoot()2743 const ActiveScrolledRoot* GetActiveScrolledRoot() const {
2744 return mActiveScrolledRoot;
2745 }
2746
2747 virtual void SetClipChain(const DisplayItemClipChain* aClipChain,
2748 bool aStore);
GetClipChain()2749 const DisplayItemClipChain* GetClipChain() const { return mClipChain; }
2750
BackfaceIsHidden()2751 bool BackfaceIsHidden() const {
2752 return mItemFlags.contains(ItemFlag::BackfaceHidden);
2753 }
2754
Combines3DTransformWithAncestors()2755 bool Combines3DTransformWithAncestors() const {
2756 return mItemFlags.contains(ItemFlag::Combines3DTransformWithAncestors);
2757 }
2758
ForceNotVisible()2759 bool ForceNotVisible() const {
2760 return mItemFlags.contains(ItemFlag::ForceNotVisible);
2761 }
2762
In3DContextAndBackfaceIsHidden()2763 bool In3DContextAndBackfaceIsHidden() const {
2764 return mItemFlags.contains(ItemFlag::BackfaceHidden) &&
2765 mItemFlags.contains(ItemFlag::Combines3DTransformWithAncestors);
2766 }
2767
HasDifferentFrame(const nsDisplayItem * aOther)2768 bool HasDifferentFrame(const nsDisplayItem* aOther) const {
2769 return mFrame != aOther->mFrame;
2770 }
2771
HasHitTestInfo()2772 bool HasHitTestInfo() const {
2773 return mItemFlags.contains(ItemFlag::HasHitTestInfo);
2774 }
2775
HasSameTypeAndClip(const nsDisplayItem * aOther)2776 bool HasSameTypeAndClip(const nsDisplayItem* aOther) const {
2777 return GetPerFrameKey() == aOther->GetPerFrameKey() &&
2778 GetClipChain() == aOther->GetClipChain();
2779 }
2780
HasSameContent(const nsDisplayItem * aOther)2781 bool HasSameContent(const nsDisplayItem* aOther) const {
2782 return mFrame->GetContent() == aOther->Frame()->GetContent();
2783 }
2784
NotifyUsed(nsDisplayListBuilder * aBuilder)2785 virtual void NotifyUsed(nsDisplayListBuilder* aBuilder) {}
2786
2787 virtual Maybe<nsRect> GetClipWithRespectToASR(
2788 nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR) const;
2789
GetUntransformedPaintRect()2790 virtual const nsRect& GetUntransformedPaintRect() const {
2791 return GetBuildingRect();
2792 }
2793
2794 nsRect GetPaintRect(nsDisplayListBuilder* aBuilder, gfxContext* aCtx);
2795
GetHitTestInfo()2796 virtual const HitTestInfo& GetHitTestInfo() { return HitTestInfo::Empty(); }
2797
2798 enum class ReuseState : uint8_t {
2799 None,
2800 // Set during display list building.
2801 Reusable,
2802 // Set during display list preprocessing.
2803 PreProcessed,
2804 // Set during partial display list build.
2805 Reused,
2806 };
2807
SetReusable()2808 void SetReusable() {
2809 MOZ_ASSERT(mReuseState == ReuseState::None ||
2810 mReuseState == ReuseState::Reused);
2811 mReuseState = ReuseState::Reusable;
2812 }
2813
IsReusable()2814 bool IsReusable() const { return mReuseState == ReuseState::Reusable; }
2815
SetPreProcessed()2816 void SetPreProcessed() {
2817 MOZ_ASSERT(mReuseState == ReuseState::Reusable);
2818 mReuseState = ReuseState::PreProcessed;
2819 }
2820
IsPreProcessed()2821 bool IsPreProcessed() const {
2822 return mReuseState == ReuseState::PreProcessed;
2823 }
2824
SetReusedItem()2825 void SetReusedItem() {
2826 MOZ_ASSERT(mReuseState == ReuseState::PreProcessed);
2827 mReuseState = ReuseState::Reused;
2828 }
2829
IsReusedItem()2830 bool IsReusedItem() const { return mReuseState == ReuseState::Reused; }
2831
ResetReuseState()2832 void ResetReuseState() { mReuseState = ReuseState::None; }
2833
GetReuseState()2834 ReuseState GetReuseState() const { return mReuseState; }
2835
2836 nsIFrame* mFrame; // 8
2837
2838 private:
2839 enum class ItemFlag : uint16_t {
2840 CantBeReused,
2841 CantBeCached,
2842 DeletedFrame,
2843 ModifiedFrame,
2844 ReusedItem,
2845 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2846 MergedItem,
2847 PreProcessedItem,
2848 #endif
2849 BackfaceHidden,
2850 Combines3DTransformWithAncestors,
2851 ForceNotVisible,
2852 HasHitTestInfo,
2853 IsGlassItem,
2854 #ifdef MOZ_DUMP_PAINTING
2855 // True if this frame has been painted.
2856 Painted,
2857 #endif
2858 };
2859
2860 EnumSet<ItemFlag, uint16_t> mItemFlags; // 2
2861 DisplayItemType mType = DisplayItemType::TYPE_ZERO; // 1
2862 uint8_t mExtraPageForPageNum = 0; // 1
2863 uint16_t mPerFrameIndex = 0; // 2
2864 ReuseState mReuseState = ReuseState::None;
2865 OldListIndex mOldListIndex; // 4
2866 uintptr_t mOldList = 0; // 8
2867
2868 // This is the rectangle that nsDisplayListBuilder was using as the visible
2869 // rect to decide which items to construct.
2870 nsRect mBuildingRect;
2871
2872 protected:
SetItemFlag(ItemFlag aFlag,const bool aValue)2873 void SetItemFlag(ItemFlag aFlag, const bool aValue) {
2874 if (aValue) {
2875 mItemFlags += aFlag;
2876 } else {
2877 mItemFlags -= aFlag;
2878 }
2879 }
2880
SetHasHitTestInfo()2881 void SetHasHitTestInfo() { mItemFlags += ItemFlag::HasHitTestInfo; }
2882
2883 // Result of ToReferenceFrame(mFrame), if mFrame is non-null
2884 nsPoint mToReferenceFrame;
2885
2886 RefPtr<const ActiveScrolledRoot> mActiveScrolledRoot;
2887 RefPtr<const DisplayItemClipChain> mClipChain;
2888
2889 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
2890 public:
IsMergedItem()2891 bool IsMergedItem() const {
2892 return mItemFlags.contains(ItemFlag::MergedItem);
2893 }
2894
IsPreProcessedItem()2895 bool IsPreProcessedItem() const {
2896 return mItemFlags.contains(ItemFlag::PreProcessedItem);
2897 }
2898
SetMergedPreProcessed(bool aMerged,bool aPreProcessed)2899 void SetMergedPreProcessed(bool aMerged, bool aPreProcessed) {
2900 SetItemFlag(ItemFlag::MergedItem, aMerged);
2901 SetItemFlag(ItemFlag::PreProcessedItem, aPreProcessed);
2902 }
2903
2904 uint32_t mOldListKey = 0;
2905 uint32_t mOldNestingDepth = 0;
2906 #endif
2907 };
2908
2909 class nsPaintedDisplayItem : public nsDisplayItem {
2910 public:
AsPaintedDisplayItem()2911 nsPaintedDisplayItem* AsPaintedDisplayItem() final { return this; }
AsPaintedDisplayItem()2912 const nsPaintedDisplayItem* AsPaintedDisplayItem() const final {
2913 return this;
2914 }
2915
2916 /**
2917 * Returns true if this display item would return true from ApplyOpacity
2918 * without actually applying the opacity. Otherwise returns false.
2919 */
CanApplyOpacity(WebRenderLayerManager * aManager,nsDisplayListBuilder * aBuilder)2920 virtual bool CanApplyOpacity(WebRenderLayerManager* aManager,
2921 nsDisplayListBuilder* aBuilder) const {
2922 return false;
2923 }
2924
2925 /**
2926 * Returns true if this item supports PaintWithClip, where the clipping
2927 * is used directly as the primitive geometry instead of needing an explicit
2928 * clip.
2929 */
CanPaintWithClip(const DisplayItemClip & aClip)2930 virtual bool CanPaintWithClip(const DisplayItemClip& aClip) { return false; }
2931
2932 /**
2933 * Same as |Paint()|, except provides a clip to use the geometry to draw with.
2934 * Must not be called unless |CanPaintWithClip()| returned true.
2935 */
PaintWithClip(nsDisplayListBuilder * aBuilder,gfxContext * aCtx,const DisplayItemClip & aClip)2936 virtual void PaintWithClip(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
2937 const DisplayItemClip& aClip) {
2938 MOZ_ASSERT_UNREACHABLE("PaintWithClip() is not implemented!");
2939 }
2940
2941 /**
2942 * Paint this item to some rendering context.
2943 */
2944 virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) = 0;
2945
2946 /**
2947 * External storage used by |DisplayItemCache| to avoid hashmap lookups.
2948 * If an item is reused and has the cache index set, it means that
2949 * |DisplayItemCache| has assigned a cache slot for the item.
2950 */
CacheIndex()2951 Maybe<uint16_t>& CacheIndex() { return mCacheIndex; }
2952
InvalidateItemCacheEntry()2953 void InvalidateItemCacheEntry() override {
2954 // |nsPaintedDisplayItem|s may have |DisplayItemCache| entries
2955 // that no longer match after a mutation. The cache will notice
2956 // on its own that the entry is no longer in use, and free it.
2957 mCacheIndex = Nothing();
2958 }
2959
GetHitTestInfo()2960 const HitTestInfo& GetHitTestInfo() final { return mHitTestInfo; }
InitializeHitTestInfo(nsDisplayListBuilder * aBuilder)2961 void InitializeHitTestInfo(nsDisplayListBuilder* aBuilder) {
2962 mHitTestInfo.Initialize(aBuilder, Frame());
2963 SetHasHitTestInfo();
2964 }
2965
2966 protected:
nsPaintedDisplayItem(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame)2967 nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
2968 : nsPaintedDisplayItem(aBuilder, aFrame,
2969 aBuilder->CurrentActiveScrolledRoot()) {}
2970
nsPaintedDisplayItem(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,const ActiveScrolledRoot * aActiveScrolledRoot)2971 nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
2972 const ActiveScrolledRoot* aActiveScrolledRoot)
2973 : nsDisplayItem(aBuilder, aFrame, aActiveScrolledRoot) {}
2974
nsPaintedDisplayItem(nsDisplayListBuilder * aBuilder,const nsPaintedDisplayItem & aOther)2975 nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder,
2976 const nsPaintedDisplayItem& aOther)
2977 : nsDisplayItem(aBuilder, aOther), mHitTestInfo(aOther.mHitTestInfo) {}
2978
2979 protected:
2980 HitTestInfo mHitTestInfo;
2981 Maybe<uint16_t> mCacheIndex;
2982 };
2983
2984 template <typename T>
2985 struct MOZ_HEAP_CLASS LinkedListNode {
LinkedListNodeLinkedListNode2986 explicit LinkedListNode(T aValue) : mNext(nullptr), mValue(aValue) {}
2987 LinkedListNode* mNext;
2988 T mValue;
2989 };
2990
2991 template <typename T>
2992 struct LinkedListIterator {
2993 using iterator_category = std::forward_iterator_tag;
2994 using difference_type = std::ptrdiff_t;
2995 using value_type = T;
2996 using pointer = T*;
2997 using reference = T&;
2998 using Node = LinkedListNode<T>;
2999
mNodeLinkedListIterator3000 explicit LinkedListIterator(Node* aNode = nullptr) : mNode(aNode) {}
3001
3002 LinkedListIterator<T>& operator++() {
3003 MOZ_ASSERT(mNode);
3004 mNode = mNode->mNext;
3005 return *this;
3006 }
3007
3008 bool operator==(const LinkedListIterator<T>& aOther) const {
3009 return mNode == aOther.mNode;
3010 }
3011
3012 bool operator!=(const LinkedListIterator<T>& aOther) const {
3013 return mNode != aOther.mNode;
3014 }
3015
3016 const T operator*() const {
3017 MOZ_ASSERT(mNode);
3018 return mNode->mValue;
3019 }
3020
3021 T operator*() {
3022 MOZ_ASSERT(mNode);
3023 return mNode->mValue;
3024 }
3025
3026 Node* mNode;
3027 };
3028
3029 /**
3030 * Manages a singly-linked list of display list items.
3031 *
3032 * Stepping upward through this list is very fast. Stepping downward is very
3033 * slow so we don't support it. The methods that need to step downward
3034 * (HitTest()) internally build a temporary array of all
3035 * the items while they do the downward traversal, so overall they're still
3036 * linear time. We have optimized for efficient AppendToTop() of both
3037 * items and lists, with minimal codesize.
3038 *
3039 * Internal linked list nodes are allocated using arena allocator.
3040 * */
3041 class nsDisplayList {
3042 public:
3043 using Node = LinkedListNode<nsDisplayItem*>;
3044 using iterator = LinkedListIterator<nsDisplayItem*>;
3045 using const_iterator = iterator;
3046
begin()3047 iterator begin() { return iterator(mBottom); }
end()3048 iterator end() { return iterator(nullptr); }
begin()3049 const_iterator begin() const { return iterator(mBottom); }
end()3050 const_iterator end() const { return iterator(nullptr); }
3051
nsDisplayList(nsDisplayListBuilder * aBuilder)3052 explicit nsDisplayList(nsDisplayListBuilder* aBuilder) : mBuilder(aBuilder) {}
3053
3054 nsDisplayList() = delete;
3055 nsDisplayList(const nsDisplayList&) = delete;
3056 nsDisplayList& operator=(const nsDisplayList&) = delete;
3057
~nsDisplayList()3058 virtual ~nsDisplayList() {
3059 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3060 if (!mAllowNonEmptyDestruction) {
3061 MOZ_RELEASE_ASSERT(IsEmpty(), "Nonempty list left over?");
3062 }
3063 #endif
3064 Clear();
3065 }
3066
nsDisplayList(nsDisplayList && aOther)3067 nsDisplayList(nsDisplayList&& aOther)
3068 : mBottom(aOther.mBottom),
3069 mTop(aOther.mTop),
3070 mLength(aOther.mLength),
3071 mBuilder(aOther.mBuilder) {
3072 aOther.SetEmpty();
3073 }
3074
3075 nsDisplayList& operator=(nsDisplayList&& aOther) {
3076 MOZ_RELEASE_ASSERT(mBuilder == aOther.mBuilder);
3077
3078 if (this != &aOther) {
3079 MOZ_RELEASE_ASSERT(IsEmpty());
3080 mBottom = std::move(aOther.mBottom);
3081 mTop = std::move(aOther.mTop);
3082 mLength = std::move(aOther.mLength);
3083 aOther.SetEmpty();
3084 }
3085 return *this;
3086 }
3087
3088 /**
3089 * Append an item to the top of the list.
3090 **/
AppendToTop(nsDisplayItem * aItem)3091 void AppendToTop(nsDisplayItem* aItem) {
3092 if (!aItem) {
3093 return;
3094 }
3095
3096 auto* next = Allocate(aItem);
3097 MOZ_ASSERT(next);
3098
3099 if (IsEmpty()) {
3100 mBottom = next;
3101 mTop = next;
3102 } else {
3103 mTop->mNext = next;
3104 mTop = next;
3105 }
3106
3107 mLength++;
3108
3109 MOZ_ASSERT(mBottom && mTop);
3110 MOZ_ASSERT(mTop->mNext == nullptr);
3111 }
3112
3113 template <typename T, typename F, typename... Args>
AppendNewToTop(nsDisplayListBuilder * aBuilder,F * aFrame,Args &&...aArgs)3114 void AppendNewToTop(nsDisplayListBuilder* aBuilder, F* aFrame,
3115 Args&&... aArgs) {
3116 AppendNewToTopWithIndex<T>(aBuilder, aFrame, 0,
3117 std::forward<Args>(aArgs)...);
3118 }
3119
3120 template <typename T, typename F, typename... Args>
AppendNewToTopWithIndex(nsDisplayListBuilder * aBuilder,F * aFrame,const uint16_t aIndex,Args &&...aArgs)3121 void AppendNewToTopWithIndex(nsDisplayListBuilder* aBuilder, F* aFrame,
3122 const uint16_t aIndex, Args&&... aArgs) {
3123 nsDisplayItem* item = MakeDisplayItemWithIndex<T>(
3124 aBuilder, aFrame, aIndex, std::forward<Args>(aArgs)...);
3125 AppendToTop(item);
3126 }
3127
3128 /**
3129 * Removes all items from aList and appends them to the top of this list.
3130 */
AppendToTop(nsDisplayList * aList)3131 void AppendToTop(nsDisplayList* aList) {
3132 MOZ_ASSERT(aList != this);
3133 MOZ_RELEASE_ASSERT(mBuilder == aList->mBuilder);
3134
3135 if (aList->IsEmpty()) {
3136 return;
3137 }
3138
3139 if (IsEmpty()) {
3140 std::swap(mBottom, aList->mBottom);
3141 std::swap(mTop, aList->mTop);
3142 std::swap(mLength, aList->mLength);
3143 } else {
3144 MOZ_ASSERT(mTop && mTop->mNext == nullptr);
3145 mTop->mNext = aList->mBottom;
3146 mTop = aList->mTop;
3147 mLength += aList->mLength;
3148
3149 aList->SetEmpty();
3150 }
3151 }
3152
3153 /**
3154 * Clears the display list.
3155 */
Clear()3156 void Clear() {
3157 Node* current = mBottom;
3158 Node* next = nullptr;
3159
3160 while (current) {
3161 next = current->mNext;
3162 Deallocate(current);
3163 current = next;
3164 }
3165
3166 SetEmpty();
3167 }
3168
3169 /**
3170 * Remove all items from the list and call their destructors.
3171 */
3172 virtual void DeleteAll(nsDisplayListBuilder* aBuilder);
3173
3174 /**
3175 * @return the item at the bottom of the list, or null if the list is empty
3176 */
GetBottom()3177 nsDisplayItem* GetBottom() const {
3178 return mBottom ? mBottom->mValue : nullptr;
3179 }
3180
3181 /**
3182 * @return the item at the top of the list, or null if the list is empty
3183 */
GetTop()3184 nsDisplayItem* GetTop() const { return mTop ? mTop->mValue : nullptr; }
3185
IsEmpty()3186 bool IsEmpty() const { return mBottom == nullptr; }
3187
3188 /**
3189 * @return the number of items in the list
3190 */
Length()3191 size_t Length() const { return mLength; }
3192
3193 /**
3194 * Stable sort the list by the z-order of Frame() on
3195 * each item. 'auto' is counted as zero.
3196 * It is assumed that the list is already in content document order.
3197 */
3198 void SortByZOrder();
3199
3200 /**
3201 * Stable sort the list by the tree order of the content of
3202 * Frame() on each item. z-index is ignored.
3203 * @param aCommonAncestor a common ancestor of all the content elements
3204 * associated with the display items, for speeding up tree order
3205 * checks, or nullptr if not known; it's only a hint, if it is not an
3206 * ancestor of some elements, then we lose performance but not correctness
3207 */
3208 void SortByContentOrder(nsIContent* aCommonAncestor);
3209
3210 /**
3211 * Sort the display list using a stable sort.
3212 * aComparator(Item item1, Item item2) should return true if item1 should go
3213 * before item2.
3214 * We sort the items into increasing order.
3215 */
3216 template <typename Item, typename Comparator>
Sort(const Comparator & aComparator)3217 void Sort(const Comparator& aComparator) {
3218 if (Length() < 2) {
3219 // Only sort lists with more than one item.
3220 return;
3221 }
3222
3223 // Some casual local browsing testing suggests that a local preallocated
3224 // array of 20 items should be able to avoid a lot of dynamic allocations
3225 // here.
3226 AutoTArray<Item, 20> items;
3227
3228 for (nsDisplayItem* item : TakeItems()) {
3229 items.AppendElement(Item(item));
3230 }
3231
3232 std::stable_sort(items.begin(), items.end(), aComparator);
3233
3234 for (Item& item : items) {
3235 AppendToTop(item);
3236 }
3237 }
3238
TakeItems()3239 nsDisplayList TakeItems() {
3240 nsDisplayList list = std::move(*this);
3241 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3242 list.mAllowNonEmptyDestruction = true;
3243 #endif
3244 return list;
3245 }
3246
RemoveBottom()3247 nsDisplayItem* RemoveBottom() {
3248 if (!mBottom) {
3249 return nullptr;
3250 }
3251
3252 nsDisplayItem* bottom = mBottom->mValue;
3253
3254 auto next = mBottom->mNext;
3255 Deallocate(mBottom);
3256 mBottom = next;
3257
3258 if (!mBottom) {
3259 // No bottom item means no items at all.
3260 mTop = nullptr;
3261 }
3262
3263 MOZ_ASSERT(mLength > 0);
3264 mLength--;
3265
3266 return bottom;
3267 }
3268
3269 /**
3270 * Paint the list to the rendering context. We assume that (0,0) in aCtx
3271 * corresponds to the origin of the reference frame. For best results,
3272 * aCtx's current transform should make (0,0) pixel-aligned. The
3273 * rectangle in aDirtyRect is painted, which *must* be contained in the
3274 * dirty rect used to construct the display list.
3275 *
3276 * If aFlags contains PAINT_USE_WIDGET_LAYERS and
3277 * ShouldUseWidgetLayerManager() is set, then we will paint using
3278 * the reference frame's widget's layer manager (and ctx may be null),
3279 * otherwise we will use a temporary BasicLayerManager and ctx must
3280 * not be null.
3281 *
3282 * If PAINT_EXISTING_TRANSACTION is set, the reference frame's widget's
3283 * layer manager has already had BeginTransaction() called on it and
3284 * we should not call it again.
3285 *
3286 * This must only be called on the root display list of the display list
3287 * tree.
3288 *
3289 * We return the layer manager used for painting --- mainly so that
3290 * callers can dump its layer tree if necessary.
3291 */
3292 enum {
3293 PAINT_DEFAULT = 0,
3294 PAINT_USE_WIDGET_LAYERS = 0x01,
3295 PAINT_EXISTING_TRANSACTION = 0x04,
3296 PAINT_IDENTICAL_DISPLAY_LIST = 0x08
3297 };
3298 void PaintRoot(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
3299 uint32_t aFlags, Maybe<double> aDisplayListBuildTime);
3300
3301 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
3302 int32_t aAppUnitsPerDevPixel);
3303
3304 /**
3305 * Get the bounds. Takes the union of the bounds of all children.
3306 * The result is not cached.
3307 */
3308 nsRect GetClippedBounds(nsDisplayListBuilder* aBuilder) const;
3309
3310 /**
3311 * Get this list's bounds, respecting clips relative to aASR. The result is
3312 * the union of each item's clipped bounds with respect to aASR. That means
3313 * that if an item can move asynchronously with an ASR that is a descendant
3314 * of aASR, then the clipped bounds with respect to aASR will be the clip of
3315 * that item for aASR, because the item can move anywhere inside that clip.
3316 * If there is an item in this list which is not bounded with respect to
3317 * aASR (i.e. which does not have "finite bounds" with respect to aASR),
3318 * then this method trigger an assertion failure.
3319 * The optional aBuildingRect out argument can be set to non-null if the
3320 * caller is also interested to know the building rect. This can be used
3321 * to get the visible rect efficiently without traversing the display list
3322 * twice.
3323 */
3324 nsRect GetClippedBoundsWithRespectToASR(
3325 nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR,
3326 nsRect* aBuildingRect = nullptr) const;
3327
3328 /**
3329 * Returns the opaque region of this display list.
3330 */
GetOpaqueRegion(nsDisplayListBuilder * aBuilder)3331 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder) {
3332 nsRegion result;
3333 bool snap;
3334 for (nsDisplayItem* item : *this) {
3335 result.OrWith(item->GetOpaqueRegion(aBuilder, &snap));
3336 }
3337 return result;
3338 }
3339
3340 /**
3341 * Returns the bounds of the area that needs component alpha.
3342 */
GetComponentAlphaBounds(nsDisplayListBuilder * aBuilder)3343 nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const {
3344 nsRect bounds;
3345 for (nsDisplayItem* item : *this) {
3346 bounds.UnionRect(bounds, item->GetComponentAlphaBounds(aBuilder));
3347 }
3348 return bounds;
3349 }
3350
3351 /**
3352 * Find the topmost display item that returns a non-null frame, and return
3353 * the frame.
3354 */
3355 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
3356 nsDisplayItem::HitTestState* aState,
3357 nsTArray<nsIFrame*>* aOutFrames) const;
3358 /**
3359 * Compute the union of the visible rects of the items in the list. The
3360 * result is not cached.
3361 */
3362 nsRect GetBuildingRect() const;
3363
3364 private:
Allocate(nsDisplayItem * aItem)3365 inline Node* Allocate(nsDisplayItem* aItem) {
3366 void* ptr =
3367 mBuilder->Allocate(sizeof(Node), DisplayListArenaObjectId::LISTNODE);
3368 return new (ptr) Node(aItem);
3369 }
3370
Deallocate(Node * aNode)3371 inline void Deallocate(Node* aNode) {
3372 aNode->~Node();
3373 mBuilder->Destroy(DisplayListArenaObjectId::LISTNODE, aNode);
3374 }
3375
SetEmpty()3376 void SetEmpty() {
3377 mBottom = nullptr;
3378 mTop = nullptr;
3379 mLength = 0;
3380 }
3381
3382 Node* mBottom = nullptr;
3383 Node* mTop = nullptr;
3384 size_t mLength = 0;
3385 nsDisplayListBuilder* mBuilder = nullptr;
3386
3387 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3388 // This checks that the invariant of display lists owning their items is held.
3389 bool mAllowNonEmptyDestruction = false;
3390 #endif
3391 };
3392
3393 /**
3394 * This is passed as a parameter to nsIFrame::BuildDisplayList. That method
3395 * will put any generated items onto the appropriate list given here. It's
3396 * basically just a collection with one list for each separate stacking layer.
3397 * The lists themselves are external to this object and thus can be shared
3398 * with others. Some of the list pointers may even refer to the same list.
3399 */
3400 class nsDisplayListSet {
3401 public:
3402 /**
3403 * @return a list where one should place the border and/or background for
3404 * this frame (everything from steps 1 and 2 of CSS 2.1 appendix E)
3405 */
BorderBackground()3406 nsDisplayList* BorderBackground() const { return mBorderBackground; }
3407 /**
3408 * @return a list where one should place the borders and/or backgrounds for
3409 * block-level in-flow descendants (step 4 of CSS 2.1 appendix E)
3410 */
BlockBorderBackgrounds()3411 nsDisplayList* BlockBorderBackgrounds() const {
3412 return mBlockBorderBackgrounds;
3413 }
3414 /**
3415 * @return a list where one should place descendant floats (step 5 of
3416 * CSS 2.1 appendix E)
3417 */
Floats()3418 nsDisplayList* Floats() const { return mFloats; }
3419 /**
3420 * @return a list where one should place the (pseudo) stacking contexts
3421 * for descendants of this frame (everything from steps 3, 7 and 8
3422 * of CSS 2.1 appendix E)
3423 */
PositionedDescendants()3424 nsDisplayList* PositionedDescendants() const { return mPositioned; }
3425 /**
3426 * @return a list where one should place the outlines
3427 * for this frame and its descendants (step 9 of CSS 2.1 appendix E)
3428 */
Outlines()3429 nsDisplayList* Outlines() const { return mOutlines; }
3430 /**
3431 * @return a list where one should place all other content
3432 */
Content()3433 nsDisplayList* Content() const { return mContent; }
3434
DeleteAll(nsDisplayListBuilder * aBuilder)3435 void DeleteAll(nsDisplayListBuilder* aBuilder) {
3436 BorderBackground()->DeleteAll(aBuilder);
3437 BlockBorderBackgrounds()->DeleteAll(aBuilder);
3438 Floats()->DeleteAll(aBuilder);
3439 PositionedDescendants()->DeleteAll(aBuilder);
3440 Outlines()->DeleteAll(aBuilder);
3441 Content()->DeleteAll(aBuilder);
3442 }
3443
nsDisplayListSet(nsDisplayList * aBorderBackground,nsDisplayList * aBlockBorderBackgrounds,nsDisplayList * aFloats,nsDisplayList * aContent,nsDisplayList * aPositionedDescendants,nsDisplayList * aOutlines)3444 nsDisplayListSet(nsDisplayList* aBorderBackground,
3445 nsDisplayList* aBlockBorderBackgrounds,
3446 nsDisplayList* aFloats, nsDisplayList* aContent,
3447 nsDisplayList* aPositionedDescendants,
3448 nsDisplayList* aOutlines)
3449 : mBorderBackground(aBorderBackground),
3450 mBlockBorderBackgrounds(aBlockBorderBackgrounds),
3451 mFloats(aFloats),
3452 mContent(aContent),
3453 mPositioned(aPositionedDescendants),
3454 mOutlines(aOutlines) {}
3455
3456 /**
3457 * A copy constructor that lets the caller override the BorderBackground
3458 * list.
3459 */
nsDisplayListSet(const nsDisplayListSet & aLists,nsDisplayList * aBorderBackground)3460 nsDisplayListSet(const nsDisplayListSet& aLists,
3461 nsDisplayList* aBorderBackground)
3462 : mBorderBackground(aBorderBackground),
3463 mBlockBorderBackgrounds(aLists.BlockBorderBackgrounds()),
3464 mFloats(aLists.Floats()),
3465 mContent(aLists.Content()),
3466 mPositioned(aLists.PositionedDescendants()),
3467 mOutlines(aLists.Outlines()) {}
3468
3469 /**
3470 * Move all display items in our lists to top of the corresponding lists in
3471 * the destination.
3472 */
3473 void MoveTo(const nsDisplayListSet& aDestination) const;
3474
3475 private:
3476 // This class is only used on stack, so we don't have to worry about leaking
3477 // it. Don't let us be heap-allocated!
3478 void* operator new(size_t sz) noexcept(true);
3479
3480 protected:
3481 nsDisplayList* mBorderBackground;
3482 nsDisplayList* mBlockBorderBackgrounds;
3483 nsDisplayList* mFloats;
3484 nsDisplayList* mContent;
3485 nsDisplayList* mPositioned;
3486 nsDisplayList* mOutlines;
3487 };
3488
3489 /**
3490 * A specialization of nsDisplayListSet where the lists are actually internal
3491 * to the object, and all distinct.
3492 */
3493 struct nsDisplayListCollection : public nsDisplayListSet {
nsDisplayListCollectionnsDisplayListCollection3494 explicit nsDisplayListCollection(nsDisplayListBuilder* aBuilder)
3495 : nsDisplayListSet(&mLists[0], &mLists[1], &mLists[2], &mLists[3],
3496 &mLists[4], &mLists[5]),
3497 mLists{nsDisplayList{aBuilder}, nsDisplayList{aBuilder},
3498 nsDisplayList{aBuilder}, nsDisplayList{aBuilder},
3499 nsDisplayList{aBuilder}, nsDisplayList{aBuilder}} {}
3500
3501 /*
3502 explicit nsDisplayListCollection(nsDisplayListBuilder* aBuilder,
3503 nsDisplayList* aBorderBackground)
3504 : nsDisplayListSet(aBorderBackground, &mLists[1], &mLists[2], &mLists[3],
3505 &mLists[4], &mLists[5]) {}
3506 */
3507 /**
3508 * Sort all lists by content order.
3509 */
SortAllByContentOrdernsDisplayListCollection3510 void SortAllByContentOrder(nsIContent* aCommonAncestor) {
3511 for (auto& mList : mLists) {
3512 mList.SortByContentOrder(aCommonAncestor);
3513 }
3514 }
3515
3516 /**
3517 * Serialize this display list collection into a display list with the items
3518 * in the correct Z order.
3519 * @param aOutList the result display list
3520 * @param aContent the content element to use for content ordering
3521 */
3522 void SerializeWithCorrectZOrder(nsDisplayList* aOutResultList,
3523 nsIContent* aContent);
3524
3525 private:
3526 // This class is only used on stack, so we don't have to worry about leaking
3527 // it. Don't let us be heap-allocated!
3528 void* operator new(size_t sz) noexcept(true);
3529
3530 nsDisplayList mLists[6];
3531 };
3532
3533 /**
3534 * A display list that also retains the partial build
3535 * information (in the form of a DAG) used to create it.
3536 *
3537 * Display lists built from a partial list aren't necessarily
3538 * in the same order as a full build, and the DAG retains
3539 * the information needing to interpret the current
3540 * order correctly.
3541 */
3542 class RetainedDisplayList : public nsDisplayList {
3543 public:
RetainedDisplayList(nsDisplayListBuilder * aBuilder)3544 explicit RetainedDisplayList(nsDisplayListBuilder* aBuilder)
3545 : nsDisplayList(aBuilder) {}
3546
RetainedDisplayList(RetainedDisplayList && aOther)3547 RetainedDisplayList(RetainedDisplayList&& aOther)
3548 : nsDisplayList(std::move(aOther)), mDAG(std::move(aOther.mDAG)) {}
3549
3550 RetainedDisplayList(const RetainedDisplayList&) = delete;
3551 RetainedDisplayList& operator=(const RetainedDisplayList&) = delete;
3552
~RetainedDisplayList()3553 ~RetainedDisplayList() override {
3554 MOZ_ASSERT(mOldItems.IsEmpty(), "Must empty list before destroying");
3555 }
3556
3557 RetainedDisplayList& operator=(RetainedDisplayList&& aOther) {
3558 MOZ_ASSERT(IsEmpty(), "Can only move into an empty list!");
3559 MOZ_ASSERT(mOldItems.IsEmpty(), "Can only move into an empty list!");
3560
3561 nsDisplayList::operator=(std::move(aOther));
3562 mDAG = std::move(aOther.mDAG);
3563 mOldItems = std::move(aOther.mOldItems);
3564 return *this;
3565 }
3566
3567 RetainedDisplayList& operator=(nsDisplayList&& aOther) {
3568 MOZ_ASSERT(IsEmpty(), "Can only move into an empty list!");
3569 MOZ_ASSERT(mOldItems.IsEmpty(), "Can only move into an empty list!");
3570 nsDisplayList::operator=(std::move(aOther));
3571 return *this;
3572 }
3573
DeleteAll(nsDisplayListBuilder * aBuilder)3574 void DeleteAll(nsDisplayListBuilder* aBuilder) override {
3575 for (OldItemInfo& i : mOldItems) {
3576 if (i.mItem && i.mOwnsItem) {
3577 i.mItem->Destroy(aBuilder);
3578 MOZ_ASSERT(!GetBottom(),
3579 "mOldItems should not be owning items if we also have items "
3580 "in the normal list");
3581 }
3582 }
3583 mOldItems.Clear();
3584 mDAG.Clear();
3585 nsDisplayList::DeleteAll(aBuilder);
3586 }
3587
3588 void AddSizeOfExcludingThis(nsWindowSizes&) const;
3589
3590 DirectedAcyclicGraph<MergedListUnits> mDAG;
3591
3592 // Temporary state initialized during the preprocess pass
3593 // of RetainedDisplayListBuilder and then used during merging.
3594 nsTArray<OldItemInfo> mOldItems;
3595 };
3596
3597 class nsDisplayContainer final : public nsDisplayItem {
3598 public:
3599 nsDisplayContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
3600 const ActiveScrolledRoot* aActiveScrolledRoot,
3601 nsDisplayList* aList);
3602
~nsDisplayContainer()3603 ~nsDisplayContainer() override { MOZ_COUNT_DTOR(nsDisplayContainer); }
3604
3605 NS_DISPLAY_DECL_NAME("nsDisplayContainer", TYPE_CONTAINER)
3606
Destroy(nsDisplayListBuilder * aBuilder)3607 void Destroy(nsDisplayListBuilder* aBuilder) override {
3608 mChildren.DeleteAll(aBuilder);
3609 nsDisplayItem::Destroy(aBuilder);
3610 }
3611
3612 bool CreateWebRenderCommands(
3613 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
3614 const StackingContextHelper& aSc,
3615 layers::RenderRootStateManager* aManager,
3616 nsDisplayListBuilder* aDisplayListBuilder) override;
3617
3618 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
3619
3620 nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override;
3621
3622 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
3623 bool* aSnap) const override;
3624
IsUniform(nsDisplayListBuilder * aBuilder)3625 Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) const override {
3626 return Nothing();
3627 }
3628
GetChildren()3629 RetainedDisplayList* GetChildren() const override { return &mChildren; }
GetSameCoordinateSystemChildren()3630 RetainedDisplayList* GetSameCoordinateSystemChildren() const override {
3631 return GetChildren();
3632 }
3633
3634 Maybe<nsRect> GetClipWithRespectToASR(
3635 nsDisplayListBuilder* aBuilder,
3636 const ActiveScrolledRoot* aASR) const override;
3637
3638 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
3639 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
3640
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)3641 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
3642 return true;
3643 }
3644
SetClipChain(const DisplayItemClipChain * aClipChain,bool aStore)3645 void SetClipChain(const DisplayItemClipChain* aClipChain,
3646 bool aStore) override {
3647 MOZ_ASSERT_UNREACHABLE("nsDisplayContainer does not support clipping");
3648 }
3649
3650 void UpdateBounds(nsDisplayListBuilder* aBuilder) override;
3651
3652 private:
3653 mutable RetainedDisplayList mChildren;
3654 nsRect mBounds;
3655 };
3656
3657 /**
3658 * Use this class to implement not-very-frequently-used display items
3659 * that are not opaque, do not receive events, and are bounded by a frame's
3660 * border-rect.
3661 *
3662 * This should not be used for display items which are created frequently,
3663 * because each item is one or two pointers bigger than an item from a
3664 * custom display item class could be, and fractionally slower. However it does
3665 * save code size. We use this for infrequently-used item types.
3666 */
3667 class nsDisplayGeneric : public nsPaintedDisplayItem {
3668 public:
3669 typedef void (*PaintCallback)(nsIFrame* aFrame, gfx::DrawTarget* aDrawTarget,
3670 const nsRect& aDirtyRect, nsPoint aFramePt);
3671
3672 // XXX: should be removed eventually
3673 typedef void (*OldPaintCallback)(nsIFrame* aFrame, gfxContext* aCtx,
3674 const nsRect& aDirtyRect, nsPoint aFramePt);
3675
nsDisplayGeneric(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,PaintCallback aPaint,const char * aName,DisplayItemType aType)3676 nsDisplayGeneric(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
3677 PaintCallback aPaint, const char* aName,
3678 DisplayItemType aType)
3679 : nsPaintedDisplayItem(aBuilder, aFrame),
3680 mPaint(aPaint),
3681 mOldPaint(nullptr),
3682 mName(aName) {
3683 MOZ_COUNT_CTOR(nsDisplayGeneric);
3684 SetType(aType);
3685 }
3686
3687 // XXX: should be removed eventually
nsDisplayGeneric(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,OldPaintCallback aOldPaint,const char * aName,DisplayItemType aType)3688 nsDisplayGeneric(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
3689 OldPaintCallback aOldPaint, const char* aName,
3690 DisplayItemType aType)
3691 : nsPaintedDisplayItem(aBuilder, aFrame),
3692 mPaint(nullptr),
3693 mOldPaint(aOldPaint),
3694 mName(aName) {
3695 MOZ_COUNT_CTOR(nsDisplayGeneric);
3696 SetType(aType);
3697 }
3698
ItemType()3699 constexpr static DisplayItemType ItemType() {
3700 return DisplayItemType::TYPE_GENERIC;
3701 }
3702
MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayGeneric)3703 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayGeneric)
3704
3705 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override {
3706 MOZ_ASSERT(!!mPaint != !!mOldPaint);
3707 if (mPaint) {
3708 mPaint(mFrame, aCtx->GetDrawTarget(), GetPaintRect(aBuilder, aCtx),
3709 ToReferenceFrame());
3710 } else {
3711 mOldPaint(mFrame, aCtx, GetPaintRect(aBuilder, aCtx), ToReferenceFrame());
3712 }
3713 }
3714
Name()3715 const char* Name() const override { return mName; }
3716
3717 // This override is needed because GetType() for nsDisplayGeneric subclasses
3718 // does not match TYPE_GENERIC that was used to allocate the object.
Destroy(nsDisplayListBuilder * aBuilder)3719 void Destroy(nsDisplayListBuilder* aBuilder) override {
3720 this->~nsDisplayGeneric();
3721 aBuilder->Destroy(DisplayItemType::TYPE_GENERIC, this);
3722 }
3723
3724 protected:
new(size_t aSize,nsDisplayListBuilder * aBuilder)3725 void* operator new(size_t aSize, nsDisplayListBuilder* aBuilder) {
3726 return aBuilder->Allocate(aSize, DisplayItemType::TYPE_GENERIC);
3727 }
3728
3729 template <typename T, typename F, typename... Args>
3730 friend T* MakeDisplayItemWithIndex(nsDisplayListBuilder* aBuilder, F* aFrame,
3731 const uint16_t aIndex, Args&&... aArgs);
3732
3733 PaintCallback mPaint;
3734 OldPaintCallback mOldPaint; // XXX: should be removed eventually
3735 const char* mName;
3736 };
3737
3738 #if defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF)
3739 /**
3740 * This class implements painting of reflow counts. Ideally, we would simply
3741 * make all the frame names be those returned by nsIFrame::GetFrameName
3742 * (except that tosses in the content tag name!) and support only one color
3743 * and eliminate this class altogether in favor of nsDisplayGeneric, but for
3744 * the time being we can't pass args to a PaintCallback, so just have a
3745 * separate class to do the right thing. Sadly, this alsmo means we need to
3746 * hack all leaf frame classes to handle this.
3747 *
3748 * XXXbz the color thing is a bit of a mess, but 0 basically means "not set"
3749 * here... I could switch it all to nscolor, but why bother?
3750 */
3751 class nsDisplayReflowCount : public nsPaintedDisplayItem {
3752 public:
3753 nsDisplayReflowCount(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
3754 const char* aFrameName, uint32_t aColor = 0)
nsPaintedDisplayItem(aBuilder,aFrame)3755 : nsPaintedDisplayItem(aBuilder, aFrame),
3756 mFrameName(aFrameName),
3757 mColor(aColor) {
3758 MOZ_COUNT_CTOR(nsDisplayReflowCount);
3759 }
3760
3761 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayReflowCount)
3762
3763 NS_DISPLAY_DECL_NAME("nsDisplayReflowCount", TYPE_REFLOW_COUNT)
3764
3765 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
3766
3767 protected:
3768 const char* mFrameName;
3769 nscolor mColor;
3770 };
3771
3772 # define DO_GLOBAL_REFLOW_COUNT_DSP(_name) \
3773 PR_BEGIN_MACRO \
3774 if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \
3775 PresShell()->IsPaintingFrameCounts()) { \
3776 aLists.Outlines()->AppendNewToTop<mozilla::nsDisplayReflowCount>( \
3777 aBuilder, this, _name); \
3778 } \
3779 PR_END_MACRO
3780
3781 # define DO_GLOBAL_REFLOW_COUNT_DSP_COLOR(_name, _color) \
3782 PR_BEGIN_MACRO \
3783 if (!aBuilder->IsBackgroundOnly() && !aBuilder->IsForEventDelivery() && \
3784 PresShell()->IsPaintingFrameCounts()) { \
3785 aLists.Outlines()->AppendNewToTop<mozilla::nsDisplayReflowCount>( \
3786 aBuilder, this, _name, _color); \
3787 } \
3788 PR_END_MACRO
3789
3790 /*
3791 Macro to be used for classes that don't actually implement BuildDisplayList
3792 */
3793 # define DECL_DO_GLOBAL_REFLOW_COUNT_DSP(_class, _super) \
3794 void BuildDisplayList(nsDisplayListBuilder* aBuilder, \
3795 const nsRect& aDirtyRect, \
3796 const nsDisplayListSet& aLists) { \
3797 DO_GLOBAL_REFLOW_COUNT_DSP(#_class); \
3798 _super::BuildDisplayList(aBuilder, aDirtyRect, aLists); \
3799 }
3800
3801 #else // MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF
3802
3803 # define DO_GLOBAL_REFLOW_COUNT_DSP(_name)
3804 # define DO_GLOBAL_REFLOW_COUNT_DSP_COLOR(_name, _color)
3805 # define DECL_DO_GLOBAL_REFLOW_COUNT_DSP(_class, _super)
3806
3807 #endif // MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF
3808
3809 class nsDisplayCaret : public nsPaintedDisplayItem {
3810 public:
3811 nsDisplayCaret(nsDisplayListBuilder* aBuilder, nsIFrame* aCaretFrame);
3812
3813 #ifdef NS_BUILD_REFCNT_LOGGING
3814 ~nsDisplayCaret() override;
3815 #endif
3816
3817 NS_DISPLAY_DECL_NAME("Caret", TYPE_CARET)
3818
3819 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
3820 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
3821 bool CreateWebRenderCommands(
3822 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
3823 const StackingContextHelper& aSc,
3824 layers::RenderRootStateManager* aManager,
3825 nsDisplayListBuilder* aDisplayListBuilder) override;
3826
3827 protected:
3828 RefPtr<nsCaret> mCaret;
3829 nsRect mBounds;
3830 };
3831
3832 /**
3833 * The standard display item to paint the CSS borders of a frame.
3834 */
3835 class nsDisplayBorder : public nsPaintedDisplayItem {
3836 public:
3837 nsDisplayBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
3838
3839 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBorder)
3840
3841 NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER)
3842
3843 bool IsInvisibleInRect(const nsRect& aRect) const override;
3844 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
3845 bool CreateWebRenderCommands(
3846 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
3847 const StackingContextHelper& aSc,
3848 layers::RenderRootStateManager* aManager,
3849 nsDisplayListBuilder* aDisplayListBuilder) override;
3850 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
3851 nsDisplayItemGeometry* AllocateGeometry(
3852 nsDisplayListBuilder* aBuilder) override;
3853 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
3854 const nsDisplayItemGeometry* aGeometry,
3855 nsRegion* aInvalidRegion) const override;
3856
GetTightBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)3857 nsRegion GetTightBounds(nsDisplayListBuilder* aBuilder,
3858 bool* aSnap) const override {
3859 *aSnap = true;
3860 return CalculateBounds<nsRegion>(*mFrame->StyleBorder());
3861 }
3862
3863 protected:
3864 template <typename T>
CalculateBounds(const nsStyleBorder & aStyleBorder)3865 T CalculateBounds(const nsStyleBorder& aStyleBorder) const {
3866 nsRect borderBounds(ToReferenceFrame(), mFrame->GetSize());
3867 if (aStyleBorder.IsBorderImageSizeAvailable()) {
3868 borderBounds.Inflate(aStyleBorder.GetImageOutset());
3869 return borderBounds;
3870 }
3871
3872 nsMargin border = aStyleBorder.GetComputedBorder();
3873 T result;
3874 if (border.top > 0) {
3875 result = nsRect(borderBounds.X(), borderBounds.Y(), borderBounds.Width(),
3876 border.top);
3877 }
3878 if (border.right > 0) {
3879 result.OrWith(nsRect(borderBounds.XMost() - border.right,
3880 borderBounds.Y(), border.right,
3881 borderBounds.Height()));
3882 }
3883 if (border.bottom > 0) {
3884 result.OrWith(nsRect(borderBounds.X(),
3885 borderBounds.YMost() - border.bottom,
3886 borderBounds.Width(), border.bottom));
3887 }
3888 if (border.left > 0) {
3889 result.OrWith(nsRect(borderBounds.X(), borderBounds.Y(), border.left,
3890 borderBounds.Height()));
3891 }
3892
3893 nscoord radii[8];
3894 if (mFrame->GetBorderRadii(radii)) {
3895 if (border.left > 0 || border.top > 0) {
3896 nsSize cornerSize(radii[eCornerTopLeftX], radii[eCornerTopLeftY]);
3897 result.OrWith(nsRect(borderBounds.TopLeft(), cornerSize));
3898 }
3899 if (border.top > 0 || border.right > 0) {
3900 nsSize cornerSize(radii[eCornerTopRightX], radii[eCornerTopRightY]);
3901 result.OrWith(
3902 nsRect(borderBounds.TopRight() - nsPoint(cornerSize.width, 0),
3903 cornerSize));
3904 }
3905 if (border.right > 0 || border.bottom > 0) {
3906 nsSize cornerSize(radii[eCornerBottomRightX],
3907 radii[eCornerBottomRightY]);
3908 result.OrWith(nsRect(borderBounds.BottomRight() -
3909 nsPoint(cornerSize.width, cornerSize.height),
3910 cornerSize));
3911 }
3912 if (border.bottom > 0 || border.left > 0) {
3913 nsSize cornerSize(radii[eCornerBottomLeftX], radii[eCornerBottomLeftY]);
3914 result.OrWith(
3915 nsRect(borderBounds.BottomLeft() - nsPoint(0, cornerSize.height),
3916 cornerSize));
3917 }
3918 }
3919 return result;
3920 }
3921
3922 nsRect mBounds;
3923 };
3924
3925 /**
3926 * A simple display item that just renders a solid color across the
3927 * specified bounds. For canvas frames (in the CSS sense) we split off the
3928 * drawing of the background color into this class (from nsDisplayBackground
3929 * via nsDisplayCanvasBackground). This is done so that we can always draw a
3930 * background color to avoid ugly flashes of white when we can't draw a full
3931 * frame tree (ie when a page is loading). The bounds can differ from the
3932 * frame's bounds -- this is needed when a frame/iframe is loading and there
3933 * is not yet a frame tree to go in the frame/iframe so we use the subdoc
3934 * frame of the parent document as a standin.
3935 */
3936 class nsDisplaySolidColorBase : public nsPaintedDisplayItem {
3937 public:
nsDisplaySolidColorBase(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,nscolor aColor)3938 nsDisplaySolidColorBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
3939 nscolor aColor)
3940 : nsPaintedDisplayItem(aBuilder, aFrame), mColor(aColor) {}
3941
AllocateGeometry(nsDisplayListBuilder * aBuilder)3942 nsDisplayItemGeometry* AllocateGeometry(
3943 nsDisplayListBuilder* aBuilder) override {
3944 return new nsDisplaySolidColorGeometry(this, aBuilder, mColor);
3945 }
3946
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion)3947 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
3948 const nsDisplayItemGeometry* aGeometry,
3949 nsRegion* aInvalidRegion) const override {
3950 const nsDisplaySolidColorGeometry* geometry =
3951 static_cast<const nsDisplaySolidColorGeometry*>(aGeometry);
3952 if (mColor != geometry->mColor) {
3953 bool dummy;
3954 aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &dummy));
3955 return;
3956 }
3957 ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion);
3958 }
3959
GetOpaqueRegion(nsDisplayListBuilder * aBuilder,bool * aSnap)3960 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
3961 bool* aSnap) const override {
3962 *aSnap = false;
3963 nsRegion result;
3964 if (NS_GET_A(mColor) == 255) {
3965 result = GetBounds(aBuilder, aSnap);
3966 }
3967 return result;
3968 }
3969
IsUniform(nsDisplayListBuilder * aBuilder)3970 Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) const override {
3971 return Some(mColor);
3972 }
3973
3974 protected:
3975 nscolor mColor;
3976 };
3977
3978 class nsDisplaySolidColor : public nsDisplaySolidColorBase {
3979 public:
3980 nsDisplaySolidColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
3981 const nsRect& aBounds, nscolor aColor,
3982 bool aCanBeReused = true)
nsDisplaySolidColorBase(aBuilder,aFrame,aColor)3983 : nsDisplaySolidColorBase(aBuilder, aFrame, aColor), mBounds(aBounds) {
3984 NS_ASSERTION(NS_GET_A(aColor) > 0,
3985 "Don't create invisible nsDisplaySolidColors!");
3986 MOZ_COUNT_CTOR(nsDisplaySolidColor);
3987 if (!aCanBeReused) {
3988 SetCantBeReused();
3989 }
3990 }
3991
3992 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplaySolidColor)
3993
3994 NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR)
3995
3996 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
3997 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
3998 void WriteDebugInfo(std::stringstream& aStream) override;
3999 bool CreateWebRenderCommands(
4000 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
4001 const StackingContextHelper& aSc,
4002 layers::RenderRootStateManager* aManager,
4003 nsDisplayListBuilder* aDisplayListBuilder) override;
4004
ZIndex()4005 int32_t ZIndex() const override {
4006 if (mOverrideZIndex) {
4007 return mOverrideZIndex.value();
4008 }
4009 return nsDisplaySolidColorBase::ZIndex();
4010 }
4011
SetOverrideZIndex(int32_t aZIndex)4012 void SetOverrideZIndex(int32_t aZIndex) { mOverrideZIndex = Some(aZIndex); }
4013
4014 private:
4015 nsRect mBounds;
4016 Maybe<int32_t> mOverrideZIndex;
4017 };
4018
4019 /**
4020 * A display item that renders a solid color over a region. This is not
4021 * exposed through CSS, its only purpose is efficient invalidation of
4022 * the find bar highlighter dimmer.
4023 */
4024 class nsDisplaySolidColorRegion : public nsPaintedDisplayItem {
4025 public:
nsDisplaySolidColorRegion(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,const nsRegion & aRegion,nscolor aColor)4026 nsDisplaySolidColorRegion(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
4027 const nsRegion& aRegion, nscolor aColor)
4028 : nsPaintedDisplayItem(aBuilder, aFrame),
4029 mRegion(aRegion),
4030 mColor(gfx::sRGBColor::FromABGR(aColor)) {
4031 NS_ASSERTION(NS_GET_A(aColor) > 0,
4032 "Don't create invisible nsDisplaySolidColorRegions!");
4033 MOZ_COUNT_CTOR(nsDisplaySolidColorRegion);
4034 }
4035
4036 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplaySolidColorRegion)
4037
4038 NS_DISPLAY_DECL_NAME("SolidColorRegion", TYPE_SOLID_COLOR_REGION)
4039
AllocateGeometry(nsDisplayListBuilder * aBuilder)4040 nsDisplayItemGeometry* AllocateGeometry(
4041 nsDisplayListBuilder* aBuilder) override {
4042 return new nsDisplaySolidColorRegionGeometry(this, aBuilder, mRegion,
4043 mColor);
4044 }
4045
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion)4046 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
4047 const nsDisplayItemGeometry* aGeometry,
4048 nsRegion* aInvalidRegion) const override {
4049 const nsDisplaySolidColorRegionGeometry* geometry =
4050 static_cast<const nsDisplaySolidColorRegionGeometry*>(aGeometry);
4051 if (mColor == geometry->mColor) {
4052 aInvalidRegion->Xor(geometry->mRegion, mRegion);
4053 } else {
4054 aInvalidRegion->Or(geometry->mRegion.GetBounds(), mRegion.GetBounds());
4055 }
4056 }
4057
4058 bool CreateWebRenderCommands(
4059 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
4060 const StackingContextHelper& aSc,
4061 layers::RenderRootStateManager* aManager,
4062 nsDisplayListBuilder* aDisplayListBuilder) override;
4063
4064 protected:
4065 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
4066 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
4067 void WriteDebugInfo(std::stringstream& aStream) override;
4068
4069 private:
4070 nsRegion mRegion;
4071 gfx::sRGBColor mColor;
4072 };
4073
4074 enum class AppendedBackgroundType : uint8_t {
4075 None,
4076 Background,
4077 ThemedBackground,
4078 };
4079
4080 /**
4081 * A display item to paint one background-image for a frame. Each background
4082 * image layer gets its own nsDisplayBackgroundImage.
4083 */
4084 class nsDisplayBackgroundImage : public nsPaintedDisplayItem {
4085 public:
4086 struct InitData {
4087 nsDisplayListBuilder* builder;
4088 ComputedStyle* backgroundStyle;
4089 nsCOMPtr<imgIContainer> image;
4090 nsRect backgroundRect;
4091 nsRect fillArea;
4092 nsRect destArea;
4093 uint32_t layer;
4094 bool isRasterImage;
4095 bool shouldFixToViewport;
4096 };
4097
4098 /**
4099 * aLayer signifies which background layer this item represents.
4100 * aIsThemed should be the value of aFrame->IsThemed.
4101 * aBackgroundStyle should be the result of
4102 * nsCSSRendering::FindBackground, or null if FindBackground returned false.
4103 * aBackgroundRect is relative to aFrame.
4104 */
4105 static InitData GetInitData(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
4106 uint16_t aLayer, const nsRect& aBackgroundRect,
4107 ComputedStyle* aBackgroundStyle);
4108
4109 explicit nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilder,
4110 nsIFrame* aFrame, const InitData& aInitData,
4111 nsIFrame* aFrameForBounds = nullptr);
4112 ~nsDisplayBackgroundImage() override;
4113
4114 NS_DISPLAY_DECL_NAME("Background", TYPE_BACKGROUND)
4115
4116 /**
4117 * This will create and append new items for all the layers of the
4118 * background. Returns the type of background that was appended.
4119 * aAllowWillPaintBorderOptimization should usually be left at true, unless
4120 * aFrame has special border drawing that causes opaque borders to not
4121 * actually be opaque.
4122 */
4123 static AppendedBackgroundType AppendBackgroundItemsToTop(
4124 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
4125 const nsRect& aBackgroundRect, nsDisplayList* aList,
4126 bool aAllowWillPaintBorderOptimization = true,
4127 ComputedStyle* aComputedStyle = nullptr,
4128 const nsRect& aBackgroundOriginRect = nsRect(),
4129 nsIFrame* aSecondaryReferenceFrame = nullptr,
4130 Maybe<nsDisplayListBuilder::AutoBuildingDisplayList>*
4131 aAutoBuildingDisplayList = nullptr);
4132
4133 bool CreateWebRenderCommands(
4134 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
4135 const StackingContextHelper& aSc,
4136 layers::RenderRootStateManager* aManager,
4137 nsDisplayListBuilder* aDisplayListBuilder) override;
4138 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
4139 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
4140 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
4141 bool* aSnap) const override;
4142 Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) const override;
4143
4144 bool CanApplyOpacity(WebRenderLayerManager* aManager,
4145 nsDisplayListBuilder* aBuilder) const override;
4146
4147 /**
4148 * GetBounds() returns the background painting area.
4149 */
4150 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
4151
4152 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
4153
4154 /**
4155 * Return the background positioning area.
4156 * (GetBounds() returns the background painting area.)
4157 * Can be called only when mBackgroundStyle is non-null.
4158 */
4159 nsRect GetPositioningArea() const;
4160
4161 /**
4162 * Returns true if existing rendered pixels of this display item may need
4163 * to be redrawn if the positioning area size changes but its position does
4164 * not.
4165 * If false, only the changed painting area needs to be redrawn when the
4166 * positioning area size changes but its position does not.
4167 */
4168 bool RenderingMightDependOnPositioningAreaSizeChange() const;
4169
AllocateGeometry(nsDisplayListBuilder * aBuilder)4170 nsDisplayItemGeometry* AllocateGeometry(
4171 nsDisplayListBuilder* aBuilder) override {
4172 return new nsDisplayBackgroundGeometry(this, aBuilder);
4173 }
4174
4175 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
4176 const nsDisplayItemGeometry* aGeometry,
4177 nsRegion* aInvalidRegion) const override;
ShouldFixToViewport(nsDisplayListBuilder * aBuilder)4178 bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) const override {
4179 return mShouldFixToViewport;
4180 }
4181
GetDestRect()4182 nsRect GetDestRect() const { return mDestRect; }
4183
GetDependentFrame()4184 nsIFrame* GetDependentFrame() override { return mDependentFrame; }
4185
SetDependentFrame(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame)4186 void SetDependentFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
4187 if (!aBuilder->IsRetainingDisplayList() || mDependentFrame == aFrame) {
4188 return;
4189 }
4190 mDependentFrame = aFrame;
4191 if (aFrame) {
4192 mDependentFrame->AddDisplayItem(this);
4193 }
4194 }
4195
RemoveFrame(nsIFrame * aFrame)4196 void RemoveFrame(nsIFrame* aFrame) override {
4197 if (aFrame == mDependentFrame) {
4198 mDependentFrame = nullptr;
4199 }
4200 nsPaintedDisplayItem::RemoveFrame(aFrame);
4201 }
4202
4203 // Match https://w3c.github.io/paint-timing/#contentful-image
IsContentful()4204 bool IsContentful() const override {
4205 const auto& styleImage =
4206 mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer].mImage;
4207
4208 return styleImage.IsSizeAvailable() && styleImage.FinalImage().IsUrl();
4209 }
4210
4211 protected:
4212 bool CanBuildWebRenderDisplayItems(layers::WebRenderLayerManager* aManager,
4213 nsDisplayListBuilder* aBuilder) const;
4214 nsRect GetBoundsInternal(nsDisplayListBuilder* aBuilder,
4215 nsIFrame* aFrameForBounds = nullptr);
4216
4217 void PaintInternal(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
4218 const nsRect& aBounds, nsRect* aClipRect);
4219
4220 // Cache the result of nsCSSRendering::FindBackground. Always null if
4221 // mIsThemed is true or if FindBackground returned false.
4222 RefPtr<ComputedStyle> mBackgroundStyle;
4223 nsCOMPtr<imgIContainer> mImage;
4224 nsIFrame* mDependentFrame;
4225 nsRect mBackgroundRect; // relative to the reference frame
4226 nsRect mFillRect;
4227 nsRect mDestRect;
4228 /* Bounds of this display item */
4229 nsRect mBounds;
4230 uint16_t mLayer;
4231 bool mIsRasterImage;
4232 /* Whether the image should be treated as fixed to the viewport. */
4233 bool mShouldFixToViewport;
4234 };
4235
4236 /**
4237 * A display item to paint background image for table. For table parts, such
4238 * as row, row group, col, col group, when drawing its background, we'll
4239 * create separate background image display item for its containning cell.
4240 * Those background image display items will reference to same DisplayItemData
4241 * if we keep the mFrame point to cell's ancestor frame. We don't want to this
4242 * happened bacause share same DisplatItemData will cause many bugs. So that
4243 * we let mFrame point to cell frame and store the table type of the ancestor
4244 * frame. And use mFrame and table type as key to generate DisplayItemData to
4245 * avoid sharing DisplayItemData.
4246 *
4247 * Also store ancestor frame as mStyleFrame for all rendering informations.
4248 */
4249 class nsDisplayTableBackgroundImage : public nsDisplayBackgroundImage {
4250 public:
4251 nsDisplayTableBackgroundImage(nsDisplayListBuilder* aBuilder,
4252 nsIFrame* aFrame, const InitData& aData,
4253 nsIFrame* aCellFrame);
4254 ~nsDisplayTableBackgroundImage() override;
4255
4256 NS_DISPLAY_DECL_NAME("TableBackgroundImage", TYPE_TABLE_BACKGROUND_IMAGE)
4257
4258 bool IsInvalid(nsRect& aRect) const override;
4259
FrameForInvalidation()4260 nsIFrame* FrameForInvalidation() const override { return mStyleFrame; }
4261
RemoveFrame(nsIFrame * aFrame)4262 void RemoveFrame(nsIFrame* aFrame) override {
4263 if (aFrame == mStyleFrame) {
4264 mStyleFrame = nullptr;
4265 SetDeletedFrame();
4266 }
4267 nsDisplayBackgroundImage::RemoveFrame(aFrame);
4268 }
4269
4270 protected:
StyleFrame()4271 nsIFrame* StyleFrame() const override { return mStyleFrame; }
4272 nsIFrame* mStyleFrame;
4273 };
4274
4275 /**
4276 * A display item to paint the native theme background for a frame.
4277 */
4278 class nsDisplayThemedBackground : public nsPaintedDisplayItem {
4279 public:
4280 nsDisplayThemedBackground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
4281 const nsRect& aBackgroundRect);
4282
4283 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayThemedBackground)
4284
4285 NS_DISPLAY_DECL_NAME("ThemedBackground", TYPE_THEMED_BACKGROUND)
4286
4287 void Init(nsDisplayListBuilder* aBuilder);
4288
Destroy(nsDisplayListBuilder * aBuilder)4289 void Destroy(nsDisplayListBuilder* aBuilder) override {
4290 aBuilder->UnregisterThemeGeometry(this);
4291 nsPaintedDisplayItem::Destroy(aBuilder);
4292 }
4293
4294 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
4295 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
4296 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
4297 bool* aSnap) const override;
4298 Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) const override;
4299 bool CreateWebRenderCommands(
4300 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
4301 const StackingContextHelper& aSc,
4302 layers::RenderRootStateManager* aManager,
4303 nsDisplayListBuilder* aDisplayListBuilder) override;
4304
MustPaintOnContentSide()4305 bool MustPaintOnContentSide() const override { return true; }
4306
4307 /**
4308 * GetBounds() returns the background painting area.
4309 */
4310 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
4311
4312 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
4313
4314 /**
4315 * Return the background positioning area.
4316 * (GetBounds() returns the background painting area.)
4317 * Can be called only when mBackgroundStyle is non-null.
4318 */
4319 nsRect GetPositioningArea() const;
4320
4321 /**
4322 * Return whether our frame's document does not have the state
4323 * NS_DOCUMENT_STATE_WINDOW_INACTIVE.
4324 */
4325 bool IsWindowActive() const;
4326
AllocateGeometry(nsDisplayListBuilder * aBuilder)4327 nsDisplayItemGeometry* AllocateGeometry(
4328 nsDisplayListBuilder* aBuilder) override {
4329 return new nsDisplayThemedBackgroundGeometry(this, aBuilder);
4330 }
4331
4332 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
4333 const nsDisplayItemGeometry* aGeometry,
4334 nsRegion* aInvalidRegion) const override;
4335
4336 void WriteDebugInfo(std::stringstream& aStream) override;
4337
4338 protected:
4339 nsRect GetBoundsInternal();
4340
4341 void PaintInternal(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
4342 const nsRect& aBounds, nsRect* aClipRect);
4343
4344 nsRect mBackgroundRect;
4345 nsRect mBounds;
4346 nsITheme::Transparency mThemeTransparency;
4347 StyleAppearance mAppearance;
4348 };
4349
4350 class nsDisplayTableThemedBackground : public nsDisplayThemedBackground {
4351 public:
nsDisplayTableThemedBackground(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,const nsRect & aBackgroundRect,nsIFrame * aAncestorFrame)4352 nsDisplayTableThemedBackground(nsDisplayListBuilder* aBuilder,
4353 nsIFrame* aFrame,
4354 const nsRect& aBackgroundRect,
4355 nsIFrame* aAncestorFrame)
4356 : nsDisplayThemedBackground(aBuilder, aFrame, aBackgroundRect),
4357 mAncestorFrame(aAncestorFrame) {
4358 if (aBuilder->IsRetainingDisplayList()) {
4359 mAncestorFrame->AddDisplayItem(this);
4360 }
4361 }
4362
~nsDisplayTableThemedBackground()4363 ~nsDisplayTableThemedBackground() override {
4364 if (mAncestorFrame) {
4365 mAncestorFrame->RemoveDisplayItem(this);
4366 }
4367 }
4368
4369 NS_DISPLAY_DECL_NAME("TableThemedBackground",
4370 TYPE_TABLE_THEMED_BACKGROUND_IMAGE)
4371
FrameForInvalidation()4372 nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
4373
RemoveFrame(nsIFrame * aFrame)4374 void RemoveFrame(nsIFrame* aFrame) override {
4375 if (aFrame == mAncestorFrame) {
4376 mAncestorFrame = nullptr;
4377 SetDeletedFrame();
4378 }
4379 nsDisplayThemedBackground::RemoveFrame(aFrame);
4380 }
4381
4382 protected:
StyleFrame()4383 nsIFrame* StyleFrame() const override { return mAncestorFrame; }
4384 nsIFrame* mAncestorFrame;
4385 };
4386
4387 class nsDisplayBackgroundColor : public nsPaintedDisplayItem {
4388 public:
nsDisplayBackgroundColor(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,const nsRect & aBackgroundRect,const ComputedStyle * aBackgroundStyle,const nscolor & aColor)4389 nsDisplayBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
4390 const nsRect& aBackgroundRect,
4391 const ComputedStyle* aBackgroundStyle,
4392 const nscolor& aColor)
4393 : nsPaintedDisplayItem(aBuilder, aFrame),
4394 mBackgroundRect(aBackgroundRect),
4395 mHasStyle(aBackgroundStyle),
4396 mDependentFrame(nullptr),
4397 mColor(gfx::sRGBColor::FromABGR(aColor)) {
4398 if (mHasStyle) {
4399 mBottomLayerClip =
4400 aBackgroundStyle->StyleBackground()->BottomLayer().mClip;
4401 } else {
4402 MOZ_ASSERT(aBuilder->IsForEventDelivery());
4403 }
4404 }
4405
~nsDisplayBackgroundColor()4406 ~nsDisplayBackgroundColor() override {
4407 if (mDependentFrame) {
4408 mDependentFrame->RemoveDisplayItem(this);
4409 }
4410 }
4411
4412 NS_DISPLAY_DECL_NAME("BackgroundColor", TYPE_BACKGROUND_COLOR)
4413
HasBackgroundClipText()4414 bool HasBackgroundClipText() const {
4415 MOZ_ASSERT(mHasStyle);
4416 return mBottomLayerClip == StyleGeometryBox::Text;
4417 }
4418
4419 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
4420 void PaintWithClip(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
4421 const DisplayItemClip& aClip) override;
4422 bool CreateWebRenderCommands(
4423 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
4424 const StackingContextHelper& aSc,
4425 layers::RenderRootStateManager* aManager,
4426 nsDisplayListBuilder* aDisplayListBuilder) override;
4427 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
4428 bool* aSnap) const override;
4429 Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) const override;
4430 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
4431 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
4432 bool CanApplyOpacity(WebRenderLayerManager* aManager,
4433 nsDisplayListBuilder* aBuilder) const override;
4434
GetOpacity()4435 float GetOpacity() const { return mColor.a; }
4436
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)4437 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override {
4438 *aSnap = true;
4439 return mBackgroundRect;
4440 }
4441
CanPaintWithClip(const DisplayItemClip & aClip)4442 bool CanPaintWithClip(const DisplayItemClip& aClip) override {
4443 if (HasBackgroundClipText()) {
4444 return false;
4445 }
4446
4447 if (aClip.GetRoundedRectCount() > 1) {
4448 return false;
4449 }
4450
4451 return true;
4452 }
4453
AllocateGeometry(nsDisplayListBuilder * aBuilder)4454 nsDisplayItemGeometry* AllocateGeometry(
4455 nsDisplayListBuilder* aBuilder) override {
4456 return new nsDisplaySolidColorGeometry(this, aBuilder, mColor.ToABGR());
4457 }
4458
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion)4459 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
4460 const nsDisplayItemGeometry* aGeometry,
4461 nsRegion* aInvalidRegion) const override {
4462 const nsDisplaySolidColorGeometry* geometry =
4463 static_cast<const nsDisplaySolidColorGeometry*>(aGeometry);
4464
4465 if (mColor.ToABGR() != geometry->mColor) {
4466 bool dummy;
4467 aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &dummy));
4468 return;
4469 }
4470 ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion);
4471 }
4472
GetDependentFrame()4473 nsIFrame* GetDependentFrame() override { return mDependentFrame; }
4474
SetDependentFrame(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame)4475 void SetDependentFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
4476 if (!aBuilder->IsRetainingDisplayList() || mDependentFrame == aFrame) {
4477 return;
4478 }
4479 mDependentFrame = aFrame;
4480 if (aFrame) {
4481 mDependentFrame->AddDisplayItem(this);
4482 }
4483 }
4484
RemoveFrame(nsIFrame * aFrame)4485 void RemoveFrame(nsIFrame* aFrame) override {
4486 if (aFrame == mDependentFrame) {
4487 mDependentFrame = nullptr;
4488 }
4489
4490 nsPaintedDisplayItem::RemoveFrame(aFrame);
4491 }
4492
4493 void WriteDebugInfo(std::stringstream& aStream) override;
4494
4495 bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override;
4496
4497 protected:
4498 const nsRect mBackgroundRect;
4499 const bool mHasStyle;
4500 StyleGeometryBox mBottomLayerClip;
4501 nsIFrame* mDependentFrame;
4502 gfx::sRGBColor mColor;
4503 };
4504
4505 class nsDisplayTableBackgroundColor : public nsDisplayBackgroundColor {
4506 public:
nsDisplayTableBackgroundColor(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,const nsRect & aBackgroundRect,const ComputedStyle * aBackgroundStyle,const nscolor & aColor,nsIFrame * aAncestorFrame)4507 nsDisplayTableBackgroundColor(nsDisplayListBuilder* aBuilder,
4508 nsIFrame* aFrame, const nsRect& aBackgroundRect,
4509 const ComputedStyle* aBackgroundStyle,
4510 const nscolor& aColor, nsIFrame* aAncestorFrame)
4511 : nsDisplayBackgroundColor(aBuilder, aFrame, aBackgroundRect,
4512 aBackgroundStyle, aColor),
4513 mAncestorFrame(aAncestorFrame) {
4514 if (aBuilder->IsRetainingDisplayList()) {
4515 mAncestorFrame->AddDisplayItem(this);
4516 }
4517 }
4518
~nsDisplayTableBackgroundColor()4519 ~nsDisplayTableBackgroundColor() override {
4520 if (mAncestorFrame) {
4521 mAncestorFrame->RemoveDisplayItem(this);
4522 }
4523 }
4524
4525 NS_DISPLAY_DECL_NAME("TableBackgroundColor", TYPE_TABLE_BACKGROUND_COLOR)
4526
FrameForInvalidation()4527 nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
4528
RemoveFrame(nsIFrame * aFrame)4529 void RemoveFrame(nsIFrame* aFrame) override {
4530 if (aFrame == mAncestorFrame) {
4531 mAncestorFrame = nullptr;
4532 SetDeletedFrame();
4533 }
4534 nsDisplayBackgroundColor::RemoveFrame(aFrame);
4535 }
4536
CanUseAsyncAnimations(nsDisplayListBuilder * aBuilder)4537 bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override {
4538 return false;
4539 }
4540
4541 protected:
4542 nsIFrame* mAncestorFrame;
4543 };
4544
4545 /**
4546 * The standard display item to paint the outer CSS box-shadows of a frame.
4547 */
4548 class nsDisplayBoxShadowOuter final : public nsPaintedDisplayItem {
4549 public:
nsDisplayBoxShadowOuter(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame)4550 nsDisplayBoxShadowOuter(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
4551 : nsPaintedDisplayItem(aBuilder, aFrame) {
4552 MOZ_COUNT_CTOR(nsDisplayBoxShadowOuter);
4553 mBounds = GetBoundsInternal();
4554 }
4555
4556 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBoxShadowOuter)
4557
4558 NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER)
4559
4560 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
4561 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
4562 bool IsInvisibleInRect(const nsRect& aRect) const override;
4563 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
4564 const nsDisplayItemGeometry* aGeometry,
4565 nsRegion* aInvalidRegion) const override;
4566
CanApplyOpacity(WebRenderLayerManager * aManager,nsDisplayListBuilder * aBuilder)4567 bool CanApplyOpacity(WebRenderLayerManager* aManager,
4568 nsDisplayListBuilder* aBuilder) const override {
4569 return CanBuildWebRenderDisplayItems();
4570 }
4571
4572 bool CanBuildWebRenderDisplayItems() const;
4573 bool CreateWebRenderCommands(
4574 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
4575 const StackingContextHelper& aSc,
4576 layers::RenderRootStateManager* aManager,
4577 nsDisplayListBuilder* aDisplayListBuilder) override;
4578 nsRect GetBoundsInternal();
4579
4580 private:
4581 nsRect mBounds;
4582 };
4583
4584 /**
4585 * The standard display item to paint the inner CSS box-shadows of a frame.
4586 */
4587 class nsDisplayBoxShadowInner : public nsPaintedDisplayItem {
4588 public:
nsDisplayBoxShadowInner(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame)4589 nsDisplayBoxShadowInner(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
4590 : nsPaintedDisplayItem(aBuilder, aFrame) {
4591 MOZ_COUNT_CTOR(nsDisplayBoxShadowInner);
4592 }
4593
4594 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBoxShadowInner)
4595
4596 NS_DISPLAY_DECL_NAME("BoxShadowInner", TYPE_BOX_SHADOW_INNER)
4597
4598 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
4599
AllocateGeometry(nsDisplayListBuilder * aBuilder)4600 nsDisplayItemGeometry* AllocateGeometry(
4601 nsDisplayListBuilder* aBuilder) override {
4602 return new nsDisplayBoxShadowInnerGeometry(this, aBuilder);
4603 }
4604
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion)4605 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
4606 const nsDisplayItemGeometry* aGeometry,
4607 nsRegion* aInvalidRegion) const override {
4608 const nsDisplayBoxShadowInnerGeometry* geometry =
4609 static_cast<const nsDisplayBoxShadowInnerGeometry*>(aGeometry);
4610 if (!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect())) {
4611 // nsDisplayBoxShadowInner is based around the padding rect, but it can
4612 // touch pixels outside of this. We should invalidate the entire bounds.
4613 bool snap;
4614 aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap));
4615 }
4616 }
4617
4618 static bool CanCreateWebRenderCommands(nsDisplayListBuilder* aBuilder,
4619 nsIFrame* aFrame,
4620 const nsPoint& aReferenceOffset);
4621 static void CreateInsetBoxShadowWebRenderCommands(
4622 wr::DisplayListBuilder& aBuilder, const StackingContextHelper& aSc,
4623 nsRect& aVisibleRect, nsIFrame* aFrame, const nsRect& aBorderRect);
4624 bool CreateWebRenderCommands(
4625 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
4626 const StackingContextHelper& aSc,
4627 layers::RenderRootStateManager* aManager,
4628 nsDisplayListBuilder* aDisplayListBuilder) override;
4629 };
4630
4631 /**
4632 * The standard display item to paint the CSS outline of a frame.
4633 */
4634 class nsDisplayOutline final : public nsPaintedDisplayItem {
4635 public:
nsDisplayOutline(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame)4636 nsDisplayOutline(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
4637 : nsPaintedDisplayItem(aBuilder, aFrame) {
4638 MOZ_COUNT_CTOR(nsDisplayOutline);
4639 }
4640
4641 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayOutline)
4642
4643 NS_DISPLAY_DECL_NAME("Outline", TYPE_OUTLINE)
4644
MustPaintOnContentSide()4645 bool MustPaintOnContentSide() const override {
4646 MOZ_ASSERT(IsThemedOutline(),
4647 "The only fallback path we have is for themed outlines");
4648 return true;
4649 }
4650
4651 bool CreateWebRenderCommands(
4652 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
4653 const StackingContextHelper& aSc,
4654 layers::RenderRootStateManager* aManager,
4655 nsDisplayListBuilder* aDisplayListBuilder) override;
4656 bool IsInvisibleInRect(const nsRect& aRect) const override;
4657 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
4658 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
4659
4660 private:
4661 nsRect GetInnerRect() const;
4662 bool IsThemedOutline() const;
4663 bool HasRadius() const;
4664 };
4665
4666 /**
4667 * A class that lets you receive events within the frame bounds but never
4668 * paints.
4669 */
4670 class nsDisplayEventReceiver final : public nsDisplayItem {
4671 public:
nsDisplayEventReceiver(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame)4672 nsDisplayEventReceiver(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
4673 : nsDisplayItem(aBuilder, aFrame) {
4674 MOZ_COUNT_CTOR(nsDisplayEventReceiver);
4675 }
4676
4677 MOZ_COUNTED_DTOR_FINAL(nsDisplayEventReceiver)
4678
4679 NS_DISPLAY_DECL_NAME("EventReceiver", TYPE_EVENT_RECEIVER)
4680
4681 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
4682 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) final;
4683 };
4684
4685 /**
4686 * Similar to nsDisplayEventReceiver in that it is used for hit-testing. However
4687 * this gets built when we're doing widget painting and we need to send the
4688 * compositor some hit-test info for a frame. This is effectively a dummy item
4689 * whose sole purpose is to carry the hit-test info to the compositor.
4690 */
4691 class nsDisplayCompositorHitTestInfo final : public nsDisplayItem {
4692 public:
nsDisplayCompositorHitTestInfo(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame)4693 nsDisplayCompositorHitTestInfo(nsDisplayListBuilder* aBuilder,
4694 nsIFrame* aFrame)
4695 : nsDisplayItem(aBuilder, aFrame) {
4696 MOZ_COUNT_CTOR(nsDisplayCompositorHitTestInfo);
4697 mHitTestInfo.Initialize(aBuilder, aFrame);
4698 SetHasHitTestInfo();
4699 }
4700
nsDisplayCompositorHitTestInfo(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,const nsRect & aArea,const gfx::CompositorHitTestInfo & aHitTestFlags)4701 nsDisplayCompositorHitTestInfo(
4702 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, const nsRect& aArea,
4703 const gfx::CompositorHitTestInfo& aHitTestFlags)
4704 : nsDisplayItem(aBuilder, aFrame) {
4705 MOZ_COUNT_CTOR(nsDisplayCompositorHitTestInfo);
4706 mHitTestInfo.SetAreaAndInfo(aArea, aHitTestFlags);
4707 mHitTestInfo.InitializeScrollTarget(aBuilder);
4708 SetHasHitTestInfo();
4709 }
4710
4711 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayCompositorHitTestInfo)
4712
4713 NS_DISPLAY_DECL_NAME("CompositorHitTestInfo", TYPE_COMPOSITOR_HITTEST_INFO)
4714
4715 bool CreateWebRenderCommands(
4716 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
4717 const StackingContextHelper& aSc,
4718 layers::RenderRootStateManager* aManager,
4719 nsDisplayListBuilder* aDisplayListBuilder) override;
4720
isInvisible()4721 bool isInvisible() const { return true; }
4722
4723 int32_t ZIndex() const override;
4724 void SetOverrideZIndex(int32_t aZIndex);
4725
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)4726 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override {
4727 *aSnap = false;
4728 return nsRect();
4729 }
4730
GetHitTestInfo()4731 const HitTestInfo& GetHitTestInfo() final { return mHitTestInfo; }
4732
4733 private:
4734 HitTestInfo mHitTestInfo;
4735 Maybe<int32_t> mOverrideZIndex;
4736 };
4737
4738 class nsDisplayWrapper;
4739
4740 /**
4741 * A class that lets you wrap a display list as a display item.
4742 *
4743 * GetUnderlyingFrame() is troublesome for wrapped lists because if the wrapped
4744 * list has many items, it's not clear which one has the 'underlying frame'.
4745 * Thus we force the creator to specify what the underlying frame is. The
4746 * underlying frame should be the root of a stacking context, because sorting
4747 * a list containing this item will not get at the children.
4748 *
4749 * In some cases (e.g., clipping) we want to wrap a list but we don't have a
4750 * particular underlying frame that is a stacking context root. In that case
4751 * we allow the frame to be nullptr. Callers to GetUnderlyingFrame must
4752 * detect and handle this case.
4753 */
4754 class nsDisplayWrapList : public nsPaintedDisplayItem {
4755 public:
4756 /**
4757 * Takes all the items from aList and puts them in our list.
4758 */
4759 nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
4760 nsDisplayList* aList);
4761
4762 nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
4763 nsDisplayItem* aItem);
4764
4765 nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
4766 nsDisplayList* aList,
4767 const ActiveScrolledRoot* aActiveScrolledRoot,
4768 bool aClearClipChain = false);
4769
nsDisplayWrapList(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame)4770 nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
4771 : nsPaintedDisplayItem(aBuilder, aFrame),
4772 mList(aBuilder),
4773 mFrameActiveScrolledRoot(aBuilder->CurrentActiveScrolledRoot()),
4774 mOverrideZIndex(0),
4775 mHasZIndexOverride(false) {
4776 MOZ_COUNT_CTOR(nsDisplayWrapList);
4777 mBaseBuildingRect = GetBuildingRect();
4778 mListPtr = &mList;
4779 mOriginalClipChain = mClipChain;
4780 }
4781
4782 nsDisplayWrapList() = delete;
4783
4784 /**
4785 * A custom copy-constructor that does not copy mList, as this would mutate
4786 * the other item.
4787 */
4788 nsDisplayWrapList(const nsDisplayWrapList& aOther) = delete;
nsDisplayWrapList(nsDisplayListBuilder * aBuilder,const nsDisplayWrapList & aOther)4789 nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
4790 const nsDisplayWrapList& aOther)
4791 : nsPaintedDisplayItem(aBuilder, aOther),
4792 mList(aBuilder),
4793 mListPtr(&mList),
4794 mFrameActiveScrolledRoot(aOther.mFrameActiveScrolledRoot),
4795 mMergedFrames(aOther.mMergedFrames.Clone()),
4796 mBounds(aOther.mBounds),
4797 mBaseBuildingRect(aOther.mBaseBuildingRect),
4798 mOriginalClipChain(aOther.mClipChain),
4799 mOverrideZIndex(aOther.mOverrideZIndex),
4800 mHasZIndexOverride(aOther.mHasZIndexOverride),
4801 mClearingClipChain(aOther.mClearingClipChain) {
4802 MOZ_COUNT_CTOR(nsDisplayWrapList);
4803 }
4804
4805 ~nsDisplayWrapList() override;
4806
AsDisplayWrapList()4807 const nsDisplayWrapList* AsDisplayWrapList() const final { return this; }
AsDisplayWrapList()4808 nsDisplayWrapList* AsDisplayWrapList() final { return this; }
4809
Destroy(nsDisplayListBuilder * aBuilder)4810 void Destroy(nsDisplayListBuilder* aBuilder) override {
4811 mList.DeleteAll(aBuilder);
4812 nsPaintedDisplayItem::Destroy(aBuilder);
4813 }
4814
4815 /**
4816 * Creates a new nsDisplayWrapper that holds a pointer to the display list
4817 * owned by the given nsDisplayItem.
4818 */
4819 nsDisplayWrapper* CreateShallowCopy(nsDisplayListBuilder* aBuilder);
4820
4821 /**
4822 * Call this if the wrapped list is changed.
4823 */
UpdateBounds(nsDisplayListBuilder * aBuilder)4824 void UpdateBounds(nsDisplayListBuilder* aBuilder) override {
4825 // Clear the clip chain up to the asr, but don't store it, so that we'll
4826 // recover it when we reuse the item.
4827 if (mClearingClipChain) {
4828 const DisplayItemClipChain* clip = mOriginalClipChain;
4829 while (clip && ActiveScrolledRoot::IsAncestor(GetActiveScrolledRoot(),
4830 clip->mASR)) {
4831 clip = clip->mParent;
4832 }
4833 SetClipChain(clip, false);
4834 }
4835
4836 nsRect buildingRect;
4837 mBounds = mListPtr->GetClippedBoundsWithRespectToASR(
4838 aBuilder, mActiveScrolledRoot, &buildingRect);
4839 // The display list may contain content that's visible outside the visible
4840 // rect (i.e. the current dirty rect) passed in when the item was created.
4841 // This happens when the dirty rect has been restricted to the visual
4842 // overflow rect of a frame for some reason (e.g. when setting up dirty
4843 // rects in nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay), but that
4844 // frame contains placeholders for out-of-flows that aren't descendants of
4845 // the frame.
4846 buildingRect.UnionRect(mBaseBuildingRect, buildingRect);
4847 SetBuildingRect(buildingRect);
4848 }
4849
SetClipChain(const DisplayItemClipChain * aClipChain,bool aStore)4850 void SetClipChain(const DisplayItemClipChain* aClipChain,
4851 bool aStore) override {
4852 nsDisplayItem::SetClipChain(aClipChain, aStore);
4853
4854 if (aStore) {
4855 mOriginalClipChain = mClipChain;
4856 }
4857 }
4858
4859 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
4860 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
4861 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
4862 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
4863 bool* aSnap) const override;
4864 Maybe<nscolor> IsUniform(nsDisplayListBuilder* aBuilder) const override;
4865
4866 /**
4867 * Try to merge with the other item (which is below us in the display
4868 * list). This gets used by nsDisplayClip to coalesce clipping operations
4869 * (optimization), by nsDisplayOpacity to merge rendering for the same
4870 * content element into a single opacity group (correctness), and will be
4871 * used by nsDisplayOutline to merge multiple outlines for the same element
4872 * (also for correctness).
4873 */
Merge(const nsDisplayItem * aItem)4874 virtual void Merge(const nsDisplayItem* aItem) {
4875 MOZ_ASSERT(CanMerge(aItem));
4876 MOZ_ASSERT(Frame() != aItem->Frame());
4877 MergeFromTrackingMergedFrames(static_cast<const nsDisplayWrapList*>(aItem));
4878 }
4879
4880 /**
4881 * Returns the underlying frames of all display items that have been
4882 * merged into this one (excluding this item's own underlying frame)
4883 * to aFrames.
4884 */
GetMergedFrames()4885 const nsTArray<nsIFrame*>& GetMergedFrames() const { return mMergedFrames; }
4886
HasMergedFrames()4887 bool HasMergedFrames() const { return !mMergedFrames.IsEmpty(); }
4888
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)4889 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
4890 return true;
4891 }
4892
IsInvalid(nsRect & aRect)4893 bool IsInvalid(nsRect& aRect) const override {
4894 if (mFrame->IsInvalid(aRect) && aRect.IsEmpty()) {
4895 return true;
4896 }
4897 nsRect temp;
4898 for (uint32_t i = 0; i < mMergedFrames.Length(); i++) {
4899 if (mMergedFrames[i]->IsInvalid(temp) && temp.IsEmpty()) {
4900 aRect.SetEmpty();
4901 return true;
4902 }
4903 aRect = aRect.Union(temp);
4904 }
4905 aRect += ToReferenceFrame();
4906 return !aRect.IsEmpty();
4907 }
4908
4909 nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override;
4910
GetSameCoordinateSystemChildren()4911 RetainedDisplayList* GetSameCoordinateSystemChildren() const override {
4912 return mListPtr;
4913 }
4914
GetChildren()4915 RetainedDisplayList* GetChildren() const override { return mListPtr; }
4916
ZIndex()4917 int32_t ZIndex() const override {
4918 return (mHasZIndexOverride) ? mOverrideZIndex
4919 : nsPaintedDisplayItem::ZIndex();
4920 }
4921
SetOverrideZIndex(int32_t aZIndex)4922 void SetOverrideZIndex(int32_t aZIndex) {
4923 mHasZIndexOverride = true;
4924 mOverrideZIndex = aZIndex;
4925 }
4926
4927 /**
4928 * This creates a copy of this item, but wrapping aItem instead of
4929 * our existing list. Only gets called if this item returned nullptr
4930 * for GetUnderlyingFrame(). aItem is guaranteed to return non-null from
4931 * GetUnderlyingFrame().
4932 */
WrapWithClone(nsDisplayListBuilder * aBuilder,nsDisplayItem * aItem)4933 nsDisplayWrapList* WrapWithClone(nsDisplayListBuilder* aBuilder,
4934 nsDisplayItem* aItem) {
4935 MOZ_ASSERT_UNREACHABLE("We never returned nullptr for GetUnderlyingFrame!");
4936 return nullptr;
4937 }
4938
CreateWebRenderCommands(wr::DisplayListBuilder & aBuilder,wr::IpcResourceUpdateQueue & aResources,const StackingContextHelper & aSc,layers::RenderRootStateManager * aManager,nsDisplayListBuilder * aDisplayListBuilder)4939 bool CreateWebRenderCommands(
4940 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
4941 const StackingContextHelper& aSc,
4942 layers::RenderRootStateManager* aManager,
4943 nsDisplayListBuilder* aDisplayListBuilder) override {
4944 return CreateWebRenderCommandsNewClipListOption(
4945 aBuilder, aResources, aSc, aManager, aDisplayListBuilder, true);
4946 }
4947
4948 // Same as the above but with the option to pass the aNewClipList argument to
4949 // WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList.
4950 bool CreateWebRenderCommandsNewClipListOption(
4951 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
4952 const StackingContextHelper& aSc,
4953 layers::RenderRootStateManager* aManager,
4954 nsDisplayListBuilder* aDisplayListBuilder, bool aNewClipList);
4955
GetFrameActiveScrolledRoot()4956 const ActiveScrolledRoot* GetFrameActiveScrolledRoot() {
4957 return mFrameActiveScrolledRoot;
4958 }
4959
4960 protected:
MergeFromTrackingMergedFrames(const nsDisplayWrapList * aOther)4961 void MergeFromTrackingMergedFrames(const nsDisplayWrapList* aOther) {
4962 mBounds.UnionRect(mBounds, aOther->mBounds);
4963 nsRect buildingRect;
4964 buildingRect.UnionRect(GetBuildingRect(), aOther->GetBuildingRect());
4965 SetBuildingRect(buildingRect);
4966 mMergedFrames.AppendElement(aOther->mFrame);
4967 mMergedFrames.AppendElements(aOther->mMergedFrames.Clone());
4968 }
4969
4970 RetainedDisplayList mList;
4971 RetainedDisplayList* mListPtr;
4972 // The active scrolled root for the frame that created this
4973 // wrap list.
4974 RefPtr<const ActiveScrolledRoot> mFrameActiveScrolledRoot;
4975 // The frames from items that have been merged into this item, excluding
4976 // this item's own frame.
4977 nsTArray<nsIFrame*> mMergedFrames;
4978 nsRect mBounds;
4979 // Displaylist building rect contributed by this display item itself.
4980 // Our mBuildingRect may include the visible areas of children.
4981 nsRect mBaseBuildingRect;
4982 RefPtr<const DisplayItemClipChain> mOriginalClipChain;
4983 int32_t mOverrideZIndex;
4984 bool mHasZIndexOverride;
4985 bool mClearingClipChain = false;
4986 };
4987
4988 class nsDisplayWrapper : public nsDisplayWrapList {
4989 public:
4990 NS_DISPLAY_DECL_NAME("WrapList", TYPE_WRAP_LIST)
4991
4992 nsDisplayWrapper(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
4993 nsDisplayList* aList,
4994 const ActiveScrolledRoot* aActiveScrolledRoot,
4995 bool aClearClipChain = false)
nsDisplayWrapList(aBuilder,aFrame,aList,aActiveScrolledRoot,aClearClipChain)4996 : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot,
4997 aClearClipChain) {}
4998
4999 nsDisplayWrapper(const nsDisplayWrapper& aOther) = delete;
nsDisplayWrapper(nsDisplayListBuilder * aBuilder,const nsDisplayWrapList & aOther)5000 nsDisplayWrapper(nsDisplayListBuilder* aBuilder,
5001 const nsDisplayWrapList& aOther)
5002 : nsDisplayWrapList(aBuilder, aOther) {}
5003
5004 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
5005
5006 private:
5007 NS_DISPLAY_ALLOW_CLONING()
5008 friend class nsDisplayListBuilder;
5009 friend class nsDisplayWrapList;
5010 };
5011
5012 /**
5013 * We call WrapDisplayList on the in-flow lists: BorderBackground(),
5014 * BlockBorderBackgrounds() and Content().
5015 * We call WrapDisplayItem on each item of Outlines(), PositionedDescendants(),
5016 * and Floats(). This is done to support special wrapping processing for frames
5017 * that may not be in-flow descendants of the current frame.
5018 */
5019 class nsDisplayItemWrapper {
5020 public:
5021 // This is never instantiated directly (it has pure virtual methods), so no
5022 // need to count constructors and destructors.
5023
WrapBorderBackground()5024 bool WrapBorderBackground() { return true; }
5025 virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
5026 nsIFrame* aFrame, nsDisplayList* aList) = 0;
5027 virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
5028 nsDisplayItem* aItem) = 0;
5029
5030 nsresult WrapLists(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5031 const nsDisplayListSet& aIn, const nsDisplayListSet& aOut);
5032 nsresult WrapListsInPlace(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5033 const nsDisplayListSet& aLists);
5034
5035 protected:
5036 nsDisplayItemWrapper() = default;
5037 };
5038
5039 /**
5040 * The standard display item to paint a stacking context with translucency
5041 * set by the stacking context root frame's 'opacity' style.
5042 */
5043 class nsDisplayOpacity : public nsDisplayWrapList {
5044 public:
5045 nsDisplayOpacity(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5046 nsDisplayList* aList,
5047 const ActiveScrolledRoot* aActiveScrolledRoot,
5048 bool aForEventsOnly, bool aNeedsActiveLayer);
5049
nsDisplayOpacity(nsDisplayListBuilder * aBuilder,const nsDisplayOpacity & aOther)5050 nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
5051 const nsDisplayOpacity& aOther)
5052 : nsDisplayWrapList(aBuilder, aOther),
5053 mOpacity(aOther.mOpacity),
5054 mForEventsOnly(aOther.mForEventsOnly),
5055 mNeedsActiveLayer(aOther.mNeedsActiveLayer),
5056 mChildOpacityState(ChildOpacityState::Unknown) {
5057 MOZ_COUNT_CTOR(nsDisplayOpacity);
5058 // We should not try to merge flattened opacities.
5059 MOZ_ASSERT(aOther.mChildOpacityState != ChildOpacityState::Applied);
5060 }
5061
5062 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
5063 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
5064
5065 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayOpacity)
5066
5067 NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
5068
InvalidateCachedChildInfo(nsDisplayListBuilder * aBuilder)5069 void InvalidateCachedChildInfo(nsDisplayListBuilder* aBuilder) override {
5070 mChildOpacityState = ChildOpacityState::Unknown;
5071 }
5072
5073 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
5074 bool* aSnap) const override;
5075 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
5076
CanMerge(const nsDisplayItem * aItem)5077 bool CanMerge(const nsDisplayItem* aItem) const override {
5078 // items for the same content element should be merged into a single
5079 // compositing group
5080 // aItem->GetUnderlyingFrame() returns non-null because it's
5081 // nsDisplayOpacity
5082 return HasDifferentFrame(aItem) && HasSameTypeAndClip(aItem) &&
5083 HasSameContent(aItem);
5084 }
5085
AllocateGeometry(nsDisplayListBuilder * aBuilder)5086 nsDisplayItemGeometry* AllocateGeometry(
5087 nsDisplayListBuilder* aBuilder) override {
5088 return new nsDisplayOpacityGeometry(this, aBuilder, mOpacity);
5089 }
5090
5091 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
5092 const nsDisplayItemGeometry* aGeometry,
5093 nsRegion* aInvalidRegion) const override;
5094
IsInvalid(nsRect & aRect)5095 bool IsInvalid(nsRect& aRect) const override {
5096 if (mForEventsOnly) {
5097 return false;
5098 }
5099 return nsDisplayWrapList::IsInvalid(aRect);
5100 }
5101 bool CanApplyOpacity(WebRenderLayerManager* aManager,
5102 nsDisplayListBuilder* aBuilder) const override;
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)5103 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
5104 return false;
5105 }
5106
5107 bool CanApplyOpacityToChildren(WebRenderLayerManager* aManager,
5108 nsDisplayListBuilder* aBuilder,
5109 float aInheritedOpacity);
5110
NeedsGeometryUpdates()5111 bool NeedsGeometryUpdates() const override {
5112 // For flattened nsDisplayOpacity items, ComputeInvalidationRegion() only
5113 // handles invalidation for changed |mOpacity|. In order to keep track of
5114 // the current bounds of the item for invalidation, nsDisplayOpacityGeometry
5115 // for the corresponding DisplayItemData needs to be updated, even if the
5116 // reported invalidation region is empty.
5117 return mChildOpacityState == ChildOpacityState::Deferred;
5118 }
5119
5120 /**
5121 * Returns true if ShouldFlattenAway() applied opacity to children.
5122 */
OpacityAppliedToChildren()5123 bool OpacityAppliedToChildren() const {
5124 return mChildOpacityState == ChildOpacityState::Applied;
5125 }
5126
5127 static bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder,
5128 nsIFrame* aFrame);
5129 void WriteDebugInfo(std::stringstream& aStream) override;
5130 bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override;
5131 bool CreateWebRenderCommands(
5132 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
5133 const StackingContextHelper& aSc,
5134 layers::RenderRootStateManager* aManager,
5135 nsDisplayListBuilder* aDisplayListBuilder) override;
5136
GetOpacity()5137 float GetOpacity() const { return mOpacity; }
5138
CreatesStackingContextHelper()5139 bool CreatesStackingContextHelper() override { return true; }
5140
5141 private:
5142 NS_DISPLAY_ALLOW_CLONING()
5143
5144 bool CanApplyToChildren(WebRenderLayerManager* aManager,
5145 nsDisplayListBuilder* aBuilder);
5146 bool ApplyToMask();
5147
5148 float mOpacity;
5149 bool mForEventsOnly : 1;
5150 enum class ChildOpacityState : uint8_t {
5151 // Our child list has changed since the last time ApplyToChildren was
5152 // called.
5153 Unknown,
5154 // Our children defer opacity handling to us.
5155 Deferred,
5156 // Opacity is applied to our children.
5157 Applied
5158 };
5159 bool mNeedsActiveLayer : 1;
5160 #ifndef __GNUC__
5161 ChildOpacityState mChildOpacityState : 2;
5162 #else
5163 ChildOpacityState mChildOpacityState;
5164 #endif
5165 };
5166
5167 class nsDisplayBlendMode : public nsDisplayWrapList {
5168 public:
5169 nsDisplayBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5170 nsDisplayList* aList, StyleBlend aBlendMode,
5171 const ActiveScrolledRoot* aActiveScrolledRoot,
5172 const bool aIsForBackground);
nsDisplayBlendMode(nsDisplayListBuilder * aBuilder,const nsDisplayBlendMode & aOther)5173 nsDisplayBlendMode(nsDisplayListBuilder* aBuilder,
5174 const nsDisplayBlendMode& aOther)
5175 : nsDisplayWrapList(aBuilder, aOther),
5176 mBlendMode(aOther.mBlendMode),
5177 mIsForBackground(aOther.mIsForBackground) {
5178 MOZ_COUNT_CTOR(nsDisplayBlendMode);
5179 }
5180
5181 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBlendMode)
5182
5183 NS_DISPLAY_DECL_NAME("BlendMode", TYPE_BLEND_MODE)
5184
5185 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
5186 bool* aSnap) const override;
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion)5187 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
5188 const nsDisplayItemGeometry* aGeometry,
5189 nsRegion* aInvalidRegion) const override {
5190 // We don't need to compute an invalidation region since we have
5191 // LayerTreeInvalidation
5192 }
5193
5194 bool CreateWebRenderCommands(
5195 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
5196 const StackingContextHelper& aSc,
5197 layers::RenderRootStateManager* aManager,
5198 nsDisplayListBuilder* aDisplayListBuilder) override;
5199 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
5200
5201 bool CanMerge(const nsDisplayItem* aItem) const override;
5202
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)5203 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
5204 return false;
5205 }
5206
5207 gfx::CompositionOp BlendMode();
5208
CreatesStackingContextHelper()5209 bool CreatesStackingContextHelper() override { return true; }
5210
5211 protected:
5212 StyleBlend mBlendMode;
5213 bool mIsForBackground;
5214
5215 private:
5216 NS_DISPLAY_ALLOW_CLONING()
5217 };
5218
5219 class nsDisplayTableBlendMode : public nsDisplayBlendMode {
5220 public:
nsDisplayTableBlendMode(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,nsDisplayList * aList,StyleBlend aBlendMode,const ActiveScrolledRoot * aActiveScrolledRoot,nsIFrame * aAncestorFrame,const bool aIsForBackground)5221 nsDisplayTableBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5222 nsDisplayList* aList, StyleBlend aBlendMode,
5223 const ActiveScrolledRoot* aActiveScrolledRoot,
5224 nsIFrame* aAncestorFrame, const bool aIsForBackground)
5225 : nsDisplayBlendMode(aBuilder, aFrame, aList, aBlendMode,
5226 aActiveScrolledRoot, aIsForBackground),
5227 mAncestorFrame(aAncestorFrame) {
5228 if (aBuilder->IsRetainingDisplayList()) {
5229 mAncestorFrame->AddDisplayItem(this);
5230 }
5231 }
5232
nsDisplayTableBlendMode(nsDisplayListBuilder * aBuilder,const nsDisplayTableBlendMode & aOther)5233 nsDisplayTableBlendMode(nsDisplayListBuilder* aBuilder,
5234 const nsDisplayTableBlendMode& aOther)
5235 : nsDisplayBlendMode(aBuilder, aOther),
5236 mAncestorFrame(aOther.mAncestorFrame) {
5237 if (aBuilder->IsRetainingDisplayList()) {
5238 mAncestorFrame->AddDisplayItem(this);
5239 }
5240 }
5241
~nsDisplayTableBlendMode()5242 ~nsDisplayTableBlendMode() override {
5243 if (mAncestorFrame) {
5244 mAncestorFrame->RemoveDisplayItem(this);
5245 }
5246 }
5247
5248 NS_DISPLAY_DECL_NAME("TableBlendMode", TYPE_TABLE_BLEND_MODE)
5249
FrameForInvalidation()5250 nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
5251
RemoveFrame(nsIFrame * aFrame)5252 void RemoveFrame(nsIFrame* aFrame) override {
5253 if (aFrame == mAncestorFrame) {
5254 mAncestorFrame = nullptr;
5255 SetDeletedFrame();
5256 }
5257 nsDisplayBlendMode::RemoveFrame(aFrame);
5258 }
5259
5260 protected:
5261 nsIFrame* mAncestorFrame;
5262
5263 private:
5264 NS_DISPLAY_ALLOW_CLONING()
5265 };
5266
5267 class nsDisplayBlendContainer : public nsDisplayWrapList {
5268 public:
5269 static nsDisplayBlendContainer* CreateForMixBlendMode(
5270 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
5271 const ActiveScrolledRoot* aActiveScrolledRoot);
5272
5273 static nsDisplayBlendContainer* CreateForBackgroundBlendMode(
5274 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5275 nsIFrame* aSecondaryFrame, nsDisplayList* aList,
5276 const ActiveScrolledRoot* aActiveScrolledRoot);
5277
5278 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBlendContainer)
5279
5280 NS_DISPLAY_DECL_NAME("BlendContainer", TYPE_BLEND_CONTAINER)
5281
5282 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
5283 bool CreateWebRenderCommands(
5284 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
5285 const StackingContextHelper& aSc,
5286 layers::RenderRootStateManager* aManager,
5287 nsDisplayListBuilder* aDisplayListBuilder) override;
5288
CanMerge(const nsDisplayItem * aItem)5289 bool CanMerge(const nsDisplayItem* aItem) const override {
5290 // Items for the same content element should be merged into a single
5291 // compositing group.
5292 return HasDifferentFrame(aItem) && HasSameTypeAndClip(aItem) &&
5293 HasSameContent(aItem) &&
5294 mIsForBackground ==
5295 static_cast<const nsDisplayBlendContainer*>(aItem)
5296 ->mIsForBackground;
5297 }
5298
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)5299 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
5300 return false;
5301 }
5302
CreatesStackingContextHelper()5303 bool CreatesStackingContextHelper() override { return true; }
5304
5305 protected:
5306 nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5307 nsDisplayList* aList,
5308 const ActiveScrolledRoot* aActiveScrolledRoot,
5309 bool aIsForBackground);
nsDisplayBlendContainer(nsDisplayListBuilder * aBuilder,const nsDisplayBlendContainer & aOther)5310 nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder,
5311 const nsDisplayBlendContainer& aOther)
5312 : nsDisplayWrapList(aBuilder, aOther),
5313 mIsForBackground(aOther.mIsForBackground) {
5314 MOZ_COUNT_CTOR(nsDisplayBlendContainer);
5315 }
5316
5317 // Used to distinguish containers created at building stacking
5318 // context or appending background.
5319 bool mIsForBackground;
5320
5321 private:
5322 NS_DISPLAY_ALLOW_CLONING()
5323 };
5324
5325 class nsDisplayTableBlendContainer : public nsDisplayBlendContainer {
5326 public:
5327 NS_DISPLAY_DECL_NAME("TableBlendContainer", TYPE_TABLE_BLEND_CONTAINER)
5328
FrameForInvalidation()5329 nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
5330
RemoveFrame(nsIFrame * aFrame)5331 void RemoveFrame(nsIFrame* aFrame) override {
5332 if (aFrame == mAncestorFrame) {
5333 mAncestorFrame = nullptr;
5334 SetDeletedFrame();
5335 }
5336 nsDisplayBlendContainer::RemoveFrame(aFrame);
5337 }
5338
5339 protected:
nsDisplayTableBlendContainer(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,nsDisplayList * aList,const ActiveScrolledRoot * aActiveScrolledRoot,bool aIsForBackground,nsIFrame * aAncestorFrame)5340 nsDisplayTableBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5341 nsDisplayList* aList,
5342 const ActiveScrolledRoot* aActiveScrolledRoot,
5343 bool aIsForBackground, nsIFrame* aAncestorFrame)
5344 : nsDisplayBlendContainer(aBuilder, aFrame, aList, aActiveScrolledRoot,
5345 aIsForBackground),
5346 mAncestorFrame(aAncestorFrame) {
5347 if (aBuilder->IsRetainingDisplayList()) {
5348 mAncestorFrame->AddDisplayItem(this);
5349 }
5350 }
5351
nsDisplayTableBlendContainer(nsDisplayListBuilder * aBuilder,const nsDisplayTableBlendContainer & aOther)5352 nsDisplayTableBlendContainer(nsDisplayListBuilder* aBuilder,
5353 const nsDisplayTableBlendContainer& aOther)
5354 : nsDisplayBlendContainer(aBuilder, aOther),
5355 mAncestorFrame(aOther.mAncestorFrame) {}
5356
~nsDisplayTableBlendContainer()5357 ~nsDisplayTableBlendContainer() override {
5358 if (mAncestorFrame) {
5359 mAncestorFrame->RemoveDisplayItem(this);
5360 }
5361 }
5362
5363 nsIFrame* mAncestorFrame;
5364
5365 private:
5366 NS_DISPLAY_ALLOW_CLONING()
5367 };
5368
5369 /**
5370 * nsDisplayOwnLayer constructor flags. If we nest this class inside
5371 * nsDisplayOwnLayer then we can't forward-declare it up at the top of this
5372 * file and that makes it hard to use in all the places that we need to use it.
5373 */
5374 enum class nsDisplayOwnLayerFlags {
5375 None = 0,
5376 GenerateSubdocInvalidations = 1 << 0,
5377 GenerateScrollableLayer = 1 << 1,
5378 };
5379
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsDisplayOwnLayerFlags)5380 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsDisplayOwnLayerFlags)
5381
5382 /**
5383 * A display item that has no purpose but to ensure its contents get
5384 * their own layer.
5385 */
5386 class nsDisplayOwnLayer : public nsDisplayWrapList {
5387 public:
5388 enum OwnLayerType {
5389 OwnLayerForTransformWithRoundedClip,
5390 OwnLayerForStackingContext,
5391 OwnLayerForImageBoxFrame,
5392 OwnLayerForScrollbar,
5393 OwnLayerForScrollThumb,
5394 OwnLayerForSubdoc,
5395 OwnLayerForBoxFrame
5396 };
5397
5398 /**
5399 * @param aFlags eGenerateSubdocInvalidations :
5400 * Add UserData to the created ContainerLayer, so that invalidations
5401 * for this layer are send to our nsPresContext.
5402 * eGenerateScrollableLayer : only valid on nsDisplaySubDocument (and
5403 * subclasses), indicates this layer is to be a scrollable layer, so call
5404 * ComputeFrameMetrics, etc.
5405 * @param aScrollTarget when eVerticalScrollbar or eHorizontalScrollbar
5406 * is set in the flags, this parameter should be the ViewID of the
5407 * scrollable content this scrollbar is for.
5408 */
5409 nsDisplayOwnLayer(
5410 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
5411 const ActiveScrolledRoot* aActiveScrolledRoot,
5412 nsDisplayOwnLayerFlags aFlags = nsDisplayOwnLayerFlags::None,
5413 const layers::ScrollbarData& aScrollbarData = layers::ScrollbarData{},
5414 bool aForceActive = true, bool aClearClipChain = false);
5415
5416 nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
5417 const nsDisplayOwnLayer& aOther)
5418 : nsDisplayWrapList(aBuilder, aOther),
5419 mFlags(aOther.mFlags),
5420 mScrollbarData(aOther.mScrollbarData),
5421 mForceActive(aOther.mForceActive),
5422 mWrAnimationId(aOther.mWrAnimationId) {
5423 MOZ_COUNT_CTOR(nsDisplayOwnLayer);
5424 }
5425
5426 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayOwnLayer)
5427
5428 NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
5429
5430 bool CreateWebRenderCommands(
5431 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
5432 const StackingContextHelper& aSc,
5433 layers::RenderRootStateManager* aManager,
5434 nsDisplayListBuilder* aDisplayListBuilder) override;
5435 bool UpdateScrollData(layers::WebRenderScrollData* aData,
5436 layers::WebRenderLayerScrollData* aLayerData) override;
5437 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override {
5438 GetChildren()->Paint(aBuilder, aCtx,
5439 mFrame->PresContext()->AppUnitsPerDevPixel());
5440 }
5441
5442 bool CanMerge(const nsDisplayItem* aItem) const override {
5443 // Don't allow merging, each sublist must have its own layer
5444 return false;
5445 }
5446
5447 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
5448 return false;
5449 }
5450
5451 void WriteDebugInfo(std::stringstream& aStream) override;
5452 nsDisplayOwnLayerFlags GetFlags() { return mFlags; }
5453 bool IsScrollThumbLayer() const;
5454 bool IsScrollbarContainer() const;
5455 bool IsRootScrollbarContainer() const;
5456 bool IsZoomingLayer() const;
5457 bool IsFixedPositionLayer() const;
5458 bool IsStickyPositionLayer() const;
5459 bool HasDynamicToolbar() const;
5460
5461 bool CreatesStackingContextHelper() override { return true; }
5462
5463 protected:
5464 nsDisplayOwnLayerFlags mFlags;
5465
5466 /**
5467 * If this nsDisplayOwnLayer represents a scroll thumb layer or a
5468 * scrollbar container layer, mScrollbarData stores information
5469 * about the scrollbar. Otherwise, mScrollbarData will be
5470 * default-constructed (in particular with mDirection == Nothing())
5471 * and can be ignored.
5472 */
5473 layers::ScrollbarData mScrollbarData;
5474 bool mForceActive;
5475 uint64_t mWrAnimationId;
5476 };
5477
5478 /**
5479 * A display item for subdocuments. This is more or less the same as
5480 * nsDisplayOwnLayer, except that it always populates the FrameMetrics instance
5481 * on the ContainerLayer it builds.
5482 */
5483 class nsDisplaySubDocument : public nsDisplayOwnLayer {
5484 public:
5485 nsDisplaySubDocument(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5486 nsSubDocumentFrame* aSubDocFrame, nsDisplayList* aList,
5487 nsDisplayOwnLayerFlags aFlags);
5488 ~nsDisplaySubDocument() override;
5489
5490 NS_DISPLAY_DECL_NAME("SubDocument", TYPE_SUBDOCUMENT)
5491
5492 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
5493
SubDocumentFrame()5494 virtual nsSubDocumentFrame* SubDocumentFrame() { return mSubDocFrame; }
5495
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)5496 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
5497 return mShouldFlatten;
5498 }
5499
SetShouldFlattenAway(bool aShouldFlatten)5500 void SetShouldFlattenAway(bool aShouldFlatten) {
5501 mShouldFlatten = aShouldFlatten;
5502 }
5503
5504 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
5505 bool* aSnap) const override;
5506
5507 nsIFrame* FrameForInvalidation() const override;
5508 void RemoveFrame(nsIFrame* aFrame) override;
5509
5510 void Disown();
5511
5512 protected:
5513 ViewID mScrollParentId;
5514 bool mForceDispatchToContentRegion{};
5515 bool mShouldFlatten;
5516 nsSubDocumentFrame* mSubDocFrame;
5517 };
5518
5519 /**
5520 * A display item used to represent sticky position elements. The contents
5521 * gets its own layer and creates a stacking context, and the layer will have
5522 * position-related metadata set on it.
5523 */
5524 class nsDisplayStickyPosition : public nsDisplayOwnLayer {
5525 public:
5526 nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5527 nsDisplayList* aList,
5528 const ActiveScrolledRoot* aActiveScrolledRoot,
5529 const ActiveScrolledRoot* aContainerASR,
5530 bool aClippedToDisplayPort);
nsDisplayStickyPosition(nsDisplayListBuilder * aBuilder,const nsDisplayStickyPosition & aOther)5531 nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder,
5532 const nsDisplayStickyPosition& aOther)
5533 : nsDisplayOwnLayer(aBuilder, aOther),
5534 mContainerASR(aOther.mContainerASR),
5535 mClippedToDisplayPort(aOther.mClippedToDisplayPort),
5536 mShouldFlatten(false) {
5537 MOZ_COUNT_CTOR(nsDisplayStickyPosition);
5538 }
5539
MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayStickyPosition)5540 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayStickyPosition)
5541
5542 const DisplayItemClip& GetClip() const override {
5543 return DisplayItemClip::NoClip();
5544 }
IsClippedToDisplayPort()5545 bool IsClippedToDisplayPort() const { return mClippedToDisplayPort; }
5546
5547 NS_DISPLAY_DECL_NAME("StickyPosition", TYPE_STICKY_POSITION)
Paint(nsDisplayListBuilder * aBuilder,gfxContext * aCtx)5548 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override {
5549 GetChildren()->Paint(aBuilder, aCtx,
5550 mFrame->PresContext()->AppUnitsPerDevPixel());
5551 }
5552
5553 bool CreateWebRenderCommands(
5554 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
5555 const StackingContextHelper& aSc,
5556 layers::RenderRootStateManager* aManager,
5557 nsDisplayListBuilder* aDisplayListBuilder) override;
5558
5559 bool UpdateScrollData(layers::WebRenderScrollData* aData,
5560 layers::WebRenderLayerScrollData* aLayerData) override;
5561
GetContainerASR()5562 const ActiveScrolledRoot* GetContainerASR() const { return mContainerASR; }
5563
CreatesStackingContextHelper()5564 bool CreatesStackingContextHelper() override { return true; }
5565
CanMoveAsync()5566 bool CanMoveAsync() override { return true; }
5567
SetShouldFlatten(bool aShouldFlatten)5568 void SetShouldFlatten(bool aShouldFlatten) {
5569 mShouldFlatten = aShouldFlatten;
5570 }
5571
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)5572 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) final {
5573 return mShouldFlatten;
5574 }
5575
5576 private:
5577 NS_DISPLAY_ALLOW_CLONING()
5578
5579 void CalculateLayerScrollRanges(StickyScrollContainer* aStickyScrollContainer,
5580 float aAppUnitsPerDevPixel, float aScaleX,
5581 float aScaleY,
5582 LayerRectAbsolute& aStickyOuter,
5583 LayerRectAbsolute& aStickyInner);
5584
5585 StickyScrollContainer* GetStickyScrollContainer();
5586
5587 // This stores the ASR that this sticky container item would have assuming it
5588 // has no fixed descendants. This may be the same as the ASR returned by
5589 // GetActiveScrolledRoot(), or it may be a descendant of that.
5590 RefPtr<const ActiveScrolledRoot> mContainerASR;
5591 // This flag tracks if this sticky item is just clipped to the enclosing
5592 // scrollframe's displayport, or if there are additional clips in play. In
5593 // the former case, we can skip setting the displayport clip as the scrolled-
5594 // clip of the corresponding layer. This allows sticky items to remain
5595 // unclipped when the enclosing scrollframe is scrolled past the displayport.
5596 // i.e. when the rest of the scrollframe checkerboards, the sticky item will
5597 // not. This makes sense to do because the sticky item has abnormal scrolling
5598 // behavior and may still be visible even if the rest of the scrollframe is
5599 // checkerboarded. Note that the sticky item will still be subject to the
5600 // scrollport clip.
5601 bool mClippedToDisplayPort;
5602
5603 // True if this item should be flattened away.
5604 bool mShouldFlatten;
5605 };
5606
5607 class nsDisplayFixedPosition : public nsDisplayOwnLayer {
5608 public:
5609 nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5610 nsDisplayList* aList,
5611 const ActiveScrolledRoot* aActiveScrolledRoot,
5612 const ActiveScrolledRoot* aScrollTargetASR);
nsDisplayFixedPosition(nsDisplayListBuilder * aBuilder,const nsDisplayFixedPosition & aOther)5613 nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
5614 const nsDisplayFixedPosition& aOther)
5615 : nsDisplayOwnLayer(aBuilder, aOther),
5616 mScrollTargetASR(aOther.mScrollTargetASR),
5617 mIsFixedBackground(aOther.mIsFixedBackground) {
5618 MOZ_COUNT_CTOR(nsDisplayFixedPosition);
5619 }
5620
5621 static nsDisplayFixedPosition* CreateForFixedBackground(
5622 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5623 nsIFrame* aSecondaryFrame, nsDisplayBackgroundImage* aImage,
5624 const uint16_t aIndex, const ActiveScrolledRoot* aScrollTargetASR);
5625
5626 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayFixedPosition)
5627
5628 NS_DISPLAY_DECL_NAME("FixedPosition", TYPE_FIXED_POSITION)
5629
Paint(nsDisplayListBuilder * aBuilder,gfxContext * aCtx)5630 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override {
5631 GetChildren()->Paint(aBuilder, aCtx,
5632 mFrame->PresContext()->AppUnitsPerDevPixel());
5633 }
5634
ShouldFixToViewport(nsDisplayListBuilder * aBuilder)5635 bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) const override {
5636 return mIsFixedBackground;
5637 }
5638
5639 bool CreateWebRenderCommands(
5640 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
5641 const StackingContextHelper& aSc,
5642 layers::RenderRootStateManager* aManager,
5643 nsDisplayListBuilder* aDisplayListBuilder) override;
5644 bool UpdateScrollData(layers::WebRenderScrollData* aData,
5645 layers::WebRenderLayerScrollData* aLayerData) override;
5646 void WriteDebugInfo(std::stringstream& aStream) override;
5647
5648 protected:
5649 // For background-attachment:fixed
5650 nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5651 nsDisplayList* aList,
5652 const ActiveScrolledRoot* aScrollTargetASR);
5653 ViewID GetScrollTargetId();
5654
5655 RefPtr<const ActiveScrolledRoot> mScrollTargetASR;
5656 bool mIsFixedBackground;
5657
5658 private:
5659 NS_DISPLAY_ALLOW_CLONING()
5660 };
5661
5662 class nsDisplayTableFixedPosition : public nsDisplayFixedPosition {
5663 public:
5664 NS_DISPLAY_DECL_NAME("TableFixedPosition", TYPE_TABLE_FIXED_POSITION)
5665
FrameForInvalidation()5666 nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
5667
RemoveFrame(nsIFrame * aFrame)5668 void RemoveFrame(nsIFrame* aFrame) override {
5669 if (aFrame == mAncestorFrame) {
5670 mAncestorFrame = nullptr;
5671 SetDeletedFrame();
5672 }
5673 nsDisplayFixedPosition::RemoveFrame(aFrame);
5674 }
5675
5676 protected:
5677 nsDisplayTableFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5678 nsDisplayList* aList, nsIFrame* aAncestorFrame,
5679 const ActiveScrolledRoot* aScrollTargetASR);
5680
nsDisplayTableFixedPosition(nsDisplayListBuilder * aBuilder,const nsDisplayTableFixedPosition & aOther)5681 nsDisplayTableFixedPosition(nsDisplayListBuilder* aBuilder,
5682 const nsDisplayTableFixedPosition& aOther)
5683 : nsDisplayFixedPosition(aBuilder, aOther),
5684 mAncestorFrame(aOther.mAncestorFrame) {}
5685
~nsDisplayTableFixedPosition()5686 ~nsDisplayTableFixedPosition() override {
5687 if (mAncestorFrame) {
5688 mAncestorFrame->RemoveDisplayItem(this);
5689 }
5690 }
5691
5692 nsIFrame* mAncestorFrame;
5693
5694 private:
5695 NS_DISPLAY_ALLOW_CLONING()
5696 };
5697
5698 /**
5699 * This creates an empty scrollable layer. It has no child layers.
5700 * It is used to record the existence of a scrollable frame in the layer
5701 * tree.
5702 */
5703 class nsDisplayScrollInfoLayer : public nsDisplayWrapList {
5704 public:
5705 nsDisplayScrollInfoLayer(nsDisplayListBuilder* aBuilder,
5706 nsIFrame* aScrolledFrame, nsIFrame* aScrollFrame,
5707 const gfx::CompositorHitTestInfo& aHitInfo,
5708 const nsRect& aHitArea);
5709
5710 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayScrollInfoLayer)
5711
5712 NS_DISPLAY_DECL_NAME("ScrollInfoLayer", TYPE_SCROLL_INFO_LAYER)
5713
GetOpaqueRegion(nsDisplayListBuilder * aBuilder,bool * aSnap)5714 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
5715 bool* aSnap) const override {
5716 *aSnap = false;
5717 return nsRegion();
5718 }
5719
Paint(nsDisplayListBuilder * aBuilder,gfxContext * aCtx)5720 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override {
5721 return;
5722 }
5723
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)5724 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
5725 return false;
5726 }
5727
5728 void WriteDebugInfo(std::stringstream& aStream) override;
5729 UniquePtr<layers::ScrollMetadata> ComputeScrollMetadata(
5730 nsDisplayListBuilder* aBuilder,
5731 layers::WebRenderLayerManager* aLayerManager);
5732 bool UpdateScrollData(layers::WebRenderScrollData* aData,
5733 layers::WebRenderLayerScrollData* aLayerData) override;
5734 bool CreateWebRenderCommands(
5735 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
5736 const StackingContextHelper& aSc,
5737 layers::RenderRootStateManager* aManager,
5738 nsDisplayListBuilder* aDisplayListBuilder) override;
5739
5740 protected:
5741 nsIFrame* mScrollFrame;
5742 nsIFrame* mScrolledFrame;
5743 ViewID mScrollParentId;
5744 gfx::CompositorHitTestInfo mHitInfo;
5745 nsRect mHitArea;
5746 };
5747
5748 /**
5749 * nsDisplayZoom is used for subdocuments that have a different full zoom than
5750 * their parent documents. This item creates a container layer.
5751 */
5752 class nsDisplayZoom : public nsDisplaySubDocument {
5753 public:
5754 /**
5755 * @param aFrame is the root frame of the subdocument.
5756 * @param aList contains the display items for the subdocument.
5757 * @param aAPD is the app units per dev pixel ratio of the subdocument.
5758 * @param aParentAPD is the app units per dev pixel ratio of the parent
5759 * document.
5760 * @param aFlags eGenerateSubdocInvalidations :
5761 * Add UserData to the created ContainerLayer, so that invalidations
5762 * for this layer are send to our nsPresContext.
5763 */
5764 nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5765 nsSubDocumentFrame* aSubDocFrame, nsDisplayList* aList,
5766 int32_t aAPD, int32_t aParentAPD,
5767 nsDisplayOwnLayerFlags aFlags = nsDisplayOwnLayerFlags::None);
5768
5769 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayZoom)
5770
5771 NS_DISPLAY_DECL_NAME("Zoom", TYPE_ZOOM)
5772
5773 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
5774 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
5775 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
5776 // Get the app units per dev pixel ratio of the child document.
GetChildAppUnitsPerDevPixel()5777 int32_t GetChildAppUnitsPerDevPixel() { return mAPD; }
5778 // Get the app units per dev pixel ratio of the parent document.
GetParentAppUnitsPerDevPixel()5779 int32_t GetParentAppUnitsPerDevPixel() { return mParentAPD; }
5780
5781 private:
5782 int32_t mAPD, mParentAPD;
5783 };
5784
5785 /**
5786 * nsDisplayAsyncZoom is used for APZ zooming. It wraps the contents of the
5787 * root content document's scroll frame, including fixed position content. It
5788 * does not contain the scroll frame's scrollbars. It is clipped to the scroll
5789 * frame's scroll port clip. It is not scrolled; only its non-fixed contents
5790 * are scrolled. This item creates a container layer.
5791 */
5792 class nsDisplayAsyncZoom : public nsDisplayOwnLayer {
5793 public:
5794 nsDisplayAsyncZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5795 nsDisplayList* aList,
5796 const ActiveScrolledRoot* aActiveScrolledRoot,
5797 layers::FrameMetrics::ViewID aViewID);
nsDisplayAsyncZoom(nsDisplayListBuilder * aBuilder,const nsDisplayAsyncZoom & aOther)5798 nsDisplayAsyncZoom(nsDisplayListBuilder* aBuilder,
5799 const nsDisplayAsyncZoom& aOther)
5800 : nsDisplayOwnLayer(aBuilder, aOther), mViewID(aOther.mViewID) {
5801 MOZ_COUNT_CTOR(nsDisplayAsyncZoom);
5802 }
5803
5804 #ifdef NS_BUILD_REFCNT_LOGGING
5805 virtual ~nsDisplayAsyncZoom();
5806 #endif
5807
5808 NS_DISPLAY_DECL_NAME("AsyncZoom", TYPE_ASYNC_ZOOM)
5809
5810 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
5811 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
5812 bool UpdateScrollData(layers::WebRenderScrollData* aData,
5813 layers::WebRenderLayerScrollData* aLayerData) override;
5814
5815 protected:
5816 layers::FrameMetrics::ViewID mViewID;
5817 };
5818
5819 /**
5820 * A base class for different effects types.
5821 */
5822 class nsDisplayEffectsBase : public nsDisplayWrapList {
5823 public:
5824 nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5825 nsDisplayList* aList,
5826 const ActiveScrolledRoot* aActiveScrolledRoot,
5827 bool aClearClipChain = false);
5828 nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5829 nsDisplayList* aList);
5830
nsDisplayEffectsBase(nsDisplayListBuilder * aBuilder,const nsDisplayEffectsBase & aOther)5831 nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder,
5832 const nsDisplayEffectsBase& aOther)
5833 : nsDisplayWrapList(aBuilder, aOther),
5834 mEffectsBounds(aOther.mEffectsBounds) {
5835 MOZ_COUNT_CTOR(nsDisplayEffectsBase);
5836 }
5837
5838 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayEffectsBase)
5839
5840 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
5841 bool* aSnap) const override;
5842 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
5843 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
5844
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)5845 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
5846 return false;
5847 }
5848
5849 gfxRect BBoxInUserSpace() const;
5850 gfxPoint UserSpaceOffset() const;
5851
5852 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
5853 const nsDisplayItemGeometry* aGeometry,
5854 nsRegion* aInvalidRegion) const override;
5855
5856 protected:
5857 bool ValidateSVGFrame();
5858
5859 // relative to mFrame
5860 nsRect mEffectsBounds;
5861 };
5862
5863 /**
5864 * A display item to paint a stacking context with 'mask' and 'clip-path'
5865 * effects set by the stacking context root frame's style. The 'mask' and
5866 * 'clip-path' properties may both contain multiple masks and clip paths,
5867 * respectively.
5868 *
5869 * Note that 'mask' and 'clip-path' may just contain CSS simple-images and CSS
5870 * basic shapes, respectively. That is, they don't necessarily reference
5871 * resources such as SVG 'mask' and 'clipPath' elements.
5872 */
5873 class nsDisplayMasksAndClipPaths : public nsDisplayEffectsBase {
5874 public:
5875 nsDisplayMasksAndClipPaths(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5876 nsDisplayList* aList,
5877 const ActiveScrolledRoot* aActiveScrolledRoot);
nsDisplayMasksAndClipPaths(nsDisplayListBuilder * aBuilder,const nsDisplayMasksAndClipPaths & aOther)5878 nsDisplayMasksAndClipPaths(nsDisplayListBuilder* aBuilder,
5879 const nsDisplayMasksAndClipPaths& aOther)
5880 : nsDisplayEffectsBase(aBuilder, aOther),
5881 mDestRects(aOther.mDestRects.Clone()) {
5882 MOZ_COUNT_CTOR(nsDisplayMasksAndClipPaths);
5883 }
5884
5885 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayMasksAndClipPaths)
5886
5887 NS_DISPLAY_DECL_NAME("Mask", TYPE_MASK)
5888
5889 bool CanMerge(const nsDisplayItem* aItem) const override;
5890
Merge(const nsDisplayItem * aItem)5891 void Merge(const nsDisplayItem* aItem) override {
5892 nsDisplayWrapList::Merge(aItem);
5893
5894 const nsDisplayMasksAndClipPaths* other =
5895 static_cast<const nsDisplayMasksAndClipPaths*>(aItem);
5896 mEffectsBounds.UnionRect(
5897 mEffectsBounds,
5898 other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
5899 }
5900
5901 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
5902
AllocateGeometry(nsDisplayListBuilder * aBuilder)5903 nsDisplayItemGeometry* AllocateGeometry(
5904 nsDisplayListBuilder* aBuilder) override {
5905 return new nsDisplayMasksAndClipPathsGeometry(this, aBuilder);
5906 }
5907
5908 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
5909 const nsDisplayItemGeometry* aGeometry,
5910 nsRegion* aInvalidRegion) const override;
5911 #ifdef MOZ_DUMP_PAINTING
5912 void PrintEffects(nsACString& aTo);
5913 #endif
5914
5915 bool IsValidMask();
5916
5917 void PaintWithContentsPaintCallback(
5918 nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
5919 const std::function<void()>& aPaintChildren);
5920
5921 /*
5922 * Paint mask onto aMaskContext in mFrame's coordinate space and
5923 * return whether the mask layer was painted successfully.
5924 */
5925 bool PaintMask(nsDisplayListBuilder* aBuilder, gfxContext* aMaskContext,
5926 bool aHandleOpacity, bool* aMaskPainted = nullptr);
5927
GetDestRects()5928 const nsTArray<nsRect>& GetDestRects() { return mDestRects; }
5929
5930 bool CreateWebRenderCommands(
5931 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
5932 const StackingContextHelper& aSc,
5933 layers::RenderRootStateManager* aManager,
5934 nsDisplayListBuilder* aDisplayListBuilder) override;
5935
5936 Maybe<nsRect> GetClipWithRespectToASR(
5937 nsDisplayListBuilder* aBuilder,
5938 const ActiveScrolledRoot* aASR) const override;
5939
CreatesStackingContextHelper()5940 bool CreatesStackingContextHelper() override { return true; }
5941
5942 private:
5943 NS_DISPLAY_ALLOW_CLONING()
5944
5945 nsTArray<nsRect> mDestRects;
5946 };
5947
5948 class nsDisplayBackdropRootContainer : public nsDisplayWrapList {
5949 public:
nsDisplayBackdropRootContainer(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,nsDisplayList * aList,const ActiveScrolledRoot * aActiveScrolledRoot)5950 nsDisplayBackdropRootContainer(nsDisplayListBuilder* aBuilder,
5951 nsIFrame* aFrame, nsDisplayList* aList,
5952 const ActiveScrolledRoot* aActiveScrolledRoot)
5953 : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, true) {
5954 MOZ_COUNT_CTOR(nsDisplayBackdropRootContainer);
5955 }
5956
5957 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBackdropRootContainer)
5958
5959 NS_DISPLAY_DECL_NAME("BackdropRootContainer", TYPE_BACKDROP_ROOT_CONTAINER)
5960
5961 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
5962
5963 bool CreateWebRenderCommands(
5964 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
5965 const StackingContextHelper& aSc,
5966 layers::RenderRootStateManager* aManager,
5967 nsDisplayListBuilder* aDisplayListBuilder) override;
5968
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)5969 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
5970 return !aBuilder->IsPaintingForWebRender();
5971 }
5972
CreatesStackingContextHelper()5973 bool CreatesStackingContextHelper() override { return true; }
5974 };
5975
5976 class nsDisplayBackdropFilters : public nsDisplayWrapList {
5977 public:
nsDisplayBackdropFilters(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,nsDisplayList * aList,const nsRect & aBackdropRect)5978 nsDisplayBackdropFilters(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
5979 nsDisplayList* aList, const nsRect& aBackdropRect)
5980 : nsDisplayWrapList(aBuilder, aFrame, aList),
5981 mBackdropRect(aBackdropRect) {
5982 MOZ_COUNT_CTOR(nsDisplayBackdropFilters);
5983 }
5984
5985 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayBackdropFilters)
5986
5987 NS_DISPLAY_DECL_NAME("BackdropFilter", TYPE_BACKDROP_FILTER)
5988
5989 bool CreateWebRenderCommands(
5990 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
5991 const StackingContextHelper& aSc,
5992 layers::RenderRootStateManager* aManager,
5993 nsDisplayListBuilder* aDisplayListBuilder) override;
5994 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
5995
5996 static bool CanCreateWebRenderCommands(nsDisplayListBuilder* aBuilder,
5997 nsIFrame* aFrame);
5998
ShouldFlattenAway(nsDisplayListBuilder * aBuilder)5999 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
6000 return !aBuilder->IsPaintingForWebRender();
6001 }
6002
CreatesStackingContextHelper()6003 bool CreatesStackingContextHelper() override { return true; }
6004
6005 private:
6006 nsRect mBackdropRect;
6007 };
6008
6009 /**
6010 * A display item to paint a stacking context with filter effects set by the
6011 * stacking context root frame's style.
6012 *
6013 * Note that the filters may just be simple CSS filter functions. That is,
6014 * they won't necessarily be references to SVG 'filter' elements.
6015 */
6016 class nsDisplayFilters : public nsDisplayEffectsBase {
6017 public:
6018 nsDisplayFilters(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
6019 nsDisplayList* aList);
6020
nsDisplayFilters(nsDisplayListBuilder * aBuilder,const nsDisplayFilters & aOther)6021 nsDisplayFilters(nsDisplayListBuilder* aBuilder,
6022 const nsDisplayFilters& aOther)
6023 : nsDisplayEffectsBase(aBuilder, aOther),
6024 mEffectsBounds(aOther.mEffectsBounds) {
6025 MOZ_COUNT_CTOR(nsDisplayFilters);
6026 }
6027
6028 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayFilters)
6029
6030 NS_DISPLAY_DECL_NAME("Filter", TYPE_FILTER)
6031
CanMerge(const nsDisplayItem * aItem)6032 bool CanMerge(const nsDisplayItem* aItem) const override {
6033 // Items for the same content element should be merged into a single
6034 // compositing group.
6035 return HasDifferentFrame(aItem) && HasSameTypeAndClip(aItem) &&
6036 HasSameContent(aItem);
6037 }
6038
Merge(const nsDisplayItem * aItem)6039 void Merge(const nsDisplayItem* aItem) override {
6040 nsDisplayWrapList::Merge(aItem);
6041
6042 const nsDisplayFilters* other = static_cast<const nsDisplayFilters*>(aItem);
6043 mEffectsBounds.UnionRect(
6044 mEffectsBounds,
6045 other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
6046 }
6047
6048 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
6049
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)6050 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override {
6051 *aSnap = false;
6052 return mEffectsBounds + ToReferenceFrame();
6053 }
6054
AllocateGeometry(nsDisplayListBuilder * aBuilder)6055 nsDisplayItemGeometry* AllocateGeometry(
6056 nsDisplayListBuilder* aBuilder) override {
6057 return new nsDisplayFiltersGeometry(this, aBuilder);
6058 }
6059
6060 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
6061 const nsDisplayItemGeometry* aGeometry,
6062 nsRegion* aInvalidRegion) const override;
6063 #ifdef MOZ_DUMP_PAINTING
6064 void PrintEffects(nsACString& aTo);
6065 #endif
6066
6067 void PaintWithContentsPaintCallback(
6068 nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
6069 const std::function<void(gfxContext* aContext)>& aPaintChildren);
6070
6071 bool CreateWebRenderCommands(
6072 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
6073 const StackingContextHelper& aSc,
6074 layers::RenderRootStateManager* aManager,
6075 nsDisplayListBuilder* aDisplayListBuilder) override;
6076 bool CanCreateWebRenderCommands() const;
6077
CanApplyOpacity(WebRenderLayerManager * aManager,nsDisplayListBuilder * aBuilder)6078 bool CanApplyOpacity(WebRenderLayerManager* aManager,
6079 nsDisplayListBuilder* aBuilder) const override {
6080 return CanCreateWebRenderCommands();
6081 }
6082
CreatesStackingContextHelper()6083 bool CreatesStackingContextHelper() override { return true; }
6084
6085 private:
6086 NS_DISPLAY_ALLOW_CLONING()
6087
6088 // relative to mFrame
6089 nsRect mEffectsBounds;
6090 nsRect mVisibleRect;
6091 };
6092
6093 /* A display item that applies a transformation to all of its descendant
6094 * elements. This wrapper should only be used if there is a transform applied
6095 * to the root element.
6096 *
6097 * The reason that a "bounds" rect is involved in transform calculations is
6098 * because CSS-transforms allow percentage values for the x and y components
6099 * of <translation-value>s, where percentages are percentages of the element's
6100 * border box.
6101 *
6102 * INVARIANT: The wrapped frame is transformed or we supplied a transform getter
6103 * function.
6104 * INVARIANT: The wrapped frame is non-null.
6105 */
6106 class nsDisplayTransform : public nsPaintedDisplayItem {
6107 using Matrix4x4 = gfx::Matrix4x4;
6108 using Matrix4x4Flagged = gfx::Matrix4x4Flagged;
6109 using TransformReferenceBox = nsStyleTransformMatrix::TransformReferenceBox;
6110
6111 public:
6112 enum class PrerenderDecision : uint8_t { No, Full, Partial };
6113
6114 enum {
6115 WithTransformGetter,
6116 };
6117
6118 /* Constructor accepts a display list, empties it, and wraps it up. It also
6119 * ferries the underlying frame to the nsDisplayItem constructor.
6120 */
6121 nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
6122 nsDisplayList* aList, const nsRect& aChildrenBuildingRect);
6123
6124 nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
6125 nsDisplayList* aList, const nsRect& aChildrenBuildingRect,
6126 PrerenderDecision aPrerenderDecision);
6127
6128 nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
6129 nsDisplayList* aList, const nsRect& aChildrenBuildingRect,
6130 decltype(WithTransformGetter));
6131
6132 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayTransform)
6133
6134 NS_DISPLAY_DECL_NAME("nsDisplayTransform", TYPE_TRANSFORM)
6135
6136 void UpdateBounds(nsDisplayListBuilder* aBuilder) override;
6137
6138 /**
6139 * This function updates bounds for items with a frame establishing
6140 * 3D rendering context.
6141 */
6142 void UpdateBoundsFor3D(nsDisplayListBuilder* aBuilder);
6143
6144 void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override;
6145
Destroy(nsDisplayListBuilder * aBuilder)6146 void Destroy(nsDisplayListBuilder* aBuilder) override {
6147 GetChildren()->DeleteAll(aBuilder);
6148 nsPaintedDisplayItem::Destroy(aBuilder);
6149 }
6150
6151 nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const override;
6152
GetChildren()6153 RetainedDisplayList* GetChildren() const override { return &mChildren; }
6154
GetUntransformedBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)6155 nsRect GetUntransformedBounds(nsDisplayListBuilder* aBuilder,
6156 bool* aSnap) const override {
6157 *aSnap = false;
6158 return mChildBounds;
6159 }
6160
GetUntransformedPaintRect()6161 const nsRect& GetUntransformedPaintRect() const override {
6162 return mChildrenBuildingRect;
6163 }
6164
6165 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
6166
6167 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
6168 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
6169 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
6170 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
6171 bool* aSnap) const override;
6172 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
6173 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
6174 const Maybe<gfx::Polygon>& aPolygon);
6175 bool CreateWebRenderCommands(
6176 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
6177 const StackingContextHelper& aSc,
6178 layers::RenderRootStateManager* aManager,
6179 nsDisplayListBuilder* aDisplayListBuilder) override;
6180 bool UpdateScrollData(layers::WebRenderScrollData* aData,
6181 layers::WebRenderLayerScrollData* aLayerData) override;
6182
AllocateGeometry(nsDisplayListBuilder * aBuilder)6183 nsDisplayItemGeometry* AllocateGeometry(
6184 nsDisplayListBuilder* aBuilder) override {
6185 return new nsDisplayTransformGeometry(
6186 this, aBuilder, GetTransformForRendering(),
6187 mFrame->PresContext()->AppUnitsPerDevPixel());
6188 }
6189
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion)6190 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
6191 const nsDisplayItemGeometry* aGeometry,
6192 nsRegion* aInvalidRegion) const override {
6193 const nsDisplayTransformGeometry* geometry =
6194 static_cast<const nsDisplayTransformGeometry*>(aGeometry);
6195
6196 // This code is only called for flattened, inactive transform items.
6197 // Only check if the transform has changed. The bounds invalidation should
6198 // be handled by the children themselves.
6199 if (!geometry->mTransform.FuzzyEqual(GetTransformForRendering())) {
6200 bool snap;
6201 aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
6202 }
6203 }
6204
ReferenceFrameForChildren()6205 const nsIFrame* ReferenceFrameForChildren() const override {
6206 // If we were created using a transform-getter, then we don't
6207 // belong to a transformed frame, and aren't a reference frame
6208 // for our children.
6209 if (!mHasTransformGetter) {
6210 return mFrame;
6211 }
6212 return nsPaintedDisplayItem::ReferenceFrameForChildren();
6213 }
6214
GetBuildingRectForChildren()6215 const nsRect& GetBuildingRectForChildren() const override {
6216 return mChildrenBuildingRect;
6217 }
6218
6219 enum { INDEX_MAX = UINT32_MAX >> TYPE_BITS };
6220
6221 /**
6222 * We include the perspective matrix from our containing block for the
6223 * purposes of visibility calculations, but we exclude it from the transform
6224 * we set on the layer (for rendering), since there will be an
6225 * nsDisplayPerspective created for that.
6226 */
6227 const Matrix4x4Flagged& GetTransform() const;
6228 const Matrix4x4Flagged& GetInverseTransform() const;
6229
6230 bool ShouldSkipTransform(nsDisplayListBuilder* aBuilder) const;
6231 Matrix4x4 GetTransformForRendering(
6232 LayoutDevicePoint* aOutOrigin = nullptr) const;
6233
6234 /**
6235 * Return the transform that is aggregation of all transform on the
6236 * preserves3d chain.
6237 */
6238 const Matrix4x4& GetAccumulatedPreserved3DTransform(
6239 nsDisplayListBuilder* aBuilder);
6240
6241 float GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder,
6242 const nsPoint& aPoint);
6243
6244 /**
6245 * TransformRect takes in as parameters a rectangle (in aFrame's coordinate
6246 * space) and returns the smallest rectangle (in aFrame's coordinate space)
6247 * containing the transformed image of that rectangle. That is, it takes
6248 * the four corners of the rectangle, transforms them according to the
6249 * matrix associated with the specified frame, then returns the smallest
6250 * rectangle containing the four transformed points.
6251 *
6252 * @param untransformedBounds The rectangle (in app units) to transform.
6253 * @param aFrame The frame whose transformation should be applied. This
6254 * function raises an assertion if aFrame is null or doesn't have a
6255 * transform applied to it.
6256 * @param aRefBox the reference box to use, which would usually be just
6257 * TransformReferemceBox(aFrame), but callers may override it if
6258 * needed.
6259 */
6260 static nsRect TransformRect(const nsRect& aUntransformedBounds,
6261 const nsIFrame* aFrame,
6262 TransformReferenceBox& aRefBox);
6263
6264 /* UntransformRect is like TransformRect, except that it inverts the
6265 * transform.
6266 */
6267 static bool UntransformRect(const nsRect& aTransformedBounds,
6268 const nsRect& aChildBounds,
6269 const nsIFrame* aFrame, nsRect* aOutRect);
6270
6271 bool UntransformRect(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
6272 nsRect* aOutRect) const;
6273
UntransformBuildingRect(nsDisplayListBuilder * aBuilder,nsRect * aOutRect)6274 bool UntransformBuildingRect(nsDisplayListBuilder* aBuilder,
6275 nsRect* aOutRect) const {
6276 return UntransformRect(aBuilder, GetBuildingRect(), aOutRect);
6277 }
6278
6279 static gfx::Point3D GetDeltaToTransformOrigin(const nsIFrame* aFrame,
6280 TransformReferenceBox&,
6281 float aAppUnitsPerPixel);
6282
6283 /*
6284 * Returns true if aFrame has perspective applied from its containing
6285 * block.
6286 * Returns the matrix to append to apply the persective (taking
6287 * perspective-origin into account), relative to aFrames coordinate
6288 * space).
6289 * aOutMatrix is assumed to be the identity matrix, and isn't explicitly
6290 * cleared.
6291 */
6292 static bool ComputePerspectiveMatrix(const nsIFrame* aFrame,
6293 float aAppUnitsPerPixel,
6294 Matrix4x4& aOutMatrix);
6295
6296 struct MOZ_STACK_CLASS FrameTransformProperties {
6297 FrameTransformProperties(const nsIFrame* aFrame,
6298 TransformReferenceBox& aRefBox,
6299 float aAppUnitsPerPixel);
FrameTransformPropertiesFrameTransformProperties6300 FrameTransformProperties(const StyleTranslate& aTranslate,
6301 const StyleRotate& aRotate,
6302 const StyleScale& aScale,
6303 const StyleTransform& aTransform,
6304 const Maybe<ResolvedMotionPathData>& aMotion,
6305 const gfx::Point3D& aToTransformOrigin)
6306 : mFrame(nullptr),
6307 mTranslate(aTranslate),
6308 mRotate(aRotate),
6309 mScale(aScale),
6310 mTransform(aTransform),
6311 mMotion(aMotion),
6312 mToTransformOrigin(aToTransformOrigin) {}
6313
HasTransformFrameTransformProperties6314 bool HasTransform() const {
6315 return !mTranslate.IsNone() || !mRotate.IsNone() || !mScale.IsNone() ||
6316 !mTransform.IsNone() || mMotion.isSome();
6317 }
6318
6319 const nsIFrame* mFrame;
6320 const StyleTranslate& mTranslate;
6321 const StyleRotate& mRotate;
6322 const StyleScale& mScale;
6323 const StyleTransform& mTransform;
6324 const Maybe<ResolvedMotionPathData> mMotion;
6325 const gfx::Point3D mToTransformOrigin;
6326 };
6327
6328 /**
6329 * Given a frame with the transform property or an SVG transform,
6330 * returns the transformation matrix for that frame.
6331 *
6332 * @param aFrame The frame to get the matrix from.
6333 * @param aOrigin Relative to which point this transform should be applied.
6334 * @param aAppUnitsPerPixel The number of app units per graphics unit.
6335 * @param aBoundsOverride [optional] If this is nullptr (the default), the
6336 * computation will use the value of TransformReferenceBox(aFrame).
6337 * Otherwise, it will use the value of aBoundsOverride. This is
6338 * mostly for internal use and in most cases you will not need to
6339 * specify a value.
6340 * @param aFlags OFFSET_BY_ORIGIN The resulting matrix will be translated
6341 * by aOrigin. This translation is applied *before* the CSS transform.
6342 * @param aFlags INCLUDE_PRESERVE3D_ANCESTORS The computed transform will
6343 * include the transform of any ancestors participating in the same
6344 * 3d rendering context.
6345 * @param aFlags INCLUDE_PERSPECTIVE The resulting matrix will include the
6346 * perspective transform from the containing block if applicable.
6347 */
6348 enum {
6349 OFFSET_BY_ORIGIN = 1 << 0,
6350 INCLUDE_PRESERVE3D_ANCESTORS = 1 << 1,
6351 INCLUDE_PERSPECTIVE = 1 << 2,
6352 };
6353 static Matrix4x4 GetResultingTransformMatrix(const nsIFrame* aFrame,
6354 const nsPoint& aOrigin,
6355 float aAppUnitsPerPixel,
6356 uint32_t aFlags);
6357 static Matrix4x4 GetResultingTransformMatrix(
6358 const FrameTransformProperties& aProperties, TransformReferenceBox&,
6359 float aAppUnitsPerPixel);
6360
6361 struct PrerenderInfo {
CanUseAsyncAnimationsPrerenderInfo6362 bool CanUseAsyncAnimations() const {
6363 return mDecision != PrerenderDecision::No && mHasAnimations;
6364 }
6365 PrerenderDecision mDecision = PrerenderDecision::No;
6366 bool mHasAnimations = true;
6367 };
6368 /**
6369 * Decide whether we should prerender some or all of the contents of the
6370 * transformed frame even when it's not completely visible (yet).
6371 * Return PrerenderDecision::Full if the entire contents should be
6372 * prerendered, PrerenderDecision::Partial if some but not all of the
6373 * contents should be prerendered, or PrerenderDecision::No if only the
6374 * visible area should be rendered.
6375 * |mNoAffectDecisionInPreserve3D| is set if the prerender decision should not
6376 * affect the decision on other frames in the preserve 3d tree.
6377 * |aDirtyRect| is updated to the area that should be prerendered.
6378 */
6379 static PrerenderInfo ShouldPrerenderTransformedContent(
6380 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsRect* aDirtyRect);
6381
6382 bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override;
6383
6384 bool MayBeAnimated(nsDisplayListBuilder* aBuilder) const;
6385
6386 void WriteDebugInfo(std::stringstream& aStream) override;
6387
CanMoveAsync()6388 bool CanMoveAsync() override {
6389 return EffectCompositor::HasAnimationsForCompositor(
6390 mFrame, DisplayItemType::TYPE_TRANSFORM);
6391 }
6392
6393 /**
6394 * This item is an additional item as the boundary between parent
6395 * and child 3D rendering context.
6396 * \see nsIFrame::BuildDisplayListForStackingContext().
6397 */
IsTransformSeparator()6398 bool IsTransformSeparator() const { return mIsTransformSeparator; }
6399 /**
6400 * This item is the boundary between parent and child 3D rendering
6401 * context.
6402 */
IsLeafOf3DContext()6403 bool IsLeafOf3DContext() const {
6404 return (IsTransformSeparator() ||
6405 (!mFrame->Extend3DContext() && Combines3DTransformWithAncestors()));
6406 }
6407 /**
6408 * The backing frame of this item participates a 3D rendering
6409 * context.
6410 */
IsParticipating3DContext()6411 bool IsParticipating3DContext() const {
6412 return mFrame->Extend3DContext() || Combines3DTransformWithAncestors();
6413 }
6414
IsPartialPrerender()6415 bool IsPartialPrerender() const {
6416 return mPrerenderDecision == PrerenderDecision::Partial;
6417 }
6418
6419 /**
6420 * Mark this item as created together with `nsDisplayPerspective`.
6421 * \see nsIFrame::BuildDisplayListForStackingContext().
6422 */
MarkWithAssociatedPerspective()6423 void MarkWithAssociatedPerspective() { mHasAssociatedPerspective = true; }
6424
6425 void AddSizeOfExcludingThis(nsWindowSizes&) const override;
6426
CreatesStackingContextHelper()6427 bool CreatesStackingContextHelper() override { return true; }
6428
6429 private:
6430 void ComputeBounds(nsDisplayListBuilder* aBuilder);
6431 nsRect TransformUntransformedBounds(nsDisplayListBuilder* aBuilder,
6432 const Matrix4x4Flagged& aMatrix) const;
6433 void UpdateUntransformedBounds(nsDisplayListBuilder* aBuilder);
6434
6435 void SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder);
6436 void Init(nsDisplayListBuilder* aBuilder, nsDisplayList* aChildren);
6437
6438 static Matrix4x4 GetResultingTransformMatrixInternal(
6439 const FrameTransformProperties& aProperties,
6440 TransformReferenceBox& aRefBox, const nsPoint& aOrigin,
6441 float aAppUnitsPerPixel, uint32_t aFlags);
6442
6443 void Collect3DTransformLeaves(nsDisplayListBuilder* aBuilder,
6444 nsTArray<nsDisplayTransform*>& aLeaves);
6445 using TransformPolygon = layers::BSPPolygon<nsDisplayTransform>;
6446 void CollectSorted3DTransformLeaves(nsDisplayListBuilder* aBuilder,
6447 nsTArray<TransformPolygon>& aLeaves);
6448
6449 mutable RetainedDisplayList mChildren;
6450 mutable Maybe<Matrix4x4Flagged> mTransform;
6451 mutable Maybe<Matrix4x4Flagged> mInverseTransform;
6452 // Accumulated transform of ancestors on the preserves-3d chain.
6453 UniquePtr<Matrix4x4> mTransformPreserves3D;
6454 nsRect mChildrenBuildingRect;
6455
6456 // The untransformed bounds of |mChildren|.
6457 nsRect mChildBounds;
6458 // The transformed bounds of this display item.
6459 nsRect mBounds;
6460 PrerenderDecision mPrerenderDecision : 8;
6461 // This item is a separator between 3D rendering contexts, and
6462 // mTransform have been presetted by the constructor.
6463 // This also forces us not to extend the 3D context. Since we don't create a
6464 // transform item, a container layer, for every frame in a preserves3d
6465 // context, the transform items of a child preserves3d context may extend the
6466 // parent context unintendedly if the root of the child preserves3d context
6467 // doesn't create a transform item.
6468 bool mIsTransformSeparator : 1;
6469 // True if we have a transform getter.
6470 bool mHasTransformGetter : 1;
6471 // True if this item is created together with `nsDisplayPerspective`
6472 // from the same CSS stacking context.
6473 bool mHasAssociatedPerspective : 1;
6474 };
6475
6476 /* A display item that applies a perspective transformation to a single
6477 * nsDisplayTransform child item. We keep this as a separate item since the
6478 * perspective-origin is relative to an ancestor of the transformed frame, and
6479 * APZ can scroll the child separately.
6480 */
6481 class nsDisplayPerspective : public nsPaintedDisplayItem {
6482 public:
6483 nsDisplayPerspective(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
6484 nsDisplayList* aList);
6485 ~nsDisplayPerspective() override = default;
6486
6487 NS_DISPLAY_DECL_NAME("nsDisplayPerspective", TYPE_PERSPECTIVE)
6488
Destroy(nsDisplayListBuilder * aBuilder)6489 void Destroy(nsDisplayListBuilder* aBuilder) override {
6490 mList.DeleteAll(aBuilder);
6491 nsPaintedDisplayItem::Destroy(aBuilder);
6492 }
6493
HitTest(nsDisplayListBuilder * aBuilder,const nsRect & aRect,HitTestState * aState,nsTArray<nsIFrame * > * aOutFrames)6494 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
6495 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override {
6496 return GetChildren()->HitTest(aBuilder, aRect, aState, aOutFrames);
6497 }
6498
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)6499 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override {
6500 *aSnap = false;
6501 return GetChildren()->GetClippedBoundsWithRespectToASR(aBuilder,
6502 mActiveScrolledRoot);
6503 }
6504
ComputeInvalidationRegion(nsDisplayListBuilder * aBuilder,const nsDisplayItemGeometry * aGeometry,nsRegion * aInvalidRegion)6505 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
6506 const nsDisplayItemGeometry* aGeometry,
6507 nsRegion* aInvalidRegion) const override {}
6508
6509 nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
6510 bool* aSnap) const override;
6511
6512 bool CreateWebRenderCommands(
6513 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
6514 const StackingContextHelper& aSc,
6515 layers::RenderRootStateManager* aManager,
6516 nsDisplayListBuilder* aDisplayListBuilder) override;
6517
6518 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
6519
GetSameCoordinateSystemChildren()6520 RetainedDisplayList* GetSameCoordinateSystemChildren() const override {
6521 return &mList;
6522 }
6523
GetChildren()6524 RetainedDisplayList* GetChildren() const override { return &mList; }
6525
GetComponentAlphaBounds(nsDisplayListBuilder * aBuilder)6526 nsRect GetComponentAlphaBounds(
6527 nsDisplayListBuilder* aBuilder) const override {
6528 return GetChildren()->GetComponentAlphaBounds(aBuilder);
6529 }
6530
DoUpdateBoundsPreserves3D(nsDisplayListBuilder * aBuilder)6531 void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override {
6532 if (GetChildren()->GetTop()) {
6533 static_cast<nsDisplayTransform*>(GetChildren()->GetTop())
6534 ->DoUpdateBoundsPreserves3D(aBuilder);
6535 }
6536 }
6537
CreatesStackingContextHelper()6538 bool CreatesStackingContextHelper() override { return true; }
6539
6540 private:
6541 mutable RetainedDisplayList mList;
6542 };
6543
6544 class nsDisplayTextGeometry;
6545
6546 /**
6547 * This class adds basic support for limiting the rendering (in the inline axis
6548 * of the writing mode) to the part inside the specified edges.
6549 * The two members, mVisIStartEdge and mVisIEndEdge, are relative to the edges
6550 * of the frame's scrollable overflow rectangle and are the amount to suppress
6551 * on each side.
6552 *
6553 * Setting none, both or only one edge is allowed.
6554 * The values must be non-negative.
6555 * The default value for both edges is zero, which means everything is painted.
6556 */
6557 class nsDisplayText final : public nsPaintedDisplayItem {
6558 public:
6559 nsDisplayText(nsDisplayListBuilder* aBuilder, nsTextFrame* aFrame);
6560 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayText)
6561
6562 NS_DISPLAY_DECL_NAME("Text", TYPE_TEXT)
6563
GetBounds(nsDisplayListBuilder * aBuilder,bool * aSnap)6564 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const final {
6565 *aSnap = false;
6566 return mBounds;
6567 }
6568
HitTest(nsDisplayListBuilder * aBuilder,const nsRect & aRect,HitTestState * aState,nsTArray<nsIFrame * > * aOutFrames)6569 void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
6570 HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) final {
6571 if (nsRect(ToReferenceFrame(), mFrame->GetSize()).Intersects(aRect)) {
6572 aOutFrames->AppendElement(mFrame);
6573 }
6574 }
6575
6576 bool CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
6577 wr::IpcResourceUpdateQueue& aResources,
6578 const StackingContextHelper& aSc,
6579 layers::RenderRootStateManager* aManager,
6580 nsDisplayListBuilder* aDisplayListBuilder) final;
6581 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) final;
6582
GetComponentAlphaBounds(nsDisplayListBuilder * aBuilder)6583 nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const final {
6584 if (gfxPlatform::GetPlatform()->RespectsFontStyleSmoothing()) {
6585 // On OS X, web authors can turn off subpixel text rendering using the
6586 // CSS property -moz-osx-font-smoothing. If they do that, we don't need
6587 // to use component alpha layers for the affected text.
6588 if (mFrame->StyleFont()->mFont.smoothing == NS_FONT_SMOOTHING_GRAYSCALE) {
6589 return nsRect();
6590 }
6591 }
6592 bool snap;
6593 return GetBounds(aBuilder, &snap);
6594 }
6595
6596 nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) final;
6597
6598 void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
6599 const nsDisplayItemGeometry* aGeometry,
6600 nsRegion* aInvalidRegion) const final;
6601
6602 void RenderToContext(gfxContext* aCtx, nsDisplayListBuilder* aBuilder,
6603 const nsRect& aVisibleRect, float aOpacity = 1.0f,
6604 bool aIsRecording = false);
6605
6606 bool CanApplyOpacity(WebRenderLayerManager* aManager,
6607 nsDisplayListBuilder* aBuilder) const final;
6608
6609 void WriteDebugInfo(std::stringstream& aStream) final;
6610
CheckCast(nsDisplayItem * aItem)6611 static nsDisplayText* CheckCast(nsDisplayItem* aItem) {
6612 return (aItem->GetType() == DisplayItemType::TYPE_TEXT)
6613 ? static_cast<nsDisplayText*>(aItem)
6614 : nullptr;
6615 }
6616
VisIStartEdge()6617 nscoord& VisIStartEdge() { return mVisIStartEdge; }
VisIEndEdge()6618 nscoord& VisIEndEdge() { return mVisIEndEdge; }
6619
6620 private:
6621 nsRect mBounds;
6622 nsRect mVisibleRect;
6623
6624 // Lengths measured from the visual inline start and end sides
6625 // (i.e. left and right respectively in horizontal writing modes,
6626 // regardless of bidi directionality; top and bottom in vertical modes).
6627 nscoord mVisIStartEdge;
6628 nscoord mVisIEndEdge;
6629 };
6630
6631 /**
6632 * A display item that for webrender to handle SVG
6633 */
6634 class nsDisplaySVGWrapper : public nsDisplayWrapList {
6635 public:
6636 nsDisplaySVGWrapper(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
6637 nsDisplayList* aList);
6638
6639 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplaySVGWrapper)
6640
6641 NS_DISPLAY_DECL_NAME("SVGWrapper", TYPE_SVG_WRAPPER)
6642
Paint(nsDisplayListBuilder * aBuilder,gfxContext * aCtx)6643 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override {
6644 GetChildren()->Paint(aBuilder, aCtx,
6645 mFrame->PresContext()->AppUnitsPerDevPixel());
6646 }
6647 bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
6648 bool CreateWebRenderCommands(
6649 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
6650 const StackingContextHelper& aSc,
6651 layers::RenderRootStateManager* aManager,
6652 nsDisplayListBuilder* aDisplayListBuilder) override;
6653 };
6654
6655 /**
6656 * A display item for webrender to handle SVG foreign object
6657 */
6658 class nsDisplayForeignObject : public nsDisplayWrapList {
6659 public:
6660 nsDisplayForeignObject(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
6661 nsDisplayList* aList);
6662 #ifdef NS_BUILD_REFCNT_LOGGING
6663 virtual ~nsDisplayForeignObject();
6664 #endif
6665
6666 NS_DISPLAY_DECL_NAME("ForeignObject", TYPE_FOREIGN_OBJECT)
6667
6668 virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
Paint(nsDisplayListBuilder * aBuilder,gfxContext * aCtx)6669 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override {
6670 GetChildren()->Paint(aBuilder, aCtx,
6671 mFrame->PresContext()->AppUnitsPerDevPixel());
6672 }
6673
6674 bool CreateWebRenderCommands(
6675 wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
6676 const StackingContextHelper& aSc,
6677 layers::RenderRootStateManager* aManager,
6678 nsDisplayListBuilder* aDisplayListBuilder) override;
6679 };
6680
6681 /**
6682 * A display item to represent a hyperlink.
6683 */
6684 class nsDisplayLink : public nsPaintedDisplayItem {
6685 public:
nsDisplayLink(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,const char * aLinkSpec,const nsRect & aRect)6686 nsDisplayLink(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
6687 const char* aLinkSpec, const nsRect& aRect)
6688 : nsPaintedDisplayItem(aBuilder, aFrame),
6689 mLinkSpec(aLinkSpec),
6690 mRect(aRect) {}
6691
6692 NS_DISPLAY_DECL_NAME("Link", TYPE_LINK)
6693
6694 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
6695
6696 private:
6697 nsCString mLinkSpec;
6698 nsRect mRect;
6699 };
6700
6701 /**
6702 * A display item to represent a destination within the document.
6703 */
6704 class nsDisplayDestination : public nsPaintedDisplayItem {
6705 public:
nsDisplayDestination(nsDisplayListBuilder * aBuilder,nsIFrame * aFrame,const char * aDestinationName,const nsPoint & aPosition)6706 nsDisplayDestination(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
6707 const char* aDestinationName, const nsPoint& aPosition)
6708 : nsPaintedDisplayItem(aBuilder, aFrame),
6709 mDestinationName(aDestinationName),
6710 mPosition(aPosition) {}
6711
6712 NS_DISPLAY_DECL_NAME("Destination", TYPE_DESTINATION)
6713
6714 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
6715
6716 private:
6717 nsCString mDestinationName;
6718 nsPoint mPosition;
6719 };
6720
6721 class FlattenedDisplayListIterator {
6722 public:
FlattenedDisplayListIterator(nsDisplayListBuilder * aBuilder,nsDisplayList * aList)6723 FlattenedDisplayListIterator(nsDisplayListBuilder* aBuilder,
6724 nsDisplayList* aList)
6725 : mBuilder(aBuilder), mStart(aList->begin()), mEnd(aList->end()) {
6726 ResolveFlattening();
6727 }
6728
HasNext()6729 bool HasNext() const { return !AtEndOfCurrentList(); }
6730
GetNextItem()6731 nsDisplayItem* GetNextItem() {
6732 MOZ_ASSERT(HasNext());
6733
6734 nsDisplayItem* current = NextItem();
6735 Advance();
6736
6737 if (!AtEndOfCurrentList() && current->CanMerge(NextItem())) {
6738 // Since we can merge at least two display items, create an array and
6739 // collect mergeable display items there.
6740 AutoTArray<nsDisplayItem*, 2> willMerge{current};
6741
6742 auto it = mStart;
6743 while (it != mEnd) {
6744 nsDisplayItem* next = *it;
6745 if (current->CanMerge(next)) {
6746 willMerge.AppendElement(next);
6747 ++it;
6748 } else {
6749 break;
6750 }
6751 }
6752 mStart = it;
6753
6754 current = mBuilder->MergeItems(willMerge);
6755 }
6756
6757 ResolveFlattening();
6758 return current;
6759 }
6760
6761 protected:
Advance()6762 void Advance() { ++mStart; }
6763
AtEndOfNestedList()6764 bool AtEndOfNestedList() const {
6765 return AtEndOfCurrentList() && mStack.Length() > 0;
6766 }
6767
AtEndOfCurrentList()6768 bool AtEndOfCurrentList() const { return mStart == mEnd; }
6769
NextItem()6770 nsDisplayItem* NextItem() {
6771 MOZ_ASSERT(HasNext());
6772 return *mStart;
6773 }
6774
ShouldFlattenNextItem()6775 bool ShouldFlattenNextItem() {
6776 return HasNext() && NextItem()->ShouldFlattenAway(mBuilder);
6777 }
6778
ResolveFlattening()6779 void ResolveFlattening() {
6780 // Handle the case where we reach the end of a nested list, or the current
6781 // item should start a new nested list. Repeat this until we find an actual
6782 // item, or the very end of the outer list.
6783 while (AtEndOfNestedList() || ShouldFlattenNextItem()) {
6784 if (AtEndOfNestedList()) {
6785 // We reached the end of the list, pop the next list from the stack.
6786 std::tie(mStart, mEnd) = mStack.PopLastElement();
6787 } else {
6788 // The next item wants to be flattened. This means that we will skip the
6789 // flattened item and directly iterate over its sublist.
6790 MOZ_ASSERT(ShouldFlattenNextItem());
6791
6792 nsDisplayList* sublist = NextItem()->GetChildren();
6793 MOZ_ASSERT(sublist);
6794
6795 // Skip the flattened item.
6796 Advance();
6797
6798 // Store the current position on the stack.
6799 if (!AtEndOfCurrentList()) {
6800 mStack.AppendElement(std::make_pair(mStart, mEnd));
6801 }
6802
6803 // Iterate over the sublist.
6804 mStart = sublist->begin();
6805 mEnd = sublist->end();
6806 }
6807 }
6808 }
6809
6810 private:
6811 nsDisplayListBuilder* mBuilder;
6812 nsDisplayList::iterator mStart;
6813 nsDisplayList::iterator mEnd;
6814 nsTArray<std::pair<nsDisplayList::iterator, nsDisplayList::iterator>> mStack;
6815 };
6816
6817 class PaintTelemetry {
6818 public:
6819 class AutoRecordPaint {
6820 public:
6821 AutoRecordPaint();
6822 ~AutoRecordPaint();
6823
6824 private:
6825 TimeStamp mStart;
6826 };
6827
6828 private:
6829 static uint32_t sPaintLevel;
6830 };
6831
6832 } // namespace mozilla
6833
6834 #endif /*NSDISPLAYLIST_H_*/
6835