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